Merge "Update TrustedPresentationListener docs and update exceptions" into main
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 0877bce..d13c4d7 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -97,7 +97,6 @@
         "framework-minus-apex.ravenwood",
         "hoststubgen-helper-runtime.ravenwood",
         "hoststubgen-helper-framework-runtime.ravenwood",
-        "core-libart-for-host",
         "all-updatable-modules-system-stubs",
         "junit",
         "truth",
diff --git a/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java b/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java
index 10bfa42..426fcab 100644
--- a/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/TextViewSetTextMeasurePerfTest.java
@@ -20,10 +20,12 @@
 
 import android.graphics.Canvas;
 import android.graphics.RecordingCanvas;
+import android.graphics.RectF;
 import android.graphics.RenderNode;
 import android.perftests.utils.BenchmarkState;
 import android.perftests.utils.PerfStatusReporter;
 import android.text.NonEditableTextGenerator.TextType;
+import android.view.View;
 import android.widget.TextView;
 
 import androidx.test.InstrumentationRegistry;
@@ -79,7 +81,7 @@
         mCached = cached;
         mTextPaint = new TextPaint();
         mTextPaint.setTextSize(10);
-        mLineWidth = Integer.MAX_VALUE;
+        mLineWidth = 2048;
     }
 
     /**
@@ -106,7 +108,9 @@
             state.resumeTiming();
 
             textView.setText(text);
-            textView.measure(AT_MOST | mLineWidth, UNSPECIFIED);
+            textView.measure(
+                    View.MeasureSpec.makeMeasureSpec(mLineWidth, AT_MOST),
+                    UNSPECIFIED);
         }
     }
 
@@ -129,10 +133,16 @@
         while (state.keepRunning()) {
 
             state.pauseTiming();
-            final RecordingCanvas canvas = node.start(1200, 200);
-            int save = canvas.save();
             textView.setTextLocale(Locale.UK);
             textView.setTextLocale(Locale.US);
+            textView.measure(
+                    View.MeasureSpec.makeMeasureSpec(mLineWidth, AT_MOST),
+                    UNSPECIFIED);
+            RectF bounds = textView.getLayout().computeDrawingBoundingBox();
+            final RecordingCanvas canvas = node.start(
+                    (int) Math.ceil(bounds.width()),
+                    (int) Math.ceil(bounds.height()));
+            int save = canvas.save();
             if (!mCached) Canvas.freeTextLayoutCaches();
             state.resumeTiming();
 
diff --git a/core/api/current.txt b/core/api/current.txt
index f41982f..b095501 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -41234,6 +41234,7 @@
     method public void startAssistantActivity(@NonNull android.content.Intent, @NonNull android.os.Bundle);
     method public void startVoiceActivity(android.content.Intent);
     method public final void unregisterVisibleActivityCallback(@NonNull android.service.voice.VoiceInteractionSession.VisibleActivityCallback);
+    field @FlaggedApi("android.service.voice.flags.allow_foreground_activities_in_on_show") public static final String KEY_FOREGROUND_ACTIVITIES = "android.service.voice.FOREGROUND_ACTIVITIES";
     field public static final String KEY_SHOW_SESSION_ID = "android.service.voice.SHOW_SESSION_ID";
     field public static final int SHOW_SOURCE_ACTIVITY = 16; // 0x10
     field public static final int SHOW_SOURCE_APPLICATION = 8; // 0x8
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 1edf4bd..e14bf68 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -75,6 +75,7 @@
  * {@link android.content.Context#startActivity(android.content.Intent, android.os.Bundle)
  * Context.startActivity(Intent, Bundle)} and related methods.
  */
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
 public class ActivityOptions extends ComponentOptions {
     private static final String TAG = "ActivityOptions";
 
@@ -527,6 +528,7 @@
      * @return Returns a new ActivityOptions object that you can use to
      * supply these options as the options Bundle when starting an activity.
      */
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = Context.class)
     public static ActivityOptions makeCustomAnimation(Context context,
             int enterResId, int exitResId) {
         return makeCustomAnimation(context, enterResId, exitResId, 0, null, null);
@@ -547,6 +549,7 @@
      * @return Returns a new ActivityOptions object that you can use to
      * supply these options as the options Bundle when starting an activity.
      */
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = Context.class)
     public static @NonNull ActivityOptions makeCustomAnimation(@NonNull Context context,
             int enterResId, int exitResId, int backgroundColor) {
         return makeCustomAnimation(context, enterResId, exitResId, backgroundColor, null, null);
@@ -572,6 +575,7 @@
      * @hide
      */
     @UnsupportedAppUsage
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = Context.class)
     public static ActivityOptions makeCustomAnimation(Context context,
             int enterResId, int exitResId, int backgroundColor, Handler handler,
             OnAnimationStartedListener listener) {
@@ -607,6 +611,7 @@
      * @hide
      */
     @TestApi
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = Context.class)
     public static @NonNull ActivityOptions makeCustomAnimation(@NonNull Context context,
             int enterResId, int exitResId, int backgroundColor, @Nullable Handler handler,
             @Nullable OnAnimationStartedListener startedListener,
@@ -641,6 +646,7 @@
      */
     @RequiresPermission(START_TASKS_FROM_RECENTS)
     @TestApi
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = Context.class)
     public static @NonNull ActivityOptions makeCustomTaskAnimation(@NonNull Context context,
             int enterResId, int exitResId, @Nullable Handler handler,
             @Nullable OnAnimationStartedListener startedListener,
@@ -663,6 +669,7 @@
      * supply these options as the options Bundle when running an in-place animation.
      * @hide
      */
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = Context.class)
     public static ActivityOptions makeCustomInPlaceAnimation(Context context, int animId) {
         if (animId == 0) {
             throw new RuntimeException("You must specify a valid animation.");
@@ -769,6 +776,7 @@
      * @return Returns a new ActivityOptions object that you can use to
      * supply these options as the options Bundle when starting an activity.
      */
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = View.class)
     public static ActivityOptions makeScaleUpAnimation(View source,
             int startX, int startY, int width, int height) {
         ActivityOptions opts = new ActivityOptions();
@@ -797,6 +805,7 @@
      * @return Returns a new ActivityOptions object that you can use to
      * supply these options as the options Bundle when starting an activity.
      */
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = View.class)
     public static ActivityOptions makeClipRevealAnimation(View source,
             int startX, int startY, int width, int height) {
         ActivityOptions opts = new ActivityOptions();
@@ -842,6 +851,7 @@
      * @return Returns a new ActivityOptions object that you can use to
      * supply these options as the options Bundle when starting an activity.
      */
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = View.class)
     public static ActivityOptions makeThumbnailScaleUpAnimation(View source,
             Bitmap thumbnail, int startX, int startY) {
         return makeThumbnailScaleUpAnimation(source, thumbnail, startX, startY, null);
@@ -864,11 +874,13 @@
      * @return Returns a new ActivityOptions object that you can use to
      * supply these options as the options Bundle when starting an activity.
      */
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = View.class)
     private static ActivityOptions makeThumbnailScaleUpAnimation(View source,
             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener) {
         return makeThumbnailAnimation(source, thumbnail, startX, startY, listener, true);
     }
 
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = View.class)
     private static ActivityOptions makeThumbnailAnimation(View source,
             Bitmap thumbnail, int startX, int startY, OnAnimationStartedListener listener,
             boolean scaleUp) {
@@ -890,6 +902,7 @@
      * @hide
      */
     @UnsupportedAppUsage
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = Context.class)
     public static ActivityOptions makeMultiThumbFutureAspectScaleAnimation(Context context,
             Handler handler, IAppTransitionAnimationSpecsFuture specsFuture,
             OnAnimationStartedListener listener, boolean scaleUp) {
@@ -922,6 +935,7 @@
      * supply these options as the options Bundle when starting an activity.
      * @hide
      */
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = View.class)
     public static ActivityOptions makeThumbnailAspectScaleDownAnimation(View source,
             Bitmap thumbnail, int startX, int startY, int targetWidth, int targetHeight,
             Handler handler, OnAnimationStartedListener listener) {
@@ -929,6 +943,7 @@
                 targetWidth, targetHeight, handler, listener, false);
     }
 
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = View.class)
     private static ActivityOptions makeAspectScaledThumbnailAnimation(View source, Bitmap thumbnail,
             int startX, int startY, int targetWidth, int targetHeight,
             Handler handler, OnAnimationStartedListener listener, boolean scaleUp) {
@@ -948,6 +963,7 @@
     }
 
     /** @hide */
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = View.class)
     public static ActivityOptions makeThumbnailAspectScaleDownAnimation(View source,
             AppTransitionAnimationSpec[] specs, Handler handler,
             OnAnimationStartedListener onAnimationStartedListener,
@@ -980,6 +996,7 @@
      * @see android.transition.Transition#setEpicenterCallback(
      *          android.transition.Transition.EpicenterCallback)
      */
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = Activity.class)
     public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
             View sharedElement, String sharedElementName) {
         return makeSceneTransitionAnimation(activity, Pair.create(sharedElement, sharedElementName));
@@ -1005,6 +1022,7 @@
      *          android.transition.Transition.EpicenterCallback)
      */
     @SafeVarargs
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = Activity.class)
     public static ActivityOptions makeSceneTransitionAnimation(Activity activity,
             Pair<View, String>... sharedElements) {
         ActivityOptions opts = new ActivityOptions();
@@ -1031,6 +1049,7 @@
      * @hide
      */
     @SafeVarargs
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = Window.class)
     public static Pair<ActivityOptions, ExitTransitionCoordinator> startSharedElementAnimation(
             Window window, ExitTransitionCallbacks exitCallbacks, SharedElementCallback callback,
             Pair<View, String>... sharedElements) {
@@ -1052,6 +1071,7 @@
      *
      * @hide
      */
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = Window.class)
     public static void stopSharedElementAnimation(Window window) {
         final View decorView = window.getDecorView();
         if (decorView == null) {
@@ -1069,6 +1089,7 @@
         }
     }
 
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = Window.class)
     static ExitTransitionCoordinator makeSceneTransitionAnimation(
             ExitTransitionCallbacks exitCallbacks, SharedElementCallback callback, Window window,
             ActivityOptions opts, Pair<View, String>[] sharedElements) {
@@ -1119,6 +1140,7 @@
     }
 
     /** @hide */
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = Activity.class)
     static ActivityOptions makeSceneTransitionAnimation(Activity activity,
             ExitTransitionCoordinator exitCoordinator, ArrayList<String> sharedElementNames,
             int resultCode, Intent resultData) {
@@ -1173,6 +1195,7 @@
      */
     @RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
     @UnsupportedAppUsage
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = RemoteAnimationAdapter.class)
     public static ActivityOptions makeRemoteAnimation(
             RemoteAnimationAdapter remoteAnimationAdapter) {
         final ActivityOptions opts = new ActivityOptions();
@@ -1187,6 +1210,7 @@
      * @hide
      */
     @RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = RemoteAnimationAdapter.class)
     public static ActivityOptions makeRemoteAnimation(RemoteAnimationAdapter remoteAnimationAdapter,
             RemoteTransition remoteTransition) {
         final ActivityOptions opts = new ActivityOptions();
@@ -1202,6 +1226,7 @@
      * @hide
      */
     @RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = RemoteAnimationAdapter.class)
     public static ActivityOptions makeRemoteTransition(RemoteTransition remoteTransition) {
         final ActivityOptions opts = new ActivityOptions();
         opts.mRemoteTransition = remoteTransition;
@@ -1216,6 +1241,7 @@
      *                               picture-in-picture mode.
      */
     @NonNull
+    @android.ravenwood.annotation.RavenwoodThrow(blockedBy = PictureInPictureParams.class)
     public static ActivityOptions makeLaunchIntoPip(
             @NonNull PictureInPictureParams pictureInPictureParams) {
         final ActivityOptions opts = new ActivityOptions();
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 41b4004..f727ee5 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -46,6 +46,7 @@
  * {@link android.content.Context#sendBroadcast(android.content.Intent)
  * Context.sendBroadcast(Intent)} and related methods.
  */
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
 public class BroadcastOptions extends ComponentOptions {
     private @Flags int mFlags;
     private long mTemporaryAppAllowlistDuration;
@@ -751,6 +752,7 @@
      * @hide
      */
     @TestApi
+    @android.ravenwood.annotation.RavenwoodThrow
     public boolean testRequireCompatChange(int uid) {
         if (mRequireCompatChangeId != CHANGE_INVALID) {
             final boolean requireEnabled = (mFlags & FLAG_REQUIRE_COMPAT_CHANGE_ENABLED) != 0;
diff --git a/core/java/android/app/ComponentOptions.java b/core/java/android/app/ComponentOptions.java
index e0e2855..ce16ddf 100644
--- a/core/java/android/app/ComponentOptions.java
+++ b/core/java/android/app/ComponentOptions.java
@@ -34,6 +34,7 @@
 @TestApi
 // Suppressed since lint is recommending class have a suffix of Params.
 @SuppressLint("UserHandleName")
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
 public class ComponentOptions {
 
     /**
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 4dc32d5..61b52c6 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -800,7 +800,6 @@
      *
      * @hide
      */
-    @android.ravenwood.annotation.RavenwoodReplace
     public static void bytesToFile(String filename, byte[] content) throws IOException {
         if (filename.startsWith("/proc/")) {
             final int oldMask = StrictMode.allowThreadDiskWritesMask();
@@ -816,14 +815,6 @@
         }
     }
 
-    /** @hide */
-    public static void bytesToFile$ravenwood(String filename, byte[] content) throws IOException {
-        // No StrictMode support, so we can just directly write
-        try (FileOutputStream fos = new FileOutputStream(filename)) {
-            fos.write(content);
-        }
-    }
-
     /**
      * Writes string to file. Basically same as "echo -n $string > $filename"
      *
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 93d5082..6532d5c 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -40,14 +40,18 @@
 import android.content.ContentResolver;
 import android.net.Uri;
 import android.os.MessageQueue.OnFileDescriptorEventListener;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
+import android.ravenwood.annotation.RavenwoodNativeSubstitutionClass;
+import android.ravenwood.annotation.RavenwoodReplace;
+import android.ravenwood.annotation.RavenwoodThrow;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
 import android.system.StructStat;
+import android.util.CloseGuard;
 import android.util.Log;
 import android.util.Slog;
 
-import dalvik.system.CloseGuard;
 import dalvik.system.VMRuntime;
 
 import libcore.io.IoUtils;
@@ -70,6 +74,8 @@
  * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing
  * you to close it when done with it.
  */
+@RavenwoodKeepWholeClass
+@RavenwoodNativeSubstitutionClass("com.android.hoststubgen.nativesubstitution.ParcelFileDescriptor_host")
 public class ParcelFileDescriptor implements Parcelable, Closeable {
     private static final String TAG = "ParcelFileDescriptor";
 
@@ -197,11 +203,11 @@
         }
         mWrapped = null;
         mFd = fd;
-        IoUtils.setFdOwner(mFd, this);
+        setFdOwner(mFd);
 
         mCommFd = commChannel;
         if (mCommFd != null) {
-            IoUtils.setFdOwner(mCommFd, this);
+            setFdOwner(mCommFd);
         }
 
         mGuard.open("close");
@@ -284,15 +290,17 @@
      */
     // We can't accept a generic Executor here, since we need to use
     // MessageQueue.addOnFileDescriptorEventListener()
+    @RavenwoodThrow(blockedBy = MessageQueue.class)
     @SuppressLint("ExecutorRegistration")
     public static @NonNull ParcelFileDescriptor wrap(@NonNull ParcelFileDescriptor pfd,
             @NonNull Handler handler, @NonNull OnCloseListener listener) throws IOException {
         final FileDescriptor original = new FileDescriptor();
-        original.setInt$(pfd.detachFd());
+        setFdInt(original, pfd.detachFd());
         return fromFd(original, handler, listener);
     }
 
     /** {@hide} */
+    @RavenwoodThrow(blockedBy = MessageQueue.class)
     public static ParcelFileDescriptor fromFd(FileDescriptor fd, Handler handler,
             final OnCloseListener listener) throws IOException {
         if (handler == null) {
@@ -318,7 +326,7 @@
                 }
                 if (status != null) {
                     queue.removeOnFileDescriptorEventListener(fd);
-                    IoUtils.closeQuietly(fd);
+                    closeInternal(fd);
                     listener.onClose(status.asIOException());
                     return 0;
                 }
@@ -329,6 +337,7 @@
         return pfd;
     }
 
+    @RavenwoodReplace
     private static FileDescriptor openInternal(File file, int mode) throws FileNotFoundException {
         if ((mode & MODE_WRITE_ONLY) != 0 && (mode & MODE_APPEND) == 0
                 && (mode & MODE_TRUNCATE) == 0 && ((mode & MODE_READ_ONLY) == 0)
@@ -352,17 +361,38 @@
         }
     }
 
+    private static FileDescriptor openInternal$ravenwood(File file, int mode)
+            throws FileNotFoundException {
+        try {
+            return native_open$ravenwood(file, mode);
+        } catch (FileNotFoundException e) {
+            throw e;
+        } catch (IOException e) {
+            throw new FileNotFoundException(e.getMessage());
+        }
+    }
+
+    @RavenwoodReplace
+    private static void closeInternal(FileDescriptor fd) {
+        IoUtils.closeQuietly(fd);
+    }
+
+    private static void closeInternal$ravenwood(FileDescriptor fd) {
+        native_close$ravenwood(fd);
+    }
+
     /**
      * Create a new ParcelFileDescriptor that is a dup of an existing
      * FileDescriptor.  This obeys standard POSIX semantics, where the
      * new file descriptor shared state such as file position with the
      * original file descriptor.
      */
+    @RavenwoodThrow(reason = "Requires JNI support")
     public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
         try {
             final FileDescriptor fd = new FileDescriptor();
             int intfd = Os.fcntlInt(orig, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0);
-            fd.setInt$(intfd);
+            setFdInt(fd, intfd);
             return new ParcelFileDescriptor(fd);
         } catch (ErrnoException e) {
             throw e.rethrowAsIOException();
@@ -375,6 +405,7 @@
      * new file descriptor shared state such as file position with the
      * original file descriptor.
      */
+    @RavenwoodThrow(reason = "Requires JNI support")
     public ParcelFileDescriptor dup() throws IOException {
         if (mWrapped != null) {
             return mWrapped.dup();
@@ -393,14 +424,15 @@
      * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
      * for a dup of the given fd.
      */
+    @RavenwoodThrow(reason = "Requires JNI support")
     public static ParcelFileDescriptor fromFd(int fd) throws IOException {
         final FileDescriptor original = new FileDescriptor();
-        original.setInt$(fd);
+        setFdInt(original, fd);
 
         try {
             final FileDescriptor dup = new FileDescriptor();
             int intfd = Os.fcntlInt(original, (isAtLeastQ() ? F_DUPFD_CLOEXEC : F_DUPFD), 0);
-            dup.setInt$(intfd);
+            setFdInt(dup, intfd);
             return new ParcelFileDescriptor(dup);
         } catch (ErrnoException e) {
             throw e.rethrowAsIOException();
@@ -423,7 +455,7 @@
      */
     public static ParcelFileDescriptor adoptFd(int fd) {
         final FileDescriptor fdesc = new FileDescriptor();
-        fdesc.setInt$(fd);
+        setFdInt(fdesc, fd);
 
         return new ParcelFileDescriptor(fdesc);
     }
@@ -452,6 +484,7 @@
      *
      * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
      */
+    @RavenwoodThrow(reason = "Requires JNI support")
     public static ParcelFileDescriptor fromSocket(Socket socket) {
         FileDescriptor fd = socket.getFileDescriptor$();
         try {
@@ -485,6 +518,7 @@
      *
      * @throws UncheckedIOException if {@link #dup(FileDescriptor)} throws IOException.
      */
+    @RavenwoodThrow(reason = "Requires JNI support")
     public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) {
         FileDescriptor fd = datagramSocket.getFileDescriptor$();
         try {
@@ -499,6 +533,7 @@
      * ParcelFileDescriptor in the returned array is the read side; the second
      * is the write side.
      */
+    @RavenwoodThrow(reason = "Requires JNI support")
     public static ParcelFileDescriptor[] createPipe() throws IOException {
         try {
             final FileDescriptor[] fds = Os.pipe2(ifAtLeastQ(O_CLOEXEC));
@@ -520,6 +555,7 @@
      * calling {@link #checkError()}, usually after detecting an EOF.
      * This can also be used to detect remote crashes.
      */
+    @RavenwoodThrow(reason = "Requires JNI support")
     public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
         try {
             final FileDescriptor[] comm = createCommSocketPair();
@@ -536,6 +572,7 @@
      * Create two ParcelFileDescriptors structured as a pair of sockets
      * connected to each other. The two sockets are indistinguishable.
      */
+    @RavenwoodThrow(reason = "Requires JNI support")
     public static ParcelFileDescriptor[] createSocketPair() throws IOException {
         return createSocketPair(SOCK_STREAM);
     }
@@ -543,6 +580,7 @@
     /**
      * @hide
      */
+    @RavenwoodThrow(reason = "Requires JNI support")
     public static ParcelFileDescriptor[] createSocketPair(int type) throws IOException {
         try {
             final FileDescriptor fd0 = new FileDescriptor();
@@ -565,6 +603,7 @@
      * calling {@link #checkError()}, usually after detecting an EOF.
      * This can also be used to detect remote crashes.
      */
+    @RavenwoodThrow(reason = "Requires JNI support")
     public static ParcelFileDescriptor[] createReliableSocketPair() throws IOException {
         return createReliableSocketPair(SOCK_STREAM);
     }
@@ -572,6 +611,7 @@
     /**
      * @hide
      */
+    @RavenwoodThrow(reason = "Requires JNI support")
     public static ParcelFileDescriptor[] createReliableSocketPair(int type) throws IOException {
         try {
             final FileDescriptor[] comm = createCommSocketPair();
@@ -586,6 +626,7 @@
         }
     }
 
+    @RavenwoodThrow(reason = "Requires JNI support")
     private static FileDescriptor[] createCommSocketPair() throws IOException {
         try {
             // Use SOCK_SEQPACKET so that we have a guarantee that the status
@@ -614,6 +655,7 @@
      */
     @UnsupportedAppUsage
     @Deprecated
+    @RavenwoodThrow(reason = "Requires JNI support")
     public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException {
         if (data == null) return null;
         MemoryFile file = new MemoryFile(name, data.length);
@@ -669,9 +711,10 @@
      * @hide
      */
     @TestApi
+    @RavenwoodThrow(reason = "Requires kernel support")
     public static File getFile(FileDescriptor fd) throws IOException {
         try {
-            final String path = Os.readlink("/proc/self/fd/" + fd.getInt$());
+            final String path = Os.readlink("/proc/self/fd/" + getFdInt(fd));
             if (OsConstants.S_ISREG(Os.stat(path).st_mode)
                     || OsConstants.S_ISCHR(Os.stat(path).st_mode)) {
                 return new File(path);
@@ -700,6 +743,7 @@
      * Return the total size of the file representing this fd, as determined by
      * {@code stat()}. Returns -1 if the fd is not a file.
      */
+    @RavenwoodThrow(reason = "Requires JNI support")
     public long getStatSize() {
         if (mWrapped != null) {
             return mWrapped.getStatSize();
@@ -724,6 +768,7 @@
      * @hide
      */
     @UnsupportedAppUsage
+    @RavenwoodThrow(reason = "Requires JNI support")
     public long seekTo(long pos) throws IOException {
         if (mWrapped != null) {
             return mWrapped.seekTo(pos);
@@ -751,7 +796,7 @@
             if (mClosed) {
                 throw new IllegalStateException("Already closed");
             }
-            return mFd.getInt$();
+            return getFdInt(mFd);
         }
     }
 
@@ -773,7 +818,7 @@
             if (mClosed) {
                 throw new IllegalStateException("Already closed");
             }
-            int fd = IoUtils.acquireRawFd(mFd);
+            int fd = acquireRawFd(mFd);
             writeCommStatusAndClose(Status.DETACHED, null);
             mClosed = true;
             mGuard.close();
@@ -832,7 +877,7 @@
         }
         // Status MUST be sent before closing actual descriptor
         writeCommStatusAndClose(status, msg);
-        IoUtils.closeQuietly(mFd);
+        closeInternal(mFd);
         releaseResources();
     }
 
@@ -899,7 +944,7 @@
             }
 
         } finally {
-            IoUtils.closeQuietly(mCommFd);
+            closeInternal(mCommFd);
             mCommFd = null;
         }
     }
@@ -991,6 +1036,7 @@
      * take care of calling {@link ParcelFileDescriptor#close
      * ParcelFileDescriptor.close()} for you when the stream is closed.
      */
+    @RavenwoodKeepWholeClass
     public static class AutoCloseInputStream extends FileInputStream {
         private final ParcelFileDescriptor mPfd;
 
@@ -1042,6 +1088,7 @@
      * take care of calling {@link ParcelFileDescriptor#close
      * ParcelFileDescriptor.close()} for you when the stream is closed.
      */
+    @RavenwoodKeepWholeClass
     public static class AutoCloseOutputStream extends FileOutputStream {
         private final ParcelFileDescriptor mPfd;
 
@@ -1232,10 +1279,58 @@
         }
     }
 
+    // These native methods are currently only implemented by Ravenwood, as it's the only
+    // mechanism we have to jump to our RavenwoodNativeSubstitutionClass
+    private static native void native_setFdInt$ravenwood(FileDescriptor fd, int fdInt);
+    private static native int native_getFdInt$ravenwood(FileDescriptor fd);
+    private static native FileDescriptor native_open$ravenwood(File file, int pfdMode)
+            throws IOException;
+    private static native void native_close$ravenwood(FileDescriptor fd);
+
+    @RavenwoodReplace
+    private static void setFdInt(FileDescriptor fd, int fdInt) {
+        fd.setInt$(fdInt);
+    }
+
+    private static void setFdInt$ravenwood(FileDescriptor fd, int fdInt) {
+        native_setFdInt$ravenwood(fd, fdInt);
+    }
+
+    @RavenwoodReplace
+    private static int getFdInt(FileDescriptor fd) {
+        return fd.getInt$();
+    }
+
+    private static int getFdInt$ravenwood(FileDescriptor fd) {
+        return native_getFdInt$ravenwood(fd);
+    }
+
+    @RavenwoodReplace
+    private void setFdOwner(FileDescriptor fd) {
+        IoUtils.setFdOwner(fd, this);
+    }
+
+    private void setFdOwner$ravenwood(FileDescriptor fd) {
+        // FD owners currently unsupported under Ravenwood; ignored
+    }
+
+    @RavenwoodReplace
+    private int acquireRawFd(FileDescriptor fd) {
+        return IoUtils.acquireRawFd(fd);
+    }
+
+    private int acquireRawFd$ravenwood(FileDescriptor fd) {
+        // FD owners currently unsupported under Ravenwood; return FD directly
+        return getFdInt(fd);
+
+    }
+
+    @RavenwoodThrow
     private static boolean isAtLeastQ() {
         return (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q);
     }
 
+    @RavenwoodThrow
     private static int ifAtLeastQ(int value) {
         return isAtLeastQ() ? value : 0;
     }
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 8c8af0e..222c69c 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -77,6 +77,7 @@
 import com.android.internal.os.RuntimeInit;
 import com.android.internal.util.FastPrintWriter;
 import com.android.internal.util.HexDump;
+import com.android.internal.util.Preconditions;
 
 import dalvik.system.BlockGuard;
 import dalvik.system.CloseGuard;
@@ -154,6 +155,7 @@
  * android.os.Binder} calls, it's still ultimately a best effort mechanism. Notably, disk or network
  * access from JNI calls won't necessarily trigger it.
  */
+@android.ravenwood.annotation.RavenwoodKeepPartialClass
 public final class StrictMode {
     private static final String TAG = "StrictMode";
     private static final boolean LOG_V = Log.isLoggable(TAG, Log.VERBOSE);
@@ -1267,6 +1269,7 @@
     }
 
     /** @hide */
+    @android.ravenwood.annotation.RavenwoodReplace
     public static void setThreadPolicyMask(@ThreadPolicyMask int threadPolicyMask) {
         // In addition to the Java-level thread-local in Dalvik's
         // BlockGuard, we also need to keep a native thread-local in
@@ -1279,6 +1282,12 @@
         Binder.setThreadStrictModePolicy(threadPolicyMask);
     }
 
+    /** @hide */
+    public static void setThreadPolicyMask$ravenwood(@ThreadPolicyMask int threadPolicyMask) {
+        // Ravenwood currently doesn't support any detection modes
+        Preconditions.checkFlagsArgument(threadPolicyMask, 0);
+    }
+
     // Sets the policy in Dalvik/libcore (BlockGuard)
     private static void setBlockGuardPolicy(@ThreadPolicyMask int threadPolicyMask) {
         if (threadPolicyMask == 0) {
@@ -1321,6 +1330,7 @@
      * @hide
      */
     @UnsupportedAppUsage
+    @android.ravenwood.annotation.RavenwoodReplace
     public static @ThreadPolicyMask int getThreadPolicyMask() {
         final BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
         if (policy instanceof AndroidBlockGuardPolicy) {
@@ -1330,6 +1340,12 @@
         }
     }
 
+    /** @hide */
+    public static @ThreadPolicyMask int getThreadPolicyMask$ravenwood() {
+        // Ravenwood currently doesn't support any detection modes
+        return 0;
+    }
+
     /** Returns the current thread's policy. */
     public static ThreadPolicy getThreadPolicy() {
         // TODO: this was a last minute Gingerbread API change (to
@@ -1359,6 +1375,7 @@
     }
 
     /** @hide */
+    @android.ravenwood.annotation.RavenwoodKeep
     public static @ThreadPolicyMask int allowThreadDiskWritesMask() {
         int oldPolicyMask = getThreadPolicyMask();
         int newPolicyMask = oldPolicyMask & ~(DETECT_THREAD_DISK_WRITE | DETECT_THREAD_DISK_READ);
@@ -1383,6 +1400,7 @@
     }
 
     /** @hide */
+    @android.ravenwood.annotation.RavenwoodKeep
     public static @ThreadPolicyMask int allowThreadDiskReadsMask() {
         int oldPolicyMask = getThreadPolicyMask();
         int newPolicyMask = oldPolicyMask & ~(DETECT_THREAD_DISK_READ);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ce7a026..be9915c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11909,6 +11909,16 @@
                 "accessibility_magnification_two_finger_triple_tap_enabled";
 
         /**
+         * For pinch to zoom anywhere feature.
+         *
+         * If true, you should be able to pinch to magnify the window anywhere.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED =
+                "accessibility_pinch_to_zoom_anywhere_enabled";
+
+        /**
          * Controls magnification capability. Accessibility magnification is capable of at least one
          * of the magnification modes.
          *
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index d40b39e..d1368ca 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -20,6 +20,7 @@
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 
 import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -53,6 +54,7 @@
 import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.service.voice.flags.Flags;
 import android.util.ArrayMap;
 import android.util.DebugUtils;
 import android.util.Log;
@@ -184,6 +186,17 @@
      */
     public static final String KEY_SHOW_SESSION_ID = "android.service.voice.SHOW_SESSION_ID";
 
+    /**
+     * Bundle key used to specify foreground activity app components.
+     * <p>
+     * Type: ArrayList&ltComponentName&gt
+     * </p>
+     * @see #onShow(Bundle, int)
+     */
+    @FlaggedApi(Flags.FLAG_ALLOW_FOREGROUND_ACTIVITIES_IN_ON_SHOW)
+    public static final String KEY_FOREGROUND_ACTIVITIES =
+            "android.service.voice.FOREGROUND_ACTIVITIES";
+
     final Context mContext;
     final HandlerCaller mHandlerCaller;
 
@@ -1803,14 +1816,39 @@
      *
      * @param args The arguments that were supplied to
      * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
-     * Some example keys include : "invocation_type", "invocation_phone_state",
-     * {@link #KEY_SHOW_SESSION_ID}, "invocation_time_ms",
-     * Intent.EXTRA_TIME ("android.intent.extra.TIME") indicating timing
-     * in milliseconds of the KeyEvent that triggered Assistant and
-     * Intent.EXTRA_ASSIST_INPUT_DEVICE_ID (android.intent.extra.ASSIST_INPUT_DEVICE_ID)
-     *  referring to the device that sent the request. Starting from Android 14, the system will
-     * add {@link #KEY_SHOW_SESSION_ID}, the Bundle is not null. But the
-     * application should handle null case before Android 14.
+     * Some example keys include :
+     * <ul>
+     *     <li>
+     *         invocation_type
+     *     </li>
+     *     <li>
+     *         invocation_phone_state
+     *     </li>
+     *     <li>
+     *         {@link #KEY_SHOW_SESSION_ID}
+     *     </li>
+     *     <li>
+     *         invocation_time_ms
+     *     </li>
+     *     <li>
+     *         Intent.EXTRA_TIME ("android.intent.extra.TIME") indicating timing in milliseconds of
+     *         the KeyEvent that triggered Assistant
+     *     </li>
+     *     <li>
+     *         Intent.EXTRA_ASSIST_INPUT_DEVICE_ID (android.intent.extra.ASSIST_INPUT_DEVICE_ID)
+     *         referring to the device that sent the request
+     *     </li>
+     *     <li>
+     *         {@link #KEY_FOREGROUND_ACTIVITIES} provides foreground activities of up coming
+     *         onHandleAssist/onHandleScreenshot calls earlier. This is only populated if session
+     *         was requested with {@link VoiceInteractionSession.SHOW_WITH_ASSIST} show flag.
+     *     </li>
+     *     <li>
+     *         Starting from Android 14, the system will add {@link #KEY_SHOW_SESSION_ID}, the
+     *         Bundle is not null. But the application should handle null case before Android 14.
+     *     </li>
+     * </ul>
+     *
      * @param showFlags The show flags originally provided to
      * {@link VoiceInteractionService#showSession VoiceInteractionService.showSession}.
      */
diff --git a/core/java/android/service/voice/flags/flags.aconfig b/core/java/android/service/voice/flags/flags.aconfig
index b596666..1c8752b 100644
--- a/core/java/android/service/voice/flags/flags.aconfig
+++ b/core/java/android/service/voice/flags/flags.aconfig
@@ -13,3 +13,10 @@
     description: "This flag allows hotword detection service to egress reason code for hotword bump."
     bug: "290951024"
 }
+
+flag {
+    name: "allow_foreground_activities_in_on_show"
+    namespace: "voice_interaction_session"
+    description: "This flag allows providing foreground app component along with onShow args."
+    bug: "319409708"
+}
diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java
index 09f15c3..95d1974 100644
--- a/core/java/android/text/MeasuredParagraph.java
+++ b/core/java/android/text/MeasuredParagraph.java
@@ -116,9 +116,6 @@
     // This is empty if mLtrWithoutBidi is true.
     private @NonNull ByteArray mLevels = new ByteArray();
 
-    // The bidi level for runs.
-    private @NonNull ByteArray mRunLevels = new ByteArray();
-
     private Bidi mBidi;
 
     // The whole width of the text.
@@ -154,7 +151,6 @@
         reset();
         mLevels.clearWithReleasingLargeArray();
         mWidths.clearWithReleasingLargeArray();
-        mRunLevels.clearWithReleasingLargeArray();
         mFontMetrics.clearWithReleasingLargeArray();
         mSpanEndCache.clearWithReleasingLargeArray();
     }
@@ -167,7 +163,6 @@
         mCopiedBuffer = null;
         mWholeWidth = 0;
         mLevels.clear();
-        mRunLevels.clear();
         mWidths.clear();
         mFontMetrics.clear();
         mSpanEndCache.clear();
@@ -250,8 +245,7 @@
             }
 
             // Reorder directionality run visually.
-            mRunLevels.resize(bidi.getRunCount());
-            byte[] levels = mRunLevels.getRawArray();
+            byte[] levels = new byte[bidi.getRunCount()];
             for (int i = 0; i < bidi.getRunCount(); ++i) {
                 levels[i] = (byte) bidi.getRunLevel(i);
             }
diff --git a/core/java/android/util/CloseGuard.java b/core/java/android/util/CloseGuard.java
index ba504a3..efe4132 100644
--- a/core/java/android/util/CloseGuard.java
+++ b/core/java/android/util/CloseGuard.java
@@ -17,6 +17,8 @@
 package android.util;
 
 import android.annotation.NonNull;
+import android.ravenwood.annotation.RavenwoodKeepWholeClass;
+import android.ravenwood.annotation.RavenwoodReplace;
 
 /**
  * CloseGuard is a mechanism for flagging implicit finalizer cleanup of
@@ -108,15 +110,35 @@
  * in a method, the call to {@code open} should occur just after
  * resource acquisition.
  */
+@RavenwoodKeepWholeClass
 public final class CloseGuard {
     private final dalvik.system.CloseGuard mImpl;
 
     /**
      * Constructs a new CloseGuard instance.
      * {@link #open(String)} can be used to set up the instance to warn on failure to close.
+     *
+     * @hide
+     */
+    public static CloseGuard get() {
+        return new CloseGuard();
+    }
+
+    /**
+     * Constructs a new CloseGuard instance.
+     * {@link #open(String)} can be used to set up the instance to warn on failure to close.
      */
     public CloseGuard() {
-        mImpl = dalvik.system.CloseGuard.get();
+        mImpl = getImpl();
+    }
+
+    @RavenwoodReplace
+    private dalvik.system.CloseGuard getImpl() {
+        return dalvik.system.CloseGuard.get();
+    }
+
+    private dalvik.system.CloseGuard getImpl$ravenwood() {
+        return null;
     }
 
     /**
@@ -127,12 +149,16 @@
      * @throws NullPointerException if closeMethodName is null.
      */
     public void open(@NonNull String closeMethodName) {
-        mImpl.open(closeMethodName);
+        if (mImpl != null) {
+            mImpl.open(closeMethodName);
+        }
     }
 
     /** Marks this CloseGuard instance as closed to avoid warnings on finalization. */
     public void close() {
-        mImpl.close();
+        if (mImpl != null) {
+            mImpl.close();
+        }
     }
 
     /**
@@ -140,6 +166,8 @@
      * before finalization.
      */
     public void warnIfOpen() {
-        mImpl.warnIfOpen();
+        if (mImpl != null) {
+            mImpl.warnIfOpen();
+        }
     }
 }
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 4a3b8ac..de809c8 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -168,7 +168,8 @@
             statsToken = ImeTracker.forLogging().onRequestHide(null /* component */,
                     Process.myUid(),
                     ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
-                    SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API);
+                    SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API,
+                    mController.getHost().isHandlingPointerEvent() /* fromUser */);
         }
 
         ImeTracker.forLogging().onProgress(statsToken,
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index dd09157..6b7f9db 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -224,6 +224,11 @@
          * @param running {@code true} if there is any animation running; {@code false} otherwise.
          */
         default void notifyAnimationRunningStateChanged(boolean running) {}
+
+        /** @see ViewRootImpl#isHandlingPointerEvent */
+        default boolean isHandlingPointerEvent() {
+            return false;
+        }
     }
 
     private static final String TAG = "InsetsController";
@@ -1063,7 +1068,8 @@
         if ((types & ime()) != 0) {
             statsToken = ImeTracker.forLogging().onRequestShow(null /* component */,
                     Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
-                    SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API);
+                    SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API,
+                    mHost.isHandlingPointerEvent() /* fromUser */);
         }
 
         show(types, false /* fromIme */, statsToken);
@@ -1168,7 +1174,8 @@
         if ((types & ime()) != 0) {
             statsToken = ImeTracker.forLogging().onRequestHide(null /* component */,
                     Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
-                    SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API);
+                    SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API,
+                    mHost.isHandlingPointerEvent() /* fromUser */);
         }
 
         hide(types, false /* fromIme */, statsToken);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e03f857..32e6069 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -7587,6 +7587,15 @@
         }
     }
 
+    /**
+     * Returns whether this view is currently handling a pointer event.
+     *
+     * @hide
+     */
+    public boolean isHandlingPointerEvent() {
+        return mAttachInfo.mHandlingPointerEvent;
+    }
+
     private void resetPointerIcon(MotionEvent event) {
         mPointerIconType = null;
         mResolvedPointerIcon = null;
diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java
index 40730e8..f2a3b4c 100644
--- a/core/java/android/view/ViewRootInsetsControllerHost.java
+++ b/core/java/android/view/ViewRootInsetsControllerHost.java
@@ -286,6 +286,11 @@
         }
     }
 
+    @Override
+    public boolean isHandlingPointerEvent() {
+        return mViewRoot != null && mViewRoot.isHandlingPointerEvent();
+    }
+
     private boolean isVisibleToUser() {
         return mViewRoot.getHostVisibility() == View.VISIBLE;
     }
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index 3e7a9cb..0b3581e 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -25,3 +25,20 @@
     bug: "305193969"
     is_fixed_read_only: true
 }
+
+flag {
+  name: "sensitive_content_app_protection_api"
+  namespace: "permissions"
+  description: "This flag controls the new sensitive content protection API,"
+    " The API will be used by other ui toolkits (i.e. compose, webview, custom virtual views)."
+  bug: "322887144"
+}
+
+flag {
+  name: "sensitive_content_app_protection"
+  namespace: "permissions"
+  description: "This flag controls the sensitive content protection when sharing the screen"
+  bug: "322887144"
+  # Referenced in WM where WM starts before DeviceConfig
+  is_fixed_read_only: true
+}
\ No newline at end of file
diff --git a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
index c244287..89da041 100644
--- a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
+++ b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
@@ -575,14 +575,14 @@
     @AnyThread
     @NonNull
     static ImeTracker.Token onRequestShow(@NonNull String tag, int uid,
-            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) {
+            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) {
         final IImeTracker service = getImeTrackerService();
         if (service == null) {
             // Create token with "fake" binder if the service was not found.
             return new ImeTracker.Token(new Binder(), tag);
         }
         try {
-            return service.onRequestShow(tag, uid, origin, reason);
+            return service.onRequestShow(tag, uid, origin, reason, fromUser);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -592,14 +592,14 @@
     @AnyThread
     @NonNull
     static ImeTracker.Token onRequestHide(@NonNull String tag, int uid,
-            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) {
+            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) {
         final IImeTracker service = getImeTrackerService();
         if (service == null) {
             // Create token with "fake" binder if the service was not found.
             return new ImeTracker.Token(new Binder(), tag);
         }
         try {
-            return service.onRequestHide(tag, uid, origin, reason);
+            return service.onRequestHide(tag, uid, origin, reason, fromUser);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index 1b7d57b..31c0363 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -37,6 +37,7 @@
 import android.util.Log;
 import android.view.InsetsController.AnimationType;
 import android.view.SurfaceControl;
+import android.view.View;
 
 import com.android.internal.inputmethod.InputMethodDebug;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
@@ -325,12 +326,22 @@
      * @param uid the uid of the client that requested the IME.
      * @param origin the origin of the IME show request.
      * @param reason the reason why the IME show request was created.
+     * @param fromUser whether this request was created directly from user interaction.
      *
      * @return An IME tracking token.
      */
     @NonNull
     Token onRequestShow(@Nullable String component, int uid, @Origin int origin,
-            @SoftInputShowHideReason int reason);
+            @SoftInputShowHideReason int reason, boolean fromUser);
+
+    /**
+     * Alias for {@link #onRequestShow(String, int, int, int, boolean)} with
+     * {@code fromUser} set to {@code false}.
+     */
+    default Token onRequestShow(@Nullable String component, int uid, @Origin int origin,
+            @SoftInputShowHideReason int reason) {
+        return onRequestShow(component, uid, origin, reason, false /* fromUser */);
+    }
 
     /**
      * Creates an IME hide request tracking token.
@@ -340,12 +351,22 @@
      * @param uid the uid of the client that requested the IME.
      * @param origin the origin of the IME hide request.
      * @param reason the reason why the IME hide request was created.
+     * @param fromUser whether this request was created directly from user interaction.
      *
      * @return An IME tracking token.
      */
     @NonNull
     Token onRequestHide(@Nullable String component, int uid, @Origin int origin,
-            @SoftInputShowHideReason int reason);
+            @SoftInputShowHideReason int reason, boolean fromUser);
+
+    /**
+     * Alias for {@link #onRequestHide(String, int, int, int, boolean)} with
+     * {@code fromUser} set to {@code false}.
+     */
+    default Token onRequestHide(@Nullable String component, int uid, @Origin int origin,
+            @SoftInputShowHideReason int reason) {
+        return onRequestHide(component, uid, origin, reason, false /* fromUser */);
+    }
 
     /**
      * Called when an IME request progresses to a further phase.
@@ -394,6 +415,28 @@
     void onHidden(@Nullable Token token);
 
     /**
+     * Returns whether the current IME request was created due to a user interaction. This can
+     * only be {@code true} when running on the view's UI thread.
+     *
+     * @param view the view for which the IME was requested.
+     * @return {@code true} if this request is coming from a user interaction,
+     * {@code false} otherwise.
+     */
+    static boolean isFromUser(@Nullable View view) {
+        if (view == null) {
+            return false;
+        }
+        final var handler = view.getHandler();
+        // Early return if not on the UI thread, to ensure safe access to getViewRootImpl() below.
+        if (handler == null || handler.getLooper() == null
+                || !handler.getLooper().isCurrentThread()) {
+            return false;
+        }
+        final var viewRootImpl = view.getViewRootImpl();
+        return viewRootImpl != null && viewRootImpl.isHandlingPointerEvent();
+    }
+
+    /**
      * Get the singleton request tracker instance.
      *
      * @return the singleton request tracker instance
@@ -450,13 +493,14 @@
         @NonNull
         @Override
         public Token onRequestShow(@Nullable String component, int uid, @Origin int origin,
-                @SoftInputShowHideReason int reason) {
+                @SoftInputShowHideReason int reason, boolean fromUser) {
             final var tag = getTag(component);
             final var token = IInputMethodManagerGlobalInvoker.onRequestShow(tag, uid, origin,
-                    reason);
+                    reason, fromUser);
 
             Log.i(TAG, token.mTag + ": onRequestShow at " + Debug.originToString(origin)
-                    + " reason " + InputMethodDebug.softInputDisplayReasonToString(reason),
+                    + " reason " + InputMethodDebug.softInputDisplayReasonToString(reason)
+                    + " fromUser " + fromUser,
                     mLogStackTrace ? new Throwable() : null);
 
             return token;
@@ -465,13 +509,14 @@
         @NonNull
         @Override
         public Token onRequestHide(@Nullable String component, int uid, @Origin int origin,
-                @SoftInputShowHideReason int reason) {
+                @SoftInputShowHideReason int reason, boolean fromUser) {
             final var tag = getTag(component);
             final var token = IInputMethodManagerGlobalInvoker.onRequestHide(tag, uid, origin,
-                    reason);
+                    reason, fromUser);
 
             Log.i(TAG, token.mTag + ": onRequestHide at " + Debug.originToString(origin)
-                    + " reason " + InputMethodDebug.softInputDisplayReasonToString(reason),
+                    + " reason " + InputMethodDebug.softInputDisplayReasonToString(reason)
+                    + " fromUser " + fromUser,
                     mLogStackTrace ? new Throwable() : null);
 
             return token;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 3bc02a6..3d70c5b 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2141,8 +2141,10 @@
             @ShowFlags int flags, ResultReceiver resultReceiver,
             @SoftInputShowHideReason int reason) {
         if (statsToken == null) {
+            // TODO(b/303041796): handle tracking physical keyboard and DPAD as user interactions
             statsToken = ImeTracker.forLogging().onRequestShow(null /* component */,
-                    Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT, reason);
+                    Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT, reason,
+                    ImeTracker.isFromUser(view));
         }
         ImeTracker.forLatency().onRequestShow(statsToken, ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
                 reason, ActivityThread::currentApplication);
@@ -2291,15 +2293,22 @@
 
     private boolean hideSoftInputFromWindow(IBinder windowToken, @HideFlags int flags,
             ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
+        // Get served view initially for statsToken creation.
+        final View initialServedView;
+        synchronized (mH) {
+            initialServedView = getServedViewLocked();
+        }
+
         final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
-                null /* component */, Process.myUid(),
-                ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, reason);
+                null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
+                reason, ImeTracker.isFromUser(initialServedView));
         ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
                 reason, ActivityThread::currentApplication);
         ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromWindow",
                 this, null /* icProto */);
         checkFocus();
         synchronized (mH) {
+            // Get served view again in case it changed between the synchronized blocks.
             final View servedView = getServedViewLocked();
             if (servedView == null || servedView.getWindowToken() != windowToken) {
                 ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
@@ -2335,8 +2344,8 @@
 
         final var reason = SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_VIEW;
         final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
-                null /* component */, Process.myUid(),
-                ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, reason);
+                null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
+                reason, ImeTracker.isFromUser(view));
         ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
                 reason, ActivityThread::currentApplication);
         ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromView",
diff --git a/core/java/com/android/internal/inputmethod/IImeTracker.aidl b/core/java/com/android/internal/inputmethod/IImeTracker.aidl
index c7418ee..2759043 100644
--- a/core/java/com/android/internal/inputmethod/IImeTracker.aidl
+++ b/core/java/com/android/internal/inputmethod/IImeTracker.aidl
@@ -31,9 +31,10 @@
      * @param uid the uid of the client that requested the IME.
      * @param origin the origin of the IME show request.
      * @param reason the reason why the IME show request was created.
+     * @param fromUser whether this request was created directly from user interaction.
      * @return A new IME tracking token.
      */
-    ImeTracker.Token onRequestShow(String tag, int uid, int origin, int reason);
+    ImeTracker.Token onRequestShow(String tag, int uid, int origin, int reason, boolean fromUser);
 
     /**
      * Called when an IME hide request is created.
@@ -42,9 +43,10 @@
      * @param uid the uid of the client that requested the IME.
      * @param origin the origin of the IME hide request.
      * @param reason the reason why the IME hide request was created.
+     * @param fromUser whether this request was created directly from user interaction.
      * @return A new IME tracking token.
      */
-    ImeTracker.Token onRequestHide(String tag, int uid, int origin, int reason);
+    ImeTracker.Token onRequestHide(String tag, int uid, int origin, int reason, boolean fromUser);
 
     /**
      * Called when the IME request progresses to a further phase.
diff --git a/core/java/com/android/internal/jank/Cuj.java b/core/java/com/android/internal/jank/Cuj.java
index 7b3565b..48c455a 100644
--- a/core/java/com/android/internal/jank/Cuj.java
+++ b/core/java/com/android/internal/jank/Cuj.java
@@ -28,7 +28,7 @@
 /** @hide */
 public class Cuj {
     @VisibleForTesting
-    public static final int MAX_LENGTH_OF_CUJ_NAME = 80;
+    public static final int MAX_LENGTH_OF_CUJ_NAME = 82;
 
     // Every value must have a corresponding entry in CUJ_STATSD_INTERACTION_TYPE.
     public static final int CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE = 0;
@@ -122,10 +122,12 @@
     public static final int CUJ_PREDICTIVE_BACK_HOME = 86;
     public static final int CUJ_LAUNCHER_SEARCH_QSB_OPEN = 87;
     public static final int CUJ_BACK_PANEL_ARROW = 88;
+    public static final int CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK = 89;
+    public static final int CUJ_LAUNCHER_SEARCH_QSB_WEB_SEARCH = 90;
 
     // When adding a CUJ, update this and make sure to also update CUJ_TO_STATSD_INTERACTION_TYPE.
     @VisibleForTesting
-    static final int LAST_CUJ = CUJ_BACK_PANEL_ARROW;
+    static final int LAST_CUJ = CUJ_LAUNCHER_SEARCH_QSB_WEB_SEARCH;
 
     /** @hide */
     @IntDef({
@@ -209,6 +211,8 @@
             CUJ_PREDICTIVE_BACK_HOME,
             CUJ_LAUNCHER_SEARCH_QSB_OPEN,
             CUJ_BACK_PANEL_ARROW,
+            CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK,
+            CUJ_LAUNCHER_SEARCH_QSB_WEB_SEARCH,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface CujType {
@@ -302,6 +306,8 @@
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_PREDICTIVE_BACK_HOME] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__PREDICTIVE_BACK_HOME;
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_SEARCH_QSB_OPEN] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_SEARCH_QSB_OPEN;
         CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_BACK_PANEL_ARROW] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__BACK_PANEL_ARROW;
+        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_CLOSE_ALL_APPS_BACK;
+        CUJ_TO_STATSD_INTERACTION_TYPE[CUJ_LAUNCHER_SEARCH_QSB_WEB_SEARCH] = FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__INTERACTION_TYPE__LAUNCHER_SEARCH_QSB_WEB_SEARCH;
     }
 
     private Cuj() {
@@ -478,6 +484,10 @@
                 return "LAUNCHER_SEARCH_QSB_OPEN";
             case CUJ_BACK_PANEL_ARROW:
                 return "BACK_PANEL_ARROW";
+            case CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK:
+                return "LAUNCHER_CLOSE_ALL_APPS_BACK";
+            case CUJ_LAUNCHER_SEARCH_QSB_WEB_SEARCH:
+                return "LAUNCHER_SEARCH_QSB_WEB_SEARCH";
         }
         return "UNKNOWN";
     }
diff --git a/core/java/com/android/internal/os/ProcStatsUtil.java b/core/java/com/android/internal/os/ProcStatsUtil.java
index b67190b..1d8cf83 100644
--- a/core/java/com/android/internal/os/ProcStatsUtil.java
+++ b/core/java/com/android/internal/os/ProcStatsUtil.java
@@ -93,23 +93,17 @@
      * seen, or at the end of the file
      */
     @Nullable
-    @android.ravenwood.annotation.RavenwoodReplace
     public static String readTerminatedProcFile(String path, byte terminator) {
         // Permit disk reads here, as /proc isn't really "on disk" and should be fast.
         // TODO: make BlockGuard ignore /proc/ and /sys/ files perhaps?
-        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
+        final int savedPolicy = StrictMode.allowThreadDiskReadsMask();
         try {
             return readTerminatedProcFileInternal(path, terminator);
         } finally {
-            StrictMode.setThreadPolicy(savedPolicy);
+            StrictMode.setThreadPolicyMask(savedPolicy);
         }
     }
 
-    public static String readTerminatedProcFile$ravenwood(String path, byte terminator) {
-        // No StrictMode under Ravenwood
-        return readTerminatedProcFileInternal(path, terminator);
-    }
-
     private static String readTerminatedProcFileInternal(String path, byte terminator) {
         try (FileInputStream is = new FileInputStream(path)) {
             ByteArrayOutputStream byteStream = null;
diff --git a/core/java/com/android/internal/os/StoragedUidIoStatsReader.java b/core/java/com/android/internal/os/StoragedUidIoStatsReader.java
index 2d485da..fb6e133d 100644
--- a/core/java/com/android/internal/os/StoragedUidIoStatsReader.java
+++ b/core/java/com/android/internal/os/StoragedUidIoStatsReader.java
@@ -74,7 +74,6 @@
      *
      * @param callback The callback to invoke for each line of the proc file.
      */
-    @android.ravenwood.annotation.RavenwoodReplace
     public void readAbsolute(Callback callback) {
         final int oldMask = StrictMode.allowThreadDiskReadsMask();
         try {
@@ -84,10 +83,6 @@
         }
     }
 
-    public void readAbsolute$ravenwood(Callback callback) {
-        readAbsoluteInternal(callback);
-    }
-
     private void readAbsoluteInternal(Callback callback) {
         File file = new File(sUidIoFile);
         try (BufferedReader reader = Files.newBufferedReader(file.toPath())) {
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 10f75d0..c62e536 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -100,6 +100,7 @@
         optional SettingProto accessibility_force_invert_color_enabled = 52 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto accessibility_magnification_two_finger_triple_tap_enabled = 53 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto qs_targets = 54 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto accessibility_pinch_to_zoom_anywhere_enabled = 55 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
     }
     optional Accessibility accessibility = 2;
diff --git a/core/tests/coretests/src/android/os/StrictModeTest.java b/core/tests/coretests/src/android/os/StrictModeTest.java
new file mode 100644
index 0000000..9050583
--- /dev/null
+++ b/core/tests/coretests/src/android/os/StrictModeTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 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.os;
+
+import static org.junit.Assert.assertEquals;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+
+@RunWith(AndroidJUnit4.class)
+public class StrictModeTest {
+    private File mFile;
+
+    @Before
+    public void setUp() throws Exception {
+        mFile = File.createTempFile("StrictModeTest", "tmp");
+    }
+
+    @Test
+    public void testAllowThreadDiskReadsMask() throws Exception {
+        final int mask = StrictMode.allowThreadDiskReadsMask();
+        try {
+            mFile.exists();
+        } finally {
+            StrictMode.setThreadPolicyMask(mask);
+        }
+    }
+
+    @Test
+    public void testAllowThreadDiskWritesMask() throws Exception {
+        final int mask = StrictMode.allowThreadDiskReadsMask();
+        try {
+            mFile.delete();
+        } finally {
+            StrictMode.setThreadPolicyMask(mask);
+        }
+    }
+
+    @Test
+    public void testThreadMask() throws Exception {
+        StrictMode.setThreadPolicyMask(0);
+        assertEquals(0, StrictMode.getThreadPolicyMask());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
index 8310333..27398ea 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
@@ -31,10 +31,13 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -43,6 +46,9 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class BinderDeathDispatcherTest {
+    @Rule
+    public RavenwoodRule mRavenwood = new RavenwoodRule.Builder().build();
+
     private static class MyTarget implements IInterface, IBinder {
         public boolean isAlive = true;
         public DeathRecipient mRecipient;
@@ -195,6 +201,7 @@
     }
 
     @Test
+    @DisabledOnRavenwood(reason = "b/324433654 -- depends on unsupported classes")
     public void testRegisterAndKill() {
         BinderDeathDispatcher<MyTarget> d = new BinderDeathDispatcher<>();
 
@@ -265,6 +272,7 @@
     }
 
     @Test
+    @DisabledOnRavenwood(reason = "b/324433654 -- depends on unsupported classes")
     public void duplicateRegistrations() {
         BinderDeathDispatcher<MyTarget> d = new BinderDeathDispatcher<>();
 
diff --git a/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java b/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java
index 80061a5..cc6c4e8 100644
--- a/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/StoragedUidIoStatsReaderTest.java
@@ -20,12 +20,15 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
 import android.os.FileUtils;
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.ravenwood.RavenwoodRule;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -44,6 +47,8 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class StoragedUidIoStatsReaderTest {
+    @Rule
+    public RavenwoodRule mRavenwood = new RavenwoodRule.Builder().build();
 
     private File mTestDir;
     private File mTestFile;
@@ -79,6 +84,7 @@
      * Tests that reading a file with 3 uids works as expected.
      */
     @Test
+    @DisabledOnRavenwood(reason = "b/324433654 -- depends on unsupported classes")
     public void testReadExpected() throws Exception {
         BufferedWriter bufferedWriter = Files.newBufferedWriter(mTestFile.toPath());
         int[] uids = {0, 100, 200};
@@ -116,6 +122,7 @@
      * Tests that a line with less than 11 items is passed over.
      */
     @Test
+    @DisabledOnRavenwood(reason = "b/324433654 -- depends on unsupported classes")
     public void testLineDoesNotElevenEntries() throws Exception {
         BufferedWriter bufferedWriter = Files.newBufferedWriter(mTestFile.toPath());
 
@@ -139,6 +146,7 @@
      * Tests that a line that is malformed is passed over.
      */
     @Test
+    @DisabledOnRavenwood(reason = "b/324433654 -- depends on unsupported classes")
     public void testLineIsMalformed() throws Exception {
         BufferedWriter bufferedWriter = Files.newBufferedWriter(mTestFile.toPath());
 
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index dc8116d..cdcf8e4 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -226,6 +226,7 @@
         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED,
         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED,
         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
+        Settings.Secure.ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED,
         Settings.Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED,
         Settings.Secure.NOTIFICATION_BUBBLES,
         Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index fabdafc..35d45a9 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -319,6 +319,7 @@
         VALIDATORS.put(
                 Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
                 BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
                 Secure.ACCESSIBILITY_BUTTON_TARGETS,
                 ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index bc07836..612badd 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1861,6 +1861,10 @@
                 SecureSettingsProto.Accessibility
                         .ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED);
         dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED,
+                SecureSettingsProto.Accessibility
+                        .ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED);
+        dumpSetting(s, p,
                 Settings.Secure.HEARING_AID_RINGTONE_ROUTING,
                 SecureSettingsProto.Accessibility.HEARING_AID_RINGTONE_ROUTING);
         dumpSetting(s, p,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
index f3d0d2c..97db9b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.scene.shared.flag.SceneContainerFlags
+import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
 import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled
@@ -65,7 +66,9 @@
 
                             controller.setOverExpansion(0f)
                             controller.setOverScrollAmount(0)
-                            controller.updateFooter()
+                            if (!FooterViewRefactor.isEnabled) {
+                                controller.updateFooter()
+                            }
                         }
                     }
                 }
diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/framework-minus-apex-ravenwood-policies.txt
index 16f99e9..0229611 100644
--- a/ravenwood/framework-minus-apex-ravenwood-policies.txt
+++ b/ravenwood/framework-minus-apex-ravenwood-policies.txt
@@ -142,6 +142,8 @@
 class android.telephony.PinResult stubclass
 
 # Just enough to support mocking, no further functionality
+class android.content.BroadcastReceiver stub
+    method <init> ()V stub
 class android.content.Context stub
     method <init> ()V stub
 class android.content.pm.PackageManager stub
diff --git a/ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java b/ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java
index 4bf0980..1adb0f3 100644
--- a/ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java
+++ b/ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java
@@ -42,4 +42,13 @@
 @Target({ElementType.METHOD, ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)
 public @interface DisabledOnRavenwood {
+    /**
+     * One or more classes that aren't yet supported by Ravenwood, which this test depends on.
+     */
+    Class<?>[] blockedBy() default {};
+
+    /**
+     * General free-form description of why this test is being ignored.
+     */
+    String reason() default "";
 }
diff --git a/ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java b/ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java
index 916dd59..7faa654 100644
--- a/ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java
+++ b/ravenwood/junit-src/android/platform/test/annotations/IgnoreUnderRavenwood.java
@@ -35,9 +35,12 @@
  * to be enabled.
  *
  * @hide
+ *
+ * @deprecated Use {@link DisabledOnRavenwood} instead.
  */
 @Target({ElementType.METHOD, ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)
+@Deprecated
 public @interface IgnoreUnderRavenwood {
     /**
      * One or more classes that aren't yet supported by Ravenwood, which this test depends on.
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index 75c5a49..01c0074 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -21,6 +21,7 @@
 com.android.internal.power.ModemPowerProfile
 
 android.util.AtomicFile
+android.util.CloseGuard
 android.util.DataUnit
 android.util.DayOfMonthCursor
 android.util.DumpableContainer
@@ -68,10 +69,14 @@
 android.os.MessageQueue
 android.os.PackageTagsList
 android.os.Parcel
+android.os.ParcelFileDescriptor
+android.os.ParcelFileDescriptor$AutoCloseInputStream
+android.os.ParcelFileDescriptor$AutoCloseOutputStream
 android.os.Parcelable
 android.os.PowerComponents
 android.os.Process
 android.os.ServiceSpecificException
+android.os.StrictMode
 android.os.SystemClock
 android.os.SystemProperties
 android.os.TestLooperManager
@@ -147,6 +152,9 @@
 android.content.ContentProvider
 
 android.app.ActivityManager
+android.app.ActivityOptions
+android.app.BroadcastOptions
+android.app.ComponentOptions
 android.app.Instrumentation
 
 android.metrics.LogMaker
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index e923e30a..bdc4a7a 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -38,6 +38,7 @@
 per-file PackageWatchdog.java, RescueParty.java = file:/services/core/java/com/android/server/rollback/OWNERS
 per-file PinnerService.java = file:/core/java/android/app/pinner/OWNERS
 per-file RescueParty.java = shuc@google.com, ancr@google.com, harshitmahajan@google.com
+per-file SensitiveContentProtectionManagerService.java = file:/core/java/android/permission/OWNERS
 per-file SystemClockTime.java = file:/services/core/java/com/android/server/timedetector/OWNERS
 per-file SystemTimeZone.java = file:/services/core/java/com/android/server/timezonedetector/OWNERS
 per-file TelephonyRegistry.java = file:/telephony/OWNERS
diff --git a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
index 27e1b9a..d06c31c 100644
--- a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
+++ b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
@@ -76,11 +76,11 @@
     @NonNull
     @Override
     public ImeTracker.Token onRequestShow(@NonNull String tag, int uid,
-            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) {
+            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) {
         final var binder = new Binder();
         final var token = new ImeTracker.Token(binder, tag);
         final var entry = new History.Entry(tag, uid, ImeTracker.TYPE_SHOW, ImeTracker.STATUS_RUN,
-                origin, reason);
+                origin, reason, fromUser);
         synchronized (mLock) {
             mHistory.addEntry(binder, entry);
 
@@ -98,11 +98,11 @@
     @NonNull
     @Override
     public ImeTracker.Token onRequestHide(@NonNull String tag, int uid,
-            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) {
+            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) {
         final var binder = new Binder();
         final var token = new ImeTracker.Token(binder, tag);
         final var entry = new History.Entry(tag, uid, ImeTracker.TYPE_HIDE, ImeTracker.STATUS_RUN,
-                origin, reason);
+                origin, reason, fromUser);
         synchronized (mLock) {
             mHistory.addEntry(binder, entry);
 
@@ -269,7 +269,7 @@
             // Log newly finished entry.
             FrameworkStatsLog.write(FrameworkStatsLog.IME_REQUEST_FINISHED, entry.mUid,
                     entry.mDuration, entry.mType, entry.mStatus, entry.mReason,
-                    entry.mOrigin, entry.mPhase);
+                    entry.mOrigin, entry.mPhase, entry.mFromUser);
         }
 
         /** Dumps the contents of the circular buffer. */
@@ -353,6 +353,9 @@
             @ImeTracker.Phase
             private int mPhase = ImeTracker.PHASE_NOT_SET;
 
+            /** Whether this request was created directly from a user interaction. */
+            private final boolean mFromUser;
+
             /**
              * Name of the window that created the IME request.
              *
@@ -363,13 +366,14 @@
 
             private Entry(@NonNull String tag, int uid, @ImeTracker.Type int type,
                     @ImeTracker.Status int status, @ImeTracker.Origin int origin,
-                    @SoftInputShowHideReason int reason) {
+                    @SoftInputShowHideReason int reason, boolean fromUser) {
                 mTag = tag;
                 mUid = uid;
                 mType = type;
                 mStatus = status;
                 mOrigin = origin;
                 mReason = reason;
+                mFromUser = fromUser;
             }
         }
     }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 3bd1e1a..5ab9151 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -3529,7 +3529,7 @@
         // Create statsToken is none exists.
         if (statsToken == null) {
             statsToken = createStatsTokenForFocusedClient(true /* show */,
-                    ImeTracker.ORIGIN_SERVER_START_INPUT, reason);
+                    ImeTracker.ORIGIN_SERVER_START_INPUT, reason, false /* fromUser */);
         }
 
         if (!mVisibilityStateComputer.onImeShowFlags(statsToken, flags)) {
@@ -3605,8 +3605,9 @@
             @SoftInputShowHideReason int reason) {
         // Create statsToken is none exists.
         if (statsToken == null) {
+            final boolean fromUser = reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY;
             statsToken = createStatsTokenForFocusedClient(false /* show */,
-                    ImeTracker.ORIGIN_SERVER_HIDE_INPUT, reason);
+                    ImeTracker.ORIGIN_SERVER_HIDE_INPUT, reason, fromUser);
         }
 
         if (!mVisibilityStateComputer.canHideIme(statsToken, flags)) {
@@ -6675,10 +6676,11 @@
      * @param show whether this is a show or a hide request.
      * @param origin the origin of the IME request.
      * @param reason the reason why the IME request was created.
+     * @param fromUser whether this request was created directly from user interaction.
      */
     @NonNull
     private ImeTracker.Token createStatsTokenForFocusedClient(boolean show,
-            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) {
+            @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) {
         final int uid = mCurFocusedWindowClient != null
                 ? mCurFocusedWindowClient.mUid
                 : -1;
@@ -6687,9 +6689,11 @@
                 : "uid(" + uid + ")";
 
         if (show) {
-            return ImeTracker.forLogging().onRequestShow(packageName, uid, origin, reason);
+            return ImeTracker.forLogging()
+                    .onRequestShow(packageName, uid, origin, reason, fromUser);
         } else {
-            return ImeTracker.forLogging().onRequestHide(packageName, uid, origin, reason);
+            return ImeTracker.forLogging()
+                    .onRequestHide(packageName, uid, origin, reason, fromUser);
         }
     }
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 775a361..25e4116 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4995,6 +4995,14 @@
                 }
                 break;
             }
+            case KeyEvent.KEYCODE_STEM_PRIMARY: {
+                if (down && event.getRepeatCount() == 0 && (result & ACTION_PASS_TO_USER) == 0) {
+                    // We've decided not to pass key to user at queueing stage. Make the gesture
+                    // executable.
+                    setDeferredKeyActionsExecutableAsync(keyCode, event.getDownTime());
+                }
+                break;
+            }
             case KeyEvent.KEYCODE_VIDEO_APP_1:
             case KeyEvent.KEYCODE_VIDEO_APP_2:
             case KeyEvent.KEYCODE_VIDEO_APP_3:
diff --git a/services/core/java/com/android/server/uri/UriPermission.java b/services/core/java/com/android/server/uri/UriPermission.java
index f3eeab0..e406eb2 100644
--- a/services/core/java/com/android/server/uri/UriPermission.java
+++ b/services/core/java/com/android/server/uri/UriPermission.java
@@ -269,8 +269,9 @@
      * Remove given read owner, updating {@Link #modeFlags} as needed.
      */
     void removeReadOwner(UriPermissionOwner owner) {
-        if (!mReadOwners.remove(owner)) {
+        if (mReadOwners == null || !mReadOwners.remove(owner)) {
             Slog.wtf(TAG, "Unknown read owner " + owner + " in " + this);
+            return;
         }
         if (mReadOwners.size() == 0) {
             mReadOwners = null;
@@ -294,8 +295,9 @@
      * Remove given write owner, updating {@Link #modeFlags} as needed.
      */
     void removeWriteOwner(UriPermissionOwner owner) {
-        if (!mWriteOwners.remove(owner)) {
+        if (mWriteOwners == null || !mWriteOwners.remove(owner)) {
             Slog.wtf(TAG, "Unknown write owner " + owner + " in " + this);
+            return;
         }
         if (mWriteOwners.size() == 0) {
             mWriteOwners = null;
diff --git a/services/core/java/com/android/server/wm/ActivityAssistInfo.java b/services/core/java/com/android/server/wm/ActivityAssistInfo.java
index e1e7ee4..3b91780 100644
--- a/services/core/java/com/android/server/wm/ActivityAssistInfo.java
+++ b/services/core/java/com/android/server/wm/ActivityAssistInfo.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import android.content.ComponentName;
 import android.os.IBinder;
 
 /**
@@ -28,11 +29,13 @@
     private final IBinder mActivityToken;
     private final IBinder mAssistToken;
     private final int mTaskId;
+    private final ComponentName mComponentName;
 
     public ActivityAssistInfo(ActivityRecord activityRecord) {
         this.mActivityToken = activityRecord.token;
         this.mAssistToken = activityRecord.assistToken;
         this.mTaskId = activityRecord.getTask().mTaskId;
+        this.mComponentName = activityRecord.mActivityComponent;
     }
 
     /** @hide */
@@ -49,4 +52,9 @@
     public int getTaskId() {
         return mTaskId;
     }
+
+    /** @hide */
+    public ComponentName getComponentName() {
+        return mComponentName;
+    }
 }
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 53c1960..6d3b8ac 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -119,3 +119,19 @@
         "android.test.runner",
     ],
 }
+
+android_ravenwood_test {
+    name: "FrameworksMockingServicesTestsRavenwood",
+    libs: [
+        "android.test.mock",
+    ],
+    static_libs: [
+        "androidx.annotation_annotation",
+        "androidx.test.rules",
+        "services.core",
+    ],
+    srcs: [
+        "src/com/android/server/am/BroadcastRecordTest.java",
+    ],
+    auto_gen_config: true,
+}
diff --git a/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java
index 50d37ec..77e7a0a 100644
--- a/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/StemKeyGestureTests.java
@@ -34,6 +34,7 @@
 import android.content.ComponentName;
 import android.os.RemoteException;
 import android.provider.Settings;
+import android.view.Display;
 
 import org.junit.Test;
 
@@ -104,6 +105,27 @@
     }
 
     @Test
+    public void stemSingleKey_launchTargetActivity_whenScreenIsOff() {
+        overrideBehavior(
+                STEM_PRIMARY_BUTTON_SHORT_PRESS,
+                SHORT_PRESS_PRIMARY_LAUNCH_TARGET_ACTIVITY);
+        setUpPhoneWindowManager(/* supportSettingsUpdate= */ true);
+        mPhoneWindowManager.overrideShouldEarlyShortPressOnStemPrimary(false);
+        mPhoneWindowManager.overrideStartActivity();
+        mPhoneWindowManager.setKeyguardServiceDelegateIsShowing(false);
+        mPhoneWindowManager.overrideIsUserSetupComplete(true);
+        mPhoneWindowManager.assumeResolveActivityNotNull();
+        mPhoneWindowManager.overrideDisplayState(Display.STATE_OFF);
+        ComponentName targetComponent = ComponentName.unflattenFromString(TEST_TARGET_ACTIVITY);
+        mPhoneWindowManager.overrideStemPressTargetActivity(targetComponent);
+        mPhoneWindowManager.overrideKeyEventPolicyFlags(0);
+
+        sendKey(KEYCODE_STEM_PRIMARY);
+
+        mPhoneWindowManager.assertActivityTargetLaunched(targetComponent);
+    }
+
+    @Test
     public void stemSingleKey_appHasOverridePermission_consumedByApp_notOpenAllApp() {
         overrideBehavior(STEM_PRIMARY_BUTTON_SHORT_PRESS, SHORT_PRESS_PRIMARY_LAUNCH_ALL_APPS);
         setUpPhoneWindowManager(/* supportSettingsUpdate= */ true);
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index 2904c03..1a26c45 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -180,6 +180,8 @@
     private boolean mIsTalkBackEnabled;
     private boolean mIsTalkBackShortcutGestureEnabled;
 
+    private int mKeyEventPolicyFlags = FLAG_INTERACTIVE;
+
     private class TestTalkbackShortcutController extends TalkbackShortcutController {
         TestTalkbackShortcutController(Context context) {
             super(context);
@@ -379,12 +381,12 @@
     }
 
     int interceptKeyBeforeQueueing(KeyEvent event) {
-        return mPhoneWindowManager.interceptKeyBeforeQueueing(event, FLAG_INTERACTIVE);
+        return mPhoneWindowManager.interceptKeyBeforeQueueing(event, mKeyEventPolicyFlags);
     }
 
     long interceptKeyBeforeDispatching(KeyEvent event) {
         return mPhoneWindowManager.interceptKeyBeforeDispatching(mInputToken, event,
-                FLAG_INTERACTIVE);
+                mKeyEventPolicyFlags);
     }
 
     void dispatchUnhandledKey(KeyEvent event) {
@@ -588,6 +590,10 @@
                 .when(mButtonOverridePermissionChecker).canAppOverrideSystemKey(any(), anyInt());
     }
 
+    void overrideKeyEventPolicyFlags(int flags) {
+        mKeyEventPolicyFlags = flags;
+    }
+
     /**
      * Below functions will check the policy behavior could be invoked.
      */
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index d722f2f..5dd4feb 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -20,6 +20,7 @@
 import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE;
 import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
 import static android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
+import static android.service.voice.VoiceInteractionSession.KEY_FOREGROUND_ACTIVITIES;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 
@@ -35,6 +36,7 @@
 import android.app.ActivityTaskManager;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
+import android.app.IActivityTaskManager;
 import android.app.UriGrantsManager;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
@@ -112,6 +114,7 @@
     final Callback mCallback;
     final int mCallingUid;
     final Handler mHandler;
+    final IActivityTaskManager mActivityTaskManager;
     final IActivityManager mAm;
     final UriGrantsManagerInternal mUgmInternal;
     final IWindowManager mIWindowManager;
@@ -224,6 +227,7 @@
         mCallback = callback;
         mCallingUid = callingUid;
         mHandler = handler;
+        mActivityTaskManager = ActivityTaskManager.getService();
         mAm = ActivityManager.getService();
         mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
         mIWindowManager = IWindowManager.Stub.asInterface(
@@ -300,11 +304,30 @@
                 for (int i = 0; i < topActivitiesCount; i++) {
                     topActivitiesToken.add(topActivities.get(i).getActivityToken());
                 }
+                boolean fetchDataAllowed =
+                        (disabledContext & VoiceInteractionSession.SHOW_WITH_ASSIST) == 0;
+
+                // Ensure that the current activity supports assist data
+                boolean isAssistDataAllowed = false;
+                try {
+                    isAssistDataAllowed = mActivityTaskManager.isAssistDataAllowed();
+                } catch (RemoteException e) {
+                    // Should never happen
+                }
+
+                // TODO: Refactor to have all assist data allowed checks in one place.
+                if (fetchDataAllowed && isAssistDataAllowed) {
+                    ArrayList<ComponentName> topComponents = new ArrayList<>(topActivitiesCount);
+                    for (int i = 0; i < topActivitiesCount; i++) {
+                        topComponents.add(topActivities.get(i).getComponentName());
+                    }
+                    mShowArgs.putParcelableArrayList(KEY_FOREGROUND_ACTIVITIES, topComponents);
+                }
 
                 mAssistDataRequester.requestAssistData(topActivitiesToken,
                         fetchData,
                         fetchScreenshot,
-                        (disabledContext & VoiceInteractionSession.SHOW_WITH_ASSIST) == 0,
+                        fetchDataAllowed,
                         (disabledContext & VoiceInteractionSession.SHOW_WITH_SCREENSHOT) == 0,
                         mCallingUid,
                         mSessionComponentName.getPackageName(),
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/ParcelFileDescriptor_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/ParcelFileDescriptor_host.java
new file mode 100644
index 0000000..0ebaac60
--- /dev/null
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/ParcelFileDescriptor_host.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2024 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.hoststubgen.nativesubstitution;
+
+import static android.os.ParcelFileDescriptor.MODE_APPEND;
+import static android.os.ParcelFileDescriptor.MODE_CREATE;
+import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
+import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
+import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
+import static android.os.ParcelFileDescriptor.MODE_WORLD_READABLE;
+import static android.os.ParcelFileDescriptor.MODE_WORLD_WRITEABLE;
+import static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ParcelFileDescriptor_host {
+    /**
+     * Since we don't have a great way to keep an unmanaged {@code FileDescriptor} reference
+     * alive, we keep a strong reference to the {@code RandomAccessFile} we used to open it. This
+     * gives us a way to look up the original parent object when closing later.
+     */
+    @GuardedBy("sActive")
+    private static final Map<FileDescriptor, RandomAccessFile> sActive = new HashMap<>();
+
+    public static void native_setFdInt$ravenwood(FileDescriptor fd, int fdInt) {
+        try {
+            final Object obj = Class.forName("jdk.internal.access.SharedSecrets").getMethod(
+                    "getJavaIOFileDescriptorAccess").invoke(null);
+            Class.forName("jdk.internal.access.JavaIOFileDescriptorAccess").getMethod(
+                    "set", FileDescriptor.class, int.class).invoke(obj, fd, fdInt);
+        } catch (ReflectiveOperationException e) {
+            throw new RuntimeException("Failed to interact with raw FileDescriptor internals;"
+                    + " perhaps JRE has changed?", e);
+        }
+    }
+
+    public static int native_getFdInt$ravenwood(FileDescriptor fd) {
+        try {
+            final Object obj = Class.forName("jdk.internal.access.SharedSecrets").getMethod(
+                    "getJavaIOFileDescriptorAccess").invoke(null);
+            return (int) Class.forName("jdk.internal.access.JavaIOFileDescriptorAccess").getMethod(
+                    "get", FileDescriptor.class).invoke(obj, fd);
+        } catch (ReflectiveOperationException e) {
+            throw new RuntimeException("Failed to interact with raw FileDescriptor internals;"
+                    + " perhaps JRE has changed?", e);
+        }
+    }
+
+    public static FileDescriptor native_open$ravenwood(File file, int pfdMode) throws IOException {
+        if ((pfdMode & MODE_CREATE) != 0 && !file.exists()) {
+            throw new FileNotFoundException();
+        }
+
+        final String modeString;
+        if ((pfdMode & MODE_READ_WRITE) == MODE_READ_WRITE) {
+            modeString = "rw";
+        } else if ((pfdMode & MODE_WRITE_ONLY) == MODE_WRITE_ONLY) {
+            modeString = "rw";
+        } else if ((pfdMode & MODE_READ_ONLY) == MODE_READ_ONLY) {
+            modeString = "r";
+        } else {
+            throw new IllegalArgumentException();
+        }
+
+        final RandomAccessFile raf = new RandomAccessFile(file, modeString);
+
+        // Now that we have a real file on disk, match requested flags
+        if ((pfdMode & MODE_TRUNCATE) != 0) {
+            raf.setLength(0);
+        }
+        if ((pfdMode & MODE_APPEND) != 0) {
+            raf.seek(raf.length());
+        }
+        if ((pfdMode & MODE_WORLD_READABLE) != 0) {
+            file.setReadable(true, false);
+        }
+        if ((pfdMode & MODE_WORLD_WRITEABLE) != 0) {
+            file.setWritable(true, false);
+        }
+
+        final FileDescriptor fd = raf.getFD();
+        synchronized (sActive) {
+            sActive.put(fd, raf);
+        }
+        return fd;
+    }
+
+    public static void native_close$ravenwood(FileDescriptor fd) {
+        final RandomAccessFile raf;
+        synchronized (sActive) {
+            raf = sActive.remove(fd);
+        }
+        try {
+            if (raf != null) {
+                raf.close();
+            } else {
+                // Odd, we don't remember opening this ourselves, but let's release the
+                // underlying resource as requested
+                System.err.println("Closing unknown FileDescriptor: " + fd);
+                new FileOutputStream(fd).close();
+            }
+        } catch (IOException ignored) {
+        }
+    }
+}