Merge "Avoid binder transaction to WM for lock orientation"
diff --git a/Android.mk b/Android.mk
index 46529eb..d9e202c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -15,6 +15,14 @@
 #
 LOCAL_PATH := $(call my-dir)
 
+$(eval $(call declare-1p-copy-files,frameworks/base,.ogg))
+$(eval $(call declare-1p-copy-files,frameworks/base,.kl))
+$(eval $(call declare-1p-copy-files,frameworks/base,.kcm))
+$(eval $(call declare-1p-copy-files,frameworks/base,.idc))
+$(eval $(call declare-1p-copy-files,frameworks/base,dirty-image-objects))
+$(eval $(call declare-1p-copy-files,frameworks/base/config,))
+$(eval $(call declare-1p-copy-files,frameworks/native/data,))
+
 # Load framework-specific path mappings used later in the build.
 include $(LOCAL_PATH)/pathmap.mk
 
diff --git a/ApiDocs.bp b/ApiDocs.bp
index b5acfb2..996cdc9 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -87,6 +87,7 @@
         ":framework-graphics-srcs",
         ":framework-mediaprovider-sources",
         ":framework-nearby-sources",
+        ":framework-ondevicepersonalization-sources",
         ":framework-permission-sources",
         ":framework-permission-s-sources",
         ":framework-scheduling-sources",
diff --git a/api/Android.bp b/api/Android.bp
index d57f5db..e902530 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -116,6 +116,7 @@
         "framework-graphics",
         "framework-media",
         "framework-mediaprovider",
+        "framework-ondevicepersonalization",
         "framework-permission",
         "framework-permission-s",
         "framework-scheduling",
diff --git a/boot/Android.bp b/boot/Android.bp
index 55ffe7c..aa22532 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -80,6 +80,10 @@
             module: "com.android.mediaprovider-bootclasspath-fragment",
         },
         {
+            apex: "com.android.ondevicepersonalization",
+            module: "com.android.ondevicepersonalization-bootclasspath-fragment",
+        },
+        {
             apex: "com.android.os.statsd",
             module: "com.android.os.statsd-bootclasspath-fragment",
         },
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index 1c82597..e1b7829 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -134,19 +134,19 @@
   ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
 
   ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::integer::int1,
-                                             R::overlay::integer::int1)),
+                                                 R::overlay::integer::int1)),
             std::string::npos)
       << result->stdout_str;
   ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str1,
-                                             R::overlay::string::str1)),
+                                                 R::overlay::string::str1)),
             std::string::npos)
       << result->stdout_str;
   ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str3,
-                                             R::overlay::string::str3)),
+                                                 R::overlay::string::str3)),
             std::string::npos)
       << result->stdout_str;
   ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str4,
-                                             R::overlay::string::str4)),
+                                                 R::overlay::string::str4)),
             std::string::npos)
       << result->stdout_str;
 
diff --git a/core/api/current.txt b/core/api/current.txt
index ea3830f..51c9ad7 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -631,6 +631,7 @@
     field public static final int elevation = 16843840; // 0x1010440
     field public static final int ellipsize = 16842923; // 0x10100ab
     field public static final int ems = 16843096; // 0x1010158
+    field public static final int enableOnBackInvokedCallback;
     field public static final int enableVrMode = 16844069; // 0x1010525
     field public static final int enabled = 16842766; // 0x101000e
     field public static final int end = 16843996; // 0x10104dc
@@ -17124,12 +17125,17 @@
     field public static final int MICROPHONE = 1; // 0x1
   }
 
-  public final class SyncFence implements java.io.Closeable android.os.Parcelable {
-    method public void close() throws java.io.IOException;
+  public final class SyncFence implements java.lang.AutoCloseable android.os.Parcelable {
+    method public boolean await(@NonNull java.time.Duration);
+    method public boolean awaitForever();
+    method public void close();
     method public int describeContents();
+    method public long getSignalTime();
     method public boolean isValid();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.hardware.SyncFence> CREATOR;
+    field public static final long SIGNAL_TIME_INVALID = -1L; // 0xffffffffffffffffL
+    field public static final long SIGNAL_TIME_PENDING = 9223372036854775807L; // 0x7fffffffffffffffL
   }
 
   public final class TriggerEvent {
@@ -27879,12 +27885,17 @@
 
   public class EGLExt {
     ctor public EGLExt();
+    method @NonNull public static android.hardware.SyncFence eglDupNativeFenceFDANDROID(@NonNull android.opengl.EGLDisplay, @NonNull android.opengl.EGLSync);
     method public static boolean eglPresentationTimeANDROID(android.opengl.EGLDisplay, android.opengl.EGLSurface, long);
     field public static final int EGL_CONTEXT_FLAGS_KHR = 12540; // 0x30fc
     field public static final int EGL_CONTEXT_MAJOR_VERSION_KHR = 12440; // 0x3098
     field public static final int EGL_CONTEXT_MINOR_VERSION_KHR = 12539; // 0x30fb
+    field public static final int EGL_NO_NATIVE_FENCE_FD_ANDROID = -1; // 0xffffffff
     field public static final int EGL_OPENGL_ES3_BIT_KHR = 64; // 0x40
     field public static final int EGL_RECORDABLE_ANDROID = 12610; // 0x3142
+    field public static final int EGL_SYNC_NATIVE_FENCE_ANDROID = 12612; // 0x3144
+    field public static final int EGL_SYNC_NATIVE_FENCE_FD_ANDROID = 12613; // 0x3145
+    field public static final int EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID = 12614; // 0x3146
   }
 
   public class EGLImage extends android.opengl.EGLObjectHandle {
@@ -39594,7 +39605,7 @@
 
   public class SpeechRecognizer {
     method @MainThread public void cancel();
-    method public void checkRecognitionSupport(@NonNull android.content.Intent, @NonNull android.speech.RecognitionSupportCallback);
+    method public void checkRecognitionSupport(@NonNull android.content.Intent, @NonNull java.util.concurrent.Executor, @NonNull android.speech.RecognitionSupportCallback);
     method @MainThread @NonNull public static android.speech.SpeechRecognizer createOnDeviceSpeechRecognizer(@NonNull android.content.Context);
     method @MainThread public static android.speech.SpeechRecognizer createSpeechRecognizer(android.content.Context);
     method @MainThread public static android.speech.SpeechRecognizer createSpeechRecognizer(android.content.Context, android.content.ComponentName);
@@ -42724,16 +42735,16 @@
     ctor @Deprecated public ServiceState(android.os.Parcel);
     method protected void copyFrom(android.telephony.ServiceState);
     method public int describeContents();
-    method public int getCdmaNetworkId();
-    method public int getCdmaSystemId();
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public int getCdmaNetworkId();
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public int getCdmaSystemId();
     method public int[] getCellBandwidths();
     method public int getChannelNumber();
     method public int getDuplexMode();
     method public boolean getIsManualSelection();
     method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList();
-    method public String getOperatorAlphaLong();
-    method public String getOperatorAlphaShort();
-    method public String getOperatorNumeric();
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public String getOperatorAlphaLong();
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public String getOperatorAlphaShort();
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public String getOperatorNumeric();
     method public boolean getRoaming();
     method public int getState();
     method public boolean isSearching();
@@ -49244,6 +49255,7 @@
     method @NonNull public android.view.SurfaceControl.Transaction reparent(@NonNull android.view.SurfaceControl, @Nullable android.view.SurfaceControl);
     method @NonNull public android.view.SurfaceControl.Transaction setAlpha(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0, to=1.0) float);
     method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer);
+    method @NonNull public android.view.SurfaceControl.Transaction setBuffer(@NonNull android.view.SurfaceControl, @Nullable android.hardware.HardwareBuffer, @Nullable android.hardware.SyncFence);
     method @NonNull public android.view.SurfaceControl.Transaction setBufferSize(@NonNull android.view.SurfaceControl, @IntRange(from=0) int, @IntRange(from=0) int);
     method @NonNull public android.view.SurfaceControl.Transaction setBufferTransform(@NonNull android.view.SurfaceControl, int);
     method @NonNull public android.view.SurfaceControl.Transaction setCrop(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 535d6a2..df08721 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -2164,7 +2164,7 @@
     method @Nullable public android.net.Uri getSliceUri();
     method @NonNull public String getSmartspaceTargetId();
     method @Nullable public String getSourceNotificationKey();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData getTemplateData();
+    method @Nullable public android.app.smartspace.uitemplatedata.BaseTemplateData getTemplateData();
     method @NonNull public android.os.UserHandle getUserHandle();
     method @Nullable public android.appwidget.AppWidgetProviderInfo getWidget();
     method public boolean isSensitive();
@@ -2221,7 +2221,7 @@
     method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setShouldShowExpanded(boolean);
     method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setSliceUri(@NonNull android.net.Uri);
     method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setSourceNotificationKey(@NonNull String);
-    method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setTemplateData(@Nullable android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData);
+    method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setTemplateData(@Nullable android.app.smartspace.uitemplatedata.BaseTemplateData);
     method @NonNull public android.app.smartspace.SmartspaceTarget.Builder setWidget(@NonNull android.appwidget.AppWidgetProviderInfo);
   }
 
@@ -2252,156 +2252,156 @@
 
 package android.app.smartspace.uitemplatedata {
 
-  public final class SmartspaceCarouselUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData {
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getCarouselAction();
-    method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem> getCarouselItems();
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData> CREATOR;
-  }
-
-  public static final class SmartspaceCarouselUiTemplateData.Builder extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder {
-    ctor public SmartspaceCarouselUiTemplateData.Builder(@NonNull java.util.List<android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem>);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData build();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.Builder setCarouselAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction);
-  }
-
-  public static final class SmartspaceCarouselUiTemplateData.CarouselItem implements android.os.Parcelable {
+  public class BaseTemplateData implements android.os.Parcelable {
     method public int describeContents();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getImage();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getLowerText();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getTapAction();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getUpperText();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem> CREATOR;
-  }
-
-  public static final class SmartspaceCarouselUiTemplateData.CarouselItem.Builder {
-    ctor public SmartspaceCarouselUiTemplateData.CarouselItem.Builder();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem build();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setImage(@Nullable android.app.smartspace.uitemplatedata.SmartspaceIcon);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setLowerText(@Nullable android.app.smartspace.uitemplatedata.SmartspaceText);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setTapAction(@Nullable android.app.smartspace.uitemplatedata.SmartspaceTapAction);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCarouselUiTemplateData.CarouselItem.Builder setUpperText(@Nullable android.app.smartspace.uitemplatedata.SmartspaceText);
-  }
-
-  public final class SmartspaceCombinedCardsUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData {
-    method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData> getCombinedCardDataList();
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceCombinedCardsUiTemplateData> CREATOR;
-  }
-
-  public static final class SmartspaceCombinedCardsUiTemplateData.Builder extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder {
-    ctor public SmartspaceCombinedCardsUiTemplateData.Builder(@NonNull java.util.List<android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData>);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceCombinedCardsUiTemplateData build();
-  }
-
-  public class SmartspaceDefaultUiTemplateData implements android.os.Parcelable {
-    method public int describeContents();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getPrimaryTapAction();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getSubtitleIcon();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getSubtitleText();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getSupplementalAlarmText();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getSupplementalSubtitleIcon();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getSupplementalSubtitleTapAction();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getSupplementalSubtitleText();
+    method @Nullable public android.app.smartspace.uitemplatedata.TapAction getPrimaryTapAction();
+    method @Nullable public android.app.smartspace.uitemplatedata.Icon getSubtitleIcon();
+    method @Nullable public android.app.smartspace.uitemplatedata.Text getSubtitleText();
+    method @Nullable public android.app.smartspace.uitemplatedata.Text getSupplementalAlarmText();
+    method @Nullable public android.app.smartspace.uitemplatedata.Icon getSupplementalSubtitleIcon();
+    method @Nullable public android.app.smartspace.uitemplatedata.TapAction getSupplementalSubtitleTapAction();
+    method @Nullable public android.app.smartspace.uitemplatedata.Text getSupplementalSubtitleText();
     method public int getTemplateType();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getTitleIcon();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getTitleText();
+    method @Nullable public android.app.smartspace.uitemplatedata.Icon getTitleIcon();
+    method @Nullable public android.app.smartspace.uitemplatedata.Text getTitleText();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData> CREATOR;
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.BaseTemplateData> CREATOR;
   }
 
-  public static class SmartspaceDefaultUiTemplateData.Builder {
-    ctor public SmartspaceDefaultUiTemplateData.Builder(int);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData build();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setPrimaryTapAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSubtitleIcon(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSubtitleText(@NonNull android.app.smartspace.uitemplatedata.SmartspaceText);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalAlarmText(@NonNull android.app.smartspace.uitemplatedata.SmartspaceText);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalSubtitleIcon(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalSubtitleTapAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setSupplementalSubtitleText(@NonNull android.app.smartspace.uitemplatedata.SmartspaceText);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setTitleIcon(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder setTitleText(@NonNull android.app.smartspace.uitemplatedata.SmartspaceText);
+  public static class BaseTemplateData.Builder {
+    ctor public BaseTemplateData.Builder(int);
+    method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData build();
+    method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setPrimaryTapAction(@NonNull android.app.smartspace.uitemplatedata.TapAction);
+    method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSubtitleIcon(@NonNull android.app.smartspace.uitemplatedata.Icon);
+    method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSubtitleText(@NonNull android.app.smartspace.uitemplatedata.Text);
+    method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSupplementalAlarmText(@NonNull android.app.smartspace.uitemplatedata.Text);
+    method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSupplementalSubtitleIcon(@NonNull android.app.smartspace.uitemplatedata.Icon);
+    method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSupplementalSubtitleTapAction(@NonNull android.app.smartspace.uitemplatedata.TapAction);
+    method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setSupplementalSubtitleText(@NonNull android.app.smartspace.uitemplatedata.Text);
+    method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setTitleIcon(@NonNull android.app.smartspace.uitemplatedata.Icon);
+    method @NonNull public android.app.smartspace.uitemplatedata.BaseTemplateData.Builder setTitleText(@NonNull android.app.smartspace.uitemplatedata.Text);
   }
 
-  public final class SmartspaceHeadToHeadUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData {
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getHeadToHeadAction();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getHeadToHeadFirstCompetitorIcon();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getHeadToHeadFirstCompetitorText();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getHeadToHeadSecondCompetitorIcon();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getHeadToHeadSecondCompetitorText();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getHeadToHeadTitle();
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData> CREATOR;
+  public final class CarouselTemplateData extends android.app.smartspace.uitemplatedata.BaseTemplateData {
+    method @Nullable public android.app.smartspace.uitemplatedata.TapAction getCarouselAction();
+    method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.CarouselTemplateData.CarouselItem> getCarouselItems();
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.CarouselTemplateData> CREATOR;
   }
 
-  public static final class SmartspaceHeadToHeadUiTemplateData.Builder extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder {
-    ctor public SmartspaceHeadToHeadUiTemplateData.Builder();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData build();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadAction(@Nullable android.app.smartspace.uitemplatedata.SmartspaceTapAction);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadFirstCompetitorIcon(@Nullable android.app.smartspace.uitemplatedata.SmartspaceIcon);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadFirstCompetitorText(@Nullable android.app.smartspace.uitemplatedata.SmartspaceText);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadSecondCompetitorIcon(@Nullable android.app.smartspace.uitemplatedata.SmartspaceIcon);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadSecondCompetitorText(@Nullable android.app.smartspace.uitemplatedata.SmartspaceText);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceHeadToHeadUiTemplateData.Builder setHeadToHeadTitle(@Nullable android.app.smartspace.uitemplatedata.SmartspaceText);
+  public static final class CarouselTemplateData.Builder extends android.app.smartspace.uitemplatedata.BaseTemplateData.Builder {
+    ctor public CarouselTemplateData.Builder(@NonNull java.util.List<android.app.smartspace.uitemplatedata.CarouselTemplateData.CarouselItem>);
+    method @NonNull public android.app.smartspace.uitemplatedata.CarouselTemplateData build();
+    method @NonNull public android.app.smartspace.uitemplatedata.CarouselTemplateData.Builder setCarouselAction(@NonNull android.app.smartspace.uitemplatedata.TapAction);
   }
 
-  public final class SmartspaceIcon implements android.os.Parcelable {
+  public static final class CarouselTemplateData.CarouselItem implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.app.smartspace.uitemplatedata.Icon getImage();
+    method @Nullable public android.app.smartspace.uitemplatedata.Text getLowerText();
+    method @Nullable public android.app.smartspace.uitemplatedata.TapAction getTapAction();
+    method @Nullable public android.app.smartspace.uitemplatedata.Text getUpperText();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.CarouselTemplateData.CarouselItem> CREATOR;
+  }
+
+  public static final class CarouselTemplateData.CarouselItem.Builder {
+    ctor public CarouselTemplateData.CarouselItem.Builder();
+    method @NonNull public android.app.smartspace.uitemplatedata.CarouselTemplateData.CarouselItem build();
+    method @NonNull public android.app.smartspace.uitemplatedata.CarouselTemplateData.CarouselItem.Builder setImage(@Nullable android.app.smartspace.uitemplatedata.Icon);
+    method @NonNull public android.app.smartspace.uitemplatedata.CarouselTemplateData.CarouselItem.Builder setLowerText(@Nullable android.app.smartspace.uitemplatedata.Text);
+    method @NonNull public android.app.smartspace.uitemplatedata.CarouselTemplateData.CarouselItem.Builder setTapAction(@Nullable android.app.smartspace.uitemplatedata.TapAction);
+    method @NonNull public android.app.smartspace.uitemplatedata.CarouselTemplateData.CarouselItem.Builder setUpperText(@Nullable android.app.smartspace.uitemplatedata.Text);
+  }
+
+  public final class CombinedCardsTemplateData extends android.app.smartspace.uitemplatedata.BaseTemplateData {
+    method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.BaseTemplateData> getCombinedCardDataList();
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.CombinedCardsTemplateData> CREATOR;
+  }
+
+  public static final class CombinedCardsTemplateData.Builder extends android.app.smartspace.uitemplatedata.BaseTemplateData.Builder {
+    ctor public CombinedCardsTemplateData.Builder(@NonNull java.util.List<android.app.smartspace.uitemplatedata.BaseTemplateData>);
+    method @NonNull public android.app.smartspace.uitemplatedata.CombinedCardsTemplateData build();
+  }
+
+  public final class HeadToHeadTemplateData extends android.app.smartspace.uitemplatedata.BaseTemplateData {
+    method @Nullable public android.app.smartspace.uitemplatedata.TapAction getHeadToHeadAction();
+    method @Nullable public android.app.smartspace.uitemplatedata.Icon getHeadToHeadFirstCompetitorIcon();
+    method @Nullable public android.app.smartspace.uitemplatedata.Text getHeadToHeadFirstCompetitorText();
+    method @Nullable public android.app.smartspace.uitemplatedata.Icon getHeadToHeadSecondCompetitorIcon();
+    method @Nullable public android.app.smartspace.uitemplatedata.Text getHeadToHeadSecondCompetitorText();
+    method @Nullable public android.app.smartspace.uitemplatedata.Text getHeadToHeadTitle();
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.HeadToHeadTemplateData> CREATOR;
+  }
+
+  public static final class HeadToHeadTemplateData.Builder extends android.app.smartspace.uitemplatedata.BaseTemplateData.Builder {
+    ctor public HeadToHeadTemplateData.Builder();
+    method @NonNull public android.app.smartspace.uitemplatedata.HeadToHeadTemplateData build();
+    method @NonNull public android.app.smartspace.uitemplatedata.HeadToHeadTemplateData.Builder setHeadToHeadAction(@Nullable android.app.smartspace.uitemplatedata.TapAction);
+    method @NonNull public android.app.smartspace.uitemplatedata.HeadToHeadTemplateData.Builder setHeadToHeadFirstCompetitorIcon(@Nullable android.app.smartspace.uitemplatedata.Icon);
+    method @NonNull public android.app.smartspace.uitemplatedata.HeadToHeadTemplateData.Builder setHeadToHeadFirstCompetitorText(@Nullable android.app.smartspace.uitemplatedata.Text);
+    method @NonNull public android.app.smartspace.uitemplatedata.HeadToHeadTemplateData.Builder setHeadToHeadSecondCompetitorIcon(@Nullable android.app.smartspace.uitemplatedata.Icon);
+    method @NonNull public android.app.smartspace.uitemplatedata.HeadToHeadTemplateData.Builder setHeadToHeadSecondCompetitorText(@Nullable android.app.smartspace.uitemplatedata.Text);
+    method @NonNull public android.app.smartspace.uitemplatedata.HeadToHeadTemplateData.Builder setHeadToHeadTitle(@Nullable android.app.smartspace.uitemplatedata.Text);
+  }
+
+  public final class Icon implements android.os.Parcelable {
     method public int describeContents();
     method @Nullable public CharSequence getContentDescription();
     method @NonNull public android.graphics.drawable.Icon getIcon();
     method public boolean shouldTint();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceIcon> CREATOR;
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.Icon> CREATOR;
   }
 
-  public static final class SmartspaceIcon.Builder {
-    ctor public SmartspaceIcon.Builder(@NonNull android.graphics.drawable.Icon);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceIcon build();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceIcon.Builder setContentDescription(@NonNull CharSequence);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceIcon.Builder setShouldTint(boolean);
+  public static final class Icon.Builder {
+    ctor public Icon.Builder(@NonNull android.graphics.drawable.Icon);
+    method @NonNull public android.app.smartspace.uitemplatedata.Icon build();
+    method @NonNull public android.app.smartspace.uitemplatedata.Icon.Builder setContentDescription(@NonNull CharSequence);
+    method @NonNull public android.app.smartspace.uitemplatedata.Icon.Builder setShouldTint(boolean);
   }
 
-  public final class SmartspaceSubCardUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData {
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getSubCardAction();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceIcon getSubCardIcon();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceText getSubCardText();
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceSubCardUiTemplateData> CREATOR;
+  public final class SubCardTemplateData extends android.app.smartspace.uitemplatedata.BaseTemplateData {
+    method @Nullable public android.app.smartspace.uitemplatedata.TapAction getSubCardAction();
+    method @NonNull public android.app.smartspace.uitemplatedata.Icon getSubCardIcon();
+    method @Nullable public android.app.smartspace.uitemplatedata.Text getSubCardText();
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SubCardTemplateData> CREATOR;
   }
 
-  public static final class SmartspaceSubCardUiTemplateData.Builder extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder {
-    ctor public SmartspaceSubCardUiTemplateData.Builder(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubCardUiTemplateData build();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubCardUiTemplateData.Builder setSubCardAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubCardUiTemplateData.Builder setSubCardText(@NonNull android.app.smartspace.uitemplatedata.SmartspaceText);
+  public static final class SubCardTemplateData.Builder extends android.app.smartspace.uitemplatedata.BaseTemplateData.Builder {
+    ctor public SubCardTemplateData.Builder(@NonNull android.app.smartspace.uitemplatedata.Icon);
+    method @NonNull public android.app.smartspace.uitemplatedata.SubCardTemplateData build();
+    method @NonNull public android.app.smartspace.uitemplatedata.SubCardTemplateData.Builder setSubCardAction(@NonNull android.app.smartspace.uitemplatedata.TapAction);
+    method @NonNull public android.app.smartspace.uitemplatedata.SubCardTemplateData.Builder setSubCardText(@NonNull android.app.smartspace.uitemplatedata.Text);
   }
 
-  public final class SmartspaceSubImageUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData {
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getSubImageAction();
-    method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.SmartspaceText> getSubImageTexts();
-    method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.SmartspaceIcon> getSubImages();
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceSubImageUiTemplateData> CREATOR;
+  public final class SubImageTemplateData extends android.app.smartspace.uitemplatedata.BaseTemplateData {
+    method @Nullable public android.app.smartspace.uitemplatedata.TapAction getSubImageAction();
+    method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.Text> getSubImageTexts();
+    method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.Icon> getSubImages();
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SubImageTemplateData> CREATOR;
   }
 
-  public static final class SmartspaceSubImageUiTemplateData.Builder extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder {
-    ctor public SmartspaceSubImageUiTemplateData.Builder(@NonNull java.util.List<android.app.smartspace.uitemplatedata.SmartspaceText>, @NonNull java.util.List<android.app.smartspace.uitemplatedata.SmartspaceIcon>);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubImageUiTemplateData build();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubImageUiTemplateData.Builder setSubImageAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction);
+  public static final class SubImageTemplateData.Builder extends android.app.smartspace.uitemplatedata.BaseTemplateData.Builder {
+    ctor public SubImageTemplateData.Builder(@NonNull java.util.List<android.app.smartspace.uitemplatedata.Text>, @NonNull java.util.List<android.app.smartspace.uitemplatedata.Icon>);
+    method @NonNull public android.app.smartspace.uitemplatedata.SubImageTemplateData build();
+    method @NonNull public android.app.smartspace.uitemplatedata.SubImageTemplateData.Builder setSubImageAction(@NonNull android.app.smartspace.uitemplatedata.TapAction);
   }
 
-  public final class SmartspaceSubListUiTemplateData extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData {
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceTapAction getSubListAction();
-    method @Nullable public android.app.smartspace.uitemplatedata.SmartspaceIcon getSubListIcon();
-    method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.SmartspaceText> getSubListTexts();
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceSubListUiTemplateData> CREATOR;
+  public final class SubListTemplateData extends android.app.smartspace.uitemplatedata.BaseTemplateData {
+    method @Nullable public android.app.smartspace.uitemplatedata.TapAction getSubListAction();
+    method @Nullable public android.app.smartspace.uitemplatedata.Icon getSubListIcon();
+    method @NonNull public java.util.List<android.app.smartspace.uitemplatedata.Text> getSubListTexts();
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SubListTemplateData> CREATOR;
   }
 
-  public static final class SmartspaceSubListUiTemplateData.Builder extends android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData.Builder {
-    ctor public SmartspaceSubListUiTemplateData.Builder(@NonNull java.util.List<android.app.smartspace.uitemplatedata.SmartspaceText>);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubListUiTemplateData build();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubListUiTemplateData.Builder setSubListAction(@NonNull android.app.smartspace.uitemplatedata.SmartspaceTapAction);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceSubListUiTemplateData.Builder setSubListIcon(@NonNull android.app.smartspace.uitemplatedata.SmartspaceIcon);
+  public static final class SubListTemplateData.Builder extends android.app.smartspace.uitemplatedata.BaseTemplateData.Builder {
+    ctor public SubListTemplateData.Builder(@NonNull java.util.List<android.app.smartspace.uitemplatedata.Text>);
+    method @NonNull public android.app.smartspace.uitemplatedata.SubListTemplateData build();
+    method @NonNull public android.app.smartspace.uitemplatedata.SubListTemplateData.Builder setSubListAction(@NonNull android.app.smartspace.uitemplatedata.TapAction);
+    method @NonNull public android.app.smartspace.uitemplatedata.SubListTemplateData.Builder setSubListIcon(@NonNull android.app.smartspace.uitemplatedata.Icon);
   }
 
-  public final class SmartspaceTapAction implements android.os.Parcelable {
+  public final class TapAction implements android.os.Parcelable {
     method public int describeContents();
     method @Nullable public android.os.Bundle getExtras();
     method @Nullable public CharSequence getId();
@@ -2409,31 +2409,33 @@
     method @Nullable public android.app.PendingIntent getPendingIntent();
     method @Nullable public android.os.UserHandle getUserHandle();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceTapAction> CREATOR;
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.TapAction> CREATOR;
   }
 
-  public static final class SmartspaceTapAction.Builder {
-    ctor public SmartspaceTapAction.Builder(@NonNull CharSequence);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceTapAction build();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceTapAction.Builder setExtras(@NonNull android.os.Bundle);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceTapAction.Builder setIntent(@NonNull android.content.Intent);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceTapAction.Builder setPendingIntent(@NonNull android.app.PendingIntent);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceTapAction.Builder setUserHandle(@Nullable android.os.UserHandle);
+  public static final class TapAction.Builder {
+    ctor public TapAction.Builder(@NonNull CharSequence);
+    method @NonNull public android.app.smartspace.uitemplatedata.TapAction build();
+    method @NonNull public android.app.smartspace.uitemplatedata.TapAction.Builder setExtras(@NonNull android.os.Bundle);
+    method @NonNull public android.app.smartspace.uitemplatedata.TapAction.Builder setIntent(@NonNull android.content.Intent);
+    method @NonNull public android.app.smartspace.uitemplatedata.TapAction.Builder setPendingIntent(@NonNull android.app.PendingIntent);
+    method @NonNull public android.app.smartspace.uitemplatedata.TapAction.Builder setUserHandle(@Nullable android.os.UserHandle);
   }
 
-  public final class SmartspaceText implements android.os.Parcelable {
+  public final class Text implements android.os.Parcelable {
     method public int describeContents();
+    method public int getMaxLines();
     method @NonNull public CharSequence getText();
     method @NonNull public android.text.TextUtils.TruncateAt getTruncateAtType();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.SmartspaceText> CREATOR;
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.smartspace.uitemplatedata.Text> CREATOR;
   }
 
-  public static final class SmartspaceText.Builder {
-    ctor public SmartspaceText.Builder(@NonNull CharSequence);
-    ctor public SmartspaceText.Builder(@NonNull CharSequence, @NonNull android.text.TextUtils.TruncateAt);
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceText build();
-    method @NonNull public android.app.smartspace.uitemplatedata.SmartspaceText.Builder setTruncateAtType(@NonNull android.text.TextUtils.TruncateAt);
+  public static final class Text.Builder {
+    ctor public Text.Builder(@NonNull CharSequence);
+    ctor public Text.Builder(@NonNull CharSequence, @NonNull android.text.TextUtils.TruncateAt);
+    method @NonNull public android.app.smartspace.uitemplatedata.Text build();
+    method @NonNull public android.app.smartspace.uitemplatedata.Text.Builder setMaxLines(int);
+    method @NonNull public android.app.smartspace.uitemplatedata.Text.Builder setTruncateAtType(@NonNull android.text.TextUtils.TruncateAt);
   }
 
 }
@@ -2745,7 +2747,7 @@
 package android.companion.virtual {
 
   public final class VirtualDeviceManager {
-    method @Nullable @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.VirtualDeviceManager.VirtualDevice createVirtualDevice(int, @NonNull android.companion.virtual.VirtualDeviceParams);
+    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.VirtualDeviceManager.VirtualDevice createVirtualDevice(int, @NonNull android.companion.virtual.VirtualDeviceParams);
   }
 
   public static interface VirtualDeviceManager.ActivityListener {
@@ -5316,9 +5318,9 @@
     method public int getCurrentDataRole();
     method public int getCurrentMode();
     method public int getCurrentPowerRole();
-    method public int getPowerBrickStatus();
+    method public int getPowerBrickConnectionStatus();
     method public int getSupportedRoleCombinations();
-    method @Nullable public int[] getUsbDataStatus();
+    method public int getUsbDataStatus();
     method public boolean isConnected();
     method public boolean isPowerTransferLimited();
     method public boolean isRoleCombinationSupported(int, int);
@@ -5327,6 +5329,13 @@
     field public static final int DATA_ROLE_DEVICE = 2; // 0x2
     field public static final int DATA_ROLE_HOST = 1; // 0x1
     field public static final int DATA_ROLE_NONE = 0; // 0x0
+    field public static final int DATA_STATUS_DISABLED_CONTAMINANT = 4; // 0x4
+    field public static final int DATA_STATUS_DISABLED_DEBUG = 32; // 0x20
+    field public static final int DATA_STATUS_DISABLED_DOCK = 8; // 0x8
+    field public static final int DATA_STATUS_DISABLED_FORCE = 16; // 0x10
+    field public static final int DATA_STATUS_DISABLED_OVERHEAT = 2; // 0x2
+    field public static final int DATA_STATUS_ENABLED = 1; // 0x1
+    field public static final int DATA_STATUS_UNKNOWN = 0; // 0x0
     field public static final int MODE_AUDIO_ACCESSORY = 4; // 0x4
     field public static final int MODE_DEBUG_ACCESSORY = 8; // 0x8
     field public static final int MODE_DFP = 2; // 0x2
@@ -5338,13 +5347,6 @@
     field public static final int POWER_ROLE_NONE = 0; // 0x0
     field public static final int POWER_ROLE_SINK = 2; // 0x2
     field public static final int POWER_ROLE_SOURCE = 1; // 0x1
-    field public static final int USB_DATA_STATUS_DISABLED_CONTAMINANT = 3; // 0x3
-    field public static final int USB_DATA_STATUS_DISABLED_DEBUG = 6; // 0x6
-    field public static final int USB_DATA_STATUS_DISABLED_DOCK = 4; // 0x4
-    field public static final int USB_DATA_STATUS_DISABLED_FORCE = 5; // 0x5
-    field public static final int USB_DATA_STATUS_DISABLED_OVERHEAT = 2; // 0x2
-    field public static final int USB_DATA_STATUS_ENABLED = 1; // 0x1
-    field public static final int USB_DATA_STATUS_UNKNOWN = 0; // 0x0
   }
 
 }
@@ -15619,7 +15621,7 @@
 
   public interface WindowManager extends android.view.ViewManager {
     method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public android.graphics.Region getCurrentImeTouchRegion();
-    method public default void registerTaskFpsCallback(@IntRange(from=0) int, @NonNull android.window.TaskFpsCallback);
+    method public default void registerTaskFpsCallback(@IntRange(from=0) int, @NonNull java.util.concurrent.Executor, @NonNull android.window.TaskFpsCallback);
     method public default void unregisterTaskFpsCallback(@NonNull android.window.TaskFpsCallback);
   }
 
@@ -16211,12 +16213,9 @@
 
 package android.window {
 
-  public final class TaskFpsCallback {
-    ctor public TaskFpsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.window.TaskFpsCallback.OnFpsCallbackListener);
-  }
-
-  public static interface TaskFpsCallback.OnFpsCallbackListener {
-    method public void onFpsReported(float);
+  public abstract class TaskFpsCallback {
+    ctor public TaskFpsCallback();
+    method public abstract void onFpsReported(float);
   }
 
 }
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 84b393a..239bba5 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -107,6 +107,8 @@
     method public final boolean addDumpable(@NonNull android.util.Dumpable);
     method public void dumpInternal(@NonNull String, @Nullable java.io.FileDescriptor, @NonNull java.io.PrintWriter, @Nullable String[]);
     method public void onMovedToDisplay(int, android.content.res.Configuration);
+    field public static final String DUMP_ARG_DUMP_DUMPABLE = "--dump-dumpable";
+    field public static final String DUMP_ARG_LIST_DUMPABLES = "--list-dumpables";
   }
 
   public class ActivityManager {
@@ -1200,7 +1202,6 @@
     field public static final int SWITCHING_TYPE_NONE = 0; // 0x0
     field public static final int SWITCHING_TYPE_WITHIN_GROUPS = 1; // 0x1
     field public static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 512; // 0x200
-    field public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1024; // 0x400
   }
 
 }
@@ -2983,6 +2984,7 @@
     field public static final String DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE = "max_buffer_size";
     field public static final String DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED = "service_explicitly_enabled";
     field public static final String DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY = "text_change_flush_frequency";
+    field public static final String DUMPABLE_NAME = "ContentCaptureManager";
     field public static final int LOGGING_LEVEL_DEBUG = 1; // 0x1
     field public static final int LOGGING_LEVEL_OFF = 0; // 0x0
     field public static final int LOGGING_LEVEL_VERBOSE = 2; // 0x2
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 983dde3..2b2f08f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -814,6 +814,13 @@
         Dialog mDialog;
         Bundle mArgs;
     }
+
+    /** @hide */ public static final String DUMP_ARG_AUTOFILL = "--autofill";
+    /** @hide */ public static final String DUMP_ARG_CONTENT_CAPTURE = "--contentcapture";
+    /** @hide */ public static final String DUMP_ARG_TRANSLATION = "--translation";
+    /** @hide */ @TestApi public static final String DUMP_ARG_LIST_DUMPABLES = "--list-dumpables";
+    /** @hide */ @TestApi public static final String DUMP_ARG_DUMP_DUMPABLE = "--dump-dumpable";
+
     private SparseArray<ManagedDialog> mManagedDialogs;
 
     // set by the thread after the constructor and before onCreate(Bundle savedInstanceState) is called.
@@ -1649,7 +1656,10 @@
         }
         mRestoredFromBundle = savedInstanceState != null;
         mCalled = true;
-        if (!WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+
+        boolean aheadOfTimeBack = WindowOnBackInvokedDispatcher
+                .isOnBackInvokedCallbackEnabled(this);
+        if (aheadOfTimeBack) {
             // Add onBackPressed as default back behavior.
             mDefaultBackCallback = new OnBackInvokedCallback() {
                 @Override
@@ -7348,43 +7358,72 @@
     public void dumpInternal(@NonNull String prefix,
             @SuppressLint("UseParcelFileDescriptor") @Nullable FileDescriptor fd,
             @NonNull PrintWriter writer, @Nullable String[] args) {
-        if (args != null && args.length > 0
-                && CompatChanges.isChangeEnabled(DUMP_IGNORES_SPECIAL_ARGS)) {
+
+        // Lazy-load mDumpableContainer with Dumpables activity might already have a reference to
+        if (mAutofillClientController != null) {
+            addDumpable(mAutofillClientController);
+        }
+        if (mUiTranslationController != null) {
+            addDumpable(mUiTranslationController);
+        }
+        if (mContentCaptureManager != null) {
+            mContentCaptureManager.addDumpable(this);
+        }
+
+        boolean dumpInternalState = true;
+        String arg = null;
+        if (args != null && args.length > 0) {
+            arg = args[0];
+            boolean isSpecialCase = true;
             // Handle special cases
-            switch (args[0]) {
-                case "--autofill":
-                    dumpAutofillManager(prefix, writer, args);
+            switch (arg) {
+                case DUMP_ARG_AUTOFILL:
+                    dumpLegacyDumpable(prefix, writer, arg,
+                            AutofillClientController.DUMPABLE_NAME);
                     return;
-                case "--contentcapture":
-                    dumpContentCaptureManager(prefix, writer);
+                case DUMP_ARG_CONTENT_CAPTURE:
+                    dumpLegacyDumpable(prefix, writer, arg,
+                            ContentCaptureManager.DUMPABLE_NAME);
                     return;
-                case "--translation":
-                    dumpUiTranslation(prefix, writer);
+                case DUMP_ARG_TRANSLATION:
+                    dumpLegacyDumpable(prefix, writer, arg,
+                            UiTranslationController.DUMPABLE_NAME);
                     return;
-                case "--list-dumpables":
+                case DUMP_ARG_LIST_DUMPABLES:
                     if (mDumpableContainer == null) {
                         writer.print(prefix); writer.println("No dumpables");
-                        return;
+                    } else {
+                        mDumpableContainer.listDumpables(prefix, writer);
                     }
                     mDumpableContainer.listDumpables(prefix, writer);
                     return;
-                case "--dump-dumpable":
+                case DUMP_ARG_DUMP_DUMPABLE:
                     if (args.length == 1) {
-                        writer.println("--dump-dumpable requires the dumpable name");
-                        return;
-                    }
-                    if (mDumpableContainer == null) {
+                        writer.print(DUMP_ARG_DUMP_DUMPABLE);
+                        writer.println(" requires the dumpable name");
+                    } else if (mDumpableContainer == null) {
                         writer.println("no dumpables");
-                        return;
+                    } else {
+                        // Strips --dump-dumpable NAME
+                        String[] prunedArgs = new String[args.length - 2];
+                        System.arraycopy(args, 2, prunedArgs, 0, prunedArgs.length);
+                        mDumpableContainer.dumpOneDumpable(prefix, writer, args[1], prunedArgs);
                     }
-                    // Strips --dump-dumpable NAME
-                    String[] prunedArgs = new String[args.length - 2];
-                    System.arraycopy(args, 2, prunedArgs, 0, prunedArgs.length);
-                    mDumpableContainer.dumpOneDumpable(prefix, writer, args[1], prunedArgs);
-                    return;
+                    break;
+                default:
+                    isSpecialCase = false;
+                    break;
+            }
+            if (isSpecialCase) {
+                dumpInternalState = !CompatChanges.isChangeEnabled(DUMP_IGNORES_SPECIAL_ARGS);
             }
         }
-        dump(prefix, fd, writer, args);
+
+        if (dumpInternalState) {
+            dump(prefix, fd, writer, args);
+        } else {
+            Log.i(TAG, "Not calling dump() on " + this + " because of special argument " + arg);
+        }
     }
 
     void dumpInner(@NonNull String prefix, @Nullable FileDescriptor fd,
@@ -7428,26 +7467,10 @@
         }
     }
 
-    private void dumpContentCaptureManager(String prefix, PrintWriter writer) {
-        getContentCaptureManager();
-        dumpLegacyDumpable(prefix, writer, ContentCaptureManager.DUMPABLE_NAME, /* args= */ null);
-    }
-
-    private void dumpUiTranslation(String prefix, PrintWriter writer) {
-        dumpLegacyDumpable(prefix, writer, UiTranslationController.DUMPABLE_NAME, /* args= */ null);
-    }
-
-    private void dumpAutofillManager(String prefix, PrintWriter writer, String[] args) {
-        dumpLegacyDumpable(prefix, writer, AutofillClientController.DUMPABLE_NAME, args);
-    }
-
-    private void dumpLegacyDumpable(@NonNull String prefix, @NonNull PrintWriter writer,
-            @NonNull String dumpableName, @Nullable String[] args) {
-        if (mDumpableContainer == null) {
-            writer.print(prefix); writer.print("no "); writer.println(dumpableName);
-            return;
-        }
-        mDumpableContainer.dumpOneDumpable(prefix, writer, dumpableName, args);
+    private void dumpLegacyDumpable(String prefix, PrintWriter writer, String legacyOption,
+            String dumpableName) {
+        writer.printf("%s%s option deprecated. Use %s %s instead\n", prefix, legacyOption,
+                DUMP_ARG_DUMP_DUMPABLE, dumpableName);
     }
 
     /**
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 294621e..9fe8e79 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -826,4 +826,14 @@
      * Register the bind service event listener callback.
      */
     public abstract void addBindServiceEventListener(@NonNull BindServiceEventListener listener);
+
+    /**
+     * Restart android.
+     */
+    public abstract void restart();
+
+    /**
+     * Returns some summary statistics of the current PendingIntent queue - sizes and counts.
+     */
+    public abstract List<PendingIntentStats> getPendingIntentStats();
 }
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index aa6c184..569fda9 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -456,7 +456,8 @@
      */
     protected void onStart() {
         if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true);
-        if (mContext != null && !WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+        if (mContext != null
+                && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
             // Add onBackPressed as default back behavior.
             mDefaultBackCallback = new OnBackInvokedCallback() {
                 @Override
@@ -703,7 +704,7 @@
         if ((keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE)
                 && event.isTracking()
                 && !event.isCanceled()
-                && WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+                && !WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
             onBackPressed();
             return true;
         }
diff --git a/core/java/android/app/IUiModeManager.aidl b/core/java/android/app/IUiModeManager.aidl
index 55afed2..2242224b 100644
--- a/core/java/android/app/IUiModeManager.aidl
+++ b/core/java/android/app/IUiModeManager.aidl
@@ -73,6 +73,7 @@
      * @param nightModeCustomType
      * @hide
      */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)")
     void setNightModeCustomType(int nightModeCustomType);
 
     /**
@@ -82,6 +83,7 @@
      * {@link #MODE_NIGHT_CUSTOM_TYPE_UNKNOWN}.
      * @hide
      */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)")
     int getNightModeCustomType();
 
     /**
@@ -113,6 +115,7 @@
      *         {@code nightModeCustomType}.
      * @hide
      */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)")
     boolean setNightModeActivatedForCustomMode(int nightModeCustom, boolean active);
 
     /**
diff --git a/core/java/android/window/IOnFpsCallbackListener.aidl b/core/java/android/app/PendingIntentStats.java
similarity index 63%
copy from core/java/android/window/IOnFpsCallbackListener.aidl
copy to core/java/android/app/PendingIntentStats.java
index 3091df3..111db3c 100644
--- a/core/java/android/window/IOnFpsCallbackListener.aidl
+++ b/core/java/android/app/PendingIntentStats.java
@@ -14,17 +14,20 @@
  * limitations under the License.
  */
 
-package android.window;
+package android.app;
 
 /**
+ * Data about pending intents - size and count, per UID that sent the intent.
  * @hide
  */
-oneway interface IOnFpsCallbackListener {
+public class PendingIntentStats {
+    public final int uid;
+    public final int count;
+    public final int sizeKb;
 
-    /**
-     * Reports the fps from the registered task
-     * @param fps The frame rate per second of the task that has the registered task id
-     *            and its children.
-     */
-    void onFpsReported(in float fps);
+    public PendingIntentStats(int uid, int count, int sizeKb) {
+        this.uid = uid;
+        this.count = count;
+        this.sizeKb = sizeKb;
+    }
 }
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index cfaffb1..ecab37d 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -244,7 +244,18 @@
     public static final int MODE_NIGHT_YES = 2;
 
     /**
-     * Granular types for {@link MODE_NIGHT_CUSTOM_TYPE_BEDTIME}
+     * Granular types for {@link #setNightModeCustomType(int)}
+     * @hide
+     */
+    @IntDef(prefix = { "MODE_NIGHT_CUSTOM_TYPE_" }, value = {
+            MODE_NIGHT_CUSTOM_TYPE_SCHEDULE,
+            MODE_NIGHT_CUSTOM_TYPE_BEDTIME,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NightModeCustomType {}
+
+    /**
+     * Granular types for {@link #getNightModeCustomType()}
      * @hide
      */
     @IntDef(prefix = { "MODE_NIGHT_CUSTOM_TYPE_" }, value = {
@@ -253,7 +264,7 @@
             MODE_NIGHT_CUSTOM_TYPE_BEDTIME,
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface NightModeCustomType {}
+    public @interface NightModeCustomReturnType {}
 
     /**
      * A granular type for {@link #MODE_NIGHT_CUSTOM} which is unknown.
@@ -539,6 +550,8 @@
      * {@code nightModeCustomType}.
      *
      * @param nightModeCustomType
+     * @throws IllegalArgumentException if passed an unsupported type to
+     *         {@code nightModeCustomType}.
      * @hide
      */
     @SystemApi
@@ -562,7 +575,7 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
-    public int getNightModeCustomType() {
+    public @NightModeCustomReturnType int getNightModeCustomType() {
         if (mService != null) {
             try {
                 return mService.getNightModeCustomType();
diff --git a/core/java/android/app/smartspace/SmartspaceTarget.java b/core/java/android/app/smartspace/SmartspaceTarget.java
index 78f51be..fd7088f 100644
--- a/core/java/android/app/smartspace/SmartspaceTarget.java
+++ b/core/java/android/app/smartspace/SmartspaceTarget.java
@@ -20,7 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
-import android.app.smartspace.uitemplatedata.SmartspaceDefaultUiTemplateData;
+import android.app.smartspace.uitemplatedata.BaseTemplateData;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.net.Uri;
@@ -133,7 +133,7 @@
     private final AppWidgetProviderInfo mWidget;
 
     @Nullable
-    private final SmartspaceDefaultUiTemplateData mTemplateData;
+    private final BaseTemplateData mTemplateData;
 
     public static final int FEATURE_UNDEFINED = 0;
     public static final int FEATURE_WEATHER = 1;
@@ -194,15 +194,25 @@
     }
 
     public static final int UI_TEMPLATE_UNDEFINED = 0;
+    // Default template whose data is represented by {@link BaseTemplateData}. The default
+    // template is also a base card for the other types of templates.
     public static final int UI_TEMPLATE_DEFAULT = 1;
+    // Sub-image template whose data is represented by {@link SubImageTemplateData}
     public static final int UI_TEMPLATE_SUB_IMAGE = 2;
+    // Sub-list template whose data is represented by {@link SubListTemplateData}
     public static final int UI_TEMPLATE_SUB_LIST = 3;
+    // Carousel template whose data is represented by {@link CarouselTemplateData}
     public static final int UI_TEMPLATE_CAROUSEL = 4;
+    // Head-to-head template whose data is represented by {@link HeadToHeadTemplateData}
     public static final int UI_TEMPLATE_HEAD_TO_HEAD = 5;
+    // Combined-cards template whose data is represented by {@link CombinedCardsTemplateData}
     public static final int UI_TEMPLATE_COMBINED_CARDS = 6;
+    // Sub-card template whose data is represented by {@link SubCardTemplateData}
     public static final int UI_TEMPLATE_SUB_CARD = 7;
 
     /**
+     * The types of the Smartspace ui templates.
+     *
      * @hide
      */
     @IntDef(prefix = {"UI_TEMPLATE_"}, value = {
@@ -237,7 +247,7 @@
         this.mAssociatedSmartspaceTargetId = in.readString();
         this.mSliceUri = in.readTypedObject(Uri.CREATOR);
         this.mWidget = in.readTypedObject(AppWidgetProviderInfo.CREATOR);
-        this.mTemplateData = in.readTypedObject(SmartspaceDefaultUiTemplateData.CREATOR);
+        this.mTemplateData = in.readTypedObject(BaseTemplateData.CREATOR);
     }
 
     private SmartspaceTarget(String smartspaceTargetId,
@@ -248,7 +258,7 @@
             boolean shouldShowExpanded, String sourceNotificationKey,
             ComponentName componentName, UserHandle userHandle,
             String associatedSmartspaceTargetId, Uri sliceUri,
-            AppWidgetProviderInfo widget, SmartspaceDefaultUiTemplateData templateData) {
+            AppWidgetProviderInfo widget, BaseTemplateData templateData) {
         mSmartspaceTargetId = smartspaceTargetId;
         mHeaderAction = headerAction;
         mBaseAction = baseAction;
@@ -406,7 +416,7 @@
      * Returns the UI template data.
      */
     @Nullable
-    public SmartspaceDefaultUiTemplateData getTemplateData() {
+    public BaseTemplateData getTemplateData() {
         return mTemplateData;
     }
 
@@ -536,7 +546,7 @@
         private String mAssociatedSmartspaceTargetId;
         private Uri mSliceUri;
         private AppWidgetProviderInfo mWidget;
-        private SmartspaceDefaultUiTemplateData mTemplateData;
+        private BaseTemplateData mTemplateData;
 
         /**
          * A builder for {@link SmartspaceTarget}.
@@ -689,7 +699,7 @@
          */
         @NonNull
         public Builder setTemplateData(
-                @Nullable SmartspaceDefaultUiTemplateData templateData) {
+                @Nullable BaseTemplateData templateData) {
             mTemplateData = templateData;
             return this;
         }
diff --git a/core/java/android/app/smartspace/SmartspaceUtils.java b/core/java/android/app/smartspace/SmartspaceUtils.java
index 4545f43..cad4453 100644
--- a/core/java/android/app/smartspace/SmartspaceUtils.java
+++ b/core/java/android/app/smartspace/SmartspaceUtils.java
@@ -17,7 +17,7 @@
 package android.app.smartspace;
 
 import android.annotation.Nullable;
-import android.app.smartspace.uitemplatedata.SmartspaceText;
+import android.app.smartspace.uitemplatedata.Text;
 import android.text.TextUtils;
 
 /**
@@ -30,13 +30,13 @@
     private SmartspaceUtils() {
     }
 
-    /** Returns true if the passed in {@link SmartspaceText} is null or its content is empty. */
-    public static boolean isEmpty(@Nullable SmartspaceText text) {
+    /** Returns true if the passed in {@link Text} is null or its content is empty. */
+    public static boolean isEmpty(@Nullable Text text) {
         return text == null || TextUtils.isEmpty(text.getText());
     }
 
-    /** Returns true if the passed-in {@link SmartspaceText}s are equal. */
-    public static boolean isEqual(@Nullable SmartspaceText text1, @Nullable SmartspaceText text2) {
+    /** Returns true if the passed-in {@link Text}s are equal. */
+    public static boolean isEqual(@Nullable Text text1, @Nullable Text text2) {
         if (text1 == null && text2 == null) return true;
         if (text1 == null || text2 == null) return false;
         return text1.equals(text2);
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceDefaultUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/BaseTemplateData.java
similarity index 69%
rename from core/java/android/app/smartspace/uitemplatedata/SmartspaceDefaultUiTemplateData.java
rename to core/java/android/app/smartspace/uitemplatedata/BaseTemplateData.java
index a7ac9c7..a07af68 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceDefaultUiTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/BaseTemplateData.java
@@ -29,12 +29,19 @@
 
 /**
  * Holds all the relevant data needed to render a Smartspace card with the default Ui Template.
+ * <ul>
+ *     <li> title_text (may contain a start drawable) </li>
+ *     <li> subtitle_text (may contain a start drawable) . supplemental_subtitle_text (may
+ *     contain a start drawable) </li>
+ *     <li> next_alarm_text (contain a start drawable) + supplemental_alarm_text .
+ *     do_not_disturb_view </li>
+ * </ul>
  *
  * @hide
  */
 @SystemApi
 @SuppressLint("ParcelNotFinal")
-public class SmartspaceDefaultUiTemplateData implements Parcelable {
+public class BaseTemplateData implements Parcelable {
 
     /**
      * {@link UiTemplateType} indicating the template type of this template data.
@@ -49,17 +56,17 @@
      * will be used, which has its own tap action applied to the title area.
      */
     @Nullable
-    private final SmartspaceText mTitleText;
+    private final Text mTitleText;
 
     @Nullable
-    private final SmartspaceIcon mTitleIcon;
+    private final Icon mTitleIcon;
 
     /** Subtitle text and icon are shown at the second row. */
     @Nullable
-    private final SmartspaceText mSubtitleText;
+    private final Text mSubtitleText;
 
     @Nullable
-    private final SmartspaceIcon mSubtitleIcon;
+    private final Icon mSubtitleIcon;
 
     /**
      * Primary tap action for the entire card, including the blank spaces, except: 1. When title is
@@ -67,59 +74,59 @@
      * action if being set; 3. Secondary card uses its own tap action if being set.
      */
     @Nullable
-    private final SmartspaceTapAction mPrimaryTapAction;
+    private final TapAction mPrimaryTapAction;
 
     /**
      * Supplemental subtitle text and icon are shown at the second row following the subtitle text.
      * Mainly used for weather info on non-weather card.
      */
     @Nullable
-    private final SmartspaceText mSupplementalSubtitleText;
+    private final Text mSupplementalSubtitleText;
 
     @Nullable
-    private final SmartspaceIcon mSupplementalSubtitleIcon;
+    private final Icon mSupplementalSubtitleIcon;
 
     /**
      * Tap action for the supplemental subtitle's text and icon. Will use the primary tap action if
      * not being set.
      */
     @Nullable
-    private final SmartspaceTapAction mSupplementalSubtitleTapAction;
+    private final TapAction mSupplementalSubtitleTapAction;
 
     /**
      * Supplemental alarm text is specifically used for holiday alarm, which is appended to "next
      * alarm".
      */
     @Nullable
-    private final SmartspaceText mSupplementalAlarmText;
+    private final Text mSupplementalAlarmText;
 
-    SmartspaceDefaultUiTemplateData(@NonNull Parcel in) {
+    BaseTemplateData(@NonNull Parcel in) {
         mTemplateType = in.readInt();
-        mTitleText = in.readTypedObject(SmartspaceText.CREATOR);
-        mTitleIcon = in.readTypedObject(SmartspaceIcon.CREATOR);
-        mSubtitleText = in.readTypedObject(SmartspaceText.CREATOR);
-        mSubtitleIcon = in.readTypedObject(SmartspaceIcon.CREATOR);
-        mPrimaryTapAction = in.readTypedObject(SmartspaceTapAction.CREATOR);
-        mSupplementalSubtitleText = in.readTypedObject(SmartspaceText.CREATOR);
-        mSupplementalSubtitleIcon = in.readTypedObject(SmartspaceIcon.CREATOR);
-        mSupplementalSubtitleTapAction = in.readTypedObject(SmartspaceTapAction.CREATOR);
-        mSupplementalAlarmText = in.readTypedObject(SmartspaceText.CREATOR);
+        mTitleText = in.readTypedObject(Text.CREATOR);
+        mTitleIcon = in.readTypedObject(Icon.CREATOR);
+        mSubtitleText = in.readTypedObject(Text.CREATOR);
+        mSubtitleIcon = in.readTypedObject(Icon.CREATOR);
+        mPrimaryTapAction = in.readTypedObject(TapAction.CREATOR);
+        mSupplementalSubtitleText = in.readTypedObject(Text.CREATOR);
+        mSupplementalSubtitleIcon = in.readTypedObject(Icon.CREATOR);
+        mSupplementalSubtitleTapAction = in.readTypedObject(TapAction.CREATOR);
+        mSupplementalAlarmText = in.readTypedObject(Text.CREATOR);
     }
 
     /**
      * Should ONLY used by subclasses. For the general instance creation, please use
      * SmartspaceDefaultUiTemplateData.Builder.
      */
-    SmartspaceDefaultUiTemplateData(@UiTemplateType int templateType,
-            @Nullable SmartspaceText titleText,
-            @Nullable SmartspaceIcon titleIcon,
-            @Nullable SmartspaceText subtitleText,
-            @Nullable SmartspaceIcon subtitleIcon,
-            @Nullable SmartspaceTapAction primaryTapAction,
-            @Nullable SmartspaceText supplementalSubtitleText,
-            @Nullable SmartspaceIcon supplementalSubtitleIcon,
-            @Nullable SmartspaceTapAction supplementalSubtitleTapAction,
-            @Nullable SmartspaceText supplementalAlarmText) {
+    BaseTemplateData(@UiTemplateType int templateType,
+            @Nullable Text titleText,
+            @Nullable Icon titleIcon,
+            @Nullable Text subtitleText,
+            @Nullable Icon subtitleIcon,
+            @Nullable TapAction primaryTapAction,
+            @Nullable Text supplementalSubtitleText,
+            @Nullable Icon supplementalSubtitleIcon,
+            @Nullable TapAction supplementalSubtitleTapAction,
+            @Nullable Text supplementalAlarmText) {
         mTemplateType = templateType;
         mTitleText = titleText;
         mTitleIcon = titleIcon;
@@ -132,53 +139,63 @@
         mSupplementalAlarmText = supplementalAlarmText;
     }
 
+    /** Returns the template type. By default is UNDEFINED. */
     @UiTemplateType
     public int getTemplateType() {
         return mTemplateType;
     }
 
+    /** Returns the title's text. */
     @Nullable
-    public SmartspaceText getTitleText() {
+    public Text getTitleText() {
         return mTitleText;
     }
 
+    /** Returns the title's icon. */
     @Nullable
-    public SmartspaceIcon getTitleIcon() {
+    public Icon getTitleIcon() {
         return mTitleIcon;
     }
 
+    /** Returns the subtitle's text. */
     @Nullable
-    public SmartspaceText getSubtitleText() {
+    public Text getSubtitleText() {
         return mSubtitleText;
     }
 
+    /** Returns the subtitle's icon. */
     @Nullable
-    public SmartspaceIcon getSubtitleIcon() {
+    public Icon getSubtitleIcon() {
         return mSubtitleIcon;
     }
 
+    /** Returns the card's primary tap action. */
     @Nullable
-    public SmartspaceTapAction getPrimaryTapAction() {
+    public TapAction getPrimaryTapAction() {
         return mPrimaryTapAction;
     }
 
+    /** Returns the supplemental subtitle's text. */
     @Nullable
-    public SmartspaceText getSupplementalSubtitleText() {
+    public Text getSupplementalSubtitleText() {
         return mSupplementalSubtitleText;
     }
 
+    /** Returns the supplemental subtitle's icon. */
     @Nullable
-    public SmartspaceIcon getSupplementalSubtitleIcon() {
+    public Icon getSupplementalSubtitleIcon() {
         return mSupplementalSubtitleIcon;
     }
 
+    /** Returns the supplemental subtitle's tap action. Can be null if not being set. */
     @Nullable
-    public SmartspaceTapAction getSupplementalSubtitleTapAction() {
+    public TapAction getSupplementalSubtitleTapAction() {
         return mSupplementalSubtitleTapAction;
     }
 
+    /** Returns the supplemental alarm text. */
     @Nullable
-    public SmartspaceText getSupplementalAlarmText() {
+    public Text getSupplementalAlarmText() {
         return mSupplementalAlarmText;
     }
 
@@ -186,16 +203,16 @@
      * @see Parcelable.Creator
      */
     @NonNull
-    public static final Creator<SmartspaceDefaultUiTemplateData> CREATOR =
-            new Creator<SmartspaceDefaultUiTemplateData>() {
+    public static final Creator<BaseTemplateData> CREATOR =
+            new Creator<BaseTemplateData>() {
                 @Override
-                public SmartspaceDefaultUiTemplateData createFromParcel(Parcel in) {
-                    return new SmartspaceDefaultUiTemplateData(in);
+                public BaseTemplateData createFromParcel(Parcel in) {
+                    return new BaseTemplateData(in);
                 }
 
                 @Override
-                public SmartspaceDefaultUiTemplateData[] newArray(int size) {
-                    return new SmartspaceDefaultUiTemplateData[size];
+                public BaseTemplateData[] newArray(int size) {
+                    return new BaseTemplateData[size];
                 }
             };
 
@@ -221,8 +238,8 @@
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
-        if (!(o instanceof SmartspaceDefaultUiTemplateData)) return false;
-        SmartspaceDefaultUiTemplateData that = (SmartspaceDefaultUiTemplateData) o;
+        if (!(o instanceof BaseTemplateData)) return false;
+        BaseTemplateData that = (BaseTemplateData) o;
         return mTemplateType == that.mTemplateType && SmartspaceUtils.isEqual(mTitleText,
                 that.mTitleText)
                 && Objects.equals(mTitleIcon, that.mTitleIcon)
@@ -261,7 +278,7 @@
     }
 
     /**
-     * A builder for {@link SmartspaceDefaultUiTemplateData} object.
+     * A builder for {@link BaseTemplateData} object.
      *
      * @hide
      */
@@ -270,18 +287,18 @@
     public static class Builder {
         @UiTemplateType
         private final int mTemplateType;
-        private SmartspaceText mTitleText;
-        private SmartspaceIcon mTitleIcon;
-        private SmartspaceText mSubtitleText;
-        private SmartspaceIcon mSubtitleIcon;
-        private SmartspaceTapAction mPrimaryTapAction;
-        private SmartspaceText mSupplementalSubtitleText;
-        private SmartspaceIcon mSupplementalSubtitleIcon;
-        private SmartspaceTapAction mSupplementalSubtitleTapAction;
-        private SmartspaceText mSupplementalAlarmText;
+        private Text mTitleText;
+        private Icon mTitleIcon;
+        private Text mSubtitleText;
+        private Icon mSubtitleIcon;
+        private TapAction mPrimaryTapAction;
+        private Text mSupplementalSubtitleText;
+        private Icon mSupplementalSubtitleIcon;
+        private TapAction mSupplementalSubtitleTapAction;
+        private Text mSupplementalAlarmText;
 
         /**
-         * A builder for {@link SmartspaceDefaultUiTemplateData}.
+         * A builder for {@link BaseTemplateData}.
          *
          * @param templateType the {@link UiTemplateType} of this template data.
          */
@@ -299,63 +316,63 @@
         /** Should ONLY be used by the subclasses */
         @Nullable
         @SuppressLint("GetterOnBuilder")
-        SmartspaceText getTitleText() {
+        Text getTitleText() {
             return mTitleText;
         }
 
         /** Should ONLY be used by the subclasses */
         @Nullable
         @SuppressLint("GetterOnBuilder")
-        SmartspaceIcon getTitleIcon() {
+        Icon getTitleIcon() {
             return mTitleIcon;
         }
 
         /** Should ONLY be used by the subclasses */
         @Nullable
         @SuppressLint("GetterOnBuilder")
-        SmartspaceText getSubtitleText() {
+        Text getSubtitleText() {
             return mSubtitleText;
         }
 
         /** Should ONLY be used by the subclasses */
         @Nullable
         @SuppressLint("GetterOnBuilder")
-        SmartspaceIcon getSubtitleIcon() {
+        Icon getSubtitleIcon() {
             return mSubtitleIcon;
         }
 
         /** Should ONLY be used by the subclasses */
         @Nullable
         @SuppressLint("GetterOnBuilder")
-        SmartspaceTapAction getPrimaryTapAction() {
+        TapAction getPrimaryTapAction() {
             return mPrimaryTapAction;
         }
 
         /** Should ONLY be used by the subclasses */
         @Nullable
         @SuppressLint("GetterOnBuilder")
-        SmartspaceText getSupplementalSubtitleText() {
+        Text getSupplementalSubtitleText() {
             return mSupplementalSubtitleText;
         }
 
         /** Should ONLY be used by the subclasses */
         @Nullable
         @SuppressLint("GetterOnBuilder")
-        SmartspaceIcon getSupplementalSubtitleIcon() {
+        Icon getSupplementalSubtitleIcon() {
             return mSupplementalSubtitleIcon;
         }
 
         /** Should ONLY be used by the subclasses */
         @Nullable
         @SuppressLint("GetterOnBuilder")
-        SmartspaceTapAction getSupplementalSubtitleTapAction() {
+        TapAction getSupplementalSubtitleTapAction() {
             return mSupplementalSubtitleTapAction;
         }
 
         /** Should ONLY be used by the subclasses */
         @Nullable
         @SuppressLint("GetterOnBuilder")
-        SmartspaceText getSupplementalAlarmText() {
+        Text getSupplementalAlarmText() {
             return mSupplementalAlarmText;
         }
 
@@ -363,7 +380,7 @@
          * Sets the card title.
          */
         @NonNull
-        public Builder setTitleText(@NonNull SmartspaceText titleText) {
+        public Builder setTitleText(@NonNull Text titleText) {
             mTitleText = titleText;
             return this;
         }
@@ -372,7 +389,7 @@
          * Sets the card title icon.
          */
         @NonNull
-        public Builder setTitleIcon(@NonNull SmartspaceIcon titleIcon) {
+        public Builder setTitleIcon(@NonNull Icon titleIcon) {
             mTitleIcon = titleIcon;
             return this;
         }
@@ -381,7 +398,7 @@
          * Sets the card subtitle.
          */
         @NonNull
-        public Builder setSubtitleText(@NonNull SmartspaceText subtitleText) {
+        public Builder setSubtitleText(@NonNull Text subtitleText) {
             mSubtitleText = subtitleText;
             return this;
         }
@@ -390,7 +407,7 @@
          * Sets the card subtitle icon.
          */
         @NonNull
-        public Builder setSubtitleIcon(@NonNull SmartspaceIcon subtitleIcon) {
+        public Builder setSubtitleIcon(@NonNull Icon subtitleIcon) {
             mSubtitleIcon = subtitleIcon;
             return this;
         }
@@ -399,7 +416,7 @@
          * Sets the card primary tap action.
          */
         @NonNull
-        public Builder setPrimaryTapAction(@NonNull SmartspaceTapAction primaryTapAction) {
+        public Builder setPrimaryTapAction(@NonNull TapAction primaryTapAction) {
             mPrimaryTapAction = primaryTapAction;
             return this;
         }
@@ -409,7 +426,7 @@
          */
         @NonNull
         public Builder setSupplementalSubtitleText(
-                @NonNull SmartspaceText supplementalSubtitleText) {
+                @NonNull Text supplementalSubtitleText) {
             mSupplementalSubtitleText = supplementalSubtitleText;
             return this;
         }
@@ -419,7 +436,7 @@
          */
         @NonNull
         public Builder setSupplementalSubtitleIcon(
-                @NonNull SmartspaceIcon supplementalSubtitleIcon) {
+                @NonNull Icon supplementalSubtitleIcon) {
             mSupplementalSubtitleIcon = supplementalSubtitleIcon;
             return this;
         }
@@ -431,7 +448,7 @@
          */
         @NonNull
         public Builder setSupplementalSubtitleTapAction(
-                @NonNull SmartspaceTapAction supplementalSubtitleTapAction) {
+                @NonNull TapAction supplementalSubtitleTapAction) {
             mSupplementalSubtitleTapAction = supplementalSubtitleTapAction;
             return this;
         }
@@ -440,7 +457,7 @@
          * Sets the supplemental alarm text.
          */
         @NonNull
-        public Builder setSupplementalAlarmText(@NonNull SmartspaceText supplementalAlarmText) {
+        public Builder setSupplementalAlarmText(@NonNull Text supplementalAlarmText) {
             mSupplementalAlarmText = supplementalAlarmText;
             return this;
         }
@@ -449,8 +466,8 @@
          * Builds a new SmartspaceDefaultUiTemplateData instance.
          */
         @NonNull
-        public SmartspaceDefaultUiTemplateData build() {
-            return new SmartspaceDefaultUiTemplateData(mTemplateType, mTitleText, mTitleIcon,
+        public BaseTemplateData build() {
+            return new BaseTemplateData(mTemplateType, mTitleText, mTitleIcon,
                     mSubtitleText, mSubtitleIcon, mPrimaryTapAction, mSupplementalSubtitleText,
                     mSupplementalSubtitleIcon, mSupplementalSubtitleTapAction,
                     mSupplementalAlarmText);
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceCarouselUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/CarouselTemplateData.java
similarity index 69%
rename from core/java/android/app/smartspace/uitemplatedata/SmartspaceCarouselUiTemplateData.java
rename to core/java/android/app/smartspace/uitemplatedata/CarouselTemplateData.java
index e996056..feb1c34 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceCarouselUiTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/CarouselTemplateData.java
@@ -30,10 +30,16 @@
 /**
  * Holds all the relevant data needed to render a Smartspace card with the carousel Ui Template.
  *
+ * This template will add a sub-card displaying a list of carousel items within the default-template
+ * card:
+ * <ul>
+ *     <li> carouselItem1, carouselItem2, carouselItem3... </li>
+ * </ul>
+ *
  * @hide
  */
 @SystemApi
-public final class SmartspaceCarouselUiTemplateData extends SmartspaceDefaultUiTemplateData {
+public final class CarouselTemplateData extends BaseTemplateData {
 
     /** Lists of {@link CarouselItem}. */
     @NonNull
@@ -41,26 +47,26 @@
 
     /** Tap action for the entire carousel secondary card, including the blank space */
     @Nullable
-    private final SmartspaceTapAction mCarouselAction;
+    private final TapAction mCarouselAction;
 
-    SmartspaceCarouselUiTemplateData(@NonNull Parcel in) {
+    CarouselTemplateData(@NonNull Parcel in) {
         super(in);
         mCarouselItems = in.createTypedArrayList(CarouselItem.CREATOR);
-        mCarouselAction = in.readTypedObject(SmartspaceTapAction.CREATOR);
+        mCarouselAction = in.readTypedObject(TapAction.CREATOR);
     }
 
-    private SmartspaceCarouselUiTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
-            @Nullable SmartspaceText titleText,
-            @Nullable SmartspaceIcon titleIcon,
-            @Nullable SmartspaceText subtitleText,
-            @Nullable SmartspaceIcon subTitleIcon,
-            @Nullable SmartspaceTapAction primaryTapAction,
-            @Nullable SmartspaceText supplementalSubtitleText,
-            @Nullable SmartspaceIcon supplementalSubtitleIcon,
-            @Nullable SmartspaceTapAction supplementalSubtitleTapAction,
-            @Nullable SmartspaceText supplementalAlarmText,
+    private CarouselTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
+            @Nullable Text titleText,
+            @Nullable Icon titleIcon,
+            @Nullable Text subtitleText,
+            @Nullable Icon subTitleIcon,
+            @Nullable TapAction primaryTapAction,
+            @Nullable Text supplementalSubtitleText,
+            @Nullable Icon supplementalSubtitleIcon,
+            @Nullable TapAction supplementalSubtitleTapAction,
+            @Nullable Text supplementalAlarmText,
             @NonNull List<CarouselItem> carouselItems,
-            @Nullable SmartspaceTapAction carouselAction) {
+            @Nullable TapAction carouselAction) {
         super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction,
                 supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction,
                 supplementalAlarmText);
@@ -68,13 +74,15 @@
         mCarouselAction = carouselAction;
     }
 
+    /** Returns the list of {@link CarouselItem}. Can be empty if not being set. */
     @NonNull
     public List<CarouselItem> getCarouselItems() {
         return mCarouselItems;
     }
 
+    /** Returns the card's tap action. */
     @Nullable
-    public SmartspaceTapAction getCarouselAction() {
+    public TapAction getCarouselAction() {
         return mCarouselAction;
     }
 
@@ -82,16 +90,16 @@
      * @see Parcelable.Creator
      */
     @NonNull
-    public static final Creator<SmartspaceCarouselUiTemplateData> CREATOR =
-            new Creator<SmartspaceCarouselUiTemplateData>() {
+    public static final Creator<CarouselTemplateData> CREATOR =
+            new Creator<CarouselTemplateData>() {
                 @Override
-                public SmartspaceCarouselUiTemplateData createFromParcel(Parcel in) {
-                    return new SmartspaceCarouselUiTemplateData(in);
+                public CarouselTemplateData createFromParcel(Parcel in) {
+                    return new CarouselTemplateData(in);
                 }
 
                 @Override
-                public SmartspaceCarouselUiTemplateData[] newArray(int size) {
-                    return new SmartspaceCarouselUiTemplateData[size];
+                public CarouselTemplateData[] newArray(int size) {
+                    return new CarouselTemplateData[size];
                 }
             };
 
@@ -111,9 +119,9 @@
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
-        if (!(o instanceof SmartspaceCarouselUiTemplateData)) return false;
+        if (!(o instanceof CarouselTemplateData)) return false;
         if (!super.equals(o)) return false;
-        SmartspaceCarouselUiTemplateData that = (SmartspaceCarouselUiTemplateData) o;
+        CarouselTemplateData that = (CarouselTemplateData) o;
         return mCarouselItems.equals(that.mCarouselItems) && Objects.equals(mCarouselAction,
                 that.mCarouselAction);
     }
@@ -132,18 +140,18 @@
     }
 
     /**
-     * A builder for {@link SmartspaceCarouselUiTemplateData} object.
+     * A builder for {@link CarouselTemplateData} object.
      *
      * @hide
      */
     @SystemApi
-    public static final class Builder extends SmartspaceDefaultUiTemplateData.Builder {
+    public static final class Builder extends BaseTemplateData.Builder {
 
         private final List<CarouselItem> mCarouselItems;
-        private SmartspaceTapAction mCarouselAction;
+        private TapAction mCarouselAction;
 
         /**
-         * A builder for {@link SmartspaceCarouselUiTemplateData}.
+         * A builder for {@link CarouselTemplateData}.
          */
         public Builder(@NonNull List<CarouselItem> carouselItems) {
             super(SmartspaceTarget.UI_TEMPLATE_CAROUSEL);
@@ -154,23 +162,23 @@
          * Sets the card tap action.
          */
         @NonNull
-        public Builder setCarouselAction(@NonNull SmartspaceTapAction carouselAction) {
+        public Builder setCarouselAction(@NonNull TapAction carouselAction) {
             mCarouselAction = carouselAction;
             return this;
         }
 
         /**
-         * Builds a new SmartspaceCarouselUiTemplateData instance.
+         * Builds a new {@link CarouselTemplateData} instance.
          *
          * @throws IllegalStateException if the carousel data is invalid.
          */
         @NonNull
-        public SmartspaceCarouselUiTemplateData build() {
+        public CarouselTemplateData build() {
             if (mCarouselItems.isEmpty()) {
                 throw new IllegalStateException("Carousel data is empty");
             }
 
-            return new SmartspaceCarouselUiTemplateData(getTemplateType(), getTitleText(),
+            return new CarouselTemplateData(getTemplateType(), getTitleText(),
                     getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(),
                     getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
                     getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mCarouselItems,
@@ -178,37 +186,45 @@
         }
     }
 
-    /** Holds all the relevant data needed to render a carousel item. */
+    /**
+     * Holds all the relevant data needed to render a carousel item.
+     *
+     * <ul>
+     *     <li> upper text </li>
+     *     <li> image </li>
+     *     <li> lower text </li>
+     * </ul>
+     */
     public static final class CarouselItem implements Parcelable {
 
         /** Text which is above the image item. */
         @Nullable
-        private final SmartspaceText mUpperText;
+        private final Text mUpperText;
 
         /** Image item. Can be empty. */
         @Nullable
-        private final SmartspaceIcon mImage;
+        private final Icon mImage;
 
         /** Text which is under the image item. */
         @Nullable
-        private final SmartspaceText mLowerText;
+        private final Text mLowerText;
 
         /**
          * Tap action for this {@link CarouselItem} instance. {@code mCarouselAction} is used if not
          * being set.
          */
         @Nullable
-        private final SmartspaceTapAction mTapAction;
+        private final TapAction mTapAction;
 
         CarouselItem(@NonNull Parcel in) {
-            mUpperText = in.readTypedObject(SmartspaceText.CREATOR);
-            mImage = in.readTypedObject(SmartspaceIcon.CREATOR);
-            mLowerText = in.readTypedObject(SmartspaceText.CREATOR);
-            mTapAction = in.readTypedObject(SmartspaceTapAction.CREATOR);
+            mUpperText = in.readTypedObject(Text.CREATOR);
+            mImage = in.readTypedObject(Icon.CREATOR);
+            mLowerText = in.readTypedObject(Text.CREATOR);
+            mTapAction = in.readTypedObject(TapAction.CREATOR);
         }
 
-        private CarouselItem(@Nullable SmartspaceText upperText, @Nullable SmartspaceIcon image,
-                @Nullable SmartspaceText lowerText, @Nullable SmartspaceTapAction tapAction) {
+        private CarouselItem(@Nullable Text upperText, @Nullable Icon image,
+                @Nullable Text lowerText, @Nullable TapAction tapAction) {
             mUpperText = upperText;
             mImage = image;
             mLowerText = lowerText;
@@ -216,22 +232,22 @@
         }
 
         @Nullable
-        public SmartspaceText getUpperText() {
+        public Text getUpperText() {
             return mUpperText;
         }
 
         @Nullable
-        public SmartspaceIcon getImage() {
+        public Icon getImage() {
             return mImage;
         }
 
         @Nullable
-        public SmartspaceText getLowerText() {
+        public Text getLowerText() {
             return mLowerText;
         }
 
         @Nullable
-        public SmartspaceTapAction getTapAction() {
+        public TapAction getTapAction() {
             return mTapAction;
         }
 
@@ -299,16 +315,16 @@
         @SystemApi
         public static final class Builder {
 
-            private SmartspaceText mUpperText;
-            private SmartspaceIcon mImage;
-            private SmartspaceText mLowerText;
-            private SmartspaceTapAction mTapAction;
+            private Text mUpperText;
+            private Icon mImage;
+            private Text mLowerText;
+            private TapAction mTapAction;
 
             /**
              * Sets the upper text.
              */
             @NonNull
-            public Builder setUpperText(@Nullable SmartspaceText upperText) {
+            public Builder setUpperText(@Nullable Text upperText) {
                 mUpperText = upperText;
                 return this;
             }
@@ -317,7 +333,7 @@
              * Sets the image.
              */
             @NonNull
-            public Builder setImage(@Nullable SmartspaceIcon image) {
+            public Builder setImage(@Nullable Icon image) {
                 mImage = image;
                 return this;
             }
@@ -327,7 +343,7 @@
              * Sets the lower text.
              */
             @NonNull
-            public Builder setLowerText(@Nullable SmartspaceText lowerText) {
+            public Builder setLowerText(@Nullable Text lowerText) {
                 mLowerText = lowerText;
                 return this;
             }
@@ -336,7 +352,7 @@
              * Sets the tap action.
              */
             @NonNull
-            public Builder setTapAction(@Nullable SmartspaceTapAction tapAction) {
+            public Builder setTapAction(@Nullable TapAction tapAction) {
                 mTapAction = tapAction;
                 return this;
             }
diff --git a/core/java/android/app/smartspace/uitemplatedata/CombinedCardsTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/CombinedCardsTemplateData.java
new file mode 100644
index 0000000..13091e2
--- /dev/null
+++ b/core/java/android/app/smartspace/uitemplatedata/CombinedCardsTemplateData.java
@@ -0,0 +1,160 @@
+/*
+ * 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.smartspace.uitemplatedata;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.smartspace.SmartspaceTarget;
+import android.os.Parcel;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Holds all the relevant data needed to render a Smartspace card with the combined-card Ui
+ * Template.
+ *
+ * We only support adding a 1 sub-list card combined with 1 sub-card card (may expand our supported
+ * combinations in the future) within the default-template card:
+ *
+ * <ul>
+ *     <li> sub-list card, sub-card card </li>
+ * </ul>
+ *
+ * @hide
+ */
+@SystemApi
+public final class CombinedCardsTemplateData extends BaseTemplateData {
+
+    /** A list of secondary cards. */
+    @NonNull
+    private final List<BaseTemplateData> mCombinedCardDataList;
+
+    CombinedCardsTemplateData(@NonNull Parcel in) {
+        super(in);
+        mCombinedCardDataList = in.createTypedArrayList(BaseTemplateData.CREATOR);
+    }
+
+    private CombinedCardsTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
+            @Nullable Text titleText,
+            @Nullable Icon titleIcon,
+            @Nullable Text subtitleText,
+            @Nullable Icon subTitleIcon,
+            @Nullable TapAction primaryTapAction,
+            @Nullable Text supplementalSubtitleText,
+            @Nullable Icon supplementalSubtitleIcon,
+            @Nullable TapAction supplementalSubtitleTapAction,
+            @Nullable Text supplementalAlarmText,
+            @NonNull List<BaseTemplateData> combinedCardDataList) {
+        super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction,
+                supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction,
+                supplementalAlarmText);
+        mCombinedCardDataList = combinedCardDataList;
+    }
+
+    /** Returns the list of secondary cards. Can be null if not being set. */
+    @NonNull
+    public List<BaseTemplateData> getCombinedCardDataList() {
+        return mCombinedCardDataList;
+    }
+
+    /**
+     * @see Parcelable.Creator
+     */
+    @NonNull
+    public static final Creator<CombinedCardsTemplateData> CREATOR =
+            new Creator<CombinedCardsTemplateData>() {
+                @Override
+                public CombinedCardsTemplateData createFromParcel(Parcel in) {
+                    return new CombinedCardsTemplateData(in);
+                }
+
+                @Override
+                public CombinedCardsTemplateData[] newArray(int size) {
+                    return new CombinedCardsTemplateData[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        super.writeToParcel(out, flags);
+        out.writeTypedList(mCombinedCardDataList);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof CombinedCardsTemplateData)) return false;
+        if (!super.equals(o)) return false;
+        CombinedCardsTemplateData that = (CombinedCardsTemplateData) o;
+        return mCombinedCardDataList.equals(that.mCombinedCardDataList);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), mCombinedCardDataList);
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + " + SmartspaceCombinedCardsUiTemplateData{"
+                + "mCombinedCardDataList=" + mCombinedCardDataList
+                + '}';
+    }
+
+    /**
+     * A builder for {@link CombinedCardsTemplateData} object.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder extends BaseTemplateData.Builder {
+
+        private final List<BaseTemplateData> mCombinedCardDataList;
+
+        /**
+         * A builder for {@link CombinedCardsTemplateData}.
+         */
+        public Builder(@NonNull List<BaseTemplateData> combinedCardDataList) {
+            super(SmartspaceTarget.UI_TEMPLATE_COMBINED_CARDS);
+            mCombinedCardDataList = Objects.requireNonNull(combinedCardDataList);
+        }
+
+        /**
+         * Builds a new SmartspaceCombinedCardsUiTemplateData instance.
+         *
+         * @throws IllegalStateException if any required non-null field is null
+         */
+        @NonNull
+        public CombinedCardsTemplateData build() {
+            if (mCombinedCardDataList == null) {
+                throw new IllegalStateException("Please assign a value to all @NonNull args.");
+            }
+            return new CombinedCardsTemplateData(getTemplateType(), getTitleText(),
+                    getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(),
+                    getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
+                    getSupplementalSubtitleTapAction(), getSupplementalAlarmText(),
+                    mCombinedCardDataList);
+        }
+    }
+}
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceHeadToHeadUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/HeadToHeadTemplateData.java
similarity index 62%
rename from core/java/android/app/smartspace/uitemplatedata/SmartspaceHeadToHeadUiTemplateData.java
rename to core/java/android/app/smartspace/uitemplatedata/HeadToHeadTemplateData.java
index bcd12eb..eb56e93 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceHeadToHeadUiTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/HeadToHeadTemplateData.java
@@ -28,52 +28,59 @@
 /**
  * Holds all the relevant data needed to render a Smartspace card with the head-to-head Ui Template.
  *
+ * This template will add a head-to-head card within the default-template card:
+ * <ul>
+ *                     <li> head-to-head title </li>
+ *     <li> first-competitor icon       second-competitor icon </li>
+ *     <li> first-competitor text       second-competitor text </li>
+ * </ul>
+ *
  * @hide
  */
 @SystemApi
-public final class SmartspaceHeadToHeadUiTemplateData extends SmartspaceDefaultUiTemplateData {
+public final class HeadToHeadTemplateData extends BaseTemplateData {
 
     @Nullable
-    private final SmartspaceText mHeadToHeadTitle;
+    private final Text mHeadToHeadTitle;
     @Nullable
-    private final SmartspaceIcon mHeadToHeadFirstCompetitorIcon;
+    private final Icon mHeadToHeadFirstCompetitorIcon;
     @Nullable
-    private final SmartspaceIcon mHeadToHeadSecondCompetitorIcon;
+    private final Icon mHeadToHeadSecondCompetitorIcon;
     @Nullable
-    private final SmartspaceText mHeadToHeadFirstCompetitorText;
+    private final Text mHeadToHeadFirstCompetitorText;
     @Nullable
-    private final SmartspaceText mHeadToHeadSecondCompetitorText;
+    private final Text mHeadToHeadSecondCompetitorText;
 
     /** Tap action for the head-to-head secondary card. */
     @Nullable
-    private final SmartspaceTapAction mHeadToHeadAction;
+    private final TapAction mHeadToHeadAction;
 
-    SmartspaceHeadToHeadUiTemplateData(@NonNull Parcel in) {
+    HeadToHeadTemplateData(@NonNull Parcel in) {
         super(in);
-        mHeadToHeadTitle = in.readTypedObject(SmartspaceText.CREATOR);
-        mHeadToHeadFirstCompetitorIcon = in.readTypedObject(SmartspaceIcon.CREATOR);
-        mHeadToHeadSecondCompetitorIcon = in.readTypedObject(SmartspaceIcon.CREATOR);
-        mHeadToHeadFirstCompetitorText = in.readTypedObject(SmartspaceText.CREATOR);
-        mHeadToHeadSecondCompetitorText = in.readTypedObject(SmartspaceText.CREATOR);
-        mHeadToHeadAction = in.readTypedObject(SmartspaceTapAction.CREATOR);
+        mHeadToHeadTitle = in.readTypedObject(Text.CREATOR);
+        mHeadToHeadFirstCompetitorIcon = in.readTypedObject(Icon.CREATOR);
+        mHeadToHeadSecondCompetitorIcon = in.readTypedObject(Icon.CREATOR);
+        mHeadToHeadFirstCompetitorText = in.readTypedObject(Text.CREATOR);
+        mHeadToHeadSecondCompetitorText = in.readTypedObject(Text.CREATOR);
+        mHeadToHeadAction = in.readTypedObject(TapAction.CREATOR);
     }
 
-    private SmartspaceHeadToHeadUiTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
-            @Nullable SmartspaceText titleText,
-            @Nullable SmartspaceIcon titleIcon,
-            @Nullable SmartspaceText subtitleText,
-            @Nullable SmartspaceIcon subTitleIcon,
-            @Nullable SmartspaceTapAction primaryTapAction,
-            @Nullable SmartspaceText supplementalSubtitleText,
-            @Nullable SmartspaceIcon supplementalSubtitleIcon,
-            @Nullable SmartspaceTapAction supplementalSubtitleTapAction,
-            @Nullable SmartspaceText supplementalAlarmText,
-            @Nullable SmartspaceText headToHeadTitle,
-            @Nullable SmartspaceIcon headToHeadFirstCompetitorIcon,
-            @Nullable SmartspaceIcon headToHeadSecondCompetitorIcon,
-            @Nullable SmartspaceText headToHeadFirstCompetitorText,
-            @Nullable SmartspaceText headToHeadSecondCompetitorText,
-            @Nullable SmartspaceTapAction headToHeadAction) {
+    private HeadToHeadTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
+            @Nullable Text titleText,
+            @Nullable Icon titleIcon,
+            @Nullable Text subtitleText,
+            @Nullable Icon subTitleIcon,
+            @Nullable TapAction primaryTapAction,
+            @Nullable Text supplementalSubtitleText,
+            @Nullable Icon supplementalSubtitleIcon,
+            @Nullable TapAction supplementalSubtitleTapAction,
+            @Nullable Text supplementalAlarmText,
+            @Nullable Text headToHeadTitle,
+            @Nullable Icon headToHeadFirstCompetitorIcon,
+            @Nullable Icon headToHeadSecondCompetitorIcon,
+            @Nullable Text headToHeadFirstCompetitorText,
+            @Nullable Text headToHeadSecondCompetitorText,
+            @Nullable TapAction headToHeadAction) {
         super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction,
                 supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction,
                 supplementalAlarmText);
@@ -85,33 +92,39 @@
         mHeadToHeadAction = headToHeadAction;
     }
 
+    /** Returns the head-to-head card's title. */
     @Nullable
-    public SmartspaceText getHeadToHeadTitle() {
+    public Text getHeadToHeadTitle() {
         return mHeadToHeadTitle;
     }
 
+    /** Returns the first competitor's icon. */
     @Nullable
-    public SmartspaceIcon getHeadToHeadFirstCompetitorIcon() {
+    public Icon getHeadToHeadFirstCompetitorIcon() {
         return mHeadToHeadFirstCompetitorIcon;
     }
 
+    /** Returns the second competitor's icon. */
     @Nullable
-    public SmartspaceIcon getHeadToHeadSecondCompetitorIcon() {
+    public Icon getHeadToHeadSecondCompetitorIcon() {
         return mHeadToHeadSecondCompetitorIcon;
     }
 
+    /** Returns the first competitor's text. */
     @Nullable
-    public SmartspaceText getHeadToHeadFirstCompetitorText() {
+    public Text getHeadToHeadFirstCompetitorText() {
         return mHeadToHeadFirstCompetitorText;
     }
 
+    /** Returns the second competitor's text. */
     @Nullable
-    public SmartspaceText getHeadToHeadSecondCompetitorText() {
+    public Text getHeadToHeadSecondCompetitorText() {
         return mHeadToHeadSecondCompetitorText;
     }
 
+    /** Returns the head-to-head card's tap action. */
     @Nullable
-    public SmartspaceTapAction getHeadToHeadAction() {
+    public TapAction getHeadToHeadAction() {
         return mHeadToHeadAction;
     }
 
@@ -119,16 +132,16 @@
      * @see Parcelable.Creator
      */
     @NonNull
-    public static final Creator<SmartspaceHeadToHeadUiTemplateData> CREATOR =
-            new Creator<SmartspaceHeadToHeadUiTemplateData>() {
+    public static final Creator<HeadToHeadTemplateData> CREATOR =
+            new Creator<HeadToHeadTemplateData>() {
                 @Override
-                public SmartspaceHeadToHeadUiTemplateData createFromParcel(Parcel in) {
-                    return new SmartspaceHeadToHeadUiTemplateData(in);
+                public HeadToHeadTemplateData createFromParcel(Parcel in) {
+                    return new HeadToHeadTemplateData(in);
                 }
 
                 @Override
-                public SmartspaceHeadToHeadUiTemplateData[] newArray(int size) {
-                    return new SmartspaceHeadToHeadUiTemplateData[size];
+                public HeadToHeadTemplateData[] newArray(int size) {
+                    return new HeadToHeadTemplateData[size];
                 }
             };
 
@@ -151,9 +164,9 @@
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
-        if (!(o instanceof SmartspaceHeadToHeadUiTemplateData)) return false;
+        if (!(o instanceof HeadToHeadTemplateData)) return false;
         if (!super.equals(o)) return false;
-        SmartspaceHeadToHeadUiTemplateData that = (SmartspaceHeadToHeadUiTemplateData) o;
+        HeadToHeadTemplateData that = (HeadToHeadTemplateData) o;
         return SmartspaceUtils.isEqual(mHeadToHeadTitle, that.mHeadToHeadTitle) && Objects.equals(
                 mHeadToHeadFirstCompetitorIcon, that.mHeadToHeadFirstCompetitorIcon)
                 && Objects.equals(
@@ -187,22 +200,22 @@
     }
 
     /**
-     * A builder for {@link SmartspaceHeadToHeadUiTemplateData} object.
+     * A builder for {@link HeadToHeadTemplateData} object.
      *
      * @hide
      */
     @SystemApi
-    public static final class Builder extends SmartspaceDefaultUiTemplateData.Builder {
+    public static final class Builder extends BaseTemplateData.Builder {
 
-        private SmartspaceText mHeadToHeadTitle;
-        private SmartspaceIcon mHeadToHeadFirstCompetitorIcon;
-        private SmartspaceIcon mHeadToHeadSecondCompetitorIcon;
-        private SmartspaceText mHeadToHeadFirstCompetitorText;
-        private SmartspaceText mHeadToHeadSecondCompetitorText;
-        private SmartspaceTapAction mHeadToHeadAction;
+        private Text mHeadToHeadTitle;
+        private Icon mHeadToHeadFirstCompetitorIcon;
+        private Icon mHeadToHeadSecondCompetitorIcon;
+        private Text mHeadToHeadFirstCompetitorText;
+        private Text mHeadToHeadSecondCompetitorText;
+        private TapAction mHeadToHeadAction;
 
         /**
-         * A builder for {@link SmartspaceHeadToHeadUiTemplateData}.
+         * A builder for {@link HeadToHeadTemplateData}.
          */
         public Builder() {
             super(SmartspaceTarget.UI_TEMPLATE_HEAD_TO_HEAD);
@@ -212,7 +225,7 @@
          * Sets the head-to-head card's title
          */
         @NonNull
-        public Builder setHeadToHeadTitle(@Nullable SmartspaceText headToHeadTitle) {
+        public Builder setHeadToHeadTitle(@Nullable Text headToHeadTitle) {
             mHeadToHeadTitle = headToHeadTitle;
             return this;
         }
@@ -222,7 +235,7 @@
          */
         @NonNull
         public Builder setHeadToHeadFirstCompetitorIcon(
-                @Nullable SmartspaceIcon headToHeadFirstCompetitorIcon) {
+                @Nullable Icon headToHeadFirstCompetitorIcon) {
             mHeadToHeadFirstCompetitorIcon = headToHeadFirstCompetitorIcon;
             return this;
         }
@@ -232,7 +245,7 @@
          */
         @NonNull
         public Builder setHeadToHeadSecondCompetitorIcon(
-                @Nullable SmartspaceIcon headToHeadSecondCompetitorIcon) {
+                @Nullable Icon headToHeadSecondCompetitorIcon) {
             mHeadToHeadSecondCompetitorIcon = headToHeadSecondCompetitorIcon;
             return this;
         }
@@ -242,7 +255,7 @@
          */
         @NonNull
         public Builder setHeadToHeadFirstCompetitorText(
-                @Nullable SmartspaceText headToHeadFirstCompetitorText) {
+                @Nullable Text headToHeadFirstCompetitorText) {
             mHeadToHeadFirstCompetitorText = headToHeadFirstCompetitorText;
             return this;
         }
@@ -252,7 +265,7 @@
          */
         @NonNull
         public Builder setHeadToHeadSecondCompetitorText(
-                @Nullable SmartspaceText headToHeadSecondCompetitorText) {
+                @Nullable Text headToHeadSecondCompetitorText) {
             mHeadToHeadSecondCompetitorText = headToHeadSecondCompetitorText;
             return this;
         }
@@ -261,7 +274,7 @@
          * Sets the head-to-head card's tap action
          */
         @NonNull
-        public Builder setHeadToHeadAction(@Nullable SmartspaceTapAction headToHeadAction) {
+        public Builder setHeadToHeadAction(@Nullable TapAction headToHeadAction) {
             mHeadToHeadAction = headToHeadAction;
             return this;
         }
@@ -270,8 +283,8 @@
          * Builds a new SmartspaceHeadToHeadUiTemplateData instance.
          */
         @NonNull
-        public SmartspaceHeadToHeadUiTemplateData build() {
-            return new SmartspaceHeadToHeadUiTemplateData(getTemplateType(), getTitleText(),
+        public HeadToHeadTemplateData build() {
+            return new HeadToHeadTemplateData(getTemplateType(), getTitleText(),
                     getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(),
                     getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
                     getSupplementalSubtitleTapAction(), getSupplementalAlarmText(),
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceIcon.java b/core/java/android/app/smartspace/uitemplatedata/Icon.java
similarity index 75%
rename from core/java/android/app/smartspace/uitemplatedata/SmartspaceIcon.java
rename to core/java/android/app/smartspace/uitemplatedata/Icon.java
index 1efbaeb..2b1f420 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceIcon.java
+++ b/core/java/android/app/smartspace/uitemplatedata/Icon.java
@@ -20,7 +20,6 @@
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.smartspace.SmartspaceUtils;
-import android.graphics.drawable.Icon;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -34,34 +33,37 @@
  * @hide
  */
 @SystemApi
-public final class SmartspaceIcon implements Parcelable {
+public final class Icon implements Parcelable {
 
     @NonNull
-    private final Icon mIcon;
+    private final android.graphics.drawable.Icon mIcon;
 
     @Nullable
     private final CharSequence mContentDescription;
 
     private final boolean mShouldTint;
 
-    SmartspaceIcon(@NonNull Parcel in) {
-        mIcon = in.readTypedObject(Icon.CREATOR);
+    Icon(@NonNull Parcel in) {
+        mIcon = in.readTypedObject(android.graphics.drawable.Icon.CREATOR);
         mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mShouldTint = in.readBoolean();
     }
 
-    private SmartspaceIcon(@NonNull Icon icon, @Nullable CharSequence contentDescription,
+    private Icon(@NonNull android.graphics.drawable.Icon icon,
+            @Nullable CharSequence contentDescription,
             boolean shouldTint) {
         mIcon = icon;
         mContentDescription = contentDescription;
         mShouldTint = shouldTint;
     }
 
+    /** Returns the icon image. */
     @NonNull
-    public Icon getIcon() {
+    public android.graphics.drawable.Icon getIcon() {
         return mIcon;
     }
 
+    /** Returns the content description of the icon image. */
     @Nullable
     public CharSequence getContentDescription() {
         return mContentDescription;
@@ -73,23 +75,23 @@
     }
 
     @NonNull
-    public static final Creator<SmartspaceIcon> CREATOR = new Creator<SmartspaceIcon>() {
+    public static final Creator<Icon> CREATOR = new Creator<Icon>() {
         @Override
-        public SmartspaceIcon createFromParcel(Parcel in) {
-            return new SmartspaceIcon(in);
+        public Icon createFromParcel(Parcel in) {
+            return new Icon(in);
         }
 
         @Override
-        public SmartspaceIcon[] newArray(int size) {
-            return new SmartspaceIcon[size];
+        public Icon[] newArray(int size) {
+            return new Icon[size];
         }
     };
 
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
-        if (!(o instanceof SmartspaceIcon)) return false;
-        SmartspaceIcon that = (SmartspaceIcon) o;
+        if (!(o instanceof Icon)) return false;
+        Icon that = (Icon) o;
         return mIcon.toString().equals(that.mIcon.toString()) && SmartspaceUtils.isEqual(
                 mContentDescription,
                 that.mContentDescription) && mShouldTint == that.mShouldTint;
@@ -122,23 +124,23 @@
     }
 
     /**
-     * A builder for {@link SmartspaceIcon} object.
+     * A builder for {@link Icon} object.
      *
      * @hide
      */
     @SystemApi
     public static final class Builder {
 
-        private Icon mIcon;
+        private android.graphics.drawable.Icon mIcon;
         private CharSequence mContentDescription;
         private boolean mShouldTint;
 
         /**
-         * A builder for {@link SmartspaceIcon}, which sets shouldTint to true by default.
+         * A builder for {@link Icon}, which sets shouldTint to true by default.
          *
-         * @param icon the icon image of this {@link SmartspaceIcon} instance.
+         * @param icon the icon image of this {@link Icon} instance.
          */
-        public Builder(@NonNull Icon icon) {
+        public Builder(@NonNull android.graphics.drawable.Icon icon) {
             mIcon = Objects.requireNonNull(icon);
             mShouldTint = true;
         }
@@ -165,8 +167,8 @@
          * Builds a new SmartspaceIcon instance.
          */
         @NonNull
-        public SmartspaceIcon build() {
-            return new SmartspaceIcon(mIcon, mContentDescription, mShouldTint);
+        public Icon build() {
+            return new Icon(mIcon, mContentDescription, mShouldTint);
         }
     }
 }
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceCombinedCardsUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceCombinedCardsUiTemplateData.java
deleted file mode 100644
index 9d4c8e2..0000000
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceCombinedCardsUiTemplateData.java
+++ /dev/null
@@ -1,155 +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 android.app.smartspace.uitemplatedata;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.app.smartspace.SmartspaceTarget;
-import android.os.Parcel;
-
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Holds all the relevant data needed to render a Smartspace card with the combined-card Ui
- * Template.
- *
- * We only support 1 sub-list card combined with 1 carousel card. And we may expand our supported
- * combinations in the future.
- *
- * @hide
- */
-@SystemApi
-public final class SmartspaceCombinedCardsUiTemplateData extends SmartspaceDefaultUiTemplateData {
-
-    /** A list of secondary cards. */
-    @NonNull
-    private final List<SmartspaceDefaultUiTemplateData> mCombinedCardDataList;
-
-    SmartspaceCombinedCardsUiTemplateData(@NonNull Parcel in) {
-        super(in);
-        mCombinedCardDataList = in.createTypedArrayList(SmartspaceDefaultUiTemplateData.CREATOR);
-    }
-
-    private SmartspaceCombinedCardsUiTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
-            @Nullable SmartspaceText titleText,
-            @Nullable SmartspaceIcon titleIcon,
-            @Nullable SmartspaceText subtitleText,
-            @Nullable SmartspaceIcon subTitleIcon,
-            @Nullable SmartspaceTapAction primaryTapAction,
-            @Nullable SmartspaceText supplementalSubtitleText,
-            @Nullable SmartspaceIcon supplementalSubtitleIcon,
-            @Nullable SmartspaceTapAction supplementalSubtitleTapAction,
-            @Nullable SmartspaceText supplementalAlarmText,
-            @NonNull List<SmartspaceDefaultUiTemplateData> combinedCardDataList) {
-        super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction,
-                supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction,
-                supplementalAlarmText);
-        mCombinedCardDataList = combinedCardDataList;
-    }
-
-    @NonNull
-    public List<SmartspaceDefaultUiTemplateData> getCombinedCardDataList() {
-        return mCombinedCardDataList;
-    }
-
-    /**
-     * @see Parcelable.Creator
-     */
-    @NonNull
-    public static final Creator<SmartspaceCombinedCardsUiTemplateData> CREATOR =
-            new Creator<SmartspaceCombinedCardsUiTemplateData>() {
-                @Override
-                public SmartspaceCombinedCardsUiTemplateData createFromParcel(Parcel in) {
-                    return new SmartspaceCombinedCardsUiTemplateData(in);
-                }
-
-                @Override
-                public SmartspaceCombinedCardsUiTemplateData[] newArray(int size) {
-                    return new SmartspaceCombinedCardsUiTemplateData[size];
-                }
-            };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel out, int flags) {
-        super.writeToParcel(out, flags);
-        out.writeTypedList(mCombinedCardDataList);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (!(o instanceof SmartspaceCombinedCardsUiTemplateData)) return false;
-        if (!super.equals(o)) return false;
-        SmartspaceCombinedCardsUiTemplateData that = (SmartspaceCombinedCardsUiTemplateData) o;
-        return mCombinedCardDataList.equals(that.mCombinedCardDataList);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(super.hashCode(), mCombinedCardDataList);
-    }
-
-    @Override
-    public String toString() {
-        return super.toString() + " + SmartspaceCombinedCardsUiTemplateData{"
-                + "mCombinedCardDataList=" + mCombinedCardDataList
-                + '}';
-    }
-
-    /**
-     * A builder for {@link SmartspaceCombinedCardsUiTemplateData} object.
-     *
-     * @hide
-     */
-    @SystemApi
-    public static final class Builder extends SmartspaceDefaultUiTemplateData.Builder {
-
-        private final List<SmartspaceDefaultUiTemplateData> mCombinedCardDataList;
-
-        /**
-         * A builder for {@link SmartspaceCombinedCardsUiTemplateData}.
-         */
-        public Builder(@NonNull List<SmartspaceDefaultUiTemplateData> combinedCardDataList) {
-            super(SmartspaceTarget.UI_TEMPLATE_COMBINED_CARDS);
-            mCombinedCardDataList = Objects.requireNonNull(combinedCardDataList);
-        }
-
-        /**
-         * Builds a new SmartspaceCombinedCardsUiTemplateData instance.
-         *
-         * @throws IllegalStateException if any required non-null field is null
-         */
-        @NonNull
-        public SmartspaceCombinedCardsUiTemplateData build() {
-            if (mCombinedCardDataList == null) {
-                throw new IllegalStateException("Please assign a value to all @NonNull args.");
-            }
-            return new SmartspaceCombinedCardsUiTemplateData(getTemplateType(), getTitleText(),
-                    getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(),
-                    getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
-                    getSupplementalSubtitleTapAction(), getSupplementalAlarmText(),
-                    mCombinedCardDataList);
-        }
-    }
-}
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubImageUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubImageUiTemplateData.java
deleted file mode 100644
index 2fe4cf8..0000000
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubImageUiTemplateData.java
+++ /dev/null
@@ -1,190 +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 android.app.smartspace.uitemplatedata;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.app.smartspace.SmartspaceTarget;
-import android.os.Parcel;
-
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Holds all the relevant data needed to render a Smartspace card with the sub-image Ui Template.
- *
- * @hide
- */
-@SystemApi
-public final class SmartspaceSubImageUiTemplateData extends SmartspaceDefaultUiTemplateData {
-
-    /** Texts are shown next to the image as a vertical list */
-    @NonNull
-    private final List<SmartspaceText> mSubImageTexts;
-
-    /** If multiple images are passed in, they will be rendered as GIF. */
-    @NonNull
-    private final List<SmartspaceIcon> mSubImages;
-
-    /** Tap action for the sub-image secondary card. */
-    @Nullable
-    private final SmartspaceTapAction mSubImageAction;
-
-    SmartspaceSubImageUiTemplateData(@NonNull Parcel in) {
-        super(in);
-        mSubImageTexts = in.createTypedArrayList(SmartspaceText.CREATOR);
-        mSubImages = in.createTypedArrayList(SmartspaceIcon.CREATOR);
-        mSubImageAction = in.readTypedObject(SmartspaceTapAction.CREATOR);
-    }
-
-    private SmartspaceSubImageUiTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
-            @Nullable SmartspaceText titleText,
-            @Nullable SmartspaceIcon titleIcon,
-            @Nullable SmartspaceText subtitleText,
-            @Nullable SmartspaceIcon subTitleIcon,
-            @Nullable SmartspaceTapAction primaryTapAction,
-            @Nullable SmartspaceText supplementalSubtitleText,
-            @Nullable SmartspaceIcon supplementalSubtitleIcon,
-            @Nullable SmartspaceTapAction supplementalSubtitleTapAction,
-            @Nullable SmartspaceText supplementalAlarmText,
-            @NonNull List<SmartspaceText> subImageTexts,
-            @NonNull List<SmartspaceIcon> subImages,
-            @Nullable SmartspaceTapAction subImageAction) {
-        super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction,
-                supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction,
-                supplementalAlarmText);
-        mSubImageTexts = subImageTexts;
-        mSubImages = subImages;
-        mSubImageAction = subImageAction;
-    }
-
-    @NonNull
-    public List<SmartspaceText> getSubImageTexts() {
-        return mSubImageTexts;
-    }
-
-    @NonNull
-    public List<SmartspaceIcon> getSubImages() {
-        return mSubImages;
-    }
-
-    @Nullable
-    public SmartspaceTapAction getSubImageAction() {
-        return mSubImageAction;
-    }
-
-    /**
-     * @see Parcelable.Creator
-     */
-    @NonNull
-    public static final Creator<SmartspaceSubImageUiTemplateData> CREATOR =
-            new Creator<SmartspaceSubImageUiTemplateData>() {
-                @Override
-                public SmartspaceSubImageUiTemplateData createFromParcel(Parcel in) {
-                    return new SmartspaceSubImageUiTemplateData(in);
-                }
-
-                @Override
-                public SmartspaceSubImageUiTemplateData[] newArray(int size) {
-                    return new SmartspaceSubImageUiTemplateData[size];
-                }
-            };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel out, int flags) {
-        super.writeToParcel(out, flags);
-        out.writeTypedList(mSubImageTexts);
-        out.writeTypedList(mSubImages);
-        out.writeTypedObject(mSubImageAction, flags);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (!(o instanceof SmartspaceSubImageUiTemplateData)) return false;
-        if (!super.equals(o)) return false;
-        SmartspaceSubImageUiTemplateData that = (SmartspaceSubImageUiTemplateData) o;
-        return Objects.equals(mSubImageTexts, that.mSubImageTexts)
-                && Objects.equals(mSubImages, that.mSubImages) && Objects.equals(
-                mSubImageAction, that.mSubImageAction);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(super.hashCode(), mSubImageTexts, mSubImages, mSubImageAction);
-    }
-
-    @Override
-    public String toString() {
-        return super.toString() + " + SmartspaceSubImageUiTemplateData{"
-                + "mSubImageTexts=" + mSubImageTexts
-                + ", mSubImages=" + mSubImages
-                + ", mSubImageAction=" + mSubImageAction
-                + '}';
-    }
-
-    /**
-     * A builder for {@link SmartspaceSubImageUiTemplateData} object.
-     *
-     * @hide
-     */
-    @SystemApi
-    public static final class Builder extends SmartspaceDefaultUiTemplateData.Builder {
-
-        private final List<SmartspaceText> mSubImageTexts;
-        private final List<SmartspaceIcon> mSubImages;
-        private SmartspaceTapAction mSubImageAction;
-
-        /**
-         * A builder for {@link SmartspaceSubImageUiTemplateData}.
-         */
-        public Builder(@NonNull List<SmartspaceText> subImageTexts,
-                @NonNull List<SmartspaceIcon> subImages) {
-            super(SmartspaceTarget.UI_TEMPLATE_SUB_IMAGE);
-            mSubImageTexts = Objects.requireNonNull(subImageTexts);
-            mSubImages = Objects.requireNonNull(subImages);
-        }
-
-        /**
-         * Sets the card tap action.
-         */
-        @NonNull
-        public Builder setSubImageAction(@NonNull SmartspaceTapAction subImageAction) {
-            mSubImageAction = subImageAction;
-            return this;
-        }
-
-        /**
-         * Builds a new SmartspaceSubImageUiTemplateData instance.
-         */
-        @NonNull
-        public SmartspaceSubImageUiTemplateData build() {
-            return new SmartspaceSubImageUiTemplateData(getTemplateType(), getTitleText(),
-                    getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(),
-                    getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
-                    getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mSubImageTexts,
-                    mSubImages,
-                    mSubImageAction);
-        }
-    }
-}
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubListUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubListUiTemplateData.java
deleted file mode 100644
index 9512c7f..0000000
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubListUiTemplateData.java
+++ /dev/null
@@ -1,195 +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 android.app.smartspace.uitemplatedata;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.app.smartspace.SmartspaceTarget;
-import android.os.Parcel;
-
-import java.util.List;
-import java.util.Objects;
-
-
-/**
- * Holds all the relevant data needed to render a Smartspace card with the sub-list Ui Template.
- *
- * @hide
- */
-@SystemApi
-public final class SmartspaceSubListUiTemplateData extends SmartspaceDefaultUiTemplateData {
-
-    @Nullable
-    private final SmartspaceIcon mSubListIcon;
-    @NonNull
-    private final List<SmartspaceText> mSubListTexts;
-
-    /** Tap action for the sub-list secondary card. */
-    @Nullable
-    private final SmartspaceTapAction mSubListAction;
-
-    SmartspaceSubListUiTemplateData(@NonNull Parcel in) {
-        super(in);
-        mSubListIcon = in.readTypedObject(SmartspaceIcon.CREATOR);
-        mSubListTexts = in.createTypedArrayList(SmartspaceText.CREATOR);
-        mSubListAction = in.readTypedObject(SmartspaceTapAction.CREATOR);
-    }
-
-    private SmartspaceSubListUiTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
-            @Nullable SmartspaceText titleText,
-            @Nullable SmartspaceIcon titleIcon,
-            @Nullable SmartspaceText subtitleText,
-            @Nullable SmartspaceIcon subTitleIcon,
-            @Nullable SmartspaceTapAction primaryTapAction,
-            @Nullable SmartspaceText supplementalSubtitleText,
-            @Nullable SmartspaceIcon supplementalSubtitleIcon,
-            @Nullable SmartspaceTapAction supplementalSubtitleTapAction,
-            @Nullable SmartspaceText supplementalAlarmText,
-            @Nullable SmartspaceIcon subListIcon,
-            @NonNull List<SmartspaceText> subListTexts,
-            @Nullable SmartspaceTapAction subListAction) {
-        super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction,
-                supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction,
-                supplementalAlarmText);
-        mSubListIcon = subListIcon;
-        mSubListTexts = subListTexts;
-        mSubListAction = subListAction;
-    }
-
-    @Nullable
-    public SmartspaceIcon getSubListIcon() {
-        return mSubListIcon;
-    }
-
-    @NonNull
-    public List<SmartspaceText> getSubListTexts() {
-        return mSubListTexts;
-    }
-
-    @Nullable
-    public SmartspaceTapAction getSubListAction() {
-        return mSubListAction;
-    }
-
-    /**
-     * @see Parcelable.Creator
-     */
-    @NonNull
-    public static final Creator<SmartspaceSubListUiTemplateData> CREATOR =
-            new Creator<SmartspaceSubListUiTemplateData>() {
-                @Override
-                public SmartspaceSubListUiTemplateData createFromParcel(Parcel in) {
-                    return new SmartspaceSubListUiTemplateData(in);
-                }
-
-                @Override
-                public SmartspaceSubListUiTemplateData[] newArray(int size) {
-                    return new SmartspaceSubListUiTemplateData[size];
-                }
-            };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel out, int flags) {
-        super.writeToParcel(out, flags);
-        out.writeTypedObject(mSubListIcon, flags);
-        out.writeTypedList(mSubListTexts);
-        out.writeTypedObject(mSubListAction, flags);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (!(o instanceof SmartspaceSubListUiTemplateData)) return false;
-        if (!super.equals(o)) return false;
-        SmartspaceSubListUiTemplateData that = (SmartspaceSubListUiTemplateData) o;
-        return Objects.equals(mSubListIcon, that.mSubListIcon) && Objects.equals(
-                mSubListTexts, that.mSubListTexts) && Objects.equals(mSubListAction,
-                that.mSubListAction);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(super.hashCode(), mSubListIcon, mSubListTexts, mSubListAction);
-    }
-
-    @Override
-    public String toString() {
-        return super.toString() + " + SmartspaceSubListUiTemplateData{"
-                + "mSubListIcon=" + mSubListIcon
-                + ", mSubListTexts=" + mSubListTexts
-                + ", mSubListAction=" + mSubListAction
-                + '}';
-    }
-
-    /**
-     * A builder for {@link SmartspaceSubListUiTemplateData} object.
-     *
-     * @hide
-     */
-    @SystemApi
-    public static final class Builder extends SmartspaceDefaultUiTemplateData.Builder {
-
-        private SmartspaceIcon mSubListIcon;
-        private final List<SmartspaceText> mSubListTexts;
-        private SmartspaceTapAction mSubListAction;
-
-        /**
-         * A builder for {@link SmartspaceSubListUiTemplateData}.
-         */
-        public Builder(@NonNull List<SmartspaceText> subListTexts) {
-            super(SmartspaceTarget.UI_TEMPLATE_SUB_LIST);
-            mSubListTexts = Objects.requireNonNull(subListTexts);
-        }
-
-        /**
-         * Sets the sub-list card icon.
-         */
-        @NonNull
-        public Builder setSubListIcon(@NonNull SmartspaceIcon subListIcon) {
-            mSubListIcon = subListIcon;
-            return this;
-        }
-
-        /**
-         * Sets the card tap action.
-         */
-        @NonNull
-        public Builder setSubListAction(@NonNull SmartspaceTapAction subListAction) {
-            mSubListAction = subListAction;
-            return this;
-        }
-
-        /**
-         * Builds a new SmartspaceSubListUiTemplateData instance.
-         */
-        @NonNull
-        public SmartspaceSubListUiTemplateData build() {
-            return new SmartspaceSubListUiTemplateData(getTemplateType(), getTitleText(),
-                    getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(),
-                    getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
-                    getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mSubListIcon,
-                    mSubListTexts,
-                    mSubListAction);
-        }
-    }
-}
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubCardUiTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SubCardTemplateData.java
similarity index 60%
rename from core/java/android/app/smartspace/uitemplatedata/SmartspaceSubCardUiTemplateData.java
rename to core/java/android/app/smartspace/uitemplatedata/SubCardTemplateData.java
index 2db13d31..9c8330d 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceSubCardUiTemplateData.java
+++ b/core/java/android/app/smartspace/uitemplatedata/SubCardTemplateData.java
@@ -28,43 +28,49 @@
 /**
  * Holds all the relevant data needed to render a Smartspace card with the sub-card Ui Template.
  *
+ * This template will add a sub-card card within the default-template card:
+ * <ul>
+ *     <li> sub-card icon </li>
+ *     <li> sub-card text </li>
+ * </ul>
+ *
  * @hide
  */
 @SystemApi
-public final class SmartspaceSubCardUiTemplateData extends SmartspaceDefaultUiTemplateData {
+public final class SubCardTemplateData extends BaseTemplateData {
 
     /** Icon for the sub-card. */
     @NonNull
-    private final SmartspaceIcon mSubCardIcon;
+    private final Icon mSubCardIcon;
 
     /** Text for the sub-card, which shows below the icon when being set. */
     @Nullable
-    private final SmartspaceText mSubCardText;
+    private final Text mSubCardText;
 
     /** Tap action for the sub-card secondary card. */
     @Nullable
-    private final SmartspaceTapAction mSubCardAction;
+    private final TapAction mSubCardAction;
 
-    SmartspaceSubCardUiTemplateData(@NonNull Parcel in) {
+    SubCardTemplateData(@NonNull Parcel in) {
         super(in);
-        mSubCardIcon = in.readTypedObject(SmartspaceIcon.CREATOR);
-        mSubCardText = in.readTypedObject(SmartspaceText.CREATOR);
-        mSubCardAction = in.readTypedObject(SmartspaceTapAction.CREATOR);
+        mSubCardIcon = in.readTypedObject(Icon.CREATOR);
+        mSubCardText = in.readTypedObject(Text.CREATOR);
+        mSubCardAction = in.readTypedObject(TapAction.CREATOR);
     }
 
-    private SmartspaceSubCardUiTemplateData(int templateType,
-            @Nullable SmartspaceText titleText,
-            @Nullable SmartspaceIcon titleIcon,
-            @Nullable SmartspaceText subtitleText,
-            @Nullable SmartspaceIcon subTitleIcon,
-            @Nullable SmartspaceTapAction primaryTapAction,
-            @Nullable SmartspaceText supplementalSubtitleText,
-            @Nullable SmartspaceIcon supplementalSubtitleIcon,
-            @Nullable SmartspaceTapAction supplementalSubtitleTapAction,
-            @Nullable SmartspaceText supplementalAlarmText,
-            @NonNull SmartspaceIcon subCardIcon,
-            @Nullable SmartspaceText subCardText,
-            @Nullable SmartspaceTapAction subCardAction) {
+    private SubCardTemplateData(int templateType,
+            @Nullable Text titleText,
+            @Nullable Icon titleIcon,
+            @Nullable Text subtitleText,
+            @Nullable Icon subTitleIcon,
+            @Nullable TapAction primaryTapAction,
+            @Nullable Text supplementalSubtitleText,
+            @Nullable Icon supplementalSubtitleIcon,
+            @Nullable TapAction supplementalSubtitleTapAction,
+            @Nullable Text supplementalAlarmText,
+            @NonNull Icon subCardIcon,
+            @Nullable Text subCardText,
+            @Nullable TapAction subCardAction) {
         super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction,
                 supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction,
                 supplementalAlarmText);
@@ -73,18 +79,21 @@
         mSubCardAction = subCardAction;
     }
 
+    /** Returns the sub-card card's icon. */
     @NonNull
-    public SmartspaceIcon getSubCardIcon() {
+    public Icon getSubCardIcon() {
         return mSubCardIcon;
     }
 
+    /** Returns the sub-card card's text. */
     @Nullable
-    public SmartspaceText getSubCardText() {
+    public Text getSubCardText() {
         return mSubCardText;
     }
 
+    /** Returns the sub-card card's tap action. */
     @Nullable
-    public SmartspaceTapAction getSubCardAction() {
+    public TapAction getSubCardAction() {
         return mSubCardAction;
     }
 
@@ -92,16 +101,16 @@
      * @see Parcelable.Creator
      */
     @NonNull
-    public static final Creator<SmartspaceSubCardUiTemplateData> CREATOR =
-            new Creator<SmartspaceSubCardUiTemplateData>() {
+    public static final Creator<SubCardTemplateData> CREATOR =
+            new Creator<SubCardTemplateData>() {
                 @Override
-                public SmartspaceSubCardUiTemplateData createFromParcel(Parcel in) {
-                    return new SmartspaceSubCardUiTemplateData(in);
+                public SubCardTemplateData createFromParcel(Parcel in) {
+                    return new SubCardTemplateData(in);
                 }
 
                 @Override
-                public SmartspaceSubCardUiTemplateData[] newArray(int size) {
-                    return new SmartspaceSubCardUiTemplateData[size];
+                public SubCardTemplateData[] newArray(int size) {
+                    return new SubCardTemplateData[size];
                 }
             };
 
@@ -121,9 +130,9 @@
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
-        if (!(o instanceof SmartspaceSubCardUiTemplateData)) return false;
+        if (!(o instanceof SubCardTemplateData)) return false;
         if (!super.equals(o)) return false;
-        SmartspaceSubCardUiTemplateData that = (SmartspaceSubCardUiTemplateData) o;
+        SubCardTemplateData that = (SubCardTemplateData) o;
         return mSubCardIcon.equals(that.mSubCardIcon) && SmartspaceUtils.isEqual(mSubCardText,
                 that.mSubCardText) && Objects.equals(mSubCardAction,
                 that.mSubCardAction);
@@ -144,21 +153,21 @@
     }
 
     /**
-     * A builder for {@link SmartspaceSubCardUiTemplateData} object.
+     * A builder for {@link SubCardTemplateData} object.
      *
      * @hide
      */
     @SystemApi
-    public static final class Builder extends SmartspaceDefaultUiTemplateData.Builder {
+    public static final class Builder extends BaseTemplateData.Builder {
 
-        private final SmartspaceIcon mSubCardIcon;
-        private SmartspaceText mSubCardText;
-        private SmartspaceTapAction mSubCardAction;
+        private final Icon mSubCardIcon;
+        private Text mSubCardText;
+        private TapAction mSubCardAction;
 
         /**
-         * A builder for {@link SmartspaceSubCardUiTemplateData}.
+         * A builder for {@link SubCardTemplateData}.
          */
-        public Builder(@NonNull SmartspaceIcon subCardIcon) {
+        public Builder(@NonNull Icon subCardIcon) {
             super(SmartspaceTarget.UI_TEMPLATE_SUB_CARD);
             mSubCardIcon = Objects.requireNonNull(subCardIcon);
         }
@@ -167,7 +176,7 @@
          * Sets the card text.
          */
         @NonNull
-        public Builder setSubCardText(@NonNull SmartspaceText subCardText) {
+        public Builder setSubCardText(@NonNull Text subCardText) {
             mSubCardText = subCardText;
             return this;
         }
@@ -176,7 +185,7 @@
          * Sets the card tap action.
          */
         @NonNull
-        public Builder setSubCardAction(@NonNull SmartspaceTapAction subCardAction) {
+        public Builder setSubCardAction(@NonNull TapAction subCardAction) {
             mSubCardAction = subCardAction;
             return this;
         }
@@ -185,8 +194,8 @@
          * Builds a new SmartspaceSubCardUiTemplateData instance.
          */
         @NonNull
-        public SmartspaceSubCardUiTemplateData build() {
-            return new SmartspaceSubCardUiTemplateData(getTemplateType(), getTitleText(),
+        public SubCardTemplateData build() {
+            return new SubCardTemplateData(getTemplateType(), getTitleText(),
                     getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(),
                     getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
                     getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mSubCardIcon,
diff --git a/core/java/android/app/smartspace/uitemplatedata/SubImageTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SubImageTemplateData.java
new file mode 100644
index 0000000..7df5238
--- /dev/null
+++ b/core/java/android/app/smartspace/uitemplatedata/SubImageTemplateData.java
@@ -0,0 +1,203 @@
+/*
+ * 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.smartspace.uitemplatedata;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.smartspace.SmartspaceTarget;
+import android.os.Parcel;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Holds all the relevant data needed to render a Smartspace card with the sub-image Ui Template.
+ *
+ * This template will add a sub-image card within the default-template card:
+ * <ul>
+ *     <li> sub-image text1 </li>   <ul>
+ *     <li> sub-image text2 </li>        image (can be a GIF)
+ *     ...                          </ul>
+ * </ul>
+ *
+ * @hide
+ */
+@SystemApi
+public final class SubImageTemplateData extends BaseTemplateData {
+
+    /** Texts are shown next to the image as a vertical list */
+    @NonNull
+    private final List<Text> mSubImageTexts;
+
+    /** If multiple images are passed in, they will be rendered as GIF. */
+    @NonNull
+    private final List<Icon> mSubImages;
+
+    /** Tap action for the sub-image secondary card. */
+    @Nullable
+    private final TapAction mSubImageAction;
+
+    SubImageTemplateData(@NonNull Parcel in) {
+        super(in);
+        mSubImageTexts = in.createTypedArrayList(Text.CREATOR);
+        mSubImages = in.createTypedArrayList(Icon.CREATOR);
+        mSubImageAction = in.readTypedObject(TapAction.CREATOR);
+    }
+
+    private SubImageTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
+            @Nullable Text titleText,
+            @Nullable Icon titleIcon,
+            @Nullable Text subtitleText,
+            @Nullable Icon subTitleIcon,
+            @Nullable TapAction primaryTapAction,
+            @Nullable Text supplementalSubtitleText,
+            @Nullable Icon supplementalSubtitleIcon,
+            @Nullable TapAction supplementalSubtitleTapAction,
+            @Nullable Text supplementalAlarmText,
+            @NonNull List<Text> subImageTexts,
+            @NonNull List<Icon> subImages,
+            @Nullable TapAction subImageAction) {
+        super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction,
+                supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction,
+                supplementalAlarmText);
+        mSubImageTexts = subImageTexts;
+        mSubImages = subImages;
+        mSubImageAction = subImageAction;
+    }
+
+    /** Returns the list of sub-image card's texts. Can be empty if not being set. */
+    @NonNull
+    public List<Text> getSubImageTexts() {
+        return mSubImageTexts;
+    }
+
+    /**
+     * Returns the list of sub-image card's image. It's a single-element list if it's a static
+     * image, or a multi-elements list if it's a GIF.
+     */
+    @NonNull
+    public List<Icon> getSubImages() {
+        return mSubImages;
+    }
+
+    /** Returns the sub-image card's tap action. */
+    @Nullable
+    public TapAction getSubImageAction() {
+        return mSubImageAction;
+    }
+
+    /**
+     * @see Parcelable.Creator
+     */
+    @NonNull
+    public static final Creator<SubImageTemplateData> CREATOR =
+            new Creator<SubImageTemplateData>() {
+                @Override
+                public SubImageTemplateData createFromParcel(Parcel in) {
+                    return new SubImageTemplateData(in);
+                }
+
+                @Override
+                public SubImageTemplateData[] newArray(int size) {
+                    return new SubImageTemplateData[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        super.writeToParcel(out, flags);
+        out.writeTypedList(mSubImageTexts);
+        out.writeTypedList(mSubImages);
+        out.writeTypedObject(mSubImageAction, flags);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof SubImageTemplateData)) return false;
+        if (!super.equals(o)) return false;
+        SubImageTemplateData that = (SubImageTemplateData) o;
+        return Objects.equals(mSubImageTexts, that.mSubImageTexts)
+                && Objects.equals(mSubImages, that.mSubImages) && Objects.equals(
+                mSubImageAction, that.mSubImageAction);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), mSubImageTexts, mSubImages, mSubImageAction);
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + " + SmartspaceSubImageUiTemplateData{"
+                + "mSubImageTexts=" + mSubImageTexts
+                + ", mSubImages=" + mSubImages
+                + ", mSubImageAction=" + mSubImageAction
+                + '}';
+    }
+
+    /**
+     * A builder for {@link SubImageTemplateData} object.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder extends BaseTemplateData.Builder {
+
+        private final List<Text> mSubImageTexts;
+        private final List<Icon> mSubImages;
+        private TapAction mSubImageAction;
+
+        /**
+         * A builder for {@link SubImageTemplateData}.
+         */
+        public Builder(@NonNull List<Text> subImageTexts,
+                @NonNull List<Icon> subImages) {
+            super(SmartspaceTarget.UI_TEMPLATE_SUB_IMAGE);
+            mSubImageTexts = Objects.requireNonNull(subImageTexts);
+            mSubImages = Objects.requireNonNull(subImages);
+        }
+
+        /**
+         * Sets the card tap action.
+         */
+        @NonNull
+        public Builder setSubImageAction(@NonNull TapAction subImageAction) {
+            mSubImageAction = subImageAction;
+            return this;
+        }
+
+        /**
+         * Builds a new SmartspaceSubImageUiTemplateData instance.
+         */
+        @NonNull
+        public SubImageTemplateData build() {
+            return new SubImageTemplateData(getTemplateType(), getTitleText(),
+                    getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(),
+                    getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
+                    getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mSubImageTexts,
+                    mSubImages,
+                    mSubImageAction);
+        }
+    }
+}
diff --git a/core/java/android/app/smartspace/uitemplatedata/SubListTemplateData.java b/core/java/android/app/smartspace/uitemplatedata/SubListTemplateData.java
new file mode 100644
index 0000000..6f6034d
--- /dev/null
+++ b/core/java/android/app/smartspace/uitemplatedata/SubListTemplateData.java
@@ -0,0 +1,206 @@
+/*
+ * 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.smartspace.uitemplatedata;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.smartspace.SmartspaceTarget;
+import android.os.Parcel;
+
+import java.util.List;
+import java.util.Objects;
+
+
+/**
+ * Holds all the relevant data needed to render a Smartspace card with the sub-list Ui Template.
+ *
+ * This template will add a sub-list card within the default-template card:
+ * <ul>
+ *     <li> sub-list text1       sub-list icon </li>
+ *     <li> sub-list text2 </li>
+ *     <li> sub-list text3 </li>
+ *     ...
+ * </ul>
+ *
+ * @hide
+ */
+@SystemApi
+public final class SubListTemplateData extends BaseTemplateData {
+
+    @Nullable
+    private final Icon mSubListIcon;
+    @NonNull
+    private final List<Text> mSubListTexts;
+
+    /** Tap action for the sub-list secondary card. */
+    @Nullable
+    private final TapAction mSubListAction;
+
+    SubListTemplateData(@NonNull Parcel in) {
+        super(in);
+        mSubListIcon = in.readTypedObject(Icon.CREATOR);
+        mSubListTexts = in.createTypedArrayList(Text.CREATOR);
+        mSubListAction = in.readTypedObject(TapAction.CREATOR);
+    }
+
+    private SubListTemplateData(@SmartspaceTarget.UiTemplateType int templateType,
+            @Nullable Text titleText,
+            @Nullable Icon titleIcon,
+            @Nullable Text subtitleText,
+            @Nullable Icon subTitleIcon,
+            @Nullable TapAction primaryTapAction,
+            @Nullable Text supplementalSubtitleText,
+            @Nullable Icon supplementalSubtitleIcon,
+            @Nullable TapAction supplementalSubtitleTapAction,
+            @Nullable Text supplementalAlarmText,
+            @Nullable Icon subListIcon,
+            @NonNull List<Text> subListTexts,
+            @Nullable TapAction subListAction) {
+        super(templateType, titleText, titleIcon, subtitleText, subTitleIcon, primaryTapAction,
+                supplementalSubtitleText, supplementalSubtitleIcon, supplementalSubtitleTapAction,
+                supplementalAlarmText);
+        mSubListIcon = subListIcon;
+        mSubListTexts = subListTexts;
+        mSubListAction = subListAction;
+    }
+
+    /** Returns the sub-list card's icon. */
+    @Nullable
+    public Icon getSubListIcon() {
+        return mSubListIcon;
+    }
+
+    /** Returns the sub-list card's texts list. */
+    @NonNull
+    public List<Text> getSubListTexts() {
+        return mSubListTexts;
+    }
+
+    /** Returns the sub-list card's tap action. */
+    @Nullable
+    public TapAction getSubListAction() {
+        return mSubListAction;
+    }
+
+    /**
+     * @see Parcelable.Creator
+     */
+    @NonNull
+    public static final Creator<SubListTemplateData> CREATOR =
+            new Creator<SubListTemplateData>() {
+                @Override
+                public SubListTemplateData createFromParcel(Parcel in) {
+                    return new SubListTemplateData(in);
+                }
+
+                @Override
+                public SubListTemplateData[] newArray(int size) {
+                    return new SubListTemplateData[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel out, int flags) {
+        super.writeToParcel(out, flags);
+        out.writeTypedObject(mSubListIcon, flags);
+        out.writeTypedList(mSubListTexts);
+        out.writeTypedObject(mSubListAction, flags);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof SubListTemplateData)) return false;
+        if (!super.equals(o)) return false;
+        SubListTemplateData that = (SubListTemplateData) o;
+        return Objects.equals(mSubListIcon, that.mSubListIcon) && Objects.equals(
+                mSubListTexts, that.mSubListTexts) && Objects.equals(mSubListAction,
+                that.mSubListAction);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), mSubListIcon, mSubListTexts, mSubListAction);
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + " + SmartspaceSubListUiTemplateData{"
+                + "mSubListIcon=" + mSubListIcon
+                + ", mSubListTexts=" + mSubListTexts
+                + ", mSubListAction=" + mSubListAction
+                + '}';
+    }
+
+    /**
+     * A builder for {@link SubListTemplateData} object.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class Builder extends BaseTemplateData.Builder {
+
+        private Icon mSubListIcon;
+        private final List<Text> mSubListTexts;
+        private TapAction mSubListAction;
+
+        /**
+         * A builder for {@link SubListTemplateData}.
+         */
+        public Builder(@NonNull List<Text> subListTexts) {
+            super(SmartspaceTarget.UI_TEMPLATE_SUB_LIST);
+            mSubListTexts = Objects.requireNonNull(subListTexts);
+        }
+
+        /**
+         * Sets the sub-list card icon.
+         */
+        @NonNull
+        public Builder setSubListIcon(@NonNull Icon subListIcon) {
+            mSubListIcon = subListIcon;
+            return this;
+        }
+
+        /**
+         * Sets the card tap action.
+         */
+        @NonNull
+        public Builder setSubListAction(@NonNull TapAction subListAction) {
+            mSubListAction = subListAction;
+            return this;
+        }
+
+        /**
+         * Builds a new SmartspaceSubListUiTemplateData instance.
+         */
+        @NonNull
+        public SubListTemplateData build() {
+            return new SubListTemplateData(getTemplateType(), getTitleText(),
+                    getTitleIcon(), getSubtitleText(), getSubtitleIcon(), getPrimaryTapAction(),
+                    getSupplementalSubtitleText(), getSupplementalSubtitleIcon(),
+                    getSupplementalSubtitleTapAction(), getSupplementalAlarmText(), mSubListIcon,
+                    mSubListTexts,
+                    mSubListAction);
+        }
+    }
+}
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceTapAction.java b/core/java/android/app/smartspace/uitemplatedata/TapAction.java
similarity index 81%
rename from core/java/android/app/smartspace/uitemplatedata/SmartspaceTapAction.java
rename to core/java/android/app/smartspace/uitemplatedata/TapAction.java
index 27d8e5f..83ff6ab 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceTapAction.java
+++ b/core/java/android/app/smartspace/uitemplatedata/TapAction.java
@@ -33,7 +33,7 @@
 import java.util.Objects;
 
 /**
- * A {@link SmartspaceTapAction} represents an action which can be taken by a user by tapping on
+ * A {@link TapAction} represents an action which can be taken by a user by tapping on
  * either the title, the subtitle or on the icon. Supported instances are Intents and
  * PendingIntents. These actions can be called from another process or within the client process.
  *
@@ -42,9 +42,9 @@
  * @hide
  */
 @SystemApi
-public final class SmartspaceTapAction implements Parcelable {
+public final class TapAction implements Parcelable {
 
-    /** A unique Id of this {@link SmartspaceTapAction}. */
+    /** A unique Id of this {@link TapAction}. */
     @Nullable
     private final CharSequence mId;
 
@@ -60,7 +60,7 @@
     @Nullable
     private Bundle mExtras;
 
-    SmartspaceTapAction(@NonNull Parcel in) {
+    TapAction(@NonNull Parcel in) {
         mId = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mIntent = in.readTypedObject(Intent.CREATOR);
         mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
@@ -68,7 +68,7 @@
         mExtras = in.readBundle();
     }
 
-    private SmartspaceTapAction(@Nullable CharSequence id, @Nullable Intent intent,
+    private TapAction(@Nullable CharSequence id, @Nullable Intent intent,
             @Nullable PendingIntent pendingIntent, @Nullable UserHandle userHandle,
             @Nullable Bundle extras) {
         mId = id;
@@ -78,27 +78,32 @@
         mExtras = extras;
     }
 
+    /** Returns the unique id of the tap action. */
     @Nullable
     public CharSequence getId() {
         return mId;
     }
 
+    /** Returns the intent of the tap action. */
     @SuppressLint("IntentBuilderName")
     @Nullable
     public Intent getIntent() {
         return mIntent;
     }
 
+    /** Returns the pending intent of the tap action. */
     @Nullable
     public PendingIntent getPendingIntent() {
         return mPendingIntent;
     }
 
+    /** Returns the user handle of the tap action. */
     @Nullable
     public UserHandle getUserHandle() {
         return mUserHandle;
     }
 
+    /** Returns the extras bundle of the tap action. */
     @Nullable
     @SuppressLint("NullableCollection")
     public Bundle getExtras() {
@@ -120,23 +125,23 @@
     }
 
     @NonNull
-    public static final Creator<SmartspaceTapAction> CREATOR = new Creator<SmartspaceTapAction>() {
+    public static final Creator<TapAction> CREATOR = new Creator<TapAction>() {
         @Override
-        public SmartspaceTapAction createFromParcel(Parcel in) {
-            return new SmartspaceTapAction(in);
+        public TapAction createFromParcel(Parcel in) {
+            return new TapAction(in);
         }
 
         @Override
-        public SmartspaceTapAction[] newArray(int size) {
-            return new SmartspaceTapAction[size];
+        public TapAction[] newArray(int size) {
+            return new TapAction[size];
         }
     };
 
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
-        if (!(o instanceof SmartspaceTapAction)) return false;
-        SmartspaceTapAction that = (SmartspaceTapAction) o;
+        if (!(o instanceof TapAction)) return false;
+        TapAction that = (TapAction) o;
         return SmartspaceUtils.isEqual(mId, that.mId);
     }
 
@@ -157,7 +162,7 @@
     }
 
     /**
-     * A builder for {@link SmartspaceTapAction} object.
+     * A builder for {@link TapAction} object.
      *
      * @hide
      */
@@ -171,9 +176,9 @@
         private Bundle mExtras;
 
         /**
-         * A builder for {@link SmartspaceTapAction}.
+         * A builder for {@link TapAction}.
          *
-         * @param id A unique Id of this {@link SmartspaceTapAction}.
+         * @param id A unique Id of this {@link TapAction}.
          */
         public Builder(@NonNull CharSequence id) {
             mId = Objects.requireNonNull(id);
@@ -222,11 +227,11 @@
          * @throws IllegalStateException if the tap action is empty.
          */
         @NonNull
-        public SmartspaceTapAction build() {
+        public TapAction build() {
             if (mIntent == null && mPendingIntent == null && mExtras == null) {
                 throw new IllegalStateException("Please assign at least 1 valid tap field");
             }
-            return new SmartspaceTapAction(mId, mIntent, mPendingIntent, mUserHandle, mExtras);
+            return new TapAction(mId, mIntent, mPendingIntent, mUserHandle, mExtras);
         }
     }
 }
diff --git a/core/java/android/app/smartspace/uitemplatedata/SmartspaceText.java b/core/java/android/app/smartspace/uitemplatedata/Text.java
similarity index 63%
rename from core/java/android/app/smartspace/uitemplatedata/SmartspaceText.java
rename to core/java/android/app/smartspace/uitemplatedata/Text.java
index 25d13e6..b733394 100644
--- a/core/java/android/app/smartspace/uitemplatedata/SmartspaceText.java
+++ b/core/java/android/app/smartspace/uitemplatedata/Text.java
@@ -32,43 +32,54 @@
  * @hide
  */
 @SystemApi
-public final class SmartspaceText implements Parcelable {
+public final class Text implements Parcelable {
 
     @NonNull
     private final CharSequence mText;
 
     private final TextUtils.TruncateAt mTruncateAtType;
 
-    SmartspaceText(Parcel in) {
+    private final int mMaxLines;
+
+    Text(Parcel in) {
         mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mTruncateAtType = TextUtils.TruncateAt.valueOf(in.readString());
+        mMaxLines = in.readInt();
     }
 
-    private SmartspaceText(@NonNull CharSequence text, TextUtils.TruncateAt truncateAtType) {
+    private Text(@NonNull CharSequence text, TextUtils.TruncateAt truncateAtType, int maxLines) {
         mText = text;
         mTruncateAtType = truncateAtType;
+        mMaxLines = maxLines;
     }
 
+    /** Returns the text content. */
     @NonNull
     public CharSequence getText() {
         return mText;
     }
 
+    /** Returns the {@link TextUtils.TruncateAt} type of the text content. */
     @NonNull
     public TextUtils.TruncateAt getTruncateAtType() {
         return mTruncateAtType;
     }
 
+    /** Returns the allowed max lines for presenting the text content. */
+    public int getMaxLines() {
+        return mMaxLines;
+    }
+
     @NonNull
-    public static final Creator<SmartspaceText> CREATOR = new Creator<SmartspaceText>() {
+    public static final Creator<Text> CREATOR = new Creator<Text>() {
         @Override
-        public SmartspaceText createFromParcel(Parcel in) {
-            return new SmartspaceText(in);
+        public Text createFromParcel(Parcel in) {
+            return new Text(in);
         }
 
         @Override
-        public SmartspaceText[] newArray(int size) {
-            return new SmartspaceText[size];
+        public Text[] newArray(int size) {
+            return new Text[size];
         }
     };
 
@@ -80,25 +91,26 @@
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
-        if (!(o instanceof SmartspaceText)) return false;
-        SmartspaceText that = (SmartspaceText) o;
+        if (!(o instanceof Text)) return false;
+        Text that = (Text) o;
         return mTruncateAtType == that.mTruncateAtType && SmartspaceUtils.isEqual(mText,
-                that.mText);
+                that.mText) && mMaxLines == that.mMaxLines;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mText, mTruncateAtType);
+        return Objects.hash(mText, mTruncateAtType, mMaxLines);
     }
 
     @Override
     public void writeToParcel(@NonNull Parcel out, int flags) {
         TextUtils.writeToParcel(mText, out, flags);
         out.writeString(mTruncateAtType.name());
+        out.writeInt(mMaxLines);
     }
 
     /**
-     * A builder for {@link SmartspaceText} object.
+     * A builder for {@link Text} object.
      *
      * @hide
      */
@@ -106,25 +118,31 @@
     public static final class Builder {
         private final CharSequence mText;
         private TextUtils.TruncateAt mTruncateAtType;
+        private int mMaxLines;
 
         /**
-         * A builder for {@link SmartspaceText}, which sets TruncateAtType to AT_END by default.
+         * A builder for {@link Text}, which by default sets TruncateAtType to AT_END, and the max
+         * lines to 1.
          */
         public Builder(@NonNull CharSequence text) {
             mText = Objects.requireNonNull(text);
             mTruncateAtType = TextUtils.TruncateAt.END;
+            mMaxLines = 1;
         }
 
         /**
-         * A builder for {@link SmartspaceText}.
+         * A builder for {@link Text} with specifying {@link TextUtils.TruncateAt} type, and by
+         * default set the max lines to 1.
          */
         public Builder(@NonNull CharSequence text, @NonNull TextUtils.TruncateAt truncateAtType) {
             mText = Objects.requireNonNull(text);
             mTruncateAtType = Objects.requireNonNull(truncateAtType);
+            mMaxLines = 1;
         }
 
         /**
-         * Sets truncateAtType.
+         * Sets truncateAtType, where the text content should be truncated if not all the content
+         * can be presented.
          */
         @NonNull
         public Builder setTruncateAtType(@NonNull TextUtils.TruncateAt truncateAtType) {
@@ -133,11 +151,20 @@
         }
 
         /**
+         * Sets the allowed max lines for the text content.
+         */
+        @NonNull
+        public Builder setMaxLines(int maxLines) {
+            mMaxLines = maxLines;
+            return this;
+        }
+
+        /**
          * Builds a new SmartspaceText instance.
          */
         @NonNull
-        public SmartspaceText build() {
-            return new SmartspaceText(mText, mTruncateAtType);
+        public Text build() {
+            return new Text(mText, mTruncateAtType, mMaxLines);
         }
     }
 }
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index f1abb05..d50a6ba 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -82,14 +82,21 @@
     }
 
     /**
-     * Creates a virtual device.
+     * Creates a virtual device where applications can launch and receive input events injected by
+     * the creator.
+     *
+     * <p>The {@link android.Manifest.permission#CREATE_VIRTUAL_DEVICE} permission is required to
+     * create virtual devices, which is only available to system apps holding specific roles.
      *
      * @param associationId The association ID as returned by {@link AssociationInfo#getId()} from
      *   Companion Device Manager. Virtual devices must have a corresponding association with CDM in
      *   order to be created.
+     * @param params The parameters for creating virtual devices. See {@link VirtualDeviceParams}
+     *   for the available options.
+     * @return The created virtual device.
      */
     @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
-    @Nullable
+    @NonNull
     public VirtualDevice createVirtualDevice(
             int associationId,
             @NonNull VirtualDeviceParams params) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e5cffb1..0aa25ef 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -9209,6 +9209,16 @@
     }
 
     /**
+     * Returns the total size of the extras in bytes, or 0 if no extras are present.
+     * @hide
+     */
+    public int getExtrasTotalSize() {
+        return (mExtras != null)
+                ? mExtras.getSize()
+                : 0;
+    }
+
+    /**
      * @return Whether {@link #maybeStripForHistory} will return an lightened intent or
      * return itself as-is.
      * @hide
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 2528e16..be58ba7 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -39,6 +39,7 @@
 import android.util.Printer;
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
+import android.view.OnBackInvokedCallback;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Parcelling;
@@ -801,11 +802,24 @@
      */
     public static final int PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE = 1 << 2;
 
+
+    /**
+     * If false, {@link android.view.KeyEvent#KEYCODE_BACK} related events will be forwarded to
+     * the Activities, Dialogs and Views and {@link android.app.Activity#onBackPressed()},
+     * {@link android.app.Dialog#onBackPressed} will be called. Otherwise, those events will be
+     * replaced by a call to {@link OnBackInvokedCallback#onBackInvoked()} on the focused window.
+     *
+     * @hide
+     * @see android.R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback
+     */
+    public static final int PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK = 1 << 3;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "PRIVATE_FLAG_EXT_" }, value = {
             PRIVATE_FLAG_EXT_PROFILEABLE,
             PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION,
             PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE,
+            PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ApplicationInfoPrivateFlagsExt {}
@@ -1683,6 +1697,7 @@
                 pw.println(prefix + "localeConfigRes=0x"
                         + Integer.toHexString(localeConfigRes));
             }
+            pw.println(prefix + "enableOnBackInvokedCallback=" + isOnBackInvokedCallbackEnabled());
         }
         pw.println(prefix + "createTimestamp=" + createTimestamp);
         if (mKnownActivityEmbeddingCerts != null) {
@@ -2566,6 +2581,17 @@
     }
 
     /**
+     * Returns whether the application will use the {@link android.view.OnBackInvokedCallback}
+     * navigation system instead of the {@link android.view.KeyEvent#KEYCODE_BACK} and related
+     * callbacks.
+     *
+     * @hide
+     */
+    public boolean isOnBackInvokedCallbackEnabled() {
+        return ((privateFlagsExt & PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK)) != 0;
+    }
+
+    /**
      * @hide
      */
     @Override protected ApplicationInfo getApplicationInfo() {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index dc79ee6..a162c41 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -8035,6 +8035,7 @@
             return PackageParser.generatePackageInfo(pkg, null, (int) flagsBits, 0, 0, null,
                     FrameworkPackageUserState.DEFAULT);
         } catch (PackageParser.PackageParserException e) {
+            Log.w(TAG, "Failure to parse package archive", e);
             return null;
         }
     }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 98cc8f6..e914432 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -59,6 +59,7 @@
 import android.content.pm.overlay.OverlayPaths;
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
+import android.content.pm.permission.SplitPermissionInfoParcelable;
 import android.content.pm.pkg.FrameworkPackageUserState;
 import android.content.res.ApkAssets;
 import android.content.res.AssetManager;
@@ -2417,9 +2418,28 @@
             Slog.i(TAG, newPermsMsg.toString());
         }
 
-        final List<PermissionManager.SplitPermissionInfo> splitPermissions =
-                ActivityThread.currentApplication().getSystemService(PermissionManager.class)
-                        .getSplitPermissions();
+        // Must build permission info manually for legacy code, which can be called before
+        // Appication is available through the app process, so the normal API doesn't work.
+        List<SplitPermissionInfoParcelable> splitPermissionParcelables;
+        try {
+            splitPermissionParcelables = ActivityThread.getPermissionManager()
+                    .getSplitPermissions();
+        } catch (RemoteException e) {
+            splitPermissionParcelables = Collections.emptyList();
+        }
+
+        int splitPermissionsSize = splitPermissionParcelables.size();
+        List<PermissionManager.SplitPermissionInfo> splitPermissions =
+                new ArrayList<>(splitPermissionsSize);
+        for (int index = 0; index < splitPermissionsSize; index++) {
+            SplitPermissionInfoParcelable splitPermissionParcelable =
+                    splitPermissionParcelables.get(index);
+            splitPermissions.add(new PermissionManager.SplitPermissionInfo(
+                    splitPermissionParcelable.getSplitPermission(),
+                    splitPermissionParcelable.getNewPermissions(),
+                    splitPermissionParcelable.getTargetSdk()
+            ));
+        }
 
         final int listSize = splitPermissions.size();
         for (int is = 0; is < listSize; is++) {
diff --git a/core/java/android/content/res/FontResourcesParser.java b/core/java/android/content/res/FontResourcesParser.java
index ecd240d..24ae31e 100644
--- a/core/java/android/content/res/FontResourcesParser.java
+++ b/core/java/android/content/res/FontResourcesParser.java
@@ -199,6 +199,7 @@
                         certs.add(certsList);
                     }
                 }
+                typedArray.recycle();
             }
             return new ProviderResourceEntry(
                     authority,
diff --git a/core/java/android/hardware/ISensorPrivacyListener.aidl b/core/java/android/hardware/ISensorPrivacyListener.aidl
index 5d40265..2ac21d2 100644
--- a/core/java/android/hardware/ISensorPrivacyListener.aidl
+++ b/core/java/android/hardware/ISensorPrivacyListener.aidl
@@ -24,6 +24,6 @@
     // the ones in
     //   frameworks/native/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyListener.aidl
     // =============== Beginning of transactions used on native side as well ======================
-    void onSensorPrivacyChanged(boolean enabled);
+    void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled);
     // =============== End of transactions used on native side as well ============================
 }
diff --git a/core/java/android/hardware/ISensorPrivacyManager.aidl b/core/java/android/hardware/ISensorPrivacyManager.aidl
index 5571165..a392afd 100644
--- a/core/java/android/hardware/ISensorPrivacyManager.aidl
+++ b/core/java/android/hardware/ISensorPrivacyManager.aidl
@@ -24,34 +24,31 @@
     // the ones in
     //   frameworks/native/libs/sensorprivacy/aidl/android/hardware/ISensorPrivacyManager.aidl
     // =============== Beginning of transactions used on native side as well ======================
-    boolean supportsSensorToggle(int sensor);
+    boolean supportsSensorToggle(int toggleType, int sensor);
 
     void addSensorPrivacyListener(in ISensorPrivacyListener listener);
 
-    void addIndividualSensorPrivacyListener(int userId, int sensor,
-            in ISensorPrivacyListener listener);
+    void addToggleSensorPrivacyListener(in ISensorPrivacyListener listener);
 
     void removeSensorPrivacyListener(in ISensorPrivacyListener listener);
 
-    void removeIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
+    void removeToggleSensorPrivacyListener(in ISensorPrivacyListener listener);
 
     boolean isSensorPrivacyEnabled();
 
-    boolean isIndividualSensorPrivacyEnabled(int userId, int sensor);
+    boolean isCombinedToggleSensorPrivacyEnabled(int sensor);
+
+    boolean isToggleSensorPrivacyEnabled(int toggleType, int sensor);
 
     void setSensorPrivacy(boolean enable);
 
-    void setIndividualSensorPrivacy(int userId, int source, int sensor, boolean enable);
+    void setToggleSensorPrivacy(int userId, int source, int sensor, boolean enable);
 
-    void setIndividualSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
+    void setToggleSensorPrivacyForProfileGroup(int userId, int source, int sensor, boolean enable);
     // =============== End of transactions used on native side as well ============================
 
-    void suppressIndividualSensorPrivacyReminders(int userId, int sensor, IBinder token,
+    void suppressToggleSensorPrivacyReminders(int userId, int sensor, IBinder token,
             boolean suppress);
 
-    void addUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
-
-    void removeUserGlobalIndividualSensorPrivacyListener(int sensor, in ISensorPrivacyListener listener);
-
     void showSensorUseDialog(int sensor);
 }
\ No newline at end of file
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 47659a9..dec424c 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -639,7 +639,7 @@
     /**
      * Unregisters a listener for the sensors with which it is registered.
      *
-     * <p class="note"></p>
+     * <p class="note">
      * Note: Don't use this method with a one shot trigger sensor such as
      * {@link Sensor#TYPE_SIGNIFICANT_MOTION}.
      * Use {@link #cancelTriggerSensor(TriggerEventListener, Sensor)} instead.
diff --git a/core/java/android/hardware/SensorPrivacyManager.java b/core/java/android/hardware/SensorPrivacyManager.java
index 79153d7..4399af9 100644
--- a/core/java/android/hardware/SensorPrivacyManager.java
+++ b/core/java/android/hardware/SensorPrivacyManager.java
@@ -36,7 +36,6 @@
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Pair;
-import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -73,8 +72,6 @@
     public static final String EXTRA_ALL_SENSORS = SensorPrivacyManager.class.getName()
             + ".extra.all_sensors";
 
-    private final SparseArray<Boolean> mToggleSupportCache = new SparseArray<>();
-
     /**
      * Sensor constants which are used in {@link SensorPrivacyManager}
      */
@@ -241,8 +238,55 @@
         void onSensorPrivacyChanged(int sensor, boolean enabled);
     }
 
+    /**
+     * A class implementing this interface can register with the {@link
+     * android.hardware.SensorPrivacyManager} to receive notification when the sensor privacy
+     * state changes.
+     *
+     * @hide
+     */
+    public interface OnToggleSensorPrivacyChangedListener {
+
+        /**
+         * A class containing information about what the sensor privacy state has changed to.
+         */
+        class SensorPrivacyChangedParams {
+
+            private int mToggleType;
+            private int mSensor;
+            private boolean mEnabled;
+
+            private SensorPrivacyChangedParams(int toggleType, int sensor, boolean enabled) {
+                mToggleType = toggleType;
+                mSensor = sensor;
+                mEnabled = enabled;
+            }
+
+            public @ToggleTypes.ToggleType int getToggleType() {
+                return mToggleType;
+            }
+
+            public @Sensors.Sensor int getSensor() {
+                return mSensor;
+            }
+
+            public boolean isEnabled() {
+                return mEnabled;
+            }
+        }
+
+        /**
+         * Callback invoked when the sensor privacy state changes.
+         *
+         * @param params Parameters describing the new state
+         */
+        void onSensorPrivacyChanged(@NonNull SensorPrivacyChangedParams params);
+    }
+
     private static final Object sInstanceLock = new Object();
 
+    private final Object mLock = new Object();
+
     @GuardedBy("sInstanceLock")
     private static SensorPrivacyManager sInstance;
 
@@ -252,12 +296,46 @@
     @NonNull
     private final ISensorPrivacyManager mService;
 
+    @GuardedBy("mLock")
+    private final ArrayMap<Pair<Integer, Integer>, Boolean> mToggleSupportCache = new ArrayMap<>();
+
     @NonNull
     private final ArrayMap<OnAllSensorPrivacyChangedListener, ISensorPrivacyListener> mListeners;
 
+    /** Registered listeners */
+    @GuardedBy("mLock")
     @NonNull
-    private final ArrayMap<Pair<OnSensorPrivacyChangedListener, Integer>, ISensorPrivacyListener>
-            mIndividualListeners;
+    private final ArrayMap<OnToggleSensorPrivacyChangedListener, Executor> mToggleListeners =
+            new ArrayMap<>();
+
+    /** Listeners registered using the deprecated APIs and which
+     * OnToggleSensorPrivacyChangedListener they're using. */
+    @GuardedBy("mLock")
+    @NonNull
+    private final ArrayMap<Pair<Integer, OnSensorPrivacyChangedListener>,
+            OnToggleSensorPrivacyChangedListener> mLegacyToggleListeners = new ArrayMap<>();
+
+    /** The singleton ISensorPrivacyListener for IPC which will be used to dispatch to local
+     * listeners */
+    @NonNull
+    private final ISensorPrivacyListener mIToggleListener = new ISensorPrivacyListener.Stub() {
+        @Override
+        public void onSensorPrivacyChanged(int toggleType, int sensor, boolean enabled) {
+            synchronized (mLock) {
+                for (int i = 0; i < mToggleListeners.size(); i++) {
+                    OnToggleSensorPrivacyChangedListener listener = mToggleListeners.keyAt(i);
+                    mToggleListeners.valueAt(i).execute(() -> listener
+                            .onSensorPrivacyChanged(new OnToggleSensorPrivacyChangedListener
+                                    .SensorPrivacyChangedParams(toggleType, sensor, enabled)));
+                }
+            }
+        }
+    };
+
+    /** Whether the singleton ISensorPrivacyListener has been registered */
+    @GuardedBy("mLock")
+    @NonNull
+    private boolean mToggleListenerRegistered = false;
 
     /**
      * Private constructor to ensure only a single instance is created.
@@ -266,7 +344,6 @@
         mContext = context;
         mService = service;
         mListeners = new ArrayMap<>();
-        mIndividualListeners = new ArrayMap<>();
     }
 
     /**
@@ -295,25 +372,43 @@
      * @return whether the toggle for the sensor is supported on this device.
      */
     public boolean supportsSensorToggle(@Sensors.Sensor int sensor) {
+        return supportsSensorToggle(ToggleTypes.SOFTWARE, sensor);
+    }
+
+    /**
+     * Checks if the given toggle is supported on this device
+     * @param sensor The sensor to check
+     * @return whether the toggle for the sensor is supported on this device.
+     *
+     * @hide
+     */
+    public boolean supportsSensorToggle(@ToggleTypes.ToggleType int toggleType,
+            @Sensors.Sensor int sensor) {
         try {
-            Boolean val = mToggleSupportCache.get(sensor);
-            if (val == null) {
-                val = mService.supportsSensorToggle(sensor);
-                mToggleSupportCache.put(sensor, val);
+            Pair key = new Pair(toggleType, sensor);
+            synchronized (mLock) {
+                Boolean val = mToggleSupportCache.get(key);
+                if (val == null) {
+                    val = mService.supportsSensorToggle(toggleType, sensor);
+                    mToggleSupportCache.put(key, val);
+                }
+                return val;
             }
-            return val;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
+     *
      * Registers a new listener to receive notification when the state of sensor privacy
      * changes.
      *
      * @param sensor the sensor to listen to changes to
      * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
-     *                 privacy changes.
+     *                       privacy changes.
+     *
+     * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)}
      *
      * @hide
      */
@@ -325,6 +420,7 @@
     }
 
     /**
+     *
      * Registers a new listener to receive notification when the state of sensor privacy
      * changes.
      *
@@ -333,22 +429,27 @@
      * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
      *                 privacy changes.
      *
+     * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)}
+     *
      * @hide
      */
     @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
-    public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @UserIdInt int userId,
+    public void addSensorPrivacyListener(@Sensors.Sensor int sensor, int userId,
             @NonNull OnSensorPrivacyChangedListener listener) {
-        addSensorPrivacyListener(sensor, userId, mContext.getMainExecutor(), listener);
+        addSensorPrivacyListener(sensor, mContext.getMainExecutor(), listener);
     }
 
     /**
+     *
      * Registers a new listener to receive notification when the state of sensor privacy
      * changes.
      *
      * @param sensor the sensor to listen to changes to
      * @param executor the executor to dispatch the callback on
      * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
-     *                 privacy changes.
+     *                       privacy changes.
+     *
+     * {@link #addSensorPrivacyListener(Executor, OnToggleSensorPrivacyChangedListener)}
      *
      * @hide
      */
@@ -356,61 +457,69 @@
     @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
     public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @NonNull Executor executor,
             @NonNull OnSensorPrivacyChangedListener listener) {
-        Pair<OnSensorPrivacyChangedListener, Integer> key = new Pair<>(listener, sensor);
-        synchronized (mIndividualListeners) {
-            ISensorPrivacyListener iListener = mIndividualListeners.get(key);
-            if (iListener == null) {
-                iListener = new ISensorPrivacyListener.Stub() {
-                    @Override
-                    public void onSensorPrivacyChanged(boolean enabled) {
-                        executor.execute(() -> listener.onSensorPrivacyChanged(sensor, enabled));
-                    }
-                };
-                mIndividualListeners.put(key, iListener);
-            }
 
-            try {
-                mService.addUserGlobalIndividualSensorPrivacyListener(sensor, iListener);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
+        Pair<Integer, OnSensorPrivacyChangedListener> pair = new Pair(sensor, listener);
+        OnToggleSensorPrivacyChangedListener toggleListener = params -> {
+            if (params.getSensor() == sensor) {
+                listener.onSensorPrivacyChanged(params.getSensor(), params.isEnabled());
             }
+        };
+
+        synchronized (mLock) {
+            mLegacyToggleListeners.put(pair, toggleListener);
+            addSensorPrivacyListenerLocked(executor, toggleListener);
         }
     }
 
     /**
+     *
      * Registers a new listener to receive notification when the state of sensor privacy
      * changes.
      *
-     * @param sensor the sensor to listen to changes to
-     * @param executor the executor to dispatch the callback on
-     * @param userId the user's id
-     * @param listener the OnSensorPrivacyChangedListener to be notified when the state of sensor
-     *                 privacy changes.
+     * @param listener the OnToggleSensorPrivacyChangedListener to be notified when the state of
+     *                 sensor privacy changes.
      *
      * @hide
      */
     @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
-    public void addSensorPrivacyListener(@Sensors.Sensor int sensor, @UserIdInt int userId,
-            @NonNull Executor executor, @NonNull OnSensorPrivacyChangedListener listener) {
-        synchronized (mIndividualListeners) {
-            ISensorPrivacyListener iListener = mIndividualListeners.get(listener);
-            if (iListener == null) {
-                iListener = new ISensorPrivacyListener.Stub() {
-                    @Override
-                    public void onSensorPrivacyChanged(boolean enabled) {
-                        executor.execute(() -> listener.onSensorPrivacyChanged(sensor, enabled));
-                    }
-                };
-                mIndividualListeners.put(new Pair<>(listener, sensor), iListener);
-            }
+    public void addSensorPrivacyListener(@NonNull OnToggleSensorPrivacyChangedListener listener) {
+        addSensorPrivacyListener(mContext.getMainExecutor(), listener);
+    }
 
+    /**
+     *
+     * Registers a new listener to receive notification when the state of sensor privacy
+     * changes.
+     *
+     * @param executor the executor to dispatch the callback on
+     * @param listener the OnToggleSensorPrivacyChangedListener to be notified when the state of
+     *                 sensor privacy changes.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+    public void addSensorPrivacyListener(@NonNull Executor executor,
+            @NonNull OnToggleSensorPrivacyChangedListener listener) {
+        synchronized (mLock) {
+            addSensorPrivacyListenerLocked(executor, listener);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void addSensorPrivacyListenerLocked(@NonNull Executor executor,
+            @NonNull OnToggleSensorPrivacyChangedListener listener) {
+        if (!mToggleListenerRegistered) {
             try {
-                mService.addIndividualSensorPrivacyListener(userId, sensor,
-                        iListener);
+                mService.addToggleSensorPrivacyListener(mIToggleListener);
+                mToggleListenerRegistered = true;
             } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
+                e.rethrowFromSystemServer();
             }
         }
+        if (mToggleListeners.containsKey(listener)) {
+            throw new IllegalArgumentException("listener is already registered");
+        }
+        mToggleListeners.put(listener, executor);
     }
 
     /**
@@ -420,30 +529,60 @@
      * @param listener the OnSensorPrivacyChangedListener to be unregistered from notifications when
      *                 sensor privacy changes.
      *
+     * {@link #removeSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} with
+     * {@link #addSensorPrivacyListener(OnToggleSensorPrivacyChangedListener)} or
+     * {@link #addSensorPrivacyListener(Executor, OnToggleSensorPrivacyChangedListener)}
+     *
      * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
     public void removeSensorPrivacyListener(@Sensors.Sensor int sensor,
             @NonNull OnSensorPrivacyChangedListener listener) {
-        synchronized (mListeners) {
-            for (int i = 0; i < mIndividualListeners.size(); i++) {
-                Pair<OnSensorPrivacyChangedListener, Integer> pair = mIndividualListeners.keyAt(i);
-                if (pair.second == sensor && pair.first.equals(listener)) {
-                    try {
-                        mService.removeIndividualSensorPrivacyListener(sensor,
-                                mIndividualListeners.valueAt(i));
-                    } catch (RemoteException e) {
-                        throw e.rethrowFromSystemServer();
-                    }
-                    mIndividualListeners.removeAt(i--);
-                }
+        Pair<Integer, OnSensorPrivacyChangedListener> pair = new Pair(sensor, listener);
+        synchronized (mLock) {
+            OnToggleSensorPrivacyChangedListener onToggleSensorPrivacyChangedListener =
+                    mLegacyToggleListeners.remove(pair);
+            if (onToggleSensorPrivacyChangedListener != null) {
+                removeSensorPrivacyListenerLocked(onToggleSensorPrivacyChangedListener);
             }
         }
     }
 
     /**
-     * Returns whether sensor privacy is currently enabled for a specific sensor.
+     * Unregisters the specified listener from receiving notifications when the state of any sensor
+     * privacy changes.
+     *
+     * @param listener the {@link OnToggleSensorPrivacyChangedListener} to be unregistered from
+     *                 notifications when sensor privacy changes.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+    public void removeSensorPrivacyListener(
+            @NonNull OnToggleSensorPrivacyChangedListener listener) {
+        synchronized (mLock) {
+            removeSensorPrivacyListenerLocked(listener);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void removeSensorPrivacyListenerLocked(
+            @NonNull OnToggleSensorPrivacyChangedListener listener) {
+        mToggleListeners.remove(listener);
+        if (mToggleListeners.size() == 0) {
+            try {
+                mService.removeToggleSensorPrivacyListener(mIToggleListener);
+                mToggleListenerRegistered = false;
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        }
+    }
+
+    /**
+     * Returns whether sensor privacy is currently enabled by software control for a specific
+     * sensor.
      *
      * @return true if sensor privacy is currently enabled, false otherwise.
      *
@@ -452,7 +591,7 @@
     @SystemApi
     @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
     public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor) {
-        return isSensorPrivacyEnabled(sensor, UserHandle.USER_CURRENT);
+        return isSensorPrivacyEnabled(ToggleTypes.SOFTWARE, sensor);
     }
 
     /**
@@ -463,9 +602,27 @@
      * @hide
      */
     @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
-    public boolean isSensorPrivacyEnabled(@Sensors.Sensor int sensor, @UserIdInt int userId) {
+    public boolean isSensorPrivacyEnabled(@ToggleTypes.ToggleType int toggleType,
+            @Sensors.Sensor int sensor) {
         try {
-            return mService.isIndividualSensorPrivacyEnabled(userId, sensor);
+            return mService.isToggleSensorPrivacyEnabled(toggleType, sensor);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Returns whether sensor privacy is currently enabled for a specific sensor.
+     * Combines the state of the SW + HW toggles and returns the actual privacy state.
+     *
+     * @return true if sensor privacy is currently enabled, false otherwise.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.OBSERVE_SENSOR_PRIVACY)
+    public boolean isToggleSensorPrivacyEnabled(@Sensors.Sensor int sensor) {
+        try {
+            return mService.isCombinedToggleSensorPrivacyEnabled(sensor);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -524,7 +681,7 @@
     public void setSensorPrivacy(@Sources.Source int source, @Sensors.Sensor int sensor,
             boolean enable, @UserIdInt int userId) {
         try {
-            mService.setIndividualSensorPrivacy(userId, source, sensor, enable);
+            mService.setToggleSensorPrivacy(userId, source, sensor, enable);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -561,7 +718,7 @@
     public void setSensorPrivacyForProfileGroup(@Sources.Source int source,
             @Sensors.Sensor int sensor, boolean enable, @UserIdInt int userId) {
         try {
-            mService.setIndividualSensorPrivacyForProfileGroup(userId, source, sensor, enable);
+            mService.setToggleSensorPrivacyForProfileGroup(userId, source, sensor, enable);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -592,7 +749,7 @@
     public void suppressSensorPrivacyReminders(int sensor,
             boolean suppress, @UserIdInt int userId) {
         try {
-            mService.suppressIndividualSensorPrivacyReminders(userId, sensor,
+            mService.suppressToggleSensorPrivacyReminders(userId, sensor,
                     token, suppress);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -667,7 +824,8 @@
             if (iListener == null) {
                 iListener = new ISensorPrivacyListener.Stub() {
                     @Override
-                    public void onSensorPrivacyChanged(boolean enabled) {
+                    public void onSensorPrivacyChanged(int toggleType, int sensor,
+                            boolean enabled) {
                         listener.onAllSensorPrivacyChanged(enabled);
                     }
                 };
diff --git a/core/java/android/hardware/SensorPrivacyManagerInternal.java b/core/java/android/hardware/SensorPrivacyManagerInternal.java
index d12e9f8..f4de966 100644
--- a/core/java/android/hardware/SensorPrivacyManagerInternal.java
+++ b/core/java/android/hardware/SensorPrivacyManagerInternal.java
@@ -61,4 +61,9 @@
      */
     public abstract void addSensorPrivacyListenerForAllUsers(int sensor,
             OnUserSensorPrivacyChangedListener listener);
+
+    /**
+     *  Set the HW toggle sensor value based on HW switch states, called from InputManagerService
+     */
+    public abstract void setPhysicalToggleSensorPrivacy(int userId, int sensor, boolean enable);
 }
diff --git a/core/java/android/hardware/SyncFence.java b/core/java/android/hardware/SyncFence.java
index b0a6f51..99791ce 100644
--- a/core/java/android/hardware/SyncFence.java
+++ b/core/java/android/hardware/SyncFence.java
@@ -17,12 +17,17 @@
 package android.hardware;
 
 import android.annotation.NonNull;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLSync;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 
-import java.io.Closeable;
+import libcore.util.NativeAllocationRegistry;
+
+import java.io.FileDescriptor;
 import java.io.IOException;
+import java.time.Duration;
 
 /**
  * A SyncFence represents a synchronization primitive which signals when hardware buffers have
@@ -34,19 +39,57 @@
  * Once the fence signals, then the backing storage for the framebuffer may be safely read from,
  * such as for display or for media encoding.</p>
  *
- * @see <a href="https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkCreateFence.html">
- * VkFence</a>
+ * @see android.opengl.EGLExt#eglDupNativeFenceFDANDROID(EGLDisplay, EGLSync)
+ * @see android.media.Image#getFence()
  */
-public final class SyncFence implements Closeable, Parcelable {
-    private static final String TAG = "SyncFence";
+public final class SyncFence implements AutoCloseable, Parcelable {
 
     /**
-     * Wrapped {@link android.os.ParcelFileDescriptor}.
+     * An invalid signal time. Represents either the signal time for a SyncFence that isn't valid
+     * (that is, {@link #isValid()} is false), or if an error occurred while attempting to retrieve
+     * the signal time.
      */
-    private ParcelFileDescriptor mWrapped;
+    public static final long SIGNAL_TIME_INVALID = -1;
+
+    /**
+     * A pending signal time. This is equivalent to the max value of a long, representing an
+     * infinitely far point in the future.
+     */
+    public static final long SIGNAL_TIME_PENDING = Long.MAX_VALUE;
+
+    private static final NativeAllocationRegistry sRegistry =
+            NativeAllocationRegistry.createNonmalloced(SyncFence.class.getClassLoader(),
+                    nGetDestructor(), 4);
+
+    private long mNativePtr;
+
+    // The destructor for this object
+    // This is also used as our internal lock object. Although SyncFence doesn't claim to be
+    // thread-safe, the cost of doing so to avoid issues around double-close or similar issues
+    // is well worth making.
+    private final Runnable mCloser;
 
     private SyncFence(@NonNull ParcelFileDescriptor wrapped) {
-        mWrapped = wrapped;
+        mNativePtr = nCreate(wrapped.detachFd());
+        mCloser = sRegistry.registerNativeAllocation(this, mNativePtr);
+    }
+
+    private SyncFence(@NonNull Parcel parcel) {
+        boolean valid = parcel.readBoolean();
+        FileDescriptor fileDescriptor = null;
+        if (valid) {
+            fileDescriptor = parcel.readRawFileDescriptor();
+        }
+        if (fileDescriptor != null) {
+            mNativePtr = nCreate(fileDescriptor.getInt$());
+            mCloser = sRegistry.registerNativeAllocation(this, mNativePtr);
+        } else {
+            mCloser = () -> {};
+        }
+    }
+
+    private SyncFence() {
+        mCloser = () -> {};
     }
 
     /***
@@ -56,7 +99,7 @@
      * @hide
      */
     public static @NonNull SyncFence createEmpty() {
-        return new SyncFence(ParcelFileDescriptor.adoptFd(-1));
+        return new SyncFence();
     }
 
     /**
@@ -75,7 +118,13 @@
      * @hide
      */
     public @NonNull ParcelFileDescriptor getFdDup() throws IOException {
-        return mWrapped.dup();
+        synchronized (mCloser) {
+            final int fd = mNativePtr != 0 ? nGetFd(mNativePtr) : -1;
+            if (fd == -1) {
+                throw new IllegalStateException("Cannot dup the FD of an invalid SyncFence");
+            }
+            return ParcelFileDescriptor.fromFd(fd);
+        }
     }
 
     /**
@@ -85,29 +134,94 @@
      *         {@code false} otherwise.
      */
     public boolean isValid() {
-        return mWrapped.getFileDescriptor().valid();
+        synchronized (mCloser) {
+            return mNativePtr != 0 && nIsValid(mNativePtr);
+        }
+    }
+
+    /**
+     * Waits for a SyncFence to signal for up to the timeout duration.
+     *
+     * An invalid SyncFence, that is if {@link #isValid()} is false, is treated equivalently
+     * to a SyncFence that has already signaled. That is, wait() will immediately return true.
+     *
+     * @param timeout The timeout duration. If the duration is negative, then this waits forever.
+     * @return true if the fence signaled or isn't valid, false otherwise.
+     */
+    public boolean await(@NonNull Duration timeout) {
+        final long timeoutNanos;
+        if (timeout.isNegative()) {
+            timeoutNanos = -1;
+        } else {
+            timeoutNanos = timeout.toNanos();
+        }
+        return await(timeoutNanos);
+    }
+
+    /**
+     * Waits forever for a SyncFence to signal.
+     *
+     * An invalid SyncFence, that is if {@link #isValid()} is false, is treated equivalently
+     * to a SyncFence that has already signaled. That is, wait() will immediately return true.
+     *
+     * @return true if the fence signaled or isn't valid, false otherwise.
+     */
+    public boolean awaitForever() {
+        return await(-1);
+    }
+
+    private boolean await(long timeoutNanos) {
+        synchronized (mCloser) {
+            return mNativePtr != 0 && nWait(mNativePtr, timeoutNanos);
+        }
+    }
+
+    /**
+     * Returns the time that the fence signaled in the CLOCK_MONOTONIC time domain.
+     *
+     * If the fence isn't valid, that is if {@link #isValid()} is false, then this returns
+     * {@link #SIGNAL_TIME_INVALID}. Similarly, if an error occurs while trying to access the
+     * signal time, then {@link #SIGNAL_TIME_INVALID} is also returned.
+     *
+     * If the fence hasn't yet signaled, then {@link #SIGNAL_TIME_PENDING} is returned.
+     *
+     * @return The time the fence signaled, {@link #SIGNAL_TIME_INVALID} if there's an error,
+     *         or {@link #SIGNAL_TIME_PENDING} if the fence hasn't signaled yet.
+     */
+    public long getSignalTime() {
+        synchronized (mCloser) {
+            return mNativePtr != 0 ? nGetSignalTime(mNativePtr) : SIGNAL_TIME_INVALID;
+        }
     }
 
     /**
      * Close the SyncFence. This implementation closes the underlying OS resources allocated
      * this stream.
-     *
-     * @throws IOException If an error occurs attempting to close this SyncFence.
      */
     @Override
-    public void close() throws IOException {
-        if (mWrapped != null) {
-            try {
-                mWrapped.close();
-            } finally {
-                // success
+    public void close() {
+        synchronized (mCloser) {
+            if (mNativePtr == 0) {
+                return;
             }
+            mNativePtr = 0;
+            mCloser.run();
         }
     }
 
     @Override
     public int describeContents() {
-        return mWrapped.describeContents();
+        return CONTENTS_FILE_DESCRIPTOR;
+    }
+
+    /** @hide */
+    public Object getLock() {
+        return mCloser;
+    }
+
+    /** @hide */
+    public long getNativeFence() {
+        return mNativePtr;
     }
 
     /**
@@ -119,23 +233,36 @@
      */
     @Override
     public void writeToParcel(@NonNull Parcel out, int flags) {
-        try {
-            mWrapped.writeToParcel(out, flags);
-        } finally {
-            // success
+        synchronized (mCloser) {
+            final int fd = mNativePtr != 0 ? nGetFd(mNativePtr) : -1;
+            if (fd == -1) {
+                out.writeBoolean(false);
+            } else {
+                out.writeBoolean(true);
+                FileDescriptor temp = new FileDescriptor();
+                temp.setInt$(fd);
+                out.writeFileDescriptor(temp);
+            }
         }
     }
 
     public static final @NonNull Parcelable.Creator<SyncFence> CREATOR =
             new Parcelable.Creator<SyncFence>() {
-        @Override
-        public SyncFence createFromParcel(Parcel in) {
-            return new SyncFence(ParcelFileDescriptor.CREATOR.createFromParcel(in));
-        }
+                @Override
+                public SyncFence createFromParcel(Parcel in) {
+                    return new SyncFence(in);
+                }
 
-        @Override
-        public SyncFence[] newArray(int size) {
-            return new SyncFence[size];
-        }
-    };
+                @Override
+                public SyncFence[] newArray(int size) {
+                    return new SyncFence[size];
+                }
+            };
+
+    private static native long nGetDestructor();
+    private static native long nCreate(int fd);
+    private static native boolean nIsValid(long nPtr);
+    private static native int nGetFd(long nPtr);
+    private static native boolean nWait(long nPtr, long timeout);
+    private static native long nGetSignalTime(long nPtr);
 }
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 971b61b..c053c92 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -356,7 +356,6 @@
      * @see #VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
      * @hide
      */
-    @TestApi
     @SystemApi
     public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1 << 10;
 
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index a979725..7b695e7 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -39,13 +39,13 @@
 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE;
 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_UNKNOWN;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_ENABLED;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_OVERHEAT;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_CONTAMINANT;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_DOCK;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_FORCE;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_DEBUG;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_UNKNOWN;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_ENABLED;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_OVERHEAT;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_CONTAMINANT;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DOCK;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DEBUG;
 
 import android.Manifest;
 import android.annotation.CheckResult;
@@ -400,7 +400,7 @@
     }
 
     /**
-     * Enables Usb data when disabled due to {@link UsbPort#USB_DATA_STATUS_DISABLED_DOCK}
+     * Enables Usb data when disabled due to {@link UsbPort#DATA_STATUS_DISABLED_DOCK}
      *
      * @return {@link #ENABLE_USB_DATA_WHILE_DOCKED_SUCCESS} when request completes successfully or
      *         {@link #ENABLE_USB_DATA_WHILE_DOCKED_ERROR_INTERNAL} when request fails due to
@@ -421,7 +421,8 @@
                 + " callingUid:" + Binder.getCallingUid());
         UsbPortStatus portStatus = getStatus();
         if (portStatus != null &&
-                !usbDataStatusToString(portStatus.getUsbDataStatus()).contains("disabled-dock")) {
+                (portStatus.getUsbDataStatus() & DATA_STATUS_DISABLED_DOCK) !=
+                 DATA_STATUS_DISABLED_DOCK) {
             return ENABLE_USB_DATA_WHILE_DOCKED_ERROR_DATA_ENABLED;
         }
 
@@ -584,44 +585,43 @@
 
     /** @hide */
     public static String usbDataStatusToString(int usbDataStatus) {
-        switch (usbDataStatus) {
-            case USB_DATA_STATUS_UNKNOWN:
-                return "unknown";
-            case USB_DATA_STATUS_ENABLED:
-                return "enabled";
-            case USB_DATA_STATUS_DISABLED_OVERHEAT:
-                return "disabled-overheat";
-            case USB_DATA_STATUS_DISABLED_CONTAMINANT:
-                return "disabled-contaminant";
-            case USB_DATA_STATUS_DISABLED_DOCK:
-                return "disabled-dock";
-            case USB_DATA_STATUS_DISABLED_FORCE:
-                return "disabled-force";
-            case USB_DATA_STATUS_DISABLED_DEBUG:
-                return "disabled-debug";
-            default:
-                return Integer.toString(usbDataStatus);
-        }
-    }
+        StringBuilder statusString = new StringBuilder();
 
-    /** @hide */
-    public static String usbDataStatusToString(int[] usbDataStatus) {
-        StringBuilder modeString = new StringBuilder();
-        if (usbDataStatus == null) {
+        if (usbDataStatus == DATA_STATUS_UNKNOWN) {
             return "unknown";
         }
-        for (int i = 0; i < usbDataStatus.length; i++) {
-            modeString.append(usbDataStatusToString(usbDataStatus[i]));
-            if (i < usbDataStatus.length - 1) {
-                modeString.append(", ");
-            }
+
+        if ((usbDataStatus & DATA_STATUS_ENABLED) == DATA_STATUS_ENABLED) {
+            return "enabled";
         }
-        return modeString.toString();
+
+        if ((usbDataStatus & DATA_STATUS_DISABLED_OVERHEAT) == DATA_STATUS_DISABLED_OVERHEAT) {
+            statusString.append("disabled-overheat, ");
+        }
+
+        if ((usbDataStatus & DATA_STATUS_DISABLED_CONTAMINANT)
+                == DATA_STATUS_DISABLED_CONTAMINANT) {
+            statusString.append("disabled-contaminant, ");
+        }
+
+        if ((usbDataStatus & DATA_STATUS_DISABLED_DOCK) == DATA_STATUS_DISABLED_DOCK) {
+            statusString.append("disabled-dock, ");
+        }
+
+        if ((usbDataStatus & DATA_STATUS_DISABLED_FORCE) == DATA_STATUS_DISABLED_FORCE) {
+            statusString.append("disabled-force, ");
+        }
+
+        if ((usbDataStatus & DATA_STATUS_DISABLED_DEBUG) == DATA_STATUS_DISABLED_DEBUG) {
+            statusString.append("disabled-debug, ");
+        }
+
+        return statusString.toString().replaceAll(", $", "");
     }
 
     /** @hide */
-    public static String powerBrickStatusToString(int powerBrickStatus) {
-        switch (powerBrickStatus) {
+    public static String powerBrickConnectionStatusToString(int powerBrickConnectionStatus) {
+        switch (powerBrickConnectionStatus) {
             case POWER_BRICK_STATUS_UNKNOWN:
                 return "unknown";
             case POWER_BRICK_STATUS_CONNECTED:
@@ -629,7 +629,7 @@
             case POWER_BRICK_STATUS_DISCONNECTED:
                 return "disconnected";
             default:
-                return Integer.toString(powerBrickStatus);
+                return Integer.toString(powerBrickConnectionStatus);
         }
     }
 
diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java
index d1f4246..3221ec8 100644
--- a/core/java/android/hardware/usb/UsbPortStatus.java
+++ b/core/java/android/hardware/usb/UsbPortStatus.java
@@ -44,8 +44,8 @@
     private final @ContaminantProtectionStatus int mContaminantProtectionStatus;
     private final @ContaminantDetectionStatus int mContaminantDetectionStatus;
     private final boolean mPowerTransferLimited;
-    private final @UsbDataStatus int[] mUsbDataStatus;
-    private final @PowerBrickStatus int mPowerBrickStatus;
+    private final @UsbDataStatus int mUsbDataStatus;
+    private final @PowerBrickConnectionStatus int mPowerBrickConnectionStatus;
 
     /**
      * Power role: This USB port does not have a power role.
@@ -198,38 +198,38 @@
     /**
      * USB data status is not known.
      */
-    public static final int USB_DATA_STATUS_UNKNOWN = 0;
+    public static final int DATA_STATUS_UNKNOWN = 0;
 
     /**
      * USB data is enabled.
      */
-    public static final int USB_DATA_STATUS_ENABLED = 1;
+    public static final int DATA_STATUS_ENABLED = 1 << 0;
 
     /**
      * USB data is disabled as the port is too hot.
      */
-    public static final int USB_DATA_STATUS_DISABLED_OVERHEAT = 2;
+    public static final int DATA_STATUS_DISABLED_OVERHEAT = 1 << 1;
 
     /**
      * USB data is disabled due to contaminated port.
      */
-    public static final int USB_DATA_STATUS_DISABLED_CONTAMINANT = 3;
+    public static final int DATA_STATUS_DISABLED_CONTAMINANT = 1 << 2;
 
     /**
      * USB data is disabled due to docking event.
      */
-    public static final int USB_DATA_STATUS_DISABLED_DOCK = 4;
+    public static final int DATA_STATUS_DISABLED_DOCK = 1 << 3;
 
     /**
      * USB data is disabled by
      * {@link UsbPort#enableUsbData UsbPort.enableUsbData}.
      */
-    public static final int USB_DATA_STATUS_DISABLED_FORCE = 5;
+    public static final int DATA_STATUS_DISABLED_FORCE = 1 << 4;
 
     /**
      * USB data is disabled for debug.
      */
-    public static final int USB_DATA_STATUS_DISABLED_DEBUG = 6;
+    public static final int DATA_STATUS_DISABLED_DEBUG = 1 << 5;
 
     /**
      * Unknown whether a power brick is connected.
@@ -276,14 +276,14 @@
     @interface UsbPortMode{}
 
     /** @hide */
-    @IntDef(prefix = { "USB_DATA_STATUS_" }, value = {
-            USB_DATA_STATUS_UNKNOWN,
-            USB_DATA_STATUS_ENABLED,
-            USB_DATA_STATUS_DISABLED_OVERHEAT,
-            USB_DATA_STATUS_DISABLED_CONTAMINANT,
-            USB_DATA_STATUS_DISABLED_DOCK,
-            USB_DATA_STATUS_DISABLED_FORCE,
-            USB_DATA_STATUS_DISABLED_DEBUG
+    @IntDef(prefix = { "DATA_STATUS_" }, flag = true, value = {
+            DATA_STATUS_UNKNOWN,
+            DATA_STATUS_ENABLED,
+            DATA_STATUS_DISABLED_OVERHEAT,
+            DATA_STATUS_DISABLED_CONTAMINANT,
+            DATA_STATUS_DISABLED_DOCK,
+            DATA_STATUS_DISABLED_FORCE,
+            DATA_STATUS_DISABLED_DEBUG
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface UsbDataStatus{}
@@ -295,13 +295,14 @@
             POWER_BRICK_STATUS_CONNECTED,
     })
     @Retention(RetentionPolicy.SOURCE)
-    @interface PowerBrickStatus{}
+    @interface PowerBrickConnectionStatus{}
 
     /** @hide */
     public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
             int supportedRoleCombinations, int contaminantProtectionStatus,
-            int contaminantDetectionStatus, @UsbDataStatus int[] usbDataStatus,
-            boolean powerTransferLimited, @PowerBrickStatus int powerBrickStatus) {
+            int contaminantDetectionStatus, @UsbDataStatus int usbDataStatus,
+            boolean powerTransferLimited,
+            @PowerBrickConnectionStatus int powerBrickConnectionStatus) {
         mCurrentMode = currentMode;
         mCurrentPowerRole = currentPowerRole;
         mCurrentDataRole = currentDataRole;
@@ -310,7 +311,7 @@
         mContaminantDetectionStatus = contaminantDetectionStatus;
         mUsbDataStatus = usbDataStatus;
         mPowerTransferLimited = powerTransferLimited;
-        mPowerBrickStatus = powerBrickStatus;
+        mPowerBrickConnectionStatus = powerBrickConnectionStatus;
     }
 
     /** @hide */
@@ -323,8 +324,8 @@
         mSupportedRoleCombinations = supportedRoleCombinations;
         mContaminantProtectionStatus = contaminantProtectionStatus;
         mContaminantDetectionStatus = contaminantDetectionStatus;
-        mUsbDataStatus = new int[]{USB_DATA_STATUS_UNKNOWN};
-        mPowerBrickStatus = POWER_BRICK_STATUS_UNKNOWN;
+        mUsbDataStatus = DATA_STATUS_UNKNOWN;
+        mPowerBrickConnectionStatus = POWER_BRICK_STATUS_UNKNOWN;
         mPowerTransferLimited = false;
     }
 
@@ -411,13 +412,13 @@
     /**
      * Returns UsbData status.
      *
-     * @return Current USB data status of the port: {@link #USB_DATA_STATUS_UNKNOWN}
-     *         or {@link #USB_DATA_STATUS_ENABLED} or {@link #USB_DATA_STATUS_DIASBLED_OVERHEAT}
-     *         or {@link #USB_DATA_STATUS_DISABLED_CONTAMINANT}
-     *         or {@link #USB_DATA_STATUS_DISABLED_DOCK} or {@link #USB_DATA_STATUS_DISABLED_FORCE}
-     *         or {@link #USB_DATA_STATUS_DISABLED_DEBUG}
+     * @return Current USB data status of the port with one or more of the following values
+     *         {@link #DATA_STATUS_UNKNOWN}, {@link #DATA_STATUS_ENABLED},
+     *         {@link #DATA_STATUS_DISABLED_OVERHEAT}, {@link #DATA_STATUS_DISABLED_CONTAMINANT},
+     *         {@link #DATA_STATUS_DISABLED_DOCK}, {@link #DATA_STATUS_DISABLED_FORCE},
+     *         {@link #DATA_STATUS_DISABLED_DEBUG}
      */
-    public @UsbDataStatus @Nullable int[] getUsbDataStatus() {
+    public @UsbDataStatus int getUsbDataStatus() {
         return mUsbDataStatus;
     }
 
@@ -432,14 +433,14 @@
     }
 
     /**
-     * Let's the caller know if a power brick is connected to the USB port.
+     * Returns the connection status of the power brick.
      *
      * @return {@link #POWER_BRICK_STATUS_UNKNOWN}
      *         or {@link #POWER_BRICK_STATUS_CONNECTED}
      *         or {@link #POWER_BRICK_STATUS_DISCONNECTED}
      */
-    public @PowerBrickStatus int getPowerBrickStatus() {
-        return mPowerBrickStatus;
+    public @PowerBrickConnectionStatus int getPowerBrickConnectionStatus() {
+        return mPowerBrickConnectionStatus;
     }
 
     @NonNull
@@ -459,8 +460,9 @@
                         + UsbPort.usbDataStatusToString(getUsbDataStatus())
                 + ", isPowerTransferLimited="
                         + isPowerTransferLimited()
-                +", powerBrickStatus="
-                        + UsbPort.powerBrickStatusToString(getPowerBrickStatus())
+                +", powerBrickConnectionStatus="
+                        + UsbPort
+                            .powerBrickConnectionStatusToString(getPowerBrickConnectionStatus())
                 + "}";
     }
 
@@ -477,10 +479,9 @@
         dest.writeInt(mSupportedRoleCombinations);
         dest.writeInt(mContaminantProtectionStatus);
         dest.writeInt(mContaminantDetectionStatus);
-        dest.writeInt(mUsbDataStatus.length);
-        dest.writeIntArray(mUsbDataStatus);
+        dest.writeInt(mUsbDataStatus);
         dest.writeBoolean(mPowerTransferLimited);
-        dest.writeInt(mPowerBrickStatus);
+        dest.writeInt(mPowerBrickConnectionStatus);
     }
 
     public static final @NonNull Parcelable.Creator<UsbPortStatus> CREATOR =
@@ -493,14 +494,13 @@
             int supportedRoleCombinations = in.readInt();
             int contaminantProtectionStatus = in.readInt();
             int contaminantDetectionStatus = in.readInt();
-            int[] usbDataStatus = new int[in.readInt()];
-            in.readIntArray(usbDataStatus);
+            int usbDataStatus = in.readInt();
             boolean powerTransferLimited = in.readBoolean();
-            int powerBrickStatus = in.readInt();
+            int powerBrickConnectionStatus = in.readInt();
             return new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
                     supportedRoleCombinations, contaminantProtectionStatus,
                     contaminantDetectionStatus, usbDataStatus, powerTransferLimited,
-                    powerBrickStatus);
+                    powerBrickConnectionStatus);
         }
 
         @Override
@@ -508,4 +508,126 @@
             return new UsbPortStatus[size];
         }
     };
+
+    /**
+     * Builder is used to create {@link UsbPortStatus} objects.
+     *
+     * @hide
+     */
+    public static final class Builder {
+        private @UsbPortMode int mCurrentMode;
+        private @UsbPowerRole int mCurrentPowerRole;
+        private @UsbDataRole int mCurrentDataRole;
+        private int mSupportedRoleCombinations;
+        private @ContaminantProtectionStatus int mContaminantProtectionStatus;
+        private @ContaminantDetectionStatus int mContaminantDetectionStatus;
+        private boolean mPowerTransferLimited;
+        private @UsbDataStatus int mUsbDataStatus;
+        private @PowerBrickConnectionStatus int mPowerBrickConnectionStatus;
+
+        public Builder() {
+            mCurrentMode = MODE_NONE;
+            mCurrentPowerRole = POWER_ROLE_NONE;
+            mCurrentDataRole = DATA_ROLE_NONE;
+            mContaminantProtectionStatus = CONTAMINANT_PROTECTION_NONE;
+            mContaminantDetectionStatus = CONTAMINANT_DETECTION_NOT_SUPPORTED;
+            mUsbDataStatus = DATA_STATUS_UNKNOWN;
+            mPowerBrickConnectionStatus = POWER_BRICK_STATUS_UNKNOWN;
+        }
+
+        /**
+         * Sets the current mode of {@link UsbPortStatus}
+         *
+         * @return Instance of {@link Builder}
+         */
+        @NonNull
+        public Builder setCurrentMode(@UsbPortMode int currentMode) {
+            mCurrentMode = currentMode;
+            return this;
+        }
+
+        /**
+         * Sets the current power role and data role of {@link UsbPortStatus}
+         *
+         * @return Instance of {@link Builder}
+         */
+        @NonNull
+        public Builder setCurrentRoles(@UsbPowerRole int currentPowerRole,
+                @UsbDataRole int currentDataRole) {
+            mCurrentPowerRole = currentPowerRole;
+            mCurrentDataRole = currentDataRole;
+            return this;
+        }
+
+        /**
+         * Sets supported role combinations of {@link UsbPortStatus}
+         *
+         * @return Instance of {@link Builder}
+         */
+        @NonNull
+        public Builder setSupportedRoleCombinations(int supportedRoleCombinations) {
+            mSupportedRoleCombinations = supportedRoleCombinations;
+            return this;
+        }
+
+        /**
+         * Sets current contaminant status of {@link UsbPortStatus}
+         *
+         * @return Instance of {@link Builder}
+         */
+        @NonNull
+        public Builder setContaminantStatus(
+                @ContaminantProtectionStatus int contaminantProtectionStatus,
+                @ContaminantDetectionStatus int contaminantDetectionStatus) {
+            mContaminantProtectionStatus = contaminantProtectionStatus;
+            mContaminantDetectionStatus = contaminantDetectionStatus;
+            return this;
+        }
+
+        /**
+         * Sets power limit power transfer of {@link UsbPortStatus}
+         *
+         * @return Instance of {@link Builder}
+         */
+        @NonNull
+        public Builder setPowerTransferLimited(boolean powerTransferLimited) {
+            mPowerTransferLimited = powerTransferLimited;
+            return this;
+        }
+
+        /**
+         * Sets the USB data status of {@link UsbPortStatus}
+         *
+         * @return Instance of {@link Builder}
+         */
+        @NonNull
+        public Builder setUsbDataStatus(@UsbDataStatus int usbDataStatus) {
+            mUsbDataStatus = usbDataStatus;
+            return this;
+        }
+
+        /**
+         * Sets the power brick connection status of {@link UsbPortStatus}
+         *
+         * @return Instance of {@link Builder}
+         */
+        @NonNull
+        public Builder setPowerBrickConnectionStatus(
+                @PowerBrickConnectionStatus int powerBrickConnectionStatus) {
+            mPowerBrickConnectionStatus = powerBrickConnectionStatus;
+            return this;
+        }
+
+        /**
+         * Creates the {@link UsbPortStatus} object.
+         */
+        @NonNull
+        public UsbPortStatus build() {
+            UsbPortStatus status = new UsbPortStatus(mCurrentMode, mCurrentPowerRole,
+                    mCurrentDataRole, mSupportedRoleCombinations, mContaminantProtectionStatus,
+                    mContaminantDetectionStatus, mUsbDataStatus, mPowerTransferLimited,
+                    mPowerBrickConnectionStatus);
+            return status;
+        }
+    };
 }
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index adf2759..b6078e0 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -989,24 +989,6 @@
         public void changeInputMethodSubtype(InputMethodSubtype subtype) {
             dispatchOnCurrentInputMethodSubtypeChanged(subtype);
         }
-
-        /**
-         * {@inheritDoc}
-         * @hide
-         */
-        @Override
-        public void setCurrentShowInputToken(IBinder showInputToken) {
-            mCurShowInputToken = showInputToken;
-        }
-
-        /**
-         * {@inheritDoc}
-         * @hide
-         */
-        @Override
-        public void setCurrentHideInputToken(IBinder hideInputToken) {
-            mCurHideInputToken = hideInputToken;
-        }
     }
 
     /**
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index 6f4fd76..19fa01d 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -45,7 +45,6 @@
 import android.view.Window;
 import android.view.WindowInsets;
 import android.view.WindowInsetsController.Appearance;
-import android.view.WindowManagerPolicyConstants;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 import android.widget.FrameLayout;
@@ -138,7 +137,7 @@
 
         private boolean mDestroyed = false;
 
-        private boolean mRenderGesturalNavButtons;
+        private boolean mImeDrawsImeNavBar;
 
         @Nullable
         private NavigationBarFrame mNavigationBarFrame;
@@ -185,7 +184,7 @@
         }
 
         private void installNavigationBarFrameIfNecessary() {
-            if (!mRenderGesturalNavButtons) {
+            if (!mImeDrawsImeNavBar) {
                 return;
             }
             if (mNavigationBarFrame != null) {
@@ -253,7 +252,7 @@
         @Override
         public void updateTouchableInsets(@NonNull InputMethodService.Insets originalInsets,
                 @NonNull ViewTreeObserver.InternalInsetsInfo dest) {
-            if (!mRenderGesturalNavButtons || mNavigationBarFrame == null
+            if (!mImeDrawsImeNavBar || mNavigationBarFrame == null
                     || mService.isExtractViewShown()) {
                 return;
             }
@@ -360,13 +359,12 @@
             });
         }
 
-        private boolean isGesturalNavigationEnabled() {
+        private boolean imeDrawsImeNavBar() {
             final Resources resources = mService.getResources();
             if (resources == null) {
                 return false;
             }
-            return resources.getInteger(com.android.internal.R.integer.config_navBarInteractionMode)
-                    == WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
+            return resources.getBoolean(com.android.internal.R.bool.config_imeDrawsImeNavBar);
         }
 
         @Override
@@ -381,7 +379,7 @@
             if (mDestroyed) {
                 return;
             }
-            mRenderGesturalNavButtons = isGesturalNavigationEnabled();
+            mImeDrawsImeNavBar = imeDrawsImeNavBar();
             if (mSystemOverlayChangedReceiver == null) {
                 final IntentFilter intentFilter = new IntentFilter(ACTION_OVERLAY_CHANGED);
                 intentFilter.addDataScheme(IntentFilter.SCHEME_PACKAGE);
@@ -392,8 +390,8 @@
                         if (mDestroyed) {
                             return;
                         }
-                        mRenderGesturalNavButtons = isGesturalNavigationEnabled();
-                        if (mRenderGesturalNavButtons) {
+                        mImeDrawsImeNavBar = imeDrawsImeNavBar();
+                        if (mImeDrawsImeNavBar) {
                             installNavigationBarFrameIfNecessary();
                         } else {
                             uninstallNavigationBarFrameIfNecessary();
@@ -423,7 +421,7 @@
 
         @Override
         public void onWindowShown() {
-            if (mDestroyed || !mRenderGesturalNavButtons || mNavigationBarFrame == null) {
+            if (mDestroyed || !mImeDrawsImeNavBar || mNavigationBarFrame == null) {
                 return;
             }
             final Insets systemInsets = getSystemInsets();
@@ -546,7 +544,7 @@
 
         @Override
         public String toDebugString() {
-            return "{mRenderGesturalNavButtons=" + mRenderGesturalNavButtons
+            return "{mImeDrawsImeNavBar=" + mImeDrawsImeNavBar
                     + " mNavigationBarFrame=" + mNavigationBarFrame
                     + " mShouldShowImeSwitcherWhenImeIsShown="
                     + mShouldShowImeSwitcherWhenImeIsShown
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index b9252d6..7379443 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -104,6 +104,8 @@
 public final class SystemClock {
     private static final String TAG = "SystemClock";
 
+    private static volatile IAlarmManager sIAlarmManager;
+
     /**
      * This class is uninstantiable.
      */
@@ -151,8 +153,7 @@
      * @return if the clock was successfully set to the specified time.
      */
     public static boolean setCurrentTimeMillis(long millis) {
-        final IAlarmManager mgr = IAlarmManager.Stub
-                .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
+        final IAlarmManager mgr = getIAlarmManager();
         if (mgr == null) {
             Slog.e(TAG, "Unable to set RTC: mgr == null");
             return false;
@@ -280,8 +281,7 @@
      * @hide
      */
     public static long currentNetworkTimeMillis() {
-        final IAlarmManager mgr = IAlarmManager.Stub
-                .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
+        final IAlarmManager mgr = getIAlarmManager();
         if (mgr != null) {
             try {
                 return mgr.currentNetworkTimeMillis();
@@ -296,6 +296,14 @@
         }
     }
 
+    private static IAlarmManager getIAlarmManager() {
+        if (sIAlarmManager == null) {
+            sIAlarmManager = IAlarmManager.Stub
+                    .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
+        }
+        return sIAlarmManager;
+    }
+
     /**
      * Returns a {@link Clock} that starts at January 1, 1970 00:00:00.0 UTC,
      * synchronized using a remote network source outside the device.
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 4e1337f..cc98339 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1538,6 +1538,8 @@
      * be reserved for cached data depending on the device state which is then passed on
      * to getStorageCacheBytes.
      *
+     * Input File path must point to a storage volume.
+     *
      * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ea20ed4..23e02e9 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11720,8 +11720,8 @@
                 "night_display_forced_auto_mode_available";
 
         /**
-         * If UTC time between two NITZ signals is greater than this value then the second signal
-         * cannot be ignored.
+         * If Unix epoch time between two NITZ signals is greater than this value then the second
+         * signal cannot be ignored.
          *
          * <p>This value is in milliseconds. It is used for telephony-based time and time zone
          * detection.
@@ -16865,6 +16865,14 @@
                 "system_server_watchdog_timeout_ms";
 
         /**
+         * Whether to enable managed device provisioning via the role holder.
+         *
+         * @hide
+         */
+        public static final String MANAGED_PROVISIONING_DEFER_PROVISIONING_TO_ROLE_HOLDER =
+                "managed_provisioning_defer_provisioning_to_role_holder";
+
+        /**
          * Settings migrated from Wear OS settings provider.
          * @hide
          */
diff --git a/core/java/android/service/resumeonreboot/OWNERS b/core/java/android/service/resumeonreboot/OWNERS
index 3a127d5..721fbaf 100644
--- a/core/java/android/service/resumeonreboot/OWNERS
+++ b/core/java/android/service/resumeonreboot/OWNERS
@@ -1,2 +1 @@
-xunchang@google.com
-zhaojiac@google.com
+ejyzhang@google.com
\ No newline at end of file
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index e075c05..832db91 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -17,6 +17,7 @@
 package android.speech;
 
 import android.Manifest;
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
@@ -38,7 +39,6 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
-import android.util.Pair;
 import android.util.Slog;
 
 import com.android.internal.R;
@@ -49,6 +49,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Queue;
+import java.util.concurrent.Executor;
 import java.util.concurrent.LinkedBlockingQueue;
 
 /**
@@ -206,10 +207,9 @@
                     handleSetTemporaryComponent((ComponentName) msg.obj);
                     break;
                 case MSG_CHECK_RECOGNITION_SUPPORT:
-                    Pair<Intent, RecognitionSupportCallback> intentAndListener =
-                            (Pair<Intent, RecognitionSupportCallback>) msg.obj;
+                    CheckRecognitionSupportArgs args = (CheckRecognitionSupportArgs) msg.obj;
                     handleCheckRecognitionSupport(
-                            intentAndListener.first, intentAndListener.second);
+                            args.mIntent, args.mCallbackExecutor, args.mCallback);
                     break;
                 case MSG_TRIGGER_MODEL_DOWNLOAD:
                     handleTriggerModelDownload((Intent) msg.obj);
@@ -492,6 +492,7 @@
      */
     public void checkRecognitionSupport(
             @NonNull Intent recognizerIntent,
+            @NonNull @CallbackExecutor Executor executor,
             @NonNull RecognitionSupportCallback supportListener) {
         Objects.requireNonNull(recognizerIntent, "intent must not be null");
         Objects.requireNonNull(supportListener, "listener must not be null");
@@ -508,13 +509,13 @@
             connectToSystemService();
         }
         putMessage(Message.obtain(mHandler, MSG_CHECK_RECOGNITION_SUPPORT,
-                Pair.create(recognizerIntent, supportListener)));
+                new CheckRecognitionSupportArgs(recognizerIntent, executor, supportListener)));
     }
 
     /**
      * Attempts to download the support for the given {@code recognizerIntent}. This might trigger
      * user interaction to approve the download. Callers can verify the status of the request via
-     * {@link #checkRecognitionSupport(Intent, RecognitionSupportCallback)}.
+     * {@link #checkRecognitionSupport(Intent, Executor, RecognitionSupportCallback)}.
      *
      * @param recognizerIntent contains parameters for the recognition to be performed. The intent
      *        may also contain optional extras, see {@link RecognizerIntent}.
@@ -625,18 +626,20 @@
     }
 
     private void handleCheckRecognitionSupport(
-            Intent recognizerIntent, RecognitionSupportCallback recognitionSupportCallback) {
+            Intent recognizerIntent,
+            Executor callbackExecutor,
+            RecognitionSupportCallback recognitionSupportCallback) {
         if (!maybeInitializeManagerService()) {
             return;
         }
         try {
             mService.checkRecognitionSupport(
                     recognizerIntent,
-                    new InternalSupportCallback(recognitionSupportCallback));
+                    new InternalSupportCallback(callbackExecutor, recognitionSupportCallback));
             if (DBG) Log.d(TAG, "service support command succeeded");
         } catch (final RemoteException e) {
             Log.e(TAG, "checkRecognitionSupport() failed", e);
-            mListener.onError(ERROR_CLIENT);
+            callbackExecutor.execute(() -> recognitionSupportCallback.onError(ERROR_CLIENT));
         }
     }
 
@@ -780,6 +783,21 @@
         return ComponentName.unflattenFromString(serviceComponent);
     }
 
+    private static class CheckRecognitionSupportArgs {
+        final Intent mIntent;
+        final Executor mCallbackExecutor;
+        final RecognitionSupportCallback mCallback;
+
+        private CheckRecognitionSupportArgs(
+                Intent intent,
+                Executor callbackExecutor,
+                RecognitionSupportCallback callback) {
+            mIntent = intent;
+            mCallbackExecutor = callbackExecutor;
+            mCallback = callback;
+        }
+    }
+
     /**
      * Internal wrapper of IRecognitionListener which will propagate the results to
      * RecognitionListener
@@ -890,40 +908,22 @@
     }
 
     private static class InternalSupportCallback extends IRecognitionSupportCallback.Stub {
+        private final Executor mExecutor;
         private final RecognitionSupportCallback mCallback;
 
-        private static final int MSG_SUPPORT_RESULT = 1;
-        private static final int MSG_ERROR = 2;
-
-        private final Handler mInternalHandler = new Handler(Looper.getMainLooper()) {
-            @Override
-            public void handleMessage(Message msg) {
-                if (mCallback == null) {
-                    return;
-                }
-                switch (msg.what) {
-                    case MSG_SUPPORT_RESULT:
-                        mCallback.onSupportResult((RecognitionSupport) msg.obj);
-                        break;
-                    case MSG_ERROR:
-                        mCallback.onError((Integer) msg.obj);
-                        break;
-                }
-            }
-        };
-
-        private InternalSupportCallback(RecognitionSupportCallback callback) {
+        private InternalSupportCallback(Executor executor, RecognitionSupportCallback callback) {
+            this.mExecutor = executor;
             this.mCallback = callback;
         }
 
         @Override
         public void onSupportResult(RecognitionSupport recognitionSupport) throws RemoteException {
-            Message.obtain(mInternalHandler, MSG_SUPPORT_RESULT, recognitionSupport).sendToTarget();
+            mExecutor.execute(() -> mCallback.onSupportResult(recognitionSupport));
         }
 
         @Override
         public void onError(int errorCode) throws RemoteException {
-            Message.obtain(mInternalHandler, MSG_ERROR, errorCode).sendToTarget();
+            mExecutor.execute(() -> mCallback.onError(errorCode));
         }
     }
 }
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 048b94f..188bc3f 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -67,6 +67,13 @@
     public static final String SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME =
             "settings_app_allow_dark_theme_activation_at_bedtime";
 
+    /**
+     * Hide back key in the Settings two pane design.
+     * @hide
+     */
+    public static final String SETTINGS_HIDE_SECONDARY_PAGE_BACK_BUTTON_IN_TWO_PANE =
+            "settings_hide_secondary_page_back_button_in_two_pane";
+
     private static final Map<String, String> DEFAULT_FLAGS;
 
     static {
@@ -92,6 +99,7 @@
         DEFAULT_FLAGS.put(SETTINGS_APP_LANGUAGE_SELECTION, "true");
         DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true");
         DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "false");
+        DEFAULT_FLAGS.put(SETTINGS_HIDE_SECONDARY_PAGE_BACK_BUTTON_IN_TWO_PANE, "true");
     }
 
     private static final Set<String> PERSISTENT_FLAGS;
@@ -101,6 +109,7 @@
         PERSISTENT_FLAGS.add(SETTINGS_SUPPORT_LARGE_SCREEN);
         PERSISTENT_FLAGS.add(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
         PERSISTENT_FLAGS.add(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME);
+        PERSISTENT_FLAGS.add(SETTINGS_HIDE_SECONDARY_PAGE_BACK_BUTTON_IN_TWO_PANE);
     }
 
     /**
diff --git a/core/java/android/util/OWNERS b/core/java/android/util/OWNERS
index 28c078e..d4cf6e6 100644
--- a/core/java/android/util/OWNERS
+++ b/core/java/android/util/OWNERS
@@ -6,3 +6,7 @@
 per-file TypedValue.java = file:/core/java/android/content/res/OWNERS
 
 per-file PackageUtils.java = file:/core/java/android/content/pm/OWNERS
+
+per-file NtpTrustedTime.java = file:/services/core/java/com/android/server/timezonedetector/OWNERS
+per-file TimeUtils.java = file:/services/core/java/com/android/server/timezonedetector/OWNERS
+per-file TrustedTime.java = file:/services/core/java/com/android/server/timezonedetector/OWNERS
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 5fd0c33..9a93e1b 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -153,8 +153,8 @@
      *
      * <p>Time zone database updates should be expected to occur periodically due to
      * political and legal changes that cannot be anticipated in advance.  Therefore,
-     * when computing the UTC time for a future event, applications should be aware that
-     * the results may differ following a time zone database update.  This method allows
+     * when computing the time for a future event, applications should be aware that the
+     * results may differ following a time zone database update.  This method allows
      * applications to detect that a database change has occurred, and to recalculate any
      * cached times accordingly.
      *
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 36baa04..ce21086 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -65,7 +65,7 @@
 import android.view.SurfaceControl;
 import android.view.displayhash.DisplayHash;
 import android.view.displayhash.VerifiedDisplayHash;
-import android.window.IOnFpsCallbackListener;
+import android.window.ITaskFpsCallback;
 
 /**
  * System private interface to the window manager.
@@ -926,21 +926,21 @@
      * registered, the registered callback will not be unregistered until
      * {@link unregisterTaskFpsCallback()} is called
      * @param taskId task id of the task.
-     * @param listener listener to be registered.
+     * @param callback callback to be registered.
      *
      * @hide
      */
-    void registerTaskFpsCallback(in int taskId, in IOnFpsCallbackListener listener);
+    void registerTaskFpsCallback(in int taskId, in ITaskFpsCallback callback);
 
     /**
      * Unregisters the frame rate per second count callback which was registered with
      * {@link #registerTaskFpsCallback(int,TaskFpsCallback)}.
      *
-     * @param listener listener to be unregistered.
+     * @param callback callback to be unregistered.
      *
      * @hide
      */
-    void unregisterTaskFpsCallback(in IOnFpsCallbackListener listener);
+    void unregisterTaskFpsCallback(in ITaskFpsCallback listener);
 
     /**
      * Take a snapshot using the same path that's used for Recents. This is used for Testing only.
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index ce54968..c08177e 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -46,10 +46,13 @@
 import android.gui.DropInputMode;
 import android.hardware.DataSpace;
 import android.hardware.HardwareBuffer;
+import android.hardware.SyncFence;
 import android.hardware.display.DeviceProductInfo;
 import android.hardware.display.DisplayedContentSample;
 import android.hardware.display.DisplayedContentSamplingAttributes;
 import android.hardware.graphics.common.DisplayDecorationSupport;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLSync;
 import android.os.Build;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -209,7 +212,7 @@
     private static native void nativeReparent(long transactionObj, long nativeObject,
             long newParentNativeObject);
     private static native void nativeSetBuffer(long transactionObj, long nativeObject,
-            HardwareBuffer buffer);
+            HardwareBuffer buffer, long fencePtr);
     private static native void nativeSetBufferTransform(long transactionObj, long nativeObject,
             int transform);
     private static native void nativeSetDataSpace(long transactionObj, long nativeObject,
@@ -3692,8 +3695,44 @@
          */
         public @NonNull Transaction setBuffer(@NonNull SurfaceControl sc,
                 @Nullable HardwareBuffer buffer) {
+            return setBuffer(sc, buffer, null);
+        }
+
+        /**
+         * Updates the HardwareBuffer displayed for the SurfaceControl.
+         *
+         * Note that the buffer must be allocated with {@link HardwareBuffer#USAGE_COMPOSER_OVERLAY}
+         * as well as {@link HardwareBuffer#USAGE_GPU_SAMPLED_IMAGE} as the surface control might
+         * be composited using either an overlay or using the GPU.
+         *
+         * A presentation fence may be passed to improve performance by allowing the buffer
+         * to complete rendering while it is waiting for the transaction to be applied.
+         * For example, if the buffer is being produced by rendering with OpenGL ES then
+         * a fence created with
+         * {@link android.opengl.EGLExt#eglDupNativeFenceFDANDROID(EGLDisplay, EGLSync)} can be
+         * used to allow the GPU rendering to be concurrent with the transaction. The compositor
+         * will wait for the fence to be signaled before the buffer is displayed. If multiple
+         * buffers are set as part of the same transaction, the presentation fences of all of them
+         * must signal before any buffer is displayed. That is, the entire transaction is delayed
+         * until all presentation fences have signaled, ensuring the transaction remains consistent.
+         *
+         * @param sc The SurfaceControl to update
+         * @param buffer The buffer to be displayed
+         * @param fence The presentation fence. If null or invalid, this is equivalent to
+         *              {@link #setBuffer(SurfaceControl, HardwareBuffer)}
+         * @return this
+         */
+        public @NonNull Transaction setBuffer(@NonNull SurfaceControl sc,
+                @Nullable HardwareBuffer buffer, @Nullable SyncFence fence) {
             checkPreconditions(sc);
-            nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer);
+            if (fence != null) {
+                synchronized (fence.getLock()) {
+                    nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer,
+                            fence.getNativeFence());
+                }
+            } else {
+                nativeSetBuffer(mNativeObject, sc.mNativeObject, buffer, 0);
+            }
             return this;
         }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8236fbb..8444032 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1201,7 +1201,7 @@
                         mTmpFrames.displayFrame, mTempRect2, mTmpFrames.frame);
                 setFrame(mTmpFrames.frame);
                 registerBackCallbackOnWindow();
-                if (WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+                if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
                     // For apps requesting legacy back behavior, we add a compat callback that
                     // dispatches {@link KeyEvent#KEYCODE_BACK} to their root views.
                     // This way from system point of view, these apps are providing custom
@@ -6507,7 +6507,7 @@
 
             if (isBack(event)
                     && mContext != null
-                    && !WindowOnBackInvokedDispatcher.shouldUseLegacyBack()) {
+                    && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
                 // Invoke the appropriate {@link OnBackInvokedCallback} if the new back
                 // navigation should be used, and the key event is not handled by anything else.
                 OnBackInvokedCallback topCallback =
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 771d40b..1c27046 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -4865,21 +4865,24 @@
      * Registers the frame rate per second count callback for one given task ID.
      * Each callback can only register for receiving FPS callback for one task id until unregister
      * is called. If there's no task associated with the given task id,
-     * {@link IllegalArgumentException} will be thrown. If a task id destroyed after a callback is
-     * registered, the registered callback will not be unregistered until
-     * {@link #unregisterTaskFpsCallback(TaskFpsCallback))} is called
+     * {@link IllegalArgumentException} will be thrown. Registered callbacks should always be
+     * unregistered via {@link #unregisterTaskFpsCallback(TaskFpsCallback)}
+     * even when the task id has been destroyed.
+     *
      * @param taskId task id of the task.
+     * @param executor Executor to execute the callback.
      * @param callback callback to be registered.
      *
      * @hide
      */
     @SystemApi
     default void registerTaskFpsCallback(@IntRange(from = 0) int taskId,
+            @NonNull Executor executor,
             @NonNull TaskFpsCallback callback) {}
 
     /**
      * Unregisters the frame rate per second count callback which was registered with
-     * {@link #registerTaskFpsCallback(int,TaskFpsCallback)}.
+     * {@link #registerTaskFpsCallback(Executor, int, TaskFpsCallback)}.
      *
      * @param callback callback to be unregistered.
      *
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index f4353eb..20cdad4 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -39,14 +39,18 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.StrictMode;
+import android.window.ITaskFpsCallback;
 import android.window.TaskFpsCallback;
 import android.window.WindowContext;
 import android.window.WindowProvider;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.IResultReceiver;
 
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.Executor;
@@ -99,6 +103,10 @@
     @Nullable
     private final IBinder mWindowContextToken;
 
+    @GuardedBy("mOnFpsCallbackListenerProxies")
+    private final ArrayList<OnFpsCallbackListenerProxy> mOnFpsCallbackListenerProxies =
+            new ArrayList<>();
+
     public WindowManagerImpl(Context context) {
         this(context, null /* parentWindow */, null /* clientToken */);
     }
@@ -424,20 +432,56 @@
     }
 
     @Override
-    public void registerTaskFpsCallback(@IntRange(from = 0) int taskId, TaskFpsCallback callback) {
+    public void registerTaskFpsCallback(@IntRange(from = 0) int taskId, @NonNull Executor executor,
+            TaskFpsCallback callback) {
+        final OnFpsCallbackListenerProxy onFpsCallbackListenerProxy =
+                new OnFpsCallbackListenerProxy(executor, callback);
         try {
             WindowManagerGlobal.getWindowManagerService().registerTaskFpsCallback(
-                    taskId, callback.getListener());
+                    taskId, onFpsCallbackListenerProxy);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        synchronized (mOnFpsCallbackListenerProxies) {
+            mOnFpsCallbackListenerProxies.add(onFpsCallbackListenerProxy);
         }
     }
 
     @Override
     public void unregisterTaskFpsCallback(TaskFpsCallback callback) {
-        try {
-            WindowManagerGlobal.getWindowManagerService().unregisterTaskFpsCallback(
-                    callback.getListener());
-        } catch (RemoteException e) {
+        synchronized (mOnFpsCallbackListenerProxies) {
+            final Iterator<OnFpsCallbackListenerProxy> iterator =
+                    mOnFpsCallbackListenerProxies.iterator();
+            while (iterator.hasNext()) {
+                final OnFpsCallbackListenerProxy proxy = iterator.next();
+                if (proxy.mCallback == callback) {
+                    try {
+                        WindowManagerGlobal.getWindowManagerService()
+                                .unregisterTaskFpsCallback(proxy);
+                    } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
+                    }
+                    iterator.remove();
+                }
+            }
+        }
+    }
+
+    private static class OnFpsCallbackListenerProxy
+            extends ITaskFpsCallback.Stub {
+        private final Executor mExecutor;
+        private final TaskFpsCallback mCallback;
+
+        private OnFpsCallbackListenerProxy(Executor executor, TaskFpsCallback callback) {
+            mExecutor = executor;
+            mCallback = callback;
+        }
+
+        @Override
+        public void onFpsReported(float fps) {
+            mExecutor.execute(() -> {
+                mCallback.onFpsReported(fps);
+            });
         }
     }
 
diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java
index bd62308..de31667 100644
--- a/core/java/android/view/animation/Transformation.java
+++ b/core/java/android/view/animation/Transformation.java
@@ -158,7 +158,7 @@
     }
 
     /**
-     * @return The 3x3 Matrix representing the trnasformation to apply to the
+     * @return The 3x3 Matrix representing the transformation to apply to the
      * coordinates of the object being animated
      */
     public Matrix getMatrix() {
@@ -167,7 +167,7 @@
 
     /**
      * Sets the degree of transparency
-     * @param alpha 1.0 means fully opaqe and 0.0 means fully transparent
+     * @param alpha 1.0 means fully opaque and 0.0 means fully transparent
      */
     public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
         mAlpha = alpha;
diff --git a/core/java/android/view/autofill/AutofillClientController.java b/core/java/android/view/autofill/AutofillClientController.java
index 0f0fa4a..93d98ac 100644
--- a/core/java/android/view/autofill/AutofillClientController.java
+++ b/core/java/android/view/autofill/AutofillClientController.java
@@ -76,7 +76,6 @@
      */
     public AutofillClientController(Activity activity) {
         mActivity = activity;
-        activity.addDumpable(this);
     }
 
     private AutofillManager getAutofillManager() {
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 54bd9e7..48d2970 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -218,6 +218,7 @@
     public static final boolean DEBUG = false;
 
     /** @hide */
+    @TestApi
     public static final String DUMPABLE_NAME = "ContentCaptureManager";
 
     /** Error happened during the data sharing session. */
@@ -391,6 +392,9 @@
     @GuardedBy("mLock")
     private MainContentCaptureSession mMainSession;
 
+    @Nullable // set on-demand by addDumpable()
+    private Dumper mDumpable;
+
     /** @hide */
     public interface ContentCaptureClient {
         /**
@@ -407,9 +411,6 @@
         mService = Objects.requireNonNull(service, "service cannot be null");
         mOptions = Objects.requireNonNull(options, "options cannot be null");
 
-        if (context instanceof Activity) {
-            ((Activity) context).addDumpable(new Dumper());
-        }
         ContentCaptureHelper.setLoggingLevel(mOptions.loggingLevel);
 
         if (sVerbose) Log.v(TAG, "Constructor for " + context.getPackageName());
@@ -748,6 +749,14 @@
         return resultReceiver;
     }
 
+    /** @hide */
+    public void addDumpable(Activity activity) {
+        if (mDumpable == null) {
+            mDumpable = new Dumper();
+        }
+        activity.addDumpable(mDumpable);
+    }
+
     // NOTE: ContentCaptureManager cannot implement it directly as it would be exposed as public API
     private final class Dumper implements Dumpable {
         @Override
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 08cc31c..69ad739 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -391,22 +391,6 @@
     public void changeInputMethodSubtype(InputMethodSubtype subtype);
 
     /**
-     * Update token of the client window requesting {@link #showSoftInput(int, ResultReceiver)}
-     * @param showInputToken placeholder app window token for window requesting
-     *        {@link InputMethodManager#showSoftInput(View, int)}
-     * @hide
-     */
-    public void setCurrentShowInputToken(IBinder showInputToken);
-
-    /**
-     * Update token of the client window requesting {@link #hideSoftInput(int, ResultReceiver)}
-     * @param hideInputToken placeholder app window token for window requesting
-     *        {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}
-     * @hide
-     */
-    public void setCurrentHideInputToken(IBinder hideInputToken);
-
-    /**
      * Checks if IME is ready to start stylus handwriting session.
      * If yes, {@link #startStylusHandwriting(InputChannel, List)} is called.
      * @param requestId
diff --git a/core/java/android/window/IOnFpsCallbackListener.aidl b/core/java/android/window/ITaskFpsCallback.aidl
similarity index 95%
rename from core/java/android/window/IOnFpsCallbackListener.aidl
rename to core/java/android/window/ITaskFpsCallback.aidl
index 3091df3..aee403e9 100644
--- a/core/java/android/window/IOnFpsCallbackListener.aidl
+++ b/core/java/android/window/ITaskFpsCallback.aidl
@@ -19,7 +19,7 @@
 /**
  * @hide
  */
-oneway interface IOnFpsCallbackListener {
+oneway interface ITaskFpsCallback {
 
     /**
      * Reports the fps from the registered task
diff --git a/core/java/android/window/TaskFpsCallback.java b/core/java/android/window/TaskFpsCallback.java
index a8e01b6..19b9f28 100644
--- a/core/java/android/window/TaskFpsCallback.java
+++ b/core/java/android/window/TaskFpsCallback.java
@@ -21,8 +21,6 @@
 import android.annotation.SystemApi;
 import android.os.RemoteException;
 
-import java.util.concurrent.Executor;
-
 /**
  * Callback for sampling the frames per second for a task and its children.
  * This should only be used by a system component that needs to listen to a task's
@@ -30,44 +28,19 @@
  * Otherwise, ASurfaceTransaction_OnComplete callbacks should be used.
  *
  * Each callback can only register for receiving FPS report for one task id until
- * {@link WindowManager#unregister()} is called.
+ * {@link WindowManager#unregisterTaskFpsCallback()} is called.
  *
  * @hide
  */
 @SystemApi
-public final class TaskFpsCallback {
+public abstract class TaskFpsCallback {
 
     /**
-     * Listener interface to receive frame per second of a task.
+     * Reports the fps from the registered task
+     * @param fps The frame per second of the task that has the registered task id
+     *            and its children.
      */
-    public interface OnFpsCallbackListener {
-        /**
-         * Reports the fps from the registered task
-         * @param fps The frame per second of the task that has the registered task id
-         *            and its children.
-         */
-        void onFpsReported(float fps);
-    }
-
-    private final IOnFpsCallbackListener mListener;
-
-    public TaskFpsCallback(@NonNull Executor executor, @NonNull OnFpsCallbackListener listener) {
-        mListener = new IOnFpsCallbackListener.Stub() {
-            @Override
-            public void onFpsReported(float fps) {
-                executor.execute(() -> {
-                    listener.onFpsReported(fps);
-                });
-            }
-        };
-    }
-
-    /**
-     * @hide
-     */
-    public IOnFpsCallbackListener getListener() {
-        return mListener;
-    }
+    public abstract void onFpsReported(float fps);
 
     /**
      * Dispatch the collected sample.
@@ -76,7 +49,7 @@
      */
     @BinderThread
     private static void dispatchOnFpsReported(
-            @NonNull IOnFpsCallbackListener listener, float fps) {
+            @NonNull ITaskFpsCallback listener, float fps) {
         try {
             listener.onFpsReported(fps);
         } catch (RemoteException e) {
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 5ca29e6..aaaf729 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -650,7 +650,7 @@
             return options;
         }
 
-        public static AnimationOptions makeThumnbnailAnimOptions(HardwareBuffer srcThumb,
+        public static AnimationOptions makeThumbnailAnimOptions(HardwareBuffer srcThumb,
                 int startX, int startY, boolean scaleUp) {
             AnimationOptions options = new AnimationOptions(
                     scaleUp ? ANIM_THUMBNAIL_SCALE_UP : ANIM_THUMBNAIL_SCALE_DOWN);
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 62292f97..0503c40 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -19,9 +19,11 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.compat.CompatChanges;
+import android.content.Context;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.SystemProperties;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.IWindow;
 import android.view.IWindowSession;
@@ -50,10 +52,9 @@
     private IWindowSession mWindowSession;
     private IWindow mWindow;
     private static final String TAG = "WindowOnBackDispatcher";
-    private static final boolean DEBUG = false;
     private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
     private static final boolean IS_BACK_PREDICTABILITY_ENABLED = SystemProperties
-            .getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+            .getInt(BACK_PREDICTABILITY_PROP, 1) > 0;
 
     /** Convenience hashmap to quickly decide if a callback has been added. */
     private final HashMap<OnBackInvokedCallback, Integer> mAllCallbacks = new HashMap<>();
@@ -227,10 +228,23 @@
      *
      * Legacy back behavior dispatches KEYCODE_BACK instead of invoking the application registered
      * {@link android.view.OnBackInvokedCallback}.
-     *
      */
-    public static boolean shouldUseLegacyBack() {
-        return !CompatChanges.isChangeEnabled(DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME)
-                || !IS_BACK_PREDICTABILITY_ENABLED;
+    public static boolean isOnBackInvokedCallbackEnabled(@Nullable Context context) {
+        // new back is enabled if the app targets T AND the feature flag is enabled AND the app
+        // does not explicitly request legacy back.
+        boolean targetsT = CompatChanges.isChangeEnabled(DISPATCH_BACK_INVOCATION_AHEAD_OF_TIME);
+        boolean featureFlagEnabled = IS_BACK_PREDICTABILITY_ENABLED;
+        // If the context is null, we assume true and fallback on the two other conditions.
+        boolean appRequestsLegacy =
+                context == null || !context.getApplicationInfo().isOnBackInvokedCallbackEnabled();
+
+        if (DEBUG) {
+            Log.d(TAG, TextUtils.formatSimple("App: %s isChangeEnabled=%s featureFlagEnabled=%s "
+                            + "onBackInvokedEnabled=%s",
+                    context != null ? context.getApplicationInfo().packageName : "null context",
+                    targetsT, featureFlagEnabled, !appRequestsLegacy));
+        }
+
+        return targetsT && featureFlagEnabled && !appRequestsLegacy;
     }
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index f6a1cc0..9e70392 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -103,6 +103,9 @@
     void shutdown();
     void reboot(boolean safeMode);
 
+    /** just restarts android without rebooting device. Used for some feature flags. */
+    void restart();
+
     void addTile(in ComponentName tile);
     void remTile(in ComponentName tile);
     void clickTile(in ComponentName tile);
diff --git a/core/java/com/android/internal/usb/DumpUtils.java b/core/java/com/android/internal/usb/DumpUtils.java
index b32a6b0..1eb446e 100644
--- a/core/java/com/android/internal/usb/DumpUtils.java
+++ b/core/java/com/android/internal/usb/DumpUtils.java
@@ -249,7 +249,7 @@
         dump.write("is_power_transfer_limited", UsbPortStatusProto.IS_POWER_TRANSFER_LIMITED,
                 status.isPowerTransferLimited());
         dump.write("usb_power_brick_status", UsbPortStatusProto.USB_POWER_BRICK_STATUS,
-                UsbPort.powerBrickStatusToString(status.getPowerBrickStatus()));
+                UsbPort.powerBrickConnectionStatusToString(status.getPowerBrickConnectionStatus()));
         dump.end(token);
     }
 }
diff --git a/core/java/com/android/internal/util/dump/DumpableContainerImpl.java b/core/java/com/android/internal/util/dump/DumpableContainerImpl.java
index 2e56ebf..ccec6c6 100644
--- a/core/java/com/android/internal/util/dump/DumpableContainerImpl.java
+++ b/core/java/com/android/internal/util/dump/DumpableContainerImpl.java
@@ -47,8 +47,10 @@
         Objects.requireNonNull(name, () -> "name of" + dumpable);
 
         if (mDumpables.containsKey(name)) {
-            Log.e(TAG, "addDumpable(): ignoring " + dumpable + " as there is already a dumpable"
-                    + " with that name (" + name + "): " + mDumpables.get(name));
+            if (DEBUG) {
+                Log.d(TAG, "addDumpable(): ignoring " + dumpable + " as there is already a dumpable"
+                        + " with that name (" + name + "): " + mDumpables.get(name));
+            }
             return false;
         }
 
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 63b704c..47cb754 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -188,6 +188,7 @@
                 "android_hardware_HardwareBuffer.cpp",
                 "android_hardware_SensorManager.cpp",
                 "android_hardware_SerialPort.cpp",
+                "android_hardware_SyncFence.cpp",
                 "android_hardware_UsbDevice.cpp",
                 "android_hardware_UsbDeviceConnection.cpp",
                 "android_hardware_UsbRequest.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index cde71cf..eedf7fa 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -82,6 +82,7 @@
 extern int register_android_hardware_HardwareBuffer(JNIEnv *env);
 extern int register_android_hardware_SensorManager(JNIEnv *env);
 extern int register_android_hardware_SerialPort(JNIEnv *env);
+extern int register_android_hardware_SyncFence(JNIEnv* env);
 extern int register_android_hardware_UsbDevice(JNIEnv *env);
 extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env);
 extern int register_android_hardware_UsbRequest(JNIEnv *env);
@@ -1601,6 +1602,7 @@
         REG_JNI(register_android_hardware_HardwareBuffer),
         REG_JNI(register_android_hardware_SensorManager),
         REG_JNI(register_android_hardware_SerialPort),
+        REG_JNI(register_android_hardware_SyncFence),
         REG_JNI(register_android_hardware_UsbDevice),
         REG_JNI(register_android_hardware_UsbDeviceConnection),
         REG_JNI(register_android_hardware_UsbRequest),
diff --git a/core/jni/android_hardware_SyncFence.cpp b/core/jni/android_hardware_SyncFence.cpp
new file mode 100644
index 0000000..b996653
--- /dev/null
+++ b/core/jni/android_hardware_SyncFence.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SyncFence"
+
+#include <nativehelper/JNIHelp.h>
+#include <ui/Fence.h>
+
+#include "core_jni_helpers.h"
+#include "jni.h"
+
+using namespace android;
+
+template <typename T>
+jlong toJlong(T* ptr) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(ptr));
+}
+
+template <typename T>
+T* fromJlong(jlong jPtr) {
+    return reinterpret_cast<T*>(static_cast<uintptr_t>(jPtr));
+}
+
+static void destroyFence(Fence* fence) {
+    fence->decStrong(0);
+}
+
+static jlong SyncFence_getDestructor(JNIEnv*, jobject) {
+    return toJlong(&destroyFence);
+}
+
+static jlong SyncFence_create(JNIEnv*, jobject, int fd) {
+    Fence* fence = new Fence(fd);
+    fence->incStrong(0);
+    return toJlong(fence);
+}
+
+static jboolean SyncFence_isValid(JNIEnv*, jobject, jlong jPtr) {
+    return fromJlong<Fence>(jPtr)->isValid();
+}
+
+static jint SyncFence_getFd(JNIEnv*, jobject, jlong jPtr) {
+    return fromJlong<Fence>(jPtr)->get();
+}
+
+static jboolean SyncFence_wait(JNIEnv* env, jobject, jlong jPtr, jlong timeoutNanos) {
+    Fence* fence = fromJlong<Fence>(jPtr);
+    int err = fence->wait(timeoutNanos);
+    return err == OK;
+}
+
+static jlong SyncFence_getSignalTime(JNIEnv* env, jobject, jlong jPtr) {
+    return fromJlong<Fence>(jPtr)->getSignalTime();
+}
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/hardware/SyncFence";
+
+// clang-format off
+static const JNINativeMethod gMethods[] = {
+        { "nGetDestructor", "()J", (void*) SyncFence_getDestructor },
+        { "nCreate", "(I)J", (void*) SyncFence_create },
+        { "nIsValid", "(J)Z", (void*) SyncFence_isValid },
+        { "nGetFd", "(J)I", (void*) SyncFence_getFd },
+        { "nWait",  "(JJ)Z", (void*) SyncFence_wait },
+        { "nGetSignalTime", "(J)J", (void*) SyncFence_getSignalTime },
+};
+// clang-format on
+
+int register_android_hardware_SyncFence(JNIEnv* env) {
+    int err = RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
+    return err;
+}
\ No newline at end of file
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index d7eeb5f..93ce377 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -130,10 +130,6 @@
 
     mInfo.name = getStringField(env, obj, gInputWindowHandleClassInfo.name, "<null>");
 
-    mInfo.flags = Flags<WindowInfo::Flag>(
-            env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags));
-    mInfo.type = static_cast<WindowInfo::Type>(
-            env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType));
     mInfo.dispatchingTimeout = std::chrono::milliseconds(
             env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutMillis));
     mInfo.frameLeft = env->GetIntField(obj,
@@ -159,14 +155,72 @@
         env->DeleteLocalRef(regionObj);
     }
 
-    mInfo.visible = env->GetBooleanField(obj,
-            gInputWindowHandleClassInfo.visible);
-    mInfo.focusable = env->GetBooleanField(obj, gInputWindowHandleClassInfo.focusable);
-    mInfo.hasWallpaper = env->GetBooleanField(obj,
-            gInputWindowHandleClassInfo.hasWallpaper);
-    mInfo.paused = env->GetBooleanField(obj,
-            gInputWindowHandleClassInfo.paused);
-    mInfo.trustedOverlay = env->GetBooleanField(obj, gInputWindowHandleClassInfo.trustedOverlay);
+    const auto flags = Flags<WindowInfo::Flag>(
+            env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags));
+    const auto type = static_cast<WindowInfo::Type>(
+            env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType));
+    mInfo.layoutParamsFlags = flags;
+    mInfo.layoutParamsType = type;
+
+    using InputConfig = gui::WindowInfo::InputConfig;
+    // Determine the value for each of the InputConfig flags. We rely on a switch statement and
+    // -Wswitch-enum to give us a build error if we forget to explicitly handle an InputConfig flag.
+    mInfo.inputConfig = InputConfig::NONE;
+    InputConfig enumerationStart = InputConfig::NONE;
+    switch (enumerationStart) {
+        case InputConfig::NONE:
+            FALLTHROUGH_INTENDED;
+        case InputConfig::NOT_VISIBLE:
+            if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.visible) == JNI_FALSE) {
+                mInfo.inputConfig |= InputConfig::NOT_VISIBLE;
+            }
+            FALLTHROUGH_INTENDED;
+        case InputConfig::NOT_FOCUSABLE:
+            if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.focusable) == JNI_FALSE) {
+                mInfo.inputConfig |= InputConfig::NOT_FOCUSABLE;
+            }
+            FALLTHROUGH_INTENDED;
+        case InputConfig::NOT_TOUCHABLE:
+            if (flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) {
+                mInfo.inputConfig |= InputConfig::NOT_TOUCHABLE;
+            }
+            FALLTHROUGH_INTENDED;
+        case InputConfig::PREVENT_SPLITTING:
+            if (!flags.test(WindowInfo::Flag::SPLIT_TOUCH)) {
+                mInfo.inputConfig |= InputConfig::PREVENT_SPLITTING;
+            }
+            FALLTHROUGH_INTENDED;
+        case InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER:
+            if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.hasWallpaper) == JNI_TRUE) {
+                mInfo.inputConfig |= InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER;
+            }
+            FALLTHROUGH_INTENDED;
+        case InputConfig::IS_WALLPAPER:
+            if (type == WindowInfo::Type::WALLPAPER) {
+                mInfo.inputConfig |= InputConfig::IS_WALLPAPER;
+            }
+            FALLTHROUGH_INTENDED;
+        case InputConfig::PAUSE_DISPATCHING:
+            if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.paused) == JNI_TRUE) {
+                mInfo.inputConfig |= InputConfig::PAUSE_DISPATCHING;
+            }
+            FALLTHROUGH_INTENDED;
+        case InputConfig::TRUSTED_OVERLAY:
+            if (env->GetBooleanField(obj, gInputWindowHandleClassInfo.trustedOverlay) == JNI_TRUE) {
+                mInfo.inputConfig |= InputConfig::TRUSTED_OVERLAY;
+            }
+            FALLTHROUGH_INTENDED;
+        case InputConfig::WATCH_OUTSIDE_TOUCH:
+            if (flags.test(WindowInfo::Flag::WATCH_OUTSIDE_TOUCH)) {
+                mInfo.inputConfig |= InputConfig::WATCH_OUTSIDE_TOUCH;
+            }
+            FALLTHROUGH_INTENDED;
+        case InputConfig::SLIPPERY:
+            if (flags.test(WindowInfo::Flag::SLIPPERY)) {
+                mInfo.inputConfig |= InputConfig::SLIPPERY;
+            }
+    }
+
     mInfo.touchOcclusionMode = static_cast<TouchOcclusionMode>(
             env->GetIntField(obj, gInputWindowHandleClassInfo.touchOcclusionMode));
     mInfo.ownerPid = env->GetIntField(obj,
@@ -274,9 +328,9 @@
     env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.name,
                         env->NewStringUTF(windowInfo.name.data()));
     env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsFlags,
-                     static_cast<uint32_t>(windowInfo.flags.get()));
+                     static_cast<uint32_t>(windowInfo.layoutParamsFlags.get()));
     env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.layoutParamsType,
-                     static_cast<int32_t>(windowInfo.type));
+                     static_cast<int32_t>(windowInfo.layoutParamsType));
     env->SetLongField(inputWindowHandle, gInputWindowHandleClassInfo.dispatchingTimeoutMillis,
                       std::chrono::duration_cast<std::chrono::milliseconds>(
                               windowInfo.dispatchingTimeout)
@@ -305,15 +359,17 @@
     env->SetObjectField(inputWindowHandle, gInputWindowHandleClassInfo.touchableRegion,
                         regionObj.get());
 
+    using InputConfig = gui::WindowInfo::InputConfig;
     env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.visible,
-                         windowInfo.visible);
+                         !windowInfo.inputConfig.test(InputConfig::NOT_VISIBLE));
     env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.focusable,
-                         windowInfo.focusable);
+                         !windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE));
     env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.hasWallpaper,
-                         windowInfo.hasWallpaper);
-    env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.paused, windowInfo.paused);
+                         windowInfo.inputConfig.test(InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER));
+    env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.paused,
+                         windowInfo.inputConfig.test(InputConfig::PAUSE_DISPATCHING));
     env->SetBooleanField(inputWindowHandle, gInputWindowHandleClassInfo.trustedOverlay,
-                         windowInfo.trustedOverlay);
+                         windowInfo.inputConfig.test(InputConfig::TRUSTED_OVERLAY));
     env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.touchOcclusionMode,
                      static_cast<int32_t>(windowInfo.touchOcclusionMode));
     env->SetIntField(inputWindowHandle, gInputWindowHandleClassInfo.ownerPid, windowInfo.ownerPid);
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 73d2d8d..8c33e07 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -63,12 +63,94 @@
 static PlaybackParams::fields_t gPlaybackParamsFields;
 static VolumeShaperHelper::fields_t gVolumeShaperFields;
 
-struct audiotrack_callback_cookie {
-    jclass      audioTrack_class;
-    jobject     audioTrack_ref;
-    bool        busy;
-    Condition   cond;
-    bool        isOffload;
+class AudioTrackCallbackImpl : public AudioTrack::IAudioTrackCallback {
+  public:
+    enum event_type {
+    // Keep in sync with java
+        EVENT_MORE_DATA = 0,
+        EVENT_UNDERRUN = 1,
+        EVENT_LOOP_END = 2,
+        EVENT_MARKER = 3,
+        EVENT_NEW_POS = 4,
+        EVENT_BUFFER_END = 5,
+        EVENT_NEW_IAUDIOTRACK = 6,
+        EVENT_STREAM_END = 7,
+        // 8 is reserved for future use
+        EVENT_CAN_WRITE_MORE_DATA = 9
+    };
+
+    AudioTrackCallbackImpl(jclass audioTrackClass, jobject audioTrackWeakRef, bool isOffload)
+          : mIsOffload(isOffload)
+    {
+      const auto env = getJNIEnv();
+      mAudioTrackClass = (jclass)env->NewGlobalRef(audioTrackClass);
+      // we use a weak reference so the AudioTrack object can be garbage collected.
+      mAudioTrackWeakRef = env->NewGlobalRef(audioTrackWeakRef);
+
+    }
+
+    AudioTrackCallbackImpl(const AudioTrackCallbackImpl&) = delete;
+    AudioTrackCallbackImpl& operator=(const AudioTrackCallbackImpl&) = delete;
+    ~AudioTrackCallbackImpl() {
+        const auto env = getJNIEnv();
+        env->DeleteGlobalRef(mAudioTrackClass);
+        env->DeleteGlobalRef(mAudioTrackWeakRef);
+    }
+
+    size_t onCanWriteMoreData(const AudioTrack::Buffer& buffer) override {
+      if (!mIsOffload) {
+          LOG_FATAL("Received canWrite callback for non-offload track");
+          return 0;
+      }
+      const size_t availableForWrite = buffer.size();
+      const int arg = availableForWrite > INT32_MAX ? INT32_MAX : (int) availableForWrite;
+      postEvent(EVENT_CAN_WRITE_MORE_DATA, arg);
+      return 0;
+    }
+
+    void onMarker([[maybe_unused]] uint32_t markerPosition) override {
+        postEvent(EVENT_MARKER);
+    }
+    void onNewPos([[maybe_unused]] uint32_t newPos) override {
+        postEvent(EVENT_NEW_POS);
+    }
+
+
+    void onNewIAudioTrack() override {
+        if (!mIsOffload) return;
+        postEvent(EVENT_NEW_IAUDIOTRACK);
+    }
+
+    void onStreamEnd() override {
+        if (!mIsOffload) return;
+        postEvent(EVENT_STREAM_END);
+    }
+
+  protected:
+    jobject     mAudioTrackWeakRef;
+  private:
+     JNIEnv* getJNIEnv() {
+          auto jni = AndroidRuntime::getJNIEnv();
+          if (jni == nullptr) {
+              LOG_ALWAYS_FATAL("AudioTrackCallback thread JNI reference is null");
+          }
+          return jni;
+     }
+
+     void postEvent(int event, int arg = 0) {
+        auto env = getJNIEnv();
+        env->CallStaticVoidMethod(
+                mAudioTrackClass,
+                javaAudioTrackFields.postNativeEventInJava,
+                mAudioTrackWeakRef, event, arg, 0, NULL);
+        if (env->ExceptionCheck()) {
+            env->ExceptionDescribe();
+            env->ExceptionClear();
+        }
+    }
+
+    jclass      mAudioTrackClass;
+    const bool  mIsOffload;
 };
 
 // keep these values in sync with AudioTrack.java
@@ -76,22 +158,21 @@
 #define MODE_STREAM 1
 
 // ----------------------------------------------------------------------------
-class AudioTrackJniStorage {
+class AudioTrackJniStorage : public virtual RefBase,
+                             public AudioTrackCallbackImpl
+{
 public:
-    sp<MemoryHeapBase> mMemHeap;
-    sp<MemoryBase> mMemBase;
-    audiotrack_callback_cookie mCallbackData{};
+    // TODO do we always want to initialize the callback implementation?
+    AudioTrackJniStorage(jclass audioTrackClass, jobject audioTrackRef, bool isOffload = false)
+          : AudioTrackCallbackImpl(audioTrackClass, audioTrackRef, isOffload) {}
+
     sp<JNIDeviceCallback> mDeviceCallback;
     sp<JNIAudioTrackCallback> mAudioTrackCallback;
 
-    bool allocSharedMem(int sizeInBytes) {
-        mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
-        if (mMemHeap->getHeapID() < 0) {
-            return false;
-        }
-        mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
-        return true;
+    jobject getAudioTrackWeakRef() const {
+        return mAudioTrackWeakRef;
     }
+
 };
 
 class TunerConfigurationHelper {
@@ -136,7 +217,6 @@
 };
 
 static Mutex sLock;
-static SortedVector <audiotrack_callback_cookie *> sAudioTrackCallBackCookies;
 
 // ----------------------------------------------------------------------------
 #define DEFAULT_OUTPUT_SAMPLE_RATE   44100
@@ -147,102 +227,49 @@
 #define AUDIOTRACK_ERROR_SETUP_INVALIDSTREAMTYPE   (-19)
 #define AUDIOTRACK_ERROR_SETUP_NATIVEINITFAILED    (-20)
 
-// ----------------------------------------------------------------------------
-static void audioCallback(int event, void* user, void *info) {
-
-    audiotrack_callback_cookie *callbackInfo = (audiotrack_callback_cookie *)user;
-    {
-        Mutex::Autolock l(sLock);
-        if (sAudioTrackCallBackCookies.indexOf(callbackInfo) < 0) {
-            return;
-        }
-        callbackInfo->busy = true;
+namespace {
+sp<IMemory> allocSharedMem(int sizeInBytes) {
+    const auto heap = sp<MemoryHeapBase>::make(sizeInBytes, 0, "AudioTrack Heap Base");
+    if (heap->getBase() == MAP_FAILED || heap->getBase() == nullptr) {
+        return nullptr;
     }
-
-    // used as default argument when event callback doesn't have any, or number of
-    // frames for EVENT_CAN_WRITE_MORE_DATA
-    int arg = 0;
-    bool postEvent = false;
-    switch (event) {
-    // Offload only events
-    case AudioTrack::EVENT_CAN_WRITE_MORE_DATA:
-        // this event will read the info return parameter of the callback:
-        // for JNI offload, use the returned size to indicate:
-        // 1/ no data is returned through callback, as it's all done through write()
-        // 2/ do not wait as AudioTrack does when it receives 0 bytes
-        if (callbackInfo->isOffload) {
-            AudioTrack::Buffer* pBuffer = (AudioTrack::Buffer*) info;
-            const size_t availableForWrite = pBuffer->size;
-            arg = availableForWrite > INT32_MAX ? INT32_MAX : (int) availableForWrite;
-            pBuffer->size = 0;
-        }
-        FALLTHROUGH_INTENDED;
-    case AudioTrack::EVENT_STREAM_END:
-    case AudioTrack::EVENT_NEW_IAUDIOTRACK: // a.k.a. tear down
-        if (callbackInfo->isOffload) {
-            postEvent = true;
-        }
-        break;
-
-    // PCM and offload events
-    case AudioTrack::EVENT_MARKER:
-    case AudioTrack::EVENT_NEW_POS:
-        postEvent = true;
-        break;
-    default:
-        // event will not be posted
-        break;
-    }
-
-    if (postEvent) {
-        JNIEnv *env = AndroidRuntime::getJNIEnv();
-        if (env != NULL) {
-            env->CallStaticVoidMethod(
-                    callbackInfo->audioTrack_class,
-                    javaAudioTrackFields.postNativeEventInJava,
-                    callbackInfo->audioTrack_ref, event, arg, 0, NULL);
-            if (env->ExceptionCheck()) {
-                env->ExceptionDescribe();
-                env->ExceptionClear();
-            }
-        }
-    }
-
-    {
-        Mutex::Autolock l(sLock);
-        callbackInfo->busy = false;
-        callbackInfo->cond.broadcast();
-    }
+    return sp<MemoryBase>::make(heap, 0, sizeInBytes);
+}
+// TODO(b/218351957) move somewhere?
+template<typename T>
+sp<T> getFieldSp(JNIEnv* env, jobject thiz, jfieldID id)
+{
+    // make these fields atomic longs on the java side
+    Mutex::Autolock l(sLock);
+    return sp<T>::fromExisting(reinterpret_cast<T*>(env->GetLongField(thiz, id)));
 }
 
-
-// ----------------------------------------------------------------------------
-static sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz)
+// This (semantically) should only be called on AudioTrack creation and release
+template <typename T>
+sp<T> setFieldSp(JNIEnv* env, jobject thiz, const sp<T>& at, jfieldID id)
 {
     Mutex::Autolock l(sLock);
-    AudioTrack* const at =
-            (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
-    return sp<AudioTrack>(at);
-}
-
-static sp<AudioTrack> setAudioTrack(JNIEnv* env, jobject thiz, const sp<AudioTrack>& at)
-{
-    Mutex::Autolock l(sLock);
-    sp<AudioTrack> old =
-            (AudioTrack*)env->GetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+    // I don't think this synchronization actually prevents a race
+    // We can still invalidate under our feet in release
+    sp<T> old = sp<T>::fromExisting(reinterpret_cast<T*>(env->GetLongField(thiz, id)));
     if (at.get()) {
-        at->incStrong((void*)setAudioTrack);
+        at->incStrong((void*)setFieldSp<T>);
     }
     if (old != 0) {
-        old->decStrong((void*)setAudioTrack);
+        old->decStrong((void*)setFieldSp<T>);
     }
-    env->SetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (jlong)at.get());
+    env->SetLongField(thiz, id, (jlong)at.get());
     return old;
 }
 
+sp<AudioTrack> getAudioTrack(JNIEnv* env, jobject thiz) {
+    return getFieldSp<AudioTrack>(env, thiz, javaAudioTrackFields.nativeTrackInJavaObj);
+}
+
+} // anonymous
 // ----------------------------------------------------------------------------
 sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audioTrackObj) {
-    return getAudioTrack(env, audioTrackObj);
+    return getFieldSp<AudioTrack>(env, audioTrackObj, javaAudioTrackFields.nativeTrackInJavaObj);
 }
 
 // ----------------------------------------------------------------------------
@@ -274,7 +301,6 @@
     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
     nSession = NULL;
 
-    AudioTrackJniStorage* lpJniStorage = NULL;
 
     jclass clazz = env->GetObjectClass(thiz);
     if (clazz == NULL) {
@@ -284,6 +310,7 @@
 
     // if we pass in an existing *Native* AudioTrack, we don't need to create/initialize one.
     sp<AudioTrack> lpTrack;
+    const auto lpJniStorage = sp<AudioTrackJniStorage>::make(clazz, weak_this, offload);
     if (nativeAudioTrack == 0) {
         if (jaa == 0) {
             ALOGE("Error creating AudioTrack: invalid audio attributes");
@@ -332,7 +359,7 @@
         AttributionSourceState attributionSource;
         attributionSource.packageName = std::string(opPackageNameStr.c_str());
         attributionSource.token = sp<BBinder>::make();
-        lpTrack = new AudioTrack(attributionSource);
+        lpTrack = sp<AudioTrack>::make(attributionSource);
 
         // read the AudioAttributes values
         auto paa = JNIAudioAttributeHelper::makeUnique();
@@ -345,13 +372,6 @@
 
         // initialize the callback information:
         // this data will be passed with every AudioTrack callback
-        lpJniStorage = new AudioTrackJniStorage();
-        lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
-        // we use a weak reference so the AudioTrack object can be garbage collected.
-        lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
-        lpJniStorage->mCallbackData.isOffload = offload;
-        lpJniStorage->mCallbackData.busy = false;
-
         audio_offload_info_t offloadInfo;
         if (offload == JNI_TRUE) {
             offloadInfo = AUDIO_INFO_INITIALIZER;
@@ -385,8 +405,7 @@
                                   nativeChannelMask, offload ? 0 : frameCount,
                                   offload ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
                                           : AUDIO_OUTPUT_FLAG_NONE,
-                                  audioCallback,
-                                  &(lpJniStorage->mCallbackData), // callback, callback data (user)
+                                  lpJniStorage,
                                   0,    // notificationFrames == 0 since not using EVENT_MORE_DATA
                                         // to feed the AudioTrack
                                   0,    // shared mem
@@ -400,9 +419,10 @@
             break;
 
         case MODE_STATIC:
+        {
             // AudioTrack is using shared memory
-
-            if (!lpJniStorage->allocSharedMem(buffSizeInBytes)) {
+            const auto iMem = allocSharedMem(buffSizeInBytes);
+            if (iMem == nullptr) {
                 ALOGE("Error creating AudioTrack in static mode: error creating mem heap base");
                 goto native_init_failure;
             }
@@ -412,19 +432,18 @@
                                   sampleRateInHertz,
                                   format, // word length, PCM
                                   nativeChannelMask, frameCount, AUDIO_OUTPUT_FLAG_NONE,
-                                  audioCallback,
-                                  &(lpJniStorage->mCallbackData), // callback, callback data (user)
+                                  lpJniStorage,
                                   0, // notificationFrames == 0 since not using EVENT_MORE_DATA
                                      // to feed the AudioTrack
-                                  lpJniStorage->mMemBase, // shared mem
+                                  iMem,                   // shared mem
                                   true,                   // thread can call Java
                                   sessionId,              // audio session ID
                                   AudioTrack::TRANSFER_SHARED,
-                                  NULL,       // default offloadInfo
+                                  nullptr ,               // default offloadInfo
                                   AttributionSourceState(), // default uid, pid values
                                   paa.get());
             break;
-
+        }
         default:
             ALOGE("Unknown mode %d", memoryMode);
             goto native_init_failure;
@@ -438,7 +457,7 @@
         // MediaMetricsConstants.h: AMEDIAMETRICS_PROP_CALLERNAME_VALUE_JAVA
         lpTrack->setCallerName("java");
     } else {  // end if (nativeAudioTrack == 0)
-        lpTrack = (AudioTrack*)nativeAudioTrack;
+        lpTrack = sp<AudioTrack>::fromExisting(reinterpret_cast<AudioTrack*>(nativeAudioTrack));
         // TODO: We need to find out which members of the Java AudioTrack might
         // need to be initialized from the Native AudioTrack
         // these are directly returned from getters:
@@ -456,15 +475,19 @@
 
         // initialize the callback information:
         // this data will be passed with every AudioTrack callback
-        lpJniStorage = new AudioTrackJniStorage();
+
+        // TODO this callback information is useless, it isn't passed to the
+        // native AudioTrack object
+        /*
         lpJniStorage->mCallbackData.audioTrack_class = (jclass)env->NewGlobalRef(clazz);
         // we use a weak reference so the AudioTrack object can be garbage collected.
         lpJniStorage->mCallbackData.audioTrack_ref = env->NewGlobalRef(weak_this);
         lpJniStorage->mCallbackData.busy = false;
+        */
     }
     lpJniStorage->mAudioTrackCallback =
-            new JNIAudioTrackCallback(env, thiz, lpJniStorage->mCallbackData.audioTrack_ref,
-                                      javaAudioTrackFields.postNativeEventInJava);
+            sp<JNIAudioTrackCallback>::make(env, thiz, lpJniStorage->getAudioTrackWeakRef(),
+                                            javaAudioTrackFields.postNativeEventInJava);
     lpTrack->setAudioTrackCallback(lpJniStorage->mAudioTrackCallback);
 
     nSession = (jint *) env->GetPrimitiveArrayCritical(jSession, NULL);
@@ -482,17 +505,13 @@
         env->SetIntArrayRegion(jSampleRate, 0, 1, elements);
     }
 
-    {   // scope for the lock
-        Mutex::Autolock l(sLock);
-        sAudioTrackCallBackCookies.add(&lpJniStorage->mCallbackData);
-    }
     // save our newly created C++ AudioTrack in the "nativeTrackInJavaObj" field
     // of the Java object (in mNativeTrackInJavaObj)
-    setAudioTrack(env, thiz, lpTrack);
+    setFieldSp(env, thiz, lpTrack, javaAudioTrackFields.nativeTrackInJavaObj);
 
     // save the JNI resources so we can free them later
     //ALOGV("storing lpJniStorage: %x\n", (long)lpJniStorage);
-    env->SetLongField(thiz, javaAudioTrackFields.jniData, (jlong)lpJniStorage);
+    setFieldSp(env, thiz, lpJniStorage, javaAudioTrackFields.jniData);
 
     // since we had audio attributes, the stream type was derived from them during the
     // creation of the native AudioTrack: push the same value to the Java object
@@ -505,9 +524,6 @@
     if (nSession != NULL) {
         env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
     }
-    env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_class);
-    env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioTrack_ref);
-    delete lpJniStorage;
     env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
 
     // lpTrack goes out of scope, so reference count drops to zero
@@ -607,38 +623,9 @@
 
 // ----------------------------------------------------------------------------
 
-#define CALLBACK_COND_WAIT_TIMEOUT_MS 1000
 static void android_media_AudioTrack_release(JNIEnv *env,  jobject thiz) {
-    sp<AudioTrack> lpTrack = setAudioTrack(env, thiz, 0);
-    if (lpTrack == NULL) {
-        return;
-    }
-    //ALOGV("deleting lpTrack: %x\n", (int)lpTrack);
-
-    // delete the JNI data
-    AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
-        thiz, javaAudioTrackFields.jniData);
-    // reset the native resources in the Java object so any attempt to access
-    // them after a call to release fails.
-    env->SetLongField(thiz, javaAudioTrackFields.jniData, 0);
-
-    if (pJniStorage) {
-        Mutex::Autolock l(sLock);
-        audiotrack_callback_cookie *lpCookie = &pJniStorage->mCallbackData;
-        //ALOGV("deleting pJniStorage: %x\n", (int)pJniStorage);
-        while (lpCookie->busy) {
-            if (lpCookie->cond.waitRelative(sLock,
-                                            milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
-                                                    NO_ERROR) {
-                break;
-            }
-        }
-        sAudioTrackCallBackCookies.remove(lpCookie);
-        // delete global refs created in native_setup
-        env->DeleteGlobalRef(lpCookie->audioTrack_class);
-        env->DeleteGlobalRef(lpCookie->audioTrack_ref);
-        delete pJniStorage;
-    }
+    setFieldSp(env, thiz, sp<AudioTrack>(nullptr), javaAudioTrackFields.nativeTrackInJavaObj);
+    setFieldSp(env, thiz, sp<AudioTrackJniStorage>(nullptr), javaAudioTrackFields.jniData);
 }
 
 
@@ -1249,17 +1236,18 @@
                 JNIEnv *env,  jobject thiz) {
 
     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
-    if (lpTrack == NULL) {
+    if (lpTrack == nullptr) {
         return;
     }
-    AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
-        thiz, javaAudioTrackFields.jniData);
-    if (pJniStorage == NULL || pJniStorage->mDeviceCallback != 0) {
+    const auto pJniStorage =
+            getFieldSp<AudioTrackJniStorage>(env, thiz, javaAudioTrackFields.jniData);
+    if (pJniStorage == nullptr || pJniStorage->mDeviceCallback != nullptr) {
         return;
     }
+
     pJniStorage->mDeviceCallback =
-    new JNIDeviceCallback(env, thiz, pJniStorage->mCallbackData.audioTrack_ref,
-                          javaAudioTrackFields.postNativeEventInJava);
+            sp<JNIDeviceCallback>::make(env, thiz, pJniStorage->getAudioTrackWeakRef(),
+                                        javaAudioTrackFields.postNativeEventInJava);
     lpTrack->addAudioDeviceCallback(pJniStorage->mDeviceCallback);
 }
 
@@ -1267,12 +1255,13 @@
                 JNIEnv *env,  jobject thiz) {
 
     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
-    if (lpTrack == NULL) {
+    if (lpTrack == nullptr) {
         return;
     }
-    AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
-        thiz, javaAudioTrackFields.jniData);
-    if (pJniStorage == NULL || pJniStorage->mDeviceCallback == 0) {
+    const auto pJniStorage =
+            getFieldSp<AudioTrackJniStorage>(env, thiz, javaAudioTrackFields.jniData);
+
+    if (pJniStorage == nullptr || pJniStorage->mDeviceCallback == nullptr) {
         return;
     }
     lpTrack->removeAudioDeviceCallback(pJniStorage->mDeviceCallback);
diff --git a/core/jni/android_media_AudioTrack.h b/core/jni/android_media_AudioTrack.h
index ef2aa66..d5b858c 100644
--- a/core/jni/android_media_AudioTrack.h
+++ b/core/jni/android_media_AudioTrack.h
@@ -18,15 +18,9 @@
 #define ANDROID_MEDIA_AUDIOTRACK_H
 
 #include "jni.h"
-
+#include <media/AudioTrack.h>
 #include <utils/StrongPointer.h>
 
-namespace android {
-
-class AudioTrack;
-
-}; // namespace android
-
 /* Gets the underlying AudioTrack from an AudioTrack Java object. */
 extern android::sp<android::AudioTrack> android_media_AudioTrack_getAudioTrack(
         JNIEnv* env, jobject audioTrackObj);
diff --git a/core/jni/android_opengl_EGLExt.cpp b/core/jni/android_opengl_EGLExt.cpp
index 1758807..cdc9852 100644
--- a/core/jni/android_opengl_EGLExt.cpp
+++ b/core/jni/android_opengl_EGLExt.cpp
@@ -37,25 +37,12 @@
 #include <ui/ANativeObjectBase.h>
 
 static jclass egldisplayClass;
-static jclass eglcontextClass;
 static jclass eglsurfaceClass;
-static jclass eglconfigClass;
+static jclass eglsyncClass;
 
 static jmethodID egldisplayGetHandleID;
-static jmethodID eglcontextGetHandleID;
 static jmethodID eglsurfaceGetHandleID;
-static jmethodID eglconfigGetHandleID;
-
-static jmethodID egldisplayConstructor;
-static jmethodID eglcontextConstructor;
-static jmethodID eglsurfaceConstructor;
-static jmethodID eglconfigConstructor;
-
-static jobject eglNoContextObject;
-static jobject eglNoDisplayObject;
-static jobject eglNoSurfaceObject;
-
-
+static jmethodID eglsyncGetHandleID;
 
 /* Cache method IDs each time the class is loaded. */
 
@@ -64,37 +51,14 @@
 {
     jclass egldisplayClassLocal = _env->FindClass("android/opengl/EGLDisplay");
     egldisplayClass = (jclass) _env->NewGlobalRef(egldisplayClassLocal);
-    jclass eglcontextClassLocal = _env->FindClass("android/opengl/EGLContext");
-    eglcontextClass = (jclass) _env->NewGlobalRef(eglcontextClassLocal);
     jclass eglsurfaceClassLocal = _env->FindClass("android/opengl/EGLSurface");
     eglsurfaceClass = (jclass) _env->NewGlobalRef(eglsurfaceClassLocal);
-    jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig");
-    eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal);
+    jclass eglsyncClassLocal = _env->FindClass("android/opengl/EGLSync");
+    eglsyncClass = (jclass)_env->NewGlobalRef(eglsyncClassLocal);
 
     egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getNativeHandle", "()J");
-    eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J");
     eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getNativeHandle", "()J");
-    eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J");
-
-
-    egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V");
-    eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(J)V");
-    eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V");
-    eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(J)V");
-
-
-    jclass eglClass = _env->FindClass("android/opengl/EGL14");
-    jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;");
-    jobject localeglNoContextObject = _env->GetStaticObjectField(eglClass, noContextFieldID);
-    eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
-
-    jfieldID noDisplayFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;");
-    jobject localeglNoDisplayObject = _env->GetStaticObjectField(eglClass, noDisplayFieldID);
-    eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
-
-    jfieldID noSurfaceFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;");
-    jobject localeglNoSurfaceObject = _env->GetStaticObjectField(eglClass, noSurfaceFieldID);
-    eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
+    eglsyncGetHandleID = _env->GetMethodID(eglsyncClassLocal, "getNativeHandle", "()J");
 }
 
 static void *
@@ -108,26 +72,6 @@
     return reinterpret_cast<void*>(_env->CallLongMethod(obj, mid));
 }
 
-static jobject
-toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void * handle) {
-    if (cls == eglcontextClass &&
-       (EGLContext)handle == EGL_NO_CONTEXT) {
-           return eglNoContextObject;
-    }
-
-    if (cls == egldisplayClass &&
-       (EGLDisplay)handle == EGL_NO_DISPLAY) {
-           return eglNoDisplayObject;
-    }
-
-    if (cls == eglsurfaceClass &&
-       (EGLSurface)handle == EGL_NO_SURFACE) {
-           return eglNoSurfaceObject;
-    }
-
-    return _env->NewObject(cls, con, reinterpret_cast<jlong>(handle));
-}
-
 // --------------------------------------------------------------------------
 /* EGLBoolean eglPresentationTimeANDROID ( EGLDisplay dpy, EGLSurface sur, EGLnsecsANDROID time ) */
 static jboolean
@@ -145,11 +89,21 @@
     return (jboolean)_returnValue;
 }
 
+static jint android_eglDupNativeFenceFDANDROID(JNIEnv *env, jobject, jobject dpy, jobject sync) {
+    EGLDisplay dpy_native = (EGLDisplay)fromEGLHandle(env, egldisplayGetHandleID, dpy);
+    EGLSync sync_native = (EGLSync)fromEGLHandle(env, eglsyncGetHandleID, sync);
+
+    return eglDupNativeFenceFDANDROID(dpy_native, sync_native);
+}
+
 static const char *classPathName = "android/opengl/EGLExt";
 
 static const JNINativeMethod methods[] = {
-{"_nativeClassInit", "()V", (void*)nativeClassInit },
-{"eglPresentationTimeANDROID", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSurface;J)Z", (void *) android_eglPresentationTimeANDROID },
+        {"_nativeClassInit", "()V", (void *)nativeClassInit},
+        {"eglPresentationTimeANDROID", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSurface;J)Z",
+         (void *)android_eglPresentationTimeANDROID},
+        {"eglDupNativeFenceFDANDROIDImpl", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSync;)I",
+         (void *)android_eglDupNativeFenceFDANDROID},
 };
 
 int register_android_opengl_jni_EGLExt(JNIEnv *_env)
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index d91d526..19402f7 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -118,11 +118,11 @@
 
         ScopedLocalRef<jobjectArray>
                 frameTimelineObjs(env,
-                                  env->NewObjectArray(vsyncEventData.frameTimelines.size(),
+                                  env->NewObjectArray(VsyncEventData::kFrameTimelinesLength,
                                                       gDisplayEventReceiverClassInfo
                                                               .frameTimelineClassInfo.clazz,
                                                       /*initial element*/ NULL));
-        for (int i = 0; i < vsyncEventData.frameTimelines.size(); i++) {
+        for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
             VsyncEventData::FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i];
             ScopedLocalRef<jobject>
                     frameTimelineObj(env,
@@ -130,8 +130,8 @@
                                                             .frameTimelineClassInfo.clazz,
                                                     gDisplayEventReceiverClassInfo
                                                             .frameTimelineClassInfo.init,
-                                                    frameTimeline.id,
-                                                    frameTimeline.expectedPresentTime,
+                                                    frameTimeline.vsyncId,
+                                                    frameTimeline.expectedPresentationTime,
                                                     frameTimeline.deadlineTimestamp));
             env->SetObjectArrayElement(frameTimelineObjs.get(), i, frameTimelineObj.get());
         }
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 336161c..fb5b5ff 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -625,12 +625,16 @@
 }
 
 static void nativeSetBuffer(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
-                            jobject bufferObject) {
+                            jobject bufferObject, jlong fencePtr) {
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
     sp<GraphicBuffer> graphicBuffer(GraphicBuffer::fromAHardwareBuffer(
             android_hardware_HardwareBuffer_getNativeHardwareBuffer(env, bufferObject)));
-    transaction->setBuffer(ctrl, graphicBuffer);
+    std::optional<sp<Fence>> optFence = std::nullopt;
+    if (fencePtr != 0) {
+        optFence = sp<Fence>{reinterpret_cast<Fence*>(fencePtr)};
+    }
+    transaction->setBuffer(ctrl, graphicBuffer, optFence);
 }
 
 static void nativeSetBufferTransform(JNIEnv* env, jclass clazz, jlong transactionObj,
@@ -2133,7 +2137,7 @@
             (void*)nativeGetDisplayedContentSample },
     {"nativeSetGeometry", "(JJLandroid/graphics/Rect;Landroid/graphics/Rect;J)V",
             (void*)nativeSetGeometry },
-    {"nativeSetBuffer", "(JJLandroid/hardware/HardwareBuffer;)V",
+    {"nativeSetBuffer", "(JJLandroid/hardware/HardwareBuffer;J)V",
             (void*)nativeSetBuffer },
     {"nativeSetBufferTransform", "(JJI)V", (void*) nativeSetBufferTransform},
     {"nativeSetDataSpace", "(JJI)V",
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index f76b211..3c2a48a 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -574,6 +574,12 @@
 
     optional SettingProto lte_service_forced = 71 [ (android.privacy).dest = DEST_AUTOMATIC ];
     repeated SettingProto max_error_bytes = 151;
+
+    message ManagedDeviceProvisioning {
+        optional SettingProto managed_provisioning_defer_provisioning_to_role_holder = 1;
+    }
+    optional ManagedDeviceProvisioning managed_device_provisioning = 156;
+
     optional SettingProto mdc_initial_max_retry = 72 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
     message Mhl {
@@ -1077,5 +1083,5 @@
 
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 156;
+    // Next tag = 157;
 }
diff --git a/core/res/res/drawable/default_dream_preview.xml b/core/res/res/drawable/default_dream_preview.xml
deleted file mode 100644
index bf4a04b..0000000
--- a/core/res/res/drawable/default_dream_preview.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
-    <solid android:color="@android:color/white"/>
-</shape>
\ No newline at end of file
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index 009df4a..17ec02c 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -57,6 +57,12 @@
         com.android.systemui/com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity
     </string>
 
+    <!-- Component name of the activity used to inform a user about a sensory being blocked because
+     of hardware privacy switches. -->
+    <string name="config_sensorUseStartedActivity_hwToggle" translatable="false">
+        com.android.systemui/com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity
+    </string>
+
     <!-- Component name of the activity that shows the request for access to a usb device. -->
     <string name="config_usbPermissionActivity" translatable="false">
         com.android.systemui/com.android.systemui.usb.tv.TvUsbPermissionActivity
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 6dc975b..0e0c6a3 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2030,6 +2030,14 @@
         -->
         <attr name="resetEnabledSettingsOnAppDataCleared" format="boolean" />
         <attr name="knownActivityEmbeddingCerts" />
+
+        <!-- If false, {@link android.view.KeyEvent#KEYCODE_BACK KEYCODE_BACK} and
+             {@link android.app.Activity#onBackPressed Activity.onBackPressed()}
+             and related event will be forwarded to the Activities and View, otherwise those events
+             will be replaced by a call to
+             {@link android.view.OnBackInvokedCallback#onBackInvoked
+             OnBackInvokedCallback.onBackInvoked()} on the focused window. -->
+        <attr name="enableOnBackInvokedCallback" format="boolean"/>
     </declare-styleable>
 
     <!-- An attribution is a logical part of an app and is identified by a tag.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5e6d05a..80d84d7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2902,6 +2902,11 @@
     <string name="config_sensorUseStartedActivity" translatable="false"
             >com.android.systemui/com.android.systemui.sensorprivacy.SensorUseStartedActivity</string>
 
+    <!-- Component name of the activity used to inform a user about a sensory being blocked because
+     of hardware privacy switches. -->
+    <string name="config_sensorUseStartedActivity_hwToggle" translatable="false"
+            >com.android.systemui/com.android.systemui.sensorprivacy.SensorUseStartedActivity</string>
+
     <!-- Component name of the activity used to ask a user to confirm system language change after
          receiving <Set Menu Language> CEC message. -->
     <string name="config_hdmiCecSetMenuLanguageActivity"
@@ -3663,6 +3668,9 @@
     <!-- Controls whether the navigation bar lets through taps. -->
     <bool name="config_navBarTapThrough">false</bool>
 
+    <!-- Controls whether the IME renders the back and IME switcher buttons or not. -->
+    <bool name="config_imeDrawsImeNavBar">false</bool>
+
     <!-- Controls whether the side edge gestures can always trigger the transient nav bar to
          show. -->
     <bool name="config_navBarAlwaysShowOnSideEdgeGesture">false</bool>
@@ -5470,10 +5478,16 @@
     <!-- On-device package for providing companion device associations. -->
     <string name="config_systemCompanionDeviceProvider" translatable="false"></string>
 
-    <!-- Whether this device is supporting the microphone toggle -->
+    <!-- Whether this device is supporting the software microphone toggle -->
     <bool name="config_supportsMicToggle">false</bool>
     <!-- Whether this device is supporting the camera toggle -->
     <bool name="config_supportsCamToggle">false</bool>
+    <!-- Whether this device is supporting the hardware microphone toggle -->
+    <bool name="config_supportsHardwareMicToggle">false</bool>
+    <!-- Whether this device is supporting the hardware camera toggle -->
+    <bool name="config_supportsHardwareCamToggle">false</bool>
+    <!-- Whether a camera intent is launched when the lens cover is toggled -->
+    <bool name="config_launchCameraOnCameraLensCoverToggle">true</bool>
 
     <!-- List containing the allowed install sources for accessibility service. -->
     <string-array name="config_accessibility_allowed_install_source" translatable="false"/>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7bf34a1..9fa5f78 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3279,6 +3279,7 @@
     <public name="allowUntrustedActivityEmbedding" />
     <public name="knownActivityEmbeddingCerts" />
     <public name="intro" />
+    <public name="enableOnBackInvokedCallback" />
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01de0000">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0190451..f16b156 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -375,6 +375,7 @@
   <java-symbol type="string" name="config_usbConfirmActivity" />
   <java-symbol type="string" name="config_usbResolverActivity" />
   <java-symbol type="string" name="config_sensorUseStartedActivity" />
+  <java-symbol type="string" name="config_sensorUseStartedActivity_hwToggle" />
   <java-symbol type="string" name="config_hdmiCecSetMenuLanguageActivity" />
   <java-symbol type="integer" name="config_minNumVisibleRecentTasks_lowRam" />
   <java-symbol type="integer" name="config_maxNumVisibleRecentTasks_lowRam" />
@@ -2233,7 +2234,6 @@
   <java-symbol type="string" name="config_dreamsDefaultComponent" />
   <java-symbol type="array" name="config_supportedDreamComplications" />
   <java-symbol type="array" name="config_dreamComplicationsEnabledByDefault" />
-  <java-symbol type="drawable" name="default_dream_preview" />
   <java-symbol type="array" name="config_disabledDreamComponents" />
   <java-symbol type="string" name="config_dozeComponent" />
   <java-symbol type="string" name="enable_explore_by_touch_warning_title" />
@@ -2996,6 +2996,7 @@
   <java-symbol type="integer" name="config_navBarInteractionMode" />
   <java-symbol type="bool" name="config_navBarCanMove" />
   <java-symbol type="bool" name="config_navBarTapThrough" />
+  <java-symbol type="bool" name="config_imeDrawsImeNavBar" />
   <java-symbol type="bool" name="config_navBarAlwaysShowOnSideEdgeGesture" />
   <java-symbol type="bool" name="config_navBarNeedsScrim" />
   <java-symbol type="bool" name="config_allowSeamlessRotationDespiteNavBarMoving" />
@@ -4648,6 +4649,9 @@
 
   <java-symbol type="bool" name="config_supportsMicToggle" />
   <java-symbol type="bool" name="config_supportsCamToggle" />
+  <java-symbol type="bool" name="config_supportsHardwareMicToggle" />
+  <java-symbol type="bool" name="config_supportsHardwareCamToggle" />
+  <java-symbol type="bool" name="config_launchCameraOnCameraLensCoverToggle" />
 
   <java-symbol type="dimen" name="starting_surface_icon_size" />
   <java-symbol type="dimen" name="starting_surface_default_icon_size" />
diff --git a/core/tests/coretests/src/android/widget/OWNERS b/core/tests/coretests/src/android/widget/OWNERS
new file mode 100644
index 0000000..5a9aed3
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/OWNERS
@@ -0,0 +1,5 @@
+include /core/java/android/widget/OWNERS
+
+per-file *SuggestionsPopup* = file:/core/java/android/text/OWNERS
+
+per-file *FloatingToolbar*, *SelectionToolbar* = file:/core/java/android/view/textclassifier/OWNERS
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/window/TaskFpsCallbackTest.java b/core/tests/coretests/src/android/window/TaskFpsCallbackTest.java
index bf508db..2dadb20 100644
--- a/core/tests/coretests/src/android/window/TaskFpsCallbackTest.java
+++ b/core/tests/coretests/src/android/window/TaskFpsCallbackTest.java
@@ -53,14 +53,15 @@
     @Test
     public void testRegisterAndUnregister() {
 
-        final TaskFpsCallback.OnFpsCallbackListener listener = fps -> {
-            // Ignore
+        final TaskFpsCallback callback = new TaskFpsCallback() {
+            @Override
+            public void onFpsReported(float fps) {
+                // Ignore
+            }
         };
-        final TaskFpsCallback callback = new TaskFpsCallback(Runnable::run, listener);
-
         final List<ActivityManager.RunningTaskInfo> tasks = mActivityTaskManager.getTasks(1);
         assertEquals(tasks.size(), 1);
-        mWindowManager.registerTaskFpsCallback(tasks.get(0).taskId, callback);
+        mWindowManager.registerTaskFpsCallback(tasks.get(0).taskId, Runnable::run, callback);
         mWindowManager.unregisterTaskFpsCallback(callback);
     }
 }
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 88228f2..2a82d8e 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C} 2018 The Android Open Source Project
+// Copyright (C) 2018 The Android Open Source Project
 //
 // Licensed under the Apache License, Version 2.0 (the "License"};
 // you may not use this file except in compliance with the License.
@@ -140,13 +140,6 @@
 }
 
 prebuilt_etc {
-    name: "privapp_whitelist_com.android.networkstack.tethering",
-    sub_dir: "permissions",
-    src: "com.android.networkstack.tethering.xml",
-    filename_from_src: true,
-}
-
-prebuilt_etc {
     name: "privapp_whitelist_com.android.provision",
     system_ext_specific: true,
     sub_dir: "permissions",
diff --git a/data/etc/com.android.networkstack.tethering.xml b/data/etc/com.android.networkstack.tethering.xml
deleted file mode 100644
index f26a961..0000000
--- a/data/etc/com.android.networkstack.tethering.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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
--->
-
-<permissions>
-    <privapp-permissions package="com.android.networkstack.tethering">
-        <permission name="android.permission.BLUETOOTH_PRIVILEGED" />
-        <permission name="android.permission.MANAGE_USB"/>
-        <permission name="android.permission.MODIFY_PHONE_STATE"/>
-        <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
-        <permission name="android.permission.TETHER_PRIVILEGED"/>
-        <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
-        <permission name="android.permission.UPDATE_DEVICE_STATS"/>
-      </privapp-permissions>
-</permissions>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 4aa0f07..1779655 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2653,6 +2653,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "664667685": {
+      "message": "Activity %s: enableOnBackInvokedCallback=false. Returning null BackNavigationInfo.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
     "665256544": {
       "message": "All windows drawn!",
       "level": "DEBUG",
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index d35ecbd..0bf078d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -833,8 +833,8 @@
 
             if (shouldExpand(null, intent, getSplitRules())) {
                 setLaunchingInExpandedContainer(launchingActivity, options);
-            } else if (!setLaunchingToSideContainer(launchingActivity, intent, options)) {
-                setLaunchingInSameContainer(launchingActivity, intent, options);
+            } else if (!splitWithLaunchingActivity(launchingActivity, intent, options)) {
+                setLaunchingInSameSideContainer(launchingActivity, intent, options);
             }
 
             return super.onStartActivity(who, intent, options);
@@ -853,9 +853,9 @@
         /**
          * Returns {@code true} if the activity that is going to be started via the
          * {@code intent} should be paired with the {@code launchingActivity} and is set to be
-         * launched in an empty side container.
+         * launched in the side container.
          */
-        private boolean setLaunchingToSideContainer(Activity launchingActivity, Intent intent,
+        private boolean splitWithLaunchingActivity(Activity launchingActivity, Intent intent,
                 Bundle options) {
             final SplitPairRule splitPairRule = getSplitRule(launchingActivity, intent,
                     getSplitRules());
@@ -863,9 +863,14 @@
                 return false;
             }
 
-            // Create a new split with an empty side container
-            final TaskFragmentContainer secondaryContainer = mPresenter
-                    .createNewSplitWithEmptySideContainer(launchingActivity, splitPairRule);
+            // Check if there is any existing side container to launch into.
+            TaskFragmentContainer secondaryContainer = findSideContainerForNewLaunch(
+                    launchingActivity, splitPairRule);
+            if (secondaryContainer == null) {
+                // Create a new split with an empty side container.
+                secondaryContainer = mPresenter
+                        .createNewSplitWithEmptySideContainer(launchingActivity, splitPairRule);
+            }
 
             // Amend the request to let the WM know that the activity should be placed in the
             // dedicated container.
@@ -875,12 +880,39 @@
         }
 
         /**
+         * Finds if there is an existing split side {@link TaskFragmentContainer} that can be used
+         * for the new rule.
+         */
+        @Nullable
+        private TaskFragmentContainer findSideContainerForNewLaunch(Activity launchingActivity,
+                SplitPairRule splitPairRule) {
+            final TaskFragmentContainer launchingContainer = getContainerWithActivity(
+                    launchingActivity.getActivityToken());
+            if (launchingContainer == null) {
+                return null;
+            }
+
+            // We only check if the launching activity is the primary of the split. We will check
+            // if the launching activity is the secondary in #setLaunchingInSameSideContainer.
+            final SplitContainer splitContainer = getActiveSplitForContainer(launchingContainer);
+            if (splitContainer == null
+                    || splitContainer.getPrimaryContainer() != launchingContainer) {
+                return null;
+            }
+
+            if (canReuseContainer(splitPairRule, splitContainer.getSplitRule())) {
+                return splitContainer.getSecondaryContainer();
+            }
+            return null;
+        }
+
+        /**
          * Checks if the activity that is going to be started via the {@code intent} should be
          * paired with the existing top activity which is currently paired with the
-         * {@code launchingActivity}. If so, set the activity to be launched in the same
+         * {@code launchingActivity}. If so, set the activity to be launched in the same side
          * container of the {@code launchingActivity}.
          */
-        private void setLaunchingInSameContainer(Activity launchingActivity, Intent intent,
+        private void setLaunchingInSameSideContainer(Activity launchingActivity, Intent intent,
                 Bundle options) {
             final TaskFragmentContainer launchingContainer = getContainerWithActivity(
                     launchingActivity.getActivityToken());
@@ -911,6 +943,11 @@
                 return;
             }
 
+            // Can only launch in the same container if the rules share the same presentation.
+            if (!canReuseContainer(splitPairRule, splitContainer.getSplitRule())) {
+                return;
+            }
+
             // Amend the request to let the WM know that the activity should be placed in the
             // dedicated container. This is necessary for the case that the activity is started
             // into a new Task, or new Task will be escaped from the current host Task and be
@@ -928,4 +965,31 @@
     public boolean isActivityEmbedded(@NonNull Activity activity) {
         return mPresenter.isActivityEmbedded(activity.getActivityToken());
     }
+
+    /**
+     * If the two rules have the same presentation, we can reuse the same {@link SplitContainer} if
+     * there is any.
+     */
+    private static boolean canReuseContainer(SplitRule rule1, SplitRule rule2) {
+        if (!isContainerReusableRule(rule1) || !isContainerReusableRule(rule2)) {
+            return false;
+        }
+        return rule1.getSplitRatio() == rule2.getSplitRatio()
+                && rule1.getLayoutDirection() == rule2.getLayoutDirection();
+    }
+
+    /**
+     * Whether it is ok for other rule to reuse the {@link TaskFragmentContainer} of the given
+     * rule.
+     */
+    private static boolean isContainerReusableRule(SplitRule rule) {
+        // We don't expect to reuse the placeholder rule.
+        if (!(rule instanceof SplitPairRule)) {
+            return false;
+        }
+        final SplitPairRule pairRule = (SplitPairRule) rule;
+
+        // Not reuse if it needs to destroy the existing.
+        return !pairRule.shouldClearTop();
+    }
 }
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
index 5beaa87..9592376 100644
--- a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
@@ -22,81 +22,101 @@
 
     <!-- The background of the top-level layout acts as the background dim. -->
 
-    <!-- Setting the alpha of the dialog container to 0, since it shouldn't be visible until the
+    <!-- Vertical margin will be set dynamically since it depends on task bounds.
+         Setting the alpha of the dialog container to 0, since it shouldn't be visible until the
          enter animation starts. -->
-    <LinearLayout
+    <FrameLayout
         android:id="@+id/letterbox_education_dialog_container"
-        android:layout_width="wrap_content"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:gravity="center_horizontal"
-        android:orientation="vertical"
+        android:layout_marginHorizontal="@dimen/letterbox_education_dialog_margin"
         android:background="@drawable/letterbox_education_dialog_background"
-        android:padding="24dp"
-        android:alpha="0">
+        android:alpha="0"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintWidth_max="@dimen/letterbox_education_dialog_width"
+        app:layout_constrainedHeight="true">
 
-        <ImageView
-            android:id="@+id/letterbox_education_icon"
-            android:layout_width="@dimen/letterbox_education_dialog_icon_size"
-            android:layout_height="@dimen/letterbox_education_dialog_icon_size"
-            android:layout_marginBottom="12dp"
-            android:src="@drawable/letterbox_education_ic_letterboxed_app"/>
-
-        <TextView
-            android:id="@+id/letterbox_education_dialog_title"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:maxWidth="@dimen/letterbox_education_dialog_title_max_width"
-            android:lineSpacingExtra="4sp"
-            android:text="@string/letterbox_education_dialog_title"
-            android:textAlignment="center"
-            android:textColor="@color/compat_controls_text"
-            android:textSize="24sp"/>
-
-        <TextView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="8dp"
-            android:maxWidth="@dimen/letterbox_education_dialog_title_max_width"
-            android:lineSpacingExtra="4sp"
-            android:text="@string/letterbox_education_dialog_subtext"
-            android:textAlignment="center"
-            android:textColor="@color/letterbox_education_text_secondary"
-            android:textSize="14sp"/>
-
-        <LinearLayout
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:gravity="top"
-            android:orientation="horizontal"
-            android:paddingTop="48dp">
-
-            <com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogActionLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                app:icon="@drawable/letterbox_education_ic_screen_rotation"
-                app:text="@string/letterbox_education_screen_rotation_text"/>
-
-            <com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogActionLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="@dimen/letterbox_education_dialog_space_between_actions"
-                app:icon="@drawable/letterbox_education_ic_reposition"
-                app:text="@string/letterbox_education_reposition_text"/>
-
-        </LinearLayout>
-
-        <Button
-            android:id="@+id/letterbox_education_dialog_dismiss_button"
+        <!-- The ScrollView should only wrap the content of the dialog, otherwise the background
+             corner radius will be cut off when scrolling to the top/bottom. -->
+        <ScrollView
             android:layout_width="match_parent"
-            android:layout_height="56dp"
-            android:layout_marginTop="48dp"
-            android:background="@drawable/letterbox_education_dismiss_button_background_ripple"
-            android:text="@string/letterbox_education_got_it"
-            android:textColor="@android:color/system_neutral1_900"
-            android:textAlignment="center"
-            android:contentDescription="@string/letterbox_education_got_it"/>
+            android:layout_height="wrap_content">
 
-    </LinearLayout>
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_horizontal"
+                android:orientation="vertical"
+                android:padding="24dp">
+
+                <ImageView
+                    android:layout_width="@dimen/letterbox_education_dialog_icon_size"
+                    android:layout_height="@dimen/letterbox_education_dialog_icon_size"
+                    android:layout_marginBottom="12dp"
+                    android:src="@drawable/letterbox_education_ic_letterboxed_app"/>
+
+                <TextView
+                    android:id="@+id/letterbox_education_dialog_title"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:lineSpacingExtra="4sp"
+                    android:text="@string/letterbox_education_dialog_title"
+                    android:textAlignment="center"
+                    android:textColor="@color/compat_controls_text"
+                    android:textSize="24sp"/>
+
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="8dp"
+                    android:lineSpacingExtra="4sp"
+                    android:text="@string/letterbox_education_dialog_subtext"
+                    android:textAlignment="center"
+                    android:textColor="@color/letterbox_education_text_secondary"
+                    android:textSize="14sp"/>
+
+                <LinearLayout
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:gravity="top"
+                    android:orientation="horizontal"
+                    android:paddingTop="48dp">
+
+                    <com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogActionLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        app:icon="@drawable/letterbox_education_ic_screen_rotation"
+                        app:text="@string/letterbox_education_screen_rotation_text"/>
+
+                    <com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogActionLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginStart=
+                            "@dimen/letterbox_education_dialog_space_between_actions"
+                        app:icon="@drawable/letterbox_education_ic_reposition"
+                        app:text="@string/letterbox_education_reposition_text"/>
+
+                </LinearLayout>
+
+                <Button
+                    android:id="@+id/letterbox_education_dialog_dismiss_button"
+                    android:layout_width="match_parent"
+                    android:layout_height="56dp"
+                    android:layout_marginTop="48dp"
+                    android:background=
+                        "@drawable/letterbox_education_dismiss_button_background_ripple"
+                    android:text="@string/letterbox_education_got_it"
+                    android:textColor="@android:color/system_neutral1_900"
+                    android:textAlignment="center"
+                    android:contentDescription="@string/letterbox_education_got_it"/>
+
+            </LinearLayout>
+
+        </ScrollView>
+
+    </FrameLayout>
 
 </com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogLayout>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 7a398c5..8a8231d 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -225,15 +225,18 @@
     <!-- The size of an icon in the letterbox education dialog. -->
     <dimen name="letterbox_education_dialog_icon_size">48dp</dimen>
 
+    <!-- The fixed width of the dialog if there is enough space in the parent. -->
+    <dimen name="letterbox_education_dialog_width">472dp</dimen>
+
+    <!-- The margin between the dialog container and its parent. -->
+    <dimen name="letterbox_education_dialog_margin">16dp</dimen>
+
     <!-- The width of each action container in the letterbox education dialog -->
     <dimen name="letterbox_education_dialog_action_width">140dp</dimen>
 
     <!-- The space between two actions in the letterbox education dialog -->
     <dimen name="letterbox_education_dialog_space_between_actions">24dp</dimen>
 
-    <!-- The maximum width of the title and subtitle in the letterbox education dialog. -->
-    <dimen name="letterbox_education_dialog_title_max_width">444dp</dimen>
-
     <!-- The width of the brand image on staring surface. -->
     <dimen name="starting_surface_brand_image_width">200dp</dimen>
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 8d5fdfb..e50ad38 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -54,7 +54,7 @@
 
     private static final String BACK_PREDICTABILITY_PROP = "persist.debug.back_predictability";
     public static final boolean IS_ENABLED = SystemProperties
-            .getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+            .getInt(BACK_PREDICTABILITY_PROP, 1) > 0;
     private static final String BACK_PREDICTABILITY_PROGRESS_THRESHOLD_PROP =
             "persist.debug.back_predictability_progress_threshold";
     private static final int PROGRESS_THRESHOLD = SystemProperties
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
index 3a37b5e..7c6780a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManager.java
@@ -189,15 +189,18 @@
     }
 
     @Override
-    protected void updateSurfacePosition(Rect taskBounds, Rect stableBounds) {
+    @VisibleForTesting
+    public void updateSurfacePosition() {
         if (mLayout == null) {
             return;
         }
         // Position of the button in the container coordinate.
+        final Rect taskBounds = getTaskBounds();
+        final Rect taskStableBounds = getTaskStableBounds();
         final int positionX = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL
-                ? stableBounds.left - taskBounds.left
-                : stableBounds.right - taskBounds.left - mLayout.getMeasuredWidth();
-        final int positionY = stableBounds.bottom - taskBounds.top
+                ? taskStableBounds.left - taskBounds.left
+                : taskStableBounds.right - taskBounds.left - mLayout.getMeasuredWidth();
+        final int positionY = taskStableBounds.bottom - taskBounds.top
                 - mLayout.getMeasuredHeight();
 
         updateSurfacePosition(positionX, positionY);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
index 7014fcc..5679bc4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
@@ -51,15 +51,15 @@
  */
 public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowManager {
 
-    protected final SyncTransactionQueue mSyncQueue;
-    protected final int mDisplayId;
     protected final int mTaskId;
-
     protected Context mContext;
-    protected Configuration mTaskConfig;
-    protected ShellTaskOrganizer.TaskListener mTaskListener;
-    protected DisplayLayout mDisplayLayout;
-    protected final Rect mStableBounds;
+
+    private final SyncTransactionQueue mSyncQueue;
+    private final int mDisplayId;
+    private Configuration mTaskConfig;
+    private ShellTaskOrganizer.TaskListener mTaskListener;
+    private DisplayLayout mDisplayLayout;
+    private final Rect mStableBounds;
 
     /**
      * Utility class for adding and releasing a View hierarchy for this {@link
@@ -211,7 +211,7 @@
         boolean layoutDirectionUpdated =
                 mTaskConfig.getLayoutDirection() != prevTaskConfig.getLayoutDirection();
         if (boundsUpdated || layoutDirectionUpdated) {
-            updateSurface();
+            onParentBoundsChanged();
         }
 
         if (layout != null && layoutDirectionUpdated) {
@@ -248,8 +248,9 @@
         displayLayout.getStableBounds(curStableBounds);
         mDisplayLayout = displayLayout;
         if (!prevStableBounds.equals(curStableBounds)) {
-            updateSurface();
+            // mStableBounds should be updated before we call onParentBoundsChanged.
             mStableBounds.set(curStableBounds);
+            onParentBoundsChanged();
         }
     }
 
@@ -289,51 +290,39 @@
     }
 
     /** Re-layouts the view host and updates the surface position. */
-    public void relayout() {
+    void relayout() {
+        relayout(getWindowLayoutParams());
+    }
+
+    protected void relayout(WindowManager.LayoutParams windowLayoutParams) {
         if (mViewHost == null) {
             return;
         }
-        mViewHost.relayout(getWindowLayoutParams());
+        mViewHost.relayout(windowLayoutParams);
         updateSurfacePosition();
     }
 
     /**
-     * Updates the surface following a change in the task bounds, display layout stable bounds,
-     * or the layout direction.
+     * Called following a change in the task bounds, display layout stable bounds, or the layout
+     * direction.
      */
-    protected void updateSurface() {
+    protected void onParentBoundsChanged() {
         updateSurfacePosition();
     }
 
     /**
-     * Updates the position of the surface with respect to the task bounds and display layout
-     * stable bounds.
+     * Updates the position of the surface with respect to the parent bounds.
      */
-    @VisibleForTesting
-    void updateSurfacePosition() {
-        if (mLeash == null) {
-            return;
-        }
-        // Use stable bounds to prevent controls from overlapping with system bars.
-        final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds();
-        final Rect stableBounds = new Rect();
-        mDisplayLayout.getStableBounds(stableBounds);
-        stableBounds.intersect(taskBounds);
-
-        updateSurfacePosition(taskBounds, stableBounds);
-    }
-
-    /**
-     * Updates the position of the surface with respect to the given {@code taskBounds} and {@code
-     * stableBounds}.
-     */
-    protected abstract void updateSurfacePosition(Rect taskBounds, Rect stableBounds);
+    protected abstract void updateSurfacePosition();
 
     /**
      * Updates the position of the surface with respect to the given {@code positionX} and {@code
      * positionY}.
      */
     protected void updateSurfacePosition(int positionX, int positionY) {
+        if (mLeash == null) {
+            return;
+        }
         mSyncQueue.runInSync(t -> {
             if (mLeash == null || !mLeash.isValid()) {
                 Log.w(getTag(), "The leash has been released.");
@@ -347,6 +336,17 @@
         return mContext.getResources().getConfiguration().getLayoutDirection();
     }
 
+    protected Rect getTaskBounds() {
+        return mTaskConfig.windowConfiguration.getBounds();
+    }
+
+    /** Returns the intersection between the task bounds and the display layout stable bounds. */
+    protected Rect getTaskStableBounds() {
+        final Rect result = new Rect(mStableBounds);
+        result.intersect(getTaskBounds());
+        return result;
+    }
+
     @VisibleForTesting
     SurfaceControlViewHost createSurfaceViewHost() {
         return new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
index eff2602..3810eca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java
@@ -43,6 +43,8 @@
 class LetterboxEduAnimationController {
     private static final String TAG = "LetterboxEduAnimation";
 
+    private static final int ENTER_ANIM_START_DELAY_MILLIS = 500;
+
     private final TransitionAnimation mTransitionAnimation;
     private final String mPackageName;
     @AnyRes
@@ -87,6 +89,9 @@
                 mDialogAnimation.getDuration());
         mBackgroundDimAnimator.addListener(getDimAnimatorListener());
 
+        mDialogAnimation.setStartOffset(ENTER_ANIM_START_DELAY_MILLIS);
+        mBackgroundDimAnimator.setStartDelay(ENTER_ANIM_START_DELAY_MILLIS);
+
         dialogContainer.startAnimation(mDialogAnimation);
         mBackgroundDimAnimator.start();
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
index bc1d19b..bb6fe98 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java
@@ -20,7 +20,8 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.View;
-import android.widget.FrameLayout;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
 
 import com.android.wm.shell.R;
 
@@ -31,7 +32,7 @@
  * background dim which dismisses the dialog when clicked.
  */
 // TODO(b/215316431): Add tests
-class LetterboxEduDialogLayout extends FrameLayout {
+class LetterboxEduDialogLayout extends ConstraintLayout {
 
     // The alpha of a background is a number between 0 (fully transparent) to 255 (fully opaque).
     // 204 is simply 255 * 0.8.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
index 074610b..bb4d427 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
@@ -26,6 +26,7 @@
 import android.provider.Settings;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup.MarginLayoutParams;
 import android.view.WindowManager;
 
 import com.android.wm.shell.R;
@@ -109,6 +110,7 @@
     protected View createLayout() {
         setSeenLetterboxEducation();
         mLayout = inflateLayout();
+        updateDialogMargins();
 
         mAnimationController.startEnterAnimation(mLayout, /* endCallback= */
                 this::setDismissOnClickListener);
@@ -116,6 +118,22 @@
         return mLayout;
     }
 
+    private void updateDialogMargins() {
+        if (mLayout == null) {
+            return;
+        }
+        final View dialogContainer = mLayout.getDialogContainer();
+        MarginLayoutParams marginParams = (MarginLayoutParams) dialogContainer.getLayoutParams();
+        int verticalMargin = (int) mContext.getResources().getDimension(
+                R.dimen.letterbox_education_dialog_margin);
+
+        final Rect taskBounds = getTaskBounds();
+        final Rect taskStableBounds = getTaskStableBounds();
+        marginParams.topMargin = taskStableBounds.top - taskBounds.top + verticalMargin;
+        marginParams.bottomMargin = taskBounds.bottom - taskStableBounds.bottom + verticalMargin;
+        dialogContainer.setLayoutParams(marginParams);
+    }
+
     private LetterboxEduDialogLayout inflateLayout() {
         return (LetterboxEduDialogLayout) LayoutInflater.from(mContext).inflate(
                 R.layout.letterbox_education_dialog_layout, null);
@@ -150,20 +168,26 @@
     }
 
     @Override
-    protected void updateSurface() {
-        // We need to relayout because the layout dimensions depend on the task bounds.
-        relayout();
+    protected void onParentBoundsChanged() {
+        if (mLayout == null) {
+            return;
+        }
+        // Both the layout dimensions and dialog margins depend on the parent bounds.
+        WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams();
+        mLayout.setLayoutParams(windowLayoutParams);
+        updateDialogMargins();
+        relayout(windowLayoutParams);
     }
 
     @Override
-    protected void updateSurfacePosition(Rect taskBounds, Rect stableBounds) {
+    protected void updateSurfacePosition() {
         // Nothing to do, since the position of the surface is fixed to the top left corner (0,0)
         // of the task (parent surface), which is the default position of a surface.
     }
 
     @Override
     protected WindowManager.LayoutParams getWindowLayoutParams() {
-        final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds();
+        final Rect taskBounds = getTaskBounds();
         return getWindowLayoutParams(/* width= */ taskBounds.width(), /* height= */
                 taskBounds.height());
     }
diff --git a/libs/androidfw/tests/BackupHelpers_test.cpp b/libs/androidfw/tests/BackupHelpers_test.cpp
index 86b7fb3..c2fcb69 100644
--- a/libs/androidfw/tests/BackupHelpers_test.cpp
+++ b/libs/androidfw/tests/BackupHelpers_test.cpp
@@ -50,7 +50,7 @@
 TEST_F(BackupHelpersTest, WriteTarFileWithSizeGreaterThan2GB) {
   TemporaryFile tf;
   // Allocate a 2 GB file.
-  off64_t fileSize = 2ll * 1024ll * 1024ll * 1024ll + 512ll;
+  off64_t fileSize = 2LL * 1024LL * 1024LL * 1024LL + 512LL;
   ASSERT_EQ(0, posix_fallocate64(tf.fd, 0, fileSize));
   off64_t tarSize = 0;
   int err = write_tarfile(/* packageName */ String8("test-pkg"), /* domain */ String8(""), /* rootpath */ String8(""), /* filePath */ String8(tf.path), /* outSize */ &tarSize, /* writer */ NULL);
diff --git a/media/java/android/media/AudioDeviceVolumeManager.java b/media/java/android/media/AudioDeviceVolumeManager.java
new file mode 100644
index 0000000..0e9c99b
--- /dev/null
+++ b/media/java/android/media/AudioDeviceVolumeManager.java
@@ -0,0 +1,192 @@
+/*
+ * 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.media;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ * AudioDeviceVolumeManager provides access to audio device volume control.
+ */
+public class AudioDeviceVolumeManager {
+
+    // define when using Log.*
+    //private static final String TAG = "AudioDeviceVolumeManager";
+    private static IAudioService sService;
+
+    private final String mPackageName;
+
+    public AudioDeviceVolumeManager(Context context) {
+        mPackageName = context.getApplicationContext().getOpPackageName();
+    }
+
+    /**
+     * @hide
+     * Interface to receive volume changes on a device that behaves in absolute volume mode.
+     * @see #setDeviceAbsoluteMultiVolumeBehavior(AudioDeviceAttributes, List, Executor,
+     *         OnAudioDeviceVolumeChangeListener)
+     * @see #setDeviceAbsoluteVolumeBehavior(AudioDeviceAttributes, VolumeInfo, Executor,
+     *         OnAudioDeviceVolumeChangeListener)
+     */
+    public interface OnAudioDeviceVolumeChangedListener {
+        /**
+         * Called the device for the given audio device has changed.
+         * @param device the audio device whose volume has changed
+         * @param vol the new volume for the device
+         */
+        void onAudioDeviceVolumeChanged(
+                @NonNull AudioDeviceAttributes device,
+                @NonNull VolumeInfo vol);
+    }
+
+    static class ListenerInfo {
+        final @NonNull OnAudioDeviceVolumeChangedListener mListener;
+        final @NonNull Executor mExecutor;
+        final @NonNull AudioDeviceAttributes mDevice;
+
+        ListenerInfo(@NonNull OnAudioDeviceVolumeChangedListener listener, @NonNull Executor exe,
+                @NonNull AudioDeviceAttributes device) {
+            mListener = listener;
+            mExecutor = exe;
+            mDevice = device;
+        }
+    }
+
+    private final Object mDeviceVolumeListenerLock = new Object();
+    /**
+     * List of listeners for volume changes, the associated device, and their associated Executor.
+     * List is lazy-initialized on first registration
+     */
+    @GuardedBy("mDeviceVolumeListenerLock")
+    private @Nullable ArrayList<ListenerInfo> mDeviceVolumeListeners;
+
+    @GuardedBy("mDeviceVolumeListenerLock")
+    private DeviceVolumeDispatcherStub mDeviceVolumeDispatcherStub;
+
+    final class DeviceVolumeDispatcherStub extends IAudioDeviceVolumeDispatcher.Stub {
+        /**
+         * Register / unregister the stub
+         * @param register true for registering, false for unregistering
+         * @param device device for which volume is monitored
+         */
+        public void register(boolean register, @NonNull AudioDeviceAttributes device,
+                @NonNull List<VolumeInfo> volumes) {
+            try {
+                getService().registerDeviceVolumeDispatcherForAbsoluteVolume(register,
+                        this, mPackageName,
+                        Objects.requireNonNull(device), Objects.requireNonNull(volumes));
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        }
+
+        @Override
+        public void dispatchDeviceVolumeChanged(
+                @NonNull AudioDeviceAttributes device, @NonNull VolumeInfo vol) {
+            final ArrayList<ListenerInfo> volumeListeners;
+            synchronized (mDeviceVolumeListenerLock) {
+                volumeListeners = (ArrayList<ListenerInfo>) mDeviceVolumeListeners.clone();
+            }
+            for (ListenerInfo listenerInfo : volumeListeners) {
+                if (listenerInfo.mDevice.equals(device)) {
+                    listenerInfo.mExecutor.execute(
+                            () -> listenerInfo.mListener.onAudioDeviceVolumeChanged(device, vol));
+                }
+            }
+        }
+    }
+
+    /**
+     * @hide
+     * Configures a device to use absolute volume model, and registers a listener for receiving
+     * volume updates to apply on that device
+     * @param device the audio device set to absolute volume mode
+     * @param volume the type of volume this device responds to
+     * @param executor the Executor used for receiving volume updates through the listener
+     * @param vclistener the callback for volume updates
+     */
+    @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED })
+    public void setDeviceAbsoluteVolumeBehavior(
+            @NonNull AudioDeviceAttributes device,
+            @NonNull VolumeInfo volume,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnAudioDeviceVolumeChangedListener vclistener) {
+        final ArrayList<VolumeInfo> volumes = new ArrayList<>(1);
+        volumes.add(volume);
+        setDeviceAbsoluteMultiVolumeBehavior(device, volumes, executor, vclistener);
+    }
+
+    /**
+     * @hide
+     * Configures a device to use absolute volume model applied to different volume types, and
+     * registers a listener for receiving volume updates to apply on that device
+     * @param device the audio device set to absolute multi-volume mode
+     * @param volumes the list of volumes the given device responds to
+     * @param executor the Executor used for receiving volume updates through the listener
+     * @param vclistener the callback for volume updates
+     */
+    @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED })
+    public void setDeviceAbsoluteMultiVolumeBehavior(
+            @NonNull AudioDeviceAttributes device,
+            @NonNull List<VolumeInfo> volumes,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull OnAudioDeviceVolumeChangedListener vclistener) {
+        Objects.requireNonNull(device);
+        Objects.requireNonNull(volumes);
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(vclistener);
+
+        // TODO verify not already registered
+        //final ListenerInfo listenerInfo = new ListenerInfo(vclistener, executor, device);
+        synchronized (mDeviceVolumeListenerLock) {
+            if (mDeviceVolumeListeners == null) {
+                mDeviceVolumeListeners = new ArrayList<>();
+            }
+            if (mDeviceVolumeListeners.size() == 0) {
+                if (mDeviceVolumeDispatcherStub == null) {
+                    mDeviceVolumeDispatcherStub = new DeviceVolumeDispatcherStub();
+                }
+            }
+            mDeviceVolumeDispatcherStub.register(true, device, volumes);
+        }
+    }
+
+    private static IAudioService getService() {
+        if (sService != null) {
+            return sService;
+        }
+        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+        sService = IAudioService.Stub.asInterface(b);
+        return sService;
+    }
+}
diff --git a/core/java/android/window/IOnFpsCallbackListener.aidl b/media/java/android/media/IAudioDeviceVolumeDispatcher.aidl
similarity index 65%
copy from core/java/android/window/IOnFpsCallbackListener.aidl
copy to media/java/android/media/IAudioDeviceVolumeDispatcher.aidl
index 3091df3..65633fe 100644
--- a/core/java/android/window/IOnFpsCallbackListener.aidl
+++ b/media/java/android/media/IAudioDeviceVolumeDispatcher.aidl
@@ -14,17 +14,18 @@
  * limitations under the License.
  */
 
-package android.window;
+package android.media;
+
+import android.media.AudioDeviceAttributes;
+import android.media.VolumeInfo;
 
 /**
- * @hide
+ * AIDL for the AudioService to signal audio device volume changes.
+ *
+ * {@hide}
  */
-oneway interface IOnFpsCallbackListener {
+oneway interface IAudioDeviceVolumeDispatcher {
 
-    /**
-     * Reports the fps from the registered task
-     * @param fps The frame rate per second of the task that has the registered task id
-     *            and its children.
-     */
-    void onFpsReported(in float fps);
+    void dispatchDeviceVolumeChanged(in AudioDeviceAttributes device, in VolumeInfo vol);
+
 }
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index a6fdf6c..2c9f015 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -26,6 +26,7 @@
 import android.media.AudioRecordingConfiguration;
 import android.media.AudioRoutesInfo;
 import android.media.BluetoothProfileConnectionInfo;
+import android.media.IAudioDeviceVolumeDispatcher;
 import android.media.IAudioFocusDispatcher;
 import android.media.IAudioModeDispatcher;
 import android.media.IAudioRoutesObserver;
@@ -44,6 +45,7 @@
 import android.media.IVolumeController;
 import android.media.IVolumeController;
 import android.media.PlayerBase;
+import android.media.VolumeInfo;
 import android.media.VolumePolicy;
 import android.media.audiopolicy.AudioPolicyConfig;
 import android.media.audiopolicy.AudioProductStrategy;
@@ -456,6 +458,8 @@
 
     boolean isVolumeFixed();
 
+    VolumeInfo getDefaultVolumeInfo();
+
     boolean isPstnCallAudioInterceptable();
 
     oneway void muteAwaitConnection(in int[] usagesToMute, in AudioDeviceAttributes dev,
@@ -474,6 +478,7 @@
 
     boolean sendFocusLoss(in AudioFocusInfo focusLoser, in IAudioPolicyCallback apcb);
 
+
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
     void addAssistantServicesUids(in int[] assistantUID);
 
@@ -488,4 +493,10 @@
 
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
     int[] getActiveAssistantServiceUids();
+
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)")
+    void registerDeviceVolumeDispatcherForAbsoluteVolume(boolean register,
+            in IAudioDeviceVolumeDispatcher cb,
+            in String packageName,
+            in AudioDeviceAttributes device, in List<VolumeInfo> volumes);
 }
diff --git a/media/java/android/media/VolumeInfo.aidl b/media/java/android/media/VolumeInfo.aidl
new file mode 100644
index 0000000..aa82f52
--- /dev/null
+++ b/media/java/android/media/VolumeInfo.aidl
@@ -0,0 +1,18 @@
+/* Copyright 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.media;
+
+parcelable VolumeInfo;
diff --git a/media/java/android/media/VolumeInfo.java b/media/java/android/media/VolumeInfo.java
new file mode 100644
index 0000000..c61b0e5
--- /dev/null
+++ b/media/java/android/media/VolumeInfo.java
@@ -0,0 +1,380 @@
+/*
+ * 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.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.media.audiopolicy.AudioVolumeGroup;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @hide
+ * A class to represent type of volume information.
+ * Can be used to represent volume associated with a stream type or {@link AudioVolumeGroup}.
+ * Volume index is optional when used to represent a category of volume.
+ * Index ranges are supported too, making the representation of volume changes agnostic to the
+ * range (e.g. can be used to map BT A2DP absolute volume range to internal range).
+ *
+ * Note: this class is not yet part of the SystemApi but is intended to be gradually introduced
+ *       particularly in parts of the audio framework that suffer from code ambiguity when
+ *       dealing with different volume ranges / units.
+ */
+public final class VolumeInfo implements Parcelable {
+    private static final String TAG = "VolumeInfo";
+
+    private final boolean mUsesStreamType; // false implies AudioVolumeGroup is used
+    private final boolean mIsMuted;
+    private final int mVolIndex;
+    private final int mMinVolIndex;
+    private final int mMaxVolIndex;
+    private final int mVolGroupId;
+    private final int mStreamType;
+
+    private static IAudioService sService;
+    private static VolumeInfo sDefaultVolumeInfo;
+
+    private VolumeInfo(boolean usesStreamType, boolean isMuted, int volIndex,
+            int minVolIndex, int maxVolIndex,
+            int volGroupId, int streamType) {
+        mUsesStreamType = usesStreamType;
+        mIsMuted = isMuted;
+        mVolIndex = volIndex;
+        mMinVolIndex = minVolIndex;
+        mMaxVolIndex = maxVolIndex;
+        mVolGroupId = volGroupId;
+        mStreamType = streamType;
+    }
+
+    /**
+     * Indicates whether this instance has a stream type associated to it.
+     * Note this method returning true implies {@link #hasVolumeGroup()} returns false.
+     * (e.g. {@link AudioManager#STREAM_MUSIC}).
+     * @return true if it has stream type information
+     */
+    public boolean hasStreamType() {
+        return mUsesStreamType;
+    }
+
+    /**
+     * Returns the associated stream type, or will throw if {@link #hasStreamType()} returned false.
+     * @return a stream type value, see AudioManager.STREAM_*
+     */
+    public int getStreamType() {
+        if (!mUsesStreamType) {
+            throw new IllegalStateException("VolumeInfo doesn't use stream types");
+        }
+        return mStreamType;
+    }
+
+    /**
+     * Indicates whether this instance has a {@link AudioVolumeGroup} associated to it.
+     * Note this method returning true implies {@link #hasStreamType()} returns false.
+     * @return true if it has volume group information
+     */
+    public boolean hasVolumeGroup() {
+        return !mUsesStreamType;
+    }
+
+    /**
+     * Returns the associated volume group, or will throw if {@link #hasVolumeGroup()} returned
+     * false.
+     * @return the volume group corresponding to this VolumeInfo, or null if an error occurred
+     * in the volume group management
+     */
+    public @Nullable AudioVolumeGroup getVolumeGroup() {
+        if (mUsesStreamType) {
+            throw new IllegalStateException("VolumeInfo doesn't use AudioVolumeGroup");
+        }
+        List<AudioVolumeGroup> volGroups = AudioVolumeGroup.getAudioVolumeGroups();
+        for (AudioVolumeGroup group : volGroups) {
+            if (group.getId() == mVolGroupId) {
+                return group;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns whether this instance is conveying a mute state.
+     * @return true if the volume state is muted
+     */
+    public boolean isMuted() {
+        return mIsMuted;
+    }
+
+    /**
+     * A value used to express no volume index has been set.
+     */
+    public static final int INDEX_NOT_SET = -100;
+
+    /**
+     * Returns the volume index.
+     * @return a volume index, or {@link #INDEX_NOT_SET} if no index was set, in which case this
+     *      instance is used to express a volume representation type (stream vs group) and
+     *      optionally its volume range
+     */
+    public int getVolumeIndex() {
+        return mVolIndex;
+    }
+
+    /**
+     * Returns the minimum volume index.
+     * @return the minimum volume index, or {@link #INDEX_NOT_SET} if no minimum index was set.
+     */
+    public int getMinVolumeIndex() {
+        return mMinVolIndex;
+    }
+
+    /**
+     * Returns the maximum volume index.
+     * @return the maximum volume index, or {@link #INDEX_NOT_SET} if no maximum index was
+     *      set.
+     */
+    public int getMaxVolumeIndex() {
+        return mMaxVolIndex;
+    }
+
+    /**
+     * Returns the default info for the platform, typically initialized
+     * to STREAM_MUSIC with min/max initialized to the associated range
+     * @return the default VolumeInfo for the device
+     */
+    public static @NonNull VolumeInfo getDefaultVolumeInfo() {
+        if (sService == null) {
+            IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
+            sService = IAudioService.Stub.asInterface(b);
+        }
+        if (sDefaultVolumeInfo == null) {
+            try {
+                sDefaultVolumeInfo = sService.getDefaultVolumeInfo();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error calling getDefaultVolumeInfo", e);
+                // return a valid value, but don't cache it
+                return new VolumeInfo.Builder(AudioManager.STREAM_MUSIC).build();
+            }
+        }
+        return sDefaultVolumeInfo;
+    }
+
+    /**
+     * The builder class for creating and initializing, or copying and modifying VolumeInfo
+     * instances
+     */
+    public static final class Builder {
+        private boolean mUsesStreamType = true; // false implies AudioVolumeGroup is used
+        private int mStreamType = AudioManager.STREAM_MUSIC;
+        private boolean mIsMuted = false;
+        private int mVolIndex = INDEX_NOT_SET;
+        private int mMinVolIndex = INDEX_NOT_SET;
+        private int mMaxVolIndex = INDEX_NOT_SET;
+        private int mVolGroupId = -Integer.MIN_VALUE;
+
+        /**
+         * Builder constructor for stream type-based VolumeInfo
+         */
+        public Builder(int streamType) {
+            // TODO validate stream type
+            mUsesStreamType = true;
+            mStreamType = streamType;
+        }
+
+        /**
+         * Builder constructor for volume group-based VolumeInfo
+         */
+        public Builder(@NonNull AudioVolumeGroup volGroup) {
+            Objects.requireNonNull(volGroup);
+            mUsesStreamType = false;
+            mStreamType = -Integer.MIN_VALUE;
+            mVolGroupId = volGroup.getId();
+        }
+
+        /**
+         * Builder constructor to copy a given VolumeInfo.
+         * Note you can't change the stream type or volume group later.
+         */
+        public Builder(@NonNull VolumeInfo info) {
+            Objects.requireNonNull(info);
+            mUsesStreamType = info.mUsesStreamType;
+            mStreamType = info.mStreamType;
+            mIsMuted = info.mIsMuted;
+            mVolIndex = info.mVolIndex;
+            mMinVolIndex = info.mMinVolIndex;
+            mMaxVolIndex = info.mMaxVolIndex;
+            mVolGroupId = info.mVolGroupId;
+        }
+
+        /**
+         * Sets whether the volume is in a muted state
+         * @param isMuted
+         * @return the same builder instance
+         */
+        public @NonNull Builder setMuted(boolean isMuted) {
+            mIsMuted = isMuted;
+            return this;
+        }
+
+        /**
+         * Sets the volume index
+         * @param volIndex a 0 or greater value, or {@link #INDEX_NOT_SET} if unknown
+         * @return the same builder instance
+         */
+        // TODO should we allow muted true + volume index set? (useful when toggling mute on/off?)
+        public @NonNull Builder setVolumeIndex(int volIndex) {
+            if (volIndex != INDEX_NOT_SET && volIndex < 0) {
+                throw new IllegalArgumentException("Volume index cannot be negative");
+            }
+            mVolIndex = volIndex;
+            return this;
+        }
+
+        /**
+         * Sets the minimum volume index
+         * @param minIndex a 0 or greater value, or {@link #INDEX_NOT_SET} if unknown
+         * @return the same builder instance
+         */
+        public @NonNull Builder setMinVolumeIndex(int minIndex) {
+            if (minIndex != INDEX_NOT_SET && minIndex < 0) {
+                throw new IllegalArgumentException("Min volume index cannot be negative");
+            }
+            mMinVolIndex = minIndex;
+            return this;
+        }
+
+        /**
+         * Sets the maximum volume index
+         * @param maxIndex a 0 or greater value, or {@link #INDEX_NOT_SET} if unknown
+         * @return the same builder instance
+         */
+        public @NonNull Builder setMaxVolumeIndex(int maxIndex) {
+            if (maxIndex != INDEX_NOT_SET && maxIndex < 0) {
+                throw new IllegalArgumentException("Max volume index cannot be negative");
+            }
+            mMaxVolIndex = maxIndex;
+            return this;
+        }
+
+        /**
+         * Builds the VolumeInfo with the data given to the builder
+         * @return the new VolumeInfo instance
+         */
+        public @NonNull VolumeInfo build() {
+            if (mVolIndex != INDEX_NOT_SET) {
+                if (mMinVolIndex != INDEX_NOT_SET && mVolIndex < mMinVolIndex) {
+                    throw new IllegalArgumentException("Volume index:" + mVolIndex
+                            + " lower than min index:" + mMinVolIndex);
+                }
+                if (mMaxVolIndex != INDEX_NOT_SET && mVolIndex > mMaxVolIndex) {
+                    throw new IllegalArgumentException("Volume index:" + mVolIndex
+                            + " greater than max index:" + mMaxVolIndex);
+                }
+            }
+            if (mMinVolIndex != INDEX_NOT_SET && mMaxVolIndex != INDEX_NOT_SET
+                    && mMinVolIndex > mMaxVolIndex) {
+                throw new IllegalArgumentException("Min volume index:" + mMinVolIndex
+                        + " greater than max index:" + mMaxVolIndex);
+            }
+            return new VolumeInfo(mUsesStreamType, mIsMuted,
+                    mVolIndex, mMinVolIndex, mMaxVolIndex,
+                    mVolGroupId, mStreamType);
+        }
+    }
+
+    //-----------------------------------------------
+    // Parcelable
+    @Override
+    public int hashCode() {
+        return Objects.hash(mUsesStreamType, mStreamType, mIsMuted,
+                mVolIndex, mMinVolIndex, mMaxVolIndex, mVolGroupId);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        VolumeInfo that = (VolumeInfo) o;
+        return ((mUsesStreamType == that.mUsesStreamType)
+                && (mStreamType == that.mStreamType)
+            && (mIsMuted == that.mIsMuted)
+            && (mVolIndex == that.mVolIndex)
+            && (mMinVolIndex == that.mMinVolIndex)
+            && (mMaxVolIndex == that.mMaxVolIndex)
+            && (mVolGroupId == that.mVolGroupId));
+    }
+
+    @Override
+    public String toString() {
+        return new String("VolumeInfo:"
+                + (mUsesStreamType ? (" streamType:" + mStreamType)
+                    : (" volGroupId" + mVolGroupId))
+                + " muted:" + mIsMuted
+                + ((mVolIndex != INDEX_NOT_SET) ? (" volIndex:" + mVolIndex) : "")
+                + ((mMinVolIndex != INDEX_NOT_SET) ? (" min:" + mMinVolIndex) : "")
+                + ((mMaxVolIndex != INDEX_NOT_SET) ? (" max:" + mMaxVolIndex) : ""));
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeBoolean(mUsesStreamType);
+        dest.writeInt(mStreamType);
+        dest.writeBoolean(mIsMuted);
+        dest.writeInt(mVolIndex);
+        dest.writeInt(mMinVolIndex);
+        dest.writeInt(mMaxVolIndex);
+        dest.writeInt(mVolGroupId);
+    }
+
+    private VolumeInfo(@NonNull Parcel in) {
+        mUsesStreamType = in.readBoolean();
+        mStreamType = in.readInt();
+        mIsMuted = in.readBoolean();
+        mVolIndex = in.readInt();
+        mMinVolIndex = in.readInt();
+        mMaxVolIndex = in.readInt();
+        mVolGroupId = in.readInt();
+    }
+
+    public static final @NonNull Parcelable.Creator<VolumeInfo> CREATOR =
+            new Parcelable.Creator<VolumeInfo>() {
+                /**
+                 * Rebuilds a VolumeInfo previously stored with writeToParcel().
+                 * @param p Parcel object to read the VolumeInfo from
+                 * @return a new VolumeInfo created from the data in the parcel
+                 */
+                public VolumeInfo createFromParcel(Parcel p) {
+                    return new VolumeInfo(p);
+                }
+
+                public VolumeInfo[] newArray(int size) {
+                    return new VolumeInfo[size];
+                }
+            };
+}
diff --git a/opengl/java/android/opengl/EGLExt.java b/opengl/java/android/opengl/EGLExt.java
index 74b64ea..1570e0e 100644
--- a/opengl/java/android/opengl/EGLExt.java
+++ b/opengl/java/android/opengl/EGLExt.java
@@ -18,6 +18,11 @@
 
 package android.opengl;
 
+import android.annotation.NonNull;
+import android.hardware.SyncFence;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
 /**
  * EGL Extensions
  */
@@ -30,6 +35,12 @@
     public static final int EGL_OPENGL_ES3_BIT_KHR          = 0x0040;
     public static final int EGL_RECORDABLE_ANDROID          = 0x3142;
 
+    // EGL_ANDROID_native_fence_sync
+    public static final int EGL_SYNC_NATIVE_FENCE_ANDROID     = 0x3144;
+    public static final int EGL_SYNC_NATIVE_FENCE_FD_ANDROID  = 0x3145;
+    public static final int EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID = 0x3146;
+    public static final int EGL_NO_NATIVE_FENCE_FD_ANDROID    = -1;
+
     native private static void _nativeClassInit();
     static {
         _nativeClassInit();
@@ -43,4 +54,33 @@
         long time
     );
 
+    /**
+     * Retrieves the SyncFence for an EGLSync created with EGL_SYNC_NATIVE_FENCE_ANDROID
+     *
+     * See <a href="https://www.khronos.org/registry/EGL/extensions/ANDROID/EGL_ANDROID_native_fence_sync.txt">
+     *     EGL_ANDROID_native_fence_sync</a> extension for more details
+     * @param display The EGLDisplay connection
+     * @param sync The EGLSync to fetch the SyncFence from
+     * @return A SyncFence representing the native fence.
+     *       * If <sync> is not a valid sync object for <display>,
+     *         an {@link SyncFence#isValid() invalid} SyncFence is returned and an EGL_BAD_PARAMETER
+     *         error is generated.
+     *       * If the EGL_SYNC_NATIVE_FENCE_FD_ANDROID attribute of <sync> is
+     *         EGL_NO_NATIVE_FENCE_FD_ANDROID, an {@link SyncFence#isValid() invalid} SyncFence is
+     *         returned and an EGL_BAD_PARAMETER error is generated.
+     *       * If <display> does not match the display passed to eglCreateSync
+     *         when <sync> was created, the behaviour is undefined.
+     */
+    public static @NonNull SyncFence eglDupNativeFenceFDANDROID(@NonNull EGLDisplay display,
+            @NonNull EGLSync sync) {
+        int fd = eglDupNativeFenceFDANDROIDImpl(display, sync);
+        Log.d("EGL", "eglDupNativeFence returned " + fd);
+        if (fd >= 0) {
+            return SyncFence.create(ParcelFileDescriptor.adoptFd(fd));
+        } else {
+            return SyncFence.createEmpty();
+        }
+    }
+
+    private static native int eglDupNativeFenceFDANDROIDImpl(EGLDisplay display, EGLSync sync);
 }
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 9d3fc7f..16e851b 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -51,6 +51,8 @@
 
 import androidx.appcompat.app.AppCompatActivity;
 
+import java.util.List;
+
 /**
  *  A CompanionDevice activity response for showing the available
  *  nearby devices to be associated with.
@@ -204,10 +206,7 @@
         if (mRequest.isSelfManaged()) {
             initUiForSelfManagedAssociation(appLabel);
         } else if (mRequest.isSingleDevice()) {
-            // TODO(b/211722613)
-            // Treat singleDevice as the multipleDevices for now
-            // initUiForSingleDevice(appLabel);
-            initUiForMultipleDevices(appLabel);
+            initUiForSingleDevice(appLabel);
         } else {
             initUiForMultipleDevices(appLabel);
         }
@@ -221,12 +220,6 @@
     }
 
     private void onUserSelectedDevice(@NonNull DeviceFilterPair<?> selectedDevice) {
-        if (mSelectedDevice != null) {
-            if (DEBUG) Log.w(TAG, "Already selected.");
-            return;
-        }
-        mSelectedDevice = requireNonNull(selectedDevice);
-
         final MacAddress macAddress = selectedDevice.getMacAddress();
         onAssociationApproved(macAddress);
     }
@@ -346,13 +339,26 @@
     private void initUiForSingleDevice(CharSequence appLabel) {
         if (DEBUG) Log.i(TAG, "initUiFor_SingleDevice()");
 
-        // TODO: use real name
-        final String deviceName = "<device>";
         final String deviceProfile = mRequest.getDeviceProfile();
 
+        CompanionDeviceDiscoveryService.getScanResult().observe(this,
+                deviceFilterPairs -> updateSingleDeviceUi(
+                        deviceFilterPairs, deviceProfile, appLabel));
+
+        mListView.setVisibility(View.GONE);
+    }
+
+    private void updateSingleDeviceUi(List<DeviceFilterPair<?>> deviceFilterPairs,
+            String deviceProfile, CharSequence appLabel) {
+        // Ignore "empty" scan repots.
+        if (deviceFilterPairs.isEmpty()) return;
+        mSelectedDevice = requireNonNull(deviceFilterPairs.get(0));
+
+        final String deviceName = mSelectedDevice.getDisplayName();
         final Spanned title = getHtmlFromResources(
                 this, R.string.confirmation_title, appLabel, deviceName);
         final Spanned summary;
+
         if (deviceProfile == null) {
             summary = getHtmlFromResources(this, R.string.summary_generic);
         } else if (deviceProfile.equals(DEVICE_PROFILE_WATCH)) {
@@ -363,8 +369,6 @@
 
         mTitle.setText(title);
         mSummary.setText(summary);
-
-        mListView.setVisibility(View.GONE);
     }
 
     private void initUiForMultipleDevices(CharSequence appLabel) {
@@ -405,6 +409,14 @@
         if (DEBUG) Log.d(TAG, "onListItemClick() " + position);
 
         final DeviceFilterPair<?> selectedDevice = mAdapter.getItem(position);
+
+        if (mSelectedDevice != null) {
+            if (DEBUG) Log.w(TAG, "Already selected.");
+            return;
+        }
+
+        mSelectedDevice = requireNonNull(selectedDevice);
+
         onUserSelectedDevice(selectedDevice);
     }
 
@@ -417,9 +429,7 @@
         if (mRequest.isSelfManaged()) {
             onAssociationApproved(null);
         } else {
-            // TODO(b/211722613): call onUserSelectedDevice().
-            throw new UnsupportedOperationException(
-                    "isSingleDevice() requests are not supported yet.");
+            onUserSelectedDevice(mSelectedDevice);
         }
     }
 
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index 5d48708..5f07fcf 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -103,6 +103,8 @@
 
     private final Runnable mTimeoutRunnable = this::timeout;
 
+    private boolean mStopAfterFirstMatch;;
+
     /**
      * A state enum for devices' discovery.
      */
@@ -163,8 +165,7 @@
                 break;
 
             case ACTION_STOP_DISCOVERY:
-                stopDiscoveryAndFinish();
-                sStateLiveData.setValue(DiscoveryState.FINISHED_STOPPED);
+                stopDiscoveryAndFinish(/* timeout */ false);
                 break;
         }
         return START_NOT_STICKY;
@@ -182,6 +183,7 @@
         requireNonNull(request);
 
         if (mDiscoveryStarted) throw new RuntimeException("Discovery in progress.");
+        mStopAfterFirstMatch = request.isSingleDevice();
         mDiscoveryStarted = true;
         sStateLiveData.setValue(DiscoveryState.DISCOVERY_IN_PROGRESS);
         sScanResultsLiveData.setValue(Collections.emptyList());
@@ -208,7 +210,7 @@
     }
 
     @MainThread
-    private void stopDiscoveryAndFinish() {
+    private void stopDiscoveryAndFinish(boolean timeout) {
         if (DEBUG) Log.i(TAG, "stopDiscovery()");
 
         if (!mDiscoveryStarted) {
@@ -243,6 +245,12 @@
 
         Handler.getMain().removeCallbacks(mTimeoutRunnable);
 
+        if (timeout) {
+            sStateLiveData.setValue(DiscoveryState.FINISHED_TIMEOUT);
+        } else {
+            sStateLiveData.setValue(DiscoveryState.FINISHED_STOPPED);
+        }
+
         // "Finish".
         stopSelf();
     }
@@ -332,6 +340,7 @@
     private void onDeviceFound(@NonNull DeviceFilterPair<?> device) {
         runOnMainThread(() -> {
             if (DEBUG) Log.v(TAG, "onDeviceFound() " + device);
+            if (mDiscoveryStopped) return;
             if (mDevicesFound.contains(device)) {
                 // TODO: update the device instead of ignoring (new found device may contain
                 //  additional/updated info, eg. name of the device).
@@ -347,6 +356,10 @@
             mDevicesFound.add(device);
             // Then: notify observers.
             sScanResultsLiveData.setValue(mDevicesFound);
+            // Stop discovery when there's one device found for singleDevice.
+            if (mStopAfterFirstMatch) {
+                stopDiscoveryAndFinish(/* timeout */ false);
+            }
         });
     }
 
@@ -378,8 +391,7 @@
 
     private void timeout() {
         if (DEBUG) Log.i(TAG, "timeout()");
-        stopDiscoveryAndFinish();
-        sStateLiveData.setValue(DiscoveryState.FINISHED_TIMEOUT);
+        stopDiscoveryAndFinish(/* timeout */ true);
     }
 
     @Override
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
index 30748e6..d2a4de4 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
@@ -50,7 +50,7 @@
             android:tint="?android:attr/colorAccent"
             android:layout_gravity="center_vertical"
             android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
-            android:src="@android:drawable/ic_info"
+            android:src="@drawable/settingslib_ic_info"
             android:visibility="gone" />
 
         <Switch
diff --git a/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml b/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml
index 923d022..52d7775 100644
--- a/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml
+++ b/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml
@@ -34,14 +34,4 @@
         android:textAppearance="?android:attr/textAppearanceListItemSmall"
         android:textColor="?android:attr/textColorAlertDialogListItem" />
 
-    <ImageView
-        android:id="@+id/restricted_icon"
-        android:layout_width="@*android:dimen/config_restrictedIconSize"
-        android:layout_height="@*android:dimen/config_restrictedIconSize"
-        android:layout_alignParentRight="true"
-        android:scaleType="centerInside"
-        android:src="@*android:drawable/ic_info"
-        android:tint="?android:attr/colorAccent"
-        android:visibility="gone" />
-
 </RelativeLayout>
diff --git a/packages/SettingsLib/res/layout/restricted_preference_widget_primary_switch.xml b/packages/SettingsLib/res/layout/restricted_preference_widget_primary_switch.xml
deleted file mode 100644
index 69df751..0000000
--- a/packages/SettingsLib/res/layout/restricted_preference_widget_primary_switch.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <include layout="@layout/restricted_icon"/>
-
-    <include layout="@layout/preference_widget_primary_switch"/>
-</merge>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/restricted_switch_widget.xml b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
deleted file mode 100644
index 1520ac8..0000000
--- a/packages/SettingsLib/res/layout/restricted_switch_widget.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@+id/restricted_icon"
-        android:layout_width="@dimen/two_target_min_width"
-        android:layout_height="@*android:dimen/config_restrictedIconSize"
-        android:tint="?android:attr/colorAccent"
-        android:src="@*android:drawable/ic_info"
-        android:gravity="center" />
-    <!-- Based off frameworks/base/core/res/res/layout/preference_widget_switch.xml -->
-    <Switch xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@android:id/switch_widget"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:focusable="false"
-        android:clickable="false"
-        android:background="@null" />
-</merge>
diff --git a/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
index 246fc8dd..b43b444 100644
--- a/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/PrimarySwitchPreference.java
@@ -59,7 +59,7 @@
 
     @Override
     protected int getSecondTargetResId() {
-        return R.layout.restricted_preference_widget_primary_switch;
+        return R.layout.preference_widget_primary_switch;
     }
 
     @Override
@@ -67,7 +67,6 @@
         super.onBindViewHolder(holder);
         final View switchWidget = holder.findViewById(R.id.switchWidget);
         if (switchWidget != null) {
-            switchWidget.setVisibility(isDisabledByAdmin() ? View.GONE : View.VISIBLE);
             switchWidget.setOnClickListener(new OnClickListener() {
                 @Override
                 public void onClick(View v) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
index 81146fa..db2a6ec 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
@@ -22,7 +22,6 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.util.AttributeSet;
-import android.view.View;
 
 import androidx.core.content.res.TypedArrayUtils;
 import androidx.preference.PreferenceManager;
@@ -67,23 +66,9 @@
     }
 
     @Override
-    protected int getSecondTargetResId() {
-        return R.layout.restricted_icon;
-    }
-
-    @Override
-    protected boolean shouldHideSecondTarget() {
-        return !isDisabledByAdmin();
-    }
-
-    @Override
     public void onBindViewHolder(PreferenceViewHolder holder) {
         super.onBindViewHolder(holder);
         mHelper.onBindViewHolder(holder);
-        final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
-        if (restrictedIcon != null) {
-            restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
-        }
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index 342189d..c607d74 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -46,7 +46,6 @@
     public RestrictedSwitchPreference(Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        setWidgetLayoutResource(R.layout.restricted_switch_widget);
         mHelper = new RestrictedPreferenceHelper(context, this, attrs);
         if (attrs != null) {
             final TypedArray attributes = context.obtainStyledAttributes(attrs,
@@ -108,15 +107,6 @@
             switchSummary = mRestrictedSwitchSummary;
         }
 
-        final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
-        final View switchWidget = holder.findViewById(android.R.id.switch_widget);
-        if (restrictedIcon != null) {
-            restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
-        }
-        if (switchWidget != null) {
-            switchWidget.setVisibility(isDisabledByAdmin() ? View.GONE : View.VISIBLE);
-        }
-
         final ImageView icon = holder.itemView.findViewById(android.R.id.icon);
 
         if (mIconSize > 0) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java b/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
index afd3626..fc38ada 100644
--- a/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
@@ -22,6 +22,7 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.os.Handler;
 import android.os.UserHandle;
@@ -33,7 +34,10 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -48,11 +52,12 @@
     private static DeviceStateRotationLockSettingsManager sSingleton;
 
     private final ContentResolver mContentResolver;
-    private final String[] mDeviceStateRotationLockDefaults;
     private final Handler mMainHandler = Handler.getMain();
     private final Set<DeviceStateRotationLockSettingsListener> mListeners = new HashSet<>();
+    private String[] mDeviceStateRotationLockDefaults;
     private SparseIntArray mDeviceStateRotationLockSettings;
     private SparseIntArray mDeviceStateRotationLockFallbackSettings;
+    private List<SettableDeviceState> mSettableDeviceStates;
 
     private DeviceStateRotationLockSettingsManager(Context context) {
         mContentResolver = context.getContentResolver();
@@ -73,6 +78,12 @@
         return sSingleton;
     }
 
+    /** Resets the singleton instance of this class. Only used for testing. */
+    @VisibleForTesting
+    public static synchronized void resetInstance() {
+        sSingleton = null;
+    }
+
     /** Returns true if device-state based rotation lock settings are enabled. */
     public static boolean isDeviceStateRotationLockEnabled(Context context) {
         return context.getResources()
@@ -180,6 +191,12 @@
         return true;
     }
 
+    /** Returns a list of device states and their respective auto-rotation setting availability. */
+    public List<SettableDeviceState> getSettableDeviceStates() {
+        // Returning a copy to make sure that nothing outside can mutate our internal list.
+        return new ArrayList<>(mSettableDeviceStates);
+    }
+
     private void initializeInMemoryMap() {
         String serializedSetting =
                 Settings.Secure.getStringForUser(
@@ -215,6 +232,17 @@
         }
     }
 
+    /**
+     * Resets the state of the class and saved settings back to the default values provided by the
+     * resources config.
+     */
+    @VisibleForTesting
+    public void resetStateForTesting(Resources resources) {
+        mDeviceStateRotationLockDefaults =
+                resources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
+        fallbackOnDefaults();
+    }
+
     private void fallbackOnDefaults() {
         loadDefaults();
         persistSettings();
@@ -251,6 +279,7 @@
     }
 
     private void loadDefaults() {
+        mSettableDeviceStates = new ArrayList<>(mDeviceStateRotationLockDefaults.length);
         mDeviceStateRotationLockSettings = new SparseIntArray(
                 mDeviceStateRotationLockDefaults.length);
         mDeviceStateRotationLockFallbackSettings = new SparseIntArray(1);
@@ -271,6 +300,8 @@
                                         + values.length);
                     }
                 }
+                boolean isSettable = rotationLockSetting != DEVICE_STATE_ROTATION_LOCK_IGNORED;
+                mSettableDeviceStates.add(new SettableDeviceState(deviceState, isSettable));
                 mDeviceStateRotationLockSettings.put(deviceState, rotationLockSetting);
             } catch (NumberFormatException e) {
                 Log.wtf(TAG, "Error parsing settings entry. Entry was: " + entry, e);
@@ -300,4 +331,38 @@
         /** Called whenever the settings have changed. */
         void onSettingsChanged();
     }
+
+    /** Represents a device state and whether it has an auto-rotation setting. */
+    public static class SettableDeviceState {
+        private final int mDeviceState;
+        private final boolean mIsSettable;
+
+        SettableDeviceState(int deviceState, boolean isSettable) {
+            mDeviceState = deviceState;
+            mIsSettable = isSettable;
+        }
+
+        /** Returns the device state associated with this object. */
+        public int getDeviceState() {
+            return mDeviceState;
+        }
+
+        /** Returns whether there is an auto-rotation setting for this device state. */
+        public boolean isSettable() {
+            return mIsSettable;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof SettableDeviceState)) return false;
+            SettableDeviceState that = (SettableDeviceState) o;
+            return mDeviceState == that.mDeviceState && mIsSettable == that.mIsSettable;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mDeviceState, mIsSettable);
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index bd3deae..fcb56d2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -50,7 +50,6 @@
 public class DreamBackend {
     private static final String TAG = "DreamBackend";
     private static final boolean DEBUG = false;
-    private final Drawable mDreamPreviewDefault;
 
     public static class DreamInfo {
         public CharSequence caption;
@@ -135,8 +134,6 @@
                 com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
         mDreamsActivatedOnDockByDefault = resources.getBoolean(
                 com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
-        mDreamPreviewDefault = resources.getDrawable(
-                com.android.internal.R.drawable.default_dream_preview);
         mDisabledDreams = Arrays.stream(resources.getStringArray(
                         com.android.internal.R.array.config_disabledDreamComponents))
                 .map(ComponentName::unflattenFromString)
@@ -182,9 +179,6 @@
                 dreamInfo.settingsComponentName = dreamMetadata.settingsActivity;
                 dreamInfo.previewImage = dreamMetadata.previewImage;
             }
-            if (dreamInfo.previewImage == null) {
-                dreamInfo.previewImage = mDreamPreviewDefault;
-            }
             dreamInfos.add(dreamInfo);
         }
         dreamInfos.sort(mComparator);
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
new file mode 100644
index 0000000..8d687b6
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.settingslib.devicestate;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.R;
+import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager.SettableDeviceState;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DeviceStateRotationLockSettingsManagerTest {
+
+    @Mock private Context mMockContext;
+    @Mock private Resources mMockResources;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        Context context = InstrumentationRegistry.getTargetContext();
+        when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
+        when(mMockContext.getResources()).thenReturn(mMockResources);
+        when(mMockContext.getContentResolver()).thenReturn(context.getContentResolver());
+    }
+
+    @Test
+    public void getSettableDeviceStates_returnsExpectedValuesInOriginalOrder() {
+        when(mMockResources.getStringArray(
+                R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
+                new String[]{"2:2", "4:0", "1:1", "0:0"});
+
+        List<SettableDeviceState> settableDeviceStates =
+                DeviceStateRotationLockSettingsManager.getInstance(
+                        mMockContext).getSettableDeviceStates();
+
+        assertThat(settableDeviceStates).containsExactly(
+                new SettableDeviceState(/* deviceState= */ 2, /* isSettable= */ true),
+                new SettableDeviceState(/* deviceState= */ 4, /* isSettable= */ false),
+                new SettableDeviceState(/* deviceState= */ 1, /* isSettable= */ true),
+                new SettableDeviceState(/* deviceState= */ 0, /* isSettable= */ false)
+        ).inOrder();
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
index 4e2b63b..9c16740 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/PrimarySwitchPreferenceTest.java
@@ -53,13 +53,7 @@
         mHolder = PreferenceViewHolder.createInstanceForTests(inflater.inflate(
                 com.android.settingslib.R.layout.preference_two_target, null));
         mWidgetView = mHolder.itemView.findViewById(android.R.id.widget_frame);
-        inflater.inflate(R.layout.restricted_preference_widget_primary_switch, mWidgetView, true);
-    }
-
-    @Test
-    public void createNewPreference_shouldSetLayout() {
-        assertThat(mPreference.getWidgetLayoutResource())
-                .isEqualTo(R.layout.restricted_preference_widget_primary_switch);
+        inflater.inflate(R.layout.preference_widget_primary_switch, mWidgetView, true);
     }
 
     @Test
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 7381e05..a2b6992 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -696,6 +696,14 @@
                 Settings.Global.MAX_ERROR_BYTES_PREFIX,
                 GlobalSettingsProto.MAX_ERROR_BYTES);
 
+        final long managedDeviceProvisioningToken =
+                p.start(GlobalSettingsProto.MANAGED_DEVICE_PROVISIONING);
+        dumpSetting(s, p,
+                Settings.Global.MANAGED_PROVISIONING_DEFER_PROVISIONING_TO_ROLE_HOLDER,
+                GlobalSettingsProto.ManagedDeviceProvisioning
+                        .MANAGED_PROVISIONING_DEFER_PROVISIONING_TO_ROLE_HOLDER);
+        p.end(managedDeviceProvisioningToken);
+
         final long euiccToken = p.start(GlobalSettingsProto.EUICC);
         dumpSetting(s, p,
                 Settings.Global.EUICC_PROVISIONED,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 2905429..3f4372b 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -594,6 +594,7 @@
                     Settings.Global.KEY_CHORD_POWER_VOLUME_UP,
                     Settings.Global.CLOCKWORK_HOME_READY,
                     Settings.Global.WATCHDOG_TIMEOUT_MILLIS,
+                    Settings.Global.MANAGED_PROVISIONING_DEFER_PROVISIONING_TO_ROLE_HOLDER,
                     Settings.Global.Wearable.BATTERY_SAVER_MODE,
                     Settings.Global.Wearable.COMBINED_LOCATION_ENABLED,
                     Settings.Global.Wearable.HAS_PAY_TOKENS,
diff --git a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
index ffee894..d4b4a74 100644
--- a/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
+++ b/packages/SystemUI/plugin/bcsmartspace/src/com/android/systemui/plugins/BcSmartspaceDataPlugin.java
@@ -20,7 +20,7 @@
 import android.app.smartspace.SmartspaceAction;
 import android.app.smartspace.SmartspaceTarget;
 import android.app.smartspace.SmartspaceTargetEvent;
-import android.app.smartspace.uitemplatedata.SmartspaceTapAction;
+import android.app.smartspace.uitemplatedata.TapAction;
 import android.content.ActivityNotFoundException;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
@@ -144,7 +144,7 @@
             }
         }
 
-        default void startFromAction(SmartspaceTapAction action, View v, boolean showOnLockscreen) {
+        default void startFromAction(TapAction action, View v, boolean showOnLockscreen) {
             try {
                 if (action.getIntent() != null) {
                     startIntent(v, action.getIntent(), showOnLockscreen);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
index 757ed76..b33c544 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/DarkIconDispatcher.java
@@ -91,6 +91,9 @@
      *         areas, false otherwise
      */
     static boolean isInAreas(ArrayList<Rect> areas, View view) {
+        if (areas.isEmpty()) {
+            return true;
+        }
         for (Rect area : areas) {
             if (isInArea(area, view)) {
                 return true;
diff --git a/packages/SystemUI/res-keyguard/layout/footer_actions.xml b/packages/SystemUI/res-keyguard/layout/footer_actions.xml
index 339cab4..fb401ee 100644
--- a/packages/SystemUI/res-keyguard/layout/footer_actions.xml
+++ b/packages/SystemUI/res-keyguard/layout/footer_actions.xml
@@ -77,16 +77,6 @@
             android:src="@drawable/ic_settings"
             android:tint="?android:attr/textColorPrimary" />
 
-        <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:id="@+id/tuner_icon"
-            android:layout_width="8dp"
-            android:layout_height="8dp"
-            android:layout_gravity="center_horizontal|bottom"
-            android:layout_marginBottom="@dimen/qs_footer_icon_padding"
-            android:src="@drawable/tuner"
-            android:tint="?android:attr/textColorTertiary"
-            android:visibility="invisible" />
-
     </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
 
 </com.android.systemui.qs.FooterActionsView>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/layout/new_footer_actions.xml b/packages/SystemUI/res-keyguard/layout/new_footer_actions.xml
index 4884df7..59712c0 100644
--- a/packages/SystemUI/res-keyguard/layout/new_footer_actions.xml
+++ b/packages/SystemUI/res-keyguard/layout/new_footer_actions.xml
@@ -78,16 +78,6 @@
                 android:src="@drawable/ic_settings"
                 android:tint="?android:attr/textColorPrimary" />
 
-            <com.android.systemui.statusbar.AlphaOptimizedImageView
-                android:id="@+id/tuner_icon"
-                android:layout_width="8dp"
-                android:layout_height="8dp"
-                android:layout_gravity="center_horizontal|bottom"
-                android:layout_marginBottom="@dimen/qs_footer_icon_padding"
-                android:src="@drawable/tuner"
-                android:tint="?android:attr/textColorTertiary"
-                android:visibility="invisible" />
-
         </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
 
         <com.android.systemui.statusbar.AlphaOptimizedImageView
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
index 4824f4c..e066d38 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
@@ -20,6 +20,7 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:fontFamily="@font/clock"
+    android:includeFontPadding="false"
     android:textColor="@android:color/white"
     android:format12Hour="h:mm"
     android:format24Hour="kk:mm"
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index bc366ab..5c9f5db 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -20,6 +20,7 @@
 
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
@@ -101,6 +102,8 @@
                 return R.string.kg_prompt_reason_user_request;
             case PROMPT_REASON_PREPARE_FOR_UPDATE:
                 return R.string.kg_prompt_reason_timeout_password;
+            case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
+                return R.string.kg_prompt_reason_timeout_password;
             case PROMPT_REASON_NONE:
                 return 0;
             default:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 0b4bc9e..41f9240 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -327,6 +327,9 @@
             case PROMPT_REASON_PREPARE_FOR_UPDATE:
                 mMessageAreaController.setMessage(R.string.kg_prompt_reason_timeout_pattern);
                 break;
+            case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
+                mMessageAreaController.setMessage(R.string.kg_prompt_reason_timeout_pattern);
+                break;
             case PROMPT_REASON_NONE:
                 break;
             default:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 0b8868f..4723af2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -18,6 +18,7 @@
 
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_DEVICE_ADMIN;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NONE;
+import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
@@ -113,6 +114,8 @@
                 return R.string.kg_prompt_reason_user_request;
             case PROMPT_REASON_PREPARE_FOR_UPDATE:
                 return R.string.kg_prompt_reason_timeout_pin;
+            case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
+                return R.string.kg_prompt_reason_timeout_pin;
             case PROMPT_REASON_NONE:
                 return 0;
             default:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 99e0ec1..37f4564 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2027,6 +2027,7 @@
         mAuthController.addCallback(new AuthController.Callback() {
             @Override
             public void onAllAuthenticatorsRegistered() {
+                mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE));
             }
 
             @Override
@@ -2156,6 +2157,10 @@
             return;
         }
 
+        // don't start running fingerprint until they're registered
+        if (!mAuthController.areAllAuthenticatorsRegistered()) {
+            return;
+        }
         final boolean shouldListenForFingerprint = shouldListenForFingerprint(isUdfpsSupported());
         final boolean runningOrRestarting = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING
                 || mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING;
@@ -3523,6 +3528,8 @@
             final int strongAuthFlags = mStrongAuthTracker.getStrongAuthForUser(userId);
             BiometricAuthenticated fingerprint = mUserFingerprintAuthenticated.get(userId);
             pw.println("  Fingerprint state (user=" + userId + ")");
+            pw.println("    areAllAuthenticatorsRegistered="
+                    + mAuthController.areAllAuthenticatorsRegistered());
             pw.println("    allowed="
                     + (fingerprint != null
                             && isUnlockingWithBiometricAllowed(fingerprint.mIsStrongBiometric)));
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index fe5e36e..dfb8c18 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -136,6 +136,7 @@
     @NonNull private final SparseBooleanArray mUdfpsEnrolledForUser;
     @NonNull private final SensorPrivacyManager mSensorPrivacyManager;
     private final WakefulnessLifecycle mWakefulnessLifecycle;
+    private boolean mAllAuthenticatorsRegistered;
 
     private class BiometricTaskStackListener extends TaskStackListener {
         @Override
@@ -226,6 +227,13 @@
         }
     }
 
+    /**
+     * Whether all authentictors have been registered.
+     */
+    public boolean areAllAuthenticatorsRegistered() {
+        return mAllAuthenticatorsRegistered;
+    }
+
     private void handleAllAuthenticatorsRegistered(
             List<FingerprintSensorPropertiesInternal> sensors) {
         mExecution.assertIsMainThread();
@@ -233,6 +241,7 @@
             Log.d(TAG, "handleAllAuthenticatorsRegistered | sensors: " + Arrays.toString(
                     sensors.toArray()));
         }
+        mAllAuthenticatorsRegistered = true;
         mFpProps = sensors;
         List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>();
         List<FingerprintSensorPropertiesInternal> sidefpsProps = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index 40689ee..a17ddc8 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -151,11 +151,7 @@
         mWindow = FloatingWindowUtil.getFloatingWindow(mContext);
         mWindow.setWindowManager(mWindowManager, null, null);
 
-        if (!mAccessibilityManager.isTouchExplorationEnabled()) {
-            setWindowFocusable(true);
-        } else {
-            setWindowFocusable(false);
-        }
+        setWindowFocusable(false);
 
         mContainer = (FrameLayout)
                 LayoutInflater.from(mContext).inflate(R.layout.clipboard_overlay, null);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index b96c5ae..13067bf 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -42,6 +42,7 @@
 import com.android.systemui.flags.FlagsModule;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.log.dagger.LogModule;
+import com.android.systemui.lowlightclock.LowLightClockController;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.BcSmartspaceDataPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -86,6 +87,7 @@
 import com.android.systemui.wallet.dagger.WalletModule;
 import com.android.systemui.wmshell.BubblesManager;
 import com.android.wm.shell.bubbles.Bubbles;
+import com.android.wm.shell.dagger.DynamicOverride;
 
 import java.util.Optional;
 import java.util.concurrent.Executor;
@@ -214,4 +216,19 @@
                 groupManager, entryManager, notifCollection, notifPipeline, sysUiState,
                 notifPipelineFlags, dumpManager, sysuiMainExecutor));
     }
+
+    @BindsOptionalOf
+    @DynamicOverride
+    abstract LowLightClockController optionalLowLightClockController();
+
+    @SysUISingleton
+    @Provides
+    static Optional<LowLightClockController> provideLowLightClockController(
+            @DynamicOverride Optional<LowLightClockController> optionalController) {
+        if (optionalController.isPresent() && optionalController.get().isLowLightClockEnabled()) {
+            return optionalController;
+        } else {
+            return Optional.empty();
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 239109a..c8720e4 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -288,7 +288,7 @@
         for (TriggerSensor triggerSensor : mTriggerSensors) {
             triggerSensor.setListening(false);
         }
-        mProximitySensor.pause();
+        mProximitySensor.destroy();
 
         mDevicePostureController.removeCallback(mDevicePostureCallback);
         mAuthController.removeCallback(mAuthControllerCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 68b74bd..8bff3ba 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -228,6 +228,7 @@
     @Override
     public void destroy() {
         mDozeSensors.destroy();
+        mProxCheck.destroy();
     }
 
     private void onNotification(Runnable onPulseSuppressedListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
index f3b721c..df60599 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
@@ -30,11 +30,13 @@
 import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.os.Bundle;
+import android.os.RemoteException;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.Dumpable;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -70,6 +72,7 @@
     private final Supplier<Map<Integer, Flag<?>>> mFlagsCollector;
     private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>();
     private final Map<Integer, String> mStringFlagCache = new TreeMap<>();
+    private final IStatusBarService mBarService;
 
     @Inject
     public FeatureFlagsDebug(
@@ -78,7 +81,8 @@
             SecureSettings secureSettings,
             @Main Resources resources,
             DumpManager dumpManager,
-            @Nullable Supplier<Map<Integer, Flag<?>>> flagsCollector) {
+            @Nullable Supplier<Map<Integer, Flag<?>>> flagsCollector,
+            IStatusBarService barService) {
         mFlagManager = flagManager;
         mSecureSettings = secureSettings;
         mResources = resources;
@@ -91,6 +95,7 @@
         context.registerReceiver(mReceiver, filter, null, null,
                 Context.RECEIVER_EXPORTED_UNAUDITED);
         dumpManager.registerDumpable(TAG, this);
+        mBarService = barService;
     }
 
     @Override
@@ -212,6 +217,14 @@
         System.exit(0);
     }
 
+    private void restartAndroid() {
+        Log.i(TAG, "Restarting Android");
+        try {
+            mBarService.restart();
+        } catch (RemoteException e) {
+        }
+    }
+
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 55e48a7..dd36fd6 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -111,7 +111,7 @@
     public static final ResourceBooleanFlag QS_USER_DETAIL_SHORTCUT =
             new ResourceBooleanFlag(503, R.bool.flag_lockscreen_qs_user_detail_shortcut);
 
-    public static final BooleanFlag NEW_FOOTER = new BooleanFlag(504, false);
+    public static final BooleanFlag NEW_FOOTER = new BooleanFlag(504, true);
 
     public static final BooleanFlag NEW_HEADER = new BooleanFlag(505, false);
     public static final ResourceBooleanFlag FULL_SCREEN_USER_SWITCHER =
diff --git a/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightClockController.java b/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightClockController.java
new file mode 100644
index 0000000..0b15f4f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightClockController.java
@@ -0,0 +1,48 @@
+/*
+ * 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.lowlightclock;
+
+import android.view.ViewGroup;
+
+/**
+ * A controller responsible for attaching and showing an optional low-light clock while dozing.
+ */
+public interface LowLightClockController {
+    /**
+     * Returns {@code true} if the low-light clock is enabled.
+     */
+    boolean isLowLightClockEnabled();
+
+    /**
+     * Attach the low light-clock to the given parent {@link ViewGroup}.
+     * @param parent The parent {@link ViewGroup} to which the low-light clock view should be
+     *               attached.
+     */
+    void attachLowLightClockView(ViewGroup parent);
+
+    /**
+     * Show or hide the low-light clock.
+     * @param show Whether to show the low-light clock.
+     * @return {@code true} if the low-light clock was shown.
+     */
+    boolean showLowLightClock(boolean show);
+
+    /**
+     * An opportunity to perform burn-in prevention.
+     */
+    void dozeTimeTick();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index 6145f0f..eee3955 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -28,6 +28,7 @@
 import android.view.ViewGroup
 import android.view.ViewGroupOverlay
 import androidx.annotation.VisibleForTesting
+import com.android.keyguard.KeyguardViewController
 import com.android.systemui.R
 import com.android.systemui.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
@@ -40,7 +41,6 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator
 import com.android.systemui.statusbar.phone.KeyguardBypassController
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.Utils
@@ -83,7 +83,7 @@
     private val notifLockscreenUserManager: NotificationLockscreenUserManager,
     configurationController: ConfigurationController,
     wakefulnessLifecycle: WakefulnessLifecycle,
-    private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
+    private val keyguardViewController: KeyguardViewController,
     private val dreamOverlayStateController: DreamOverlayStateController
 ) {
 
@@ -1016,7 +1016,7 @@
 
     private fun isLockScreenVisibleToUser(): Boolean {
         return !statusBarStateController.isDozing &&
-                !statusBarKeyguardViewManager.isBouncerShowing &&
+                !keyguardViewController.isBouncerShowing &&
                 statusBarStateController.state == StatusBarState.KEYGUARD &&
                 notifLockscreenUserManager.shouldShowLockscreenNotifications() &&
                 statusBarStateController.isExpanded &&
@@ -1025,7 +1025,7 @@
 
     private fun isLockScreenShadeVisibleToUser(): Boolean {
         return !statusBarStateController.isDozing &&
-                !statusBarKeyguardViewManager.isBouncerShowing &&
+                !keyguardViewController.isBouncerShowing &&
                 (statusBarStateController.state == StatusBarState.SHADE_LOCKED ||
                         (statusBarStateController.state == StatusBarState.KEYGUARD && qsExpanded))
     }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 593b278c..6ea7aec 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -125,6 +125,7 @@
     int mDisabledFlags = 0;
     int mNavigationIconHints = 0;
     private int mNavBarMode;
+    private boolean mImeDrawsImeNavBar;
 
     private final Region mTmpRegion = new Region();
     private final int[] mTmpPosition = new int[2];
@@ -324,6 +325,7 @@
         mIsVertical = false;
         mLongClickableAccessibilityButton = false;
         mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this);
+        mImeDrawsImeNavBar = Dependency.get(NavigationModeController.class).getImeDrawsImeNavBar();
 
         mSysUiFlagContainer = Dependency.get(SysUiState.class);
         // Set up the context group of buttons
@@ -773,7 +775,7 @@
 
         updateRecentsIcon();
 
-        boolean isImeRenderingNavButtons = isGesturalMode(mNavBarMode)
+        boolean isImeRenderingNavButtons = mImeDrawsImeNavBar
                 && mImeCanRenderGesturalNavButtons
                 && (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0;
 
@@ -966,6 +968,7 @@
     @Override
     public void onNavigationModeChanged(int mode) {
         mNavBarMode = mode;
+        mImeDrawsImeNavBar = Dependency.get(NavigationModeController.class).getImeDrawsImeNavBar();
         mBarTransitions.onNavigationModeChanged(mNavBarMode);
         mEdgeBackGestureHandler.onNavigationModeChanged(mNavBarMode);
         updateRotationButton();
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
index 73a0c54..6920ffb 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationModeController.java
@@ -156,6 +156,11 @@
         mListeners.remove(listener);
     }
 
+    public boolean getImeDrawsImeNavBar() {
+        return mCurrentUserContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_imeDrawsImeNavBar);
+    }
+
     private int getCurrentInteractionMode(Context context) {
         int mode = context.getResources().getInteger(
                 com.android.internal.R.integer.config_navBarInteractionMode);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
index 5df8b80..a262b8a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
@@ -24,7 +24,6 @@
 import android.view.View
 import android.view.ViewGroup
 import android.widget.LinearLayout
-import android.widget.Toast
 import androidx.annotation.VisibleForTesting
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.logging.MetricsLogger
@@ -46,7 +45,6 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.statusbar.policy.UserInfoController
 import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener
-import com.android.systemui.tuner.TunerService
 import com.android.systemui.util.DualHeightHorizontalLinearLayout
 import com.android.systemui.util.ViewController
 import com.android.systemui.util.settings.GlobalSettings
@@ -71,7 +69,6 @@
     private val fgsManagerFooterController: QSFgsManagerFooter,
     private val falsingManager: FalsingManager,
     private val metricsLogger: MetricsLogger,
-    private val tunerService: TunerService,
     private val globalActionsDialog: GlobalActionsDialogLite,
     private val uiEventLogger: UiEventLogger,
     @Named(PM_LITE_ENABLED) private val showPMLiteButton: Boolean,
@@ -131,22 +128,7 @@
                 return@OnClickListener
             }
             metricsLogger.action(MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH)
-            if (settingsButton.isTunerClick) {
-                activityStarter.postQSRunnableDismissingKeyguard {
-                    if (isTunerEnabled()) {
-                        tunerService.showResetRequest {
-                            // Relaunch settings so that the tuner disappears.
-                            startSettingsActivity()
-                        }
-                    } else {
-                        Toast.makeText(context, R.string.tuner_toast, Toast.LENGTH_LONG).show()
-                        tunerService.isTunerEnabled = true
-                    }
-                    startSettingsActivity()
-                }
-            } else {
-                startSettingsActivity()
-            }
+            startSettingsActivity()
         } else if (v === powerMenuLite) {
             uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS)
             globalActionsDialog.showOrHideDialog(false, true, v)
@@ -228,7 +210,7 @@
     }
 
     private fun updateView() {
-        mView.updateEverything(isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled)
+        mView.updateEverything(multiUserSwitchController.isMultiUserEnabled)
     }
 
     override fun onViewDetached() {
@@ -254,7 +236,7 @@
     }
 
     fun disable(state2: Int) {
-        mView.disable(state2, isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled)
+        mView.disable(state2, multiUserSwitchController.isMultiUserEnabled)
     }
 
     fun setExpansion(headerExpansionFraction: Float) {
@@ -275,6 +257,4 @@
     fun setKeyguardShowing(showing: Boolean) {
         setExpansion(lastExpansion)
     }
-
-    private fun isTunerEnabled() = tunerService.isTunerEnabled
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
index 18e0cfa..9413a90 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
@@ -17,7 +17,6 @@
 
 import android.app.StatusBarManager
 import android.content.Context
-import android.content.res.Configuration
 import android.graphics.PorterDuff
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.RippleDrawable
@@ -42,7 +41,6 @@
     private lateinit var settingsButton: SettingsButton
     private lateinit var multiUserSwitch: MultiUserSwitch
     private lateinit var multiUserAvatar: ImageView
-    private lateinit var tunerIcon: View
 
     private var qsDisabled = false
     private var expansionAmount = 0f
@@ -53,50 +51,30 @@
         settingsContainer = findViewById(R.id.settings_button_container)
         multiUserSwitch = findViewById(R.id.multi_user_switch)
         multiUserAvatar = multiUserSwitch.findViewById(R.id.multi_user_avatar)
-        tunerIcon = requireViewById(R.id.tuner_icon)
 
         // RenderThread is doing more harm than good when touching the header (to expand quick
         // settings), so disable it for this view
         if (settingsButton.background is RippleDrawable) {
             (settingsButton.background as RippleDrawable).setForceSoftware(true)
         }
-        updateResources()
         importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES
     }
 
-    override fun onConfigurationChanged(newConfig: Configuration) {
-        super.onConfigurationChanged(newConfig)
-        updateResources()
-    }
-
-    override fun onRtlPropertiesChanged(layoutDirection: Int) {
-        super.onRtlPropertiesChanged(layoutDirection)
-        updateResources()
-    }
-
-    private fun updateResources() {
-        val tunerIconTranslation = mContext.resources
-                .getDimensionPixelOffset(R.dimen.qs_footer_tuner_icon_translation).toFloat()
-        tunerIcon.translationX = if (isLayoutRtl) (-tunerIconTranslation) else tunerIconTranslation
-    }
-
     fun disable(
         state2: Int,
-        isTunerEnabled: Boolean,
         multiUserEnabled: Boolean
     ) {
         val disabled = state2 and StatusBarManager.DISABLE2_QUICK_SETTINGS != 0
         if (disabled == qsDisabled) return
         qsDisabled = disabled
-        updateEverything(isTunerEnabled, multiUserEnabled)
+        updateEverything(multiUserEnabled)
     }
 
     fun updateEverything(
-        isTunerEnabled: Boolean,
         multiUserEnabled: Boolean
     ) {
         post {
-            updateVisibilities(isTunerEnabled, multiUserEnabled)
+            updateVisibilities(multiUserEnabled)
             updateClickabilities()
             isClickable = false
         }
@@ -108,11 +86,9 @@
     }
 
     private fun updateVisibilities(
-        isTunerEnabled: Boolean,
         multiUserEnabled: Boolean
     ) {
         settingsContainer.visibility = if (qsDisabled) GONE else VISIBLE
-        tunerIcon.visibility = if (isTunerEnabled) VISIBLE else INVISIBLE
         multiUserSwitch.visibility = if (multiUserEnabled) VISIBLE else GONE
         val isDemo = UserManager.isDeviceInDemoMode(context)
         settingsButton.visibility = if (isDemo) INVISIBLE else VISIBLE
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 72c4ce8..0fb6ea6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -427,15 +427,17 @@
                 typedValue, true);
         float scaleFactor = typedValue.getFloat();
 
-        // We downscale the loaded drawable to reasonable size to protect against applications
-        // using too much memory. The size can be tweaked in config.xml. Drawables
-        // that are already sized properly won't be touched.
-        boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
-        Resources res = sysuiContext.getResources();
-        int maxIconSize = res.getDimensionPixelSize(isLowRamDevice
-                                ? com.android.internal.R.dimen.notification_small_icon_size_low_ram
-                                : com.android.internal.R.dimen.notification_small_icon_size);
-        icon = DrawableSize.downscaleToSize(res, icon, maxIconSize, maxIconSize);
+        if (icon != null) {
+            // We downscale the loaded drawable to reasonable size to protect against applications
+            // using too much memory. The size can be tweaked in config.xml. Drawables that are
+            // already sized properly won't be touched.
+            boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
+            Resources res = sysuiContext.getResources();
+            int maxIconSize = res.getDimensionPixelSize(isLowRamDevice
+                    ? com.android.internal.R.dimen.notification_small_icon_size_low_ram
+                    : com.android.internal.R.dimen.notification_small_icon_size);
+            icon = DrawableSize.downscaleToSize(res, icon, maxIconSize, maxIconSize);
+        }
 
         // No need to scale the icon, so return it as is.
         if (scaleFactor == 1.f) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 7811401..fcbe179 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -507,6 +507,10 @@
         pw.println(" mLeaveOpenOnKeyguardHide=" + mLeaveOpenOnKeyguardHide);
         pw.println(" mKeyguardRequested=" + mKeyguardRequested);
         pw.println(" mIsDozing=" + mIsDozing);
+        pw.println(" mListeners{" + mListeners.size() + "}=");
+        for (RankedListener rl : mListeners) {
+            pw.println("    " + rl.mListener);
+        }
         pw.println(" Historical states:");
         // Ignore records without a timestamp
         int size = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index 60d1317..82b56cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -234,7 +234,7 @@
                 ApplicationInfo appInfo =
                         pm.getApplicationInfo(
                                 pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES, info.userId);
-                if (appInfo.isInstantApp()) {
+                if (appInfo != null && appInfo.isInstantApp()) {
                     postInstantAppNotif(
                             pkg,
                             info.userId,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index d610b37..b141110 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -309,7 +309,12 @@
      * delayed for a few seconds. This might be useful to play animations without reducing FPS.
      */
     public boolean shouldDelayDisplayDozeTransition() {
-        return mScreenOffAnimationController.shouldDelayDisplayDozeTransition();
+        return willAnimateFromLockScreenToAod()
+                || mScreenOffAnimationController.shouldDelayDisplayDozeTransition();
+    }
+
+    private boolean willAnimateFromLockScreenToAod() {
+        return getAlwaysOn() && mKeyguardShowing;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index b35e684..6d774838 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -214,6 +214,7 @@
         }
 
         mStatusBarStateController.setIsDozing(dozing);
+        mNotificationShadeWindowViewController.setDozing(dozing);
     }
 
     @Override
@@ -294,6 +295,7 @@
     public void dozeTimeTick() {
         mNotificationPanel.dozeTimeTick();
         mAuthController.dozeTimeTick();
+        mNotificationShadeWindowViewController.dozeTimeTick();
         if (mAmbientIndicationContainer instanceof DozeReceiver) {
             ((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index 4e2eb6a..396703b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -36,6 +36,7 @@
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.lowlightclock.LowLightClockController;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -49,6 +50,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Optional;
 
 import javax.inject.Inject;
 
@@ -84,6 +86,7 @@
     private final DockManager mDockManager;
     private final NotificationPanelViewController mNotificationPanelViewController;
     private final PanelExpansionStateManager mPanelExpansionStateManager;
+    private final Optional<LowLightClockController> mLowLightClockController;
 
     private boolean mIsTrackingBarGesture = false;
 
@@ -101,7 +104,8 @@
             NotificationStackScrollLayoutController notificationStackScrollLayoutController,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             StatusBarWindowStateController statusBarWindowStateController,
-            LockIconViewController lockIconViewController) {
+            LockIconViewController lockIconViewController,
+            Optional<LowLightClockController> lowLightClockController) {
         mLockscreenShadeTransitionController = transitionController;
         mFalsingCollector = falsingCollector;
         mTunerService = tunerService;
@@ -115,6 +119,7 @@
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mStatusBarWindowStateController = statusBarWindowStateController;
         mLockIconViewController = lockIconViewController;
+        mLowLightClockController = lowLightClockController;
 
         // This view is not part of the newly inflated expanded status bar.
         mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -171,6 +176,8 @@
                 };
         mGestureDetector = new GestureDetector(mView.getContext(), gestureListener);
 
+        mLowLightClockController.ifPresent(controller -> controller.attachLowLightClockView(mView));
+
         mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() {
             @Override
             public Boolean handleDispatchTouchEvent(MotionEvent ev) {
@@ -450,6 +457,21 @@
         mNotificationShadeWindowController = controller;
     }
 
+    /**
+     * Tell the controller that dozing has begun or ended.
+     * @param dozing True if dozing has begun.
+     */
+    public void setDozing(boolean dozing) {
+        mLowLightClockController.ifPresent(controller -> controller.showLowLightClock(dozing));
+    }
+
+    /**
+     * Tell the controller to perform burn-in prevention.
+     */
+    public void dozeTimeTick() {
+        mLowLightClockController.ifPresent(LowLightClockController::dozeTimeTick);
+    }
+
     @VisibleForTesting
     void setDragDownHelper(DragDownHelper dragDownHelper) {
         mDragDownHelper = dragDownHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
index 8471e0a..a32a5ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DevicePostureControllerImpl.java
@@ -25,6 +25,7 @@
 import com.android.internal.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.util.Assert;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -70,6 +71,7 @@
         }
 
         deviceStateManager.registerCallback(executor, state -> {
+            Assert.isMainThread();
             mCurrentDevicePosture =
                     mDeviceStateToPostureMap.get(state, DEVICE_POSTURE_UNKNOWN);
 
@@ -79,11 +81,13 @@
 
     @Override
     public void addCallback(@NonNull Callback listener) {
+        Assert.isMainThread();
         mListeners.add(listener);
     }
 
     @Override
     public void removeCallback(@NonNull Callback listener) {
+        Assert.isMainThread();
         mListeners.remove(listener);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 3205e09..48949f92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -118,7 +118,6 @@
     private boolean mColorized;
     private int mTint;
     private boolean mResetting;
-    private boolean mWasSpinning;
 
     // TODO(b/193539698): move these to a Controller
     private RemoteInputController mController;
@@ -440,10 +439,6 @@
                 mEditText.requestFocus();
             }
         }
-        if (mWasSpinning) {
-            mController.addSpinning(mEntry.getKey(), mToken);
-            mWasSpinning = false;
-        }
     }
 
     @Override
@@ -452,7 +447,6 @@
         mEditText.removeTextChangedListener(mTextWatcher);
         mEditText.setOnEditorActionListener(null);
         mEditText.mRemoteInputView = null;
-        mWasSpinning = mController.isSpinning(mEntry.getKey(), mToken);
         if (mEntry.getRow().isChangingPosition() || isTemporarilyDetached()) {
             return;
         }
@@ -539,8 +533,6 @@
         if (isActive() && mWrapper != null) {
             mWrapper.setRemoteInputVisible(true);
         }
-
-        mWasSpinning = false;
     }
 
     private void reset() {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index d97815f..b23d870 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -34,6 +34,8 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
+import androidx.annotation.WorkerThread;
+
 import com.android.internal.util.ArrayUtils;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.R;
@@ -287,6 +289,7 @@
     }
 
     @Override
+    @WorkerThread
     public boolean isTunerEnabled() {
         return mUserTracker.getUserContext().getPackageManager().getComponentEnabledSetting(
                 mTunerComponent) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
index 40982bb..460b7d9 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/PostureDependentProximitySensor.java
@@ -37,6 +37,8 @@
     private final ThresholdSensor[] mPostureToPrimaryProxSensorMap;
     private final ThresholdSensor[] mPostureToSecondaryProxSensorMap;
 
+    private final DevicePostureController mDevicePostureController;
+
     @Inject
     PostureDependentProximitySensor(
             @PrimaryProxSensor ThresholdSensor[] postureToPrimaryProxSensorMap,
@@ -53,15 +55,24 @@
         );
         mPostureToPrimaryProxSensorMap = postureToPrimaryProxSensorMap;
         mPostureToSecondaryProxSensorMap = postureToSecondaryProxSensorMap;
-        mDevicePosture = devicePostureController.getDevicePosture();
-        devicePostureController.addCallback(mDevicePostureCallback);
+        mDevicePostureController = devicePostureController;
+
+        mDevicePosture = mDevicePostureController.getDevicePosture();
+        mDevicePostureController.addCallback(mDevicePostureCallback);
 
         chooseSensors();
     }
+
+    @Override
+    public void destroy() {
+        super.destroy();
+        mDevicePostureController.removeCallback(mDevicePostureCallback);
+    }
+
     private void chooseSensors() {
         if (mDevicePosture >= mPostureToPrimaryProxSensorMap.length
                 || mDevicePosture >= mPostureToSecondaryProxSensorMap.length) {
-            Log.e("PostureDependentProxSensor",
+            Log.e("PostureDependProxSensor",
                     "unsupported devicePosture=" + mDevicePosture);
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java
index a8a6341..c06a3a1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximityCheck.java
@@ -73,6 +73,13 @@
         }
     }
 
+    /**
+     * Cleanup after no longer needed.
+     */
+    public void destroy() {
+        mSensor.destroy();
+    }
+
     private void unregister() {
         mSensor.unregister(mListener);
         mRegistered.set(false);
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index d3f1c93..7f64322 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -42,4 +42,10 @@
      * of what is reported by the primary sensor.
      */
     void setSecondarySafe(boolean safe);
+
+    /**
+     * Called when the proximity sensor is no longer needed. All listeners should
+     * be unregistered and cleaned up.
+     */
+    void destroy();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
index 5568f64..8ab5bc6 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensorImpl.java
@@ -252,6 +252,11 @@
     }
 
     @Override
+    public void destroy() {
+        pause();
+    }
+
+    @Override
     public String getName() {
         return mPrimaryThresholdSensor.getName();
     }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index f71dd24..42e15c4 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -243,6 +243,9 @@
         verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
         mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue();
         mKeyguardUpdateMonitor.registerCallback(mTestCallback);
+
+        mTestableLooper.processAllMessages();
+        when(mAuthController.areAllAuthenticatorsRegistered()).thenReturn(true);
     }
 
     @After
@@ -471,6 +474,18 @@
     }
 
     @Test
+    public void test_doesNotTryToAuthenticateFingerprint_whenAuthenticatorsNotRegistered() {
+        when(mAuthController.areAllAuthenticatorsRegistered()).thenReturn(false);
+
+        mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
+        mTestableLooper.processAllMessages();
+
+        verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+                anyInt(), anyInt());
+        verify(mFingerprintManager, never()).detectFingerprint(any(), any(), anyInt());
+    }
+
+    @Test
     public void testFingerprintDoesNotAuth_whenEncrypted() {
         testFingerprintWhenStrongAuth(
                 STRONG_AUTH_REQUIRED_AFTER_BOOT);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index f207b9e..0a1e45c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -175,6 +175,7 @@
     public void testDestroy() {
         mDozeSensors.destroy();
 
+        verify(mProximitySensor).destroy();
         verify(mTriggerSensor).setListening(false);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 7fc354f..ae387e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -299,6 +299,12 @@
         verify(mAuthController).onAodInterrupt(eq(screenX), eq(screenY), eq(major), eq(minor));
     }
 
+    @Test
+    public void testDestroy() {
+        mTriggers.destroy();
+        verify(mProximityCheck).destroy();
+    }
+
     private void waitForSensorManager() {
         mExecutor.runAllReady();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
index 87bc732..4cc5673 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
@@ -18,10 +18,10 @@
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
-import android.content.pm.PackageManager
 import android.content.pm.PackageManager.NameNotFoundException
 import android.content.res.Resources
 import androidx.test.filters.SmallTest
+import com.android.internal.statusbar.IStatusBarService
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.util.mockito.any
@@ -59,6 +59,7 @@
     @Mock private lateinit var mSecureSettings: SecureSettings
     @Mock private lateinit var mResources: Resources
     @Mock private lateinit var mDumpManager: DumpManager
+    @Mock private lateinit var mBarService: IStatusBarService
     private val mFlagMap = mutableMapOf<Int, Flag<*>>()
     private lateinit var mBroadcastReceiver: BroadcastReceiver
     private lateinit var mClearCacheAction: Consumer<Int>
@@ -72,7 +73,8 @@
             mSecureSettings,
             mResources,
             mDumpManager,
-            { mFlagMap }
+            { mFlagMap },
+            mBarService
         )
         verify(mFlagManager).restartAction = any()
         mBroadcastReceiver = withArgCaptor {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index 97b3b10..e606be1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -22,6 +22,7 @@
 import android.view.ViewGroup
 import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
+import com.android.keyguard.KeyguardViewController
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq
@@ -32,7 +33,6 @@
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.SysuiStatusBarStateController
 import com.android.systemui.statusbar.phone.KeyguardBypassController
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.animation.UniqueObjectHostView
@@ -81,7 +81,7 @@
     @Mock
     private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
     @Mock
-    private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+    private lateinit var keyguardViewController: KeyguardViewController
     @Mock
     private lateinit var configurationController: ConfigurationController
     @Mock
@@ -113,7 +113,7 @@
                 notificationLockscreenUserManager,
                 configurationController,
                 wakefulnessLifecycle,
-                statusBarKeyguardViewManager,
+                keyguardViewController,
                 dreamOverlayStateController)
         verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
         verify(statusBarStateController).addCallback(statusBarCallback.capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
index 91a9f9e..8ce50a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
@@ -12,7 +12,6 @@
 import com.android.internal.logging.MetricsLogger
 import com.android.internal.logging.UiEventLogger
 import com.android.internal.logging.testing.FakeMetricsLogger
-import com.android.systemui.Dependency
 import com.android.systemui.R
 import com.android.systemui.classifier.FalsingManagerFake
 import com.android.systemui.flags.FeatureFlags
@@ -23,9 +22,7 @@
 import com.android.systemui.statusbar.phone.MultiUserSwitchController
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.statusbar.policy.UserInfoController
-import com.android.systemui.tuner.TunerService
 import com.android.systemui.util.settings.FakeSettings
-import com.android.systemui.utils.leaks.FakeTunerService
 import com.android.systemui.utils.leaks.LeakCheckedTest
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
@@ -82,8 +79,6 @@
         MockitoAnnotations.initMocks(this)
         testableLooper = TestableLooper.get(this)
         fakeSettings = FakeSettings()
-        injectLeakCheckedDependencies(*LeakCheckedTest.ALL_SUPPORTED_CLASSES)
-        val fakeTunerService = Dependency.get(TunerService::class.java) as FakeTunerService
 
         whenever(multiUserSwitchControllerFactory.create(any()))
                 .thenReturn(multiUserSwitchController)
@@ -95,9 +90,8 @@
         controller = FooterActionsController(view, multiUserSwitchControllerFactory,
                 activityStarter, userManager, userTracker, userInfoController,
                 deviceProvisionedController, securityFooterController, fgsManagerController,
-                falsingManager, metricsLogger, fakeTunerService,
-                globalActionsDialog, uiEventLogger, showPMLiteButton = true, fakeSettings,
-                Handler(testableLooper.looper), featureFlags)
+                falsingManager, metricsLogger, globalActionsDialog, uiEventLogger,
+                showPMLiteButton = true, fakeSettings, Handler(testableLooper.looper), featureFlags)
         controller.init()
         ViewUtils.attachView(view)
         // View looper is the testable looper associated with the test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index d13451d..03c22b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -155,4 +155,19 @@
         mIconView.getIcon(largeIcon);
         // no crash? good
     }
-}
\ No newline at end of file
+
+    @Test
+    public void testNullIcon() {
+        Icon mockIcon = mock(Icon.class);
+        when(mockIcon.loadDrawableAsUser(any(), anyInt())).thenReturn(null);
+        mStatusBarIcon.icon = mockIcon;
+        mIconView.set(mStatusBarIcon);
+
+        Bitmap bitmap = Bitmap.createBitmap(60, 60, Bitmap.Config.ARGB_8888);
+        Icon icon = Icon.createWithBitmap(bitmap);
+        StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage",
+                icon, 0, 0, "");
+        mIconView.getIcon(largeIcon);
+        // No crash? good
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
index 12e71af..34a5d4b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewControllerTest.kt
@@ -24,6 +24,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollectorFake
 import com.android.systemui.dock.DockManager
+import com.android.systemui.lowlightclock.LowLightClockController
 import com.android.systemui.statusbar.LockscreenShadeTransitionController
 import com.android.systemui.statusbar.NotificationShadeDepthController
 import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -38,11 +39,13 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers
 import org.mockito.Mock
 import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.anyFloat
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
+import java.util.Optional
 import org.mockito.Mockito.`when` as whenever
 
 @RunWith(AndroidTestingRunner::class)
@@ -79,6 +82,8 @@
     private lateinit var mLockIconViewController: LockIconViewController
     @Mock
     private lateinit var mPhoneStatusBarViewController: PhoneStatusBarViewController
+    @Mock
+    private lateinit var mLowLightClockController: LowLightClockController
 
     private lateinit var mInteractionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
     private lateinit var mInteractionEventHandler: InteractionEventHandler
@@ -101,7 +106,8 @@
             stackScrollLayoutController,
             mStatusBarKeyguardViewManager,
             mStatusBarWindowStateController,
-            mLockIconViewController
+            mLockIconViewController,
+            Optional.of(mLowLightClockController)
         )
         mController.setupExpandedStatusBar()
         mController.setService(mStatusBar, mNotificationShadeWindowController)
@@ -235,6 +241,31 @@
         verify(mPhoneStatusBarViewController).sendTouchToView(nextEvent)
         assertThat(returnVal).isTrue()
     }
+
+    @Test
+    fun testLowLightClockAttachedWhenExpandedStatusBarSetup() {
+        verify(mLowLightClockController).attachLowLightClockView(ArgumentMatchers.any())
+    }
+
+    @Test
+    fun testLowLightClockShownWhenDozing() {
+        mController.setDozing(true)
+        verify(mLowLightClockController).showLowLightClock(true)
+    }
+
+    @Test
+    fun testLowLightClockDozeTimeTickCalled() {
+        mController.dozeTimeTick()
+        verify(mLowLightClockController).dozeTimeTick()
+    }
+
+    @Test
+    fun testLowLightClockHiddenWhenNotDozing() {
+        mController.setDozing(true)
+        verify(mLowLightClockController).showLowLightClock(true)
+        mController.setDozing(false)
+        verify(mLowLightClockController).showLowLightClock(false)
+    }
 }
 
 private val downEv = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index d885da8..6c33113 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -37,6 +37,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.dock.DockManager;
+import com.android.systemui.lowlightclock.LowLightClockController;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -56,6 +57,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Optional;
+
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 @SmallTest
@@ -79,6 +82,7 @@
     @Mock private StatusBarWindowStateController mStatusBarWindowStateController;
     @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
     @Mock private LockIconViewController mLockIconViewController;
+    @Mock private LowLightClockController mLowLightClockController;
 
     @Captor private ArgumentCaptor<NotificationShadeWindowView.InteractionEventHandler>
             mInteractionEventHandlerCaptor;
@@ -110,7 +114,8 @@
                 mNotificationStackScrollLayoutController,
                 mStatusBarKeyguardViewManager,
                 mStatusBarWindowStateController,
-                mLockIconViewController);
+                mLockIconViewController,
+                Optional.of(mLowLightClockController));
         mController.setupExpandedStatusBar();
         mController.setService(mStatusBar, mNotificationShadeWindowController);
         mController.setDragDownHelper(mDragDownHelper);
diff --git a/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml
index cd53227..66fc2ae 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml
+++ b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml
@@ -30,6 +30,9 @@
     <!-- Controls whether the navigation bar lets through taps. -->
     <bool name="config_navBarTapThrough">true</bool>
 
+    <!-- Controls whether the IME renders the back and IME switcher buttons or not. -->
+    <bool name="config_imeDrawsImeNavBar">true</bool>
+
     <!-- Controls the size of the back gesture inset. -->
     <dimen name="config_backGestureInset">30dp</dimen>
 
diff --git a/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/res/values/config.xml b/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/res/values/config.xml
index 88cb74d79..120a489 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/res/values/config.xml
+++ b/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/res/values/config.xml
@@ -30,6 +30,9 @@
     <!-- Controls whether the navigation bar lets through taps. -->
     <bool name="config_navBarTapThrough">true</bool>
 
+    <!-- Controls whether the IME renders the back and IME switcher buttons or not. -->
+    <bool name="config_imeDrawsImeNavBar">true</bool>
+
     <!-- Controls the size of the back gesture inset. -->
     <dimen name="config_backGestureInset">40dp</dimen>
 
diff --git a/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/res/values/config.xml b/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/res/values/config.xml
index 70c41d0..c18d892 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/res/values/config.xml
+++ b/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/res/values/config.xml
@@ -30,6 +30,9 @@
     <!-- Controls whether the navigation bar lets through taps. -->
     <bool name="config_navBarTapThrough">true</bool>
 
+    <!-- Controls whether the IME renders the back and IME switcher buttons or not. -->
+    <bool name="config_imeDrawsImeNavBar">true</bool>
+
     <!-- Controls the size of the back gesture inset. -->
     <dimen name="config_backGestureInset">18dp</dimen>
 
diff --git a/packages/overlays/NavigationBarModeGesturalOverlayWideBack/res/values/config.xml b/packages/overlays/NavigationBarModeGesturalOverlayWideBack/res/values/config.xml
index de26394..877b5f8 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlayWideBack/res/values/config.xml
+++ b/packages/overlays/NavigationBarModeGesturalOverlayWideBack/res/values/config.xml
@@ -30,6 +30,9 @@
     <!-- Controls whether the navigation bar lets through taps. -->
     <bool name="config_navBarTapThrough">true</bool>
 
+    <!-- Controls whether the IME renders the back and IME switcher buttons or not. -->
+    <bool name="config_imeDrawsImeNavBar">true</bool>
+
     <!-- Controls the size of the back gesture inset. -->
     <dimen name="config_backGestureInset">32dp</dimen>
 
diff --git a/services/Android.bp b/services/Android.bp
index e010469..e0ca8a6 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -24,6 +24,7 @@
             "-Xep:ArrayHashCode:ERROR",
             "-Xep:SelfAssignment:ERROR",
             "-Xep:ArrayEquals:ERROR",
+            "-Xep:IdentityBinaryExpression:ERROR",
             // NOTE: only enable to generate local patchfiles
             // "-XepPatchChecks:refaster:frameworks/base/errorprone/refaster/EfficientXml.java.refaster",
             // "-XepPatchLocation:/tmp/refaster/",
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 6c220f6..d218af3 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -45,7 +45,6 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.Executors;
 import java.util.stream.Collectors;
 
 /**
@@ -261,7 +260,6 @@
                                 pw.println("");
                             }
                         } catch (PackageManager.NameNotFoundException e) {
-                            pw.println(packageName);
                             pw.println(packageName
                                     + ";ERROR:Unable to find PackageInfo for this module.");
                             if (verbose) {
@@ -370,13 +368,10 @@
 
         // we are only interested in doing things at PHASE_BOOT_COMPLETED
         if (phase == PHASE_BOOT_COMPLETED) {
+            // due to potentially long computation that holds up boot time, apex sha computations
+            // are deferred to first call
             Slog.i(TAG, "Boot completed. Getting VBMeta Digest.");
             getVBMetaDigestInformation();
-
-            // due to potentially long computation that may hold up boot time, SHA256 computations
-            // for APEXs and Modules will be executed via threads.
-            Slog.i(TAG, "Executing APEX & Module digest computations");
-            computeApexAndModuleDigests();
         }
     }
 
@@ -386,12 +381,6 @@
         FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest);
     }
 
-    private void computeApexAndModuleDigests() {
-        // using Executors will allow the computations to be done asynchronously, thus not holding
-        // up boot time.
-        Executors.defaultThreadFactory().newThread(() -> updateBinaryMeasurements()).start();
-    }
-
     @NonNull
     private List<PackageInfo> getInstalledApexs() {
         List<PackageInfo> results = new ArrayList<PackageInfo>();
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index c236a7f..569d480 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -43,6 +43,7 @@
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
 import android.app.UiModeManager;
+import android.app.UiModeManager.NightModeCustomReturnType;
 import android.app.UiModeManager.NightModeCustomType;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -111,6 +112,9 @@
     // Enable launching of applications when entering the dock.
     private static final boolean ENABLE_LAUNCH_DESK_DOCK_APP = true;
     private static final String SYSTEM_PROPERTY_DEVICE_THEME = "persist.sys.theme";
+    @VisibleForTesting
+    public static final Set<Integer> SUPPORTED_NIGHT_MODE_CUSTOM_TYPES = new ArraySet(
+            new Integer[]{MODE_NIGHT_CUSTOM_TYPE_SCHEDULE, MODE_NIGHT_CUSTOM_TYPE_BEDTIME});
 
     private final Injector mInjector;
     private final Object mLock = new Object();
@@ -631,6 +635,8 @@
                         + "permission ENTER_CAR_MODE_PRIORITIZED");
             }
 
+            assertLegit(callingPackage);
+
             final long ident = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
@@ -671,6 +677,9 @@
             // mode flag to be specified; this is so that the user can disable car mode at all
             // priorities using the persistent notification.
             boolean isSystemCaller = mInjector.getCallingUid() == Process.SYSTEM_UID;
+            if (!isSystemCaller) {
+                assertLegit(callingPackage);
+            }
             final int carModeFlags =
                     isSystemCaller ? flags : flags & ~UiModeManager.DISABLE_CAR_MODE_ALL_PRIORITIES;
 
@@ -728,8 +737,13 @@
                 case UiModeManager.MODE_NIGHT_NO:
                 case UiModeManager.MODE_NIGHT_YES:
                 case MODE_NIGHT_AUTO:
-                case MODE_NIGHT_CUSTOM:
                     break;
+                case MODE_NIGHT_CUSTOM:
+                    if (SUPPORTED_NIGHT_MODE_CUSTOM_TYPES.contains(customModeType)) {
+                        break;
+                    }
+                    throw new IllegalArgumentException(
+                            "Can't set the custom type to " + customModeType);
                 default:
                     throw new IllegalArgumentException("Unknown mode: " + mode);
             }
@@ -783,7 +797,7 @@
         }
 
         @Override
-        public int getNightModeCustomType() {
+        public  @NightModeCustomReturnType int getNightModeCustomType() {
             if (getContext().checkCallingOrSelfPermission(
                     android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
                     != PackageManager.PERMISSION_GRANTED) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2371101..c87943d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -188,6 +188,7 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.app.PendingIntentStats;
 import android.app.ProcessMemoryState;
 import android.app.ProfilerInfo;
 import android.app.SyncNotedAppOp;
@@ -15952,6 +15953,11 @@
             implements ActivityManagerLocal {
 
         @Override
+        public List<PendingIntentStats> getPendingIntentStats() {
+            return mPendingIntentController.dumpPendingIntentStatsForStatsd();
+        }
+
+        @Override
         public Pair<String, String> getAppProfileStatsForDebugging(long time, int lines) {
             return mAppProfiler.getAppProfileStatsForDebugging(time, lines);
         }
@@ -17149,6 +17155,11 @@
             // It's a CopyOnWriteArrayList, so no lock is needed.
             mBindServiceEventListeners.add(listener);
         }
+
+        @Override
+        public void restart() {
+            ActivityManagerService.this.restart();
+        }
     }
 
     long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
diff --git a/services/core/java/com/android/server/am/AnrHelper.java b/services/core/java/com/android/server/am/AnrHelper.java
index 34d9a60..1e1024e 100644
--- a/services/core/java/com/android/server/am/AnrHelper.java
+++ b/services/core/java/com/android/server/am/AnrHelper.java
@@ -60,6 +60,10 @@
      */
     private long mLastAnrTimeMs = 0L;
 
+    /** The pid which is running appNotResponding(). */
+    @GuardedBy("mAnrRecords")
+    private int mProcessingPid = -1;
+
     AnrHelper(final ActivityManagerService service) {
         mService = service;
     }
@@ -73,7 +77,18 @@
     void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,
             ApplicationInfo aInfo, String parentShortComponentName,
             WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
+        final int incomingPid = anrProcess.mPid;
         synchronized (mAnrRecords) {
+            if (mProcessingPid == incomingPid) {
+                Slog.i(TAG, "Skip duplicated ANR, pid=" + incomingPid + " " + annotation);
+                return;
+            }
+            for (int i = mAnrRecords.size() - 1; i >= 0; i--) {
+                if (mAnrRecords.get(i).mPid == incomingPid) {
+                    Slog.i(TAG, "Skip queued ANR, pid=" + incomingPid + " " + annotation);
+                    return;
+                }
+            }
             mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
                     parentShortComponentName, parentProcess, aboveSystem, annotation));
         }
@@ -87,8 +102,8 @@
     }
 
     /**
-     * The thread to execute {@link ProcessRecord#appNotResponding}. It will terminate if all
-     * records are handled.
+     * The thread to execute {@link ProcessErrorStateRecord#appNotResponding}. It will terminate if
+     * all records are handled.
      */
     private class AnrConsumerThread extends Thread {
         AnrConsumerThread() {
@@ -97,7 +112,12 @@
 
         private AnrRecord next() {
             synchronized (mAnrRecords) {
-                return mAnrRecords.isEmpty() ? null : mAnrRecords.remove(0);
+                if (mAnrRecords.isEmpty()) {
+                    return null;
+                }
+                final AnrRecord record = mAnrRecords.remove(0);
+                mProcessingPid = record.mPid;
+                return record;
             }
         }
 
@@ -106,6 +126,13 @@
             AnrRecord r;
             while ((r = next()) != null) {
                 scheduleBinderHeavyHitterAutoSamplerIfNecessary();
+                final int currentPid = r.mApp.mPid;
+                if (currentPid != r.mPid) {
+                    // The process may have restarted or died.
+                    Slog.i(TAG, "Skip ANR with mismatched pid=" + r.mPid + ", current pid="
+                            + currentPid);
+                    continue;
+                }
                 final long startTime = SystemClock.uptimeMillis();
                 // If there are many ANR at the same time, the latency may be larger. If the latency
                 // is too large, the stack trace might not be meaningful.
@@ -120,6 +147,7 @@
 
             mRunning.set(false);
             synchronized (mAnrRecords) {
+                mProcessingPid = -1;
                 // The race should be unlikely to happen. Just to make sure we don't miss.
                 if (!mAnrRecords.isEmpty()) {
                     startAnrConsumerIfNeeded();
@@ -139,6 +167,7 @@
 
     private static class AnrRecord {
         final ProcessRecord mApp;
+        final int mPid;
         final String mActivityShortComponentName;
         final String mParentShortComponentName;
         final String mAnnotation;
@@ -151,6 +180,7 @@
                 ApplicationInfo aInfo, String parentShortComponentName,
                 WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
             mApp = anrProcess;
+            mPid = anrProcess.mPid;
             mActivityShortComponentName = activityShortComponentName;
             mParentShortComponentName = parentShortComponentName;
             mAnnotation = annotation;
diff --git a/services/core/java/com/android/server/am/AppFGSTracker.java b/services/core/java/com/android/server/am/AppFGSTracker.java
index 5ac5a70..075402f 100644
--- a/services/core/java/com/android/server/am/AppFGSTracker.java
+++ b/services/core/java/com/android/server/am/AppFGSTracker.java
@@ -560,20 +560,22 @@
             int changes = serviceTypes ^ mForegroundServiceTypes;
             for (int serviceType = Integer.highestOneBit(changes); serviceType != 0;) {
                 final int i = foregroundServiceTypeToIndex(serviceType);
-                if ((serviceTypes & serviceType) != 0) {
-                    // Start this type.
-                    if (mEvents[i] == null) {
-                        mEvents[i] = new LinkedList<>();
-                    }
-                    if (!isActive(i)) {
-                        mEvents[i].add(new BaseTimeEvent(now));
-                        notifyListenersOnStateChangeIfNecessary(true, now, serviceType);
-                    }
-                } else {
-                    // Stop this type.
-                    if (mEvents[i] != null && isActive(i)) {
-                        mEvents[i].add(new BaseTimeEvent(now));
-                        notifyListenersOnStateChangeIfNecessary(false, now, serviceType);
+                if (i < mEvents.length) {
+                    if ((serviceTypes & serviceType) != 0) {
+                        // Start this type.
+                        if (mEvents[i] == null) {
+                            mEvents[i] = new LinkedList<>();
+                        }
+                        if (!isActive(i)) {
+                            mEvents[i].add(new BaseTimeEvent(now));
+                            notifyListenersOnStateChangeIfNecessary(true, now, serviceType);
+                        }
+                    } else {
+                        // Stop this type.
+                        if (mEvents[i] != null && isActive(i)) {
+                            mEvents[i].add(new BaseTimeEvent(now));
+                            notifyListenersOnStateChangeIfNecessary(false, now, serviceType);
+                        }
                     }
                 }
                 changes &= ~serviceType;
diff --git a/services/core/java/com/android/server/am/DataConnectionStats.java b/services/core/java/com/android/server/am/DataConnectionStats.java
index f0910dc..4c96078 100644
--- a/services/core/java/com/android/server/am/DataConnectionStats.java
+++ b/services/core/java/com/android/server/am/DataConnectionStats.java
@@ -73,7 +73,8 @@
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
-        mContext.registerReceiver(this, filter, null /* broadcastPermission */, mListenerHandler);
+        mContext.registerReceiver(this, filter, null /* broadcastPermission */, mListenerHandler,
+                Context.RECEIVER_NOT_EXPORTED);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java
index c49e696..7ee96aa 100644
--- a/services/core/java/com/android/server/am/PendingIntentController.java
+++ b/services/core/java/com/android/server/am/PendingIntentController.java
@@ -28,6 +28,7 @@
 import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
 import android.app.PendingIntent;
+import android.app.PendingIntentStats;
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.os.Binder;
@@ -60,6 +61,7 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 
 /**
  * Helper class for {@link ActivityManagerService} responsible for managing pending intents.
@@ -422,6 +424,55 @@
     }
 
     /**
+     * Provides some stats tracking of the current state of the PendingIntent queue.
+     *
+     * Data about the pending intent queue is intended to be used for memory impact tracking.
+     * Returned data (one per uid) will consist of instances of PendingIntentStats containing
+     * (I) number of PendingIntents and (II) total size of all bundled extras in the PIs.
+     *
+     * @hide
+     */
+    public List<PendingIntentStats> dumpPendingIntentStatsForStatsd() {
+        List<PendingIntentStats> pendingIntentStats = new ArrayList<>();
+
+        synchronized (mLock) {
+            if (mIntentSenderRecords.size() > 0) {
+                // First, aggregate PendingIntent data by package uid.
+                final SparseIntArray countsByUid = new SparseIntArray();
+                final SparseIntArray bundleSizesByUid = new SparseIntArray();
+
+                for (WeakReference<PendingIntentRecord> reference : mIntentSenderRecords.values()) {
+                    if (reference == null || reference.get() == null) {
+                        continue;
+                    }
+                    PendingIntentRecord record = reference.get();
+                    int index = countsByUid.indexOfKey(record.uid);
+
+                    if (index < 0) { // ie. the key was not found
+                        countsByUid.put(record.uid, 1);
+                        bundleSizesByUid.put(record.uid,
+                                record.key.requestIntent.getExtrasTotalSize());
+                    } else {
+                        countsByUid.put(record.uid, countsByUid.valueAt(index) + 1);
+                        bundleSizesByUid.put(record.uid,
+                                bundleSizesByUid.valueAt(index)
+                                + record.key.requestIntent.getExtrasTotalSize());
+                    }
+                }
+
+                // Now generate the output.
+                for (int i = 0, size = countsByUid.size(); i < size; i++) {
+                    pendingIntentStats.add(new PendingIntentStats(
+                            countsByUid.keyAt(i),
+                            countsByUid.valueAt(i),
+                            /* NB: int conversion here */ bundleSizesByUid.valueAt(i) / 1024));
+                }
+            }
+        }
+        return pendingIntentStats;
+    }
+
+    /**
      * Increment the number of the PendingIntentRecord for the given uid, log a warning
      * if there are too many for this uid already.
      */
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index c4163e6..763bbee 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1718,17 +1718,18 @@
             return Zygote.MEMORY_TAG_LEVEL_NONE;
         }
 
-        // Check to see that the compat feature for TBI is enabled.
-        if (mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING, app.info)) {
-            return Zygote.MEMORY_TAG_LEVEL_TBI;
-        }
-
         String defaultLevel = SystemProperties.get("persist.arm64.memtag.app_default");
         if ("sync".equals(defaultLevel)) {
             return Zygote.MEMORY_TAG_LEVEL_SYNC;
         } else if ("async".equals(defaultLevel)) {
             return Zygote.MEMORY_TAG_LEVEL_ASYNC;
         }
+
+        // Check to see that the compat feature for TBI is enabled.
+        if (mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING, app.info)) {
+            return Zygote.MEMORY_TAG_LEVEL_TBI;
+        }
+
         return Zygote.MEMORY_TAG_LEVEL_NONE;
     }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 3e5e435..807293f 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -36,6 +36,7 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SuppressLint;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
@@ -87,6 +88,7 @@
 import android.media.AudioRoutesInfo;
 import android.media.AudioSystem;
 import android.media.BluetoothProfileConnectionInfo;
+import android.media.IAudioDeviceVolumeDispatcher;
 import android.media.IAudioFocusDispatcher;
 import android.media.IAudioModeDispatcher;
 import android.media.IAudioRoutesObserver;
@@ -108,6 +110,7 @@
 import android.media.MediaRecorder.AudioSource;
 import android.media.PlayerBase;
 import android.media.Spatializer;
+import android.media.VolumeInfo;
 import android.media.VolumePolicy;
 import android.media.audiofx.AudioEffect;
 import android.media.audiopolicy.AudioMix;
@@ -4246,6 +4249,24 @@
         return (mStreamStates[streamType].getIndex(device) + 5) / 10;
     }
 
+    /**
+     * Default VolumeInfo returned by {@link VolumeInfo#getDefaultVolumeInfo()}
+     * Lazily initialized in {@link #getDefaultVolumeInfo()}
+     */
+    static VolumeInfo sDefaultVolumeInfo;
+
+    /** @see VolumeInfo#getDefaultVolumeInfo() */
+    public VolumeInfo getDefaultVolumeInfo() {
+        if (sDefaultVolumeInfo == null) {
+            sDefaultVolumeInfo = new VolumeInfo.Builder(AudioSystem.STREAM_MUSIC)
+                    .setMinVolumeIndex(getStreamMinVolume(AudioSystem.STREAM_MUSIC))
+                    .setMaxVolumeIndex(getStreamMaxVolume(AudioSystem.STREAM_MUSIC))
+                    .setMuted(false)
+                    .build();
+        }
+        return sDefaultVolumeInfo;
+    }
+
     /** @see AudioManager#getUiSoundsStreamType()
      * TODO(b/181140246): when using VolumeGroup alias, we are lacking configurability for
      * UI Sounds identification.
@@ -6310,6 +6331,37 @@
     }
 
     /**
+     * @see AudioDeviceVolumeManager#setDeviceAbsoluteMultiVolumeBehavior
+     * @param cb
+     * @param attr
+     * @param volumes
+     */
+    @RequiresPermission(anyOf = { android.Manifest.permission.MODIFY_AUDIO_ROUTING,
+            android.Manifest.permission.BLUETOOTH_PRIVILEGED })
+    public void registerDeviceVolumeDispatcherForAbsoluteVolume(boolean register,
+            IAudioDeviceVolumeDispatcher cb, String packageName,
+            AudioDeviceAttributes device, List<VolumeInfo> volumes) {
+        // verify permissions
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+                != PackageManager.PERMISSION_GRANTED
+                && mContext.checkCallingOrSelfPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException(
+                    "Missing MODIFY_AUDIO_ROUTING or BLUETOOTH_PRIVILEGED permissions");
+        }
+        // verify arguments
+        Objects.requireNonNull(device);
+        Objects.requireNonNull(volumes);
+
+        // current implementation maps this call to existing abs volume API of AudioManager
+        // TODO implement the volume/device listener through IAudioDeviceVolumeDispatcher
+        final int volumeBehavior = volumes.size() == 1
+                ? AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
+                : AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE;
+        setDeviceVolumeBehavior(device, volumeBehavior, packageName);
+    }
+
+    /**
      * @see AudioManager#setDeviceVolumeBehavior(AudioDeviceAttributes, int)
      * @param device the audio device to be affected
      * @param deviceVolumeBehavior one of the device behaviors
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 940c25c..c15242a 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -41,6 +41,9 @@
 import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
 import android.graphics.PointF;
+import android.hardware.SensorPrivacyManager;
+import android.hardware.SensorPrivacyManager.Sensors;
+import android.hardware.SensorPrivacyManagerInternal;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayViewport;
 import android.hardware.input.IInputDevicesChangedListener;
@@ -550,6 +553,19 @@
             }
         }
 
+        // Set the HW mic toggle switch state
+        final int micMuteState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY,
+                SW_MUTE_DEVICE);
+        if (micMuteState != InputManager.SWITCH_STATE_UNKNOWN) {
+            setSensorPrivacy(Sensors.MICROPHONE, micMuteState != InputManager.SWITCH_STATE_OFF);
+        }
+        // Set the HW camera toggle switch state
+        final int cameraMuteState = getSwitchState(-1 /* deviceId */, InputDevice.SOURCE_ANY,
+                SW_CAMERA_LENS_COVER);
+        if (cameraMuteState != InputManager.SWITCH_STATE_UNKNOWN) {
+            setSensorPrivacy(Sensors.CAMERA, cameraMuteState != InputManager.SWITCH_STATE_OFF);
+        }
+
         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
@@ -2816,6 +2832,8 @@
         if ((switchMask & SW_CAMERA_LENS_COVER_BIT) != 0) {
             final boolean lensCovered = ((switchValues & SW_CAMERA_LENS_COVER_BIT) != 0);
             mWindowManagerCallbacks.notifyCameraLensCoverSwitchChanged(whenNanos, lensCovered);
+            // Use SW_CAMERA_LENS_COVER code for camera privacy toggles
+            setSensorPrivacy(Sensors.CAMERA, lensCovered);
         }
 
         if (mUseDevInputEventForAudioJack && (switchMask & SW_JACK_BITS) != 0) {
@@ -2836,9 +2854,20 @@
             final boolean micMute = ((switchValues & SW_MUTE_DEVICE_BIT) != 0);
             AudioManager audioManager = mContext.getSystemService(AudioManager.class);
             audioManager.setMicrophoneMuteFromSwitch(micMute);
+
+            setSensorPrivacy(Sensors.MICROPHONE, micMute);
         }
     }
 
+    // Set the sensor privacy state based on the hardware toggles switch states
+    private void setSensorPrivacy(@SensorPrivacyManager.Sensors.Sensor int sensor,
+            boolean enablePrivacy) {
+        final SensorPrivacyManagerInternal sensorPrivacyManagerInternal =
+                LocalServices.getService(SensorPrivacyManagerInternal.class);
+        sensorPrivacyManagerInternal.setPhysicalToggleSensorPrivacy(UserHandle.USER_CURRENT, sensor,
+                enablePrivacy);
+    }
+
     // Native callback.
     @SuppressWarnings("unused")
     private void notifyInputChannelBroken(IBinder token) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3d34976..16b5fb1 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -682,7 +682,14 @@
             return mBuffer.descendingIterator();
         }
 
-        public StatusBarNotification[] getArray(int count, boolean includeSnoozed) {
+        public StatusBarNotification[] getArray(UserManager um, int count, boolean includeSnoozed) {
+            ArrayList<Integer> currentUsers = new ArrayList<>();
+            currentUsers.add(UserHandle.USER_ALL);
+            Binder.withCleanCallingIdentity(() -> {
+                for (int user : um.getProfileIds(ActivityManager.getCurrentUser(), false)) {
+                    currentUsers.add(user);
+                }
+            });
             synchronized (mBufferLock) {
                 if (count == 0) count = mBufferSize;
                 List<StatusBarNotification> a = new ArrayList();
@@ -691,8 +698,10 @@
                 while (iter.hasNext() && i < count) {
                     Pair<StatusBarNotification, Integer> pair = iter.next();
                     if (pair.second != REASON_SNOOZED || includeSnoozed) {
-                        i++;
-                        a.add(pair.first);
+                        if (currentUsers.contains(pair.first.getUserId())) {
+                            i++;
+                            a.add(pair.first);
+                        }
                     }
                 }
                 return a.toArray(new StatusBarNotification[a.size()]);
@@ -4200,22 +4209,32 @@
                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
                     "NotificationManagerService.getActiveNotifications");
 
-            StatusBarNotification[] tmp = null;
+            ArrayList<StatusBarNotification> tmp = new ArrayList<>();
             int uid = Binder.getCallingUid();
 
+            ArrayList<Integer> currentUsers = new ArrayList<>();
+            currentUsers.add(UserHandle.USER_ALL);
+            Binder.withCleanCallingIdentity(() -> {
+                for (int user : mUm.getProfileIds(ActivityManager.getCurrentUser(), false)) {
+                    currentUsers.add(user);
+                }
+            });
+
             // noteOp will check to make sure the callingPkg matches the uid
             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg,
                     callingAttributionTag, null)
                     == MODE_ALLOWED) {
                 synchronized (mNotificationLock) {
-                    tmp = new StatusBarNotification[mNotificationList.size()];
                     final int N = mNotificationList.size();
-                    for (int i=0; i<N; i++) {
-                        tmp[i] = mNotificationList.get(i).getSbn();
+                    for (int i = 0; i < N; i++) {
+                        final StatusBarNotification sbn = mNotificationList.get(i).getSbn();
+                        if (currentUsers.contains(sbn.getUserId())) {
+                            tmp.add(sbn);
+                        }
                     }
                 }
             }
-            return tmp;
+            return tmp.toArray(new StatusBarNotification[tmp.size()]);
         }
 
         /**
@@ -4324,7 +4343,7 @@
                     callingAttributionTag, null)
                     == MODE_ALLOWED) {
                 synchronized (mArchive) {
-                    tmp = mArchive.getArray(count, includeSnoozed);
+                    tmp = mArchive.getArray(mUm, count, includeSnoozed);
                 }
             }
             return tmp;
diff --git a/services/core/java/com/android/server/notification/PermissionHelper.java b/services/core/java/com/android/server/notification/PermissionHelper.java
index d80d9f3..6b9e374 100644
--- a/services/core/java/com/android/server/notification/PermissionHelper.java
+++ b/services/core/java/com/android/server/notification/PermissionHelper.java
@@ -185,11 +185,13 @@
             return;
         }
         try {
-            if (grant && !reviewRequired) {
+            boolean currentlyGranted = mPmi.checkPermission(packageName, NOTIFICATION_PERMISSION,
+                    userId) != PackageManager.PERMISSION_DENIED;
+            if (grant && !reviewRequired && !currentlyGranted) {
                 mPermManager.grantRuntimePermission(packageName, NOTIFICATION_PERMISSION, userId);
-            } else {
-                mPermManager.revokeRuntimePermission(packageName, NOTIFICATION_PERMISSION, userId,
-                        TAG);
+            } else if (!grant && currentlyGranted) {
+                mPermManager.revokeRuntimePermission(packageName, NOTIFICATION_PERMISSION,
+                        userId, TAG);
             }
             if (userSet) {
                 mPermManager.updatePermissionFlags(packageName, NOTIFICATION_PERMISSION,
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index dc4d04f..bdc5711 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -70,11 +70,15 @@
             "validate_notification_people_enabled";
     private static final String[] LOOKUP_PROJECTION = { Contacts._ID, Contacts.LOOKUP_KEY,
             Contacts.STARRED, Contacts.HAS_PHONE_NUMBER };
-    private static final String[] PHONE_LOOKUP_PROJECTION =
-            { ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER };
     private static final int MAX_PEOPLE = 10;
     private static final int PEOPLE_CACHE_SIZE = 200;
 
+    /** Columns used to look up phone numbers for contacts. */
+    @VisibleForTesting
+    static final String[] PHONE_LOOKUP_PROJECTION =
+            { ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER,
+                    ContactsContract.CommonDataKinds.Phone.NUMBER };
+
     /** Indicates that the notification does not reference any valid contacts. */
     static final float NONE = 0f;
 
@@ -548,14 +552,21 @@
             return mPhoneLookupKey;
         }
 
-        // Merge phone number found in this lookup and store it in mPhoneNumbers.
+        // Merge phone numbers found in this lookup and store them in mPhoneNumbers.
         public void mergePhoneNumber(Cursor cursor) {
-            final int phoneNumIdx = cursor.getColumnIndex(
+            final int normalizedNumIdx = cursor.getColumnIndex(
                     ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER);
-            if (phoneNumIdx >= 0) {
-                mPhoneNumbers.add(cursor.getString(phoneNumIdx));
+            if (normalizedNumIdx >= 0) {
+                mPhoneNumbers.add(cursor.getString(normalizedNumIdx));
             } else {
-                if (DEBUG) Slog.d(TAG, "invalid cursor: no NORMALIZED_NUMBER");
+                if (DEBUG) Slog.d(TAG, "cursor data not found: no NORMALIZED_NUMBER");
+            }
+
+            final int numIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
+            if (numIdx >= 0) {
+                mPhoneNumbers.add(cursor.getString(numIdx));
+            } else {
+                if (DEBUG) Slog.d(TAG, "cursor data not found: no NUMBER");
             }
         }
 
diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java
index d04b331..2a6dd84 100644
--- a/services/core/java/com/android/server/notification/ZenModeFiltering.java
+++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java
@@ -40,8 +40,6 @@
 import com.android.internal.util.NotificationMessagingUtil;
 
 import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
 import java.util.Date;
 
 public class ZenModeFiltering {
@@ -416,16 +414,10 @@
                 if (person == null) continue;
                 final Uri uri = Uri.parse(person);
                 if ("tel".equals(uri.getScheme())) {
-                    String tel = uri.getSchemeSpecificPart();
-                    // while ideally we should not need to do this, sometimes we have seen tel
-                    // numbers given in a url-encoded format
-                    try {
-                        tel = URLDecoder.decode(tel, "UTF-8");
-                    } catch (UnsupportedEncodingException e) {
-                        // ignore, keep the original tel string
-                        Slog.w(TAG, "unsupported encoding in tel: uri input");
-                    }
-                    mTelCalls.put(tel, now);
+                    // while ideally we should not need to decode this, sometimes we have seen tel
+                    // numbers given in an encoded format
+                    String tel = Uri.decode(uri.getSchemeSpecificPart());
+                    if (tel != null) mTelCalls.put(tel, now);
                 } else {
                     // for non-tel calls, store the entire string, uri-component and all
                     mOtherCalls.put(person, now);
@@ -436,7 +428,7 @@
             // provided; these are in the format of just a phone number string
             if (phoneNumbers != null) {
                 for (String num : phoneNumbers) {
-                    mTelCalls.put(num, now);
+                    if (num != null) mTelCalls.put(num, now);
                 }
             }
         }
@@ -456,17 +448,13 @@
                         return true;
                     } else {
                         // see if a number that matches via areSameNumber exists
-                        String numberToCheck = number;
-                        try {
-                            numberToCheck = URLDecoder.decode(number, "UTF-8");
-                        } catch (UnsupportedEncodingException e) {
-                            // ignore, continue to use the original string
-                            Slog.w(TAG, "unsupported encoding in tel: uri input");
-                        }
-                        for (String prev : mTelCalls.keySet()) {
-                            if (PhoneNumberUtils.areSamePhoneNumber(
-                                    numberToCheck, prev, defaultCountryCode)) {
-                                return true;
+                        String numberToCheck = Uri.decode(number);
+                        if (numberToCheck != null) {
+                            for (String prev : mTelCalls.keySet()) {
+                                if (PhoneNumberUtils.areSamePhoneNumber(
+                                        numberToCheck, prev, defaultCountryCode)) {
+                                    return true;
+                                }
                             }
                         }
                     }
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 4f1a9e7..d117967 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -1382,7 +1382,7 @@
                 }
             } else {
                 callingPkgSetting = null;
-                callingSharedPkgSettings = ((SharedUserSetting) callingSetting).packages;
+                callingSharedPkgSettings = ((SharedUserSetting) callingSetting).getPackageStates();
             }
             if (DEBUG_TRACING) {
                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 04f0aab..c437697 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -2176,11 +2176,13 @@
                 return null;
             }
             final SharedUserSetting sus = (SharedUserSetting) obj;
-            final int n = sus.packages.size();
+            final ArraySet<PackageStateInternal> packageStates =
+                    (ArraySet<PackageStateInternal>) sus.getPackageStates();
+            final int n = packageStates.size();
             String[] res = new String[n];
             int i = 0;
             for (int index = 0; index < n; index++) {
-                final PackageStateInternal ps = sus.packages.valueAt(index);
+                final PackageStateInternal ps = packageStates.valueAt(index);
                 if (ps.getUserStateOrDefault(userId).isInstalled()
                         && !shouldFilterApplication(ps, callingUid, userId)) {
                     res[i++] = ps.getPackageName();
@@ -2710,8 +2712,10 @@
     public final boolean shouldFilterApplication(@NonNull SharedUserSetting sus,
             int callingUid, int userId) {
         boolean filterApp = true;
-        for (int index = sus.packages.size() - 1; index >= 0 && filterApp; index--) {
-            filterApp &= shouldFilterApplication(sus.packages.valueAt(index),
+        final ArraySet<PackageStateInternal> packageStates =
+                (ArraySet<PackageStateInternal>) sus.getPackageStates();
+        for (int index = packageStates.size() - 1; index >= 0 && filterApp; index--) {
+            filterApp &= shouldFilterApplication(packageStates.valueAt(index),
                     callingUid, /* component */ null, TYPE_UNKNOWN, userId);
         }
         return filterApp;
@@ -4468,9 +4472,11 @@
         final Object obj = mSettings.getSettingBase(appId);
         if (obj instanceof SharedUserSetting) {
             final SharedUserSetting sus = (SharedUserSetting) obj;
-            final int numPackages = sus.packages.size();
+            final ArraySet<PackageStateInternal> packageStates =
+                    (ArraySet<PackageStateInternal>) sus.getPackageStates();
+            final int numPackages = packageStates.size();
             for (int index = 0; index < numPackages; index++) {
-                final PackageSetting ps = sus.packages.valueAt(index);
+                final PackageStateInternal ps = packageStates.valueAt(index);
                 if (ps.isPrivileged()) {
                     return true;
                 }
@@ -5290,8 +5296,9 @@
             final AndroidPackage pkg = ((PackageSetting) setting).getPkg();
             return pkg != null && mAppsFilter.canQueryPackage(pkg, targetPackageName);
         } else {
-            final ArraySet<PackageSetting> callingSharedPkgSettings =
-                    ((SharedUserSetting) setting).packages;
+            final ArraySet<PackageStateInternal> callingSharedPkgSettings =
+                    (ArraySet<PackageStateInternal>)
+                            ((SharedUserSetting) setting).getPackageStates();
             for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) {
                 final AndroidPackage pkg = callingSharedPkgSettings.valueAt(i).getPkg();
                 if (pkg != null && mAppsFilter.canQueryPackage(pkg, targetPackageName)) {
@@ -5595,10 +5602,12 @@
         final SettingBase settingBase = mSettings.getSettingBase(appId);
         if (settingBase instanceof SharedUserSetting) {
             final SharedUserSetting sus = (SharedUserSetting) settingBase;
+            final ArraySet<PackageStateInternal> packageStates =
+                    (ArraySet<PackageStateInternal>) sus.getPackageStates();
             int vers = Build.VERSION_CODES.CUR_DEVELOPMENT;
-            final int numPackages = sus.packages.size();
+            final int numPackages = packageStates.size();
             for (int index = 0; index < numPackages; index++) {
-                final PackageSetting ps = sus.packages.valueAt(index);
+                final PackageStateInternal ps = packageStates.valueAt(index);
                 if (ps.getPkg() != null) {
                     int v = ps.getPkg().getTargetSdkVersion();
                     if (v < vers) vers = v;
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 684e6ba..2ef092e 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -3701,7 +3701,7 @@
                     && sharedUserSetting != null) {
                 Log.d(TAG, "Shared UserID " + parsedPackage.getSharedUserId()
                         + " (uid=" + sharedUserSetting.mAppId + "):"
-                        + " packages=" + sharedUserSetting.packages);
+                        + " packages=" + sharedUserSetting.getPackageStates());
             }
             if (installedPkgSetting != null) {
                 oldSharedUserSetting = mPm.mSettings.getSharedUserSettingLPr(installedPkgSetting);
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelper.java b/services/core/java/com/android/server/pm/PackageAbiHelper.java
index ca7c2db..1dbab90 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelper.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelper.java
@@ -18,15 +18,16 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.util.ArraySet;
 import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.PackageStateInternal;
 
 import java.io.File;
-import java.util.Set;
 
 
 
@@ -74,8 +75,8 @@
      *         belonging to the shared user.
      */
     @Nullable
-    String getAdjustedAbiForSharedUser(
-            Set<PackageSetting> packagesForUser, AndroidPackage scannedPackage);
+    String getAdjustedAbiForSharedUser(ArraySet<? extends PackageStateInternal> packagesForUser,
+            AndroidPackage scannedPackage);
 
     /**
      * The native library paths and related properties that should be set on a
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 1af508f..73d81ba 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -34,6 +34,7 @@
 import android.os.FileUtils;
 import android.os.Trace;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.Pair;
 import android.util.Slog;
 
@@ -41,6 +42,7 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.pkg.PackageStateInternal;
 
 import dalvik.system.VMRuntime;
 
@@ -48,7 +50,6 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.util.Set;
 
 final class PackageAbiHelperImpl implements PackageAbiHelper {
 
@@ -496,7 +497,8 @@
     @Override
     @Nullable
     public String getAdjustedAbiForSharedUser(
-            Set<PackageSetting> packagesForUser, AndroidPackage scannedPackage) {
+            ArraySet<? extends PackageStateInternal> packagesForUser,
+            AndroidPackage scannedPackage) {
         String requiredInstructionSet = null;
         if (scannedPackage != null) {
             String pkgRawPrimaryCpuAbi = AndroidPackageUtils.getRawPrimaryCpuAbi(scannedPackage);
@@ -505,8 +507,8 @@
             }
         }
 
-        PackageSetting requirer = null;
-        for (PackageSetting ps : packagesForUser) {
+        PackageStateInternal requirer = null;
+        for (PackageStateInternal ps : packagesForUser) {
             // If packagesForUser contains scannedPackage, we skip it. This will happen
             // when scannedPackage is an update of an existing package. Without this check,
             // we will never be able to change the ABI of any package belonging to a shared
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5c68fac..725e92a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2005,7 +2005,7 @@
                         ScanPackageUtils.applyAdjustedAbiToSharedUser(
                                 setting, null /*scannedPackage*/,
                                 mInjector.getAbiHelper().getAdjustedAbiForSharedUser(
-                                setting.packages, null /*scannedPackage*/));
+                                        setting.getPackageStates(), null /*scannedPackage*/));
                 if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
                     for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
                         final String codePathString = changedAbiCodePath.get(i);
@@ -6255,6 +6255,13 @@
                 }
             });
 
+            if (wasNotLaunched) {
+                final String installerPackageName = wasNotLaunchedAndInstallerPackageName.second;
+                if (installerPackageName != null) {
+                    notifyFirstLaunch(packageName, installerPackageName, userId);
+                }
+            }
+
             scheduleWritePackageRestrictions(userId);
         }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 0dae12f..2f56bfe 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -573,9 +573,10 @@
             // Special case: if the sharedUserId capability check failed it could be due to this
             // being the only package in the sharedUserId so far and the lineage being updated to
             // deny the sharedUserId capability of the previous key in the lineage.
-            if (!match && sharedUserSetting.packages.size() == 1
-                    && sharedUserSetting.packages
-                            .valueAt(0).getPackageName().equals(packageName)) {
+            final ArraySet<PackageStateInternal> susPackageStates =
+                    (ArraySet<PackageStateInternal>) sharedUserSetting.getPackageStates();
+            if (!match && susPackageStates.size() == 1
+                    && susPackageStates.valueAt(0).getPackageName().equals(packageName)) {
                 match = true;
             }
             if (!match && compareCompat) {
@@ -605,7 +606,8 @@
             // Iterate over all of the packages in the sharedUserId and ensure any that are signed
             // with a key in this package's lineage have the SHARED_USER_ID capability granted.
             if (parsedSignatures.hasPastSigningCertificates()) {
-                for (PackageSetting shUidPkgSetting : sharedUserSetting.packages) {
+                for (int i = 0; i < susPackageStates.size(); i++) {
+                    PackageStateInternal shUidPkgSetting = susPackageStates.valueAt(i);
                     // if the current package in the sharedUserId is the package being updated then
                     // skip this check as the update may revoke the sharedUserId capability from
                     // the key with which this app was previously signed.
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 99d9d58..33f0b54 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -62,6 +62,7 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
@@ -85,6 +86,7 @@
 import com.android.server.pm.pkg.component.ParsedProvider;
 import com.android.server.pm.pkg.component.ParsedService;
 import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.utils.WatchedArraySet;
 
 import dalvik.system.VMRuntime;
 
@@ -94,7 +96,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Set;
 import java.util.UUID;
 
 /**
@@ -400,7 +401,7 @@
             // code and package path correct.
             changedAbiCodePath = applyAdjustedAbiToSharedUser(oldSharedUserSetting,
                     parsedPackage, packageAbiHelper.getAdjustedAbiForSharedUser(
-                            oldSharedUserSetting.packages, parsedPackage));
+                            oldSharedUserSetting.getPackageStates(), parsedPackage));
         }
 
         parsedPackage.setFactoryTest(isUnderFactoryTest && parsedPackage.getRequestedPermissions()
@@ -891,7 +892,7 @@
 
     /**
      * Applies the adjusted ABI calculated by
-     * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, AndroidPackage)} to all
+     * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(ArraySet, AndroidPackage)} to all
      * relevant packages and settings.
      * @param sharedUserSetting The {@code SharedUserSetting} to adjust
      * @param scannedPackage the package being scanned or null
@@ -904,7 +905,10 @@
             scannedPackage.setPrimaryCpuAbi(adjustedAbi);
         }
         List<String> changedAbiCodePath = null;
-        for (PackageSetting ps : sharedUserSetting.packages) {
+        final WatchedArraySet<PackageSetting> sharedUserPackageSettings =
+                sharedUserSetting.getPackageSettings();
+        for (int i = 0; i < sharedUserPackageSettings.size(); i++) {
+            PackageSetting ps = sharedUserPackageSettings.valueAt(i);
             if (scannedPackage == null
                     || !scannedPackage.getPackageName().equals(ps.getPackageName())) {
                 if (ps.getPrimaryCpuAbi() != null) {
@@ -912,6 +916,7 @@
                 }
 
                 ps.setPrimaryCpuAbi(adjustedAbi);
+                ps.onChanged();
                 if (ps.getPkg() != null) {
                     if (!TextUtils.equals(adjustedAbi,
                             AndroidPackageUtils.getRawPrimaryCpuAbi(ps.getPkg()))) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 5966917..936da4a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -24,6 +24,7 @@
 import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
 import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
 import static android.content.pm.PackageManager.UNINSTALL_REASON_USER_TYPE;
+import static android.os.Process.INVALID_UID;
 import static android.os.Process.PACKAGE_INFO_GID;
 import static android.os.Process.SYSTEM_UID;
 
@@ -923,11 +924,30 @@
                 removeKeys.add(entry.getKey());
                 continue;
             }
+            boolean changed = false;
             // remove packages that are no longer installed
-            sus.packages.removeIf(ps -> mPackages.get(ps.getPackageName()) == null);
-            sus.mDisabledPackages.removeIf(
-                    ps -> mDisabledSysPackages.get(ps.getPackageName()) == null);
-            if (sus.packages.isEmpty() && sus.mDisabledPackages.isEmpty()) {
+            WatchedArraySet<PackageSetting> sharedUserPackageSettings = sus.getPackageSettings();
+            for (int i = sharedUserPackageSettings.size() - 1; i >= 0; i--) {
+                PackageSetting ps = sharedUserPackageSettings.valueAt(i);
+                if (mPackages.get(ps.getPackageName()) == null) {
+                    sharedUserPackageSettings.removeAt(i);
+                    changed = true;
+                }
+            }
+            WatchedArraySet<PackageSetting> sharedUserDisabledPackageSettings =
+                    sus.getDisabledPackageSettings();
+            for (int i = sharedUserDisabledPackageSettings.size() - 1; i >= 0; i--) {
+                PackageSetting ps = sharedUserDisabledPackageSettings.valueAt(i);
+                if (mDisabledSysPackages.get(ps.getPackageName()) == null) {
+                    sharedUserDisabledPackageSettings.removeAt(i);
+                    changed = true;
+                }
+            }
+            if (changed) {
+                sus.onChanged();
+            }
+            if (sharedUserPackageSettings.isEmpty()
+                    && sharedUserDisabledPackageSettings.isEmpty()) {
                 removeValues.add(sus);
             }
         }
@@ -1098,6 +1118,9 @@
                         "Updating application package " + pkgName + " failed");
             }
             pkgSetting.setSharedUserAppId(sharedUser.mAppId);
+        } else {
+            // migrating off shared user
+            pkgSetting.setSharedUserAppId(INVALID_UID);
         }
 
         if (!pkgSetting.getPath().equals(codePath)) {
@@ -1289,7 +1312,8 @@
     }
 
     boolean checkAndPruneSharedUserLPw(SharedUserSetting s, boolean skipCheck) {
-        if (skipCheck || (s.packages.isEmpty() && s.mDisabledPackages.isEmpty())) {
+        if (skipCheck || (s.getPackageStates().isEmpty()
+                && s.getDisabledPackageStates().isEmpty())) {
             if (mSharedUsers.remove(s.name) != null) {
                 removeAppIdLPw(s.mAppId);
                 return true;
@@ -5136,11 +5160,13 @@
                 pw.print(prefix); pw.print("userId="); pw.println(su.mAppId);
 
                 pw.print(prefix); pw.println("Packages");
-                final int numPackages = su.packages.size();
+                final ArraySet<PackageStateInternal> susPackageStates =
+                        (ArraySet<PackageStateInternal>) su.getPackageStates();
+                final int numPackages = susPackageStates.size();
                 for (int i = 0; i < numPackages; i++) {
-                    final PackageSetting ps = su.packages.valueAt(i);
+                    final PackageStateInternal ps = susPackageStates.valueAt(i);
                     if (ps != null) {
-                        pw.print(prefix + "  "); pw.println(ps.toString());
+                        pw.print(prefix + "  "); pw.println(ps);
                     } else {
                         pw.print(prefix + "  "); pw.println("NULL?!");
                     }
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index d0e1e6c..4d0bbc6 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -33,6 +33,7 @@
 import com.android.server.pm.pkg.component.ParsedProcess;
 import com.android.server.pm.pkg.component.ParsedProcessImpl;
 import com.android.server.utils.SnapshotCache;
+import com.android.server.utils.WatchedArraySet;
 
 import libcore.util.EmptyArray;
 
@@ -56,14 +57,14 @@
     /** @see SharedUserApi#getSeInfoTargetSdkVersion() **/
     int seInfoTargetSdkVersion;
 
-    final ArraySet<PackageSetting> packages;
-    private ArraySet<PackageStateInternal> mPackagesSnapshot;
+    private final WatchedArraySet<PackageSetting> mPackages;
+    private final SnapshotCache<WatchedArraySet<PackageSetting>> mPackagesSnapshot;
 
     // It is possible for a system app to leave shared user ID by an update.
     // We need to keep track of the shadowed PackageSettings so that it is possible to uninstall
     // the update and revert the system app back into the original shared user ID.
-    final ArraySet<PackageSetting> mDisabledPackages;
-    private ArraySet<PackageStateInternal> mDisabledPackagesSnapshot;
+    final WatchedArraySet<PackageSetting> mDisabledPackages;
+    private final SnapshotCache<WatchedArraySet<PackageSetting>> mDisabledPackagesSnapshot;
 
     final PackageSignatures signatures = new PackageSignatures();
     Boolean signaturesChanged;
@@ -89,8 +90,12 @@
         uidPrivateFlags = _pkgPrivateFlags;
         name = _name;
         seInfoTargetSdkVersion = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
-        packages = new ArraySet<>();
-        mDisabledPackages = new ArraySet<>();
+        mPackages = new WatchedArraySet<>();
+        mPackagesSnapshot = new SnapshotCache.Auto<>(mPackages, mPackages,
+                "SharedUserSetting.packages");
+        mDisabledPackages = new WatchedArraySet<>();
+        mDisabledPackagesSnapshot = new SnapshotCache.Auto<>(mDisabledPackages, mDisabledPackages,
+                "SharedUserSetting.mDisabledPackages");
         processes = new ArrayMap<>();
         mSnapshot = makeCache();
     }
@@ -102,20 +107,10 @@
         mAppId = orig.mAppId;
         uidFlags = orig.uidFlags;
         uidPrivateFlags = orig.uidPrivateFlags;
-        packages = new ArraySet<>(orig.packages);
-        if (!packages.isEmpty()) {
-            mPackagesSnapshot = new ArraySet<>();
-            for (int index = 0; index < packages.size(); index++) {
-                mPackagesSnapshot.add(new PackageSetting(packages.valueAt(index)));
-            }
-        }
-        mDisabledPackages = new ArraySet<>(orig.mDisabledPackages);
-        if (!mDisabledPackages.isEmpty()) {
-            mDisabledPackagesSnapshot = new ArraySet<>();
-            for (int index = 0; index < mDisabledPackages.size(); index++) {
-                mDisabledPackagesSnapshot.add(new PackageSetting(mDisabledPackages.valueAt(index)));
-            }
-        }
+        mPackages = orig.mPackagesSnapshot.snapshot();
+        mPackagesSnapshot = new SnapshotCache.Sealed<>();
+        mDisabledPackages = orig.mDisabledPackagesSnapshot.snapshot();
+        mDisabledPackagesSnapshot = new SnapshotCache.Sealed<>();
         // A SigningDetails seems to consist solely of final attributes, so
         // it is safe to copy the reference.
         signatures.mSigningDetails = orig.signatures.mSigningDetails;
@@ -161,20 +156,22 @@
     }
 
     boolean removePackage(PackageSetting packageSetting) {
-        if (!packages.remove(packageSetting)) {
+        if (!mPackages.remove(packageSetting)) {
             return false;
         }
         // recalculate the pkgFlags for this shared user if needed
         if ((this.getFlags() & packageSetting.getFlags()) != 0) {
             int aggregatedFlags = uidFlags;
-            for (PackageSetting ps : packages) {
+            for (int i = 0; i < mPackages.size(); i++) {
+                PackageSetting ps = mPackages.valueAt(i);
                 aggregatedFlags |= ps.getFlags();
             }
             setFlags(aggregatedFlags);
         }
         if ((this.getPrivateFlags() & packageSetting.getPrivateFlags()) != 0) {
             int aggregatedPrivateFlags = uidPrivateFlags;
-            for (PackageSetting ps : packages) {
+            for (int i = 0; i < mPackages.size(); i++) {
+                PackageSetting ps = mPackages.valueAt(i);
                 aggregatedPrivateFlags |= ps.getPrivateFlags();
             }
             setPrivateFlags(aggregatedPrivateFlags);
@@ -188,10 +185,10 @@
     void addPackage(PackageSetting packageSetting) {
         // If this is the first package added to this shared user, temporarily (until next boot) use
         // its targetSdkVersion when assigning seInfo for the shared user.
-        if ((packages.size() == 0) && (packageSetting.getPkg() != null)) {
+        if ((mPackages.size() == 0) && (packageSetting.getPkg() != null)) {
             seInfoTargetSdkVersion = packageSetting.getPkg().getTargetSdkVersion();
         }
-        if (packages.add(packageSetting)) {
+        if (mPackages.add(packageSetting)) {
             setFlags(this.getFlags() | packageSetting.getFlags());
             setPrivateFlags(this.getPrivateFlags() | packageSetting.getPrivateFlags());
             onChanged();
@@ -204,11 +201,12 @@
     @NonNull
     @Override
     public List<AndroidPackage> getPackages() {
-        if (packages == null || packages.size() == 0) {
+        if (mPackages == null || mPackages.size() == 0) {
             return Collections.emptyList();
         }
-        final ArrayList<AndroidPackage> pkgList = new ArrayList<>(packages.size());
-        for (PackageSetting ps : packages) {
+        final ArrayList<AndroidPackage> pkgList = new ArrayList<>(mPackages.size());
+        for (int i = 0; i < mPackages.size(); i++) {
+            PackageSetting ps = mPackages.valueAt(i);
             if ((ps == null) || (ps.getPkg() == null)) {
                 continue;
             }
@@ -229,10 +227,11 @@
      * restrictive selinux domain.
      */
     public void fixSeInfoLocked() {
-        if (packages == null || packages.size() == 0) {
+        if (mPackages == null || mPackages.size() == 0) {
             return;
         }
-        for (PackageSetting ps : packages) {
+        for (int i = 0; i < mPackages.size(); i++) {
+            PackageSetting ps = mPackages.valueAt(i);
             if ((ps == null) || (ps.getPkg() == null)) {
                 continue;
             }
@@ -242,7 +241,8 @@
             }
         }
 
-        for (PackageSetting ps : packages) {
+        for (int i = 0; i < mPackages.size(); i++) {
+            PackageSetting ps = mPackages.valueAt(i);
             if ((ps == null) || (ps.getPkg() == null)) {
                 continue;
             }
@@ -258,8 +258,8 @@
      */
     public void updateProcesses() {
         processes.clear();
-        for (int i = packages.size() - 1; i >= 0; i--) {
-            final AndroidPackage pkg = packages.valueAt(i).getPkg();
+        for (int i = mPackages.size() - 1; i >= 0; i--) {
+            final AndroidPackage pkg = mPackages.valueAt(i).getPkg();
             if (pkg != null) {
                 addProcesses(pkg.getProcesses());
             }
@@ -269,7 +269,8 @@
     /** Returns userIds which doesn't have any packages with this sharedUserId */
     public int[] getNotInstalledUserIds() {
         int[] excludedUserIds = null;
-        for (PackageSetting ps : packages) {
+        for (int i = 0; i < mPackages.size(); i++) {
+            PackageSetting ps = mPackages.valueAt(i);
             final int[] userIds = ps.getNotInstalledUserIds();
             if (excludedUserIds == null) {
                 excludedUserIds = userIds;
@@ -291,8 +292,8 @@
         this.uidFlags = sharedUser.uidFlags;
         this.uidPrivateFlags = sharedUser.uidPrivateFlags;
         this.seInfoTargetSdkVersion = sharedUser.seInfoTargetSdkVersion;
-        this.packages.clear();
-        this.packages.addAll(sharedUser.packages);
+        this.mPackages.clear();
+        this.mPackages.addAll(sharedUser.mPackages);
         this.signaturesChanged = sharedUser.signaturesChanged;
         if (sharedUser.processes != null) {
             final int numProcs = sharedUser.processes.size();
@@ -335,22 +336,24 @@
         return seInfoTargetSdkVersion;
     }
 
+    public WatchedArraySet<PackageSetting> getPackageSettings() {
+        return mPackages;
+    }
+
+    public WatchedArraySet<PackageSetting> getDisabledPackageSettings() {
+        return mDisabledPackages;
+    }
+
     @NonNull
     @Override
     public ArraySet<? extends PackageStateInternal> getPackageStates() {
-        if (mPackagesSnapshot != null) {
-            return mPackagesSnapshot;
-        }
-        return packages;
+        return mPackages.untrackedStorage();
     }
 
     @NonNull
     @Override
     public ArraySet<? extends PackageStateInternal> getDisabledPackageStates() {
-        if (mDisabledPackagesSnapshot != null) {
-            return mDisabledPackagesSnapshot;
-        }
-        return mDisabledPackages;
+        return mDisabledPackages.untrackedStorage();
     }
 
     @NonNull
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index f87063a..9c74dd7 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -71,6 +71,14 @@
           "include-filter": "com.android.server.pm.test.OverlayActorVisibilityTest"
         }
       ]
+    },
+    {
+      "name": "CtsSharedUserMigrationTestCases",
+      "options": [
+        {
+          "include-filter": "android.uidmigration.cts"
+        }
+      ]
     }
   ],
   "presubmit-large": [
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
index f199841..91d2010 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
@@ -887,7 +887,9 @@
                 | flag(pkg.hasRequestForegroundServiceExemption(),
                         ApplicationInfo.PRIVATE_FLAG_EXT_REQUEST_FOREGROUND_SERVICE_EXEMPTION)
                 | flag(pkg.areAttributionsUserVisible(),
-                        ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE);
+                        ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE)
+                | flag(pkg.isOnBackInvokedCallbackEnabled(),
+                        ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK);
         // @formatter:on
         return privateFlagsExt;
     }
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index 1754877..cdc2b12 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -387,6 +387,8 @@
      */
     ParsingPackage setKnownActivityEmbeddingCerts(Set<String> knownActivityEmbeddingCerts);
 
+    ParsingPackage setOnBackInvokedCallbackEnabled(boolean enableOnBackInvokedCallback);
+
     // TODO(b/135203078): This class no longer has access to ParsedPackage, find a replacement
     //  for moving to the next step
     @CallSuper
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
index c4b1275..177eaca 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
@@ -548,6 +548,7 @@
         private static final long RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED = 1L << 48;
         private static final long SDK_LIBRARY = 1L << 49;
         private static final long INHERIT_KEYSTORE_KEYS = 1L << 50;
+        private static final long ENABLE_ON_BACK_INVOKED_CALLBACK = 1L << 51;
     }
 
     private ParsingPackageImpl setBoolean(@Booleans.Values long flag, boolean value) {
@@ -2397,6 +2398,11 @@
     }
 
     @Override
+    public boolean isOnBackInvokedCallbackEnabled() {
+        return getBoolean(Booleans.ENABLE_ON_BACK_INVOKED_CALLBACK);
+    }
+
+    @Override
     public ParsingPackageImpl setBaseRevisionCode(int value) {
         baseRevisionCode = value;
         return this;
@@ -2995,4 +3001,10 @@
         mKnownActivityEmbeddingCerts = knownEmbeddingCerts;
         return this;
     }
+
+    @Override
+    public ParsingPackage setOnBackInvokedCallbackEnabled(boolean value) {
+        setBoolean(Booleans.ENABLE_ON_BACK_INVOKED_CALLBACK, value);
+        return this;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
index 4b659a14..428374f 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
@@ -355,4 +355,9 @@
      * @see R.styleable#AndroidManifest_inheritKeyStoreKeys
      */
     boolean shouldInheritKeyStoreKeys();
+
+    /**
+     * @see R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback
+     */
+    boolean isOnBackInvokedCallbackEnabled();
 }
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index a891980..f30daa9 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -2202,8 +2202,9 @@
                 .setAutoRevokePermissions(anInt(R.styleable.AndroidManifestApplication_autoRevokePermissions, sa))
                 .setAttributionsAreUserVisible(bool(false, R.styleable.AndroidManifestApplication_attributionsAreUserVisible, sa))
                 .setResetEnabledSettingsOnAppDataCleared(bool(false,
-                    R.styleable.AndroidManifestApplication_resetEnabledSettingsOnAppDataCleared,
-                    sa))
+                        R.styleable.AndroidManifestApplication_resetEnabledSettingsOnAppDataCleared,
+                        sa))
+                .setOnBackInvokedCallbackEnabled(bool(false, R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback, sa))
                 // targetSdkVersion gated
                 .setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa))
                 .setBaseHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa))
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4b61970..4387249 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3547,6 +3547,10 @@
         if (mCameraLensCoverState == lensCoverState) {
             return;
         }
+        if (!mContext.getResources().getBoolean(
+                R.bool.config_launchCameraOnCameraLensCoverToggle)) {
+            return;
+        }
         if (mCameraLensCoverState == CAMERA_LENS_COVERED &&
                 lensCoverState == CAMERA_LENS_UNCOVERED) {
             Intent intent;
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 1856786..fd64c75 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -16,16 +16,11 @@
 
 package com.android.server.rollback;
 
-import static com.android.internal.util.FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN;
-
 import android.annotation.AnyThread;
 import android.annotation.Nullable;
 import android.annotation.WorkerThread;
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.VersionedPackage;
 import android.content.rollback.PackageRollbackInfo;
@@ -240,64 +235,6 @@
         return null;
     }
 
-    @WorkerThread
-    private BroadcastReceiver listenForStagedSessionReady(RollbackManager rollbackManager,
-            int rollbackId, @Nullable VersionedPackage logPackage) {
-        assertInWorkerThread();
-        BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                handleStagedSessionChange(rollbackManager,
-                        rollbackId, this /* BroadcastReceiver */, logPackage);
-            }
-        };
-        IntentFilter sessionUpdatedFilter =
-                new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
-        mContext.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter, null, mHandler);
-        return sessionUpdatedReceiver;
-    }
-
-    @WorkerThread
-    private void handleStagedSessionChange(RollbackManager rollbackManager, int rollbackId,
-            BroadcastReceiver listener, @Nullable VersionedPackage logPackage) {
-        assertInWorkerThread();
-        PackageInstaller packageInstaller =
-                mContext.getPackageManager().getPackageInstaller();
-        List<RollbackInfo> recentRollbacks =
-                rollbackManager.getRecentlyCommittedRollbacks();
-        for (int i = 0; i < recentRollbacks.size(); i++) {
-            RollbackInfo recentRollback = recentRollbacks.get(i);
-            int sessionId = recentRollback.getCommittedSessionId();
-            if ((rollbackId == recentRollback.getRollbackId())
-                    && (sessionId != PackageInstaller.SessionInfo.INVALID_ID)) {
-                PackageInstaller.SessionInfo sessionInfo =
-                        packageInstaller.getSessionInfo(sessionId);
-                if (sessionInfo.isStagedSessionReady() && markStagedSessionHandled(rollbackId)) {
-                    mContext.unregisterReceiver(listener);
-                    saveStagedRollbackId(rollbackId, logPackage);
-                    WatchdogRollbackLogger.logEvent(logPackage,
-                            FrameworkStatsLog
-                            .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED,
-                            WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN,
-                            "");
-                } else if (sessionInfo.isStagedSessionFailed()
-                        && markStagedSessionHandled(rollbackId)) {
-                    WatchdogRollbackLogger.logEvent(logPackage,
-                            FrameworkStatsLog
-                                    .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
-                            WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN,
-                            "");
-                    mContext.unregisterReceiver(listener);
-                }
-            }
-        }
-
-        // Wait for all pending staged sessions to get handled before rebooting.
-        if (isPendingStagedSessionsEmpty()) {
-            mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
-        }
-    }
-
     /**
      * Returns {@code true} if staged session associated with {@code rollbackId} was marked
      * as handled, {@code false} if already handled.
@@ -447,12 +384,12 @@
             if (status == RollbackManager.STATUS_SUCCESS) {
                 if (rollback.isStaged()) {
                     int rollbackId = rollback.getRollbackId();
-                    mPendingStagedRollbackIds.add(rollbackId);
-                    BroadcastReceiver listener =
-                            listenForStagedSessionReady(rollbackManager, rollbackId,
-                                    logPackage);
-                    handleStagedSessionChange(rollbackManager, rollbackId, listener,
-                            logPackage);
+                    saveStagedRollbackId(rollbackId, logPackage);
+                    WatchdogRollbackLogger.logEvent(logPackage,
+                            FrameworkStatsLog
+                            .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED,
+                            reasonToLog, failedPackageToLog);
+
                 } else {
                     WatchdogRollbackLogger.logEvent(logPackage,
                             FrameworkStatsLog
@@ -460,14 +397,18 @@
                             reasonToLog, failedPackageToLog);
                 }
             } else {
-                if (rollback.isStaged()) {
-                    markStagedSessionHandled(rollback.getRollbackId());
-                }
                 WatchdogRollbackLogger.logEvent(logPackage,
                         FrameworkStatsLog
                                 .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
                         reasonToLog, failedPackageToLog);
             }
+            if (rollback.isStaged()) {
+                markStagedSessionHandled(rollback.getRollbackId());
+                // Wait for all pending staged sessions to get handled before rebooting.
+                if (isPendingStagedSessionsEmpty()) {
+                    mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
+                }
+            }
         };
 
         final LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver(result -> {
diff --git a/services/core/java/com/android/server/sensorprivacy/PersistedState.java b/services/core/java/com/android/server/sensorprivacy/PersistedState.java
index ce9fff5..06f5fc0 100644
--- a/services/core/java/com/android/server/sensorprivacy/PersistedState.java
+++ b/services/core/java/com/android/server/sensorprivacy/PersistedState.java
@@ -295,6 +295,11 @@
                 TypeUserSensor userSensor = states.keyAt(i);
                 SensorState sensorState = states.valueAt(i);
 
+                // Do not persist hardware toggle states. Will be restored on reboot
+                if (userSensor.mType != SensorPrivacyManager.ToggleTypes.SOFTWARE) {
+                    continue;
+                }
+
                 serializer.startTag(null, XML_TAG_SENSOR_STATE);
                 serializer.attributeInt(null, XML_ATTRIBUTE_TOGGLE_TYPE,
                         userSensor.mType);
diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
index 19c8cd2..358f69e 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyService.java
@@ -39,6 +39,8 @@
 import static android.hardware.SensorPrivacyManager.Sources.QS_TILE;
 import static android.hardware.SensorPrivacyManager.Sources.SETTINGS;
 import static android.hardware.SensorPrivacyManager.Sources.SHELL;
+import static android.hardware.SensorPrivacyManager.ToggleTypes.HARDWARE;
+import static android.hardware.SensorPrivacyManager.ToggleTypes.SOFTWARE;
 import static android.os.UserHandle.USER_NULL;
 import static android.service.SensorPrivacyIndividualEnabledSensorProto.UNKNOWN;
 
@@ -108,7 +110,6 @@
 import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.Pair;
-import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.R;
@@ -127,6 +128,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Objects;
@@ -139,7 +141,7 @@
     private static final boolean DEBUG_LOGGING = false;
 
     private static final String SENSOR_PRIVACY_CHANNEL_ID = Context.SENSOR_PRIVACY_SERVICE;
-    private static final String ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY =
+    private static final String ACTION_DISABLE_TOGGLE_SENSOR_PRIVACY =
             SensorPrivacyService.class.getName() + ".action.disable_sensor_privacy";
 
     public static final int REMINDER_DIALOG_DELAY_MILLIS = 500;
@@ -273,12 +275,12 @@
             mContext.registerReceiver(new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
-                    setIndividualSensorPrivacy(
+                    setToggleSensorPrivacy(
                             ((UserHandle) intent.getParcelableExtra(
                                     Intent.EXTRA_USER)).getIdentifier(), OTHER,
                             intent.getIntExtra(EXTRA_SENSOR, UNKNOWN), false);
                 }
-            }, new IntentFilter(ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY),
+            }, new IntentFilter(ACTION_DISABLE_TOGGLE_SENSOR_PRIVACY),
                     MANAGE_SENSOR_PRIVACY, null, Context.RECEIVER_EXPORTED);
 
             mContext.registerReceiver(new BroadcastReceiver() {
@@ -299,7 +301,7 @@
             mSensorPrivacyStateController.setSensorPrivacyListener(
                     mHandler,
                     (toggleType, userId, sensor, state) -> mHandler.handleSensorPrivacyChanged(
-                            userId, sensor, state.isEnabled()));
+                            userId, toggleType, sensor, state.isEnabled()));
         }
 
         @Override
@@ -308,11 +310,11 @@
             // Reset sensor privacy when restriction is added
             if (!prevRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE)
                     && newRestrictions.getBoolean(UserManager.DISALLOW_CAMERA_TOGGLE)) {
-                setIndividualSensorPrivacyUnchecked(userId, OTHER, CAMERA, false);
+                setToggleSensorPrivacyUnchecked(SOFTWARE, userId, OTHER, CAMERA, false);
             }
             if (!prevRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE)
                     && newRestrictions.getBoolean(UserManager.DISALLOW_MICROPHONE_TOGGLE)) {
-                setIndividualSensorPrivacyUnchecked(userId, OTHER, MICROPHONE, false);
+                setToggleSensorPrivacyUnchecked(SOFTWARE, userId, OTHER, MICROPHONE, false);
             }
         }
 
@@ -352,15 +354,15 @@
         }
 
         /**
-         * Called when a sensor protected by individual sensor privacy is attempting to get used.
+         * Called when a sensor protected by toggle sensor privacy is attempting to get used.
          *
          * @param uid The uid of the app using the sensor
          * @param packageName The package name of the app using the sensor
          * @param sensor The sensor that is attempting to be used
          */
         private void onSensorUseStarted(int uid, String packageName, int sensor) {
-            UserHandle user = UserHandle.getUserHandleForUid(uid);
-            if (!isIndividualSensorPrivacyEnabled(user.getIdentifier(), sensor)) {
+            UserHandle user = UserHandle.of(mCurrentUser);
+            if (!isCombinedToggleSensorPrivacyEnabled(sensor)) {
                 return;
             }
 
@@ -371,12 +373,10 @@
             }
 
             synchronized (mLock) {
-                UserHandle parentUser = UserHandle.of(mUserManagerInternal
-                        .getProfileParentId(user.getIdentifier()));
-                if (mSuppressReminders.containsKey(new Pair<>(sensor, parentUser))) {
+                if (mSuppressReminders.containsKey(new Pair<>(sensor, user))) {
                     Log.d(TAG,
                             "Suppressed sensor privacy reminder for " + packageName + "/"
-                                    + parentUser);
+                                    + user);
                     return;
                 }
             }
@@ -406,8 +406,8 @@
                         }
 
                         tasksOfPackageUsingSensor.add(task);
-                    } else if (task.topActivity.flattenToString().equals(mContext.getResources()
-                            .getString(R.string.config_sensorUseStartedActivity))
+                    } else if (task.topActivity.flattenToString().equals(
+                            getSensorUseActivityName(new ArraySet<>(Arrays.asList(sensor))))
                             && task.isFocused) {
                         enqueueSensorUseReminderDialogAsync(task.taskId, user, packageName,
                                 sensor);
@@ -442,7 +442,7 @@
 
             String inputMethodComponent = Settings.Secure.getStringForUser(
                     mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD,
-                    mCurrentUser);
+                    user.getIdentifier());
             String inputMethodPackageName = null;
             if (inputMethodComponent != null) {
                 inputMethodPackageName = ComponentName.unflattenFromString(
@@ -534,9 +534,8 @@
                 return;
             }
             Intent dialogIntent = new Intent();
-            dialogIntent.setComponent(ComponentName.unflattenFromString(
-                    mContext.getResources().getString(
-                            R.string.config_sensorUseStartedActivity)));
+            dialogIntent.setComponent(
+                    ComponentName.unflattenFromString(getSensorUseActivityName(sensors)));
 
             ActivityOptions options = ActivityOptions.makeBasic();
             options.setLaunchTaskId(info.mTaskId);
@@ -560,6 +559,21 @@
         }
 
         /**
+         * Get the activity component based on which privacy toggles are enabled.
+         * @param sensors
+         * @return component name to launch
+         */
+        private String getSensorUseActivityName(ArraySet<Integer> sensors) {
+            for (Integer sensor : sensors) {
+                if (isToggleSensorPrivacyEnabled(HARDWARE, sensor)) {
+                    return mContext.getResources().getString(
+                            R.string.config_sensorUseStartedActivity_hwToggle);
+                }
+            }
+            return mContext.getResources().getString(R.string.config_sensorUseStartedActivity);
+        }
+
+        /**
          * Show a notification that informs the user that a sensor use or a blocked sensor started.
          * The user can then react to this event.
          *
@@ -619,7 +633,7 @@
             String actionTitle = getUiContext().getString(
                     R.string.sensor_privacy_start_use_dialog_turn_on_button);
             PendingIntent actionIntent = PendingIntent.getBroadcast(mContext, sensor,
-                    new Intent(ACTION_DISABLE_INDIVIDUAL_SENSOR_PRIVACY)
+                    new Intent(ACTION_DISABLE_TOGGLE_SENSOR_PRIVACY)
                             .setPackage(mContext.getPackageName())
                             .putExtra(EXTRA_SENSOR, sensor)
                             .putExtra(Intent.EXTRA_USER, user),
@@ -657,12 +671,12 @@
         }
 
         @Override
-        public void setIndividualSensorPrivacy(@UserIdInt int userId,
+        public void setToggleSensorPrivacy(@UserIdInt int userId,
                 @SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) {
             if (DEBUG) {
                 Log.d(TAG, "callingUid=" + Binder.getCallingUid()
                         + " callingPid=" + Binder.getCallingPid()
-                        + " setIndividualSensorPrivacy("
+                        + " setToggleSensorPrivacy("
                         + "userId=" + userId
                         + " source=" + source
                         + " sensor=" + sensor
@@ -673,22 +687,22 @@
             if (userId == UserHandle.USER_CURRENT) {
                 userId = mCurrentUser;
             }
-            if (!canChangeIndividualSensorPrivacy(userId, sensor)) {
+            if (!canChangeToggleSensorPrivacy(userId, sensor)) {
                 return;
             }
 
-            setIndividualSensorPrivacyUnchecked(userId, source, sensor, enable);
+            setToggleSensorPrivacyUnchecked(SOFTWARE, userId, source, sensor, enable);
         }
 
-        private void setIndividualSensorPrivacyUnchecked(int userId, int source, int sensor,
-                boolean enable) {
+        private void setToggleSensorPrivacyUnchecked(int toggleType, int userId, int source,
+                int sensor, boolean enable) {
             final long[] lastChange = new long[1];
             mSensorPrivacyStateController.atomic(() -> {
                 SensorState sensorState = mSensorPrivacyStateController
-                        .getState(SensorPrivacyManager.ToggleTypes.SOFTWARE, userId, sensor);
+                        .getState(toggleType, userId, sensor);
                 lastChange[0] = sensorState.getLastChange();
                 mSensorPrivacyStateController.setState(
-                        SensorPrivacyManager.ToggleTypes.SOFTWARE, userId, sensor, enable, mHandler,
+                        toggleType, userId, sensor, enable, mHandler,
                         changeSuccessful -> {
                             if (changeSuccessful) {
                                 if (userId == mUserManagerInternal.getProfileParentId(userId)) {
@@ -701,7 +715,7 @@
             });
         }
 
-        private boolean canChangeIndividualSensorPrivacy(@UserIdInt int userId, int sensor) {
+        private boolean canChangeToggleSensorPrivacy(@UserIdInt int userId, int sensor) {
             if (sensor == MICROPHONE && mCallStateHelper.isInEmergencyCall()) {
                 // During emergency call the microphone toggle managed automatically
                 Log.i(TAG, "Can't change mic toggle during an emergency call");
@@ -784,7 +798,7 @@
         }
 
         @Override
-        public void setIndividualSensorPrivacyForProfileGroup(@UserIdInt int userId,
+        public void setToggleSensorPrivacyForProfileGroup(@UserIdInt int userId,
                 @SensorPrivacyManager.Sources.Source int source, int sensor, boolean enable) {
             enforceManageSensorPrivacyPermission();
             if (userId == UserHandle.USER_CURRENT) {
@@ -793,7 +807,7 @@
             int parentId = mUserManagerInternal.getProfileParentId(userId);
             forAllUsers(userId2 -> {
                 if (parentId == mUserManagerInternal.getProfileParentId(userId2)) {
-                    setIndividualSensorPrivacy(userId2, source, sensor, enable);
+                    setToggleSensorPrivacy(userId2, source, sensor, enable);
                 }
             });
         }
@@ -835,31 +849,55 @@
         }
 
         @Override
-        public boolean isIndividualSensorPrivacyEnabled(@UserIdInt int userId, int sensor) {
+        public boolean isToggleSensorPrivacyEnabled(int toggleType, int sensor) {
             if (DEBUG) {
                 Log.d(TAG, "callingUid=" + Binder.getCallingUid()
                         + " callingPid=" + Binder.getCallingPid()
-                        + " isIndividualSensorPrivacyEnabled("
-                        + "userId=" + userId
+                        + " isToggleSensorPrivacyEnabled("
+                        + "toggleType=" + toggleType
                         + " sensor=" + sensor
                         + ")");
             }
             enforceObserveSensorPrivacyPermission();
-            if (userId == UserHandle.USER_CURRENT) {
-                userId = mCurrentUser;
-            }
-            return mSensorPrivacyStateController.getState(SensorPrivacyManager.ToggleTypes.SOFTWARE,
+
+            return mSensorPrivacyStateController.getState(toggleType, mCurrentUser, sensor)
+                    .isEnabled();
+        }
+
+        @Override
+        public boolean isCombinedToggleSensorPrivacyEnabled(int sensor) {
+            return isToggleSensorPrivacyEnabled(SOFTWARE, sensor) || isToggleSensorPrivacyEnabled(
+                    HARDWARE, sensor);
+        }
+
+        private boolean isToggleSensorPrivacyEnabledInternal(int userId, int toggleType,
+                int sensor) {
+
+            return mSensorPrivacyStateController.getState(toggleType,
                     userId, sensor).isEnabled();
         }
 
         @Override
-        public boolean supportsSensorToggle(int sensor) {
-            if (sensor == MICROPHONE) {
-                return mContext.getResources().getBoolean(R.bool.config_supportsMicToggle);
-            } else if (sensor == CAMERA) {
-                return mContext.getResources().getBoolean(R.bool.config_supportsCamToggle);
+        public boolean supportsSensorToggle(int toggleType, int sensor) {
+            if (toggleType == SOFTWARE) {
+                if (sensor == MICROPHONE) {
+                    return mContext.getResources()
+                            .getBoolean(R.bool.config_supportsMicToggle);
+                } else if (sensor == CAMERA) {
+                    return mContext.getResources()
+                            .getBoolean(R.bool.config_supportsCamToggle);
+                }
+            } else if (toggleType == SensorPrivacyManager.ToggleTypes.HARDWARE) {
+                if (sensor == MICROPHONE) {
+                    return mContext.getResources()
+                            .getBoolean(R.bool.config_supportsHardwareMicToggle);
+                } else if (sensor == CAMERA) {
+                    return mContext.getResources()
+                            .getBoolean(R.bool.config_supportsHardwareCamToggle);
+                }
             }
-            throw new IllegalArgumentException("Unable to find value " + sensor);
+            throw new IllegalArgumentException("Invalid arguments. "
+                    + "toggleType=" + toggleType + " sensor=" + sensor);
         }
 
         /**
@@ -878,29 +916,13 @@
          * Registers a listener to be notified when the sensor privacy state changes.
          */
         @Override
-        public void addIndividualSensorPrivacyListener(int userId, int sensor,
-                ISensorPrivacyListener listener) {
+        public void addToggleSensorPrivacyListener(ISensorPrivacyListener listener) {
+            Log.d("evan", "trying to add from " + Binder.getCallingUid());
             enforceObserveSensorPrivacyPermission();
             if (listener == null) {
                 throw new IllegalArgumentException("listener cannot be null");
             }
-            mHandler.addListener(userId, sensor, listener);
-        }
-
-
-        /**
-         * Registers a listener to be notified when the sensor privacy state changes. The callback
-         * can be called if the user changes and the setting is different between the transitioning
-         * users.
-         */
-        @Override
-        public void addUserGlobalIndividualSensorPrivacyListener(int sensor,
-                ISensorPrivacyListener listener) {
-            enforceObserveSensorPrivacyPermission();
-            if (listener == null) {
-                throw new IllegalArgumentException("listener cannot be null");
-            }
-            mHandler.addUserGlobalListener(sensor, listener);
+            mHandler.addToggleListener(listener);
         }
 
         /**
@@ -919,27 +941,16 @@
          * Unregisters a listener from sensor privacy state change notifications.
          */
         @Override
-        public void removeIndividualSensorPrivacyListener(int sensor,
-                ISensorPrivacyListener listener) {
+        public void removeToggleSensorPrivacyListener(ISensorPrivacyListener listener) {
             enforceObserveSensorPrivacyPermission();
             if (listener == null) {
                 throw new IllegalArgumentException("listener cannot be null");
             }
-            mHandler.removeListener(sensor, listener);
+            mHandler.removeToggleListener(listener);
         }
 
         @Override
-        public void removeUserGlobalIndividualSensorPrivacyListener(int sensor,
-                ISensorPrivacyListener listener) {
-            enforceObserveSensorPrivacyPermission();
-            if (listener == null) {
-                throw new IllegalArgumentException("listener cannot be null");
-            }
-            mHandler.removeUserGlobalListener(sensor, listener);
-        }
-
-        @Override
-        public void suppressIndividualSensorPrivacyReminders(int userId, int sensor,
+        public void suppressToggleSensorPrivacyReminders(int userId, int sensor,
                 IBinder token, boolean suppress) {
             enforceManageSensorPrivacyPermission();
             if (userId == UserHandle.USER_CURRENT) {
@@ -976,7 +987,7 @@
             if (Binder.getCallingUid() != Process.SYSTEM_UID) {
                 throw new SecurityException("Can only be called by the system uid");
             }
-            if (!isIndividualSensorPrivacyEnabled(mCurrentUser, sensor)) {
+            if (!isCombinedToggleSensorPrivacyEnabled(sensor)) {
                 return;
             }
             enqueueSensorUseReminderDialogAsync(
@@ -984,23 +995,46 @@
         }
 
         private void userSwitching(int from, int to) {
-            final boolean[] micState = new boolean[1];
-            final boolean[] camState = new boolean[1];
-            final boolean[] prevMicState = new boolean[1];
-            final boolean[] prevCamState = new boolean[1];
+            final boolean[] micState = new boolean[2];
+            final boolean[] camState = new boolean[2];
+            final boolean[] prevMicState = new boolean[2];
+            final boolean[] prevCamState = new boolean[2];
+            final int swToggleIdx = 0;
+            final int hwToggleIdx = 1;
+            // Get SW toggles state
             mSensorPrivacyStateController.atomic(() -> {
-                prevMicState[0] = isIndividualSensorPrivacyEnabled(from, MICROPHONE);
-                prevCamState[0] = isIndividualSensorPrivacyEnabled(from, CAMERA);
-                micState[0] = isIndividualSensorPrivacyEnabled(to, MICROPHONE);
-                camState[0] = isIndividualSensorPrivacyEnabled(to, CAMERA);
+                prevMicState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, SOFTWARE,
+                        MICROPHONE);
+                prevCamState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, SOFTWARE,
+                        CAMERA);
+                micState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, SOFTWARE,
+                        MICROPHONE);
+                camState[swToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, SOFTWARE, CAMERA);
             });
-            if (from == USER_NULL || prevMicState[0] != micState[0]) {
-                mHandler.onUserGlobalSensorPrivacyChanged(MICROPHONE, micState[0]);
-                setGlobalRestriction(MICROPHONE, micState[0]);
+            // Get HW toggles state
+            mSensorPrivacyStateController.atomic(() -> {
+                prevMicState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, HARDWARE,
+                        MICROPHONE);
+                prevCamState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(from, HARDWARE,
+                        CAMERA);
+                micState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, HARDWARE,
+                        MICROPHONE);
+                camState[hwToggleIdx] = isToggleSensorPrivacyEnabledInternal(to, HARDWARE, CAMERA);
+            });
+
+            if (from == USER_NULL || prevMicState[swToggleIdx] != micState[swToggleIdx]
+                    || prevMicState[hwToggleIdx] != micState[hwToggleIdx]) {
+                mHandler.handleSensorPrivacyChanged(to, SOFTWARE, MICROPHONE,
+                        micState[swToggleIdx]);
+                mHandler.handleSensorPrivacyChanged(to, HARDWARE, MICROPHONE,
+                        micState[hwToggleIdx]);
+                setGlobalRestriction(MICROPHONE, micState[swToggleIdx] || micState[hwToggleIdx]);
             }
-            if (from == USER_NULL || prevCamState[0] != camState[0]) {
-                mHandler.onUserGlobalSensorPrivacyChanged(CAMERA, camState[0]);
-                setGlobalRestriction(CAMERA, camState[0]);
+            if (from == USER_NULL || prevCamState[swToggleIdx] != camState[swToggleIdx]
+                    || prevCamState[hwToggleIdx] != camState[hwToggleIdx]) {
+                mHandler.handleSensorPrivacyChanged(to, SOFTWARE, CAMERA, camState[swToggleIdx]);
+                mHandler.handleSensorPrivacyChanged(to, HARDWARE, CAMERA, camState[hwToggleIdx]);
+                setGlobalRestriction(CAMERA, camState[swToggleIdx] || camState[hwToggleIdx]);
             }
         }
 
@@ -1153,7 +1187,7 @@
                                 return -1;
                             }
 
-                            setIndividualSensorPrivacy(userId, SHELL, sensor, true);
+                            setToggleSensorPrivacy(userId, SHELL, sensor, true);
                         }
                         break;
                         case "disable" : {
@@ -1163,7 +1197,7 @@
                                 return -1;
                             }
 
-                            setIndividualSensorPrivacy(userId, SHELL, sensor, false);
+                            setToggleSensorPrivacy(userId, SHELL, sensor, false);
                         }
                         break;
                         default:
@@ -1205,11 +1239,8 @@
         private final RemoteCallbackList<ISensorPrivacyListener> mListeners =
                 new RemoteCallbackList<>();
         @GuardedBy("mListenerLock")
-        private final SparseArray<SparseArray<RemoteCallbackList<ISensorPrivacyListener>>>
-                mIndividualSensorListeners = new SparseArray<>();
-        @GuardedBy("mListenerLock")
-        private final SparseArray<RemoteCallbackList<ISensorPrivacyListener>>
-                mUserGlobalIndividualSensorListeners = new SparseArray<>();
+        private final RemoteCallbackList<ISensorPrivacyListener>
+                mToggleSensorListeners = new RemoteCallbackList<>();
         @GuardedBy("mListenerLock")
         private final ArrayMap<ISensorPrivacyListener, Pair<DeathRecipient, Integer>>
                 mDeathRecipients;
@@ -1221,12 +1252,6 @@
             mContext = context;
         }
 
-        public void onUserGlobalSensorPrivacyChanged(int sensor, boolean enabled) {
-            sendMessage(PooledLambda.obtainMessage(
-                    SensorPrivacyHandler::handleUserGlobalSensorPrivacyChanged,
-                    this, sensor, enabled));
-        }
-
         public void addListener(ISensorPrivacyListener listener) {
             synchronized (mListenerLock) {
                 if (mListeners.register(listener)) {
@@ -1235,34 +1260,9 @@
             }
         }
 
-        public void addListener(int userId, int sensor, ISensorPrivacyListener listener) {
+        public void addToggleListener(ISensorPrivacyListener listener) {
             synchronized (mListenerLock) {
-                SparseArray<RemoteCallbackList<ISensorPrivacyListener>> listenersForUser =
-                        mIndividualSensorListeners.get(userId);
-                if (listenersForUser == null) {
-                    listenersForUser = new SparseArray<>();
-                    mIndividualSensorListeners.put(userId, listenersForUser);
-                }
-                RemoteCallbackList<ISensorPrivacyListener> listeners = listenersForUser.get(sensor);
-                if (listeners == null) {
-                    listeners = new RemoteCallbackList<>();
-                    listenersForUser.put(sensor, listeners);
-                }
-                if (listeners.register(listener)) {
-                    addDeathRecipient(listener);
-                }
-            }
-        }
-
-        public void addUserGlobalListener(int sensor, ISensorPrivacyListener listener) {
-            synchronized (mListenerLock) {
-                RemoteCallbackList<ISensorPrivacyListener> listeners =
-                        mUserGlobalIndividualSensorListeners.get(sensor);
-                if (listeners == null) {
-                    listeners = new RemoteCallbackList<>();
-                    mUserGlobalIndividualSensorListeners.put(sensor, listeners);
-                }
-                if (listeners.register(listener)) {
+                if (mToggleSensorListeners.register(listener)) {
                     addDeathRecipient(listener);
                 }
             }
@@ -1276,28 +1276,10 @@
             }
         }
 
-        public void removeListener(int sensor, ISensorPrivacyListener listener) {
+        public void removeToggleListener(ISensorPrivacyListener listener) {
             synchronized (mListenerLock) {
-                for (int i = 0, numUsers = mIndividualSensorListeners.size(); i < numUsers; i++) {
-                    RemoteCallbackList callbacks =
-                            mIndividualSensorListeners.valueAt(i).get(sensor);
-                    if (callbacks != null) {
-                        if (callbacks.unregister(listener)) {
-                            removeDeathRecipient(listener);
-                        }
-                    }
-                }
-            }
-        }
-
-        public void removeUserGlobalListener(int sensor, ISensorPrivacyListener listener) {
-            synchronized (mListenerLock) {
-                RemoteCallbackList callbacks =
-                        mUserGlobalIndividualSensorListeners.get(sensor);
-                if (callbacks != null) {
-                    if (callbacks.unregister(listener)) {
-                        removeDeathRecipient(listener);
-                    }
+                if (mToggleSensorListeners.unregister(listener)) {
+                    removeDeathRecipient(listener);
                 }
             }
         }
@@ -1307,7 +1289,7 @@
             for (int i = 0; i < count; i++) {
                 ISensorPrivacyListener listener = mListeners.getBroadcastItem(i);
                 try {
-                    listener.onSensorPrivacyChanged(enabled);
+                    listener.onSensorPrivacyChanged(-1, -1, enabled);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e);
                 }
@@ -1315,62 +1297,34 @@
             mListeners.finishBroadcast();
         }
 
-        public void handleSensorPrivacyChanged(int userId, int sensor, boolean enabled) {
-            // TODO handle hardware
+        public void handleSensorPrivacyChanged(int userId, int toggleType, int sensor,
+                boolean enabled) {
             mSensorPrivacyManagerInternal.dispatch(userId, sensor, enabled);
-            SparseArray<RemoteCallbackList<ISensorPrivacyListener>> listenersForUser =
-                    mIndividualSensorListeners.get(userId);
 
             if (userId == mCurrentUser) {
-                mSensorPrivacyServiceImpl.setGlobalRestriction(sensor, enabled);
+                mSensorPrivacyServiceImpl.setGlobalRestriction(sensor,
+                        mSensorPrivacyServiceImpl.isCombinedToggleSensorPrivacyEnabled(sensor));
             }
 
-            if (userId == mCurrentUser) {
-                onUserGlobalSensorPrivacyChanged(sensor, enabled);
-            }
-
-            if (listenersForUser == null) {
+            if (userId != mCurrentUser) {
                 return;
             }
-            RemoteCallbackList<ISensorPrivacyListener> listeners = listenersForUser.get(sensor);
-            if (listeners == null) {
-                return;
-            }
-            try {
-                final int count = listeners.beginBroadcast();
-                for (int i = 0; i < count; i++) {
-                    ISensorPrivacyListener listener = listeners.getBroadcastItem(i);
-                    try {
-                        listener.onSensorPrivacyChanged(enabled);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e);
+            synchronized (mListenerLock) {
+                try {
+                    final int count = mToggleSensorListeners.beginBroadcast();
+                    for (int i = 0; i < count; i++) {
+                        ISensorPrivacyListener listener = mToggleSensorListeners.getBroadcastItem(
+                                i);
+                        try {
+                            listener.onSensorPrivacyChanged(toggleType, sensor, enabled);
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Caught an exception notifying listener " + listener + ": ",
+                                    e);
+                        }
                     }
+                } finally {
+                    mToggleSensorListeners.finishBroadcast();
                 }
-            } finally {
-                listeners.finishBroadcast();
-            }
-        }
-
-        public void handleUserGlobalSensorPrivacyChanged(int sensor, boolean enabled) {
-            RemoteCallbackList<ISensorPrivacyListener> listeners =
-                    mUserGlobalIndividualSensorListeners.get(sensor);
-
-            if (listeners == null) {
-                return;
-            }
-
-            try {
-                final int count = listeners.beginBroadcast();
-                for (int i = 0; i < count; i++) {
-                    ISensorPrivacyListener listener = listeners.getBroadcastItem(i);
-                    try {
-                        listener.onSensorPrivacyChanged(enabled);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Caught an exception notifying listener " + listener + ": ", e);
-                    }
-                }
-            } finally {
-                listeners.finishBroadcast();
             }
         }
 
@@ -1482,7 +1436,8 @@
         @Override
         public boolean isSensorPrivacyEnabled(int userId, int sensor) {
             return SensorPrivacyService.this
-                    .mSensorPrivacyServiceImpl.isIndividualSensorPrivacyEnabled(userId, sensor);
+                    .mSensorPrivacyServiceImpl.isToggleSensorPrivacyEnabledInternal(userId,
+                            SOFTWARE, sensor);
         }
 
         @Override
@@ -1521,6 +1476,23 @@
                 sensorListeners.add(listener);
             }
         }
+
+        @Override
+        public void setPhysicalToggleSensorPrivacy(int userId, int sensor, boolean enable) {
+            final SensorPrivacyServiceImpl sps =
+                    SensorPrivacyService.this.mSensorPrivacyServiceImpl;
+
+            // Convert userId to actual user Id. mCurrentUser is USER_NULL if toggle state is set
+            // before onUserStarting.
+            userId = (userId == UserHandle.USER_CURRENT ? mCurrentUser : userId);
+            final int realUserId = (userId == UserHandle.USER_NULL ? mContext.getUserId() : userId);
+
+            sps.setToggleSensorPrivacyUnchecked(HARDWARE, realUserId, OTHER, sensor, enable);
+            // Also disable the SW toggle when disabling the HW toggle
+            if (!enable) {
+                sps.setToggleSensorPrivacyUnchecked(SOFTWARE, realUserId, OTHER, sensor, enable);
+            }
+        }
     }
 
     private class CallStateHelper {
@@ -1574,9 +1546,9 @@
                 if (!mIsInEmergencyCall) {
                     mIsInEmergencyCall = true;
                     if (mSensorPrivacyServiceImpl
-                            .isIndividualSensorPrivacyEnabled(mCurrentUser, MICROPHONE)) {
-                        mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked(
-                                mCurrentUser, OTHER, MICROPHONE, false);
+                            .isToggleSensorPrivacyEnabled(SOFTWARE, MICROPHONE)) {
+                        mSensorPrivacyServiceImpl.setToggleSensorPrivacyUnchecked(
+                                SOFTWARE, mCurrentUser, OTHER, MICROPHONE, false);
                         mMicUnmutedForEmergencyCall = true;
                     } else {
                         mMicUnmutedForEmergencyCall = false;
@@ -1601,8 +1573,8 @@
                 if (mIsInEmergencyCall) {
                     mIsInEmergencyCall = false;
                     if (mMicUnmutedForEmergencyCall) {
-                        mSensorPrivacyServiceImpl.setIndividualSensorPrivacyUnchecked(
-                                mCurrentUser, OTHER, MICROPHONE, true);
+                        mSensorPrivacyServiceImpl.setToggleSensorPrivacyUnchecked(
+                                SOFTWARE, mCurrentUser, OTHER, MICROPHONE, true);
                         mMicUnmutedForEmergencyCall = false;
                     }
                 }
diff --git a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyStateControllerImpl.java b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyStateControllerImpl.java
index d1ea8e9..3dcb4cf 100644
--- a/services/core/java/com/android/server/sensorprivacy/SensorPrivacyStateControllerImpl.java
+++ b/services/core/java/com/android/server/sensorprivacy/SensorPrivacyStateControllerImpl.java
@@ -16,7 +16,6 @@
 
 package com.android.server.sensorprivacy;
 
-import android.hardware.SensorPrivacyManager;
 import android.os.Handler;
 
 import com.android.internal.util.dump.DualDumpOutputStream;
@@ -49,10 +48,6 @@
 
     @Override
     SensorState getStateLocked(int toggleType, int userId, int sensor) {
-        if (toggleType == SensorPrivacyManager.ToggleTypes.HARDWARE) {
-            // Device doesn't support hardware state
-            return getDefaultSensorState();
-        }
         SensorState sensorState = mPersistedState.getState(toggleType, userId, sensor);
         if (sensorState != null) {
             return new SensorState(sensorState);
@@ -67,12 +62,6 @@
     @Override
     void setStateLocked(int toggleType, int userId, int sensor, boolean enabled,
             Handler callbackHandler, SetStateResultCallback callback) {
-        if (toggleType != SensorPrivacyManager.ToggleTypes.SOFTWARE) {
-            // Implementation only supports software switch
-            callbackHandler.sendMessage(PooledLambda.obtainMessage(
-                    SetStateResultCallback::callback, callback, false));
-            return;
-        }
         // Changing the SensorState's mEnabled updates the timestamp of its last change.
         // A nonexistent state -> unmuted should not set the timestamp.
         SensorState lastState = mPersistedState.getState(toggleType, userId, sensor);
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index adee325..8ec0556 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -15,7 +15,6 @@
  */
 
 package com.android.server.stats.pull;
-
 import static android.app.AppOpsManager.OP_FLAG_SELF;
 import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
@@ -74,6 +73,7 @@
 import android.app.AppOpsManager.HistoricalPackageOps;
 import android.app.AppOpsManager.HistoricalUidOps;
 import android.app.INotificationManager;
+import android.app.PendingIntentStats;
 import android.app.ProcessMemoryState;
 import android.app.RuntimeAppOpAccessMessage;
 import android.app.StatsManager;
@@ -727,6 +727,8 @@
                         return pullAccessibilityFloatingMenuStatsLocked(atomTag, data);
                     case FrameworkStatsLog.MEDIA_CAPABILITIES:
                         return pullMediaCapabilitiesStats(atomTag, data);
+                    case FrameworkStatsLog.PENDING_INTENTS_PER_PACKAGE:
+                        return pullPendingIntentsPerPackage(atomTag, data);
                     default:
                         throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
                 }
@@ -923,6 +925,7 @@
         registerAccessibilityShortcutStats();
         registerAccessibilityFloatingMenuStats();
         registerMediaCapabilitiesStats();
+        registerPendingIntentsPerPackagePuller();
     }
 
     private void initAndRegisterNetworkStatsPullers() {
@@ -1072,7 +1075,7 @@
     private void registerWifiBytesTransfer() {
         int tagId = FrameworkStatsLog.WIFI_BYTES_TRANSFER;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {2, 3, 4, 5})
+                .setAdditiveFields(new int[]{2, 3, 4, 5})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -1085,12 +1088,12 @@
     @NonNull
     private List<NetworkStatsExt> collectNetworkStatsSnapshotForAtom(int atomTag) {
         List<NetworkStatsExt> ret = new ArrayList<>();
-        switch(atomTag) {
+        switch (atomTag) {
             case FrameworkStatsLog.WIFI_BYTES_TRANSFER: {
                 final NetworkStats stats = getUidNetworkStatsSnapshotForTransport(TRANSPORT_WIFI);
                 if (stats != null) {
                     ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats),
-                            new int[] {TRANSPORT_WIFI}, /*slicedByFgbg=*/false));
+                            new int[]{TRANSPORT_WIFI}, /*slicedByFgbg=*/false));
                 }
                 break;
             }
@@ -1098,7 +1101,7 @@
                 final NetworkStats stats = getUidNetworkStatsSnapshotForTransport(TRANSPORT_WIFI);
                 if (stats != null) {
                     ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
-                                    new int[] {TRANSPORT_WIFI}, /*slicedByFgbg=*/true));
+                            new int[]{TRANSPORT_WIFI}, /*slicedByFgbg=*/true));
                 }
                 break;
             }
@@ -1107,7 +1110,7 @@
                         getUidNetworkStatsSnapshotForTransport(TRANSPORT_CELLULAR);
                 if (stats != null) {
                     ret.add(new NetworkStatsExt(sliceNetworkStatsByUid(stats),
-                                    new int[] {TRANSPORT_CELLULAR}, /*slicedByFgbg=*/false));
+                            new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/false));
                 }
                 break;
             }
@@ -1116,7 +1119,7 @@
                         getUidNetworkStatsSnapshotForTransport(TRANSPORT_CELLULAR);
                 if (stats != null) {
                     ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
-                                    new int[] {TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true));
+                            new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true));
                 }
                 break;
             }
@@ -1125,11 +1128,11 @@
                         new NetworkTemplate.Builder(MATCH_WIFI).build(), /*includeTags=*/true);
                 final NetworkStats cellularStats = getUidNetworkStatsSnapshotForTemplate(
                         new NetworkTemplate.Builder(MATCH_MOBILE)
-                        .setMeteredness(METERED_YES).build(), /*includeTags=*/true);
+                                .setMeteredness(METERED_YES).build(), /*includeTags=*/true);
                 if (wifiStats != null && cellularStats != null) {
                     final NetworkStats stats = wifiStats.add(cellularStats);
                     ret.add(new NetworkStatsExt(sliceNetworkStatsByUidTagAndMetered(stats),
-                            new int[] {TRANSPORT_WIFI, TRANSPORT_CELLULAR},
+                            new int[]{TRANSPORT_WIFI, TRANSPORT_CELLULAR},
                             /*slicedByFgbg=*/false, /*slicedByTag=*/true,
                             /*slicedByMetered=*/true, TelephonyManager.NETWORK_TYPE_UNKNOWN,
                             /*subInfo=*/null, OEM_MANAGED_ALL));
@@ -1196,7 +1199,8 @@
         return StatsManager.PULL_SUCCESS;
     }
 
-    @NonNull private static NetworkStats removeEmptyEntries(NetworkStats stats) {
+    @NonNull
+    private static NetworkStats removeEmptyEntries(NetworkStats stats) {
         NetworkStats ret = new NetworkStats(0, 1);
         for (NetworkStats.Entry e : stats) {
             if (e.getRxBytes() != 0 || e.getRxPackets() != 0 || e.getTxBytes() != 0
@@ -1278,13 +1282,14 @@
         }
     }
 
-    @NonNull private List<NetworkStatsExt> getDataUsageBytesTransferSnapshotForOemManaged() {
+    @NonNull
+    private List<NetworkStatsExt> getDataUsageBytesTransferSnapshotForOemManaged() {
         final List<Pair<Integer, Integer>> matchRulesAndTransports = List.of(
                 new Pair(MATCH_ETHERNET, TRANSPORT_ETHERNET),
                 new Pair(MATCH_MOBILE, TRANSPORT_CELLULAR),
                 new Pair(MATCH_WIFI, TRANSPORT_WIFI)
         );
-        final int[] oemManagedTypes = new int[] {OEM_MANAGED_PAID | OEM_MANAGED_PRIVATE,
+        final int[] oemManagedTypes = new int[]{OEM_MANAGED_PAID | OEM_MANAGED_PRIVATE,
                 OEM_MANAGED_PAID, OEM_MANAGED_PRIVATE};
 
         final List<NetworkStatsExt> ret = new ArrayList<>();
@@ -1301,7 +1306,7 @@
                 final Integer transport = ruleAndTransport.second;
                 if (stats != null) {
                     ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats),
-                            new int[] {transport}, /*slicedByFgbg=*/true, /*slicedByTag=*/false,
+                            new int[]{transport}, /*slicedByFgbg=*/true, /*slicedByTag=*/false,
                             /*slicedByMetered=*/false, TelephonyManager.NETWORK_TYPE_UNKNOWN,
                             /*subInfo=*/null, oemManaged));
                 }
@@ -1314,7 +1319,8 @@
     /**
      * Create a snapshot of NetworkStats for a given transport.
      */
-    @Nullable private NetworkStats getUidNetworkStatsSnapshotForTransport(int transport) {
+    @Nullable
+    private NetworkStats getUidNetworkStatsSnapshotForTransport(int transport) {
         NetworkTemplate template = null;
         switch (transport) {
             case TRANSPORT_CELLULAR:
@@ -1336,7 +1342,8 @@
      * Note that this should be only used to calculate diff since the snapshot might contains
      * some traffic before boot.
      */
-    @Nullable private NetworkStats getUidNetworkStatsSnapshotForTemplate(
+    @Nullable
+    private NetworkStats getUidNetworkStatsSnapshotForTemplate(
             @NonNull NetworkTemplate template, boolean includeTags) {
         final long elapsedMillisSinceBoot = SystemClock.elapsedRealtime();
         final long currentTimeInMillis = MICROSECONDS.toMillis(SystemClock.currentTimeMicro());
@@ -1354,8 +1361,8 @@
 
         final android.app.usage.NetworkStats queryNonTaggedStats =
                 mNetworkStatsManager.querySummary(
-                template, currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
-                currentTimeInMillis);
+                        template, currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
+                        currentTimeInMillis);
 
         final NetworkStats nonTaggedStats =
                 NetworkStatsUtils.fromPublicNetworkStats(queryNonTaggedStats);
@@ -1363,27 +1370,28 @@
 
         final android.app.usage.NetworkStats queryTaggedStats =
                 mNetworkStatsManager.queryTaggedSummary(template,
-                currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
-                currentTimeInMillis);
+                        currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
+                        currentTimeInMillis);
         final NetworkStats taggedStats =
                 NetworkStatsUtils.fromPublicNetworkStats(queryTaggedStats);
         return nonTaggedStats.add(taggedStats);
     }
 
-    @NonNull private List<NetworkStatsExt> getDataUsageBytesTransferSnapshotForSub(
+    @NonNull
+    private List<NetworkStatsExt> getDataUsageBytesTransferSnapshotForSub(
             @NonNull SubInfo subInfo) {
         final List<NetworkStatsExt> ret = new ArrayList<>();
         for (final int ratType : getAllCollapsedRatTypes()) {
             final NetworkTemplate template =
                     new NetworkTemplate.Builder(MATCH_MOBILE)
-                    .setSubscriberIds(Set.of(subInfo.subscriberId))
-                    .setRatType(ratType)
-                    .setMeteredness(METERED_YES).build();
+                            .setSubscriberIds(Set.of(subInfo.subscriberId))
+                            .setRatType(ratType)
+                            .setMeteredness(METERED_YES).build();
             final NetworkStats stats =
                     getUidNetworkStatsSnapshotForTemplate(template, /*includeTags=*/false);
             if (stats != null) {
                 ret.add(new NetworkStatsExt(sliceNetworkStatsByFgbg(stats),
-                        new int[] {TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true,
+                        new int[]{TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true,
                         /*slicedByTag=*/false, /*slicedByMetered=*/false, ratType, subInfo,
                         OEM_MANAGED_ALL));
             }
@@ -1412,51 +1420,55 @@
         return com.android.net.module.util.CollectionUtils.toIntArray(collapsedRatTypes);
     }
 
-    @NonNull private NetworkStats sliceNetworkStatsByUid(@NonNull NetworkStats stats) {
+    @NonNull
+    private NetworkStats sliceNetworkStatsByUid(@NonNull NetworkStats stats) {
         return sliceNetworkStats(stats,
                 (entry) -> {
-                        return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
-                                NetworkStats.SET_ALL, NetworkStats.TAG_NONE,
-                                NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
-                                NetworkStats.DEFAULT_NETWORK_ALL,
-                                entry.getRxBytes(), entry.getRxPackets(),
-                                entry.getTxBytes(), entry.getTxPackets(), 0);
+                    return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
+                            NetworkStats.SET_ALL, NetworkStats.TAG_NONE,
+                            NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
+                            NetworkStats.DEFAULT_NETWORK_ALL,
+                            entry.getRxBytes(), entry.getRxPackets(),
+                            entry.getTxBytes(), entry.getTxPackets(), 0);
                 });
     }
 
-    @NonNull private NetworkStats sliceNetworkStatsByFgbg(@NonNull NetworkStats stats) {
+    @NonNull
+    private NetworkStats sliceNetworkStatsByFgbg(@NonNull NetworkStats stats) {
         return sliceNetworkStats(stats,
                 (entry) -> {
-                        return new NetworkStats.Entry(null /* IFACE_ALL */, NetworkStats.UID_ALL,
-                                entry.getSet(), NetworkStats.TAG_NONE,
-                                NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
-                                NetworkStats.DEFAULT_NETWORK_ALL,
-                                entry.getRxBytes(), entry.getRxPackets(),
-                                entry.getTxBytes(), entry.getTxPackets(), 0);
+                    return new NetworkStats.Entry(null /* IFACE_ALL */, NetworkStats.UID_ALL,
+                            entry.getSet(), NetworkStats.TAG_NONE,
+                            NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
+                            NetworkStats.DEFAULT_NETWORK_ALL,
+                            entry.getRxBytes(), entry.getRxPackets(),
+                            entry.getTxBytes(), entry.getTxPackets(), 0);
                 });
     }
 
-    @NonNull private NetworkStats sliceNetworkStatsByUidAndFgbg(@NonNull NetworkStats stats) {
+    @NonNull
+    private NetworkStats sliceNetworkStatsByUidAndFgbg(@NonNull NetworkStats stats) {
         return sliceNetworkStats(stats,
                 (entry) -> {
-                        return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
-                                entry.getSet(), NetworkStats.TAG_NONE,
-                                NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
-                                NetworkStats.DEFAULT_NETWORK_ALL,
-                                entry.getRxBytes(), entry.getRxPackets(),
-                                entry.getTxBytes(), entry.getTxPackets(), 0);
+                    return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
+                            entry.getSet(), NetworkStats.TAG_NONE,
+                            NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
+                            NetworkStats.DEFAULT_NETWORK_ALL,
+                            entry.getRxBytes(), entry.getRxPackets(),
+                            entry.getTxBytes(), entry.getTxPackets(), 0);
                 });
     }
 
-    @NonNull private NetworkStats sliceNetworkStatsByUidTagAndMetered(@NonNull NetworkStats stats) {
+    @NonNull
+    private NetworkStats sliceNetworkStatsByUidTagAndMetered(@NonNull NetworkStats stats) {
         return sliceNetworkStats(stats,
                 (entry) -> {
-                        return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
-                                NetworkStats.SET_ALL, entry.getTag(),
-                                entry.getMetered(), NetworkStats.ROAMING_ALL,
-                                NetworkStats.DEFAULT_NETWORK_ALL,
-                                entry.getRxBytes(), entry.getRxPackets(),
-                                entry.getTxBytes(), entry.getTxPackets(), 0);
+                    return new NetworkStats.Entry(null /* IFACE_ALL */, entry.getUid(),
+                            NetworkStats.SET_ALL, entry.getTag(),
+                            entry.getMetered(), NetworkStats.ROAMING_ALL,
+                            NetworkStats.DEFAULT_NETWORK_ALL,
+                            entry.getRxBytes(), entry.getRxPackets(),
+                            entry.getTxBytes(), entry.getTxPackets(), 0);
                 });
     }
 
@@ -1472,17 +1484,18 @@
      *               get the state from entry to replace the default value.
      *               This is useful for slicing by particular dimensions. For example, if we wished
      *               to slice by uid and tag, we could write the following lambda:
-     *                  (entry) -> {
-     *                   return new NetworkStats.Entry(null, entry.getUid(),
-     *                           NetworkStats.SET_ALL, entry.getTag(),
-     *                           NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
-     *                           NetworkStats.DEFAULT_NETWORK_ALL,
-     *                           entry.getRxBytes(), entry.getRxPackets(),
-     *                           entry.getTxBytes(), entry.getTxPackets(), 0);
-     *                  }
+     *               (entry) -> {
+     *               return new NetworkStats.Entry(null, entry.getUid(),
+     *               NetworkStats.SET_ALL, entry.getTag(),
+     *               NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL,
+     *               NetworkStats.DEFAULT_NETWORK_ALL,
+     *               entry.getRxBytes(), entry.getRxPackets(),
+     *               entry.getTxBytes(), entry.getTxPackets(), 0);
+     *               }
      * @return new NeworkStats object appropriately sliced
      */
-    @NonNull private NetworkStats sliceNetworkStats(@NonNull NetworkStats stats,
+    @NonNull
+    private NetworkStats sliceNetworkStats(@NonNull NetworkStats stats,
             @NonNull Function<NetworkStats.Entry, NetworkStats.Entry> slicer) {
         NetworkStats ret = new NetworkStats(0, 1);
         for (NetworkStats.Entry e : stats) {
@@ -1494,7 +1507,7 @@
     private void registerWifiBytesTransferBackground() {
         int tagId = FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {3, 4, 5, 6})
+                .setAdditiveFields(new int[]{3, 4, 5, 6})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -1507,7 +1520,7 @@
     private void registerMobileBytesTransfer() {
         int tagId = FrameworkStatsLog.MOBILE_BYTES_TRANSFER;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {2, 3, 4, 5})
+                .setAdditiveFields(new int[]{2, 3, 4, 5})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -1520,7 +1533,7 @@
     private void registerMobileBytesTransferBackground() {
         int tagId = FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {3, 4, 5, 6})
+                .setAdditiveFields(new int[]{3, 4, 5, 6})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -1533,7 +1546,7 @@
     private void registerBytesTransferByTagAndMetered() {
         int tagId = FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {4, 5, 6, 7})
+                .setAdditiveFields(new int[]{4, 5, 6, 7})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -1546,7 +1559,7 @@
     private void registerDataUsageBytesTransfer() {
         int tagId = FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {2, 3, 4, 5})
+                .setAdditiveFields(new int[]{2, 3, 4, 5})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -1559,7 +1572,7 @@
     private void registerOemManagedBytesTransfer() {
         int tagId = FrameworkStatsLog.OEM_MANAGED_BYTES_TRANSFER;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {5, 6, 7, 8})
+                .setAdditiveFields(new int[]{5, 6, 7, 8})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -1572,7 +1585,7 @@
     private void registerBluetoothBytesTransfer() {
         int tagId = FrameworkStatsLog.BLUETOOTH_BYTES_TRANSFER;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {2, 3})
+                .setAdditiveFields(new int[]{2, 3})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -1661,7 +1674,7 @@
         if (KernelCpuBpfTracking.isSupported()) {
             int tagId = FrameworkStatsLog.CPU_TIME_PER_CLUSTER_FREQ;
             PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                    .setAdditiveFields(new int[] {3})
+                    .setAdditiveFields(new int[]{3})
                     .build();
             mStatsManager.setPullAtomCallback(
                     tagId,
@@ -1691,7 +1704,7 @@
     private void registerCpuTimePerUid() {
         int tagId = FrameworkStatsLog.CPU_TIME_PER_UID;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {2, 3})
+                .setAdditiveFields(new int[]{2, 3})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -1716,7 +1729,7 @@
         if (KernelCpuBpfTracking.isSupported() || KernelCpuBpfTracking.getClusters() > 0) {
             int tagId = FrameworkStatsLog.CPU_CYCLES_PER_UID_CLUSTER;
             PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                    .setAdditiveFields(new int[] {3, 4, 5})
+                    .setAdditiveFields(new int[]{3, 4, 5})
                     .build();
             mStatsManager.setPullAtomCallback(
                     tagId,
@@ -1801,7 +1814,7 @@
         // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
         int tagId = FrameworkStatsLog.CPU_TIME_PER_UID_FREQ;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {3})
+                .setAdditiveFields(new int[]{3})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -1855,7 +1868,7 @@
         if (KernelCpuBpfTracking.isSupported()) {
             int tagId = FrameworkStatsLog.CPU_CYCLES_PER_THREAD_GROUP_CLUSTER;
             PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                    .setAdditiveFields(new int[] {3, 4})
+                    .setAdditiveFields(new int[]{3, 4})
                     .build();
             mStatsManager.setPullAtomCallback(
                     tagId,
@@ -1918,7 +1931,7 @@
         // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
         int tagId = FrameworkStatsLog.CPU_ACTIVE_TIME;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {2})
+                .setAdditiveFields(new int[]{2})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -1940,7 +1953,7 @@
         // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
         int tagId = FrameworkStatsLog.CPU_CLUSTER_TIME;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {3})
+                .setAdditiveFields(new int[]{3})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -2127,7 +2140,7 @@
     private void registerProcessMemoryState() {
         int tagId = FrameworkStatsLog.PROCESS_MEMORY_STATE;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {4, 5, 6, 7, 8})
+                .setAdditiveFields(new int[]{4, 5, 6, 7, 8})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -2485,7 +2498,7 @@
     private void registerBinderCallsStats() {
         int tagId = FrameworkStatsLog.BINDER_CALLS;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {4, 5, 6, 8, 12})
+                .setAdditiveFields(new int[]{4, 5, 6, 8, 12})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -2547,7 +2560,7 @@
     private void registerLooperStats() {
         int tagId = FrameworkStatsLog.LOOPER_STATS;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {5, 6, 7, 8, 9})
+                .setAdditiveFields(new int[]{5, 6, 7, 8, 9})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -2922,7 +2935,7 @@
     private void registerDiskIO() {
         int tagId = FrameworkStatsLog.DISK_IO;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {2, 3, 4, 5, 6, 7, 8, 9, 10, 11})
+                .setAdditiveFields(new int[]{2, 3, 4, 5, 6, 7, 8, 9, 10, 11})
                 .setCoolDownMillis(3 * MILLIS_PER_SEC)
                 .build();
         mStatsManager.setPullAtomCallback(
@@ -2994,7 +3007,7 @@
     private void registerCpuTimePerThreadFreq() {
         int tagId = FrameworkStatsLog.CPU_TIME_PER_THREAD_FREQ;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {7, 9, 11, 13, 15, 17, 19, 21})
+                .setAdditiveFields(new int[]{7, 9, 11, 13, 15, 17, 19, 21})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -3092,7 +3105,7 @@
     private void registerDebugElapsedClock() {
         int tagId = FrameworkStatsLog.DEBUG_ELAPSED_CLOCK;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {1, 2, 3, 4})
+                .setAdditiveFields(new int[]{1, 2, 3, 4})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -3127,7 +3140,7 @@
     private void registerDebugFailingElapsedClock() {
         int tagId = FrameworkStatsLog.DEBUG_FAILING_ELAPSED_CLOCK;
         PullAtomMetadata metadata = new PullAtomMetadata.Builder()
-                .setAdditiveFields(new int[] {1, 2, 3, 4})
+                .setAdditiveFields(new int[]{1, 2, 3, 4})
                 .build();
         mStatsManager.setPullAtomCallback(
                 tagId,
@@ -3559,23 +3572,23 @@
                 int userId = users.get(userNum).getUserHandle().getIdentifier();
 
                 int unlockKeyguardEnabled = Settings.Secure.getIntForUser(
-                          mContext.getContentResolver(),
-                          Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED, 1, userId);
+                        mContext.getContentResolver(),
+                        Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED, 1, userId);
                 int unlockDismissesKeyguard = Settings.Secure.getIntForUser(
-                          mContext.getContentResolver(),
-                          Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, 1, userId);
+                        mContext.getContentResolver(),
+                        Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, 1, userId);
                 int unlockAttentionRequired = Settings.Secure.getIntForUser(
-                          mContext.getContentResolver(),
-                          Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, 0, userId);
+                        mContext.getContentResolver(),
+                        Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, 0, userId);
                 int unlockAppEnabled = Settings.Secure.getIntForUser(
-                          mContext.getContentResolver(),
-                          Settings.Secure.FACE_UNLOCK_APP_ENABLED, 1, userId);
+                        mContext.getContentResolver(),
+                        Settings.Secure.FACE_UNLOCK_APP_ENABLED, 1, userId);
                 int unlockAlwaysRequireConfirmation = Settings.Secure.getIntForUser(
-                          mContext.getContentResolver(),
-                          Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, 0, userId);
+                        mContext.getContentResolver(),
+                        Settings.Secure.FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION, 0, userId);
                 int unlockDiversityRequired = Settings.Secure.getIntForUser(
-                          mContext.getContentResolver(),
-                          Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED, 1, userId);
+                        mContext.getContentResolver(),
+                        Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED, 1, userId);
 
                 pulledData.add(FrameworkStatsLog.buildStatsEvent(atomTag,
                         unlockKeyguardEnabled != 0, unlockDismissesKeyguard != 0,
@@ -4481,7 +4494,7 @@
                                     opacity));
                 }
             }
-        }  catch (RuntimeException e) {
+        } catch (RuntimeException e) {
             Slog.e(TAG, "pulling accessibility floating menu stats failed at getUsers", e);
             return StatsManager.PULL_SKIP;
         } finally {
@@ -4505,7 +4518,7 @@
         byte[] sinkSurroundEncodings = toBytes(audioManager.getReportedSurroundFormats());
         List<Integer> disabledSurroundEncodingsList = new ArrayList<>();
         List<Integer> enabledSurroundEncodingsList = new ArrayList<>();
-        for (int surroundEncoding:  surroundEncodingsMap.keySet()) {
+        for (int surroundEncoding : surroundEncodingsMap.keySet()) {
             if (!surroundEncodingsMap.get(surroundEncoding)) {
                 disabledSurroundEncodingsList.add(surroundEncoding);
             } else {
@@ -4574,6 +4587,26 @@
         return StatsManager.PULL_SUCCESS;
     }
 
+    private void registerPendingIntentsPerPackagePuller() {
+        int tagId = FrameworkStatsLog.PENDING_INTENTS_PER_PACKAGE;
+        mStatsManager.setPullAtomCallback(
+                tagId,
+                null, // use default PullAtomMetadata values
+                DIRECT_EXECUTOR,
+                mStatsCallbackImpl
+        );
+    }
+
+    private int pullPendingIntentsPerPackage(int atomTag, List<StatsEvent> pulledData) {
+        List<PendingIntentStats> pendingIntentStats =
+                LocalServices.getService(ActivityManagerInternal.class).getPendingIntentStats();
+        for (PendingIntentStats stats : pendingIntentStats) {
+            pulledData.add(FrameworkStatsLog.buildStatsEvent(
+                    atomTag, stats.uid, stats.count, stats.sizeKb));
+        }
+        return StatsManager.PULL_SUCCESS;
+    }
+
     private byte[] toBytes(List<Integer> audioEncodings) {
         ProtoOutputStream protoOutputStream = new ProtoOutputStream();
         for (int audioEncoding : audioEncodings) {
@@ -4655,8 +4688,8 @@
      * string list.
      *
      * @param semicolonList colon-separated string, it should be
-     *                        {@link Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS} or
-     *                        {@link Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE}.
+     *                      {@link Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS} or
+     *                      {@link Settings.Secure#ACCESSIBILITY_SHORTCUT_TARGET_SERVICE}.
      * @return The number of accessibility services
      */
     private int countAccessibilityServices(String semicolonList) {
@@ -4778,5 +4811,4 @@
             }
         }
     }
-
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 8fee539..66904b1 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -1433,6 +1433,22 @@
         }
     }
 
+    /**
+     * Allows the status bar to restart android (vs a full reboot).
+     */
+    @Override
+    public void restart() {
+        enforceStatusBarService();
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            mHandler.post(() -> {
+                mActivityManagerInternal.restart();
+            });
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     @Override
     public void onGlobalActionsShown() {
         enforceStatusBarService();
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index a17e792..30e2617 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -146,7 +146,7 @@
         filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
         filter.addAction(ACTION_MULTI_SIM_CONFIG_CHANGED);
 
-        mContext.registerReceiver(this, filter, null, mHandler);
+        mContext.registerReceiver(this, filter, null, mHandler, Context.RECEIVER_NOT_EXPORTED);
         mSubscriptionManager.addOnSubscriptionsChangedListener(
                 executor, mSubscriptionChangedListener);
         mTelephonyManager.registerTelephonyCallback(executor, mActiveDataSubIdListener);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 8fc3a87..dc53cc6 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -4536,7 +4536,7 @@
                         pendingOptions.getStartX(), pendingOptions.getStartY(),
                         pendingOptions.getAnimationStartedListener(),
                         scaleUp);
-                options = AnimationOptions.makeThumnbnailAnimOptions(buffer,
+                options = AnimationOptions.makeThumbnailAnimOptions(buffer,
                         pendingOptions.getStartX(), pendingOptions.getStartY(), scaleUp);
                 startCallback = pendingOptions.getAnimationStartedListener();
                 if (intent.getSourceBounds() == null && buffer != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 8d99f07..4000595 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6099,7 +6099,8 @@
         public boolean onForceStopPackage(String packageName, boolean doit, boolean evenPersistent,
                 int userId) {
             synchronized (mGlobalLock) {
-
+                // In case if setWindowManager hasn't been called yet when booting.
+                if (mRootWindowContainer == null) return false;
                 return mRootWindowContainer.finishDisabledPackageActivities(packageName,
                         null /* filterByClasses */, doit, evenPersistent, userId,
                         // Only remove the activities without process because the activities with
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 475a9fb..457ea13 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -249,7 +249,7 @@
             overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
         }
 
-        final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
+        final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mClosingApps)
                 || containsVoiceInteraction(mDisplayContent.mOpeningApps);
 
         final int layoutRedo;
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index e26748c..33b807b 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -53,7 +53,11 @@
      * Returns true if the back predictability feature is enabled
      */
     static boolean isEnabled() {
-        return SystemProperties.getInt(BACK_PREDICTABILITY_PROP, 0) > 0;
+        return SystemProperties.getInt(BACK_PREDICTABILITY_PROP, 1) > 0;
+    }
+
+    static boolean isScreenshotEnabled() {
+        return false;
     }
 
     /**
@@ -101,6 +105,13 @@
 
         synchronized (task.mWmService.mGlobalLock) {
             activityRecord = task.topRunningActivity();
+
+            if(!activityRecord.info.applicationInfo.isOnBackInvokedCallbackEnabled()) {
+                ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "Activity %s: enableOnBackInvokedCallback=false."
+                        + " Returning null BackNavigationInfo.", activityRecord.getName());
+                return null;
+            }
+
             removedWindowContainer = activityRecord;
             taskWindowConfiguration = task.getTaskInfo().configuration.windowConfiguration;
             WindowState window = task.getWindow(WindowState::isFocused);
diff --git a/services/core/java/com/android/server/wm/TaskFpsCallbackController.java b/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
index d9dc9aa..c099628 100644
--- a/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
+++ b/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
@@ -19,51 +19,51 @@
 import android.content.Context;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.window.IOnFpsCallbackListener;
+import android.window.ITaskFpsCallback;
 
 import java.util.HashMap;
 
 final class TaskFpsCallbackController {
 
     private final Context mContext;
-    private final HashMap<IOnFpsCallbackListener, Long> mTaskFpsCallbackListeners;
-    private final HashMap<IOnFpsCallbackListener, IBinder.DeathRecipient> mDeathRecipients;
+    private final HashMap<ITaskFpsCallback, Long> mTaskFpsCallbacks;
+    private final HashMap<ITaskFpsCallback, IBinder.DeathRecipient> mDeathRecipients;
 
     TaskFpsCallbackController(Context context) {
         mContext = context;
-        mTaskFpsCallbackListeners = new HashMap<>();
+        mTaskFpsCallbacks = new HashMap<>();
         mDeathRecipients = new HashMap<>();
     }
 
-    void registerCallback(int taskId, IOnFpsCallbackListener listener) {
-        if (mTaskFpsCallbackListeners.containsKey(listener)) {
+    void registerListener(int taskId, ITaskFpsCallback callback) {
+        if (mTaskFpsCallbacks.containsKey(callback)) {
             return;
         }
 
-        final long nativeListener = nativeRegister(listener, taskId);
-        mTaskFpsCallbackListeners.put(listener, nativeListener);
+        final long nativeListener = nativeRegister(callback, taskId);
+        mTaskFpsCallbacks.put(callback, nativeListener);
 
-        final IBinder.DeathRecipient deathRecipient = () -> unregisterCallback(listener);
+        final IBinder.DeathRecipient deathRecipient = () -> unregisterListener(callback);
         try {
-            listener.asBinder().linkToDeath(deathRecipient, 0);
-            mDeathRecipients.put(listener, deathRecipient);
+            callback.asBinder().linkToDeath(deathRecipient, 0);
+            mDeathRecipients.put(callback, deathRecipient);
         } catch (RemoteException e) {
             // ignore
         }
     }
 
-    void unregisterCallback(IOnFpsCallbackListener listener) {
-        if (!mTaskFpsCallbackListeners.containsKey(listener)) {
+    void unregisterListener(ITaskFpsCallback callback) {
+        if (!mTaskFpsCallbacks.containsKey(callback)) {
             return;
         }
 
-        listener.asBinder().unlinkToDeath(mDeathRecipients.get(listener), 0);
-        mDeathRecipients.remove(listener);
+        callback.asBinder().unlinkToDeath(mDeathRecipients.get(callback), 0);
+        mDeathRecipients.remove(callback);
 
-        nativeUnregister(mTaskFpsCallbackListeners.get(listener));
-        mTaskFpsCallbackListeners.remove(listener);
+        nativeUnregister(mTaskFpsCallbacks.get(callback));
+        mTaskFpsCallbacks.remove(callback);
     }
 
-    private static native long nativeRegister(IOnFpsCallbackListener listener, int taskId);
+    private static native long nativeRegister(ITaskFpsCallback callback, int taskId);
     private static native void nativeUnregister(long ptr);
 }
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index c880aba..dd1f29e 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -876,11 +876,17 @@
                 if (!adjacentTaskFragments.isEmpty() && !gotTranslucentAdjacent) {
                     // The z-order of this TaskFragment is in middle of two adjacent TaskFragments
                     // and it cannot be visible if the TaskFragment on top is not translucent and
-                    // is fully occluding this one.
+                    // is occluding this one.
+                    mTmpRect.set(getBounds());
                     for (int j = adjacentTaskFragments.size() - 1; j >= 0; --j) {
                         final TaskFragment taskFragment = adjacentTaskFragments.get(j);
-                        if (!taskFragment.isTranslucent(starting)
-                                && taskFragment.getBounds().contains(this.getBounds())) {
+                        final TaskFragment adjacentTaskFragment =
+                                taskFragment.mAdjacentTaskFragment;
+                        if (adjacentTaskFragment == this) {
+                            continue;
+                        }
+                        if (mTmpRect.intersect(taskFragment.getBounds())
+                                || mTmpRect.intersect(adjacentTaskFragment.getBounds())) {
                             return TASK_FRAGMENT_VISIBILITY_INVISIBLE;
                         }
                     }
@@ -1695,7 +1701,7 @@
         if (isAddingActivity && task != null) {
 
             // TODO(b/207481538): temporary per-activity screenshoting
-            if (r != null && BackNavigationController.isEnabled()) {
+            if (r != null && BackNavigationController.isScreenshotEnabled()) {
                 ProtoLog.v(WM_DEBUG_BACK_PREVIEW, "Screenshotting Activity %s",
                         r.mActivityComponent.flattenToString());
                 Rect outBounds = r.getBounds();
@@ -2298,7 +2304,7 @@
 
     void removeChild(WindowContainer child, boolean removeSelfIfPossible) {
         super.removeChild(child);
-        if (BackNavigationController.isEnabled()) {
+        if (BackNavigationController.isScreenshotEnabled()) {
             //TODO(b/207481538) Remove once the infrastructure to support per-activity screenshot is
             // implemented
             ActivityRecord r = child.asActivityRecord();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index af12c0b..0d4eae0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -281,7 +281,7 @@
 import android.view.displayhash.DisplayHash;
 import android.view.displayhash.VerifiedDisplayHash;
 import android.window.ClientWindowFrames;
-import android.window.IOnFpsCallbackListener;
+import android.window.ITaskFpsCallback;
 import android.window.TaskSnapshot;
 
 import com.android.internal.R;
@@ -8870,7 +8870,7 @@
     @Override
     @RequiresPermission(Manifest.permission.ACCESS_FPS_COUNTER)
     public void registerTaskFpsCallback(@IntRange(from = 0) int taskId,
-            IOnFpsCallbackListener listener) {
+            ITaskFpsCallback callback) {
         if (mContext.checkCallingOrSelfPermission(Manifest.permission.ACCESS_FPS_COUNTER)
                 != PackageManager.PERMISSION_GRANTED) {
             final int pid = Binder.getCallingPid();
@@ -8882,12 +8882,12 @@
             throw new IllegalArgumentException("no task with taskId: " + taskId);
         }
 
-        mTaskFpsCallbackController.registerCallback(taskId, listener);
+        mTaskFpsCallbackController.registerListener(taskId, callback);
     }
 
     @Override
     @RequiresPermission(Manifest.permission.ACCESS_FPS_COUNTER)
-    public void unregisterTaskFpsCallback(IOnFpsCallbackListener listener) {
+    public void unregisterTaskFpsCallback(ITaskFpsCallback callback) {
         if (mContext.checkCallingOrSelfPermission(Manifest.permission.ACCESS_FPS_COUNTER)
                 != PackageManager.PERMISSION_GRANTED) {
             final int pid = Binder.getCallingPid();
@@ -8895,7 +8895,7 @@
                     + ", must have permission " + Manifest.permission.ACCESS_FPS_COUNTER);
         }
 
-        mTaskFpsCallbackController.unregisterCallback(listener);
+        mTaskFpsCallbackController.unregisterListener(callback);
     }
 
     @Override
diff --git a/services/core/jni/BroadcastRadio/types.h b/services/core/jni/BroadcastRadio/types.h
index 910bb7c..4d286bf 100644
--- a/services/core/jni/BroadcastRadio/types.h
+++ b/services/core/jni/BroadcastRadio/types.h
@@ -30,13 +30,13 @@
 // Keep in sync with STATUS_* constants from RadioManager.java.
 enum class Status : jint {
     OK = 0,
-    ERROR = -0x80000000ll,  // Integer.MIN_VALUE
+    ERROR = -0x80000000LL,   // Integer.MIN_VALUE
     PERMISSION_DENIED = -1,  // -EPERM
-    NO_INIT = -19,  // -ENODEV
-    BAD_VALUE = -22,  // -EINVAL
-    DEAD_OBJECT = -32,  // -EPIPE
-    INVALID_OPERATION = -38,  // -ENOSYS
-    TIMED_OUT = -110,  // -ETIMEDOUT
+    NO_INIT = -19,           // -ENODEV
+    BAD_VALUE = -22,         // -EINVAL
+    DEAD_OBJECT = -32,       // -EPIPE
+    INVALID_OPERATION = -38, // -ENOSYS
+    TIMED_OUT = -110,        // -ETIMEDOUT
 };
 
 // Keep in sync with REGION_* constants from RadioManager.java.
diff --git a/services/core/jni/com_android_server_wm_TaskFpsCallbackController.cpp b/services/core/jni/com_android_server_wm_TaskFpsCallbackController.cpp
index 0202306..0a60e0d 100644
--- a/services/core/jni/com_android_server_wm_TaskFpsCallbackController.cpp
+++ b/services/core/jni/com_android_server_wm_TaskFpsCallbackController.cpp
@@ -99,7 +99,7 @@
 
 static const JNINativeMethod gMethods[] = {
         /* name, signature, funcPtr */
-        {"nativeRegister", "(Landroid/window/IOnFpsCallbackListener;I)J", (void*)nativeRegister},
+        {"nativeRegister", "(Landroid/window/ITaskFpsCallback;I)J", (void*)nativeRegister},
         {"nativeUnregister", "(J)V", (void*)nativeUnregister}};
 
 } // namespace
@@ -113,7 +113,7 @@
     gCallbackClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
     gCallbackClassInfo.mDispatchOnFpsReported =
             env->GetStaticMethodID(clazz, "dispatchOnFpsReported",
-                                   "(Landroid/window/IOnFpsCallbackListener;F)V");
+                                   "(Landroid/window/ITaskFpsCallback;F)V");
     return 0;
 }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5c3721d..2e801ab 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -417,6 +417,8 @@
     private static final String UWB_SERVICE_CLASS = "com.android.server.uwb.UwbService";
     private static final String SAFETY_CENTER_SERVICE_CLASS =
             "com.android.safetycenter.SafetyCenterService";
+    private static final String BLUETOOTH_SERVICE_CLASS =
+            "com.android.server.bluetooth.BluetoothService";
 
     private static final String SUPPLEMENTALPROCESS_SERVICE_CLASS =
             "com.android.server.supplementalprocess.SupplementalProcessManagerService$Lifecycle";
@@ -1624,7 +1626,7 @@
                 Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
             } else {
                 t.traceBegin("StartBluetoothService");
-                mSystemServiceManager.startService(BluetoothService.class);
+                mSystemServiceManager.startService(BLUETOOTH_SERVICE_CLASS);
                 t.traceEnd();
             }
 
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 11300ce..cd2d0fc 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -509,7 +509,12 @@
             ParsingPackage::setInheritKeyStoreKeys,
             true
         ),
-        getter(AndroidPackage::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT"))
+        getter(AndroidPackage::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT")),
+        getSetByValue(
+            AndroidPackage::isOnBackInvokedCallbackEnabled,
+            ParsingPackage::setOnBackInvokedCallbackEnabled,
+            true
+        )
     )
 
     override fun initialObject() = PackageImpl.forParsing(
diff --git a/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java
index 02cf971..b36aa06 100644
--- a/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/adb/AdbDebuggingManagerTest.java
@@ -635,7 +635,7 @@
         long time = System.currentTimeMillis();
         for (String key : testKeys) {
             long connectionTime = adbKeyStore.getLastConnectionTime(key);
-            if (Math.abs(connectionTime - connectionTime) > epsilon) {
+            if (Math.abs(time - connectionTime) > epsilon) {
                 fail("The connection time for a previously untracked key, " + connectionTime
                         + ", is beyond the current time of " + time);
             }
diff --git a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
index 877538c..782d519 100644
--- a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
@@ -20,7 +20,12 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
@@ -42,6 +47,7 @@
 import java.io.File;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -51,6 +57,7 @@
 @SmallTest
 @Presubmit
 public class AnrHelperTest {
+    private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
     private AnrHelper mAnrHelper;
 
     private ProcessRecord mAnrApp;
@@ -106,8 +113,42 @@
         mAnrHelper.appNotResponding(mAnrApp, activityShortComponentName, appInfo,
                 parentShortComponentName, parentProcess, aboveSystem, annotation);
 
-        verify(mAnrApp.mErrorState, timeout(TimeUnit.SECONDS.toMillis(5))).appNotResponding(
+        verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS)).appNotResponding(
                 eq(activityShortComponentName), eq(appInfo), eq(parentShortComponentName),
                 eq(parentProcess), eq(aboveSystem), eq(annotation), eq(false) /* onlyDumpSelf */);
     }
+
+    @Test
+    public void testSkipDuplicatedAnr() {
+        final CountDownLatch consumerLatch = new CountDownLatch(1);
+        final CountDownLatch processingLatch = new CountDownLatch(1);
+        doAnswer(invocation -> {
+            consumerLatch.countDown();
+            // Simulate that it is dumping to block the consumer thread.
+            processingLatch.await();
+            return null;
+        }).when(mAnrApp.mErrorState).appNotResponding(anyString(), any(), any(), any(),
+                anyBoolean(), anyString(), anyBoolean());
+        final ApplicationInfo appInfo = new ApplicationInfo();
+        mAnrApp.mPid = 12345;
+        final Runnable reportAnr = () -> mAnrHelper.appNotResponding(mAnrApp,
+                "activityShortComponentName", appInfo, "parentShortComponentName",
+                null /* parentProcess */, false /* aboveSystem */, "annotation");
+        reportAnr.run();
+        // This should be skipped because the pid is pending in queue.
+        reportAnr.run();
+        // The first reported ANR must be processed.
+        try {
+            assertTrue(consumerLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException ignored) {
+        }
+        // This should be skipped because the pid is under processing.
+        reportAnr.run();
+
+        // Assume that the first one finishes after all incoming ANRs.
+        processingLatch.countDown();
+        // There is only one ANR reported.
+        verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS).only()).appNotResponding(
+                anyString(), any(), any(), any(), anyBoolean(), anyString(), anyBoolean());
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index ea7804d..d99fbb1 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -2048,8 +2048,7 @@
 
     protected List<ShortcutInfo> getShortcutAsLauncher(int targetUserId) {
         final ShortcutQuery q = new ShortcutQuery();
-        q.setQueryFlags(ShortcutQuery.FLAG_MATCH_DYNAMIC | ShortcutQuery.FLAG_MATCH_DYNAMIC
-                | ShortcutQuery.FLAG_MATCH_PINNED);
+        q.setQueryFlags(ShortcutQuery.FLAG_MATCH_DYNAMIC | ShortcutQuery.FLAG_MATCH_PINNED);
         return mLauncherApps.getShortcuts(q, UserHandle.of(targetUserId));
     }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index a12bc3b..de81d6b 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -28,6 +28,8 @@
 import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE;
 import static android.app.UiModeManager.PROJECTION_TYPE_NONE;
 
+import static com.android.server.UiModeManagerService.SUPPORTED_NIGHT_MODE_CUSTOM_TYPES;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static junit.framework.TestCase.assertFalse;
@@ -295,6 +297,24 @@
     }
 
     @Test
+    public void setNightModeCustomType_customTypeUnknown_shouldThrow() throws RemoteException {
+        assertThrows(IllegalArgumentException.class,
+                () -> mService.setNightModeCustomType(MODE_NIGHT_CUSTOM_TYPE_UNKNOWN));
+    }
+
+    @Test
+    public void setNightModeCustomType_customTypeUnsupported_shouldThrow() throws RemoteException {
+        assertThrows(IllegalArgumentException.class,
+                () -> {
+                    int maxSupportedCustomType = 0;
+                    for (Integer supportedType : SUPPORTED_NIGHT_MODE_CUSTOM_TYPES) {
+                        maxSupportedCustomType = Math.max(maxSupportedCustomType, supportedType);
+                    }
+                    mService.setNightModeCustomType(maxSupportedCustomType + 1);
+                });
+    }
+
+    @Test
     public void setNightModeCustomType_bedtime_shouldHaveNoScreenOffRegistered()
             throws RemoteException {
         try {
@@ -777,7 +797,6 @@
     }
 
 
-
     @Test
     public void customTime_darkThemeOn_beforeStartEnd() throws RemoteException {
         LocalTime now = LocalTime.now();
@@ -1220,6 +1239,35 @@
         verify(listener, never()).onProjectionStateChanged(anyInt(), any());
     }
 
+    @Test
+    public void enableCarMode_failsForBogusPackageName() throws Exception {
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+            .thenReturn(TestInjector.CALLING_UID + 1);
+
+        assertThrows(SecurityException.class, () -> mService.enableCarMode(0, 0, PACKAGE_NAME));
+        assertThat(mService.getCurrentModeType()).isNotEqualTo(Configuration.UI_MODE_TYPE_CAR);
+    }
+
+    @Test
+    public void disableCarMode_failsForBogusPackageName() throws Exception {
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+            .thenReturn(TestInjector.CALLING_UID);
+        mService.enableCarMode(0, 0, PACKAGE_NAME);
+        assertThat(mService.getCurrentModeType()).isEqualTo(Configuration.UI_MODE_TYPE_CAR);
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+            .thenReturn(TestInjector.CALLING_UID + 1);
+
+        assertThrows(SecurityException.class,
+            () -> mService.disableCarModeByCallingPackage(0, PACKAGE_NAME));
+        assertThat(mService.getCurrentModeType()).isEqualTo(Configuration.UI_MODE_TYPE_CAR);
+
+        // Clean up
+        when(mPackageManager.getPackageUidAsUser(eq(PACKAGE_NAME), anyInt()))
+            .thenReturn(TestInjector.CALLING_UID);
+         mService.disableCarModeByCallingPackage(0, PACKAGE_NAME);
+        assertThat(mService.getCurrentModeType()).isNotEqualTo(Configuration.UI_MODE_TYPE_CAR);
+    }
+
     private void requestAllPossibleProjectionTypes() throws RemoteException {
         for (int i = 0; i < Integer.SIZE; ++i) {
             mService.requestProjection(mBinder, 1 << i, PACKAGE_NAME);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
index 1126e1e..4b6183d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ArchiveTest.java
@@ -15,16 +15,22 @@
  */
 package com.android.server.notification;
 
+import static android.os.UserHandle.USER_ALL;
 import static android.os.UserHandle.USER_CURRENT;
+import static android.os.UserHandle.USER_NULL;
 import static android.os.UserHandle.USER_SYSTEM;
 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
 
 import android.app.Notification;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.service.notification.StatusBarNotification;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -35,6 +41,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
@@ -51,6 +58,8 @@
     private static final int SIZE = 5;
 
     private NotificationManagerService.Archive mArchive;
+    @Mock
+    private UserManager mUm;
 
     @Before
     public void setUp() {
@@ -59,6 +68,9 @@
         mArchive = new NotificationManagerService.Archive(SIZE);
         mArchive.updateHistoryEnabled(USER_SYSTEM, true);
         mArchive.updateHistoryEnabled(USER_CURRENT, true);
+
+        when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(
+                new int[] {USER_CURRENT, USER_SYSTEM});
     }
 
     private StatusBarNotification getNotification(String pkg, int id, UserHandle user) {
@@ -70,7 +82,6 @@
                 pkg, pkg, id, null, 0, 0, n, user, null, System.currentTimeMillis());
     }
 
-
     @Test
     public void testRecordAndRead() {
         List<String> expected = new ArrayList<>();
@@ -81,7 +92,7 @@
             mArchive.record(sbn, REASON_CANCEL);
         }
 
-        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
         assertThat(actual).hasSize(expected.size());
         for (StatusBarNotification sbn : actual) {
             assertThat(expected).contains(sbn.getKey());
@@ -89,6 +100,22 @@
     }
 
     @Test
+    public void testCrossUser() {
+        mArchive.record(getNotification("pkg", 1, UserHandle.of(USER_SYSTEM)), REASON_CANCEL);
+        mArchive.record(getNotification("pkg", 2, UserHandle.of(USER_CURRENT)), REASON_CANCEL);
+        mArchive.record(getNotification("pkg", 3, UserHandle.of(USER_ALL)), REASON_CANCEL);
+        mArchive.record(getNotification("pkg", 4, UserHandle.of(USER_NULL)), REASON_CANCEL);
+
+        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
+        assertThat(actual).hasSize(3);
+        for (StatusBarNotification sbn : actual) {
+            if (sbn.getUserId() == USER_NULL) {
+                fail("leaked notification from wrong user");
+            }
+        }
+    }
+
+    @Test
     public void testRecordAndRead_overLimit() {
         List<String> expected = new ArrayList<>();
         for (int i = 0; i < (SIZE * 2); i++) {
@@ -99,7 +126,8 @@
             }
         }
 
-        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray((SIZE * 2), true));
+        List<StatusBarNotification> actual = Arrays.asList(
+                mArchive.getArray(mUm, (SIZE * 2), true));
         assertThat(actual).hasSize(expected.size());
         for (StatusBarNotification sbn : actual) {
             assertThat(expected).contains(sbn.getKey());
@@ -119,7 +147,7 @@
             }
         }
 
-        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
         assertThat(actual).hasSize(expected.size());
         for (StatusBarNotification sbn : actual) {
             assertThat(expected).contains(sbn.getKey());
@@ -140,7 +168,7 @@
         }
         mArchive.updateHistoryEnabled(USER_CURRENT, false);
 
-        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
         assertThat(actual).hasSize(expected.size());
         for (StatusBarNotification sbn : actual) {
             assertThat(expected).contains(sbn.getKey());
@@ -165,7 +193,7 @@
         }
         mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test0");
         mArchive.removeChannelNotifications("pkg", USER_CURRENT, "test" + (SIZE - 2));
-        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
         assertThat(actual).hasSize(expected.size());
         for (StatusBarNotification sbn : actual) {
             assertThat(expected).contains(sbn.getKey());
@@ -215,7 +243,7 @@
             fail("Concurrent modification exception");
         }
 
-        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(SIZE, true));
+        List<StatusBarNotification> actual = Arrays.asList(mArchive.getArray(mUm, SIZE, true));
         assertThat(actual).hasSize(expected.size());
         for (StatusBarNotification sbn : actual) {
             assertThat(expected).contains(sbn.getKey());
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index dfcab2b..018a916 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -430,6 +430,7 @@
         when(mPermissionPolicyInternal.canShowPermissionPromptForTask(
                 any(ActivityManager.RecentTaskInfo.class))).thenReturn(false);
         mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
+        when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0});
 
         ActivityManager.AppTask task = mock(ActivityManager.AppTask.class);
         List<ActivityManager.AppTask> taskList = new ArrayList<>();
@@ -7643,8 +7644,9 @@
         waitForIdle();
 
         // A notification exists for the given record
-        StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(PKG);
-        assertEquals(1, notifsBefore.length);
+        List<StatusBarNotification> notifsBefore =
+                mBinderService.getAppActiveNotifications(PKG, nr.getSbn().getUserId()).getList();
+        assertEquals(1, notifsBefore.size());
 
         reset(mPackageManager);
 
@@ -9131,4 +9133,33 @@
         // make sure we don't bother if the migration is not enabled
         assertThat(mService.getAllUsersNotificationPermissions()).isNull();
     }
+
+    @Test
+    public void testGetActiveNotification_filtersUsers() throws Exception {
+        when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0, 10});
+
+        NotificationRecord nr0 =
+                generateNotificationRecord(mTestNotificationChannel, 0);
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag0",
+                nr0.getSbn().getId(), nr0.getSbn().getNotification(), nr0.getSbn().getUserId());
+
+        NotificationRecord nr10 =
+                generateNotificationRecord(mTestNotificationChannel, 10);
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag10",
+                nr10.getSbn().getId(), nr10.getSbn().getNotification(), nr10.getSbn().getUserId());
+
+        NotificationRecord nr11 =
+                generateNotificationRecord(mTestNotificationChannel, 11);
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag11",
+                nr11.getSbn().getId(), nr11.getSbn().getNotification(), nr11.getSbn().getUserId());
+        waitForIdle();
+
+        StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
+        assertEquals(2, notifs.length);
+        for (StatusBarNotification sbn : notifs) {
+            if (sbn.getUserId() == 11) {
+                fail("leaked data across users");
+            }
+        }
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
index d922f40..5a6ca6d 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
@@ -293,6 +293,7 @@
         LocalServices.removeServiceForTest(PackageManagerInternal.class);
         LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
         mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager);
+        when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0});
 
         doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
index b71323b4..a24ba0d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
@@ -221,6 +221,8 @@
 
     @Test
     public void testSetNotificationPermission_grantUserSet() throws Exception {
+        when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+                .thenReturn(PERMISSION_DENIED);
         mPermissionHelper.setNotificationPermission("pkg", 10, true, true);
 
         verify(mPermManager).grantRuntimePermission(
@@ -232,9 +234,12 @@
 
     @Test
     public void testSetNotificationPermission_grantReviewRequired() throws Exception {
+        when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+                .thenReturn(PERMISSION_DENIED);
+
         mPermissionHelper.setNotificationPermission("pkg", 10, true, false, true);
 
-        verify(mPermManager).revokeRuntimePermission(
+        verify(mPermManager, never()).revokeRuntimePermission(
                 "pkg", Manifest.permission.POST_NOTIFICATIONS, 10, "PermissionHelper");
         verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
                 FLAG_PERMISSION_REVIEW_REQUIRED, FLAG_PERMISSION_REVIEW_REQUIRED, true, 10);
@@ -242,11 +247,14 @@
 
     @Test
     public void testSetNotificationPermission_pkgPerm_grantReviewRequired() throws Exception {
+        when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+                .thenReturn(PERMISSION_DENIED);
+
         PermissionHelper.PackagePermission pkgPerm = new PermissionHelper.PackagePermission(
                 "pkg", 10, true, false);
         mPermissionHelper.setNotificationPermission(pkgPerm);
 
-        verify(mPermManager).revokeRuntimePermission(
+        verify(mPermManager, never()).revokeRuntimePermission(
                 "pkg", Manifest.permission.POST_NOTIFICATIONS, 10, "PermissionHelper");
         verify(mPermManager).updatePermissionFlags("pkg", Manifest.permission.POST_NOTIFICATIONS,
                 FLAG_PERMISSION_REVIEW_REQUIRED, FLAG_PERMISSION_REVIEW_REQUIRED, true, 10);
@@ -255,6 +263,8 @@
     @Test
     public void testSetNotificationPermission_pkgPerm_notUserSet_grantedByDefaultPermNotSet()
             throws Exception {
+        when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+                .thenReturn(PERMISSION_DENIED);
         when(mPermManager.getPermissionFlags(anyString(),
                 eq(Manifest.permission.POST_NOTIFICATIONS),
                 anyInt())).thenReturn(FLAG_PERMISSION_GRANTED_BY_DEFAULT);
@@ -271,6 +281,8 @@
     @Test
     public void testSetNotificationPermission_pkgPerm_userSet_grantedByDefaultPermSet()
             throws Exception {
+        when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+                .thenReturn(PERMISSION_DENIED);
         when(mPermManager.getPermissionFlags(anyString(),
                 eq(Manifest.permission.POST_NOTIFICATIONS),
                 anyInt())).thenReturn(FLAG_PERMISSION_GRANTED_BY_DEFAULT);
@@ -287,6 +299,9 @@
 
     @Test
     public void testSetNotificationPermission_revokeUserSet() throws Exception {
+        when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+                .thenReturn(PERMISSION_GRANTED);
+
         mPermissionHelper.setNotificationPermission("pkg", 10, false, true);
 
         verify(mPermManager).revokeRuntimePermission(
@@ -298,6 +313,9 @@
 
     @Test
     public void testSetNotificationPermission_grantNotUserSet() throws Exception {
+        when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+                .thenReturn(PERMISSION_DENIED);
+
         mPermissionHelper.setNotificationPermission("pkg", 10, true, false);
 
         verify(mPermManager).grantRuntimePermission(
@@ -308,6 +326,9 @@
 
     @Test
     public void testSetNotificationPermission_revokeNotUserSet() throws Exception {
+        when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+                .thenReturn(PERMISSION_GRANTED);
+
         mPermissionHelper.setNotificationPermission("pkg", 10, false, false);
 
         verify(mPermManager).revokeRuntimePermission(
@@ -343,6 +364,26 @@
     }
 
     @Test
+    public void testSetNotificationPermission_alreadyGrantedNotRegranted() throws Exception {
+        when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+                .thenReturn(PERMISSION_GRANTED);
+        mPermissionHelper.setNotificationPermission("pkg", 10, true, false);
+
+        verify(mPermManager, never()).grantRuntimePermission(
+                "pkg", Manifest.permission.POST_NOTIFICATIONS, 10);
+    }
+
+    @Test
+    public void testSetNotificationPermission_alreadyRevokedNotRerevoked() throws Exception {
+        when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
+                .thenReturn(PERMISSION_DENIED);
+        mPermissionHelper.setNotificationPermission("pkg", 10, false, false);
+
+        verify(mPermManager, never()).revokeRuntimePermission(
+                eq("pkg"), eq(Manifest.permission.POST_NOTIFICATIONS), eq(10), anyString());
+    }
+
+    @Test
     public void testIsPermissionFixed() throws Exception {
         when(mPermManager.getPermissionFlags(anyString(),
                 eq(Manifest.permission.POST_NOTIFICATIONS),
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
index 0552a83..c12f0a9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ValidateNotificationPeopleTest.java
@@ -274,7 +274,7 @@
         new ValidateNotificationPeople().searchContactsAndLookupNumbers(mockContext, lookupUri);
         verify(mockContentResolver, never()).query(
                 eq(ContactsContract.CommonDataKinds.Phone.CONTENT_URI),
-                eq(new String[] { ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER }),
+                eq(ValidateNotificationPeople.PHONE_LOOKUP_PROJECTION),
                 contains(ContactsContract.Contacts.LOOKUP_KEY),
                 any(),  // selection args
                 isNull());  // sort order
@@ -308,7 +308,7 @@
         // in the case of a phone lookup, return null cursor; that's not an error case
         // and we're not checking the actual storing of the phone data here.
         when(mockContentResolver.query(eq(ContactsContract.CommonDataKinds.Phone.CONTENT_URI),
-                eq(new String[] { ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER }),
+                eq(ValidateNotificationPeople.PHONE_LOOKUP_PROJECTION),
                 contains(ContactsContract.Contacts.LOOKUP_KEY),
                 any(), isNull())).thenReturn(null);
 
@@ -317,7 +317,7 @@
         new ValidateNotificationPeople().searchContactsAndLookupNumbers(mockContext, lookupUri);
         verify(mockContentResolver, times(1)).query(
                 eq(ContactsContract.CommonDataKinds.Phone.CONTENT_URI),
-                eq(new String[] { ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER }),
+                eq(ValidateNotificationPeople.PHONE_LOOKUP_PROJECTION),
                 contains(ContactsContract.Contacts.LOOKUP_KEY),
                 eq(new String[] { "testlookupkey" }),  // selection args
                 isNull());  // sort order
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index 3d89805..c21a5b6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.window.BackNavigationInfo.typeToString;
 
@@ -117,6 +118,9 @@
     private Task createTopTaskWithActivity() {
         Task task = createTask(mDefaultDisplay);
         ActivityRecord record = createActivityRecord(task);
+        // enable OnBackInvokedCallbacks
+        record.info.applicationInfo.privateFlagsExt |=
+                PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK;
         createWindow(null, FIRST_APPLICATION_WINDOW, record, "window");
         when(record.mSurfaceControl.isValid()).thenReturn(true);
         mAtm.setFocusedTask(task.mTaskId, record);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 2dfc72b..68e90e1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -46,6 +46,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.content.pm.PackageManager;
 import android.os.Binder;
@@ -284,4 +285,32 @@
         verify(mWm.mWindowContextListenerController, never()).registerWindowContainerListener(any(),
                 any(), anyInt(), anyInt(), any());
     }
+
+    @Test
+    public void testSetInTouchMode_instrumentedProcessGetPermissionToSwitchTouchMode() {
+        boolean currentTouchMode = mWm.getInTouchMode();
+        int callingPid = Binder.getCallingPid();
+        int callingUid = Binder.getCallingUid();
+        doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString());
+        when(mWm.mAtmService.isInstrumenting(callingPid)).thenReturn(true);
+
+        mWm.setInTouchMode(!currentTouchMode);
+
+        verify(mWm.mInputManager).setInTouchMode(
+                !currentTouchMode, callingPid, callingUid, /* hasPermission= */ true);
+    }
+
+    @Test
+    public void testSetInTouchMode_nonInstrumentedProcessDontGetPermissionToSwitchTouchMode() {
+        boolean currentTouchMode = mWm.getInTouchMode();
+        int callingPid = Binder.getCallingPid();
+        int callingUid = Binder.getCallingUid();
+        doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString());
+        when(mWm.mAtmService.isInstrumenting(callingPid)).thenReturn(false);
+
+        mWm.setInTouchMode(!currentTouchMode);
+
+        verify(mWm.mInputManager).setInTouchMode(
+                !currentTouchMode, callingPid, callingUid, /* hasPermission= */ false);
+    }
 }
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
index 9f4fee8..364d592 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
@@ -24,6 +24,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -43,6 +44,7 @@
 import android.view.translation.TranslationCapability;
 import android.view.translation.TranslationContext;
 import android.view.translation.TranslationSpec;
+import android.view.translation.UiTranslationController;
 import android.view.translation.UiTranslationManager.UiTranslationState;
 import android.view.translation.UiTranslationSpec;
 
@@ -253,7 +255,10 @@
             try (TransferPipe tp = new TransferPipe()) {
                 activityTokens.getApplicationThread().dumpActivity(tp.getWriteFd(),
                         activityTokens.getActivityToken(), prefix,
-                        new String[]{"--translation"});
+                        new String[] {
+                                Activity.DUMP_ARG_DUMP_DUMPABLE,
+                                UiTranslationController.DUMPABLE_NAME
+                        });
                 tp.go(fd);
             } catch (IOException e) {
                 pw.println(prefix + "Failure while dumping the activity: " + e);
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index d0825ba..f07a406 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -384,7 +384,7 @@
     }
 
     /**
-     * Enables USB data when disabled due to {@link UsbPortStatus#USB_DATA_STATUS_DISABLED_DOCK}
+     * Enables USB data when disabled due to {@link UsbPortStatus#DATA_STATUS_DISABLED_DOCK}
      */
     public void enableUsbDataWhileDocked(@NonNull String portId, long transactionId,
             IUsbOperationInternal callback, IndentingPrintWriter pw) {
@@ -844,7 +844,7 @@
                         portInfo.contaminantDetectionStatus,
                         portInfo.usbDataStatus,
                         portInfo.powerTransferLimited,
-                        portInfo.powerBrickStatus, pw);
+                        portInfo.powerBrickConnectionStatus, pw);
             }
         } else {
             for (RawPortInfo currentPortInfo : newPortInfo) {
@@ -859,7 +859,7 @@
                         currentPortInfo.contaminantDetectionStatus,
                         currentPortInfo.usbDataStatus,
                         currentPortInfo.powerTransferLimited,
-                        currentPortInfo.powerBrickStatus, pw);
+                        currentPortInfo.powerBrickConnectionStatus, pw);
             }
         }
 
@@ -895,9 +895,9 @@
             int contaminantProtectionStatus,
             boolean supportsEnableContaminantPresenceDetection,
             int contaminantDetectionStatus,
-            int[] usbDataStatus,
+            int usbDataStatus,
             boolean powerTransferLimited,
-            int powerBrickStatus,
+            int powerBrickConnectionStatus,
             IndentingPrintWriter pw) {
         // Only allow mode switch capability for dual role ports.
         // Validate that the current mode matches the supported modes we expect.
@@ -957,7 +957,7 @@
                     currentDataRole, canChangeDataRole,
                     supportedRoleCombinations, contaminantProtectionStatus,
                     contaminantDetectionStatus, usbDataStatus,
-                    powerTransferLimited, powerBrickStatus);
+                    powerTransferLimited, powerBrickConnectionStatus);
             mPorts.put(portId, portInfo);
         } else {
             // Validate that ports aren't changing definition out from under us.
@@ -995,7 +995,7 @@
                     currentDataRole, canChangeDataRole,
                     supportedRoleCombinations, contaminantProtectionStatus,
                     contaminantDetectionStatus, usbDataStatus,
-                    powerTransferLimited, powerBrickStatus)) {
+                    powerTransferLimited, powerBrickConnectionStatus)) {
                 portInfo.mDisposition = PortInfo.DISPOSITION_CHANGED;
             } else {
                 portInfo.mDisposition = PortInfo.DISPOSITION_READY;
@@ -1222,7 +1222,7 @@
                 mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
                         supportedRoleCombinations, UsbPortStatus.CONTAMINANT_PROTECTION_NONE,
                         UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED,
-                        new int[]{UsbPortStatus.USB_DATA_STATUS_UNKNOWN}, false,
+                        UsbPortStatus.DATA_STATUS_UNKNOWN, false,
                         UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN);
                 dispositionChanged = true;
             }
@@ -1238,31 +1238,12 @@
             return dispositionChanged;
         }
 
-        private boolean dataStatusEquals(int[] dataStatusL, int[] dataStatusR) {
-            if (dataStatusL == null && dataStatusR == null) {
-                return true;
-            }
-            if ((dataStatusL == null && dataStatusR != null)
-                || (dataStatusL != null && dataStatusR == null)) {
-                return false;
-            }
-            if (dataStatusL.length != dataStatusR.length) {
-                return false;
-            }
-            for (int i = 0; i < dataStatusL.length; i++) {
-                if (dataStatusL[i] != dataStatusR[i]) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
         public boolean setStatus(int currentMode, boolean canChangeMode,
                 int currentPowerRole, boolean canChangePowerRole,
                 int currentDataRole, boolean canChangeDataRole,
                 int supportedRoleCombinations, int contaminantProtectionStatus,
-                int contaminantDetectionStatus, int[] usbDataStatus,
-                boolean powerTransferLimited, int powerBrickStatus) {
+                int contaminantDetectionStatus, int usbDataStatus,
+                boolean powerTransferLimited, int powerBrickConnectionStatus) {
             boolean dispositionChanged = false;
 
             mCanChangeMode = canChangeMode;
@@ -1278,15 +1259,16 @@
                     != contaminantProtectionStatus
                     || mUsbPortStatus.getContaminantDetectionStatus()
                     != contaminantDetectionStatus
-                    || !dataStatusEquals(mUsbPortStatus.getUsbDataStatus(), usbDataStatus)
+                    || mUsbPortStatus.getUsbDataStatus()
+                    != usbDataStatus
                     || mUsbPortStatus.isPowerTransferLimited()
                     != powerTransferLimited
-                    || mUsbPortStatus.getPowerBrickStatus()
-                    != powerBrickStatus) {
+                    || mUsbPortStatus.getPowerBrickConnectionStatus()
+                    != powerBrickConnectionStatus) {
                 mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
                         supportedRoleCombinations, contaminantProtectionStatus,
                         contaminantDetectionStatus, usbDataStatus,
-                        powerTransferLimited, powerBrickStatus);
+                        powerTransferLimited, powerBrickConnectionStatus);
                 dispositionChanged = true;
             }
 
diff --git a/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java b/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
index dd25620..128a051 100644
--- a/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
+++ b/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
@@ -37,9 +37,9 @@
     public int contaminantProtectionStatus;
     public boolean supportsEnableContaminantPresenceDetection;
     public int contaminantDetectionStatus;
-    public int[] usbDataStatus;
+    public int usbDataStatus;
     public boolean powerTransferLimited;
-    public int powerBrickStatus;
+    public int powerBrickConnectionStatus;
 
     public RawPortInfo(String portId, int supportedModes) {
         this.portId = portId;
@@ -49,9 +49,10 @@
         this.contaminantProtectionStatus = UsbPortStatus.CONTAMINANT_PROTECTION_NONE;
         this.supportsEnableContaminantPresenceDetection = false;
         this.contaminantDetectionStatus = UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
-        this.usbDataStatus[0] = UsbPortStatus.USB_DATA_STATUS_UNKNOWN;
+        this.usbDataStatus = UsbPortStatus.DATA_STATUS_UNKNOWN;
+
         this.powerTransferLimited = false;
-        this.powerBrickStatus = UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN;
+        this.powerBrickConnectionStatus = UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN;
     }
 
     public RawPortInfo(String portId, int supportedModes, int supportedContaminantProtectionModes,
@@ -62,9 +63,9 @@
             int contaminantProtectionStatus,
             boolean supportsEnableContaminantPresenceDetection,
             int contaminantDetectionStatus,
-            int[] usbDataStatus,
+            int usbDataStatus,
             boolean powerTransferLimited,
-            int powerBrickStatus) {
+            int powerBrickConnectionStatus) {
         this.portId = portId;
         this.supportedModes = supportedModes;
         this.supportedContaminantProtectionModes = supportedContaminantProtectionModes;
@@ -82,7 +83,7 @@
         this.contaminantDetectionStatus = contaminantDetectionStatus;
         this.usbDataStatus = usbDataStatus;
         this.powerTransferLimited = powerTransferLimited;
-        this.powerBrickStatus = powerBrickStatus;
+        this.powerBrickConnectionStatus = powerBrickConnectionStatus;
     }
 
     @Override
@@ -105,10 +106,9 @@
         dest.writeInt(contaminantProtectionStatus);
         dest.writeBoolean(supportsEnableContaminantPresenceDetection);
         dest.writeInt(contaminantDetectionStatus);
-        dest.writeInt(usbDataStatus.length);
-        dest.writeIntArray(usbDataStatus);
+        dest.writeInt(usbDataStatus);
         dest.writeBoolean(powerTransferLimited);
-        dest.writeInt(powerBrickStatus);
+        dest.writeInt(powerBrickConnectionStatus);
     }
 
     public static final Parcelable.Creator<RawPortInfo> CREATOR =
@@ -128,10 +128,9 @@
             int contaminantProtectionStatus = in.readInt();
             boolean supportsEnableContaminantPresenceDetection = in.readBoolean();
             int contaminantDetectionStatus = in.readInt();
-            int[] usbDataStatus = new int[in.readInt()];
-            in.readIntArray(usbDataStatus);
+            int usbDataStatus = in.readInt();
             boolean powerTransferLimited = in.readBoolean();
-            int powerBrickStatus = in.readInt();
+            int powerBrickConnectionStatus = in.readInt();
             return new RawPortInfo(id, supportedModes,
                     supportedContaminantProtectionModes, currentMode, canChangeMode,
                     currentPowerRole, canChangePowerRole,
@@ -140,7 +139,7 @@
                     contaminantProtectionStatus,
                     supportsEnableContaminantPresenceDetection,
                     contaminantDetectionStatus, usbDataStatus,
-                    powerTransferLimited, powerBrickStatus);
+                    powerTransferLimited, powerBrickConnectionStatus);
         }
 
         @Override
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
index f468db3..1db018e 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
@@ -73,6 +73,42 @@
     private boolean mSystemReady;
     private long mTransactionId;
 
+    /**
+     * USB data status is not known.
+     */
+    public static final int USB_DATA_STATUS_UNKNOWN = 0;
+
+    /**
+     * USB data is enabled.
+     */
+    public static final int USB_DATA_STATUS_ENABLED = 1;
+
+    /**
+     * USB data is disabled as the port is too hot.
+     */
+    public static final int USB_DATA_STATUS_DISABLED_OVERHEAT = 2;
+
+    /**
+     * USB data is disabled due to contaminated port.
+     */
+    public static final int USB_DATA_STATUS_DISABLED_CONTAMINANT = 3;
+
+    /**
+     * USB data is disabled due to docking event.
+     */
+    public static final int USB_DATA_STATUS_DISABLED_DOCK = 4;
+
+    /**
+     * USB data is disabled by
+     * {@link UsbPort#enableUsbData UsbPort.enableUsbData}.
+     */
+    public static final int USB_DATA_STATUS_DISABLED_FORCE = 5;
+
+    /**
+     * USB data is disabled for debug.
+     */
+    public static final int USB_DATA_STATUS_DISABLED_DEBUG = 6;
+
     public @UsbHalVersion int getUsbHalVersion() throws RemoteException {
         synchronized (mLock) {
             if (mProxy == null) {
@@ -489,12 +525,34 @@
             return supportedContaminantProtectionModes;
         }
 
-        private int[] toIntArray(byte[] input) {
-            int[] output = new int[input.length];
-            for (int i = 0; i < input.length; i++) {
-                output[i] = input[i];
+        private int toUsbDataStatusInt(byte[] usbDataStatusHal) {
+            int usbDataStatus = UsbPortStatus.DATA_STATUS_UNKNOWN;
+            for (int i = 0; i < usbDataStatusHal.length; i++) {
+                switch (usbDataStatusHal[i]) {
+                    case USB_DATA_STATUS_ENABLED:
+                        usbDataStatus |= UsbPortStatus.DATA_STATUS_ENABLED;
+                        break;
+                    case USB_DATA_STATUS_DISABLED_OVERHEAT:
+                        usbDataStatus |= UsbPortStatus.DATA_STATUS_DISABLED_OVERHEAT;
+                        break;
+                    case USB_DATA_STATUS_DISABLED_CONTAMINANT:
+                        usbDataStatus |= UsbPortStatus.DATA_STATUS_DISABLED_CONTAMINANT;
+                        break;
+                    case USB_DATA_STATUS_DISABLED_DOCK:
+                        usbDataStatus |= UsbPortStatus.DATA_STATUS_DISABLED_DOCK;
+                        break;
+                    case USB_DATA_STATUS_DISABLED_FORCE:
+                        usbDataStatus |= UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
+                        break;
+                    case USB_DATA_STATUS_DISABLED_DEBUG:
+                        usbDataStatus |= UsbPortStatus.DATA_STATUS_DISABLED_DEBUG;
+                        break;
+                    default:
+                        usbDataStatus |= UsbPortStatus.DATA_STATUS_UNKNOWN;
+                }
             }
-            return output;
+            UsbPortManager.logAndPrint(Log.INFO, mPw, "AIDL UsbDataStatus:" + usbDataStatus);
+            return usbDataStatus;
         }
 
         @Override
@@ -528,7 +586,7 @@
                         toContaminantProtectionStatus(current.contaminantProtectionStatus),
                         current.supportsEnableContaminantPresenceDetection,
                         current.contaminantDetectionStatus,
-                        toIntArray(current.usbDataStatus),
+                        toUsbDataStatusInt(current.usbDataStatus),
                         current.powerTransferLimited,
                         current.powerBrickStatus);
                 newPortInfo.add(temp);
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
index 64e8adc..c7f0775 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
@@ -33,8 +33,8 @@
 import static android.hardware.usb.UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN;
 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_DISABLED_FORCE;
-import static android.hardware.usb.UsbPortStatus.USB_DATA_STATUS_UNKNOWN;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
+import static android.hardware.usb.UsbPortStatus.DATA_STATUS_UNKNOWN;
 
 
 import static com.android.server.usb.UsbPortManager.logAndPrint;
@@ -85,7 +85,7 @@
     private HALCallback mHALCallback;
     private boolean mSystemReady;
     // Workaround since HIDL HAL versions report UsbDataEnabled status in UsbPortStatus;
-    private static int sUsbDataStatus = USB_DATA_STATUS_UNKNOWN;
+    private static int sUsbDataStatus = DATA_STATUS_UNKNOWN;
 
     public @UsbHalVersion int getUsbHalVersion() throws RemoteException {
         int version;
@@ -375,7 +375,7 @@
             }
         }
         if (success) {
-            sUsbDataStatus = enable ? USB_DATA_STATUS_UNKNOWN : USB_DATA_STATUS_DISABLED_FORCE;
+            sUsbDataStatus = enable ? DATA_STATUS_UNKNOWN : DATA_STATUS_DISABLED_FORCE;
         }
         try {
             callback.onOperationComplete(success
@@ -421,7 +421,7 @@
                         current.canChangePowerRole,
                         current.currentDataRole, current.canChangeDataRole,
                         false, CONTAMINANT_PROTECTION_NONE,
-                        false, CONTAMINANT_DETECTION_NOT_SUPPORTED, new int[sUsbDataStatus],
+                        false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataStatus,
                         false, POWER_BRICK_STATUS_UNKNOWN);
                 newPortInfo.add(temp);
                 UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_0: "
@@ -455,7 +455,7 @@
                         current.status.canChangePowerRole,
                         current.status.currentDataRole, current.status.canChangeDataRole,
                         false, CONTAMINANT_PROTECTION_NONE,
-                        false, CONTAMINANT_DETECTION_NOT_SUPPORTED, new int[sUsbDataStatus],
+                        false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataStatus,
                         false, POWER_BRICK_STATUS_UNKNOWN);
                 newPortInfo.add(temp);
                 UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_1: "
@@ -493,7 +493,7 @@
                         current.contaminantProtectionStatus,
                         current.supportsEnableContaminantPresenceDetection,
                         current.contaminantDetectionStatus,
-                        new int[sUsbDataStatus],
+                        sUsbDataStatus,
                         false, POWER_BRICK_STATUS_UNKNOWN);
                 newPortInfo.add(temp);
                 UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_2: "
diff --git a/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.aidl b/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.aidl
new file mode 100644
index 0000000..542c6ad
--- /dev/null
+++ b/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 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.telephony;
+
+parcelable ActivityStatsTechSpecificInfo;
diff --git a/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.java b/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.java
new file mode 100644
index 0000000..e5a20ea
--- /dev/null
+++ b/telephony/java/android/telephony/ActivityStatsTechSpecificInfo.java
@@ -0,0 +1,245 @@
+/*
+ * 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.telephony;
+
+import android.annotation.DurationMillisLong;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.ServiceState.FrequencyRange;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Technology specific activity stats info. List of the activity stats for each RATs (2G, 3G, 4G and
+ * 5G) and frequency ranges (HIGH for sub6 and MMWAVE) in case of 5G. In case implementation doesn't
+ * have RAT specific activity stats then send only one activity stats info with RAT unknown.
+ *
+ * @hide
+ */
+public final class ActivityStatsTechSpecificInfo implements Parcelable {
+    private static final int TX_POWER_LEVELS = 5;
+
+    private int mRat;
+    private int mFrequencyRange;
+    private int[] mTxTimeMs;
+    private int mRxTimeMs;
+
+    /** @hide */
+    public ActivityStatsTechSpecificInfo(
+            int rat, @FrequencyRange int frequencyRange, @NonNull int[] txTimeMs, int rxTimeMs) {
+        Objects.requireNonNull(txTimeMs);
+        if (txTimeMs.length != TX_POWER_LEVELS) {
+            throw new IllegalArgumentException("txTimeMs must have length == TX_POWER_LEVELS");
+        }
+        mRat = rat;
+        mFrequencyRange = frequencyRange;
+        mTxTimeMs = txTimeMs;
+        mRxTimeMs = rxTimeMs;
+    }
+
+    /**
+     * Returns the radio access technology for this activity stats info.
+     *
+     * The returned value is define in {@link AccessNetworkConstants.AccessNetworkType};
+     * @hide
+     */
+    public int getRat() {
+        return mRat;
+    }
+
+    /**
+     * Returns the rough frequency range for this activity stats info.
+     *
+     * The returned value is define in {@link ServiceState.FrequencyRange};
+     * @hide
+     */
+    public @FrequencyRange int getFrequencyRange() {
+        return mFrequencyRange;
+    }
+
+    /**
+     * Gets the amount of time the modem spent transmitting at a certain power level.
+     *
+     * @return The amount of time, in milliseconds, that the modem spent transmitting at the given
+     *     power level.
+     */
+    public @DurationMillisLong long getTransmitTimeMillis(int powerLevel) {
+        return mTxTimeMs[powerLevel];
+    }
+
+    /**
+     * @return The raw array of transmit power durations
+     * @hide
+     */
+    @NonNull
+    public int[] getTransmitTimeMillis() {
+        return mTxTimeMs;
+    }
+
+    /**
+     * Gets the amount of time (in milliseconds) when the modem is awake and receiving data.
+     *
+     * @return Time in milliseconds.
+     * @hide
+     */
+    public @DurationMillisLong long getReceiveTimeMillis() {
+        return mRxTimeMs;
+    }
+    /** @hide */
+    public void setRat(int rat) {
+        mRat = rat;
+    }
+
+    /** @hide */
+    public void setFrequencyRange(@FrequencyRange int frequencyRange) {
+        mFrequencyRange = frequencyRange;
+    }
+
+    /** @hide */
+    public void setReceiveTimeMillis(int receiveTimeMillis) {
+        mRxTimeMs = receiveTimeMillis;
+    }
+
+    /**
+     * Provided for convenience, since the API surface needs to return longs but internal
+     * representations are ints.
+     *
+     * @hide
+     */
+    public void setReceiveTimeMillis(long receiveTimeMillis) {
+        mRxTimeMs = (int) receiveTimeMillis;
+    }
+
+    /** @hide */
+    public void setTransmitTimeMillis(int[] txTimeMs) {
+        mTxTimeMs = Arrays.copyOf(txTimeMs, TX_POWER_LEVELS);
+    }
+
+    /** @hide */
+    public boolean isTxPowerValid() {
+        return Arrays.stream(mTxTimeMs).allMatch((i) -> i >= 0);
+    }
+
+    /** @hide */
+    public boolean isRxPowerValid() {
+        return getReceiveTimeMillis() >= 0;
+    }
+
+    /** @hide */
+    public boolean isTxPowerEmpty() {
+        boolean isTxPowerEmpty =
+                mTxTimeMs == null
+                        || mTxTimeMs.length == 0
+                        || Arrays.stream(mTxTimeMs).allMatch((i) -> i == 0);
+        return isTxPowerEmpty;
+    }
+
+    /** @hide */
+    public boolean isRxPowerEmpty() {
+        return getReceiveTimeMillis() == 0;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Objects.hash(mRat, mFrequencyRange, mRxTimeMs);
+        result = 31 * result + Arrays.hashCode(mTxTimeMs);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof ActivityStatsTechSpecificInfo)) return false;
+        ActivityStatsTechSpecificInfo that = (ActivityStatsTechSpecificInfo) o;
+        return mRat == that.mRat
+                && mFrequencyRange == that.mFrequencyRange
+                && Arrays.equals(mTxTimeMs, that.mTxTimeMs)
+                && mRxTimeMs == that.mRxTimeMs;
+    }
+
+    private static String ratToString(int type) {
+        switch (type) {
+            case AccessNetworkConstants.AccessNetworkType.UNKNOWN:
+                return "UNKNOWN";
+            case AccessNetworkConstants.AccessNetworkType.GERAN:
+                return "GERAN";
+            case AccessNetworkConstants.AccessNetworkType.UTRAN:
+                return "UTRAN";
+            case AccessNetworkConstants.AccessNetworkType.EUTRAN:
+                return "EUTRAN";
+            case AccessNetworkConstants.AccessNetworkType.CDMA2000:
+                return "CDMA2000";
+            case AccessNetworkConstants.AccessNetworkType.IWLAN:
+                return "IWLAN";
+            case AccessNetworkConstants.AccessNetworkType.NGRAN:
+                return "NGRAN";
+            default:
+                return Integer.toString(type);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder()
+                .append("{mRat=")
+                .append(ratToString(mRat))
+                .append(",mFrequencyRange=")
+                .append(ServiceState.frequencyRangeToString(mFrequencyRange))
+                .append(",mTxTimeMs[]=")
+                .append(Arrays.toString(mTxTimeMs))
+                .append(",mRxTimeMs=")
+                .append(mRxTimeMs)
+                .append("}")
+                .toString();
+    }
+
+    /**
+     * {@link Parcelable#describeContents}
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final @android.annotation.NonNull Parcelable.Creator<
+                    ActivityStatsTechSpecificInfo>
+            CREATOR =
+                    new Parcelable.Creator<ActivityStatsTechSpecificInfo>() {
+                public ActivityStatsTechSpecificInfo createFromParcel(@NonNull Parcel in) {
+                    int rat = in.readInt();
+                    int frequencyRange = in.readInt();
+                    int[] txTimeMs = new int[TX_POWER_LEVELS];
+                    in.readIntArray(txTimeMs);
+                    int rxTimeMs = in.readInt();
+                    return new ActivityStatsTechSpecificInfo(
+                            rat, frequencyRange, txTimeMs, rxTimeMs);
+                }
+
+                public ActivityStatsTechSpecificInfo[] newArray(int size) {
+                    return new ActivityStatsTechSpecificInfo[size];
+                }
+    };
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mRat);
+        dest.writeInt(mFrequencyRange);
+        dest.writeIntArray(mTxTimeMs);
+        dest.writeInt(mRxTimeMs);
+    }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 2c39863..9f53d73 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -8124,6 +8124,13 @@
             "telephony_data_handover_retry_rules_string_array";
 
     /**
+     * Indicates whether delay tearing down IMS data network until voice call ends.
+     * @hide
+     */
+    public static final String KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL =
+            "delay_ims_tear_down_until_call_end_bool";
+
+    /**
      * The patterns of missed incoming call sms. This is the regular expression used for
      * matching the missed incoming call's date, time, and caller id. The pattern should match
      * fields for at least month, day, hour, and minute. Year is optional although it is encouraged.
@@ -8968,6 +8975,7 @@
                 KEY_TELEPHONY_DATA_HANDOVER_RETRY_RULES_STRING_ARRAY, new String[] {
                         "retry_interval=1000|2000|4000|8000|16000, maximum_retries=5"
                 });
+        sDefaults.putBoolean(KEY_DELAY_IMS_TEAR_DOWN_UNTIL_CALL_END_BOOL, false);
         sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]);
         sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false);
         sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, "");
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
index 837124f..ca6dc2d 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
@@ -22,6 +22,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.Objects;
 
 
@@ -76,7 +78,8 @@
     /**
      * @hide
      */
-    DataSpecificRegistrationInfo(
+    @VisibleForTesting
+    public DataSpecificRegistrationInfo(
             int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable,
             boolean isEnDcAvailable, @Nullable VopsSupportInfo vops) {
         this.maxDataCalls = maxDataCalls;
@@ -186,7 +189,7 @@
     /**
      * @return The VOPS (Voice over Packet Switched) support information.
      *
-     * The instance of {@link LTEVopsSupportInfo}, or {@link NrVopsSupportInfo},
+     * The instance of {@link LteVopsSupportInfo}, or {@link NrVopsSupportInfo},
      * null if there is there is no VOPS support information available.
      */
     @Nullable
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index ec6c25d..730a9d1 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -25,6 +25,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
+import android.telephony.ServiceState.FrequencyRange;
 import android.util.Range;
 
 import java.lang.annotation.Retention;
@@ -94,8 +95,10 @@
     private long mTimestamp;
     private int mSleepTimeMs;
     private int mIdleTimeMs;
-    private int[] mTxTimeMs;
-    private int mRxTimeMs;
+    private int[] mTotalTxTimeMs;
+    private int mTotalRxTimeMs;
+    private int mSizeOfSpecificInfo;
+    private ActivityStatsTechSpecificInfo[] mActivityStatsTechSpecificInfo;
 
     /**
      * @hide
@@ -110,8 +113,17 @@
         mTimestamp = timestamp;
         mSleepTimeMs = sleepTimeMs;
         mIdleTimeMs = idleTimeMs;
-        mTxTimeMs = txTimeMs;
-        mRxTimeMs = rxTimeMs;
+        mTotalTxTimeMs = txTimeMs;
+        mTotalRxTimeMs = rxTimeMs;
+
+        mActivityStatsTechSpecificInfo = new ActivityStatsTechSpecificInfo[1];
+        mSizeOfSpecificInfo = mActivityStatsTechSpecificInfo.length;
+        mActivityStatsTechSpecificInfo[0] =
+                new ActivityStatsTechSpecificInfo(
+                        AccessNetworkConstants.AccessNetworkType.UNKNOWN,
+                        ServiceState.FREQUENCY_RANGE_UNKNOWN,
+                        txTimeMs,
+                        rxTimeMs);
     }
 
     /**
@@ -124,14 +136,49 @@
         this(timestamp, (int) sleepTimeMs, (int) idleTimeMs, txTimeMs, (int) rxTimeMs);
     }
 
+    /** @hide */
+    public ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs,
+                        @NonNull ActivityStatsTechSpecificInfo[] activityStatsTechSpecificInfo) {
+        mTimestamp = timestamp;
+        mSleepTimeMs = sleepTimeMs;
+        mIdleTimeMs = idleTimeMs;
+        mActivityStatsTechSpecificInfo = activityStatsTechSpecificInfo;
+        mSizeOfSpecificInfo = mActivityStatsTechSpecificInfo.length;
+        mTotalTxTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
+        for (int i = 0; i < getNumTxPowerLevels(); i++) {
+            for (int j = 0; j < getSpecificInfoLength(); j++) {
+                mTotalTxTimeMs[i] = mTotalTxTimeMs[i]
+                            + (int) mActivityStatsTechSpecificInfo[j].getTransmitTimeMillis(i);
+            }
+        }
+        mTotalRxTimeMs = 0;
+        for (int i = 0; i < getSpecificInfoLength(); i++) {
+            mTotalRxTimeMs =
+                    mTotalRxTimeMs + (int) mActivityStatsTechSpecificInfo[i].getReceiveTimeMillis();
+        }
+    }
+
+    /**
+     * Provided for convenience in manipulation since the API exposes long values but internal
+     * representations are ints.
+     * @hide
+     */
+    public ModemActivityInfo(long timestamp, long sleepTimeMs, long idleTimeMs,
+                        @NonNull ActivityStatsTechSpecificInfo[] activityStatsTechSpecificInfo) {
+        this(timestamp, (int) sleepTimeMs, (int) idleTimeMs, activityStatsTechSpecificInfo);
+    }
+
     @Override
     public String toString() {
         return "ModemActivityInfo{"
-            + " mTimestamp=" + mTimestamp
-            + " mSleepTimeMs=" + mSleepTimeMs
-            + " mIdleTimeMs=" + mIdleTimeMs
-            + " mTxTimeMs[]=" + Arrays.toString(mTxTimeMs)
-            + " mRxTimeMs=" + mRxTimeMs
+            + " mTimestamp="
+            + mTimestamp
+            + " mSleepTimeMs="
+            + mSleepTimeMs
+            + " mIdleTimeMs="
+            + mIdleTimeMs
+            + " mActivityStatsTechSpecificInfo="
+            + Arrays.toString(mActivityStatsTechSpecificInfo)
             + "}";
     }
 
@@ -145,11 +192,17 @@
             long timestamp = in.readLong();
             int sleepTimeMs = in.readInt();
             int idleTimeMs = in.readInt();
-            int[] txTimeMs = new int[TX_POWER_LEVELS];
-            in.readIntArray(txTimeMs);
-            int rxTimeMs = in.readInt();
-            return new ModemActivityInfo(timestamp, sleepTimeMs, idleTimeMs,
-                                txTimeMs, rxTimeMs);
+            Parcelable[] tempSpecifiers =
+                    in.createTypedArray(ActivityStatsTechSpecificInfo.CREATOR);
+            ActivityStatsTechSpecificInfo[] activityStatsTechSpecificInfo;
+            activityStatsTechSpecificInfo =
+                    new ActivityStatsTechSpecificInfo[tempSpecifiers.length];
+            for (int i = 0; i < tempSpecifiers.length; i++) {
+                activityStatsTechSpecificInfo[i] =
+                                (ActivityStatsTechSpecificInfo) tempSpecifiers[i];
+                    }
+            return new ModemActivityInfo(
+                    timestamp, sleepTimeMs, idleTimeMs, activityStatsTechSpecificInfo);
         }
 
         public ModemActivityInfo[] newArray(int size) {
@@ -165,15 +218,14 @@
         dest.writeLong(mTimestamp);
         dest.writeInt(mSleepTimeMs);
         dest.writeInt(mIdleTimeMs);
-        dest.writeIntArray(mTxTimeMs);
-        dest.writeInt(mRxTimeMs);
+        dest.writeTypedArray(mActivityStatsTechSpecificInfo, flags);
     }
 
     /**
      * Gets the timestamp at which this modem activity info was recorded.
      *
-     * @return The timestamp, as returned by {@link SystemClock#elapsedRealtime()}, when this
-     * {@link ModemActivityInfo} was recorded.
+     * @return The timestamp, as returned by {@link SystemClock#elapsedRealtime()}, when this {@link
+     *     ModemActivityInfo} was recorded.
      */
     public @ElapsedRealtimeLong long getTimestampMillis() {
         return mTimestamp;
@@ -188,14 +240,41 @@
      * Gets the amount of time the modem spent transmitting at a certain power level.
      *
      * @param powerLevel The power level to query.
-     * @return The amount of time, in milliseconds, that the modem spent transmitting at the
-     * given power level.
+     * @return The amount of time, in milliseconds, that the modem spent transmitting at the given
+     *     power level.
      */
     public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
             @TxPowerLevel int powerLevel) {
-        return mTxTimeMs[powerLevel];
+        long txTimeMsAtPowerLevel = 0;
+        for (int i = 0; i < getSpecificInfoLength(); i++) {
+            txTimeMsAtPowerLevel +=
+                    mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis(powerLevel);
+        }
+        return txTimeMsAtPowerLevel;
     }
 
+    /** @hide */
+    public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
+            @TxPowerLevel int powerLevel, int rat) {
+        for (int i = 0; i < getSpecificInfoLength(); i++) {
+            if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
+                return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis(powerLevel);
+            }
+        }
+        return 0;
+    }
+
+    /** @hide */
+    public @DurationMillisLong long getTransmitDurationMillisAtPowerLevel(
+            @TxPowerLevel int powerLevel, int rat, @FrequencyRange int freq) {
+        for (int i = 0; i < getSpecificInfoLength(); i++) {
+            if (mActivityStatsTechSpecificInfo[i].getRat() == rat
+                    && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
+                return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis(powerLevel);
+            }
+        }
+        return 0;
+    }
     /**
      * Gets the range of transmit powers corresponding to a certain power level.
      *
@@ -208,17 +287,64 @@
     }
 
     /** @hide */
-    public void setTransmitTimeMillis(int[] txTimeMs) {
-        mTxTimeMs = Arrays.copyOf(txTimeMs, TX_POWER_LEVELS);
+    public int getSpecificInfoRat(int index) {
+        return mActivityStatsTechSpecificInfo[index].getRat();
     }
 
+    /** @hide */
+    public int getSpecificInfoFrequencyRange(int index) {
+        return mActivityStatsTechSpecificInfo[index].getFrequencyRange();
+    }
+    /** @hide */
+    public void setTransmitTimeMillis(int[] txTimeMs) {
+        mTotalTxTimeMs = Arrays.copyOf(txTimeMs, TX_POWER_LEVELS);
+    }
+    /** @hide */
+    public void setTransmitTimeMillis(int rat, int[] txTimeMs) {
+        for (int i = 0; i < getSpecificInfoLength(); i++) {
+            if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
+                mActivityStatsTechSpecificInfo[i].setTransmitTimeMillis(txTimeMs);
+            }
+        }
+    }
+    /** @hide */
+    public void setTransmitTimeMillis(int rat, int freq, int[] txTimeMs) {
+        for (int i = 0; i < getSpecificInfoLength(); i++) {
+            if (mActivityStatsTechSpecificInfo[i].getRat() == rat
+                    && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
+                mActivityStatsTechSpecificInfo[i].setTransmitTimeMillis(txTimeMs);
+            }
+        }
+    }
     /**
      * @return The raw array of transmit power durations
      * @hide
      */
     @NonNull
     public int[] getTransmitTimeMillis() {
-        return mTxTimeMs;
+        return mTotalTxTimeMs;
+    }
+
+    /** @hide */
+    public int[] getTransmitTimeMillis(@AccessNetworkConstants.RadioAccessNetworkType int rat) {
+        for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+            if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
+                return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis();
+            }
+        }
+        return new int[5];
+    }
+
+    /** @hide */
+    public int[] getTransmitTimeMillis(
+            @AccessNetworkConstants.RadioAccessNetworkType int rat, @FrequencyRange int freq) {
+        for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+            if (mActivityStatsTechSpecificInfo[i].getRat() == rat
+                    && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
+                return mActivityStatsTechSpecificInfo[i].getTransmitTimeMillis();
+            }
+        }
+        return new int[5];
     }
 
     /**
@@ -238,6 +364,7 @@
     /**
      * Provided for convenience, since the API surface needs to return longs but internal
      * representations are ints.
+     *
      * @hide
      */
     public void setSleepTimeMillis(long sleepTimeMillis) {
@@ -257,14 +384,63 @@
      */
     public @NonNull ModemActivityInfo getDelta(@NonNull ModemActivityInfo other) {
         int[] txTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
-        for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) {
-            txTimeMs[i] = other.mTxTimeMs[i] - mTxTimeMs[i];
+
+        ActivityStatsTechSpecificInfo[] mDeltaSpecificInfo;
+        mDeltaSpecificInfo = new ActivityStatsTechSpecificInfo[other.getSpecificInfoLength()];
+
+        boolean matched;
+        for (int i = 0; i < other.getSpecificInfoLength(); i++) {
+            matched = false;
+            for (int j = 0; j < getSpecificInfoLength(); j++) {
+                int rat = mActivityStatsTechSpecificInfo[j].getRat();
+                if (rat == other.mActivityStatsTechSpecificInfo[i].getRat() && !matched) {
+                    if (mActivityStatsTechSpecificInfo[j].getRat()
+                            == AccessNetworkConstants.AccessNetworkType.NGRAN) {
+                        if (other.mActivityStatsTechSpecificInfo[i].getFrequencyRange()
+                                == mActivityStatsTechSpecificInfo[j].getFrequencyRange()) {
+                            int freq = mActivityStatsTechSpecificInfo[j].getFrequencyRange();
+                            for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
+                                txTimeMs[lvl] =
+                                        (int) (other.getTransmitDurationMillisAtPowerLevel(
+                                                            lvl, rat, freq)
+                                                        - getTransmitDurationMillisAtPowerLevel(
+                                                            lvl, rat, freq));
+                            }
+                            matched = true;
+                            mDeltaSpecificInfo[i] =
+                                    new ActivityStatsTechSpecificInfo(
+                                            rat,
+                                            freq,
+                                            txTimeMs,
+                                            (int) (other.getReceiveTimeMillis(rat, freq)
+                                                        - getReceiveTimeMillis(rat, freq)));
+                        }
+                    } else {
+                        for (int lvl = 0; lvl < ModemActivityInfo.TX_POWER_LEVELS; lvl++) {
+                            txTimeMs[lvl] =
+                                    (int) (other.getTransmitDurationMillisAtPowerLevel(lvl, rat)
+                                                - getTransmitDurationMillisAtPowerLevel(lvl, rat));
+                        }
+                        matched = true;
+                        mDeltaSpecificInfo[i] =
+                                new ActivityStatsTechSpecificInfo(
+                                        rat,
+                                        ServiceState.FREQUENCY_RANGE_UNKNOWN,
+                                        txTimeMs,
+                                        (int) (other.getReceiveTimeMillis(rat)
+                                                     - getReceiveTimeMillis(rat)));
+                    }
+                }
+            }
+            if (!matched) {
+                mDeltaSpecificInfo[i] = other.mActivityStatsTechSpecificInfo[i];
+            }
         }
-        return new ModemActivityInfo(other.getTimestampMillis(),
+        return new ModemActivityInfo(
+                other.getTimestampMillis(),
                 other.getSleepTimeMillis() - getSleepTimeMillis(),
                 other.getIdleTimeMillis() - getIdleTimeMillis(),
-                txTimeMs,
-                other.getReceiveTimeMillis() - getReceiveTimeMillis());
+                mDeltaSpecificInfo);
     }
 
     /**
@@ -285,6 +461,7 @@
     /**
      * Provided for convenience, since the API surface needs to return longs but internal
      * representations are ints.
+     *
      * @hide
      */
     public void setIdleTimeMillis(long idleTimeMillis) {
@@ -297,21 +474,66 @@
      * @return Time in milliseconds.
      */
     public @DurationMillisLong long getReceiveTimeMillis() {
-        return mRxTimeMs;
+        return mTotalRxTimeMs;
+    }
+
+    /** @hide */
+    public @DurationMillisLong long getReceiveTimeMillis(int rat) {
+        for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+            if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
+                return mActivityStatsTechSpecificInfo[i].getReceiveTimeMillis();
+            }
+        }
+        return 0;
+    }
+    /** @hide */
+    public @DurationMillisLong long getReceiveTimeMillis(int rat, int freq) {
+        for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+            if (mActivityStatsTechSpecificInfo[i].getRat() == rat
+                    && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
+                return mActivityStatsTechSpecificInfo[i].getReceiveTimeMillis();
+            }
+        }
+        return 0;
     }
 
     /** @hide */
     public void setReceiveTimeMillis(int rxTimeMillis) {
-        mRxTimeMs = rxTimeMillis;
+        mTotalRxTimeMs = rxTimeMillis;
     }
 
     /**
      * Provided for convenience, since the API surface needs to return longs but internal
      * representations are ints.
+     *
      * @hide
      */
     public void setReceiveTimeMillis(long receiveTimeMillis) {
-        mRxTimeMs = (int) receiveTimeMillis;
+        mTotalRxTimeMs = (int) receiveTimeMillis;
+    }
+
+    /** @hide */
+    public void setReceiveTimeMillis(int rat, long receiveTimeMillis) {
+        for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+            if (mActivityStatsTechSpecificInfo[i].getRat() == rat) {
+                mActivityStatsTechSpecificInfo[i].setReceiveTimeMillis(receiveTimeMillis);
+            }
+        }
+    }
+
+    /** @hide */
+    public void setReceiveTimeMillis(int rat, int freq, long receiveTimeMillis) {
+        for (int i = 0; i < mActivityStatsTechSpecificInfo.length; i++) {
+            if (mActivityStatsTechSpecificInfo[i].getRat() == rat
+                    && mActivityStatsTechSpecificInfo[i].getFrequencyRange() == freq) {
+                mActivityStatsTechSpecificInfo[i].setReceiveTimeMillis(receiveTimeMillis);
+            }
+        }
+    }
+
+    /** @hide */
+    public int getSpecificInfoLength() {
+        return mSizeOfSpecificInfo;
     }
 
     /**
@@ -323,23 +545,42 @@
      */
     @TestApi
     public boolean isValid() {
-        boolean isTxPowerValid = Arrays.stream(mTxTimeMs).allMatch((i) -> i >= 0);
-
-        return isTxPowerValid && ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0)
-                && (getReceiveTimeMillis() >= 0) && !isEmpty());
+        if (mActivityStatsTechSpecificInfo == null) {
+            return false;
+        } else {
+            boolean isTxPowerValid = true;
+            boolean isRxPowerValid = true;
+            for (int i = 0; i < getSpecificInfoLength(); i++) {
+                if (!mActivityStatsTechSpecificInfo[i].isTxPowerValid()) {
+                    isTxPowerValid = false;
+                }
+                if (!mActivityStatsTechSpecificInfo[i].isRxPowerValid()) {
+                    isRxPowerValid = false;
+                }
+            }
+            return isTxPowerValid
+                    && isRxPowerValid
+                    && ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0) && !isEmpty());
+        }
     }
 
     /** @hide */
     @TestApi
     public boolean isEmpty() {
-        boolean isTxPowerEmpty = mTxTimeMs == null || mTxTimeMs.length == 0
-                || Arrays.stream(mTxTimeMs).allMatch((i) -> i == 0);
-
-        return isTxPowerEmpty && ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0)
-                && (getReceiveTimeMillis() == 0));
+        boolean isTxPowerEmpty = false;
+        boolean isRxPowerEmpty = false;
+        for (int i = 0; i < getSpecificInfoLength(); i++) {
+            if (mActivityStatsTechSpecificInfo[i].isTxPowerEmpty()) {
+                isTxPowerEmpty = true;
+            }
+            if (mActivityStatsTechSpecificInfo[i].isRxPowerEmpty()) {
+                isRxPowerEmpty = true;
+            }
+        }
+        return isTxPowerEmpty
+                && ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0) && isRxPowerEmpty);
     }
 
-
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
@@ -348,14 +589,15 @@
         return mTimestamp == that.mTimestamp
                 && mSleepTimeMs == that.mSleepTimeMs
                 && mIdleTimeMs == that.mIdleTimeMs
-                && mRxTimeMs == that.mRxTimeMs
-                && Arrays.equals(mTxTimeMs, that.mTxTimeMs);
+                && mSizeOfSpecificInfo == that.mSizeOfSpecificInfo
+                && Arrays.equals(
+                        mActivityStatsTechSpecificInfo, that.mActivityStatsTechSpecificInfo);
     }
 
     @Override
     public int hashCode() {
-        int result = Objects.hash(mTimestamp, mSleepTimeMs, mIdleTimeMs, mRxTimeMs);
-        result = 31 * result + Arrays.hashCode(mTxTimeMs);
+        int result = Objects.hash(mTimestamp, mSleepTimeMs, mIdleTimeMs, mTotalRxTimeMs);
+        result = 31 * result + Arrays.hashCode(mTotalTxTimeMs);
         return result;
     }
 }
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index c18443e..c701e44 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -242,13 +242,16 @@
      * @param cellIdentity The identity representing a unique cell or wifi AP. Set to null if the
      * information is not available.
      * @param rplmn the registered plmn or the last plmn for attempted registration if reg failed.
+     * @param voiceSpecificInfo Voice specific registration information.
+     * @param dataSpecificInfo Data specific registration information.
      */
     private NetworkRegistrationInfo(@Domain int domain, @TransportType int transportType,
-                                   @RegistrationState int registrationState,
-                                   @NetworkType int accessNetworkTechnology, int rejectCause,
-                                   boolean emergencyOnly,
-                                   @Nullable @ServiceType List<Integer> availableServices,
-                                   @Nullable CellIdentity cellIdentity, @Nullable String rplmn) {
+            @RegistrationState int registrationState,
+            @NetworkType int accessNetworkTechnology, int rejectCause,
+            boolean emergencyOnly, @Nullable @ServiceType List<Integer> availableServices,
+            @Nullable CellIdentity cellIdentity, @Nullable String rplmn,
+            @Nullable VoiceSpecificRegistrationInfo voiceSpecificInfo,
+            @Nullable DataSpecificRegistrationInfo dataSpecificInfo) {
         mDomain = domain;
         mTransportType = transportType;
         mRegistrationState = registrationState;
@@ -262,6 +265,10 @@
         mEmergencyOnly = emergencyOnly;
         mNrState = NR_STATE_NONE;
         mRplmn = rplmn;
+        mVoiceSpecificInfo = voiceSpecificInfo;
+        mDataSpecificInfo = dataSpecificInfo;
+
+        updateNrState();
     }
 
     /**
@@ -276,10 +283,9 @@
                                    boolean cssSupported, int roamingIndicator, int systemIsInPrl,
                                    int defaultRoamingIndicator) {
         this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
-                emergencyOnly, availableServices, cellIdentity, rplmn);
-
-        mVoiceSpecificInfo = new VoiceSpecificRegistrationInfo(cssSupported, roamingIndicator,
-                systemIsInPrl, defaultRoamingIndicator);
+                emergencyOnly, availableServices, cellIdentity, rplmn,
+                new VoiceSpecificRegistrationInfo(cssSupported, roamingIndicator,
+                        systemIsInPrl, defaultRoamingIndicator), null);
     }
 
     /**
@@ -295,11 +301,9 @@
                                    boolean isNrAvailable, boolean isEndcAvailable,
                                    @Nullable VopsSupportInfo vopsSupportInfo) {
         this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
-                emergencyOnly, availableServices, cellIdentity, rplmn);
-        mDataSpecificInfo = new DataSpecificRegistrationInfo(
-                maxDataCalls, isDcNrRestricted, isNrAvailable,
-                isEndcAvailable, vopsSupportInfo);
-        updateNrState();
+                emergencyOnly, availableServices, cellIdentity, rplmn, null,
+                new DataSpecificRegistrationInfo(maxDataCalls, isDcNrRestricted, isNrAvailable,
+                        isEndcAvailable, vopsSupportInfo));
     }
 
     private NetworkRegistrationInfo(Parcel source) {
@@ -804,6 +808,12 @@
         @NonNull
         private String mRplmn = "";
 
+        @Nullable
+        private DataSpecificRegistrationInfo mDataSpecificRegistrationInfo;
+
+        @Nullable
+        private VoiceSpecificRegistrationInfo mVoiceSpecificRegistrationInfo;
+
         /**
          * Default constructor for Builder.
          */
@@ -930,6 +940,30 @@
         }
 
         /**
+         * Set voice specific registration information.
+         *
+         * @param info The voice specific registration information.
+         * @return The builder.
+         * @hide
+         */
+        public @NonNull Builder setVoiceSpecificInfo(@NonNull VoiceSpecificRegistrationInfo info) {
+            mVoiceSpecificRegistrationInfo = info;
+            return this;
+        }
+
+        /**
+         * Set data specific registration information.
+         *
+         * @param info The data specific registration information.
+         * @return The builder.
+         * @hide
+         */
+        public @NonNull Builder setDataSpecificInfo(@NonNull DataSpecificRegistrationInfo info) {
+            mDataSpecificRegistrationInfo = info;
+            return this;
+        }
+
+        /**
          * Build the NetworkRegistrationInfo.
          * @return the NetworkRegistrationInfo object.
          * @hide
@@ -938,7 +972,8 @@
         public @NonNull NetworkRegistrationInfo build() {
             return new NetworkRegistrationInfo(mDomain, mTransportType, mRegistrationState,
                     mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
-                    mCellIdentity, mRplmn);
+                    mCellIdentity, mRplmn, mVoiceSpecificRegistrationInfo,
+                    mDataSpecificRegistrationInfo);
         }
     }
 }
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 70da9b9..6fe9bf9 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -767,6 +768,10 @@
      *
      * @return long name of operator, null if unregistered or unknown
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.ACCESS_FINE_LOCATION,
+            android.Manifest.permission.ACCESS_COARSE_LOCATION
+    })
     public String getOperatorAlphaLong() {
         return mOperatorAlphaLong;
     }
@@ -782,6 +787,10 @@
      * @return long name of operator
      * @hide
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.ACCESS_FINE_LOCATION,
+            android.Manifest.permission.ACCESS_COARSE_LOCATION
+    })
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
             publicAlternatives = "Use {@link #getOperatorAlphaLong} instead.")
     public String getVoiceOperatorAlphaLong() {
@@ -800,6 +809,10 @@
      *
      * @return short name of operator, null if unregistered or unknown
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.ACCESS_FINE_LOCATION,
+            android.Manifest.permission.ACCESS_COARSE_LOCATION
+    })
     public String getOperatorAlphaShort() {
         return mOperatorAlphaShort;
     }
@@ -815,6 +828,10 @@
      * @return short name of operator, null if unregistered or unknown
      * @hide
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.ACCESS_FINE_LOCATION,
+            android.Manifest.permission.ACCESS_COARSE_LOCATION
+    })
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
             publicAlternatives = "Use {@link #getOperatorAlphaShort} instead.")
     public String getVoiceOperatorAlphaShort() {
@@ -832,6 +849,10 @@
      * @return short name of operator, null if unregistered or unknown
      * @hide
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.ACCESS_FINE_LOCATION,
+            android.Manifest.permission.ACCESS_COARSE_LOCATION
+    })
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
             publicAlternatives = "Use {@link #getOperatorAlphaShort} instead.")
     public String getDataOperatorAlphaShort() {
@@ -853,6 +874,10 @@
      * @return name of operator, null if unregistered or unknown
      * @hide
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.ACCESS_FINE_LOCATION,
+            android.Manifest.permission.ACCESS_COARSE_LOCATION
+    })
     public String getOperatorAlpha() {
         if (TextUtils.isEmpty(mOperatorAlphaLong)) {
             return mOperatorAlphaShort;
@@ -878,6 +903,10 @@
      * The country code can be decoded using
      * {@link com.android.internal.telephony.MccTable#countryCodeForMcc(int)}.
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.ACCESS_FINE_LOCATION,
+            android.Manifest.permission.ACCESS_COARSE_LOCATION
+    })
     public String getOperatorNumeric() {
         return mOperatorNumeric;
     }
@@ -893,6 +922,10 @@
      * @return numeric format of operator, null if unregistered or unknown
      * @hide
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.ACCESS_FINE_LOCATION,
+            android.Manifest.permission.ACCESS_COARSE_LOCATION
+    })
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getVoiceOperatorNumeric() {
         return mOperatorNumeric;
@@ -909,6 +942,10 @@
      * @return numeric format of operator, null if unregistered or unknown
      * @hide
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.ACCESS_FINE_LOCATION,
+            android.Manifest.permission.ACCESS_COARSE_LOCATION
+    })
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q,
             publicAlternatives = "Use {@link #getOperatorNumeric} instead.")
     public String getDataOperatorNumeric() {
@@ -1168,7 +1205,15 @@
         }
     }
 
-    private void init() {
+    /**
+     * Initialize the service state. Set everything to the default value.
+     *
+     * @param legacyMode {@code true} if the device is on IWLAN legacy mode, where IWLAN is
+     * considered as a RAT on WWAN {@link NetworkRegistrationInfo}. {@code false} if the device
+     * is on AP-assisted mode, where IWLAN should be reported through WLAN.
+     * {@link NetworkRegistrationInfo}.
+     */
+    private void init(boolean legacyMode) {
         if (DBG) Rlog.d(LOG_TAG, "init");
         mVoiceRegState = STATE_OUT_OF_SERVICE;
         mDataRegState = STATE_OUT_OF_SERVICE;
@@ -1200,6 +1245,13 @@
                     .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
                     .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN)
                     .build());
+            if (!legacyMode) {
+                addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
+                        .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+                        .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
+                        .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN)
+                        .build());
+            }
         }
         mOperatorAlphaLongRaw = null;
         mOperatorAlphaShortRaw = null;
@@ -1208,15 +1260,32 @@
     }
 
     public void setStateOutOfService() {
-        init();
+        init(true);
     }
 
     public void setStateOff() {
-        init();
+        init(true);
         mVoiceRegState = STATE_POWER_OFF;
         mDataRegState = STATE_POWER_OFF;
     }
 
+    /**
+     * Set the service state to out-of-service
+     *
+     * @param legacyMode {@code true} if the device is on IWLAN legacy mode, where IWLAN is
+     * considered as a RAT on WWAN {@link NetworkRegistrationInfo}. {@code false} if the device
+     * is on AP-assisted mode, where IWLAN should be reported through WLAN.
+     * @param powerOff {@code true} if this is a power off case (i.e. Airplane mode on).
+     * @hide
+     */
+    public void setOutOfService(boolean legacyMode, boolean powerOff) {
+        init(legacyMode);
+        if (powerOff) {
+            mVoiceRegState = STATE_POWER_OFF;
+            mDataRegState = STATE_POWER_OFF;
+        }
+    }
+
     public void setState(int state) {
         setVoiceRegState(state);
         if (DBG) Rlog.e(LOG_TAG, "[ServiceState] setState deprecated use setVoiceRegState()");
@@ -1747,8 +1816,17 @@
     /**
      * Get the CDMA NID (Network Identification Number), a number uniquely identifying a network
      * within a wireless system. (Defined in 3GPP2 C.S0023 3.4.8)
+     *
+     * <p>Require at least {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
+     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}. Otherwise return
+     * {@link #UNKNOWN_ID}.
+     *
      * @return The CDMA NID or {@link #UNKNOWN_ID} if not available.
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.ACCESS_FINE_LOCATION,
+            android.Manifest.permission.ACCESS_COARSE_LOCATION
+    })
     public int getCdmaNetworkId() {
         return this.mNetworkId;
     }
@@ -1756,8 +1834,17 @@
     /**
      * Get the CDMA SID (System Identification Number), a number uniquely identifying a wireless
      * system. (Defined in 3GPP2 C.S0023 3.4.8)
+     *
+     * <p>Require at least {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
+     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}. Otherwise return
+     * {@link #UNKNOWN_ID}.
+     *
      * @return The CDMA SID or {@link #UNKNOWN_ID} if not available.
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.ACCESS_FINE_LOCATION,
+            android.Manifest.permission.ACCESS_COARSE_LOCATION
+    })
     public int getCdmaSystemId() {
         return this.mSystemId;
     }
@@ -2058,6 +2145,8 @@
         state.mOperatorAlphaLong = null;
         state.mOperatorAlphaShort = null;
         state.mOperatorNumeric = null;
+        state.mSystemId = UNKNOWN_ID;
+        state.mNetworkId = UNKNOWN_ID;
 
         return state;
     }
diff --git a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
index 978bf3e..7b1f7a5 100644
--- a/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/TelephonySubscriptionTrackerTest.java
@@ -174,7 +174,7 @@
 
     private IntentFilter getIntentFilter() {
         final ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
-        verify(mContext).registerReceiver(any(), captor.capture(), any(), any());
+        verify(mContext).registerReceiver(any(), captor.capture(), any(), any(), anyInt());
 
         return captor.getValue();
     }
@@ -258,7 +258,8 @@
                         eq(mTelephonySubscriptionTracker),
                         any(IntentFilter.class),
                         any(),
-                        eq(mHandler));
+                        eq(mHandler),
+                        eq(Context.RECEIVER_NOT_EXPORTED));
         final IntentFilter filter = getIntentFilter();
         assertEquals(2, filter.countActions());
         assertTrue(filter.hasAction(ACTION_CARRIER_CONFIG_CHANGED));