Update android_sdk extensions library

Ran third_party/android_sdk/window_extensions/update_source.sh and fixed
build errors.

Change-Id: Id4366c1281207e97d45c690f24e606326a6a6964
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7720925
Commit-Queue: Sam Maier <smaier@google.com>
Reviewed-by: Andrew Grieve <agrieve@chromium.org>
Auto-Submit: Sam Maier <smaier@google.com>
Commit-Queue: Andrew Grieve <agrieve@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1608602}
NOKEYCHECK=True
GitOrigin-RevId: 56d4a84e46dec7cc76abf24d114c139c15b2d769
diff --git a/window_extensions/BUILD.gn b/window_extensions/BUILD.gn
index d9c40dd..c7501e9 100644
--- a/window_extensions/BUILD.gn
+++ b/window_extensions/BUILD.gn
@@ -9,7 +9,10 @@
 android_library("androidx_window_extensions_java") {
   visibility = [ ":*" ]
   sources = rebase_path(read_file("sources.txt", "list lines"), ".", "java")
-  deps = [ "//third_party/androidx:androidx_annotation_annotation_jvm_java" ]
+  deps = [
+    "//third_party/android_deps:org_jspecify_jspecify_java",
+    "//third_party/androidx:androidx_annotation_annotation_jvm_java",
+  ]
 }
 
 # Use an intermediate target that omits the "_java" suffix in order to avoid
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/RequiresVendorApiLevel.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/RequiresVendorApiLevel.java
new file mode 100644
index 0000000..72e844d
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/RequiresVendorApiLevel.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2023 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 androidx.window.extensions;
+
+import androidx.annotation.IntRange;
+import androidx.annotation.RestrictTo;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** The annotation used to document the minimum supported vendor API level of the denoted target. */
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.FIELD})
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public @interface RequiresVendorApiLevel {
+
+    /** The minimum required vendor API level of the denoted target. */
+    @IntRange(from = 1)
+    int level();
+
+    /**
+     * The vendor API level that the denoted target started to deprecated, which defaults to {@link
+     * #VENDOR_API_LEVEL_NOT_SET}.
+     */
+    int deprecatedSince() default VENDOR_API_LEVEL_NOT_SET;
+
+    /** Indicates the denoted target is not deprecated. */
+    int VENDOR_API_LEVEL_NOT_SET = -1;
+}
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java
index 74163e6..10c29fa 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java
@@ -16,113 +16,29 @@
 
 package androidx.window.extensions;
 
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.app.Activity;
-import android.app.ActivityOptions;
-import android.content.Context;
-import android.os.IBinder;
-
-import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
 import androidx.window.extensions.area.WindowAreaComponent;
-import androidx.window.extensions.core.util.function.Consumer;
 import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
-import androidx.window.extensions.embedding.ActivityStack;
-import androidx.window.extensions.embedding.SplitAttributes;
-import androidx.window.extensions.embedding.SplitInfo;
 import androidx.window.extensions.layout.WindowLayoutComponent;
 
-import java.util.Set;
+import org.jspecify.annotations.Nullable;
 
 /**
  * A class to provide instances of different WindowManager Jetpack extension components. An OEM must
- * implement all the availability methods to state which WindowManager Jetpack extension
- * can be used. If a component is not available then the check must return {@code false}. Trying to
- * get a component that is not available will throw an {@link UnsupportedOperationException}.
- * All components must support the API level returned in
- * {@link WindowExtensions#getVendorApiLevel()}.
+ * implement all the availability methods to state which WindowManager Jetpack extension can be
+ * used. If a component is not available then the check must return {@code false}. Trying to get a
+ * component that is not available will throw an {@link UnsupportedOperationException}. All
+ * components must support the API level returned in {@link WindowExtensions#getVendorApiLevel()}.
  */
 public interface WindowExtensions {
-    // TODO(b/241323716) Removed after we have annotation to check API level
-    /**
-     * An invalid {@link #getVendorApiLevel vendor API level}
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    int INVALID_VENDOR_API_LEVEL = -1;
-
-    // TODO(b/241323716) Removed after we have annotation to check API level
-    /**
-     * A vendor API level constant. It helps to unify the format of documenting {@code @since}
-     * block.
-     * <p>
-     * The added APIs for Vendor API level 1 are:
-     * <ul>
-     *     <li>{@link androidx.window.extensions.embedding.ActivityRule} APIs</li>
-     *     <li>{@link androidx.window.extensions.embedding.SplitPairRule} APIs</li>
-     *     <li>{@link androidx.window.extensions.embedding.SplitPlaceholderRule} APIs</li>
-     *     <li>{@link androidx.window.extensions.embedding.SplitInfo} APIs</li>
-     *     <li>{@link androidx.window.extensions.layout.DisplayFeature} APIs</li>
-     *     <li>{@link androidx.window.extensions.layout.FoldingFeature} APIs</li>
-     *     <li>{@link androidx.window.extensions.layout.WindowLayoutInfo} APIs</li>
-     *     <li>{@link androidx.window.extensions.layout.WindowLayoutComponent} APIs</li>
-     * </ul>
-     * </p>
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    int VENDOR_API_LEVEL_1 = 1;
-
-    // TODO(b/241323716) Removed after we have annotation to check API level
-    /**
-     * A vendor API level constant. It helps to unify the format of documenting {@code @since}
-     * block.
-     * The added APIs for Vendor API level 2 are:
-     * <ul>
-     *     <li>{@link WindowAreaComponent#addRearDisplayStatusListener(Consumer)}</li>
-     *     <li>{@link WindowAreaComponent#startRearDisplaySession(Activity, Consumer)}</li>
-     *     <li>{@link androidx.window.extensions.embedding.SplitPlaceholderRule.Builder#setFinishPrimaryWithPlaceholder(int)}</li>
-     *     <li>{@link androidx.window.extensions.embedding.SplitAttributes}</li>
-     *     <li>{@link ActivityEmbeddingComponent#setSplitAttributesCalculator(
-     *      androidx.window.extensions.core.util.function.Function)}</li>
-     *     <li>{@link WindowLayoutComponent#addWindowLayoutInfoListener(Context, Consumer)}</li>
-     * </ul>
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    int VENDOR_API_LEVEL_2 = 2;
-
-    // TODO(b/241323716) Removed after we have annotation to check API level
-    /**
-     * A vendor API level constant. It helps to unify the format of documenting {@code @since}
-     * block.
-     * <p>
-     * The added APIs for Vendor API level 3 are:
-     * <ul>
-     *     <li>{@link ActivityStack#getToken()}</li>
-     *     <li>{@link SplitInfo#getToken()}</li>
-     *     <li>{@link ActivityEmbeddingComponent#setLaunchingActivityStack(ActivityOptions,
-     *     IBinder)}</li>
-     *     <li>{@link ActivityEmbeddingComponent#invalidateTopVisibleSplitAttributes()}</li>
-     *     <li>{@link ActivityEmbeddingComponent#updateSplitAttributes(IBinder, SplitAttributes)}
-     *     </li>
-     *     <li>{@link ActivityEmbeddingComponent#finishActivityStacks(Set)}</li>
-     *     <li>{@link WindowAreaComponent#addRearDisplayPresentationStatusListener(Consumer)}</li>
-     *     <li>{@link WindowAreaComponent#startRearDisplayPresentationSession(Activity, Consumer)}
-     *     </li>
-     *     <li>{@link WindowAreaComponent#getRearDisplayMetrics()}</li>
-     *     <li>{@link WindowAreaComponent#getRearDisplayPresentation()}</li>
-     * </ul>
-     * </p>
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    int VENDOR_API_LEVEL_3 = 3;
 
     /**
      * Returns the API level of the vendor library on the device. If the returned version is not
      * supported by the WindowManager library, then some functions may not be available or replaced
      * with stub implementations.
      *
-     * The expected use case is for the WindowManager library to determine which APIs are
+     * <p>The expected use case is for the WindowManager library to determine which APIs are
      * available and wrap the API so that app developers do not need to deal with the complexity.
+     *
      * @return the API level supported by the library.
      */
     default int getVendorApiLevel() {
@@ -133,30 +49,30 @@
      * Returns the OEM implementation of {@link WindowLayoutComponent} if it is supported on the
      * device, {@code null} otherwise. The implementation must match the API level reported in
      * {@link WindowExtensions}.
+     *
      * @return the OEM implementation of {@link WindowLayoutComponent}
      */
-    @Nullable
-    WindowLayoutComponent getWindowLayoutComponent();
+    @Nullable WindowLayoutComponent getWindowLayoutComponent();
 
     /**
      * Returns the OEM implementation of {@link ActivityEmbeddingComponent} if it is supported on
      * the device, {@code null} otherwise. The implementation must match the API level reported in
      * {@link WindowExtensions}.
+     *
      * @return the OEM implementation of {@link ActivityEmbeddingComponent}
      */
-    @Nullable
-    default ActivityEmbeddingComponent getActivityEmbeddingComponent() {
+    default @Nullable ActivityEmbeddingComponent getActivityEmbeddingComponent() {
         return null;
     }
 
     /**
-     * Returns the OEM implementation of {@link WindowAreaComponent} if it is supported on
-     * the device, {@code null} otherwise. The implementation must match the API level reported in
+     * Returns the OEM implementation of {@link WindowAreaComponent} if it is supported on the
+     * device, {@code null} otherwise. The implementation must match the API level reported in
      * {@link WindowExtensions}.
+     *
      * @return the OEM implementation of {@link WindowAreaComponent}
      */
-    @Nullable
-    default WindowAreaComponent getWindowAreaComponent() {
+    default @Nullable WindowAreaComponent getWindowAreaComponent() {
         return null;
     }
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensionsProvider.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensionsProvider.java
index 1f3aefd..e69a942 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensionsProvider.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensionsProvider.java
@@ -16,22 +16,20 @@
 
 package androidx.window.extensions;
 
-import androidx.annotation.NonNull;
+import org.jspecify.annotations.NonNull;
 
-/**
- * Provides the OEM implementation of {@link WindowExtensions}.
- */
+/** Provides the OEM implementation of {@link WindowExtensions}. */
 public class WindowExtensionsProvider {
 
     private WindowExtensionsProvider() {}
 
     /**
-     * Returns the OEM implementation of {@link WindowExtensions}. This method must be
-     * implemented by the OEM also.
+     * Returns the OEM implementation of {@link WindowExtensions}. This method must be implemented
+     * by the OEM also.
+     *
      * @return the OEM implementation of {@link WindowExtensions}
      */
-    @NonNull
-    public static WindowExtensions getWindowExtensions() {
+    public static @NonNull WindowExtensions getWindowExtensions() {
         throw new UnsupportedOperationException("Stub, replace with implementation");
     }
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaPresentation.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaPresentation.java
index 0ce24b8..a24375b 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaPresentation.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaPresentation.java
@@ -18,27 +18,36 @@
 
 import android.content.Context;
 import android.view.View;
+import android.view.Window;
 
-import androidx.annotation.NonNull;
+import androidx.window.extensions.RequiresVendorApiLevel;
+
+import org.jspecify.annotations.NonNull;
 
 /**
  * An interface representing a container in an extension window area in which app content can be
  * shown.
  *
- * Since {@link androidx.window.extensions.WindowExtensions#VENDOR_API_LEVEL_3}
  * @see WindowAreaComponent#getRearDisplayPresentation()
  */
 public interface ExtensionWindowAreaPresentation {
 
     /**
-     * Returns the {@link Context} for the window that is being used
-     * to display the additional content provided from the application.
+     * Returns the {@link Context} for the window that is being used to display the additional
+     * content provided from the application.
      */
-    @NonNull
-    Context getPresentationContext();
+    @RequiresVendorApiLevel(level = 3)
+    @NonNull Context getPresentationContext();
 
-    /**
-     * Sets the {@link View} that the application wants to display in the extension window area.
-     */
+    /** Sets the {@link View} that the application wants to display in the extension window area. */
+    @RequiresVendorApiLevel(level = 3)
     void setPresentationView(@NonNull View view);
+
+    /** Returns the {@link Window} for the rear display presentation area. */
+    @RequiresVendorApiLevel(level = 4)
+    default @NonNull Window getWindow() {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaStatus.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaStatus.java
index 0dcd47f..67b5009 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaStatus.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaStatus.java
@@ -18,12 +18,13 @@
 
 import android.util.DisplayMetrics;
 
-import androidx.annotation.NonNull;
+import androidx.window.extensions.RequiresVendorApiLevel;
+
+import org.jspecify.annotations.NonNull;
 
 /**
  * Interface to provide information around the current status of a window area feature.
  *
- * Since {@link androidx.window.extensions.WindowExtensions#VENDOR_API_LEVEL_3}
  * @see WindowAreaComponent#addRearDisplayPresentationStatusListener
  */
 public interface ExtensionWindowAreaStatus {
@@ -32,6 +33,7 @@
      * Returns the {@link androidx.window.extensions.area.WindowAreaComponent.WindowAreaStatus}
      * value that relates to the current status of a feature.
      */
+    @RequiresVendorApiLevel(level = 3)
     @WindowAreaComponent.WindowAreaStatus
     int getWindowAreaStatus();
 
@@ -39,6 +41,6 @@
      * Returns the {@link DisplayMetrics} that corresponds to the window area that a feature
      * interacts with. This is converted to size class information provided to developers.
      */
-    @NonNull
-    DisplayMetrics getWindowAreaDisplayMetrics();
+    @RequiresVendorApiLevel(level = 3)
+    @NonNull DisplayMetrics getWindowAreaDisplayMetrics();
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/area/WindowAreaComponent.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/area/WindowAreaComponent.java
index e5705ac..8d77345 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/area/WindowAreaComponent.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/area/WindowAreaComponent.java
@@ -20,12 +20,14 @@
 import android.util.DisplayMetrics;
 
 import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
+import androidx.window.extensions.RequiresVendorApiLevel;
 import androidx.window.extensions.WindowExtensions;
 import androidx.window.extensions.core.util.function.Consumer;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -35,64 +37,45 @@
  * The interface definition that will be used by the WindowManager library to get custom
  * OEM-provided behavior around moving windows between displays or display areas on a device.
  *
- * Currently the only behavior supported is RearDisplay Mode, where the window
- * is moved to the display that faces the same direction as the rear camera.
+ * <p>Currently the only behavior supported is RearDisplay Mode, where the window is moved to the
+ * display that faces the same direction as the rear camera.
  *
  * <p>This interface should be implemented by OEM and deployed to the target devices.
+ *
  * @see WindowExtensions#getWindowLayoutComponent()
  */
 public interface WindowAreaComponent {
 
     /**
-     * WindowArea status constant to signify that the feature is
-     * unsupported on this device. Could be due to the device not supporting that
-     * specific feature.
-     *
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+     * WindowArea status constant to signify that the feature is unsupported on this device. Could
+     * be due to the device not supporting that specific feature.
      */
     int STATUS_UNSUPPORTED = 0;
 
     /**
-     * WindowArea status constant to signify that the feature is
-     * currently unavailable but is supported on this device. This value could signify
-     * that the current device state does not support the specific feature or another
-     * process is currently enabled in that feature.
-     *
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+     * WindowArea status constant to signify that the feature is currently unavailable but is
+     * supported on this device. This value could signify that the current device state does not
+     * support the specific feature or another process is currently enabled in that feature.
      */
     int STATUS_UNAVAILABLE = 1;
 
     /**
-     * WindowArea status constant to signify that the feature is
-     * available to be entered or enabled.
-     *
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+     * WindowArea status constant to signify that the feature is available to be entered or enabled.
      */
     int STATUS_AVAILABLE = 2;
 
-    /**
-     * WindowArea status constant to signify that the feature is
-     * already enabled.
-     *
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
-     */
+    /** WindowArea status constant to signify that the feature is already enabled. */
     int STATUS_ACTIVE = 3;
 
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     @Retention(RetentionPolicy.SOURCE)
     @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
-    @IntDef({
-            STATUS_UNSUPPORTED,
-            STATUS_UNAVAILABLE,
-            STATUS_AVAILABLE,
-            STATUS_ACTIVE
-    })
+    @IntDef({STATUS_UNSUPPORTED, STATUS_UNAVAILABLE, STATUS_AVAILABLE, STATUS_ACTIVE})
     @interface WindowAreaStatus {}
 
     /**
-     * Session state constant to represent there being no active session
-     * currently in progress. Used by the library to call the correct callbacks if
-     * a session is ended.
+     * Session state constant to represent there being no active session currently in progress. Used
+     * by the library to call the correct callbacks if a session is ended.
      */
     int SESSION_STATE_INACTIVE = 0;
 
@@ -105,173 +88,169 @@
     int SESSION_STATE_ACTIVE = 1;
 
     /**
-     * Session state constant to represent that there is an
-     * active presentation session currently in progress, and the content provided by the
-     * application is visible.
+     * Session state constant to represent that there is an active presentation session currently in
+     * progress, and the content provided by the application is visible.
      */
     int SESSION_STATE_CONTENT_VISIBLE = 2;
 
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     @Retention(RetentionPolicy.SOURCE)
     @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
-    @IntDef({
-            SESSION_STATE_ACTIVE,
-            SESSION_STATE_INACTIVE,
-            SESSION_STATE_CONTENT_VISIBLE
-    })
+    @IntDef({SESSION_STATE_ACTIVE, SESSION_STATE_INACTIVE, SESSION_STATE_CONTENT_VISIBLE})
     @interface WindowAreaSessionState {}
 
     /**
-     * Adds a listener interested in receiving updates on the RearDisplayStatus
-     * of the device. Because this is being called from the OEM provided
-     * extensions, the library will post the result of the listener on the executor
-     * provided by the developer.
+     * Adds a listener interested in receiving updates on the RearDisplayStatus of the device.
+     * Because this is being called from the OEM provided extensions, the library will post the
+     * result of the listener on the executor provided by the developer.
      *
-     * The listener provided will receive values that
-     * correspond to the [WindowAreaStatus] value that aligns with the current status
-     * of the rear display.
+     * <p>The listener provided will receive values that correspond to the [WindowAreaStatus] value
+     * that aligns with the current status of the rear display.
+     *
      * @param consumer interested in receiving updates to WindowAreaStatus.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
      */
+    @RequiresVendorApiLevel(level = 2)
     void addRearDisplayStatusListener(@NonNull Consumer<Integer> consumer);
 
     /**
      * Removes a listener no longer interested in receiving updates.
+     *
      * @param consumer no longer interested in receiving updates to WindowAreaStatus
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
      */
+    @RequiresVendorApiLevel(level = 2)
     void removeRearDisplayStatusListener(@NonNull Consumer<Integer> consumer);
 
     /**
-     * Creates and starts a rear display session and sends state updates to the
-     * consumer provided. This consumer will receive a constant represented by
-     * [WindowAreaSessionState] to represent the state of the current rear display
-     * session. We will translate to a more friendly interface in the library.
+     * Creates and starts a rear display session and sends state updates to the consumer provided.
+     * This consumer will receive a constant represented by [WindowAreaSessionState] to represent
+     * the state of the current rear display session. We will translate to a more friendly interface
+     * in the library.
      *
-     * Because this is being called from the OEM provided extensions, the library
-     * will post the result of the listener on the executor provided by the developer.
+     * <p>Because this is being called from the OEM provided extensions, the library will post the
+     * result of the listener on the executor provided by the developer.
      *
-     * @param activity to allow that the OEM implementation will use as a base
-     * context and to identify the source display area of the request.
-     * The reference to the activity instance must not be stored in the OEM
-     * implementation to prevent memory leaks.
+     * @param activity to allow that the OEM implementation will use as a base context and to
+     *     identify the source display area of the request. The reference to the activity instance
+     *     must not be stored in the OEM implementation to prevent memory leaks.
      * @param consumer to provide updates to the client on the status of the session
-     * @throws UnsupportedOperationException if this method is called when RearDisplay
-     * mode is not available. This could be to an incompatible device state or when
-     * another process is currently in this mode.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+     * @throws UnsupportedOperationException if this method is called when RearDisplay mode is not
+     *     available. This could be to an incompatible device state or when another process is
+     *     currently in this mode.
      */
+    @RequiresVendorApiLevel(level = 2)
     @SuppressWarnings("ExecutorRegistration") // Jetpack will post it on the app-provided executor.
-    void startRearDisplaySession(@NonNull Activity activity,
+    void startRearDisplaySession(
+            @NonNull Activity activity,
             @NonNull Consumer<@WindowAreaSessionState Integer> consumer);
 
+    // TODO(b/264546746): Remove deprecated Window Extensions APIs after apps in g3 is updated to
+    // the latest library.
     /**
-     * Ends a RearDisplaySession and sends [STATE_INACTIVE] to the consumer
-     * provided in the {@code startRearDisplaySession} method. This method is only
-     * called through the {@code RearDisplaySession} provided to the developer.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+     * Ends a RearDisplaySession and sends [STATE_INACTIVE] to the consumer provided in the {@code
+     * startRearDisplaySession} method. This method is only called through the {@code
+     * RearDisplaySession} provided to the developer.
      */
+    @RequiresVendorApiLevel(level = 2)
     void endRearDisplaySession();
 
     /**
-     * Adds a listener interested in receiving updates on the rear display presentation status
-     * of the device. Because this is being called from the OEM provided
-     * extensions, the library will post the result of the listener on the executor
-     * provided by the developer.
+     * Adds a listener interested in receiving updates on the rear display presentation status of
+     * the device. Because this is being called from the OEM provided extensions, the library will
+     * post the result of the listener on the executor provided by the developer.
      *
-     * The listener provided will receive {@link ExtensionWindowAreaStatus} values that
+     * <p>The listener provided will receive {@link ExtensionWindowAreaStatus} values that
      * correspond to the current status of the feature.
      *
      * @param consumer interested in receiving updates to {@link ExtensionWindowAreaStatus}.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
      */
+    @RequiresVendorApiLevel(level = 3)
     default void addRearDisplayPresentationStatusListener(
             @NonNull Consumer<ExtensionWindowAreaStatus> consumer) {
-        throw new UnsupportedOperationException("This method must not be called unless there is a"
-                + " corresponding override implementation on the device.");
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
     }
 
     /**
      * Removes a listener no longer interested in receiving updates.
      *
      * @param consumer no longer interested in receiving updates to WindowAreaStatus
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
      */
+    @RequiresVendorApiLevel(level = 3)
     default void removeRearDisplayPresentationStatusListener(
             @NonNull Consumer<ExtensionWindowAreaStatus> consumer) {
-        throw new UnsupportedOperationException("This method must not be called unless there is a"
-                + " corresponding override implementation on the device.");
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
     }
 
     /**
      * Creates and starts a rear display presentation session and sends state updates to the
-     * consumer provided. This consumer will receive a constant represented by
-     * {@link WindowAreaSessionState} to represent the state of the current rear display
-     * session. We will translate to a more friendly interface in the library.
+     * consumer provided. This consumer will receive a constant represented by {@link
+     * WindowAreaSessionState} to represent the state of the current rear display session. We will
+     * translate to a more friendly interface in the library.
      *
-     * Because this is being called from the OEM provided extensions, the library
-     * will post the result of the listener on the executor provided by the developer.
+     * <p>Because this is being called from the OEM provided extensions, the library will post the
+     * result of the listener on the executor provided by the developer.
      *
-     * Rear display presentation mode refers to a feature where an {@link Activity} can present
-     * additional content on a device with a second display that is facing the same direction
-     * as the rear camera (i.e. the cover display on a fold-in style device). The calling
-     * {@link Activity} stays on the user-facing display.
+     * <p>Rear display presentation mode refers to a feature where an {@link Activity} can present
+     * additional content on a device with a second display that is facing the same direction as the
+     * rear camera (i.e. the cover display on a fold-in style device). The calling {@link Activity}
+     * stays on the user-facing display.
      *
-     * @param activity that the OEM implementation will use as a base
-     * context and to identify the source display area of the request.
-     * The reference to the activity instance must not be stored in the OEM
-     * implementation to prevent memory leaks.
+     * @param activity that the OEM implementation will use as a base context and to identify the
+     *     source display area of the request. The reference to the activity instance must not be
+     *     stored in the OEM implementation to prevent memory leaks.
      * @param consumer to provide updates to the client on the status of the session
      * @throws UnsupportedOperationException if this method is called when rear display presentation
-     * mode is not available. This could be to an incompatible device state or when
-     * another process is currently in this mode.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+     *     mode is not available. This could be to an incompatible device state or when another
+     *     process is currently in this mode.
      */
-    default void startRearDisplayPresentationSession(@NonNull Activity activity,
+    @RequiresVendorApiLevel(level = 3)
+    default void startRearDisplayPresentationSession(
+            @NonNull Activity activity,
             @NonNull Consumer<@WindowAreaSessionState Integer> consumer) {
-        throw new UnsupportedOperationException("This method must not be called unless there is a"
-                + " corresponding override implementation on the device.");
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
     }
 
     /**
-     * Ends the current rear display presentation session and provides updates to the
-     * callback provided. When this is ended, the presented content from the calling
-     * {@link Activity} will also be removed from the rear facing display.
-     * Because this is being called from the OEM provided extensions, the result of the listener
-     * will be posted on the executor provided by the developer at the initial call site.
-     *
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+     * Ends the current rear display presentation session and provides updates to the callback
+     * provided. When this is ended, the presented content from the calling {@link Activity} will
+     * also be removed from the rear facing display. Because this is being called from the OEM
+     * provided extensions, the result of the listener will be posted on the executor provided by
+     * the developer at the initial call site.
      */
+    @RequiresVendorApiLevel(level = 3)
     default void endRearDisplayPresentationSession() {
-        throw new UnsupportedOperationException("This method must not be called unless there is a"
-                + " corresponding override implementation on the device.");
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
     }
 
     /**
-     * Returns the {@link ExtensionWindowAreaPresentation} connected to the active
-     * rear display presentation session. If there is no session currently active, then it will
-     * return null.
-     *
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+     * Returns the {@link ExtensionWindowAreaPresentation} connected to the active rear display
+     * presentation session. If there is no session currently active, then it will return null.
      */
-    @Nullable
-    default ExtensionWindowAreaPresentation getRearDisplayPresentation() {
-        throw new UnsupportedOperationException("This method must not be called unless there is a"
-                + " corresponding override implementation on the device.");
+    @RequiresVendorApiLevel(level = 3)
+    default @Nullable ExtensionWindowAreaPresentation getRearDisplayPresentation() {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
     }
 
     /**
      * Returns the {@link android.util.DisplayMetrics} associated with the rear facing display. If
-     * there is no rear facing display available on the device, returns an empty
-     * {@link android.util.DisplayMetrics} object.
-     *
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+     * there is no rear facing display available on the device, returns an empty {@link
+     * android.util.DisplayMetrics} object.
      */
+    @RequiresVendorApiLevel(level = 3)
     // TODO(b/273807238): Investigate how we can provide a listener to get runtime changes in
     //  rear display metrics to better support other form-factors in the future.
-    @NonNull
-    default DisplayMetrics getRearDisplayMetrics() {
-        throw new UnsupportedOperationException("This method must not be called unless there is a"
-                + " corresponding override implementation on the device.");
+    default @NonNull DisplayMetrics getRearDisplayMetrics() {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
     }
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingComponent.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingComponent.java
index 121520c..f3b36e7 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingComponent.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingComponent.java
@@ -21,101 +21,153 @@
 import android.os.IBinder;
 import android.view.WindowMetrics;
 
-import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.window.extensions.RequiresVendorApiLevel;
 import androidx.window.extensions.WindowExtensions;
 import androidx.window.extensions.core.util.function.Consumer;
 import androidx.window.extensions.core.util.function.Function;
+import androidx.window.extensions.util.SetCompat;
+
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
 
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Executor;
 
 /**
  * Extension component definition that is used by the WindowManager library to trigger custom
  * OEM-provided methods for organizing activities that isn't covered by platform APIs.
  *
  * <p>This interface should be implemented by OEM and deployed to the target devices.
+ *
  * @see androidx.window.extensions.WindowExtensions
  */
 public interface ActivityEmbeddingComponent {
 
-    /**
-     * Updates the rules of embedding activities that are started in the client process.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_1}
-     */
+    /** The vendor API level of the overlay feature APIs. */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    int OVERLAY_FEATURE_API_LEVEL = 8;
+
+    /** Updates the rules of embedding activities that are started in the client process. */
+    @RequiresVendorApiLevel(level = 1)
     void setEmbeddingRules(@NonNull Set<EmbeddingRule> splitRules);
 
     /**
-     * @deprecated Use {@link #setSplitInfoCallback(Consumer)} starting with
-     * {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if
-     * {@link #setSplitInfoCallback(Consumer)} can't be called on
-     * {@link WindowExtensions#VENDOR_API_LEVEL_1}.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_1}
+     * @deprecated Use {@link #setSplitInfoCallback(Consumer)} starting with vendor API level 2.
+     *     Only used if {@link #setSplitInfoCallback(Consumer)} can't be called on vendor level 1.
      */
+    @RequiresVendorApiLevel(level = 1, deprecatedSince = 2)
     @Deprecated
     @SuppressWarnings("ExecutorRegistration") // Jetpack will post it on the app-provided executor.
-    void setSplitInfoCallback(@NonNull java.util.function.Consumer<List<SplitInfo>> consumer);
+    void setSplitInfoCallback(java.util.function.@NonNull Consumer<List<SplitInfo>> consumer);
 
     /**
      * Sets the callback that notifies WM Jetpack about changes in split states from the Extensions
      * Sidecar implementation. The listener should be registered for the lifetime of the process.
-     * There are no threading guarantees where the events are dispatched from. All messages are
-     * re-posted to the executors provided by developers.
+     * There are no threading guarantees where the events are dispatched from.
      *
      * @param consumer the callback to notify {@link SplitInfo} list changes
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
      */
+    @RequiresVendorApiLevel(level = 2)
     @SuppressWarnings("ExecutorRegistration") // Jetpack will post it on the app-provided executor.
     default void setSplitInfoCallback(@NonNull Consumer<List<SplitInfo>> consumer) {
-        throw new UnsupportedOperationException("This method must not be called unless there is a"
-                + " corresponding override implementation on the device.");
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
     }
 
     /**
-     * Clears the callback that was set in
-     * {@link ActivityEmbeddingComponent#setSplitInfoCallback(Consumer)}.
-     * Added in {@link WindowExtensions#getVendorApiLevel()} 2, calling an earlier version will
-     * throw {@link java.lang.NoSuchMethodError}.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+     * Clears the callback that was set in {@link
+     * ActivityEmbeddingComponent#setSplitInfoCallback(Consumer)}. Added in {@link
+     * WindowExtensions#getVendorApiLevel()} 2, calling an earlier version will throw {@link
+     * java.lang.NoSuchMethodError}.
      */
+    @RequiresVendorApiLevel(level = 2)
     void clearSplitInfoCallback();
 
     /**
      * Checks if an activity's' presentation is customized by its or any other process and only
      * occupies a portion of Task bounds.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_1}
      */
+    @RequiresVendorApiLevel(level = 1)
     boolean isActivityEmbedded(@NonNull Activity activity);
 
     /**
+     * Pins the top-most {@link ActivityStack} to keep the stack of the Activities to be positioned
+     * on top. The rest of the activities in the Task will be split with the pinned {@link
+     * ActivityStack}. The pinned {@link ActivityStack} would also have isolated activity navigation
+     * in which only the activities that are started from the pinned {@link ActivityStack} can be
+     * added on top of the {@link ActivityStack}.
+     *
+     * <p>The pinned {@link ActivityStack} is unpinned whenever the parent Task bounds don't satisfy
+     * the dimensions and aspect ratio requirements {@link SplitRule#checkParentMetrics} to show two
+     * {@link ActivityStack}s. See {@link SplitPinRule.Builder#setSticky} if the same {@link
+     * ActivityStack} should be pinned again whenever the parent Task bounds satisfies the
+     * dimensions and aspect ratios requirements defined in the rule.
+     *
+     * @param taskId The id of the Task that top {@link ActivityStack} should be pinned.
+     * @param splitPinRule The SplitRule that specifies how the top {@link ActivityStack} should be
+     *     split with others.
+     * @return Returns {@code true} if the top {@link ActivityStack} is successfully pinned.
+     *     Otherwise, {@code false}. Few examples are: 1. There's no {@link ActivityStack}. 2. There
+     *     is already an existing pinned {@link ActivityStack}. 3. There's no other {@link
+     *     ActivityStack} to split with the top {@link ActivityStack}.
+     */
+    @RequiresVendorApiLevel(level = 5)
+    default boolean pinTopActivityStack(int taskId, @NonNull SplitPinRule splitPinRule) {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Unpins the pinned {@link ActivityStack}. The {@link ActivityStack} will still be the top-most
+     * {@link ActivityStack} right after unpinned, and the {@link ActivityStack} could be expanded
+     * or continue to be split with the next top {@link ActivityStack} if the current state matches
+     * any of the existing {@link SplitPairRule}. It is a no-op call if the task does not have a
+     * pinned {@link ActivityStack}.
+     *
+     * @param taskId The id of the Task that top {@link ActivityStack} should be unpinned.
+     */
+    @RequiresVendorApiLevel(level = 5)
+    default void unpinTopActivityStack(int taskId) {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
+
+    /**
      * Sets a function to compute the {@link SplitAttributes} for the {@link SplitRule} and current
      * window state provided in {@link SplitAttributesCalculatorParams}.
-     * <p>
-     * This method can be used to dynamically configure the split layout properties when new
+     *
+     * <p>This method can be used to dynamically configure the split layout properties when new
      * activities are launched or window properties change.
-     * <p>
-     * If the {@link SplitAttributes} calculator function is not set or is cleared by
-     * {@link #clearSplitAttributesCalculator()}, apps will update its split layout with
-     * registered {@link SplitRule} configurations:
+     *
+     * <p>If the {@link SplitAttributes} calculator function is not set or is cleared by {@link
+     * #clearSplitAttributesCalculator()}, apps will update its split layout with registered {@link
+     * SplitRule} configurations:
+     *
      * <ul>
-     *     <li>Split with {@link SplitRule#getDefaultSplitAttributes()} if parent task
-     *     container size constraints defined by
-     *     {@link SplitRule#checkParentMetrics(WindowMetrics)} are satisfied</li>
-     *     <li>Occupy the whole parent task bounds if the constraints are not satisfied. </li>
+     *   <li>Split with {@link SplitRule#getDefaultSplitAttributes()} if parent task container size
+     *       constraints defined by {@link SplitRule#checkParentMetrics(WindowMetrics)} are
+     *       satisfied
+     *   <li>Occupy the whole parent task bounds if the constraints are not satisfied.
      * </ul>
-     * <p>
-     * If the function is set, {@link SplitRule#getDefaultSplitAttributes()} and
-     * {@link SplitRule#checkParentMetrics(WindowMetrics)} will be passed to
-     * {@link SplitAttributesCalculatorParams} as
-     * {@link SplitAttributesCalculatorParams#getDefaultSplitAttributes()} and
-     * {@link SplitAttributesCalculatorParams#areDefaultConstraintsSatisfied()} instead, and the
-     * function will be invoked for every device and window state change regardless of the size
-     * constraints. Users can determine to follow the {@link SplitRule} behavior or customize
-     * the {@link SplitAttributes} with the {@link SplitAttributes} calculator function.
+     *
+     * <p>If the function is set, {@link SplitRule#getDefaultSplitAttributes()} and {@link
+     * SplitRule#checkParentMetrics(WindowMetrics)} will be passed to {@link
+     * SplitAttributesCalculatorParams} as {@link
+     * SplitAttributesCalculatorParams#getDefaultSplitAttributes()} and {@link
+     * SplitAttributesCalculatorParams#areDefaultConstraintsSatisfied()} instead, and the function
+     * will be invoked for every device and window state change regardless of the size constraints.
+     * Users can determine to follow the {@link SplitRule} behavior or customize the {@link
+     * SplitAttributes} with the {@link SplitAttributes} calculator function.
      *
      * @param calculator the callback to set. It will replace the previously set callback if it
-     *                  exists.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+     *     exists.
      */
+    @RequiresVendorApiLevel(level = 2)
     void setSplitAttributesCalculator(
             @NonNull Function<SplitAttributesCalculatorParams, SplitAttributes> calculator);
 
@@ -123,22 +175,31 @@
      * Clears the previously callback set in {@link #setSplitAttributesCalculator(Function)}.
      *
      * @see #setSplitAttributesCalculator(Function)
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
      */
+    @RequiresVendorApiLevel(level = 2)
     void clearSplitAttributesCalculator();
 
     /**
-     * Sets the launching {@link ActivityStack} to the given {@link ActivityOptions}.
-     *
-     * @param options The {@link ActivityOptions} to be updated.
-     * @param token The {@link ActivityStack#getToken()} to represent the {@link ActivityStack}
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+     * @deprecated Use {@link ActivityEmbeddingOptionsProperties#KEY_ACTIVITY_STACK_TOKEN} instead.
      */
-    @NonNull
-    default ActivityOptions setLaunchingActivityStack(@NonNull ActivityOptions options,
-            @NonNull IBinder token) {
-        throw new UnsupportedOperationException("This method must not be called unless there is a"
-                + " corresponding override implementation on the device.");
+    @Deprecated
+    @RequiresVendorApiLevel(level = 3, deprecatedSince = 5)
+    default @NonNull ActivityOptions setLaunchingActivityStack(
+            @NonNull ActivityOptions options, @NonNull IBinder token) {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * @deprecated Use {@link #finishActivityStacksWithTokens(Set)} with instead.
+     */
+    @Deprecated
+    @RequiresVendorApiLevel(level = 3, deprecatedSince = 5)
+    default void finishActivityStacks(@NonNull Set<IBinder> activityStackTokens) {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
     }
 
     /**
@@ -147,12 +208,18 @@
      * expanded to fill the parent task container.
      *
      * @param activityStackTokens The set of tokens of {@link ActivityStack}-s that is going to be
-     *                            finished.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+     *     finished.
      */
-    default void finishActivityStacks(@NonNull Set<IBinder> activityStackTokens) {
-        throw new UnsupportedOperationException("This method must not be called unless there is a"
-                + " corresponding override implementation on the device.");
+    @SuppressWarnings("deprecation") // Use finishActivityStacks(Set) as its core implementation.
+    @RequiresVendorApiLevel(level = 5)
+    default void finishActivityStacksWithTokens(
+            @NonNull Set<ActivityStack.Token> activityStackTokens) {
+        final Set<IBinder> binderSet = SetCompat.create();
+
+        for (ActivityStack.Token token : activityStackTokens) {
+            binderSet.add(token.getRawToken());
+        }
+        finishActivityStacks(binderSet);
     }
 
     /**
@@ -161,25 +228,254 @@
      * when a change to the split presentation originates from the application state change rather
      * than driven by parent window changes or new activity starts. The call will be ignored if
      * there is no visible split.
+     *
      * @see #setSplitAttributesCalculator(Function)
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
      */
+    @RequiresVendorApiLevel(level = 3)
     default void invalidateTopVisibleSplitAttributes() {
-        throw new UnsupportedOperationException("This method must not be called unless there is a"
-                + " corresponding override implementation on the device.");
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
     }
 
     /**
-     * Updates the {@link SplitAttributes} of a split pair. This is an alternative to using
-     * a split attributes calculator callback, applicable when apps only need to update the
-     * splits in a few cases but rely on the default split attributes otherwise.
+     * @deprecated Use {@link #updateSplitAttributes(SplitInfo.Token, SplitAttributes)} instead.
+     */
+    @Deprecated
+    @RequiresVendorApiLevel(level = 3, deprecatedSince = 5)
+    default void updateSplitAttributes(
+            @NonNull IBinder splitInfoToken, @NonNull SplitAttributes splitAttributes) {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Updates the {@link SplitAttributes} of a split pair. This is an alternative to using a split
+     * attributes calculator callback, applicable when apps only need to update the splits in a few
+     * cases but rely on the default split attributes otherwise.
+     *
      * @param splitInfoToken The identifier of the split pair to update.
      * @param splitAttributes The {@link SplitAttributes} to apply to the split pair.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
      */
-    default void updateSplitAttributes(@NonNull IBinder splitInfoToken,
-            @NonNull SplitAttributes splitAttributes) {
-        throw new UnsupportedOperationException("This method must not be called unless there is a"
-                + " corresponding override implementation on the device.");
+    @SuppressWarnings("deprecation") // Use finishActivityStacks(Set).
+    @RequiresVendorApiLevel(level = 5)
+    default void updateSplitAttributes(
+            SplitInfo.@NonNull Token splitInfoToken, @NonNull SplitAttributes splitAttributes) {
+        updateSplitAttributes(splitInfoToken.getRawToken(), splitAttributes);
+    }
+
+    /**
+     * Returns the {@link ParentContainerInfo} by the {@link ActivityStack} token, or {@code null}
+     * if there's not such {@link ActivityStack} associated with the {@code token}.
+     *
+     * @param activityStackToken the token of an {@link ActivityStack}.
+     */
+    @RequiresVendorApiLevel(level = OVERLAY_FEATURE_API_LEVEL)
+    default @Nullable ParentContainerInfo getParentContainerInfo(
+            ActivityStack.@NonNull Token activityStackToken) {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Sets a function to compute the {@link ActivityStackAttributes} for the ActivityStack given
+     * for the current window and device state provided in {@link
+     * ActivityStackAttributesCalculatorParams} on the main thread.
+     *
+     * <p>This calculator function is only triggered if the {@link ActivityStack#getTag()} is
+     * specified. Similar to {@link #setSplitAttributesCalculator(Function)}, the calculator
+     * function could be triggered multiple times. It will be triggered whenever there's a launching
+     * standalone {@link ActivityStack} with {@link ActivityStack#getTag()} specified, or a parent
+     * window or device state update, such as device rotation, folding state change, or the host
+     * task goes to multi-window mode.
+     *
+     * @param calculator The calculator function to calculate {@link ActivityStackAttributes} based
+     *     on {@link ActivityStackAttributesCalculatorParams}.
+     */
+    @RequiresVendorApiLevel(level = OVERLAY_FEATURE_API_LEVEL)
+    default void setActivityStackAttributesCalculator(
+            @NonNull Function<ActivityStackAttributesCalculatorParams, ActivityStackAttributes>
+                    calculator) {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Clears the calculator function previously set by {@link
+     * #setActivityStackAttributesCalculator(Function)}
+     */
+    @RequiresVendorApiLevel(level = OVERLAY_FEATURE_API_LEVEL)
+    default void clearActivityStackAttributesCalculator() {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Updates {@link ActivityStackAttributes} to an {@link ActivityStack} specified with {@code
+     * token} and applies the change directly. If there's no such an {@link ActivityStack}, this
+     * method is no-op.
+     *
+     * @param token The {@link ActivityStack} to update.
+     * @param activityStackAttributes The attributes to be applied
+     */
+    @RequiresVendorApiLevel(level = OVERLAY_FEATURE_API_LEVEL)
+    default void updateActivityStackAttributes(
+            ActivityStack.@NonNull Token token,
+            @NonNull ActivityStackAttributes activityStackAttributes) {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Gets the {@link ActivityStack}'s token by {@code tag}, or {@code null} if there's no {@link
+     * ActivityStack} associated with the {@code tag}. For example, the {@link ActivityStack} is
+     * dismissed before the is method is called.
+     *
+     * <p>The {@link ActivityStack} token can be obtained immediately after the {@link
+     * ActivityStack} is created. This method is usually used when Activity Embedding library wants
+     * to {@link #updateActivityStackAttributes} before receiving the {@link ActivityStack} record
+     * from the callback set by {@link #registerActivityStackCallback}.
+     *
+     * <p>For example, an app launches an overlay container and calls {@link
+     * #updateActivityStackAttributes} immediately right before the overlay {@link ActivityStack} is
+     * received from {@link #registerActivityStackCallback}.
+     *
+     * @param tag A unique identifier of an {@link ActivityStack} if set
+     * @return The {@link ActivityStack}'s token that the tag is associated with, or {@code null} if
+     *     there's no such an {@link ActivityStack}.
+     */
+    @RequiresVendorApiLevel(level = OVERLAY_FEATURE_API_LEVEL)
+    default ActivityStack.@Nullable Token getActivityStackToken(@NonNull String tag) {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Registers a callback that notifies WindowManager Jetpack about changes in {@link
+     * ActivityStack}.
+     *
+     * <p>In most cases, {@link ActivityStack} are a part of {@link SplitInfo} as {@link
+     * SplitInfo#getPrimaryActivityStack() the primary ActivityStack} or {@link
+     * SplitInfo#getSecondaryActivityStack() the secondary ActivityStack} of a {@link SplitInfo}.
+     *
+     * <p>However, there are some cases that {@link ActivityStack} is standalone and usually
+     * expanded. Cases are:
+     *
+     * <ul>
+     *   <li>A started {@link Activity} matches {@link ActivityRule} with {@link
+     *       ActivityRule#shouldAlwaysExpand()} {@code true}.
+     *   <li>The {@code ActivityStack} is an overlay {@code ActivityStack}.
+     *   <li>The associated {@link ActivityStack activityStacks} of a {@code ActivityStack} are
+     *       dismissed by {@link #finishActivityStacks(Set)}.
+     *   <li>One {@link ActivityStack} of {@link SplitInfo}(Either {@link
+     *       SplitInfo#getPrimaryActivityStack() the primary ActivityStack} or {@link
+     *       SplitInfo#getSecondaryActivityStack() the secondary ActivityStack}) is empty and
+     *       finished, while the other {@link ActivityStack} is not finished with the finishing
+     *       {@link ActivityStack}.
+     *       <p>An example is a pair of activities matches a {@link SplitPairRule}, and its {@link
+     *       SplitPairRule#getFinishPrimaryWithSecondary()} is {@link SplitRule#FINISH_NEVER}. Then
+     *       if the last activity of {@link SplitInfo#getSecondaryActivityStack() the secondary
+     *       ActivityStack}) is finished, {@link SplitInfo#getPrimaryActivityStack() the primary
+     *       ActivityStack} will still remain.
+     * </ul>
+     *
+     * @param executor the executor to dispatch {@link ActivityStack} list changes.
+     * @param callback the callback to notify {@link ActivityStack} list changes.
+     * @see ActivityEmbeddingComponent#finishActivityStacks(Set)
+     */
+    @RequiresVendorApiLevel(level = 5)
+    default void registerActivityStackCallback(
+            @NonNull Executor executor, @NonNull Consumer<List<ActivityStack>> callback) {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Removes the callback previously registered in {@link #registerActivityStackCallback}, or
+     * no-op if the callback hasn't been registered yet.
+     *
+     * @param callback The callback to remove, which should have been registered.
+     */
+    @RequiresVendorApiLevel(level = 5)
+    default void unregisterActivityStackCallback(@NonNull Consumer<List<ActivityStack>> callback) {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Sets a callback that notifies WindowManager Jetpack about changes for a given {@link
+     * Activity} to its {@link EmbeddedActivityWindowInfo}.
+     *
+     * <p>The callback will be invoked when the {@link EmbeddedActivityWindowInfo} is changed after
+     * the {@link Activity} is launched. Similar to {@link Activity#onConfigurationChanged}, the
+     * callback will only be invoked for visible {@link Activity}.
+     *
+     * @param executor the executor to dispatch {@link EmbeddedActivityWindowInfo} change.
+     * @param callback the callback to notify {@link EmbeddedActivityWindowInfo} change.
+     */
+    @RequiresVendorApiLevel(level = 6)
+    default void setEmbeddedActivityWindowInfoCallback(
+            @NonNull Executor executor, @NonNull Consumer<EmbeddedActivityWindowInfo> callback) {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Clears the callback previously set by {@link #setEmbeddedActivityWindowInfoCallback(Executor,
+     * Consumer)}
+     */
+    @RequiresVendorApiLevel(level = 6)
+    default void clearEmbeddedActivityWindowInfoCallback() {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Returns the {@link EmbeddedActivityWindowInfo} of the given {@link Activity}, or {@code null}
+     * if the {@link Activity} is not attached.
+     *
+     * <p>This API can be used when {@link #setEmbeddedActivityWindowInfoCallback} is not set before
+     * the Activity is attached.
+     *
+     * @param activity the {@link Activity} to get {@link EmbeddedActivityWindowInfo} for.
+     */
+    @RequiresVendorApiLevel(level = 6)
+    default @Nullable EmbeddedActivityWindowInfo getEmbeddedActivityWindowInfo(
+            @NonNull Activity activity) {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Sets whether to auto save the embedding state to the system, which can be used to restore the
+     * app embedding state once the app process is restarted (if applicable).
+     *
+     * <p>The embedding state is not saved by default, in which case the embedding state and the
+     * embedded activities are removed once the app process is killed.
+     *
+     * <p>**Note** that the applications should set the {@link EmbeddingRule}s using {@link
+     * #setEmbeddingRules} when the application is initializing, such as configured in
+     * [android.app.Application.onCreate], in order to allow the library to restore the state
+     * properly. Otherwise, the state may not be restored and the activities may not be started and
+     * layout as expected.
+     *
+     * @param saveEmbeddingState whether to save the embedding state.
+     */
+    @RequiresVendorApiLevel(level = 8)
+    default void setAutoSaveEmbeddingState(boolean saveEmbeddingState) {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
     }
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingOptionsProperties.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingOptionsProperties.java
new file mode 100644
index 0000000..888df2b
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingOptionsProperties.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2023 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 androidx.window.extensions.embedding;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+
+/**
+ * A class that contains activity embedding properties that puts to or retrieves from {@link
+ * android.app.ActivityOptions}.
+ */
+public class ActivityEmbeddingOptionsProperties {
+
+    private ActivityEmbeddingOptionsProperties() {}
+
+    /**
+     * The key of the unique identifier that put into {@link android.app.ActivityOptions}.
+     *
+     * <p>Type: {@link android.os.Bundle#putString(String, String) String}
+     *
+     * <p>An {@code OverlayCreateParams} property that represents the unique identifier of the
+     * overlay container.
+     */
+    public static final String KEY_OVERLAY_TAG = "androidx.window.extensions.embedding.OverlayTag";
+
+    /**
+     * The key of {@link ActivityStack.Token#toBundle()} that put into {@link
+     * android.app.ActivityOptions}.
+     *
+     * <p>Type: {@link Bundle#putBundle}
+     *
+     * <p>Apps can launch an activity into the {@link ActivityStack} that associated with {@code
+     * token} by {@link android.app.Activity#startActivity(Intent, Bundle)}.
+     *
+     * @see androidx.window.extensions.embedding.ActivityStack.Token#toBundle()
+     * @see androidx.window.extensions.embedding.ActivityStack.Token#createFromBinder(IBinder)
+     */
+    public static final String KEY_ACTIVITY_STACK_TOKEN =
+            "androidx.window.extensions.embedding.ActivityStackToken";
+}
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityRule.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityRule.java
index c741647..fd7d062 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityRule.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityRule.java
@@ -16,31 +16,30 @@
 
 package androidx.window.extensions.embedding;
 
-import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.content.Intent;
 import android.os.Build;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
+import androidx.window.extensions.RequiresVendorApiLevel;
 import androidx.window.extensions.WindowExtensions;
 import androidx.window.extensions.core.util.function.Predicate;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.util.Objects;
 
-/**
- * Split configuration rule for individual activities.
- */
+/** Split configuration rule for individual activities. */
 public class ActivityRule extends EmbeddingRule {
-    @NonNull
-    private final Predicate<Activity> mActivityPredicate;
-    @NonNull
-    private final Predicate<Intent> mIntentPredicate;
+    private final @NonNull Predicate<Activity> mActivityPredicate;
+    private final @NonNull Predicate<Intent> mIntentPredicate;
     private final boolean mShouldAlwaysExpand;
 
-    ActivityRule(@NonNull Predicate<Activity> activityPredicate,
-            @NonNull Predicate<Intent> intentPredicate, boolean shouldAlwaysExpand,
+    ActivityRule(
+            @NonNull Predicate<Activity> activityPredicate,
+            @NonNull Predicate<Intent> intentPredicate,
+            boolean shouldAlwaysExpand,
             @Nullable String tag) {
         super(tag);
         mActivityPredicate = activityPredicate;
@@ -48,19 +47,13 @@
         mShouldAlwaysExpand = shouldAlwaysExpand;
     }
 
-    /**
-     * Checks if the rule is applicable to the provided activity.
-     */
-    @SuppressLint("ClassVerificationFailure") // Only called by Extensions implementation on device.
+    /** Checks if the rule is applicable to the provided activity. */
     @RequiresApi(api = Build.VERSION_CODES.N)
     public boolean matchesActivity(@NonNull Activity activity) {
         return mActivityPredicate.test(activity);
     }
 
-    /**
-     * Checks if the rule is applicable to the provided activity intent.
-     */
-    @SuppressLint("ClassVerificationFailure") // Only called by Extensions implementation on device.
+    /** Checks if the rule is applicable to the provided activity intent. */
     @RequiresApi(api = Build.VERSION_CODES.N)
     public boolean matchesIntent(@NonNull Intent intent) {
         return mIntentPredicate.test(intent);
@@ -74,28 +67,23 @@
         return mShouldAlwaysExpand;
     }
 
-    /**
-     * Builder for {@link ActivityRule}.
-     */
+    /** Builder for {@link ActivityRule}. */
     public static final class Builder {
-        @NonNull
-        private final Predicate<Activity> mActivityPredicate;
-        @NonNull
-        private final Predicate<Intent> mIntentPredicate;
+        private final @NonNull Predicate<Activity> mActivityPredicate;
+        private final @NonNull Predicate<Intent> mIntentPredicate;
         private boolean mAlwaysExpand;
-        @Nullable
-        private String mTag;
+        private @Nullable String mTag;
 
         /**
-         * @deprecated Use {@link #Builder(Predicate, Predicate)} starting with
-         * {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if
-         * {@link #Builder(Predicate, Predicate)} can't be called on
-         * {@link WindowExtensions#VENDOR_API_LEVEL_1}.
+         * @deprecated Use {@link #Builder(Predicate, Predicate)} starting with {@link
+         *     WindowExtensions#VENDOR_API_LEVEL_2}. Only used if {@link #Builder(Predicate,
+         *     Predicate)} can't be called on {@link WindowExtensions#VENDOR_API_LEVEL_1}.
          */
         @Deprecated
         @RequiresApi(Build.VERSION_CODES.N)
-        public Builder(@NonNull java.util.function.Predicate<Activity> activityPredicate,
-                @NonNull java.util.function.Predicate<Intent> intentPredicate) {
+        public Builder(
+                java.util.function.@NonNull Predicate<Activity> activityPredicate,
+                java.util.function.@NonNull Predicate<Intent> intentPredicate) {
             mActivityPredicate = activityPredicate::test;
             mIntentPredicate = intentPredicate::test;
         }
@@ -104,37 +92,37 @@
          * The {@link ActivityRule} Builder constructor
          *
          * @param activityPredicate the {@link Predicate} to verify if a given {@link Activity}
-         *                         matches the rule
-         * @param intentPredicate the {@link Predicate} to verify if a given {@link Intent}
-         *                         matches the rule
-         * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+         *     matches the rule
+         * @param intentPredicate the {@link Predicate} to verify if a given {@link Intent} matches
+         *     the rule
          */
-        public Builder(@NonNull Predicate<Activity> activityPredicate,
+        @RequiresVendorApiLevel(level = 2)
+        public Builder(
+                @NonNull Predicate<Activity> activityPredicate,
                 @NonNull Predicate<Intent> intentPredicate) {
             mActivityPredicate = activityPredicate;
             mIntentPredicate = intentPredicate;
         }
 
-        /** @see ActivityRule#shouldAlwaysExpand() */
-        @NonNull
-        public Builder setShouldAlwaysExpand(boolean alwaysExpand) {
+        /**
+         * @see ActivityRule#shouldAlwaysExpand()
+         */
+        public @NonNull Builder setShouldAlwaysExpand(boolean alwaysExpand) {
             mAlwaysExpand = alwaysExpand;
             return this;
         }
 
         /**
          * @see ActivityRule#getTag()
-         * Since {@link androidx.window.extensions.WindowExtensions#VENDOR_API_LEVEL_2}
          */
-        @NonNull
-        public Builder setTag(@NonNull String tag) {
+        @RequiresVendorApiLevel(level = 2)
+        public @NonNull Builder setTag(@NonNull String tag) {
             mTag = Objects.requireNonNull(tag);
             return this;
         }
 
         /** Builds a new instance of {@link ActivityRule}. */
-        @NonNull
-        public ActivityRule build() {
+        public @NonNull ActivityRule build() {
             return new ActivityRule(mActivityPredicate, mIntentPredicate, mAlwaysExpand, mTag);
         }
     }
@@ -159,10 +147,12 @@
         return result;
     }
 
-    @NonNull
     @Override
-    public String toString() {
-        return "ActivityRule{mTag=" + getTag()
-                + "mShouldAlwaysExpand=" + mShouldAlwaysExpand + '}';
+    public @NonNull String toString() {
+        return "ActivityRule{mTag="
+                + getTag()
+                + ", mShouldAlwaysExpand="
+                + mShouldAlwaysExpand
+                + '}';
     }
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStack.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStack.java
index e568666..e21be7b 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStack.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStack.java
@@ -16,13 +16,17 @@
 
 package androidx.window.extensions.embedding;
 
+import static androidx.window.extensions.embedding.ActivityEmbeddingComponent.OVERLAY_FEATURE_API_LEVEL;
+
 import android.app.Activity;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.IBinder;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-import androidx.window.extensions.WindowExtensions;
+import androidx.window.extensions.RequiresVendorApiLevel;
+
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -34,81 +38,75 @@
  */
 public class ActivityStack {
 
-    /** Only used for compatibility with the deprecated constructor. */
-    private static final IBinder INVALID_ACTIVITY_STACK_TOKEN = new Binder();
-
-    @NonNull
-    private final List<Activity> mActivities;
+    private final @NonNull List<Activity> mActivities;
 
     private final boolean mIsEmpty;
 
-    @NonNull
-    private final IBinder mToken;
+    private final @NonNull Token mToken;
+
+    private final @Nullable String mTag;
 
     /**
      * The {@code ActivityStack} constructor
      *
-     * @param activities {@link Activity Activities} in this application's process that
-     *                   belongs to this {@code ActivityStack}
-     * @param isEmpty Indicates whether there's any {@link Activity} running in this
-     *                {@code ActivityStack}
+     * @param activities {@link Activity Activities} in this application's process that belongs to
+     *     this {@code ActivityStack}
+     * @param isEmpty Indicates whether there's any {@link Activity} running in this {@code
+     *     ActivityStack}
      * @param token The token to identify this {@code ActivityStack}
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+     * @param tag A unique identifier of {@link ActivityStack}. Only specifies for the overlay
+     *     standalone {@link ActivityStack} currently.
      */
-    ActivityStack(@NonNull List<Activity> activities, boolean isEmpty, @NonNull IBinder token) {
+    ActivityStack(
+            @NonNull List<Activity> activities,
+            boolean isEmpty,
+            @NonNull Token token,
+            @Nullable String tag) {
         Objects.requireNonNull(activities);
         Objects.requireNonNull(token);
+
         mActivities = new ArrayList<>(activities);
         mIsEmpty = isEmpty;
         mToken = token;
-    }
-
-    /**
-     * @deprecated Use the {@link WindowExtensions#VENDOR_API_LEVEL_3} version.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_1}
-     */
-    @Deprecated
-    ActivityStack(@NonNull List<Activity> activities, boolean isEmpty) {
-        this(activities, isEmpty, INVALID_ACTIVITY_STACK_TOKEN);
+        mTag = tag;
     }
 
     /**
      * Returns {@link Activity Activities} in this application's process that belongs to this
      * ActivityStack.
-     * <p>
-     * Note that Activities that are running in other processes are not reported in the returned
-     * Activity list. They can be in any position in terms of ordering relative to the activities
-     * in the list.
-     * </p>
+     *
+     * <p>Note that Activities that are running in other processes are not reported in the returned
+     * Activity list. They can be in any position in terms of ordering relative to the activities in
+     * the list.
      */
-    @NonNull
-    public List<Activity> getActivities() {
+    public @NonNull List<Activity> getActivities() {
         return new ArrayList<>(mActivities);
     }
 
     /**
      * Returns {@code true} if there's no {@link Activity} running in this ActivityStack.
-     * <p>
-     * Note that {@link #getActivities()} only report Activity in the process used to create this
+     *
+     * <p>Note that {@link #getActivities()} only report Activity in the process used to create this
      * ActivityStack. That said, if this ActivityStack only contains activities from another
      * process, {@link #getActivities()} will return empty list, while this method will return
      * {@code false}.
-     * </p>
      */
     public boolean isEmpty() {
         return mIsEmpty;
     }
 
-    /**
-     * Returns a token uniquely identifying the container.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    @NonNull
-    public IBinder getToken() {
+    /** Returns a token uniquely identifying the container. */
+    @RequiresVendorApiLevel(level = 5)
+    public @NonNull Token getActivityStackToken() {
         return mToken;
     }
 
+    /** Returns the associated tag if specified. Otherwise, returns {@code null}. */
+    @RequiresVendorApiLevel(level = OVERLAY_FEATURE_API_LEVEL)
+    public @Nullable String getTag() {
+        return mTag;
+    }
+
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
@@ -116,7 +114,8 @@
         ActivityStack that = (ActivityStack) o;
         return mActivities.equals(that.mActivities)
                 && mIsEmpty == that.mIsEmpty
-                && mToken.equals(that.mToken);
+                && mToken.equals(that.mToken)
+                && Objects.equals(mTag, that.mTag);
     }
 
     @Override
@@ -124,15 +123,99 @@
         int result = (mIsEmpty ? 1 : 0);
         result = result * 31 + mActivities.hashCode();
         result = result * 31 + mToken.hashCode();
+        result = result * 31 + Objects.hashCode(mTag);
+
         return result;
     }
 
-    @NonNull
     @Override
-    public String toString() {
-        return "ActivityStack{" + "mActivities=" + mActivities
-                + ", mIsEmpty=" + mIsEmpty
-                + ", mToken=" + mToken
+    public @NonNull String toString() {
+        return "ActivityStack{"
+                + "mActivities="
+                + mActivities
+                + ", mIsEmpty="
+                + mIsEmpty
+                + ", mToken="
+                + mToken
+                + ", mTag="
+                + mTag
                 + '}';
     }
+
+    /** A unique identifier to represent an {@link ActivityStack}. */
+    public static final class Token {
+
+        /** An invalid token to provide compatibility value before vendor API level 5. */
+        public static final @NonNull Token INVALID_ACTIVITY_STACK_TOKEN = new Token(new Binder());
+
+        private static final String KEY_ACTIVITY_STACK_RAW_TOKEN =
+                "androidx.window.extensions" + ".embedding.ActivityStack.Token";
+
+        private final IBinder mToken;
+
+        Token(@NonNull IBinder token) {
+            mToken = token;
+        }
+
+        /**
+         * Creates an {@link ActivityStack} token from binder.
+         *
+         * @param token the raw binder used by OEM Extensions implementation.
+         */
+        @RequiresVendorApiLevel(level = 5)
+        public static @NonNull Token createFromBinder(@NonNull IBinder token) {
+            return new Token(token);
+        }
+
+        /**
+         * Retrieves an {@link ActivityStack} token from {@link Bundle} if it's valid.
+         *
+         * @param bundle the {@link Bundle} to retrieve the {@link ActivityStack} token from.
+         * @throws IllegalArgumentException if the {@code bundle} isn't valid.
+         */
+        @RequiresVendorApiLevel(level = 5)
+        public static @NonNull Token readFromBundle(@NonNull Bundle bundle) {
+            final IBinder token = bundle.getBinder(KEY_ACTIVITY_STACK_RAW_TOKEN);
+
+            if (token == null) {
+                throw new IllegalArgumentException("Invalid bundle to create ActivityStack Token");
+            }
+            return new Token(token);
+        }
+
+        /**
+         * Converts the token to {@link Bundle}.
+         *
+         * <p>See {@link ActivityEmbeddingOptionsProperties#KEY_ACTIVITY_STACK_TOKEN} for sample
+         * usage.
+         */
+        @RequiresVendorApiLevel(level = 5)
+        public @NonNull Bundle toBundle() {
+            final Bundle bundle = new Bundle();
+            bundle.putBinder(KEY_ACTIVITY_STACK_RAW_TOKEN, mToken);
+            return bundle;
+        }
+
+        @NonNull IBinder getRawToken() {
+            return mToken;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof Token)) return false;
+            Token token = (Token) o;
+            return Objects.equals(mToken, token.mToken);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mToken);
+        }
+
+        @Override
+        public @NonNull String toString() {
+            return "Token{" + "mToken=" + mToken + '}';
+        }
+    }
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStackAttributes.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStackAttributes.java
new file mode 100644
index 0000000..0ea2bdc
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStackAttributes.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2023 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 androidx.window.extensions.embedding;
+
+import static androidx.window.extensions.embedding.WindowAttributes.DIM_AREA_ON_ACTIVITY_STACK;
+
+import android.graphics.Rect;
+
+import androidx.window.extensions.RequiresVendorApiLevel;
+
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
+/** Attributes used to update the layout and configuration of an {@link ActivityStack}. */
+public final class ActivityStackAttributes {
+
+    private final @NonNull Rect mRelativeBounds;
+
+    private final @NonNull WindowAttributes mWindowAttributes;
+
+    private ActivityStackAttributes(
+            @NonNull Rect relativeBounds, @NonNull WindowAttributes windowAttributes) {
+        mRelativeBounds = relativeBounds;
+        mWindowAttributes = windowAttributes;
+    }
+
+    /**
+     * Returns the requested bounds of an {@link ActivityStack} which relative to its parent
+     * container.
+     *
+     * <p>{@link Rect#isEmpty() Empty} bounds mean that this {@link ActivityStack} should fill its
+     * parent container bounds.
+     */
+    @RequiresVendorApiLevel(level = 6)
+    public @NonNull Rect getRelativeBounds() {
+        return mRelativeBounds;
+    }
+
+    /**
+     * Returns the {@link WindowAttributes} which contains the configurations of the embedded
+     * Activity windows with this attributes.
+     */
+    @RequiresVendorApiLevel(level = 6)
+    public @NonNull WindowAttributes getWindowAttributes() {
+        return mWindowAttributes;
+    }
+
+    @Override
+    public int hashCode() {
+        return mRelativeBounds.hashCode() * 31 + mWindowAttributes.hashCode();
+    }
+
+    @Override
+    public boolean equals(@Nullable Object obj) {
+        if (this == obj) return true;
+        if (!(obj instanceof ActivityStackAttributes)) return false;
+        final ActivityStackAttributes attrs = (ActivityStackAttributes) obj;
+        return mRelativeBounds.equals(attrs.mRelativeBounds)
+                && mWindowAttributes.equals(attrs.mWindowAttributes);
+    }
+
+    @Override
+    public @NonNull String toString() {
+        return ActivityStackAttributes.class.getSimpleName()
+                + ": {"
+                + " relativeBounds="
+                + mRelativeBounds
+                + ", windowAttributes="
+                + mWindowAttributes
+                + "}";
+    }
+
+    /** The builder class of {@link ActivityStackAttributes}. */
+    public static final class Builder {
+
+        /** The {@link ActivityStackAttributes} builder constructor. */
+        @RequiresVendorApiLevel(level = 6)
+        public Builder() {}
+
+        private final @NonNull Rect mRelativeBounds = new Rect();
+
+        private @NonNull WindowAttributes mWindowAttributes =
+                new WindowAttributes(DIM_AREA_ON_ACTIVITY_STACK);
+
+        /**
+         * Sets the requested relative bounds of the {@link ActivityStack}. If this value is not
+         * specified, {@link #getRelativeBounds()} defaults to {@link Rect#isEmpty() empty} bounds,
+         * which means to follow the parent container bounds.
+         *
+         * @param relativeBounds The requested relative bounds.
+         * @return This {@code Builder}.
+         */
+        @RequiresVendorApiLevel(level = 6)
+        public @NonNull Builder setRelativeBounds(@NonNull Rect relativeBounds) {
+            mRelativeBounds.set(relativeBounds);
+            return this;
+        }
+
+        /**
+         * Sets the window attributes. If this value is not specified, the {@link
+         * WindowAttributes#getDimAreaBehavior()} will be only applied on the {@link ActivityStack}
+         * of the requested activity.
+         *
+         * @param attributes The {@link WindowAttributes}
+         * @return This {@code Builder}.
+         */
+        @RequiresVendorApiLevel(level = 6)
+        public @NonNull Builder setWindowAttributes(@NonNull WindowAttributes attributes) {
+            mWindowAttributes = attributes;
+            return this;
+        }
+
+        /** Builds an {@link ActivityStackAttributes} instance. */
+        @RequiresVendorApiLevel(level = 6)
+        public @NonNull ActivityStackAttributes build() {
+            return new ActivityStackAttributes(mRelativeBounds, mWindowAttributes);
+        }
+    }
+}
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStackAttributesCalculatorParams.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStackAttributesCalculatorParams.java
new file mode 100644
index 0000000..538a9db
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStackAttributesCalculatorParams.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2023 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 androidx.window.extensions.embedding;
+
+import android.os.Bundle;
+
+import androidx.window.extensions.RequiresVendorApiLevel;
+import androidx.window.extensions.core.util.function.Function;
+
+import org.jspecify.annotations.NonNull;
+
+/**
+ * The parameter container used in standalone {@link ActivityStack} calculator function to report
+ * {@link ParentContainerInfo} and associated {@link ActivityStack#getTag()} to calculate {@link
+ * ActivityStackAttributes} when there's a parent container information update or a standalone
+ * {@link ActivityStack} is going to be launched.
+ *
+ * @see ActivityEmbeddingComponent#setActivityStackAttributesCalculator(Function)
+ */
+public class ActivityStackAttributesCalculatorParams {
+
+    private final @NonNull ParentContainerInfo mParentContainerInfo;
+
+    private final @NonNull String mActivityStackTag;
+
+    private final @NonNull Bundle mLaunchOptions;
+
+    /**
+     * {@code ActivityStackAttributesCalculatorParams} constructor.
+     *
+     * @param parentContainerInfo The {@link ParentContainerInfo} of the standalone {@link
+     *     ActivityStack} to apply the {@link ActivityStackAttributes}.
+     * @param activityStackTag The unique identifier of {@link ActivityStack} to apply the {@link
+     *     ActivityStackAttributes}.
+     * @param launchOptions The options to launch the {@link ActivityStack}.
+     */
+    ActivityStackAttributesCalculatorParams(
+            @NonNull ParentContainerInfo parentContainerInfo,
+            @NonNull String activityStackTag,
+            @NonNull Bundle launchOptions) {
+        mParentContainerInfo = parentContainerInfo;
+        mActivityStackTag = activityStackTag;
+        mLaunchOptions = launchOptions;
+    }
+
+    /** Returns {@link ParentContainerInfo} of the standalone {@link ActivityStack} to calculate. */
+    @RequiresVendorApiLevel(level = 6)
+    public @NonNull ParentContainerInfo getParentContainerInfo() {
+        return mParentContainerInfo;
+    }
+
+    /** Returns unique identifier of the standalone {@link ActivityStack} to calculate. */
+    @RequiresVendorApiLevel(level = 6)
+    public @NonNull String getActivityStackTag() {
+        return mActivityStackTag;
+    }
+
+    /**
+     * Returns options that passed from WM Jetpack to WM Extensions library to launch an {@link
+     * ActivityStack}. {@link Bundle#isEmpty() empty} options mean there's no launch options.
+     *
+     * <p>For example, an {@link ActivityStack} launch options could be an {@link
+     * android.app.ActivityOptions} bundle that contains information to build an overlay {@link
+     * ActivityStack}.
+     *
+     * <p>The launch options will be used for initializing standalone {@link ActivityStack} with
+     * {@link #getActivityStackTag()} specified. The logic is owned by WM Jetpack, which is usually
+     * from the {@link android.app.ActivityOptions}, WM Extensions library must not touch the
+     * options.
+     */
+    @RequiresVendorApiLevel(level = 6)
+    public @NonNull Bundle getLaunchOptions() {
+        return mLaunchOptions;
+    }
+
+    @Override
+    public @NonNull String toString() {
+        return ActivityStackAttributesCalculatorParams.class.getSimpleName()
+                + ":{"
+                + "parentContainerInfo="
+                + mParentContainerInfo
+                + "activityStackTag="
+                + mActivityStackTag
+                + "launchOptions="
+                + mLaunchOptions
+                + "}";
+    }
+}
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/AnimationBackground.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/AnimationBackground.java
new file mode 100644
index 0000000..7d6634e
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/AnimationBackground.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2023 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 androidx.window.extensions.embedding;
+
+import android.graphics.Color;
+
+import androidx.annotation.ColorInt;
+import androidx.window.extensions.RequiresVendorApiLevel;
+
+import org.jspecify.annotations.NonNull;
+
+import java.util.Objects;
+
+/**
+ * A class to represent the background to show while animating embedding activity containers if the
+ * animation requires a background.
+ *
+ * @see SplitAttributes.Builder#setAnimationBackground
+ */
+public abstract class AnimationBackground {
+
+    /**
+     * The special {@link AnimationBackground} object representing the default option. When used,
+     * the system will determine the color to use, such as using the current theme window background
+     * color.
+     */
+    @RequiresVendorApiLevel(level = 5)
+    public static final @NonNull AnimationBackground ANIMATION_BACKGROUND_DEFAULT =
+            new DefaultBackground();
+
+    /**
+     * Creates a {@link ColorBackground} that wraps the given color. Only opaque background is
+     * supported.
+     *
+     * @param color the color to be stored.
+     * @throws IllegalArgumentException if the color is not opaque.
+     */
+    @RequiresVendorApiLevel(level = 5)
+    public static @NonNull ColorBackground createColorBackground(@ColorInt int color) {
+        return new ColorBackground(color);
+    }
+
+    private AnimationBackground() {}
+
+    /**
+     * @see #ANIMATION_BACKGROUND_DEFAULT
+     */
+    private static class DefaultBackground extends AnimationBackground {
+        @Override
+        public String toString() {
+            return DefaultBackground.class.getSimpleName();
+        }
+    }
+
+    /**
+     * An {@link AnimationBackground} to specify of using a developer-defined color as the animation
+     * background. Only opaque background is supported.
+     *
+     * @see #createColorBackground(int)
+     */
+    @RequiresVendorApiLevel(level = 5)
+    public static class ColorBackground extends AnimationBackground {
+
+        @ColorInt private final int mColor;
+
+        private ColorBackground(@ColorInt int color) {
+            final int alpha = Color.alpha(color);
+            if (alpha != 255) {
+                throw new IllegalArgumentException(
+                        "Color must be fully opaque, current alpha is " + alpha);
+            }
+            mColor = color;
+        }
+
+        /** Returns the color to use as the animation background. */
+        @RequiresVendorApiLevel(level = 5)
+        @ColorInt
+        public int getColor() {
+            return mColor;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof ColorBackground)) return false;
+            final ColorBackground that = (ColorBackground) o;
+            return mColor == that.mColor;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mColor);
+        }
+
+        @Override
+        public @NonNull String toString() {
+            return ColorBackground.class.getSimpleName() + " { color: " + mColor + " }";
+        }
+    }
+}
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/AnimationParams.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/AnimationParams.java
new file mode 100644
index 0000000..730b84b
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/AnimationParams.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright 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 androidx.window.extensions.embedding;
+
+import android.content.res.Resources;
+
+import androidx.annotation.AnimRes;
+import androidx.window.extensions.RequiresVendorApiLevel;
+
+import org.jspecify.annotations.NonNull;
+
+import java.util.Objects;
+
+/**
+ * A class to represent the animation parameters to use while animating embedding activity
+ * containers.
+ *
+ * @see SplitAttributes.Builder#setAnimationParams
+ */
+public final class AnimationParams {
+
+    /**
+     * The default value for animation resources ID, which means to use the system default
+     * animation.
+     */
+    @RequiresVendorApiLevel(level = 7)
+    @SuppressWarnings("ResourceType") // Use as a hint to use the system default animation.
+    @AnimRes
+    public static final int DEFAULT_ANIMATION_RESOURCES_ID = 0xFFFFFFFF;
+
+    private final @NonNull AnimationBackground mAnimationBackground;
+
+    @AnimRes private final int mOpenAnimationResId;
+
+    @AnimRes private final int mCloseAnimationResId;
+
+    @AnimRes private final int mChangeAnimationResId;
+
+    /**
+     * Creates an instance of this {@code AnimationParams}.
+     *
+     * @param animationBackground The {@link AnimationBackground} to use for the animation involving
+     *     this {@code AnimationParams} object.
+     * @param openAnimationResId The animation resources ID from the "android" package to use for
+     *     open transitions.
+     * @param closeAnimationResId The animation resources ID from the "android" package to use for
+     *     close transitions.
+     * @param changeAnimationResId The animation resources ID from the "android" package to use for
+     *     change (resize or move) transitions.
+     */
+    private AnimationParams(
+            @NonNull AnimationBackground animationBackground,
+            @AnimRes int openAnimationResId,
+            @AnimRes int closeAnimationResId,
+            @AnimRes int changeAnimationResId) {
+        mAnimationBackground = animationBackground;
+        mOpenAnimationResId = openAnimationResId;
+        mCloseAnimationResId = closeAnimationResId;
+        mChangeAnimationResId = changeAnimationResId;
+    }
+
+    /** Returns the {@link AnimationBackground} to use for the background during the animation. */
+    @RequiresVendorApiLevel(level = 7)
+    public @NonNull AnimationBackground getAnimationBackground() {
+        return mAnimationBackground;
+    }
+
+    /**
+     * Gets the open animation.
+     *
+     * @return the open animation transition resources ID from the "android" package.
+     */
+    @RequiresVendorApiLevel(level = 7)
+    @AnimRes
+    public int getOpenAnimationResId() {
+        return mOpenAnimationResId;
+    }
+
+    /**
+     * Gets the close animation.
+     *
+     * @return the close animation transition resources ID from the "android" package.
+     */
+    @RequiresVendorApiLevel(level = 7)
+    @AnimRes
+    public int getCloseAnimationResId() {
+        return mCloseAnimationResId;
+    }
+
+    /**
+     * Gets the change (resize or move) animation.
+     *
+     * @return the change (resize or move) animation transition resources ID from the "android"
+     *     package.
+     */
+    @RequiresVendorApiLevel(level = 7)
+    @AnimRes
+    public int getChangeAnimationResId() {
+        return mChangeAnimationResId;
+    }
+
+    /**
+     * Builder for creating an instance of {@link AnimationParams}.
+     *
+     * <p>- The default animation background is to use the current theme window background color. -
+     * The default animation resources ID's for transitions is the system default.
+     */
+    public static final class Builder {
+        private @NonNull AnimationBackground mAnimationBackground =
+                AnimationBackground.ANIMATION_BACKGROUND_DEFAULT;
+
+        @AnimRes private int mOpenAnimationResId = DEFAULT_ANIMATION_RESOURCES_ID;
+
+        @AnimRes private int mCloseAnimationResId = DEFAULT_ANIMATION_RESOURCES_ID;
+
+        @AnimRes private int mChangeAnimationResId = DEFAULT_ANIMATION_RESOURCES_ID;
+
+        /** Creates a new {@link AnimationParams.Builder} to create {@link AnimationParams}. */
+        @RequiresVendorApiLevel(level = 7)
+        public Builder() {}
+
+        /**
+         * Sets the {@link AnimationBackground} to use for the background during the animation. The
+         * default value is {@link AnimationBackground#ANIMATION_BACKGROUND_DEFAULT}, which means to
+         * use the current theme window background color.
+         *
+         * @param background An {@link AnimationBackground} to be used for the animation.
+         * @return this {@code Builder}.
+         */
+        @RequiresVendorApiLevel(level = 7)
+        public AnimationParams.@NonNull Builder setAnimationBackground(
+                @NonNull AnimationBackground background) {
+            mAnimationBackground = background;
+            return this;
+        }
+
+        /**
+         * Sets the open animation. Use {@link #DEFAULT_ANIMATION_RESOURCES_ID} for the system
+         * default animation. Use {@code 0} or {@link Resources#ID_NULL} for no animation.
+         *
+         * @param resId The resources ID to set from the "android" package.
+         * @return this {@code Builder}.
+         */
+        @RequiresVendorApiLevel(level = 7)
+        public AnimationParams.@NonNull Builder setOpenAnimationResId(@AnimRes int resId) {
+            mOpenAnimationResId = resId;
+            return this;
+        }
+
+        /**
+         * Sets the close animation. Use {@link #DEFAULT_ANIMATION_RESOURCES_ID} for the system
+         * default animation. Use {@code 0} or {@link Resources#ID_NULL} for no animation.
+         *
+         * @param resId The resources ID to set from the "android" package.
+         * @return this {@code Builder}.
+         */
+        @RequiresVendorApiLevel(level = 7)
+        public AnimationParams.@NonNull Builder setCloseAnimationResId(@AnimRes int resId) {
+            mCloseAnimationResId = resId;
+            return this;
+        }
+
+        /**
+         * Sets the change (resize or move) animation. Use {@link #DEFAULT_ANIMATION_RESOURCES_ID}
+         * for the system default animation. Use {@code 0} or {@link Resources#ID_NULL} for no
+         * animation.
+         *
+         * @param resId The resources ID to set from the "android" package.
+         * @return this {@code Builder}.
+         */
+        @RequiresVendorApiLevel(level = 7)
+        public AnimationParams.@NonNull Builder setChangeAnimationResId(@AnimRes int resId) {
+            mChangeAnimationResId = resId;
+            return this;
+        }
+
+        /**
+         * Builds a {@link AnimationParams} instance with the attributes specified by {@link
+         * #setAnimationBackground(AnimationBackground)}, {@link #setOpenAnimationResId(int)},
+         * {@link #setCloseAnimationResId(int)}, and {@link #setChangeAnimationResId(int)}.
+         *
+         * @return the new {@code AnimationParams} instance.
+         */
+        @RequiresVendorApiLevel(level = 7)
+        public @NonNull AnimationParams build() {
+            return new AnimationParams(
+                    mAnimationBackground,
+                    mOpenAnimationResId,
+                    mCloseAnimationResId,
+                    mChangeAnimationResId);
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof AnimationParams)) return false;
+        AnimationParams that = (AnimationParams) o;
+        return mAnimationBackground.equals(that.mAnimationBackground)
+                && mOpenAnimationResId == that.mOpenAnimationResId
+                && mCloseAnimationResId == that.mCloseAnimationResId
+                && mChangeAnimationResId == that.mChangeAnimationResId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                mAnimationBackground,
+                mOpenAnimationResId,
+                mCloseAnimationResId,
+                mChangeAnimationResId);
+    }
+
+    @Override
+    public @NonNull String toString() {
+        return AnimationParams.class.getSimpleName()
+                + "{"
+                + "animationBackground="
+                + mAnimationBackground
+                + ", openAnimation="
+                + mOpenAnimationResId
+                + ", closeAnimation="
+                + mCloseAnimationResId
+                + ", changeAnimation="
+                + mChangeAnimationResId
+                + "}";
+    }
+}
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/DividerAttributes.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/DividerAttributes.java
new file mode 100644
index 0000000..91afa83
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/DividerAttributes.java
@@ -0,0 +1,530 @@
+/*
+ * Copyright 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 androidx.window.extensions.embedding;
+
+import android.graphics.Color;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.Dimension;
+import androidx.annotation.IntDef;
+import androidx.window.extensions.RequiresVendorApiLevel;
+
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * The attributes of the divider layout and behavior.
+ *
+ * @see SplitAttributes.Builder#setDividerAttributes(DividerAttributes)
+ */
+public final class DividerAttributes {
+
+    /** A divider type that draws a static line between the primary and secondary containers. */
+    public static final int DIVIDER_TYPE_FIXED = 1;
+
+    /**
+     * A divider type that draws a line between the primary and secondary containers with a drag
+     * handle that the user can drag and resize the containers.
+     */
+    public static final int DIVIDER_TYPE_DRAGGABLE = 2;
+
+    @IntDef({DIVIDER_TYPE_FIXED, DIVIDER_TYPE_DRAGGABLE})
+    @Retention(RetentionPolicy.SOURCE)
+    @interface DividerType {}
+
+    /**
+     * A special value to indicate that the ratio is unset. which means the system will choose a
+     * default value based on the display size and form factor.
+     *
+     * @see #getPrimaryMinRatio()
+     * @see #getPrimaryMaxRatio()
+     */
+    public static final float RATIO_SYSTEM_DEFAULT = -1.0f;
+
+    /**
+     * A special value to indicate that the width is unset. which means the system will choose a
+     * default value based on the display size and form factor.
+     *
+     * @see #getWidthDp()
+     */
+    public static final int WIDTH_SYSTEM_DEFAULT = -1;
+
+    /**
+     * The default value for the veil color. When used, the activity window background color will be
+     * used.
+     *
+     * @see #getPrimaryVeilColor()
+     * @see #getSecondaryVeilColor()
+     */
+    public static final int DIVIDER_VEIL_COLOR_DEFAULT = Color.TRANSPARENT;
+
+    /** The {@link DividerType}. */
+    private final @DividerType int mDividerType;
+
+    /**
+     * The divider width in dp. It defaults to {@link #WIDTH_SYSTEM_DEFAULT}, which means the system
+     * will choose a default value based on the display size and form factor.
+     */
+    private final @Dimension int mWidthDp;
+
+    /**
+     * The min split ratio for the primary container. It defaults to {@link #RATIO_SYSTEM_DEFAULT},
+     * the system will choose a default value based on the display size and form factor. Will only
+     * be used when the divider type is {@link #DIVIDER_TYPE_DRAGGABLE}.
+     *
+     * <p>If {@link #isDraggingToFullscreenAllowed()} is {@code true}, the user is allowed to drag
+     * beyond this ratio, and when dragging is finished, the system will choose to either fully
+     * expand the secondary container or move the divider back to this ratio.
+     *
+     * <p>If {@link #isDraggingToFullscreenAllowed()} is {@code false}, the user is not allowed to
+     * drag beyond this ratio.
+     *
+     * @see SplitAttributes.SplitType.RatioSplitType#getRatio()
+     */
+    private final float mPrimaryMinRatio;
+
+    /**
+     * The max split ratio for the primary container. It defaults to {@link #RATIO_SYSTEM_DEFAULT},
+     * the system will choose a default value based on the display size and form factor. Will only
+     * be used when the divider type is {@link #DIVIDER_TYPE_DRAGGABLE}.
+     *
+     * <p>If {@link #isDraggingToFullscreenAllowed()} is {@code true}, the user is allowed to drag
+     * beyond this ratio, and when dragging is finished, the system will choose to either fully
+     * expand the primary container or move the divider back to this ratio.
+     *
+     * <p>If {@link #isDraggingToFullscreenAllowed()} is {@code false}, the user is not allowed to
+     * drag beyond this ratio.
+     *
+     * @see SplitAttributes.SplitType.RatioSplitType#getRatio()
+     */
+    private final float mPrimaryMaxRatio;
+
+    /** The color of the divider. */
+    private final @ColorInt int mDividerColor;
+
+    /** Whether it is allowed to expand a container to full screen by dragging the divider. */
+    private final boolean mIsDraggingToFullscreenAllowed;
+
+    /** The veil color of the primary container while dragging. */
+    private final @ColorInt int mPrimaryVeilColor;
+
+    /** The veil color of the secondary container while dragging. */
+    private final @ColorInt int mSecondaryVeilColor;
+
+    /**
+     * Constructor of {@link DividerAttributes}.
+     *
+     * @param dividerType the divider type. See {@link DividerType}.
+     * @param widthDp the width of the divider.
+     * @param primaryMinRatio the min split ratio for the primary container.
+     * @param primaryMaxRatio the max split ratio for the primary container.
+     * @param dividerColor the color of the divider.
+     * @param isDraggingToFullscreenAllowed whether it is allowed to expand a container to full
+     *     screen by dragging the divider.
+     * @param primaryVeilColor the veil color of the primary container while dragging. If {@link
+     *     #DIVIDER_VEIL_COLOR_DEFAULT}, activity window background color is used.
+     * @param secondaryVeilColor the veil color of the secondary container while dragging. If {@link
+     *     #DIVIDER_VEIL_COLOR_DEFAULT}, activity window background color is used.
+     * @throws IllegalStateException if the provided values are invalid.
+     */
+    private DividerAttributes(
+            @DividerType int dividerType,
+            @Dimension int widthDp,
+            float primaryMinRatio,
+            float primaryMaxRatio,
+            @ColorInt int dividerColor,
+            boolean isDraggingToFullscreenAllowed,
+            @ColorInt int primaryVeilColor,
+            @ColorInt int secondaryVeilColor) {
+        if (dividerType == DIVIDER_TYPE_FIXED
+                && (primaryMinRatio != RATIO_SYSTEM_DEFAULT
+                        || primaryMaxRatio != RATIO_SYSTEM_DEFAULT)) {
+            throw new IllegalStateException(
+                    "primaryMinRatio and primaryMaxRatio must be RATIO_SYSTEM_DEFAULT for "
+                            + "DIVIDER_TYPE_FIXED.");
+        }
+        if (dividerType == DIVIDER_TYPE_FIXED
+                && (primaryVeilColor != DIVIDER_VEIL_COLOR_DEFAULT
+                        || secondaryVeilColor != DIVIDER_VEIL_COLOR_DEFAULT)) {
+            throw new IllegalStateException(
+                    "primaryVeilColor and secondaryVeilColor must be unset for"
+                            + "DIVIDER_TYPE_FIXED.");
+        }
+        if (primaryMinRatio != RATIO_SYSTEM_DEFAULT
+                && primaryMaxRatio != RATIO_SYSTEM_DEFAULT
+                && primaryMinRatio > primaryMaxRatio) {
+            throw new IllegalStateException(
+                    "primaryMinRatio must be less than or equal to primaryMaxRatio");
+        }
+        mDividerType = dividerType;
+        mWidthDp = widthDp;
+        mPrimaryMinRatio = primaryMinRatio;
+        mPrimaryMaxRatio = primaryMaxRatio;
+        mDividerColor = dividerColor;
+        mIsDraggingToFullscreenAllowed = isDraggingToFullscreenAllowed;
+        mPrimaryVeilColor = primaryVeilColor;
+        mSecondaryVeilColor = secondaryVeilColor;
+    }
+
+    /**
+     * Returns the divider type.
+     *
+     * @see #DIVIDER_TYPE_FIXED
+     * @see #DIVIDER_TYPE_DRAGGABLE
+     */
+    @RequiresVendorApiLevel(level = 6)
+    public @DividerType int getDividerType() {
+        return mDividerType;
+    }
+
+    /**
+     * Returns the width of the divider. It defaults to {@link #WIDTH_SYSTEM_DEFAULT}, which means
+     * the system will choose a default value based on the display size and form factor.
+     */
+    @RequiresVendorApiLevel(level = 6)
+    public @Dimension int getWidthDp() {
+        return mWidthDp;
+    }
+
+    /**
+     * Returns the min split ratio for the primary container the divider can be dragged to. It
+     * defaults to {@link #RATIO_SYSTEM_DEFAULT}, which means the system will choose a default value
+     * based on the display size and form factor. Will only be used when the divider type is {@link
+     * #DIVIDER_TYPE_DRAGGABLE}.
+     *
+     * <p>If {@link #isDraggingToFullscreenAllowed()} is {@code true}, the user is allowed to drag
+     * beyond this ratio, and when dragging is finished, the system will choose to either fully
+     * expand the secondary container or move the divider back to this ratio.
+     *
+     * <p>If {@link #isDraggingToFullscreenAllowed()} is {@code false}, the user is not allowed to
+     * drag beyond this ratio.
+     *
+     * @see SplitAttributes.SplitType.RatioSplitType#getRatio()
+     */
+    @RequiresVendorApiLevel(level = 6)
+    public float getPrimaryMinRatio() {
+        return mPrimaryMinRatio;
+    }
+
+    /**
+     * Returns the max split ratio for the primary container the divider can be dragged to. It
+     * defaults to {@link #RATIO_SYSTEM_DEFAULT}, which means the system will choose a default value
+     * based on the display size and form factor. Will only be used when the divider type is {@link
+     * #DIVIDER_TYPE_DRAGGABLE}.
+     *
+     * <p>If {@link #isDraggingToFullscreenAllowed()} is {@code true}, the user is allowed to drag
+     * beyond this ratio, and when dragging is finished, the system will choose to either fully
+     * expand the primary container or move the divider back to this ratio.
+     *
+     * <p>If {@link #isDraggingToFullscreenAllowed()} is {@code false}, the user is not allowed to
+     * drag beyond this ratio.
+     *
+     * @see SplitAttributes.SplitType.RatioSplitType#getRatio()
+     */
+    @RequiresVendorApiLevel(level = 6)
+    public float getPrimaryMaxRatio() {
+        return mPrimaryMaxRatio;
+    }
+
+    /** Returns the color of the divider. */
+    @RequiresVendorApiLevel(level = 6)
+    public @ColorInt int getDividerColor() {
+        return mDividerColor;
+    }
+
+    /**
+     * Returns whether it is allowed to expand a container to full screen by dragging the divider.
+     * Default is {@code true}.
+     */
+    @RequiresVendorApiLevel(level = 7)
+    public boolean isDraggingToFullscreenAllowed() {
+        return mIsDraggingToFullscreenAllowed;
+    }
+
+    /**
+     * Returns the veil color of the primary container. {@link #DIVIDER_VEIL_COLOR_DEFAULT}
+     * indicates that activity window background color should be used.
+     */
+    @RequiresVendorApiLevel(level = 8)
+    public @ColorInt int getPrimaryVeilColor() {
+        return mPrimaryVeilColor;
+    }
+
+    /**
+     * Returns the veil color of the secondary container. {@link #DIVIDER_VEIL_COLOR_DEFAULT}
+     * indicates that activity window background color should be used.
+     */
+    @RequiresVendorApiLevel(level = 8)
+    public @ColorInt int getSecondaryVeilColor() {
+        return mSecondaryVeilColor;
+    }
+
+    @Override
+    public boolean equals(@Nullable Object obj) {
+        if (this == obj) return true;
+        if (!(obj instanceof DividerAttributes)) return false;
+        final DividerAttributes other = (DividerAttributes) obj;
+        return mDividerType == other.mDividerType
+                && mWidthDp == other.mWidthDp
+                && mPrimaryMinRatio == other.mPrimaryMinRatio
+                && mPrimaryMaxRatio == other.mPrimaryMaxRatio
+                && mDividerColor == other.mDividerColor
+                && mIsDraggingToFullscreenAllowed == other.mIsDraggingToFullscreenAllowed
+                && mPrimaryVeilColor == other.mPrimaryVeilColor
+                && mSecondaryVeilColor == other.mSecondaryVeilColor;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(
+                mDividerType,
+                mWidthDp,
+                mPrimaryMinRatio,
+                mPrimaryMaxRatio,
+                mIsDraggingToFullscreenAllowed,
+                mPrimaryVeilColor,
+                mSecondaryVeilColor);
+    }
+
+    @Override
+    public @NonNull String toString() {
+        return DividerAttributes.class.getSimpleName()
+                + "{"
+                + "dividerType="
+                + mDividerType
+                + ", width="
+                + mWidthDp
+                + ", minPrimaryRatio="
+                + mPrimaryMinRatio
+                + ", maxPrimaryRatio="
+                + mPrimaryMaxRatio
+                + ", dividerColor="
+                + mDividerColor
+                + ", isDraggingToFullscreenAllowed="
+                + mIsDraggingToFullscreenAllowed
+                + ", mPrimaryVeilColor="
+                + mPrimaryVeilColor
+                + ", mSecondaryVeilColor="
+                + mSecondaryVeilColor
+                + "}";
+    }
+
+    /** The {@link DividerAttributes} builder. */
+    public static final class Builder {
+
+        private final @DividerType int mDividerType;
+
+        private @Dimension int mWidthDp = WIDTH_SYSTEM_DEFAULT;
+
+        private float mPrimaryMinRatio = RATIO_SYSTEM_DEFAULT;
+
+        private float mPrimaryMaxRatio = RATIO_SYSTEM_DEFAULT;
+
+        private @ColorInt int mDividerColor = Color.BLACK;
+
+        private boolean mIsDraggingToFullscreenAllowed = false;
+
+        private @ColorInt int mPrimaryVeilColor = DIVIDER_VEIL_COLOR_DEFAULT;
+
+        private @ColorInt int mSecondaryVeilColor = DIVIDER_VEIL_COLOR_DEFAULT;
+
+        /**
+         * The {@link DividerAttributes} builder constructor.
+         *
+         * @param dividerType the divider type, possible values are {@link #DIVIDER_TYPE_FIXED} and
+         *     {@link #DIVIDER_TYPE_DRAGGABLE}.
+         */
+        @RequiresVendorApiLevel(level = 6)
+        public Builder(@DividerType int dividerType) {
+            mDividerType = dividerType;
+        }
+
+        /**
+         * The {@link DividerAttributes} builder constructor initialized by an existing {@link
+         * DividerAttributes}.
+         *
+         * @param original the original {@link DividerAttributes} to initialize the {@link Builder}.
+         */
+        @RequiresVendorApiLevel(level = 6)
+        public Builder(@NonNull DividerAttributes original) {
+            Objects.requireNonNull(original);
+            mDividerType = original.mDividerType;
+            mWidthDp = original.mWidthDp;
+            mPrimaryMinRatio = original.mPrimaryMinRatio;
+            mPrimaryMaxRatio = original.mPrimaryMaxRatio;
+            mDividerColor = original.mDividerColor;
+            mIsDraggingToFullscreenAllowed = original.mIsDraggingToFullscreenAllowed;
+            mPrimaryVeilColor = original.mPrimaryVeilColor;
+            mSecondaryVeilColor = original.mSecondaryVeilColor;
+        }
+
+        /**
+         * Sets the divider width. It defaults to {@link #WIDTH_SYSTEM_DEFAULT}, which means the
+         * system will choose a default value based on the display size and form factor.
+         *
+         * @throws IllegalArgumentException if the provided value is invalid.
+         */
+        @RequiresVendorApiLevel(level = 6)
+        public @NonNull Builder setWidthDp(@Dimension int widthDp) {
+            if (widthDp != WIDTH_SYSTEM_DEFAULT && widthDp < 0) {
+                throw new IllegalArgumentException(
+                        "widthDp must be greater than or equal to 0 or WIDTH_SYSTEM_DEFAULT.");
+            }
+            mWidthDp = widthDp;
+            return this;
+        }
+
+        /**
+         * Sets the min split ratio for the primary container. It defaults to {@link
+         * #RATIO_SYSTEM_DEFAULT}, which means the system will choose a default value based on the
+         * display size and form factor. Will only be used when the divider type is {@link
+         * #DIVIDER_TYPE_DRAGGABLE}.
+         *
+         * <p>If {@link #isDraggingToFullscreenAllowed()} is {@code true}, the user is allowed to
+         * drag beyond this ratio, and when dragging is finished, the system will choose to either
+         * fully expand the secondary container or move the divider back to this ratio.
+         *
+         * <p>If {@link #isDraggingToFullscreenAllowed()} is {@code false}, the user is not allowed
+         * to drag beyond this ratio.
+         *
+         * @param primaryMinRatio the min ratio for the primary container. Must be in range [0.0,
+         *     1.0) or {@link #RATIO_SYSTEM_DEFAULT}.
+         * @throws IllegalArgumentException if the provided value is invalid.
+         * @see SplitAttributes.SplitType.RatioSplitType#getRatio()
+         */
+        @RequiresVendorApiLevel(level = 6)
+        public @NonNull Builder setPrimaryMinRatio(float primaryMinRatio) {
+            if (primaryMinRatio != RATIO_SYSTEM_DEFAULT
+                    && (primaryMinRatio >= 1.0 || primaryMinRatio < 0.0)) {
+                throw new IllegalArgumentException(
+                        "primaryMinRatio must be in [0.0, 1.0) or RATIO_SYSTEM_DEFAULT.");
+            }
+            mPrimaryMinRatio = primaryMinRatio;
+            return this;
+        }
+
+        /**
+         * Sets the max split ratio for the primary container. It defaults to {@link
+         * #RATIO_SYSTEM_DEFAULT}, which means the system will choose a default value based on the
+         * display size and form factor. Will only be used when the divider type is {@link
+         * #DIVIDER_TYPE_DRAGGABLE}.
+         *
+         * <p>If {@link #isDraggingToFullscreenAllowed()} is {@code true}, the user is allowed to
+         * drag beyond this ratio, and when dragging is finished, the system will choose to either
+         * fully expand the primary container or move the divider back to this ratio.
+         *
+         * <p>If {@link #isDraggingToFullscreenAllowed()} is {@code false}, the user is not allowed
+         * to drag beyond this ratio.
+         *
+         * @param primaryMaxRatio the max ratio for the primary container. Must be in range (0.0,
+         *     1.0] or {@link #RATIO_SYSTEM_DEFAULT}.
+         * @throws IllegalArgumentException if the provided value is invalid.
+         * @see SplitAttributes.SplitType.RatioSplitType#getRatio()
+         */
+        @RequiresVendorApiLevel(level = 6)
+        public @NonNull Builder setPrimaryMaxRatio(float primaryMaxRatio) {
+            if (primaryMaxRatio != RATIO_SYSTEM_DEFAULT
+                    && (primaryMaxRatio > 1.0 || primaryMaxRatio <= 0.0)) {
+                throw new IllegalArgumentException(
+                        "primaryMaxRatio must be in (0.0, 1.0] or RATIO_SYSTEM_DEFAULT.");
+            }
+            mPrimaryMaxRatio = primaryMaxRatio;
+            return this;
+        }
+
+        /**
+         * Sets the color of the divider. If not set, the default color {@link Color#BLACK} is used.
+         * Only the RGB components are used and the alpha value is ignored and always considered as
+         * fully opaque.
+         */
+        @RequiresVendorApiLevel(level = 6)
+        public @NonNull Builder setDividerColor(@ColorInt int dividerColor) {
+            mDividerColor = dividerColor;
+            return this;
+        }
+
+        /**
+         * Sets whether it is allowed to expand a container to full screen by dragging the divider.
+         * Default is {@code true}.
+         */
+        @RequiresVendorApiLevel(level = 7)
+        public @NonNull Builder setDraggingToFullscreenAllowed(
+                boolean isDraggingToFullscreenAllowed) {
+            mIsDraggingToFullscreenAllowed = isDraggingToFullscreenAllowed;
+            return this;
+        }
+
+        /**
+         * Sets the veil color of the primary container. Solid color veils are used to cover
+         * activity content while dragging.
+         *
+         * <p>The default value is {@link #DIVIDER_VEIL_COLOR_DEFAULT}.
+         *
+         * @param color the veil color for the primary container. If the value equals to {@link
+         *     #DIVIDER_VEIL_COLOR_DEFAULT}, activity window background color is used. If {@link
+         *     Color#TRANSPARENT} is used, it is treated as {@link #DIVIDER_VEIL_COLOR_DEFAULT}.
+         *     Only the RGB components are used and the alpha value is ignored and always considered
+         *     as fully opaque.
+         */
+        @RequiresVendorApiLevel(level = 8)
+        public @NonNull Builder setPrimaryVeilColor(@ColorInt int color) {
+            mPrimaryVeilColor = color;
+            return this;
+        }
+
+        /**
+         * Sets the veil color of the secondary container. Solid color veils are used to cover
+         * activity content while dragging.
+         *
+         * <p>The default value is {@link #DIVIDER_VEIL_COLOR_DEFAULT}.
+         *
+         * @param color the veil color for the secondary container. If the value equals to {@link
+         *     #DIVIDER_VEIL_COLOR_DEFAULT}, activity window background color is used. If {@link
+         *     Color#TRANSPARENT} is used, it is treated as {@link #DIVIDER_VEIL_COLOR_DEFAULT}.
+         *     Only the RGB components are used and the alpha value is ignored and always considered
+         *     as fully opaque.
+         */
+        @RequiresVendorApiLevel(level = 8)
+        public @NonNull Builder setSecondaryVeilColor(@ColorInt int color) {
+            mSecondaryVeilColor = color;
+            return this;
+        }
+
+        /**
+         * Builds a {@link DividerAttributes} instance.
+         *
+         * @return a {@link DividerAttributes} instance.
+         * @throws IllegalArgumentException if the provided values are invalid.
+         */
+        @RequiresVendorApiLevel(level = 6)
+        public @NonNull DividerAttributes build() {
+            return new DividerAttributes(
+                    mDividerType,
+                    mWidthDp,
+                    mPrimaryMinRatio,
+                    mPrimaryMaxRatio,
+                    mDividerColor,
+                    mIsDraggingToFullscreenAllowed,
+                    mPrimaryVeilColor,
+                    mSecondaryVeilColor);
+        }
+    }
+}
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/EmbeddedActivityWindowInfo.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/EmbeddedActivityWindowInfo.java
new file mode 100644
index 0000000..12b8bb1
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/EmbeddedActivityWindowInfo.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2023 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 androidx.window.extensions.embedding;
+
+import android.app.Activity;
+import android.graphics.Rect;
+
+import androidx.window.extensions.RequiresVendorApiLevel;
+
+import org.jspecify.annotations.NonNull;
+
+import java.util.Objects;
+
+/**
+ * Describes the embedded window related info of an activity.
+ *
+ * @see ActivityEmbeddingComponent#setEmbeddedActivityWindowInfoCallback
+ * @see ActivityEmbeddingComponent#getEmbeddedActivityWindowInfo
+ */
+public class EmbeddedActivityWindowInfo {
+
+    private final @NonNull Activity mActivity;
+    private final boolean mIsEmbedded;
+    private final @NonNull Rect mTaskBounds;
+    private final @NonNull Rect mActivityStackBounds;
+
+    EmbeddedActivityWindowInfo(
+            @NonNull Activity activity,
+            boolean isEmbedded,
+            @NonNull Rect taskBounds,
+            @NonNull Rect activityStackBounds) {
+        mActivity = Objects.requireNonNull(activity);
+        mIsEmbedded = isEmbedded;
+        mTaskBounds = Objects.requireNonNull(taskBounds);
+        mActivityStackBounds = Objects.requireNonNull(activityStackBounds);
+    }
+
+    /** Returns the {@link Activity} this {@link EmbeddedActivityWindowInfo} is about. */
+    @RequiresVendorApiLevel(level = 6)
+    public @NonNull Activity getActivity() {
+        return mActivity;
+    }
+
+    /**
+     * Whether this activity is embedded, which means it is in an ActivityStack window that doesn't
+     * fill the Task.
+     */
+    @RequiresVendorApiLevel(level = 6)
+    public boolean isEmbedded() {
+        return mIsEmbedded;
+    }
+
+    /** Returns the bounds of the Task window in display space. */
+    @RequiresVendorApiLevel(level = 6)
+    public @NonNull Rect getTaskBounds() {
+        return mTaskBounds;
+    }
+
+    /**
+     * Returns the bounds of the ActivityStack window in display space. This can be referring to the
+     * bounds of the same window as {@link #getTaskBounds()} when the activity is not embedded.
+     */
+    @RequiresVendorApiLevel(level = 6)
+    public @NonNull Rect getActivityStackBounds() {
+        return mActivityStackBounds;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof EmbeddedActivityWindowInfo)) return false;
+        final EmbeddedActivityWindowInfo that = (EmbeddedActivityWindowInfo) o;
+        return mActivity.equals(that.mActivity)
+                && mIsEmbedded == that.mIsEmbedded
+                && mTaskBounds.equals(that.mTaskBounds)
+                && mActivityStackBounds.equals(that.mActivityStackBounds);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mActivity.hashCode();
+        result = result * 31 + (mIsEmbedded ? 1 : 0);
+        result = result * 31 + mTaskBounds.hashCode();
+        result = result * 31 + mActivityStackBounds.hashCode();
+        return result;
+    }
+
+    @Override
+    public @NonNull String toString() {
+        return "EmbeddedActivityWindowInfo{"
+                + "activity="
+                + mActivity
+                + ", isEmbedded="
+                + mIsEmbedded
+                + ", taskBounds="
+                + mTaskBounds
+                + ", activityStackBounds="
+                + mActivityStackBounds
+                + "}";
+    }
+}
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/EmbeddingRule.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/EmbeddingRule.java
index 9333bdc..ff379fe 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/EmbeddingRule.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/EmbeddingRule.java
@@ -16,9 +16,11 @@
 
 package androidx.window.extensions.embedding;
 
-import androidx.annotation.Nullable;
+import androidx.window.extensions.RequiresVendorApiLevel;
 import androidx.window.extensions.core.util.function.Function;
 
+import org.jspecify.annotations.Nullable;
+
 import java.util.Objects;
 
 /**
@@ -26,25 +28,21 @@
  * updating from the core library.
  */
 public abstract class EmbeddingRule {
-    @Nullable
-    private final String mTag;
+    private final @Nullable String mTag;
 
     EmbeddingRule(@Nullable String tag) {
         mTag = tag;
     }
 
     /**
-     * A unique string to identify this {@link EmbeddingRule}.
-     * The suggested usage is to set the tag in the corresponding rule builder to be able to
-     * differentiate between different rules in {@link SplitAttributes} calculator function. For
-     * example, it can be used to compute the {@link SplitAttributes} for the specific
-     * {@link SplitRule} in the {@link Function} set with
+     * A unique string to identify this {@link EmbeddingRule}. The suggested usage is to set the tag
+     * in the corresponding rule builder to be able to differentiate between different rules in
+     * {@link SplitAttributes} calculator function. For example, it can be used to compute the
+     * {@link SplitAttributes} for the specific {@link SplitRule} in the {@link Function} set with
      * {@link ActivityEmbeddingComponent#setSplitAttributesCalculator(Function)}.
-     *
-     * Since {@link androidx.window.extensions.WindowExtensions#VENDOR_API_LEVEL_2}
      */
-    @Nullable
-    public String getTag() {
+    @RequiresVendorApiLevel(level = 2)
+    public @Nullable String getTag() {
         return mTag;
     }
 
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ParentContainerInfo.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ParentContainerInfo.java
new file mode 100644
index 0000000..1e4f686
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ParentContainerInfo.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2023 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 androidx.window.extensions.embedding;
+
+import android.content.res.Configuration;
+import android.view.WindowMetrics;
+
+import androidx.window.extensions.RequiresVendorApiLevel;
+import androidx.window.extensions.layout.WindowLayoutInfo;
+
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * The parent container information of an {@link ActivityStack}. The data class is designed to
+ * provide information to calculate the presentation of an {@link ActivityStack}.
+ */
+@RequiresVendorApiLevel(level = 6)
+public class ParentContainerInfo {
+    private final @NonNull WindowMetrics mWindowMetrics;
+
+    private final @NonNull Configuration mConfiguration;
+
+    private final @NonNull WindowLayoutInfo mWindowLayoutInfo;
+
+    /**
+     * {@link ParentContainerInfo} constructor, which is used in Window Manager Extensions to
+     * provide information of a parent window container.
+     *
+     * @param windowMetrics The parent container's {@link WindowMetrics}
+     * @param configuration The parent container's {@link Configuration}
+     * @param windowLayoutInfo The parent container's {@link WindowLayoutInfo}
+     */
+    ParentContainerInfo(
+            @NonNull WindowMetrics windowMetrics,
+            @NonNull Configuration configuration,
+            @NonNull WindowLayoutInfo windowLayoutInfo) {
+        mWindowMetrics = windowMetrics;
+        mConfiguration = configuration;
+        mWindowLayoutInfo = windowLayoutInfo;
+    }
+
+    /** Returns the parent container's {@link WindowMetrics}. */
+    @RequiresVendorApiLevel(level = 6)
+    public @NonNull WindowMetrics getWindowMetrics() {
+        return mWindowMetrics;
+    }
+
+    /** Returns the parent container's {@link Configuration}. */
+    @RequiresVendorApiLevel(level = 6)
+    public @NonNull Configuration getConfiguration() {
+        return mConfiguration;
+    }
+
+    /** Returns the parent container's {@link WindowLayoutInfo}. */
+    @RequiresVendorApiLevel(level = 6)
+    public @NonNull WindowLayoutInfo getWindowLayoutInfo() {
+        return mWindowLayoutInfo;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mWindowMetrics.hashCode();
+        result = 31 * result + mConfiguration.hashCode();
+        result = 31 * result + mWindowLayoutInfo.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(@Nullable Object obj) {
+        if (this == obj) return true;
+        if (!(obj instanceof ParentContainerInfo)) return false;
+        final ParentContainerInfo parentContainerInfo = (ParentContainerInfo) obj;
+        return mWindowMetrics.equals(parentContainerInfo.mWindowMetrics)
+                && mConfiguration.equals(parentContainerInfo.mConfiguration)
+                && mWindowLayoutInfo.equals(parentContainerInfo.mWindowLayoutInfo);
+    }
+
+    @Override
+    public @NonNull String toString() {
+        return ParentContainerInfo.class.getSimpleName()
+                + ": {"
+                + "windowMetrics="
+                + WindowMetricsCompat.toString(mWindowMetrics)
+                + ", configuration="
+                + mConfiguration
+                + ", windowLayoutInfo="
+                + mWindowLayoutInfo
+                + "}";
+    }
+}
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributes.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributes.java
index e00e910..708f37a 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributes.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributes.java
@@ -16,80 +16,64 @@
 
 package androidx.window.extensions.embedding;
 
-import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 import static androidx.window.extensions.embedding.SplitAttributes.LayoutDirection.BOTTOM_TO_TOP;
 import static androidx.window.extensions.embedding.SplitAttributes.LayoutDirection.LEFT_TO_RIGHT;
 import static androidx.window.extensions.embedding.SplitAttributes.LayoutDirection.LOCALE;
 import static androidx.window.extensions.embedding.SplitAttributes.LayoutDirection.RIGHT_TO_LEFT;
 import static androidx.window.extensions.embedding.SplitAttributes.LayoutDirection.TOP_TO_BOTTOM;
+import static androidx.window.extensions.embedding.WindowAttributes.DIM_AREA_ON_TASK;
 
 import android.annotation.SuppressLint;
-import android.graphics.Color;
 
-import androidx.annotation.ColorInt;
 import androidx.annotation.FloatRange;
 import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
+import androidx.window.extensions.RequiresVendorApiLevel;
 import androidx.window.extensions.core.util.function.Function;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
 
 /**
- * Attributes that describe how the parent window (typically the activity task
- * window) is split between the primary and secondary activity containers,
- * including:
+ * Attributes that describe how the parent window (typically the activity task window) is split
+ * between the primary and secondary activity containers, including:
+ *
  * <ul>
- *     <li>Split type -- Categorizes the split and specifies the sizes of the
- *         primary and secondary activity containers relative to the parent
- *         bounds</li>
- *     <li>Layout direction -- Specifies whether the parent window is split
- *         vertically or horizontally and in which direction the primary and
- *         secondary containers are respectively positioned (left to right,
- *         right to left, top to bottom, and so forth)</li>
- *     <li>Animation background color -- The color of the background during
- *         animation of the split involving this {@code SplitAttributes} object
- *         if the animation requires a background</li>
+ *   <li>Split type -- Categorizes the split and specifies the sizes of the primary and secondary
+ *       activity containers relative to the parent bounds
+ *   <li>Layout direction -- Specifies whether the parent window is split vertically or horizontally
+ *       and in which direction the primary and secondary containers are respectively positioned
+ *       (left to right, right to left, top to bottom, and so forth)
+ *   <li>Animation background -- The background to show during animation of the split involving this
+ *       {@code SplitAttributes} object if the animation requires a background
  * </ul>
  *
  * <p>Attributes can be configured by:
+ *
  * <ul>
- *     <li>Setting the default {@code SplitAttributes} using
- *         {@link SplitPairRule.Builder#setDefaultSplitAttributes} or
- *         {@link SplitPlaceholderRule.Builder#setDefaultSplitAttributes}.</li>
- *     <li>Using {@link ActivityEmbeddingComponent#setSplitAttributesCalculator(Function)} to set
- *         the callback to customize the {@code SplitAttributes} for a given device and window
- *         state.</li>
+ *   <li>Setting the default {@code SplitAttributes} using {@link
+ *       SplitPairRule.Builder#setDefaultSplitAttributes} or {@link
+ *       SplitPlaceholderRule.Builder#setDefaultSplitAttributes}.
+ *   <li>Using {@link ActivityEmbeddingComponent#setSplitAttributesCalculator(Function)} to set the
+ *       callback to customize the {@code SplitAttributes} for a given device and window state.
  * </ul>
  *
  * @see SplitAttributes.SplitType
  * @see SplitAttributes.LayoutDirection
- * Since {@link androidx.window.extensions.WindowExtensions#VENDOR_API_LEVEL_2}
+ * @see AnimationParams
  */
+@RequiresVendorApiLevel(level = 2)
 public class SplitAttributes {
 
     /**
-     * The default value for animation background color, which means to use the current theme window
-     * background color.
-     *
-     * Only opaque color is supported, so {@code 0} is used as the default. Any other non-opaque
-     * color will be treated as the default.
-     *
-     * @see Builder#setAnimationBackgroundColor(int)
-     */
-    @ColorInt
-    @RestrictTo(LIBRARY)
-    public static final int DEFAULT_ANIMATION_BACKGROUND_COLOR = 0;
-
-    /**
-     * The type of window split, which defines the proportion of the parent
-     * window occupied by the primary and secondary activity containers.
+     * The type of window split, which defines the proportion of the parent window occupied by the
+     * primary and secondary activity containers.
      */
     public static class SplitType {
-        @NonNull
-        private final String mDescription;
+        private final @NonNull String mDescription;
 
         SplitType(@NonNull String description) {
             mDescription = description;
@@ -112,15 +96,13 @@
             return mDescription.equals(that.mDescription);
         }
 
-        @NonNull
         @Override
-        public String toString() {
+        public @NonNull String toString() {
             return mDescription;
         }
 
         @SuppressLint("Range") // The range is covered.
-        @NonNull
-        static SplitType createSplitTypeFromLegacySplitRatio(
+        static @NonNull SplitType createSplitTypeFromLegacySplitRatio(
                 @FloatRange(from = 0.0, to = 1.0) float splitRatio) {
             // Treat 0.0 and 1.0 as ExpandContainerSplitType because it means the parent container
             // is filled with secondary or primary container.
@@ -131,20 +113,20 @@
         }
 
         /**
-         * A window split that's based on the ratio of the size of the primary
-         * container to the size of the parent window.
+         * A window split that's based on the ratio of the size of the primary container to the size
+         * of the parent window (excluding area unavailable for the containers such as the divider.
+         * See {@link DividerAttributes}).
          *
-         * <p>Values in the non-inclusive range (0.0, 1.0) define the size of
-         * the primary container relative to the size of the parent window:
+         * <p>Values in the non-inclusive range (0.0, 1.0) define the size of the primary container
+         * relative to the size of the parent window:
+         *
          * <ul>
-         *     <li>0.5 -- Primary container occupies half of the parent
-         *         window; secondary container, the other half</li>
-         *     <li>Greater than 0.5 -- Primary container occupies a larger
-         *         proportion of the parent window than the secondary
-         *         container</li>
-         *     <li>Less than 0.5 -- Primary container occupies a smaller
-         *         proportion of the parent window than the secondary
-         *         container</li>
+         *   <li>0.5 -- Primary container occupies half of the parent window; secondary container,
+         *       the other half
+         *   <li>Greater than 0.5 -- Primary container occupies a larger proportion of the parent
+         *       window than the secondary container
+         *   <li>Less than 0.5 -- Primary container occupies a smaller proportion of the parent
+         *       window than the secondary container
          * </ul>
          */
         public static final class RatioSplitType extends SplitType {
@@ -154,29 +136,30 @@
             /**
              * Creates an instance of this {@code RatioSplitType}.
              *
-             * @param ratio The proportion of the parent window occupied by the
-             *     primary container of the split. Can be a value in the
-             *     non-inclusive range (0.0, 1.0). Use
-             *     {@link SplitType.ExpandContainersSplitType} to create a split
-             *     type that occupies the entire parent window.
+             * @param ratio The proportion of the parent window occupied by the primary container of
+             *     the split (excluding area unavailable for the containers such as the divider. See
+             *     {@link DividerAttributes}). Can be a value in the non-inclusive range (0.0, 1.0).
+             *     Use {@link SplitType.ExpandContainersSplitType} to create a split type that
+             *     occupies the entire parent window.
              */
             public RatioSplitType(
                     @FloatRange(from = 0.0, to = 1.0, fromInclusive = false, toInclusive = false)
-                    float ratio) {
+                            float ratio) {
                 super("ratio:" + ratio);
                 if (ratio <= 0.0f || ratio >= 1.0f) {
-                    throw new IllegalArgumentException("Ratio must be in range (0.0, 1.0). "
-                            + " Use SplitType.ExpandContainersSplitType() instead of 0 or 1.");
+                    throw new IllegalArgumentException(
+                            "Ratio must be in range (0.0, 1.0).  Use"
+                                    + " SplitType.ExpandContainersSplitType() instead of 0 or 1.");
                 }
                 mRatio = ratio;
             }
 
             /**
-             * Gets the proportion of the parent window occupied by the primary
-             * activity container of the split.
+             * Gets the proportion of the parent window occupied by the primary activity container
+             * of the split (excluding area unavailable for the containers such as the divider. See
+             * {@link DividerAttributes}) .
              *
-             * @return The proportion of the split occupied by the primary
-             *     container.
+             * @return The proportion of the split occupied by the primary container.
              */
             @FloatRange(from = 0.0, to = 1.0, fromInclusive = false, toInclusive = false)
             public float getRatio() {
@@ -184,58 +167,51 @@
             }
 
             /**
-             * Creates a split type in which the primary and secondary
-             * containers occupy equal portions of the parent window.
+             * Creates a split type in which the primary and secondary containers occupy equal
+             * portions of the parent window.
              *
-             * Serves as the default {@link SplitType} if
-             * {@link SplitAttributes.Builder#setSplitType(SplitType)} is not
-             * specified.
+             * <p>Serves as the default {@link SplitType} if {@link
+             * SplitAttributes.Builder#setSplitType(SplitType)} is not specified.
              *
-             * @return A {@code RatioSplitType} in which the activity containers
-             *     occupy equal portions of the parent window.
+             * @return A {@code RatioSplitType} in which the activity containers occupy equal
+             *     portions of the parent window.
              */
-            @NonNull
-            public static RatioSplitType splitEqually() {
+            public static @NonNull RatioSplitType splitEqually() {
                 return new RatioSplitType(0.5f);
             }
         }
 
         /**
-         * A parent window split in which the split ratio conforms to the
-         * position of a hinge or separating fold in the device display.
+         * A parent window split in which the split ratio conforms to the position of a hinge or
+         * separating fold in the device display.
          *
-         * The split type is created only if:
+         * <p>The split type is created only if:
+         *
          * <ul>
-         *     <li>The host task is not in multi-window mode (e.g.,
-         *         split-screen mode or picture-in-picture mode)</li>
-         *     <li>The device has a hinge or separating fold reported by
-         *         [androidx.window.layout.FoldingFeature.isSeparating]</li>
-         *     <li>The hinge or separating fold orientation matches how the
-         *         parent bounds are split:
-         *         <ul>
-         *             <li>The hinge or fold orientation is vertical, and
-         *                 the task bounds are also split vertically
-         *                 (containers are side by side)</li>
-         *             <li>The hinge or fold orientation is horizontal, and
-         *                 the task bounds are also split horizontally
-         *                 (containers are top and bottom)</li>
-         *         </ul>
-         *     </li>
+         *   <li>The host task is not in multi-window mode (e.g., split-screen mode or
+         *       picture-in-picture mode)
+         *   <li>The device has a hinge or separating fold reported by
+         *       [androidx.window.layout.FoldingFeature.isSeparating]
+         *   <li>The hinge or separating fold orientation matches how the parent bounds are split:
+         *       <ul>
+         *         <li>The hinge or fold orientation is vertical, and the task bounds are also split
+         *             vertically (containers are side by side)
+         *         <li>The hinge or fold orientation is horizontal, and the task bounds are also
+         *             split horizontally (containers are top and bottom)
+         *       </ul>
          * </ul>
          *
-         * Otherwise, the type falls back to the {@code SplitType} returned by
-         * {@link #getFallbackSplitType()}.
+         * Otherwise, the type falls back to the {@code SplitType} returned by {@link
+         * #getFallbackSplitType()}.
          */
         public static final class HingeSplitType extends SplitType {
-            @NonNull
-            private final SplitType mFallbackSplitType;
+            private final @NonNull SplitType mFallbackSplitType;
 
             /**
              * Creates an instance of this {@code HingeSplitType}.
              *
-             * @param fallbackSplitType The split type to use if a split based
-             *     on the device hinge or separating fold cannot be determined.
-             *     Can be a {@link RatioSplitType} or
+             * @param fallbackSplitType The split type to use if a split based on the device hinge
+             *     or separating fold cannot be determined. Can be a {@link RatioSplitType} or
              *     {@link ExpandContainersSplitType}.
              */
             public HingeSplitType(@NonNull SplitType fallbackSplitType) {
@@ -244,132 +220,123 @@
             }
 
             /**
-             * Returns the fallback {@link SplitType} if a split based on the
-             * device hinge or separating fold cannot be determined.
+             * Returns the fallback {@link SplitType} if a split based on the device hinge or
+             * separating fold cannot be determined.
              */
-            @NonNull
-            public SplitType getFallbackSplitType() {
+            public @NonNull SplitType getFallbackSplitType() {
                 return mFallbackSplitType;
             }
         }
 
         /**
-         * A window split in which the primary and secondary activity containers
-         * each occupy the entire parent window.
+         * A window split in which the primary and secondary activity containers each occupy the
+         * entire parent window.
          *
-         * The secondary container overlays the primary container.
+         * <p>The secondary container overlays the primary container.
          */
         public static final class ExpandContainersSplitType extends SplitType {
 
-            /**
-             * Creates an instance of this {@code ExpandContainersSplitType}.
-             */
+            /** Creates an instance of this {@code ExpandContainersSplitType}. */
             public ExpandContainersSplitType() {
                 super("expandContainers");
             }
         }
     }
 
-    /**
-     * The layout direction of the primary and secondary activity containers.
-     */
+    /** The layout direction of the primary and secondary activity containers. */
     public static final class LayoutDirection {
 
         /**
          * Specifies that the parent bounds are split vertically (side to side).
          *
-         * Places the primary container in the left portion of the parent
-         * window, and the secondary container in the right portion.
+         * <p>Places the primary container in the left portion of the parent window, and the
+         * secondary container in the right portion.
          *
-         * A possible return value of {@link SplitType#getLayoutDirection()}.
+         * <p>A possible return value of {@link SplitType#getLayoutDirection()}.
          */
-         //
-         // -------------------------
-         // |           |           |
-         // |  Primary  | Secondary |
-         // |           |           |
-         // -------------------------
-         //
-         // Must match {@link LayoutDirection#LTR} for backwards compatibility
-         // with prior versions of Extensions.
+        //
+        // -------------------------
+        // |           |           |
+        // |  Primary  | Secondary |
+        // |           |           |
+        // -------------------------
+        //
+        // Must match {@link LayoutDirection#LTR} for backwards compatibility
+        // with prior versions of Extensions.
         public static final int LEFT_TO_RIGHT = 0;
 
         /**
-         * Specifies that the parent bounds are split vertically (side to
-         * side).
+         * Specifies that the parent bounds are split vertically (side to side).
          *
-         * Places the primary container in the right portion of the parent
-         * window, and the secondary container in the left portion.
+         * <p>Places the primary container in the right portion of the parent window, and the
+         * secondary container in the left portion.
          *
-         * A possible return value of {@link SplitType#getLayoutDirection()}.
+         * <p>A possible return value of {@link SplitType#getLayoutDirection()}.
          */
-         // -------------------------
-         // |           |           |
-         // | Secondary |  Primary  |
-         // |           |           |
-         // -------------------------
-         //
-         // Must match {@link LayoutDirection#RTL} for backwards compatibility
-         // with prior versions of Extensions.
+        // -------------------------
+        // |           |           |
+        // | Secondary |  Primary  |
+        // |           |           |
+        // -------------------------
+        //
+        // Must match {@link LayoutDirection#RTL} for backwards compatibility
+        // with prior versions of Extensions.
         public static final int RIGHT_TO_LEFT = 1;
 
         /**
          * Specifies that the parent bounds are split vertically (side to side).
          *
-         * The direction of the primary and secondary containers is deduced from
-         * the locale as either {@link #LEFT_TO_RIGHT} or
-         * {@link #RIGHT_TO_LEFT}.
+         * <p>The direction of the primary and secondary containers is deduced from the locale as
+         * either {@link #LEFT_TO_RIGHT} or {@link #RIGHT_TO_LEFT}.
          *
-         * A possible return value of {@link SplitType#getLayoutDirection()}.
+         * <p>A possible return value of {@link SplitType#getLayoutDirection()}.
          */
-         // Must match {@link LayoutDirection#LOCALE} for backwards
-         // compatibility with prior versions of Extensions.
+        // Must match {@link LayoutDirection#LOCALE} for backwards
+        // compatibility with prior versions of Extensions.
         public static final int LOCALE = 3;
 
         /**
-         * Specifies that the parent bounds are split horizontally (top and
-         * bottom).
+         * Specifies that the parent bounds are split horizontally (top and bottom).
          *
-         * Places the primary container in the top portion of the parent window,
-         * and the secondary container in the bottom portion.
+         * <p>Places the primary container in the top portion of the parent window, and the
+         * secondary container in the bottom portion.
          *
-         * If the horizontal layout direction is not supported on the device,
-         * layout direction falls back to {@link #LOCALE}.
+         * <p>If the horizontal layout direction is not supported on the device, layout direction
+         * falls back to {@link #LOCALE}.
          *
-         * A possible return value of {@link SplitType#getLayoutDirection()}.
+         * <p>A possible return value of {@link SplitType#getLayoutDirection()}.
          */
-         // -------------
-         // |           |
-         // |  Primary  |
-         // |           |
-         // -------------
-         // |           |
-         // | Secondary |
-         // |           |
-         // -------------
+        // -------------
+        // |           |
+        // |  Primary  |
+        // |           |
+        // -------------
+        // |           |
+        // | Secondary |
+        // |           |
+        // -------------
         public static final int TOP_TO_BOTTOM = 4;
 
         /**
-         * Specifies that the parent bounds are split horizontally (top and
-         * bottom).
+         * Specifies that the parent bounds are split horizontally (top and bottom).
          *
-         * Places the primary container in the bottom portion of the parent
-         * window, and the secondary container in the top portion.
+         * <p>Places the primary container in the bottom portion of the parent window, and the
+         * secondary container in the top portion.
          *
-         * If the horizontal layout direction is not supported on the device,
-         * layout direction falls back to {@link #LOCALE}.
+         * <p>If the horizontal layout direction is not supported on the device, layout direction
+         * falls back to {@link #LOCALE}.
          *
-         * A possible return value of {@link SplitType#getLayoutDirection()}.
+         * <p>A possible return value of {@link SplitType#getLayoutDirection()}.
          */
-         // -------------
-         // |           |
-         // | Secondary |
-         // |           |
-         // -------------
-         // |           |
-         // |  Primary  |
-         // |           |
-         // -------------
+        // -------------
+        // |           |
+        // | Secondary |
+        // |           |
+        // -------------
+        // |           |
+        // |  Primary  |
+        // |           |
+        // -------------
         public static final int BOTTOM_TO_TOP = 5;
 
         private LayoutDirection() {}
@@ -379,31 +346,40 @@
     @Retention(RetentionPolicy.SOURCE)
     @interface ExtLayoutDirection {}
 
-    @ExtLayoutDirection
-    private final int mLayoutDirection;
+    @ExtLayoutDirection private final int mLayoutDirection;
 
-    private final SplitType mSplitType;
+    private final @NonNull SplitType mSplitType;
 
-    @ColorInt
-    private final int mAnimationBackgroundColor;
+    private final @NonNull AnimationParams mAnimationParams;
+
+    private final @NonNull WindowAttributes mWindowAttributes;
+
+    /** The attributes of a divider. If {@code null}, no divider is requested. */
+    private final @Nullable DividerAttributes mDividerAttributes;
 
     /**
      * Creates an instance of this {@code SplitAttributes}.
      *
-     * @param splitType The type of split. See
-     *     {@link SplitAttributes.SplitType}.
-     * @param layoutDirection The layout direction of the split, such as left to
-     *     right or top to bottom. See {@link SplitAttributes.LayoutDirection}.
-     * @param animationBackgroundColor The {@link ColorInt} to use for the
-     *     background color during animation of the split involving this
-     *     {@code SplitAttributes} object if the animation requires a
-     *     background.
+     * @param splitType The type of split. See {@link SplitAttributes.SplitType}.
+     * @param layoutDirection The layout direction of the split, such as left to right or top to
+     *     bottom. See {@link SplitAttributes.LayoutDirection}.
+     * @param animationParams The {@link AnimationParams} to use for the during animation of the
+     *     split involving this {@code SplitAttributes} object.
+     * @param attributes The {@link WindowAttributes} of the split, such as dim area behavior.
+     * @param dividerAttributes The {@link DividerAttributes}. If {@code null}, no divider is
+     *     requested.
      */
-    SplitAttributes(@NonNull SplitType splitType, @ExtLayoutDirection int layoutDirection,
-            @ColorInt int animationBackgroundColor) {
+    SplitAttributes(
+            @NonNull SplitType splitType,
+            @ExtLayoutDirection int layoutDirection,
+            @NonNull AnimationParams animationParams,
+            @NonNull WindowAttributes attributes,
+            @Nullable DividerAttributes dividerAttributes) {
         mSplitType = splitType;
         mLayoutDirection = layoutDirection;
-        mAnimationBackgroundColor = animationBackgroundColor;
+        mAnimationParams = animationParams;
+        mWindowAttributes = attributes;
+        mDividerAttributes = dividerAttributes;
     }
 
     /**
@@ -421,53 +397,90 @@
      *
      * @return The split type.
      */
-    @NonNull
-    public SplitType getSplitType() {
+    public @NonNull SplitType getSplitType() {
         return mSplitType;
     }
 
     /**
-     * Gets the {@link ColorInt} to use for the background color during the
-     * animation of the split involving this {@code SplitAttributes} object.
-     *
-     * The default is {@link #DEFAULT_ANIMATION_BACKGROUND_COLOR}, which means
-     * to use the current theme window background color.
-     *
-     * @return The animation background {@code ColorInt}.
+     * @deprecated Use {@link #getAnimationParams()} starting with vendor API level 7. Only used if
+     *     {@link #getAnimationParams()} can't be called on vendor API level 5 and 6.
      */
-    @ColorInt
-    @RestrictTo(LIBRARY)
-    public int getAnimationBackgroundColor() {
-        return mAnimationBackgroundColor;
+    @RequiresVendorApiLevel(level = 5, deprecatedSince = 7)
+    @Deprecated
+    @SuppressWarnings("Deprecation")
+    public @NonNull AnimationBackground getAnimationBackground() {
+        return mAnimationParams.getAnimationBackground();
+    }
+
+    /**
+     * Returns the {@link AnimationParams} to use during the animation of the split involving this
+     * {@code SplitAttributes} object.
+     */
+    @RequiresVendorApiLevel(level = 7)
+    public @NonNull AnimationParams getAnimationParams() {
+        return mAnimationParams;
+    }
+
+    /**
+     * Returns the {@link WindowAttributes} which contains the configurations of the embedded
+     * Activity windows in this SplitAttributes.
+     */
+    @RequiresVendorApiLevel(level = 5)
+    public @NonNull WindowAttributes getWindowAttributes() {
+        return mWindowAttributes;
+    }
+
+    /** Returns the {@link DividerAttributes}. If {@code null}, no divider is requested. */
+    @RequiresVendorApiLevel(level = 6)
+    public @Nullable DividerAttributes getDividerAttributes() {
+        return mDividerAttributes;
     }
 
     /**
      * Builder for creating an instance of {@link SplitAttributes}.
      *
-     * - The default split type is an equal split between primary and secondary containers.
-     * - The default layout direction is based on locale.
-     * - The default animation background color is to use the current theme window background color.
+     * <p>- The default split type is an equal split between primary and secondary containers. - The
+     * default layout direction is based on locale. - The default animation background is to use the
+     * current theme window background color.
      */
     public static final class Builder {
-        @NonNull
-        private SplitType mSplitType =  new SplitType.RatioSplitType(0.5f);
-        @ExtLayoutDirection
-        private int mLayoutDirection = LOCALE;
+        private @NonNull SplitType mSplitType = new SplitType.RatioSplitType(0.5f);
+        @ExtLayoutDirection private int mLayoutDirection = LOCALE;
 
-        @ColorInt
-        private int mAnimationBackgroundColor = 0;
+        private @NonNull AnimationParams mAnimationParams = new AnimationParams.Builder().build();
+
+        private @NonNull WindowAttributes mWindowAttributes =
+                new WindowAttributes(DIM_AREA_ON_TASK);
+
+        private @Nullable DividerAttributes mDividerAttributes;
+
+        /** Creates a new {@link Builder} to create {@link SplitAttributes}. */
+        public Builder() {}
+
+        /**
+         * Creates a {@link Builder} with values cloned from the original {@link SplitAttributes}.
+         *
+         * @param original the original {@link SplitAttributes} to initialize the {@link Builder}.
+         */
+        @RequiresVendorApiLevel(level = 6)
+        public Builder(@NonNull SplitAttributes original) {
+            mSplitType = original.mSplitType;
+            mLayoutDirection = original.mLayoutDirection;
+            mAnimationParams = original.mAnimationParams;
+            mWindowAttributes = original.mWindowAttributes;
+            mDividerAttributes = original.mDividerAttributes;
+        }
 
         /**
          * Sets the split type attribute.
          *
-         * The default is an equal split between primary and secondary
-         * containers (see {@link SplitType.RatioSplitType#splitEqually()}).
+         * <p>The default is an equal split between primary and secondary containers (see {@link
+         * SplitType.RatioSplitType#splitEqually()}).
          *
          * @param splitType The split type attribute.
          * @return This {@code Builder}.
          */
-        @NonNull
-        public Builder setSplitType(@NonNull SplitType splitType) {
+        public @NonNull Builder setSplitType(@NonNull SplitType splitType) {
             mSplitType = splitType;
             return this;
         }
@@ -475,101 +488,133 @@
         /**
          * Sets the split layout direction attribute.
          *
-         * The default is based on locale.
+         * <p>The default is based on locale.
          *
-         * Must be one of:
+         * <p>Must be one of:
+         *
          * <ul>
-         *     <li>{@link LayoutDirection#LOCALE}</li>
-         *     <li>{@link LayoutDirection#LEFT_TO_RIGHT}</li>
-         *     <li>{@link LayoutDirection#RIGHT_TO_LEFT}</li>
-         *     <li>{@link LayoutDirection#TOP_TO_BOTTOM}</li>
-         *     <li>{@link LayoutDirection#BOTTOM_TO_TOP}</li>
+         *   <li>{@link LayoutDirection#LOCALE}
+         *   <li>{@link LayoutDirection#LEFT_TO_RIGHT}
+         *   <li>{@link LayoutDirection#RIGHT_TO_LEFT}
+         *   <li>{@link LayoutDirection#TOP_TO_BOTTOM}
+         *   <li>{@link LayoutDirection#BOTTOM_TO_TOP}
          * </ul>
          *
          * @param layoutDirection The layout direction attribute.
          * @return This {@code Builder}.
          */
         @SuppressLint("WrongConstant") // To be compat with android.util.LayoutDirection APIs
-        @NonNull
-        public Builder setLayoutDirection(@ExtLayoutDirection int layoutDirection) {
+        public @NonNull Builder setLayoutDirection(@ExtLayoutDirection int layoutDirection) {
             mLayoutDirection = layoutDirection;
             return this;
         }
 
         /**
-         * Sets the {@link ColorInt} to use for the background during the
-         * animation of the split involving this {@code SplitAttributes} object
-         * if the animation requires a background.
-         *
-         * Only opaque color is supported.
-         *
-         * The default value is {@link #DEFAULT_ANIMATION_BACKGROUND_COLOR}, which
-         * means to use the current theme window background color. Any non-opaque
-         * animation color will be treated as
-         * {@link #DEFAULT_ANIMATION_BACKGROUND_COLOR}.
-         *
-         * @param color A packed color int of the form {@code AARRGGBB} for the
-         *              animation background color.
-         * @return This {@code Builder}.
+         * @deprecated Use {@link #setAnimationParams(AnimationParams)} starting with vendor API
+         *     level 7. Only used if {@link #setAnimationParams(AnimationParams)} can't be called on
+         *     vendor API level 5 and 6.
          */
-        @NonNull
-        @RestrictTo(LIBRARY)
-        public Builder setAnimationBackgroundColor(@ColorInt int color) {
-            // Any non-opaque color will be treated as the default.
-            mAnimationBackgroundColor = Color.alpha(color) != 255
-                    ? DEFAULT_ANIMATION_BACKGROUND_COLOR
-                    : color;
+        @RequiresVendorApiLevel(level = 5, deprecatedSince = 7)
+        @Deprecated
+        @SuppressWarnings("Deprecation")
+        public @NonNull Builder setAnimationBackground(@NonNull AnimationBackground background) {
+            mAnimationParams =
+                    new AnimationParams.Builder().setAnimationBackground(background).build();
             return this;
         }
 
         /**
-         * Builds a {@link SplitAttributes} instance with the attributes
-         * specified by {@link #setSplitType}, {@link #setLayoutDirection}, and
-         * {@link #setAnimationBackgroundColor}.
+         * Sets the {@link AnimationParams} to use during the animation of the split involving this
+         * {@code SplitAttributes} object.
+         *
+         * @param params The {@link AnimationParams} to be used for the animation of the split.
+         * @return This {@code Builder}.
+         */
+        @RequiresVendorApiLevel(level = 7)
+        public @NonNull Builder setAnimationParams(@NonNull AnimationParams params) {
+            mAnimationParams = params;
+            return this;
+        }
+
+        /**
+         * Sets the window attributes. If this value is not specified, the {@link
+         * WindowAttributes#getDimAreaBehavior()} will be only applied on the {@link ActivityStack}
+         * of the requested activity.
+         *
+         * @param attributes The {@link WindowAttributes}
+         * @return This {@code Builder}.
+         */
+        @RequiresVendorApiLevel(level = 5)
+        public @NonNull Builder setWindowAttributes(@NonNull WindowAttributes attributes) {
+            mWindowAttributes = attributes;
+            return this;
+        }
+
+        /** Sets the {@link DividerAttributes}. If {@code null}, no divider is requested. */
+        @RequiresVendorApiLevel(level = 6)
+        public @NonNull Builder setDividerAttributes(
+                @Nullable DividerAttributes dividerAttributes) {
+            mDividerAttributes = dividerAttributes;
+            return this;
+        }
+
+        /**
+         * Builds a {@link SplitAttributes} instance with the attributes specified by {@link
+         * #setSplitType}, {@link #setLayoutDirection}, and {@link #setAnimationParams}.
          *
          * @return The new {@code SplitAttributes} instance.
          */
-        @NonNull
-        public SplitAttributes build() {
-            return new SplitAttributes(mSplitType, mLayoutDirection, mAnimationBackgroundColor);
+        public @NonNull SplitAttributes build() {
+            return new SplitAttributes(
+                    mSplitType,
+                    mLayoutDirection,
+                    mAnimationParams,
+                    mWindowAttributes,
+                    mDividerAttributes);
         }
     }
 
     @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof SplitAttributes)) return false;
+        SplitAttributes that = (SplitAttributes) o;
+        return mLayoutDirection == that.mLayoutDirection
+                && mSplitType.equals(that.mSplitType)
+                && Objects.equals(mAnimationParams, that.mAnimationParams)
+                && mWindowAttributes.equals(that.mWindowAttributes)
+                && Objects.equals(mDividerAttributes, that.mDividerAttributes);
+    }
+
+    @Override
     public int hashCode() {
-        int result = mSplitType.hashCode();
-        result = result * 31 + mLayoutDirection;
-        result = result * 31 + mAnimationBackgroundColor;
-        return result;
+        return Objects.hash(
+                mLayoutDirection,
+                mSplitType,
+                mAnimationParams,
+                mWindowAttributes,
+                mDividerAttributes);
     }
 
     @Override
-    public boolean equals(Object other) {
-        if (other == this) {
-            return true;
-        }
-        if (!(other instanceof SplitAttributes)) {
-            return false;
-        }
-        final SplitAttributes otherAttributes = (SplitAttributes) other;
-        return mLayoutDirection == otherAttributes.mLayoutDirection
-                && mSplitType.equals(otherAttributes.mSplitType)
-                && mAnimationBackgroundColor == otherAttributes.mAnimationBackgroundColor;
-    }
-
-    @NonNull
-    @Override
-    public String toString() {
-        return SplitAttributes.class.getSimpleName() + "{"
-                + "layoutDir=" + layoutDirectionToString()
-                + ", ratio=" + mSplitType
-                + ", animationBgColor=" + Integer.toHexString(mAnimationBackgroundColor)
+    public @NonNull String toString() {
+        return SplitAttributes.class.getSimpleName()
+                + "{"
+                + "layoutDir="
+                + layoutDirectionToString()
+                + ", splitType="
+                + mSplitType
+                + ", animationParams="
+                + mAnimationParams
+                + ", windowAttributes="
+                + mWindowAttributes
+                + ", dividerAttributes="
+                + mDividerAttributes
                 + "}";
     }
 
-    @NonNull
-    private String layoutDirectionToString() {
-        switch(mLayoutDirection) {
+    private @NonNull String layoutDirectionToString() {
+        switch (mLayoutDirection) {
             case LEFT_TO_RIGHT:
                 return "LEFT_TO_RIGHT";
             case RIGHT_TO_LEFT:
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributesCalculatorParams.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributesCalculatorParams.java
index 80f98fe..ae214d8 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributesCalculatorParams.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributesCalculatorParams.java
@@ -17,87 +17,73 @@
 package androidx.window.extensions.embedding;
 
 import android.content.res.Configuration;
-import android.os.Build;
 import android.view.WindowMetrics;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
+import androidx.window.extensions.RequiresVendorApiLevel;
 import androidx.window.extensions.layout.WindowLayoutInfo;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 /**
- * The parameter container used to report the current device and window state in
- * {@link ActivityEmbeddingComponent#setSplitAttributesCalculator(
- * androidx.window.extensions.core.util.function.Function)} and references the corresponding
- * {@link SplitRule} by {@link #getSplitRuleTag()} if {@link SplitRule#getTag()} is specified.
+ * The parameter container used to report the current device and window state in {@link
+ * ActivityEmbeddingComponent#setSplitAttributesCalculator(
+ * androidx.window.extensions.core.util.function.Function)} and references the corresponding {@link
+ * SplitRule} by {@link #getSplitRuleTag()} if {@link SplitRule#getTag()} is specified.
  *
  * @see ActivityEmbeddingComponent#clearSplitAttributesCalculator()
- * Since {@link androidx.window.extensions.WindowExtensions#VENDOR_API_LEVEL_2}
  */
+@RequiresVendorApiLevel(level = 2)
 public class SplitAttributesCalculatorParams {
-    @NonNull
-    private final WindowMetrics mParentWindowMetrics;
-    @NonNull
-    private final Configuration mParentConfiguration;
-    @NonNull
-    private final WindowLayoutInfo mParentWindowLayoutInfo;
-    @NonNull
-    private final SplitAttributes mDefaultSplitAttributes;
+    private final @NonNull WindowMetrics mParentWindowMetrics;
+    private final @NonNull Configuration mParentConfiguration;
+    private final @NonNull WindowLayoutInfo mParentWindowLayoutInfo;
+    private final @NonNull SplitAttributes mDefaultSplitAttributes;
     private final boolean mAreDefaultConstraintsSatisfied;
-    @Nullable
-    private final String mSplitRuleTag;
+    private final @Nullable String mSplitRuleTag;
 
     /** Returns the parent container's {@link WindowMetrics} */
-    @NonNull
-    public WindowMetrics getParentWindowMetrics() {
+    public @NonNull WindowMetrics getParentWindowMetrics() {
         return mParentWindowMetrics;
     }
 
     /** Returns the parent container's {@link Configuration} */
-    @NonNull
-    public Configuration getParentConfiguration() {
+    public @NonNull Configuration getParentConfiguration() {
         return new Configuration(mParentConfiguration);
     }
 
     /**
-     * Returns the {@link SplitRule#getDefaultSplitAttributes()}. It could be from
-     * {@link SplitRule} Builder APIs
-     * ({@link SplitPairRule.Builder#setDefaultSplitAttributes(SplitAttributes)} or
-     * {@link SplitPlaceholderRule.Builder#setDefaultSplitAttributes(SplitAttributes)}) or from
-     * the {@code splitRatio} and {@code splitLayoutDirection} attributes from static rule
-     * definitions.
+     * Returns the {@link SplitRule#getDefaultSplitAttributes()}. It could be from {@link SplitRule}
+     * Builder APIs ({@link SplitPairRule.Builder#setDefaultSplitAttributes(SplitAttributes)} or
+     * {@link SplitPlaceholderRule.Builder#setDefaultSplitAttributes(SplitAttributes)}) or from the
+     * {@code splitRatio} and {@code splitLayoutDirection} attributes from static rule definitions.
      */
-    @NonNull
-    public SplitAttributes getDefaultSplitAttributes() {
+    public @NonNull SplitAttributes getDefaultSplitAttributes() {
         return mDefaultSplitAttributes;
     }
 
     /**
      * Returns whether the {@link #getParentWindowMetrics()} satisfies the dimensions and aspect
-     * ratios requirements specified in the {@link androidx.window.embedding.SplitRule}, which
-     * are:
-     *  - {@link androidx.window.embedding.SplitRule#minWidthDp}
-     *  - {@link androidx.window.embedding.SplitRule#minHeightDp}
-     *  - {@link androidx.window.embedding.SplitRule#minSmallestWidthDp}
-     *  - {@link androidx.window.embedding.SplitRule#maxAspectRatioInPortrait}
-     *  - {@link androidx.window.embedding.SplitRule#maxAspectRatioInLandscape}
+     * ratios requirements specified in the {@link androidx.window.embedding.SplitRule}, which are:
+     * - {@link androidx.window.embedding.SplitRule#minWidthDp} - {@link
+     * androidx.window.embedding.SplitRule#minHeightDp} - {@link
+     * androidx.window.embedding.SplitRule#minSmallestWidthDp} - {@link
+     * androidx.window.embedding.SplitRule#maxAspectRatioInPortrait} - {@link
+     * androidx.window.embedding.SplitRule#maxAspectRatioInLandscape}
      */
     public boolean areDefaultConstraintsSatisfied() {
         return mAreDefaultConstraintsSatisfied;
     }
 
     /** Returns the parent container's {@link WindowLayoutInfo} */
-    @NonNull
-    public WindowLayoutInfo getParentWindowLayoutInfo() {
+    public @NonNull WindowLayoutInfo getParentWindowLayoutInfo() {
         return mParentWindowLayoutInfo;
     }
 
     /**
-     * Returns {@link SplitRule#getTag()} to apply the {@link SplitAttributes} result if it was
-     * set.
+     * Returns {@link SplitRule#getTag()} to apply the {@link SplitAttributes} result if it was set.
      */
-    @Nullable
-    public String getSplitRuleTag() {
+    public @Nullable String getSplitRuleTag() {
         return mSplitRuleTag;
     }
 
@@ -107,8 +93,7 @@
             @NonNull WindowLayoutInfo parentWindowLayoutInfo,
             @NonNull SplitAttributes defaultSplitAttributes,
             boolean areDefaultConstraintsSatisfied,
-            @Nullable String splitRuleTag
-    ) {
+            @Nullable String splitRuleTag) {
         mParentWindowMetrics = parentWindowMetrics;
         mParentConfiguration = parentConfiguration;
         mParentWindowLayoutInfo = parentWindowLayoutInfo;
@@ -117,33 +102,22 @@
         mSplitRuleTag = splitRuleTag;
     }
 
-    @NonNull
     @Override
-    public String toString() {
-        return getClass().getSimpleName() + ":{"
-                + "windowMetrics=" + windowMetricsToString(mParentWindowMetrics)
-                + ", configuration=" + mParentConfiguration
-                + ", windowLayoutInfo=" + mParentWindowLayoutInfo
-                + ", defaultSplitAttributes=" + mDefaultSplitAttributes
-                + ", areDefaultConstraintsSatisfied=" + mAreDefaultConstraintsSatisfied
-                + ", tag=" + mSplitRuleTag + "}";
-    }
-
-    private static String windowMetricsToString(@NonNull WindowMetrics windowMetrics) {
-        // TODO(b/187712731): Use WindowMetrics#toString after it's implemented in U.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
-            return Api30Impl.windowMetricsToString(windowMetrics);
-        }
-        throw new UnsupportedOperationException("WindowMetrics didn't exist in R.");
-    }
-
-    @RequiresApi(30)
-    private static final class Api30Impl {
-        static String windowMetricsToString(@NonNull WindowMetrics windowMetrics) {
-            return WindowMetrics.class.getSimpleName() + ":{"
-                    + "bounds=" + windowMetrics.getBounds()
-                    + ", windowInsets=" + windowMetrics.getWindowInsets()
-                    + "}";
-        }
+    public @NonNull String toString() {
+        return getClass().getSimpleName()
+                + ":{"
+                + "windowMetrics="
+                + WindowMetricsCompat.toString(mParentWindowMetrics)
+                + ", configuration="
+                + mParentConfiguration
+                + ", windowLayoutInfo="
+                + mParentWindowLayoutInfo
+                + ", defaultSplitAttributes="
+                + mDefaultSplitAttributes
+                + ", areDefaultConstraintsSatisfied="
+                + mAreDefaultConstraintsSatisfied
+                + ", tag="
+                + mSplitRuleTag
+                + "}";
     }
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitInfo.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitInfo.java
index bac42a4..c603fe9 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitInfo.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitInfo.java
@@ -16,30 +16,23 @@
 
 package androidx.window.extensions.embedding;
 
-import android.os.Binder;
 import android.os.IBinder;
 
-import androidx.annotation.NonNull;
-import androidx.window.extensions.WindowExtensions;
+import androidx.window.extensions.RequiresVendorApiLevel;
 import androidx.window.extensions.embedding.SplitAttributes.SplitType;
 
+import org.jspecify.annotations.NonNull;
+
 import java.util.Objects;
 
 /** Describes a split of two containers with activities. */
 public class SplitInfo {
 
-    /** Only used for compatibility with the deprecated constructor. */
-    private static final IBinder INVALID_SPLIT_INFO_TOKEN = new Binder();
+    private final @NonNull ActivityStack mPrimaryActivityStack;
+    private final @NonNull ActivityStack mSecondaryActivityStack;
+    private final @NonNull SplitAttributes mSplitAttributes;
 
-    @NonNull
-    private final ActivityStack mPrimaryActivityStack;
-    @NonNull
-    private final ActivityStack mSecondaryActivityStack;
-    @NonNull
-    private final SplitAttributes mSplitAttributes;
-
-    @NonNull
-    private final IBinder mToken;
+    private final @NonNull Token mToken;
 
     /**
      * The {@code SplitInfo} constructor
@@ -48,12 +41,12 @@
      * @param secondaryActivityStack The secondary {@link ActivityStack}
      * @param splitAttributes The current {@link SplitAttributes} of this split pair
      * @param token The token to identify this split pair
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
      */
-    SplitInfo(@NonNull ActivityStack primaryActivityStack,
+    SplitInfo(
+            @NonNull ActivityStack primaryActivityStack,
             @NonNull ActivityStack secondaryActivityStack,
             @NonNull SplitAttributes splitAttributes,
-            @NonNull IBinder token) {
+            @NonNull Token token) {
         Objects.requireNonNull(primaryActivityStack);
         Objects.requireNonNull(secondaryActivityStack);
         Objects.requireNonNull(splitAttributes);
@@ -64,33 +57,19 @@
         mToken = token;
     }
 
-    /**
-     * @deprecated Use the {@link WindowExtensions#VENDOR_API_LEVEL_3} version.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_1}
-     */
-    @Deprecated
-    SplitInfo(@NonNull ActivityStack primaryActivityStack,
-            @NonNull ActivityStack secondaryActivityStack,
-            @NonNull SplitAttributes splitAttributes) {
-        this(primaryActivityStack, secondaryActivityStack, splitAttributes,
-                INVALID_SPLIT_INFO_TOKEN);
-    }
-
-    @NonNull
-    public ActivityStack getPrimaryActivityStack() {
+    public @NonNull ActivityStack getPrimaryActivityStack() {
         return mPrimaryActivityStack;
     }
 
-    @NonNull
-    public ActivityStack getSecondaryActivityStack() {
+    public @NonNull ActivityStack getSecondaryActivityStack() {
         return mSecondaryActivityStack;
     }
 
     /**
-     * @deprecated Use {@link #getSplitAttributes()} starting with
-     * {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if {@link #getSplitAttributes()}
-     * can't be called on {@link WindowExtensions#VENDOR_API_LEVEL_1}.
+     * @deprecated Use {@link #getSplitAttributes()} starting with vendor API level 2. Only used if
+     *     {@link #getSplitAttributes()} can't be called on vendor API level 1.
      */
+    @RequiresVendorApiLevel(level = 1, deprecatedSince = 2)
     @Deprecated
     public float getSplitRatio() {
         final SplitType splitType = mSplitAttributes.getSplitType();
@@ -101,21 +80,24 @@
         }
     }
 
-    /**
-     * Returns the {@link SplitAttributes} of this split.
-     * Since {@link androidx.window.extensions.WindowExtensions#VENDOR_API_LEVEL_2}
-     */
-    @NonNull
-    public SplitAttributes getSplitAttributes() {
+    /** Returns the {@link SplitAttributes} of this split. */
+    @RequiresVendorApiLevel(level = 2)
+    public @NonNull SplitAttributes getSplitAttributes() {
         return mSplitAttributes;
     }
 
     /**
-     * Returns a token uniquely identifying the container.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_3}
+     * @deprecated Use {@link #getSplitInfoToken()} instead.
      */
-    @NonNull
-    public IBinder getToken() {
+    @Deprecated
+    @RequiresVendorApiLevel(level = 3, deprecatedSince = 5)
+    public @NonNull IBinder getToken() {
+        return mToken.getRawToken();
+    }
+
+    /** Returns a token uniquely identifying the split. */
+    @RequiresVendorApiLevel(level = 5)
+    public @NonNull Token getSplitInfoToken() {
         return mToken;
     }
 
@@ -124,9 +106,10 @@
         if (this == o) return true;
         if (!(o instanceof SplitInfo)) return false;
         SplitInfo that = (SplitInfo) o;
-        return mSplitAttributes.equals(that.mSplitAttributes) && mPrimaryActivityStack.equals(
-                that.mPrimaryActivityStack) && mSecondaryActivityStack.equals(
-                that.mSecondaryActivityStack) && mToken.equals(that.mToken);
+        return mSplitAttributes.equals(that.mSplitAttributes)
+                && mPrimaryActivityStack.equals(that.mPrimaryActivityStack)
+                && mSecondaryActivityStack.equals(that.mSecondaryActivityStack)
+                && mToken.equals(that.mToken);
     }
 
     @Override
@@ -138,14 +121,59 @@
         return result;
     }
 
-    @NonNull
     @Override
-    public String toString() {
+    public @NonNull String toString() {
         return "SplitInfo{"
-                + "mPrimaryActivityStack=" + mPrimaryActivityStack
-                + ", mSecondaryActivityStack=" + mSecondaryActivityStack
-                + ", mSplitAttributes=" + mSplitAttributes
-                + ", mToken=" + mToken
+                + "mPrimaryActivityStack="
+                + mPrimaryActivityStack
+                + ", mSecondaryActivityStack="
+                + mSecondaryActivityStack
+                + ", mSplitAttributes="
+                + mSplitAttributes
+                + ", mToken="
+                + mToken
                 + '}';
     }
+
+    /** A unique identifier to represent the split. */
+    public static final class Token {
+
+        private final @NonNull IBinder mToken;
+
+        Token(@NonNull IBinder token) {
+            mToken = token;
+        }
+
+        @NonNull IBinder getRawToken() {
+            return mToken;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof Token)) return false;
+            Token token = (Token) o;
+            return Objects.equals(mToken, token.mToken);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mToken);
+        }
+
+        @Override
+        public @NonNull String toString() {
+            return "Token{" + "mToken=" + mToken + '}';
+        }
+
+        /**
+         * Creates a split token from binder.
+         *
+         * @param token the raw binder used by OEM Extensions implementation.
+         */
+        @RequiresVendorApiLevel(level = 5)
+        public static @NonNull Token createFromBinder(@NonNull IBinder token) {
+            return new Token(token);
+        }
+    }
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitPairRule.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitPairRule.java
index ada0637..ac78064 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitPairRule.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitPairRule.java
@@ -18,7 +18,6 @@
 
 import static androidx.window.extensions.embedding.SplitAttributes.SplitType.createSplitTypeFromLegacySplitRatio;
 
-import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.content.Intent;
 import android.os.Build;
@@ -26,31 +25,28 @@
 import android.view.WindowMetrics;
 
 import androidx.annotation.FloatRange;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
-import androidx.window.extensions.WindowExtensions;
+import androidx.window.extensions.RequiresVendorApiLevel;
 import androidx.window.extensions.core.util.function.Predicate;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.util.Objects;
 
-/**
- * Split configuration rules for activity pairs.
- */
+/** Split configuration rules for activity pairs. */
 public class SplitPairRule extends SplitRule {
-    @NonNull
-    private final Predicate<Pair<Activity, Activity>> mActivityPairPredicate;
-    @NonNull
-    private final Predicate<Pair<Activity, Intent>> mActivityIntentPredicate;
-    @SplitFinishBehavior
-    private final int mFinishPrimaryWithSecondary;
-    @SplitFinishBehavior
-    private final int mFinishSecondaryWithPrimary;
+    private final @NonNull Predicate<Pair<Activity, Activity>> mActivityPairPredicate;
+    private final @NonNull Predicate<Pair<Activity, Intent>> mActivityIntentPredicate;
+    @SplitFinishBehavior private final int mFinishPrimaryWithSecondary;
+    @SplitFinishBehavior private final int mFinishSecondaryWithPrimary;
     private final boolean mClearTop;
 
-    SplitPairRule(@NonNull SplitAttributes defaultSplitAttributes,
+    SplitPairRule(
+            @NonNull SplitAttributes defaultSplitAttributes,
             @SplitFinishBehavior int finishPrimaryWithSecondary,
-            @SplitFinishBehavior int finishSecondaryWithPrimary, boolean clearTop,
+            @SplitFinishBehavior int finishSecondaryWithPrimary,
+            boolean clearTop,
             @NonNull Predicate<Pair<Activity, Activity>> activityPairPredicate,
             @NonNull Predicate<Pair<Activity, Intent>> activityIntentPredicate,
             @NonNull Predicate<WindowMetrics> parentWindowMetricsPredicate,
@@ -63,13 +59,10 @@
         mClearTop = clearTop;
     }
 
-    /**
-     * Checks if the rule is applicable to the provided activities.
-     */
-    @SuppressLint("ClassVerificationFailure") // Only called by Extensions implementation on device.
+    /** Checks if the rule is applicable to the provided activities. */
     @RequiresApi(api = Build.VERSION_CODES.N)
-    public boolean matchesActivityPair(@NonNull Activity primaryActivity,
-            @NonNull Activity secondaryActivity) {
+    public boolean matchesActivityPair(
+            @NonNull Activity primaryActivity, @NonNull Activity secondaryActivity) {
         return mActivityPairPredicate.test(new Pair<>(primaryActivity, secondaryActivity));
     }
 
@@ -77,10 +70,9 @@
      * Checks if the rule is applicable to the provided primary activity and secondary activity
      * intent.
      */
-    @SuppressLint("ClassVerificationFailure") // Only called by Extensions implementation on device.
     @RequiresApi(api = Build.VERSION_CODES.N)
-    public boolean matchesActivityIntentPair(@NonNull Activity primaryActivity,
-            @NonNull Intent secondaryActivityIntent) {
+    public boolean matchesActivityIntentPair(
+            @NonNull Activity primaryActivity, @NonNull Intent secondaryActivityIntent) {
         return mActivityIntentPredicate.test(new Pair<>(primaryActivity, secondaryActivityIntent));
     }
 
@@ -103,53 +95,46 @@
     }
 
     /**
-     * If there is an existing split with the same primary container, indicates whether the
-     * existing secondary container and all activities in it should be destroyed. Otherwise the new
-     * secondary will appear on top. Defaults to "true".
+     * If there is an existing split with the same primary container, indicates whether the existing
+     * secondary container and all activities in it should be destroyed. Otherwise the new secondary
+     * will appear on top. Defaults to "true".
      */
     public boolean shouldClearTop() {
         return mClearTop;
     }
 
-    /**
-     * Builder for {@link SplitPairRule}.
-     */
+    /** Builder for {@link SplitPairRule}. */
     public static final class Builder {
-        @NonNull
-        private final Predicate<Pair<Activity, Activity>> mActivityPairPredicate;
-        @NonNull
-        private final Predicate<Pair<Activity, Intent>> mActivityIntentPredicate;
-        @NonNull
-        private final Predicate<WindowMetrics> mParentWindowMetricsPredicate;
+        private final @NonNull Predicate<Pair<Activity, Activity>> mActivityPairPredicate;
+        private final @NonNull Predicate<Pair<Activity, Intent>> mActivityIntentPredicate;
+        private final @NonNull Predicate<WindowMetrics> mParentWindowMetricsPredicate;
+
         // Keep for backward compatibility
         @FloatRange(from = 0.0, to = 1.0)
         private float mSplitRatio;
+
         // Keep for backward compatibility
-        @SplitAttributes.ExtLayoutDirection
-        private int mLayoutDirection;
+        @SplitAttributes.ExtLayoutDirection private int mLayoutDirection;
         private SplitAttributes mDefaultSplitAttributes;
         private boolean mClearTop;
-        @SplitFinishBehavior
-        private int mFinishPrimaryWithSecondary;
-        @SplitFinishBehavior
-        private int mFinishSecondaryWithPrimary;
-        @Nullable
-        private String mTag;
+        @SplitFinishBehavior private int mFinishPrimaryWithSecondary;
+        @SplitFinishBehavior private int mFinishSecondaryWithPrimary;
+        private @Nullable String mTag;
 
         /**
-         * @deprecated Use {@link #Builder(Predicate, Predicate, Predicate)} starting with
-         * {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if
-         * {@link #Builder(Predicate, Predicate, Predicate)} can't be called on
-         * {@link WindowExtensions#VENDOR_API_LEVEL_1}.
+         * @deprecated Use {@link #Builder(Predicate, Predicate, Predicate)} starting with vendor
+         *     API level 2. Only used if {@link #Builder(Predicate, Predicate, Predicate)} can 't be
+         *     called on vendor API level 1.
          */
+        @RequiresVendorApiLevel(level = 1, deprecatedSince = 2)
         @Deprecated
         @RequiresApi(Build.VERSION_CODES.N)
-        public Builder(@NonNull java.util.function.Predicate<Pair<Activity, Activity>>
+        public Builder(
+                java.util.function.@NonNull Predicate<Pair<Activity, Activity>>
                         activityPairPredicate,
-                @NonNull java.util.function.Predicate<Pair<Activity, Intent>>
+                java.util.function.@NonNull Predicate<Pair<Activity, Intent>>
                         activityIntentPredicate,
-                @NonNull java.util.function.Predicate<WindowMetrics>
-                        parentWindowMetricsPredicate) {
+                java.util.function.@NonNull Predicate<WindowMetrics> parentWindowMetricsPredicate) {
             mActivityPairPredicate = activityPairPredicate::test;
             mActivityIntentPredicate = activityIntentPredicate::test;
             mParentWindowMetricsPredicate = parentWindowMetricsPredicate::test;
@@ -159,15 +144,16 @@
          * The {@link SplitPairRule} builder constructor
          *
          * @param activityPairPredicate the {@link Predicate} to verify if an {@link Activity} pair
-         *                              matches this rule
+         *     matches this rule
          * @param activityIntentPredicate the {@link Predicate} to verify if an ({@link Activity},
-         *                              {@link Intent}) pair matches this rule
+         *     {@link Intent}) pair matches this rule
          * @param parentWindowMetricsPredicate the {@link Predicate} to verify if the matched split
-         *                               pair is allowed to show adjacent to each other with the
-         *                               given parent {@link WindowMetrics}
-         * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+         *     pair is allowed to show adjacent to each other with the given parent {@link
+         *     WindowMetrics}
          */
-        public Builder(@NonNull Predicate<Pair<Activity, Activity>> activityPairPredicate,
+        @RequiresVendorApiLevel(level = 2)
+        public Builder(
+                @NonNull Predicate<Pair<Activity, Activity>> activityPairPredicate,
                 @NonNull Predicate<Pair<Activity, Intent>> activityIntentPredicate,
                 @NonNull Predicate<WindowMetrics> parentWindowMetricsPredicate) {
             mActivityPairPredicate = activityPairPredicate;
@@ -176,108 +162,116 @@
         }
 
         /**
-         * @deprecated Use {@link #setDefaultSplitAttributes(SplitAttributes)} starting with
-         * {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if
-         * {@link #setDefaultSplitAttributes(SplitAttributes)} can't be called on
-         * {@link WindowExtensions#VENDOR_API_LEVEL_1}. {@code splitRatio} will be translated to
-         * {@link SplitAttributes.SplitType.ExpandContainersSplitType} for value {@code 0.0} and
-         * {@code 1.0}, and {@link SplitAttributes.SplitType.RatioSplitType} for value with range
-         * (0.0, 1.0).
+         * @deprecated Use {@link #setDefaultSplitAttributes(SplitAttributes)} starting with vendor
+         *     API level 2. Only used if {@link #setDefaultSplitAttributes(SplitAttributes)} can't
+         *     be called on vendor API level 1. {@code splitRatio} will be translated to {@link
+         *     SplitAttributes.SplitType.ExpandContainersSplitType} for value {@code 0.0} and {@code
+         *     1.0}, and {@link SplitAttributes.SplitType.RatioSplitType} for value with range (0.0,
+         *     1.0).
          */
+        @RequiresVendorApiLevel(level = 1, deprecatedSince = 2)
         @Deprecated
-        @NonNull
-        public Builder setSplitRatio(@FloatRange(from = 0.0, to = 1.0) float splitRatio) {
+        public @NonNull Builder setSplitRatio(@FloatRange(from = 0.0, to = 1.0) float splitRatio) {
             mSplitRatio = splitRatio;
             return this;
         }
 
         /**
-         * @deprecated Use {@link #setDefaultSplitAttributes(SplitAttributes)} starting with
-         * {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if
-         * {@link #setDefaultSplitAttributes(SplitAttributes)} can't be called on
-         * {@link WindowExtensions#VENDOR_API_LEVEL_1}.
+         * @deprecated Use {@link #setDefaultSplitAttributes(SplitAttributes)} starting with vendor
+         *     API level 2. Only used if {@link #setDefaultSplitAttributes(SplitAttributes)} can't
+         *     be called on vendor API level 1.
          */
+        @RequiresVendorApiLevel(level = 1, deprecatedSince = 2)
         @Deprecated
-        @NonNull
-        public Builder setLayoutDirection(@SplitAttributes.ExtLayoutDirection int layoutDirection) {
+        public @NonNull Builder setLayoutDirection(
+                @SplitAttributes.ExtLayoutDirection int layoutDirection) {
             mLayoutDirection = layoutDirection;
             return this;
         }
 
         /**
-         * See {@link SplitPairRule#getDefaultSplitAttributes()} for reference.
-         * Overrides values if set in {@link #setSplitRatio(float)} and
-         * {@link #setLayoutDirection(int)}
-         *
-         * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+         * See {@link SplitPairRule#getDefaultSplitAttributes()} for reference. Overrides values if
+         * set in {@link #setSplitRatio(float)} and {@link #setLayoutDirection(int)}
          */
-        @NonNull
-        public Builder setDefaultSplitAttributes(@NonNull SplitAttributes attrs) {
+        @RequiresVendorApiLevel(level = 2)
+        public @NonNull Builder setDefaultSplitAttributes(@NonNull SplitAttributes attrs) {
             mDefaultSplitAttributes = attrs;
             return this;
         }
 
-        /** @deprecated To be removed with next developer preview. */
+        /**
+         * @deprecated To be removed with next developer preview.
+         */
         @Deprecated
-        @NonNull
-        public Builder setShouldFinishPrimaryWithSecondary(
+        public @NonNull Builder setShouldFinishPrimaryWithSecondary(
                 boolean finishPrimaryWithSecondary) {
             return this;
         }
 
-        /** @deprecated To be removed with next developer preview. */
+        /**
+         * @deprecated To be removed with next developer preview.
+         */
         @Deprecated
-        @NonNull
-        public Builder setShouldFinishSecondaryWithPrimary(boolean finishSecondaryWithPrimary) {
+        public @NonNull Builder setShouldFinishSecondaryWithPrimary(
+                boolean finishSecondaryWithPrimary) {
             return this;
         }
 
-        /** @see SplitPairRule#getFinishPrimaryWithSecondary() */
-        @NonNull
-        public Builder setFinishPrimaryWithSecondary(@SplitFinishBehavior int finishBehavior) {
+        /**
+         * @see SplitPairRule#getFinishPrimaryWithSecondary()
+         */
+        public @NonNull Builder setFinishPrimaryWithSecondary(
+                @SplitFinishBehavior int finishBehavior) {
             mFinishPrimaryWithSecondary = finishBehavior;
             return this;
         }
 
-        /** @see SplitPairRule#getFinishSecondaryWithPrimary() */
-        @NonNull
-        public Builder setFinishSecondaryWithPrimary(@SplitFinishBehavior int finishBehavior) {
+        /**
+         * @see SplitPairRule#getFinishSecondaryWithPrimary()
+         */
+        public @NonNull Builder setFinishSecondaryWithPrimary(
+                @SplitFinishBehavior int finishBehavior) {
             mFinishSecondaryWithPrimary = finishBehavior;
             return this;
         }
 
-        /** @see SplitPairRule#shouldClearTop() */
-        @NonNull
-        public Builder setShouldClearTop(boolean shouldClearTop) {
+        /**
+         * @see SplitPairRule#shouldClearTop()
+         */
+        public @NonNull Builder setShouldClearTop(boolean shouldClearTop) {
             mClearTop = shouldClearTop;
             return this;
         }
 
         /**
          * @see SplitPairRule#getTag()
-         * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
          */
-        @NonNull
-        public Builder setTag(@NonNull String tag) {
+        @RequiresVendorApiLevel(level = 2)
+        public @NonNull Builder setTag(@NonNull String tag) {
             mTag = Objects.requireNonNull(tag);
             return this;
         }
 
         /** Builds a new instance of {@link SplitPairRule}. */
-        @NonNull
-        public SplitPairRule build() {
+        public @NonNull SplitPairRule build() {
             // To provide compatibility with prior version of WM Jetpack library, where
             // #setDefaultAttributes hasn't yet been supported and thus would not be set.
-            mDefaultSplitAttributes = (mDefaultSplitAttributes != null)
-                    ? mDefaultSplitAttributes
-                    : new SplitAttributes.Builder()
-                            .setSplitType(createSplitTypeFromLegacySplitRatio(mSplitRatio))
-                            .setLayoutDirection(mLayoutDirection)
-                            .build();
-            return new SplitPairRule(mDefaultSplitAttributes,
-                    mFinishPrimaryWithSecondary, mFinishSecondaryWithPrimary,
-                    mClearTop, mActivityPairPredicate, mActivityIntentPredicate,
-                    mParentWindowMetricsPredicate, mTag);
+            mDefaultSplitAttributes =
+                    (mDefaultSplitAttributes != null)
+                            ? mDefaultSplitAttributes
+                            : new SplitAttributes.Builder()
+                                    .setSplitType(createSplitTypeFromLegacySplitRatio(mSplitRatio))
+                                    .setLayoutDirection(mLayoutDirection)
+                                    .build();
+            return new SplitPairRule(
+                    mDefaultSplitAttributes,
+                    mFinishPrimaryWithSecondary,
+                    mFinishSecondaryWithPrimary,
+                    mClearTop,
+                    mActivityPairPredicate,
+                    mActivityIntentPredicate,
+                    mParentWindowMetricsPredicate,
+                    mTag);
         }
     }
 
@@ -305,15 +299,19 @@
         return result;
     }
 
-    @NonNull
     @Override
-    public String toString() {
+    public @NonNull String toString() {
         return "SplitPairRule{"
-                + "mTag=" + getTag()
-                + ", mDefaultSplitAttributes=" + getDefaultSplitAttributes()
-                + ", mFinishPrimaryWithSecondary=" + mFinishPrimaryWithSecondary
-                + ", mFinishSecondaryWithPrimary=" + mFinishSecondaryWithPrimary
-                + ", mClearTop=" + mClearTop
+                + "mTag="
+                + getTag()
+                + ", mDefaultSplitAttributes="
+                + getDefaultSplitAttributes()
+                + ", mFinishPrimaryWithSecondary="
+                + mFinishPrimaryWithSecondary
+                + ", mFinishSecondaryWithPrimary="
+                + mFinishSecondaryWithPrimary
+                + ", mClearTop="
+                + mClearTop
                 + '}';
     }
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitPinRule.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitPinRule.java
new file mode 100644
index 0000000..63f254b
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitPinRule.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2023 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 androidx.window.extensions.embedding;
+
+import android.view.WindowMetrics;
+
+import androidx.window.extensions.RequiresVendorApiLevel;
+import androidx.window.extensions.core.util.function.Predicate;
+
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
+import java.util.Objects;
+
+/**
+ * Split configuration rules for keeping an {@link ActivityStack} in the split in a pin state to
+ * provide an isolated Activity navigation from the split. A pin state here is referring the {@link
+ * ActivityStack} to be fixed on top.
+ *
+ * @see ActivityEmbeddingComponent#pinTopActivityStack
+ */
+@RequiresVendorApiLevel(level = 5)
+public class SplitPinRule extends SplitRule {
+    /**
+     * Whether the rule should be applied whenever the parent Task satisfied the parent window
+     * metrics predicate. See {@link ActivityEmbeddingComponent#pinTopActivityStack}.
+     */
+    private final boolean mIsSticky;
+
+    SplitPinRule(
+            @NonNull SplitAttributes defaultSplitAttributes,
+            @NonNull Predicate<WindowMetrics> parentWindowMetricsPredicate,
+            boolean isSticky,
+            @Nullable String tag) {
+        super(parentWindowMetricsPredicate, defaultSplitAttributes, tag);
+        mIsSticky = isSticky;
+    }
+
+    /**
+     * Whether the rule is sticky. This configuration rule can only be applied once when possible.
+     * That is, the rule will be abandoned whenever the pinned {@link ActivityStack} no longer able
+     * to be split with another {@link ActivityStack} once the configuration of the parent Task is
+     * changed. Sets the rule to be sticky if the rule should be permanent until the {@link
+     * ActivityStack} explicitly unpin.
+     *
+     * @see ActivityEmbeddingComponent#pinTopActivityStack
+     */
+    public boolean isSticky() {
+        return mIsSticky;
+    }
+
+    /** Builder for {@link SplitPinRule}. */
+    public static final class Builder {
+        private final @NonNull SplitAttributes mDefaultSplitAttributes;
+        private final @NonNull Predicate<WindowMetrics> mParentWindowMetricsPredicate;
+        private boolean mIsSticky;
+        private @Nullable String mTag;
+
+        /**
+         * The {@link SplitPinRule} builder constructor.
+         *
+         * @param defaultSplitAttributes the default {@link SplitAttributes} to apply
+         * @param parentWindowMetricsPredicate the {@link Predicate} to verify if the pinned {@link
+         *     ActivityStack} and the one behind are allowed to show adjacent to each other with the
+         *     given parent {@link WindowMetrics}
+         */
+        public Builder(
+                @NonNull SplitAttributes defaultSplitAttributes,
+                @NonNull Predicate<WindowMetrics> parentWindowMetricsPredicate) {
+            mDefaultSplitAttributes = defaultSplitAttributes;
+            mParentWindowMetricsPredicate = parentWindowMetricsPredicate;
+        }
+
+        /**
+         * Sets the rule to be sticky.
+         *
+         * @see SplitPinRule#isSticky()
+         */
+        public @NonNull Builder setSticky(boolean isSticky) {
+            mIsSticky = isSticky;
+            return this;
+        }
+
+        /**
+         * @see SplitPinRule#getTag()
+         */
+        public @NonNull Builder setTag(@NonNull String tag) {
+            mTag = Objects.requireNonNull(tag);
+            return this;
+        }
+
+        /** Builds a new instance of {@link SplitPinRule}. */
+        public @NonNull SplitPinRule build() {
+            return new SplitPinRule(
+                    mDefaultSplitAttributes, mParentWindowMetricsPredicate, mIsSticky, mTag);
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof SplitPinRule)) return false;
+        SplitPinRule that = (SplitPinRule) o;
+        return super.equals(o) && mIsSticky == that.mIsSticky;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        result = 31 * result + (mIsSticky ? 1 : 0);
+        return result;
+    }
+
+    @Override
+    public @NonNull String toString() {
+        return "SplitPinRule{"
+                + "mTag="
+                + getTag()
+                + ", mDefaultSplitAttributes="
+                + getDefaultSplitAttributes()
+                + ", mIsSticky="
+                + mIsSticky
+                + '}';
+    }
+}
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitPlaceholderRule.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitPlaceholderRule.java
index 38b5451..ddb9cb2 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitPlaceholderRule.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitPlaceholderRule.java
@@ -18,7 +18,6 @@
 
 import static androidx.window.extensions.embedding.SplitAttributes.SplitType.createSplitTypeFromLegacySplitRatio;
 
-import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.content.Intent;
 import android.os.Build;
@@ -26,44 +25,39 @@
 
 import androidx.annotation.FloatRange;
 import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
-import androidx.window.extensions.WindowExtensions;
+import androidx.window.extensions.RequiresVendorApiLevel;
 import androidx.window.extensions.core.util.function.Predicate;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
- * Split configuration rules for split placeholders - activities used to occupy additional
- * available space on the side before the user selects content to show.
+ * Split configuration rules for split placeholders - activities used to occupy additional available
+ * space on the side before the user selects content to show.
  */
 public class SplitPlaceholderRule extends SplitRule {
-    @NonNull
-    private final Predicate<Activity> mActivityPredicate;
-    @NonNull
-    private final Predicate<Intent> mIntentPredicate;
-    @NonNull
-    private final Intent mPlaceholderIntent;
+    private final @NonNull Predicate<Activity> mActivityPredicate;
+    private final @NonNull Predicate<Intent> mIntentPredicate;
+    private final @NonNull Intent mPlaceholderIntent;
     private final boolean mIsSticky;
 
     /**
-     * Determines what happens with the primary container when the placeholder activity is
-     * finished in one of the containers in a split.
+     * Determines what happens with the primary container when the placeholder activity is finished
+     * in one of the containers in a split.
      */
-    @IntDef({
-            FINISH_ALWAYS,
-            FINISH_ADJACENT
-    })
+    @IntDef({FINISH_ALWAYS, FINISH_ADJACENT})
     @Retention(RetentionPolicy.SOURCE)
-    @interface SplitPlaceholderFinishBehavior{}
+    @interface SplitPlaceholderFinishBehavior {}
 
-    @SplitPlaceholderFinishBehavior
-    private final int mFinishPrimaryWithPlaceholder;
+    @SplitPlaceholderFinishBehavior private final int mFinishPrimaryWithPlaceholder;
 
-    SplitPlaceholderRule(@NonNull Intent placeholderIntent,
+    SplitPlaceholderRule(
+            @NonNull Intent placeholderIntent,
             @NonNull SplitAttributes defaultSplitAttributes,
             boolean isSticky,
             @SplitPlaceholderFinishBehavior int finishPrimaryWithPlaceholder,
@@ -79,19 +73,13 @@
         mPlaceholderIntent = placeholderIntent;
     }
 
-    /**
-     * Checks if the rule is applicable to the provided activity.
-     */
-    @SuppressLint("ClassVerificationFailure") // Only called by Extensions implementation on device.
+    /** Checks if the rule is applicable to the provided activity. */
     @RequiresApi(api = Build.VERSION_CODES.N)
     public boolean matchesActivity(@NonNull Activity activity) {
         return mActivityPredicate.test(activity);
     }
 
-    /**
-     * Checks if the rule is applicable to the provided activity intent.
-     */
-    @SuppressLint("ClassVerificationFailure") // Only called by Extensions implementation on device.
+    /** Checks if the rule is applicable to the provided activity intent. */
     @RequiresApi(api = Build.VERSION_CODES.N)
     public boolean matchesIntent(@NonNull Intent intent) {
         return mIntentPredicate.test(intent);
@@ -100,8 +88,7 @@
     /**
      * An {@link Intent} used by Extensions Sidecar to launch the placeholder when the space allows.
      */
-    @NonNull
-    public Intent getPlaceholderIntent() {
+    public @NonNull Intent getPlaceholderIntent() {
         return mPlaceholderIntent;
     }
 
@@ -114,11 +101,11 @@
     }
 
     /**
-     * @deprecated Use {@link #getFinishPrimaryWithPlaceholder()} instead starting with
-     * {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if
-     * {@link #getFinishPrimaryWithPlaceholder()} can't be called on
-     * {@link WindowExtensions#VENDOR_API_LEVEL_1}.
+     * @deprecated Use {@link #getFinishPrimaryWithPlaceholder()} instead starting with vendor API
+     *     level 2. Only used if {@link #getFinishPrimaryWithPlaceholder()} can't be called on
+     *     vendor API level 1.
      */
+    @RequiresVendorApiLevel(level = 1, deprecatedSince = 2)
     @Deprecated
     @SplitPlaceholderFinishBehavior
     public int getFinishPrimaryWithSecondary() {
@@ -128,52 +115,44 @@
     /**
      * Determines what happens with the primary container when all activities are finished in the
      * associated secondary/placeholder container.
-     *
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
      */
-    // TODO(b/238905747): Add api guard for extensions.
+    @RequiresVendorApiLevel(level = 2)
     @SplitPlaceholderFinishBehavior
     public int getFinishPrimaryWithPlaceholder() {
         return mFinishPrimaryWithPlaceholder;
     }
 
-    /**
-     * Builder for {@link SplitPlaceholderRule}.
-     */
+    /** Builder for {@link SplitPlaceholderRule}. */
     public static final class Builder {
-        @NonNull
-        private final Predicate<Activity> mActivityPredicate;
-        @NonNull
-        private final Predicate<Intent> mIntentPredicate;
-        @NonNull
-        private final Predicate<WindowMetrics> mParentWindowMetricsPredicate;
-        @NonNull
-        private final Intent mPlaceholderIntent;
+        private final @NonNull Predicate<Activity> mActivityPredicate;
+        private final @NonNull Predicate<Intent> mIntentPredicate;
+        private final @NonNull Predicate<WindowMetrics> mParentWindowMetricsPredicate;
+        private final @NonNull Intent mPlaceholderIntent;
+
         // Keep for backward compatibility
         @FloatRange(from = 0.0, to = 1.0)
         private float mSplitRatio;
+
         // Keep for backward compatibility
-        @SplitAttributes.ExtLayoutDirection
-        private int mLayoutDirection;
+        @SplitAttributes.ExtLayoutDirection private int mLayoutDirection;
         private SplitAttributes mDefaultSplitAttributes;
         private boolean mIsSticky = false;
-        @SplitPlaceholderFinishBehavior
-        private int mFinishPrimaryWithPlaceholder = FINISH_ALWAYS;
-        @Nullable
-        private String mTag;
+        @SplitPlaceholderFinishBehavior private int mFinishPrimaryWithPlaceholder = FINISH_ALWAYS;
+        private @Nullable String mTag;
 
         /**
          * @deprecated Use {@link #Builder(Intent, Predicate, Predicate, Predicate)} starting with
-         * {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if
-         * {@link #Builder(Intent, Predicate, Predicate, Predicate)} can't be called on
-         * {@link WindowExtensions#VENDOR_API_LEVEL_1}.
+         *     vendor API level 2. Only used if {@link #Builder(Intent, Predicate, Predicate,
+         *     Predicate)} can't be called on vendor API level 1.
          */
+        @RequiresVendorApiLevel(level = 1, deprecatedSince = 2)
         @Deprecated
         @RequiresApi(Build.VERSION_CODES.N)
-        public Builder(@NonNull Intent placeholderIntent,
-                @NonNull java.util.function.Predicate<Activity> activityPredicate,
-                @NonNull java.util.function.Predicate<Intent> intentPredicate,
-                @NonNull java.util.function.Predicate<WindowMetrics> parentWindowMetricsPredicate) {
+        public Builder(
+                @NonNull Intent placeholderIntent,
+                java.util.function.@NonNull Predicate<Activity> activityPredicate,
+                java.util.function.@NonNull Predicate<Intent> intentPredicate,
+                java.util.function.@NonNull Predicate<WindowMetrics> parentWindowMetricsPredicate) {
             mActivityPredicate = activityPredicate::test;
             mIntentPredicate = intentPredicate::test;
             mPlaceholderIntent = placeholderIntent;
@@ -182,19 +161,19 @@
 
         /**
          * The {@link SplitPlaceholderRule} Builder constructor
-         * @param placeholderIntent the placeholder activity to launch if
-         *                         {@link SplitPlaceholderRule#checkParentMetrics(WindowMetrics)}
-         *                         is satisfied
+         *
+         * @param placeholderIntent the placeholder activity to launch if {@link
+         *     SplitPlaceholderRule#checkParentMetrics(WindowMetrics)} is satisfied
          * @param activityPredicate the {@link Predicate} to verify if a given {@link Activity}
-         *                         matches the rule
-         * @param intentPredicate the {@link Predicate} to verify if a given {@link Intent}
-         *                         matches the rule
+         *     matches the rule
+         * @param intentPredicate the {@link Predicate} to verify if a given {@link Intent} matches
+         *     the rule
          * @param parentWindowMetricsPredicate the {@link Predicate} to verify if the placeholder
-         *                                     {@link Activity} should be launched with the given
-         *                                     {@link WindowMetrics}
-         * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+         *     {@link Activity} should be launched with the given {@link WindowMetrics}
          */
-        public Builder(@NonNull Intent placeholderIntent,
+        @RequiresVendorApiLevel(level = 2)
+        public Builder(
+                @NonNull Intent placeholderIntent,
                 @NonNull Predicate<Activity> activityPredicate,
                 @NonNull Predicate<Intent> intentPredicate,
                 @NonNull Predicate<WindowMetrics> parentWindowMetricsPredicate) {
@@ -205,61 +184,58 @@
         }
 
         /**
-         * @deprecated Use {@link #setDefaultSplitAttributes(SplitAttributes)} starting with
-         * {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if
-         * {@link #setDefaultSplitAttributes(SplitAttributes)} can't be called on
-         * {@link WindowExtensions#VENDOR_API_LEVEL_1}. {@code splitRatio} will be translated to
-         * @link SplitAttributes.SplitType.ExpandContainersSplitType} for value
-         * {@code 0.0} and {@code 1.0}, and {@link SplitAttributes.SplitType.RatioSplitType} for
-         * value with range (0.0, 1.0).
+         * @deprecated Use {@link #setDefaultSplitAttributes(SplitAttributes)} starting with vendor
+         *     API level 2. Only used if {@link #setDefaultSplitAttributes(SplitAttributes)} can't
+         *     be called on vendor API level 1. {@code splitRatio} will be translated to
+         * @link SplitAttributes.SplitType.ExpandContainersSplitType} for value {@code 0.0} and
+         *     {@code 1.0}, and {@link SplitAttributes.SplitType.RatioSplitType} for value with
+         *     range (0.0, 1.0).
          */
+        @RequiresVendorApiLevel(level = 1, deprecatedSince = 2)
         @Deprecated
-        @NonNull
-        public Builder setSplitRatio(@FloatRange(from = 0.0, to = 1.0) float splitRatio) {
+        public @NonNull Builder setSplitRatio(@FloatRange(from = 0.0, to = 1.0) float splitRatio) {
             mSplitRatio = splitRatio;
             return this;
         }
 
         /**
-         * @deprecated Use {@link #setDefaultSplitAttributes(SplitAttributes)} starting with
-         * {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if
-         * {@link #setDefaultSplitAttributes(SplitAttributes)} can't be called on
-         * {@link WindowExtensions#VENDOR_API_LEVEL_1}.
+         * @deprecated Use {@link #setDefaultSplitAttributes(SplitAttributes)} starting with vendor
+         *     API level 2. Only used if {@link #setDefaultSplitAttributes(SplitAttributes)} can't
+         *     be called on vendor API level 1.
          */
+        @RequiresVendorApiLevel(level = 1, deprecatedSince = 2)
         @Deprecated
-        @NonNull
-        public Builder setLayoutDirection(@SplitAttributes.ExtLayoutDirection int layoutDirection) {
+        public @NonNull Builder setLayoutDirection(
+                @SplitAttributes.ExtLayoutDirection int layoutDirection) {
             mLayoutDirection = layoutDirection;
             return this;
         }
 
         /**
-         * See {@link SplitPlaceholderRule#getDefaultSplitAttributes()} for reference.
-         * Overrides values if set in {@link #setSplitRatio(float)} and
-         * {@link #setLayoutDirection(int)}
-         *
-         * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+         * See {@link SplitPlaceholderRule#getDefaultSplitAttributes()} for reference. Overrides
+         * values if set in {@link #setSplitRatio(float)} and {@link #setLayoutDirection(int)}
          */
-        @NonNull
-        public Builder setDefaultSplitAttributes(@NonNull SplitAttributes attrs) {
+        @RequiresVendorApiLevel(level = 2)
+        public @NonNull Builder setDefaultSplitAttributes(@NonNull SplitAttributes attrs) {
             mDefaultSplitAttributes = attrs;
             return this;
         }
 
-        /** @see SplitPlaceholderRule#isSticky() */
-        @NonNull
-        public Builder setSticky(boolean sticky) {
+        /**
+         * @see SplitPlaceholderRule#isSticky()
+         */
+        public @NonNull Builder setSticky(boolean sticky) {
             mIsSticky = sticky;
             return this;
         }
 
         /**
          * @deprecated Use SplitPlaceholderRule#setFinishPrimaryWithPlaceholder(int)} starting with
-         * {@link WindowExtensions#VENDOR_API_LEVEL_2}.
+         *     vendor API level 2.
          */
+        @RequiresVendorApiLevel(level = 1, deprecatedSince = 2)
         @Deprecated
-        @NonNull
-        public Builder setFinishPrimaryWithSecondary(
+        public @NonNull Builder setFinishPrimaryWithSecondary(
                 @SplitPlaceholderFinishBehavior int finishBehavior) {
             if (finishBehavior == FINISH_NEVER) {
                 finishBehavior = FINISH_ALWAYS;
@@ -269,11 +245,9 @@
 
         /**
          * @see SplitPlaceholderRule#getFinishPrimaryWithPlaceholder()
-         * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
          */
-        // TODO(b/238905747): Add api guard for extensions.
-        @NonNull
-        public Builder setFinishPrimaryWithPlaceholder(
+        @RequiresVendorApiLevel(level = 2)
+        public @NonNull Builder setFinishPrimaryWithPlaceholder(
                 @SplitPlaceholderFinishBehavior int finishBehavior) {
             mFinishPrimaryWithPlaceholder = finishBehavior;
             return this;
@@ -281,28 +255,33 @@
 
         /**
          * @see SplitPlaceholderRule#getTag()
-         * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
          */
-        @NonNull
-        public Builder setTag(@NonNull String tag) {
+        @RequiresVendorApiLevel(level = 2)
+        public @NonNull Builder setTag(@NonNull String tag) {
             mTag = Objects.requireNonNull(tag);
             return this;
         }
 
         /** Builds a new instance of {@link SplitPlaceholderRule}. */
-        @NonNull
-        public SplitPlaceholderRule build() {
+        public @NonNull SplitPlaceholderRule build() {
             // To provide compatibility with prior version of WM Jetpack library, where
             // #setDefaultAttributes hasn't yet been supported and thus would not be set.
-            mDefaultSplitAttributes = (mDefaultSplitAttributes != null)
-                    ? mDefaultSplitAttributes
-                    : new SplitAttributes.Builder()
-                            .setSplitType(createSplitTypeFromLegacySplitRatio(mSplitRatio))
-                            .setLayoutDirection(mLayoutDirection)
-                            .build();
-            return new SplitPlaceholderRule(mPlaceholderIntent, mDefaultSplitAttributes, mIsSticky,
-                    mFinishPrimaryWithPlaceholder, mActivityPredicate,
-                    mIntentPredicate, mParentWindowMetricsPredicate, mTag);
+            mDefaultSplitAttributes =
+                    (mDefaultSplitAttributes != null)
+                            ? mDefaultSplitAttributes
+                            : new SplitAttributes.Builder()
+                                    .setSplitType(createSplitTypeFromLegacySplitRatio(mSplitRatio))
+                                    .setLayoutDirection(mLayoutDirection)
+                                    .build();
+            return new SplitPlaceholderRule(
+                    mPlaceholderIntent,
+                    mDefaultSplitAttributes,
+                    mIsSticky,
+                    mFinishPrimaryWithPlaceholder,
+                    mActivityPredicate,
+                    mIntentPredicate,
+                    mParentWindowMetricsPredicate,
+                    mTag);
         }
     }
 
@@ -332,15 +311,19 @@
         return result;
     }
 
-    @NonNull
     @Override
-    public String toString() {
+    public @NonNull String toString() {
         return "SplitPlaceholderRule{"
-                + "mTag=" + getTag()
-                + ", mDefaultSplitAttributes=" + getDefaultSplitAttributes()
-                + ", mActivityPredicate=" + mActivityPredicate
-                + ", mIsSticky=" + mIsSticky
-                + ", mFinishPrimaryWithPlaceholder=" + mFinishPrimaryWithPlaceholder
+                + "mTag="
+                + getTag()
+                + ", mDefaultSplitAttributes="
+                + getDefaultSplitAttributes()
+                + ", mActivityPredicate="
+                + mActivityPredicate
+                + ", mIsSticky="
+                + mIsSticky
+                + ", mFinishPrimaryWithPlaceholder="
+                + mFinishPrimaryWithPlaceholder
                 + '}';
     }
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitRule.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitRule.java
index dd02b14..a072359 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitRule.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitRule.java
@@ -16,76 +16,76 @@
 
 package androidx.window.extensions.embedding;
 
-import android.annotation.SuppressLint;
 import android.os.Build;
 import android.view.WindowMetrics;
 
 import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
-import androidx.window.extensions.WindowExtensions;
+import androidx.window.extensions.RequiresVendorApiLevel;
 import androidx.window.extensions.core.util.function.Predicate;
 import androidx.window.extensions.embedding.SplitAttributes.SplitType;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
  * Split configuration rules for activities that are launched to side in a split. Define when an
- * activity that was launched in a side container from another activity should be shown
- * adjacent or on top of it, as well as the visual properties of the split. Can be applied to
- * new activities started from the same process automatically by the embedding implementation on
- * the device.
+ * activity that was launched in a side container from another activity should be shown adjacent or
+ * on top of it, as well as the visual properties of the split. Can be applied to new activities
+ * started from the same process automatically by the embedding implementation on the device.
  */
 public abstract class SplitRule extends EmbeddingRule {
-    @NonNull
-    private final Predicate<WindowMetrics> mParentWindowMetricsPredicate;
+    private final @NonNull Predicate<WindowMetrics> mParentWindowMetricsPredicate;
 
-    @NonNull
-    private final SplitAttributes mDefaultSplitAttributes;
+    private final @NonNull SplitAttributes mDefaultSplitAttributes;
 
     /**
      * Never finish the associated container.
+     *
      * @see SplitFinishBehavior
      */
     public static final int FINISH_NEVER = 0;
+
     /**
      * Always finish the associated container independent of the current presentation mode.
+     *
      * @see SplitFinishBehavior
      */
     public static final int FINISH_ALWAYS = 1;
+
     /**
      * Only finish the associated container when displayed adjacent to the one being finished. Does
      * not finish the associated one when containers are stacked on top of each other.
+     *
      * @see SplitFinishBehavior
      */
     public static final int FINISH_ADJACENT = 2;
 
     /**
-     * Determines what happens with the associated container when all activities are finished in
-     * one of the containers in a split.
-     * <p>
-     * For example, given that {@link SplitPairRule#getFinishPrimaryWithSecondary()} is
-     * {@link #FINISH_ADJACENT} and secondary container finishes. The primary associated
-     * container is finished if it's shown adjacent to the secondary container. The primary
-     * associated container is not finished if it occupies entire task bounds.</p>
+     * Determines what happens with the associated container when all activities are finished in one
+     * of the containers in a split.
+     *
+     * <p>For example, given that {@link SplitPairRule#getFinishPrimaryWithSecondary()} is {@link
+     * #FINISH_ADJACENT} and secondary container finishes. The primary associated container is
+     * finished if it's shown adjacent to the secondary container. The primary associated container
+     * is not finished if it occupies entire task bounds.
      *
      * @see SplitPairRule#getFinishPrimaryWithSecondary()
      * @see SplitPairRule#getFinishSecondaryWithPrimary()
      * @see SplitPlaceholderRule#getFinishPrimaryWithSecondary()
      */
-    @IntDef({
-            FINISH_NEVER,
-            FINISH_ALWAYS,
-            FINISH_ADJACENT
-    })
+    @IntDef({FINISH_NEVER, FINISH_ALWAYS, FINISH_ADJACENT})
     @Retention(RetentionPolicy.SOURCE)
     @interface SplitFinishBehavior {}
 
-    SplitRule(@NonNull Predicate<WindowMetrics> parentWindowMetricsPredicate,
-            @NonNull SplitAttributes defaultSplitAttributes, @Nullable String tag) {
+    SplitRule(
+            @NonNull Predicate<WindowMetrics> parentWindowMetricsPredicate,
+            @NonNull SplitAttributes defaultSplitAttributes,
+            @Nullable String tag) {
         super(tag);
         mParentWindowMetricsPredicate = parentWindowMetricsPredicate;
         mDefaultSplitAttributes = defaultSplitAttributes;
@@ -93,28 +93,27 @@
 
     /**
      * Checks whether the parent window satisfied the dimensions and aspect ratios requirements
-     * specified in the {@link androidx.window.embedding.SplitRule}, which are
-     * {@link androidx.window.embedding.SplitRule#minWidthDp},
-     * {@link androidx.window.embedding.SplitRule#minHeightDp},
-     * {@link androidx.window.embedding.SplitRule#minSmallestWidthDp},
-     * {@link androidx.window.embedding.SplitRule#maxAspectRatioInPortrait} and
-     * {@link androidx.window.embedding.SplitRule#maxAspectRatioInLandscape}.
+     * specified in the {@link androidx.window.embedding.SplitRule}, which are {@link
+     * androidx.window.embedding.SplitRule#minWidthDp}, {@link
+     * androidx.window.embedding.SplitRule#minHeightDp}, {@link
+     * androidx.window.embedding.SplitRule#minSmallestWidthDp}, {@link
+     * androidx.window.embedding.SplitRule#maxAspectRatioInPortrait} and {@link
+     * androidx.window.embedding.SplitRule#maxAspectRatioInLandscape}.
      *
      * @param parentMetrics the {@link WindowMetrics} of the parent window.
      * @return whether the parent window satisfied the {@link SplitRule} requirements.
      */
-    @SuppressLint("ClassVerificationFailure") // Only called by Extensions implementation on device.
     @RequiresApi(api = Build.VERSION_CODES.N)
     public boolean checkParentMetrics(@NonNull WindowMetrics parentMetrics) {
         return mParentWindowMetricsPredicate.test(parentMetrics);
     }
 
     /**
-     * @deprecated Use {@link #getDefaultSplitAttributes()} instead starting with
-     * {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if
-     * {@link #getDefaultSplitAttributes()} can't be called on
-     * {@link WindowExtensions#VENDOR_API_LEVEL_1}.
+     * @deprecated Use {@link #getDefaultSplitAttributes()} instead starting with vendor API level
+     *     2. Only used if {@link #getDefaultSplitAttributes()} can't be called on vendor API level
+     *     1.
      */
+    @RequiresVendorApiLevel(level = 1, deprecatedSince = 2)
     @Deprecated
     public float getSplitRatio() {
         final SplitType splitType = mDefaultSplitAttributes.getSplitType();
@@ -126,11 +125,11 @@
     }
 
     /**
-     * @deprecated Use {@link #getDefaultSplitAttributes()} instead starting with
-     * {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if
-     * {@link #getDefaultSplitAttributes()} can't be called on
-     * {@link WindowExtensions#VENDOR_API_LEVEL_1}.
+     * @deprecated Use {@link #getDefaultSplitAttributes()} instead starting with vendor API level
+     *     2. Only used if {@link #getDefaultSplitAttributes()} can't be called on vendor API level
+     *     1.
      */
+    @RequiresVendorApiLevel(level = 1, deprecatedSince = 2)
     @Deprecated
     @SplitAttributes.ExtLayoutDirection
     public int getLayoutDirection() {
@@ -138,13 +137,11 @@
     }
 
     /**
-     * Returns the default {@link SplitAttributes} which is applied if
-     * {@link #checkParentMetrics(WindowMetrics)} is {@code true}.
-     *
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
+     * Returns the default {@link SplitAttributes} which is applied if {@link
+     * #checkParentMetrics(WindowMetrics)} is {@code true}.
      */
-    @NonNull
-    public SplitAttributes getDefaultSplitAttributes() {
+    @RequiresVendorApiLevel(level = 2)
+    public @NonNull SplitAttributes getDefaultSplitAttributes() {
         return mDefaultSplitAttributes;
     }
 
@@ -166,12 +163,13 @@
         return result;
     }
 
-    @NonNull
     @Override
-    public String toString() {
+    public @NonNull String toString() {
         return "SplitRule{"
-                + "mTag=" + getTag()
-                + ", mDefaultSplitAttributes=" + mDefaultSplitAttributes
+                + "mTag="
+                + getTag()
+                + ", mDefaultSplitAttributes="
+                + mDefaultSplitAttributes
                 + '}';
     }
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/WindowAttributes.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/WindowAttributes.java
new file mode 100644
index 0000000..9275c9a
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/WindowAttributes.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2023 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 androidx.window.extensions.embedding;
+
+import androidx.annotation.IntDef;
+import androidx.window.extensions.RequiresVendorApiLevel;
+
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/** The attributes of the embedded Activity Window. */
+public final class WindowAttributes {
+
+    /**
+     * The dim effect is applying on the {@link ActivityStack} of the Activity window when needed.
+     * If the {@link ActivityStack} is not expanded to fill the parent container, the dim effect is
+     * applying only on the {@link ActivityStack} of the requested Activity.
+     */
+    public static final int DIM_AREA_ON_ACTIVITY_STACK = 1;
+
+    /**
+     * The dim effect is applying on the area of the whole Task when needed. If the embedded
+     * transparent activity is split and displayed side-by-side with another activity, the dim
+     * effect is applying on the Task, which across over the two {@link ActivityStack}s.
+     */
+    public static final int DIM_AREA_ON_TASK = 2;
+
+    @IntDef({DIM_AREA_ON_ACTIVITY_STACK, DIM_AREA_ON_TASK})
+    @Retention(RetentionPolicy.SOURCE)
+    @interface DimAreaBehavior {}
+
+    @DimAreaBehavior private final int mDimAreaBehavior;
+
+    /**
+     * The {@link WindowAttributes} constructor.
+     *
+     * @param dimAreaBehavior the type of area that the dim layer is applying.
+     */
+    @RequiresVendorApiLevel(level = 5)
+    public WindowAttributes(@DimAreaBehavior int dimAreaBehavior) {
+        mDimAreaBehavior = dimAreaBehavior;
+    }
+
+    /**
+     * Returns the {@link DimAreaBehavior} to use when dim behind the Activity window is needed.
+     *
+     * @return The dim area behavior.
+     */
+    @DimAreaBehavior
+    @RequiresVendorApiLevel(level = 5)
+    public int getDimAreaBehavior() {
+        return mDimAreaBehavior;
+    }
+
+    @Override
+    public boolean equals(@Nullable Object obj) {
+        if (this == obj) return true;
+        if (obj == null || !(obj instanceof WindowAttributes)) return false;
+        final WindowAttributes other = (WindowAttributes) obj;
+        return mDimAreaBehavior == other.getDimAreaBehavior();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mDimAreaBehavior);
+    }
+
+    @Override
+    public @NonNull String toString() {
+        return "dimAreaBehavior=" + mDimAreaBehavior;
+    }
+}
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/WindowMetricsCompat.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/WindowMetricsCompat.java
new file mode 100644
index 0000000..2d84874
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/WindowMetricsCompat.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2023 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 androidx.window.extensions.embedding;
+
+import android.os.Build;
+import android.view.WindowMetrics;
+
+import androidx.annotation.RequiresApi;
+
+import org.jspecify.annotations.NonNull;
+
+/** A helper class to access {@link WindowMetrics#toString()} with compatibility. */
+class WindowMetricsCompat {
+    private WindowMetricsCompat() {}
+
+    static @NonNull String toString(@NonNull WindowMetrics windowMetrics) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+            // WindowMetrics#toString is implemented in U.
+            return windowMetrics.toString();
+        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+            return Api30Impl.toString(windowMetrics);
+        }
+        // Should be safe since ActivityEmbedding is not enabled before R.
+        throw new UnsupportedOperationException("WindowMetrics didn't exist in R.");
+    }
+
+    @RequiresApi(30)
+    private static final class Api30Impl {
+        static @NonNull String toString(@NonNull WindowMetrics windowMetrics) {
+            return WindowMetrics.class.getSimpleName()
+                    + ":{"
+                    + "bounds="
+                    + windowMetrics.getBounds()
+                    + ", windowInsets="
+                    + windowMetrics.getWindowInsets()
+                    + "}";
+        }
+    }
+}
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/DisplayFeature.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/DisplayFeature.java
index 32b0fa1..a00639d 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/DisplayFeature.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/DisplayFeature.java
@@ -18,19 +18,16 @@
 
 import android.graphics.Rect;
 
-import androidx.annotation.NonNull;
+import org.jspecify.annotations.NonNull;
 
-/**
- * Description of a physical feature on the display.
- */
+/** Description of a physical feature on the display. */
 public interface DisplayFeature {
 
     /**
-     * The bounding rectangle of the feature within the application window
-     * in the window coordinate space.
+     * The bounding rectangle of the feature within the application window in the window coordinate
+     * space.
      *
      * @return bounds of display feature.
      */
-    @NonNull
-    Rect getBounds();
+    @NonNull Rect getBounds();
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/DisplayFoldFeature.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/DisplayFoldFeature.java
new file mode 100644
index 0000000..71be524
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/DisplayFoldFeature.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 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 androidx.window.extensions.layout;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.os.Build;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.RestrictTo;
+import androidx.window.extensions.RequiresVendorApiLevel;
+import androidx.window.extensions.core.util.function.Consumer;
+import androidx.window.extensions.util.SetUtilApi23;
+
+import org.jspecify.annotations.NonNull;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Represents a fold on a display that may intersect a window. The presence of a fold does not imply
+ * that it intersects the window an {@link android.app.Activity} is running in. For example, on a
+ * device that can fold like a book and has an outer screen, the fold should be reported regardless
+ * of the folding state, or which screen is on to indicate that there may be a fold when the user
+ * opens the device.
+ *
+ * @see WindowLayoutComponent#addWindowLayoutInfoListener(Context, Consumer) to listen to features
+ *     that affect the window.
+ */
+public final class DisplayFoldFeature {
+
+    /**
+     * The type of fold is unknown. This is here for compatibility reasons if a new type is added,
+     * and cannot be reported to an incompatible application.
+     */
+    public static final int TYPE_UNKNOWN = 0;
+
+    /** The type of fold is a physical hinge separating two display panels. */
+    public static final int TYPE_HINGE = 1;
+
+    /** The type of fold is a screen that folds from 0-180. */
+    public static final int TYPE_SCREEN_FOLD_IN = 2;
+
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {TYPE_UNKNOWN, TYPE_HINGE, TYPE_SCREEN_FOLD_IN})
+    public @interface FoldType {}
+
+    /** The fold supports the half opened state. */
+    public static final int FOLD_PROPERTY_SUPPORTS_HALF_OPENED = 1;
+
+    @Target(ElementType.TYPE_USE)
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {FOLD_PROPERTY_SUPPORTS_HALF_OPENED})
+    public @interface FoldProperty {}
+
+    @FoldType private final int mType;
+
+    private final Set<@FoldProperty Integer> mProperties;
+
+    /**
+     * Creates an instance of [FoldDisplayFeature].
+     *
+     * @param type the type of fold, either [FoldDisplayFeature.TYPE_HINGE] or
+     *     [FoldDisplayFeature.TYPE_FOLDABLE_SCREEN]
+     */
+    DisplayFoldFeature(@FoldType int type, @NonNull Set<@FoldProperty Integer> properties) {
+        mType = type;
+        if (Build.VERSION.SDK_INT >= 23) {
+            mProperties = SetUtilApi23.createSet();
+        } else {
+            mProperties = new HashSet<>();
+        }
+        mProperties.addAll(properties);
+    }
+
+    /** Returns the type of fold that is either a hinge or a fold. */
+    @RequiresVendorApiLevel(level = 6)
+    @FoldType
+    public int getType() {
+        return mType;
+    }
+
+    /** Returns {@code true} if the fold has the given property, {@code false} otherwise. */
+    @RequiresVendorApiLevel(level = 6)
+    public boolean hasProperty(@FoldProperty int property) {
+        return mProperties.contains(property);
+    }
+
+    /** Returns {@code true} if the fold has all the given properties, {@code false} otherwise. */
+    @RequiresVendorApiLevel(level = 6)
+    public boolean hasProperties(@FoldProperty int @NonNull ... properties) {
+        for (int i = 0; i < properties.length; i++) {
+            if (!mProperties.contains(properties[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        DisplayFoldFeature that = (DisplayFoldFeature) o;
+        return mType == that.mType && Objects.equals(mProperties, that.mProperties);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mType, mProperties);
+    }
+
+    @Override
+    public @NonNull String toString() {
+        return "ScreenFoldDisplayFeature{mType=" + mType + ", mProperties=" + mProperties + '}';
+    }
+
+    /** A builder to construct an instance of {@link DisplayFoldFeature}. */
+    public static final class Builder {
+
+        @FoldType private int mType;
+
+        private Set<@FoldProperty Integer> mProperties;
+
+        /**
+         * Constructs a builder to create an instance of {@link DisplayFoldFeature}.
+         *
+         * @param type the type of hinge for the {@link DisplayFoldFeature}.
+         * @see DisplayFoldFeature.FoldType
+         */
+        @RequiresVendorApiLevel(level = 6)
+        public Builder(@FoldType int type) {
+            mType = type;
+            if (Build.VERSION.SDK_INT >= 23) {
+                mProperties = SetUtilApi23.createSet();
+            } else {
+                mProperties = new HashSet<>();
+            }
+        }
+
+        /** Add a property to the set of properties exposed by {@link DisplayFoldFeature}. */
+        @SuppressLint("MissingGetterMatchingBuilder")
+        @RequiresVendorApiLevel(level = 6)
+        public @NonNull Builder addProperty(@FoldProperty int property) {
+            mProperties.add(property);
+            return this;
+        }
+
+        /**
+         * Add a list of properties to the set of properties exposed by {@link DisplayFoldFeature}.
+         */
+        @SuppressLint("MissingGetterMatchingBuilder")
+        @RequiresVendorApiLevel(level = 6)
+        public @NonNull Builder addProperties(@FoldProperty int @NonNull ... properties) {
+            for (int i = 0; i < properties.length; i++) {
+                mProperties.add(properties[i]);
+            }
+            return this;
+        }
+
+        /** Clear the properties in the builder. */
+        @RequiresVendorApiLevel(level = 6)
+        public @NonNull Builder clearProperties() {
+            mProperties.clear();
+            return this;
+        }
+
+        /** Returns an instance of {@link DisplayFoldFeature}. */
+        @RequiresVendorApiLevel(level = 6)
+        public @NonNull DisplayFoldFeature build() {
+            return new DisplayFoldFeature(mType, mProperties);
+        }
+    }
+}
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/FoldingFeature.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/FoldingFeature.java
index 9f95510..ff89f3f 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/FoldingFeature.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/FoldingFeature.java
@@ -19,77 +19,64 @@
 import android.graphics.Rect;
 
 import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
+
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * A feature that describes a fold in a flexible display
- * or a hinge between two physical display panels.
+ * A feature that describes a fold in a flexible display or a hinge between two physical display
+ * panels.
  */
 public class FoldingFeature implements DisplayFeature {
 
-    /**
-     * A fold in the flexible screen without a physical gap.
-     */
+    /** A fold in the flexible screen without a physical gap. */
     public static final int TYPE_FOLD = 1;
 
-    /**
-     * A physical separation with a hinge that allows two display panels to fold.
-     */
+    /** A physical separation with a hinge that allows two display panels to fold. */
     public static final int TYPE_HINGE = 2;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({
-            TYPE_FOLD,
-            TYPE_HINGE,
+        TYPE_FOLD,
+        TYPE_HINGE,
     })
-    @interface Type{}
+    @interface Type {}
 
     /**
      * The foldable device's hinge is completely open, the screen space that is presented to the
-     * user is flat. See the
-     * <a href="https://developer.android.com/guide/topics/ui/foldables#postures">Posture</a>
-     * section in the official documentation for visual samples and references.
+     * user is flat. See the <a
+     * href="https://developer.android.com/guide/topics/ui/foldables#postures">Posture</a> section
+     * in the official documentation for visual samples and references.
      */
     public static final int STATE_FLAT = 1;
 
     /**
      * The foldable device's hinge is in an intermediate position between opened and closed state,
      * there is a non-flat angle between parts of the flexible screen or between physical screen
-     * panels. See the
-     * <a href="https://developer.android.com/guide/topics/ui/foldables#postures">Posture</a>
-     * section in the official documentation for visual samples and references.
+     * panels. See the <a
+     * href="https://developer.android.com/guide/topics/ui/foldables#postures">Posture</a> section
+     * in the official documentation for visual samples and references.
      */
     public static final int STATE_HALF_OPENED = 2;
 
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
-            STATE_HALF_OPENED,
-            STATE_FLAT
-    })
+    @IntDef({STATE_HALF_OPENED, STATE_FLAT})
     @interface State {}
 
     /**
-     * The bounding rectangle of the feature within the application window in the window
-     * coordinate space.
+     * The bounding rectangle of the feature within the application window in the window coordinate
+     * space.
      */
-    @NonNull
-    private final Rect mBounds;
+    private final @NonNull Rect mBounds;
 
-    /**
-     * The physical type of the feature.
-     */
-    @Type
-    private final int mType;
+    /** The physical type of the feature. */
+    @Type private final int mType;
 
-    /**
-     * The state of the feature.
-     */
-    @State
-    private final int mState;
+    /** The state of the feature. */
+    @State private final int mState;
 
     public FoldingFeature(@NonNull Rect bounds, @Type int type, @State int state) {
         validateFeatureBounds(bounds);
@@ -99,9 +86,8 @@
     }
 
     /** Gets the bounding rect of the display feature in window coordinate space. */
-    @NonNull
     @Override
-    public Rect getBounds() {
+    public @NonNull Rect getBounds() {
         return new Rect(mBounds);
     }
 
@@ -117,21 +103,20 @@
         return mState;
     }
 
-    /**
-     * Verifies the bounds of the folding feature.
-     */
+    /** Verifies the bounds of the folding feature. */
     private static void validateFeatureBounds(@NonNull Rect bounds) {
         if (bounds.width() == 0 && bounds.height() == 0) {
             throw new IllegalArgumentException("Bounds must be non zero.  Bounds: " + bounds);
         }
         if (bounds.left != 0 && bounds.top != 0) {
-            throw new IllegalArgumentException("Bounding rectangle must start at the top or "
-                    + "left window edge for folding features.  Bounds: " + bounds);
+            throw new IllegalArgumentException(
+                    "Bounding rectangle must start at the top or "
+                            + "left window edge for folding features.  Bounds: "
+                            + bounds);
         }
     }
 
-    @NonNull
-    private static String typeToString(int type) {
+    private static @NonNull String typeToString(int type) {
         switch (type) {
             case TYPE_FOLD:
                 return "FOLD";
@@ -142,8 +127,7 @@
         }
     }
 
-    @NonNull
-    private static String stateToString(int state) {
+    private static @NonNull String stateToString(int state) {
         switch (state) {
             case STATE_FLAT:
                 return "FLAT";
@@ -154,11 +138,15 @@
         }
     }
 
-    @NonNull
     @Override
-    public String toString() {
-        return "ExtensionDisplayFoldFeature { " + mBounds
-                + ", type=" + typeToString(getType()) + ", state=" + stateToString(mState) + " }";
+    public @NonNull String toString() {
+        return "ExtensionDisplayFoldFeature { "
+                + mBounds
+                + ", type="
+                + typeToString(getType())
+                + ", state="
+                + stateToString(mState)
+                + " }";
     }
 
     @Override
@@ -179,10 +167,7 @@
         return mBounds.equals(other.mBounds);
     }
 
-    /**
-     * Manually computes the hashCode for the {@link Rect} since it is not implemented
-     * on API 15
-     */
+    /** Manually computes the hashCode for the {@link Rect} since it is not implemented on API 15 */
     private static int hashBounds(Rect bounds) {
         int result = bounds.left;
         result = 31 * result + bounds.top;
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/SupportedWindowFeatures.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/SupportedWindowFeatures.java
new file mode 100644
index 0000000..e2c03a6
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/SupportedWindowFeatures.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 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 androidx.window.extensions.layout;
+
+import androidx.window.extensions.RequiresVendorApiLevel;
+
+import org.jspecify.annotations.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class to represent all the possible features that may interact with or appear in a window, that
+ * an application might want to respond to.
+ */
+public final class SupportedWindowFeatures {
+
+    private final List<DisplayFoldFeature> mDisplayFoldFeatureList;
+
+    private SupportedWindowFeatures(@NonNull List<DisplayFoldFeature> displayFoldFeatureList) {
+        mDisplayFoldFeatureList = new ArrayList<>(displayFoldFeatureList);
+    }
+
+    /** Returns the possible {@link DisplayFoldFeature}s that can be reported to an application. */
+    @RequiresVendorApiLevel(level = 6)
+    public @NonNull List<DisplayFoldFeature> getDisplayFoldFeatures() {
+        return new ArrayList<>(mDisplayFoldFeatureList);
+    }
+
+    /** A class to create a {@link SupportedWindowFeatures} instance. */
+    public static final class Builder {
+
+        private final List<DisplayFoldFeature> mDisplayFoldFeatures;
+
+        /** Creates a new instance of {@link Builder} */
+        @RequiresVendorApiLevel(level = 6)
+        public Builder(@NonNull List<DisplayFoldFeature> displayFoldFeatures) {
+            mDisplayFoldFeatures = new ArrayList<>(displayFoldFeatures);
+        }
+
+        /** Creates an instance of {@link SupportedWindowFeatures} with the features set. */
+        @RequiresVendorApiLevel(level = 6)
+        public @NonNull SupportedWindowFeatures build() {
+            return new SupportedWindowFeatures(mDisplayFoldFeatures);
+        }
+    }
+}
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutComponent.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutComponent.java
index 0b7c01f..35ae14a 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutComponent.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutComponent.java
@@ -18,81 +18,121 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.os.Bundle;
+import android.view.Display;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.UiContext;
+import androidx.window.extensions.RequiresVendorApiLevel;
 import androidx.window.extensions.WindowExtensions;
 import androidx.window.extensions.core.util.function.Consumer;
 
+import org.jspecify.annotations.NonNull;
+
 /**
  * The interface definition that will be used by the WindowManager library to get custom
- * OEM-provided information about the window that isn't covered by platform APIs. Exposes methods
- * to listen to changes in the {@link WindowLayoutInfo}. A {@link WindowLayoutInfo} contains a list
- * of {@link DisplayFeature}s.
- * <p>
- * Currently {@link FoldingFeature} is the only {@link DisplayFeature}. A {@link FoldingFeature}
- * exposes the state of a hinge and the relative bounds within the window. Developers can
- * optimize their UI to support a {@link FoldingFeature} by avoiding it and placing content in
- * relevant logical areas.
+ * OEM-provided information about the window that isn't covered by platform APIs. Exposes methods to
+ * listen to changes in the {@link WindowLayoutInfo}. A {@link WindowLayoutInfo} contains a list of
+ * {@link DisplayFeature}s.
+ *
+ * <p>Currently {@link FoldingFeature} is the only {@link DisplayFeature}. A {@link FoldingFeature}
+ * exposes the state of a hinge and the relative bounds within the window. Developers can optimize
+ * their UI to support a {@link FoldingFeature} by avoiding it and placing content in relevant
+ * logical areas.
  *
  * <p>This interface should be implemented by OEM and deployed to the target devices.
+ *
  * @see WindowExtensions#getWindowLayoutComponent()
  */
 public interface WindowLayoutComponent {
     /**
-     * @deprecated Use {@link #addWindowLayoutInfoListener(Context, Consumer)}
-     * starting with {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if
-     * {@link #addWindowLayoutInfoListener(Context, Consumer)} can't be
-     * called on {@link WindowExtensions#VENDOR_API_LEVEL_1}.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_1}
+     * @deprecated Use {@link #addWindowLayoutInfoListener(Context, Consumer)} starting with vendor
+     *     API level 2. Only used if {@link #addWindowLayoutInfoListener(Context, Consumer)} can't
+     *     be called on vendor API level 1.
      */
+    @RequiresVendorApiLevel(level = 1, deprecatedSince = 2)
     @Deprecated
-    void addWindowLayoutInfoListener(@NonNull Activity activity,
-            @NonNull java.util.function.Consumer<WindowLayoutInfo> consumer);
+    void addWindowLayoutInfoListener(
+            @NonNull Activity activity,
+            java.util.function.@NonNull Consumer<WindowLayoutInfo> consumer);
 
     /**
-     * @deprecated Use {@link #removeWindowLayoutInfoListener(Consumer)} starting with
-     * {@link WindowExtensions#VENDOR_API_LEVEL_2}. Only used if
-     * {@link #removeWindowLayoutInfoListener(Consumer)} can't be called on
-     * {@link WindowExtensions#VENDOR_API_LEVEL_1}.
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_1}
+     * @deprecated Use {@link #removeWindowLayoutInfoListener(Consumer)} starting with vendor API
+     *     level 2. Only used if {@link #removeWindowLayoutInfoListener(Consumer)} can't be called
+     *     on vendor API level 1.
      */
+    @RequiresVendorApiLevel(level = 1, deprecatedSince = 2)
     @Deprecated
     void removeWindowLayoutInfoListener(
-            @NonNull java.util.function.Consumer<WindowLayoutInfo> consumer);
+            java.util.function.@NonNull Consumer<WindowLayoutInfo> consumer);
 
     /**
-     * Adds a listener interested in receiving updates to {@link WindowLayoutInfo}.
-     * Use {@link WindowLayoutComponent#removeWindowLayoutInfoListener} to remove listener.
-     * <p>
-     * A {@link Context} or a Consumer instance can only be registered once.
-     * Registering the same {@link Context} or Consumer more than once will result in
-     * a noop.
+     * Adds a listener interested in receiving updates to {@link WindowLayoutInfo}. Use {@link
+     * WindowLayoutComponent#removeWindowLayoutInfoListener} to remove listener.
      *
-     * @param context a {@link UiContext} that corresponds to a window or an area on the
-     *                      screen - an {@link Activity}, a {@link Context} created with
-     *                      {@link Context#createWindowContext(Display, int , Bundle)}, or
-     *                      {@link android.inputmethodservice.InputMethodService}.
+     * <p>A {@link Context} or a Consumer instance can only be registered once. Registering the same
+     * {@link Context} or Consumer more than once will result in a noop.
+     *
+     * @param context a {@link UiContext} that corresponds to a window or an area on the screen - an
+     *     {@link Activity}, a {@link Context} created with {@link
+     *     Context#createWindowContext(Display, int, Bundle)}, or {@link
+     *     android.inputmethodservice.InputMethodService}.
      * @param consumer interested in receiving updates to {@link WindowLayoutInfo}
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
      */
-    // TODO(b/238905747): Add api guard for extensions.
+    @RequiresVendorApiLevel(level = 2)
     @SuppressWarnings("PairedRegistration")
     // The paired method for unregistering is also removeWindowLayoutInfoListener.
-    default void addWindowLayoutInfoListener(@NonNull @UiContext Context context,
-            @NonNull Consumer<WindowLayoutInfo> consumer) {
-        throw new UnsupportedOperationException("This method must not be called unless there is a"
-                + " corresponding override implementation on the device.");
+    default void addWindowLayoutInfoListener(
+            @UiContext @NonNull Context context, @NonNull Consumer<WindowLayoutInfo> consumer) {
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
     }
 
     /**
      * Removes a listener no longer interested in receiving updates.
      *
      * @param consumer no longer interested in receiving updates to {@link WindowLayoutInfo}
-     * Since {@link WindowExtensions#VENDOR_API_LEVEL_2}
      */
+    @RequiresVendorApiLevel(level = 2)
     default void removeWindowLayoutInfoListener(@NonNull Consumer<WindowLayoutInfo> consumer) {
-        throw new UnsupportedOperationException("This method must not be called unless there is a"
-                + " corresponding override implementation on the device.");
+        throw new UnsupportedOperationException(
+                "This method must not be called unless there is a"
+                        + " corresponding override implementation on the device.");
+    }
+
+    /**
+     * Returns the {@link SupportedWindowFeatures} for the device. This value will not change over
+     * time.
+     *
+     * @see WindowLayoutComponent#addWindowLayoutInfoListener(Context, Consumer) to register a
+     *     listener for features that impact the window.
+     */
+    @RequiresVendorApiLevel(level = 6)
+    default @NonNull SupportedWindowFeatures getSupportedWindowFeatures() {
+        throw new UnsupportedOperationException(
+                "This method will not be called unless there is a"
+                        + " corresponding override implementation on the device");
+    }
+
+    /**
+     * Returns the current {@link WindowLayoutInfo} for the given {@link Context}.
+     *
+     * <p>This API provides a convenient way to access the current {@link WindowLayoutInfo} without
+     * registering a listener via {@link #addWindowLayoutInfoListener(Context, Consumer)}. It
+     * simplifies the retrieval of {@link WindowLayoutInfo} in scenarios like {@link
+     * Activity#onCreate(Bundle)}.
+     *
+     * @param context a {@link Context} that corresponds to a window or an area on the screen. This
+     *     can be an {@link Activity}, a {@link Context} created with {@link
+     *     Context#createWindowContext(Display, int, Bundle)}, or an {@link
+     *     android.inputmethodservice.InputMethodService}.
+     * @return the current {@link WindowLayoutInfo} for the given {@link Context}.
+     */
+    @RequiresVendorApiLevel(level = 9)
+    default @NonNull WindowLayoutInfo getCurrentWindowLayoutInfo(
+            @UiContext @NonNull Context context) {
+        throw new UnsupportedOperationException(
+                "This method will not be called unless there is a"
+                        + " corresponding override implementation on the device");
     }
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutInfo.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutInfo.java
index 9041f0a..6e03764 100644
--- a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutInfo.java
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutInfo.java
@@ -16,40 +16,102 @@
 
 package androidx.window.extensions.layout;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
+import androidx.annotation.IntDef;
+import androidx.annotation.RestrictTo;
+import androidx.window.extensions.RequiresVendorApiLevel;
 
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
-/**
- * Contains information about the layout of display features within the window.
- */
+/** Contains information about the layout of display features within the window. */
 public class WindowLayoutInfo {
 
     /**
+     * A flag indicating the engagement mode includes a visual presentation. When this flag is set,
+     * it means the user can visually see the app UI on visible window.
+     */
+    public static final int ENGAGEMENT_MODE_FLAG_VISUALS_ON = 1 << 0;
+
+    /**
+     * A flag indicating the engagement mode includes an audio presentation. This can be set with or
+     * without {@link #ENGAGEMENT_MODE_FLAG_VISUALS_ON}. When set without, it signifies an
+     * audio-only experience.
+     */
+    public static final int ENGAGEMENT_MODE_FLAG_AUDIO_ON = 1 << 1;
+
+    /** Annotation for the engagement mode flags. */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(
+            flag = true,
+            value = {ENGAGEMENT_MODE_FLAG_VISUALS_ON, ENGAGEMENT_MODE_FLAG_AUDIO_ON})
+    public @interface EngagementModeFlags {}
+
+    private static final int DEFAULT_ENGAGEMENT_MODE =
+            ENGAGEMENT_MODE_FLAG_VISUALS_ON | ENGAGEMENT_MODE_FLAG_AUDIO_ON;
+
+    /**
      * List of display features within the window.
+     *
      * <p>NOTE: All display features returned with this container must be cropped to the application
      * window and reported within the coordinate space of the window that was provided by the app.
      */
-    @NonNull
-    private List<DisplayFeature> mDisplayFeatures;
+    private final @NonNull List<DisplayFeature> mDisplayFeatures;
 
-    public WindowLayoutInfo(@NonNull List<DisplayFeature> displayFeatures) {
-        mDisplayFeatures = Collections.unmodifiableList(displayFeatures);
-    }
+    /** The user engagement mode flags for this window. */
+    private final @EngagementModeFlags int mEngagementModeFlags;
 
     /**
-     * Gets the list of display features present within the window.
+     * @deprecated Use the {@link Builder} instead.
      */
-    @NonNull
-    public List<DisplayFeature> getDisplayFeatures() {
+    @RequiresVendorApiLevel(level = 1, deprecatedSince = 10)
+    @Deprecated
+    public WindowLayoutInfo(@NonNull List<DisplayFeature> displayFeatures) {
+        this(displayFeatures, DEFAULT_ENGAGEMENT_MODE);
+    }
+
+    private WindowLayoutInfo(
+            @NonNull List<DisplayFeature> displayFeatures,
+            @EngagementModeFlags int engagementModeFlags) {
+        mDisplayFeatures = Collections.unmodifiableList(displayFeatures);
+        mEngagementModeFlags = engagementModeFlags;
+    }
+
+    /** Gets the list of display features present within the window. */
+    public @NonNull List<DisplayFeature> getDisplayFeatures() {
         return mDisplayFeatures;
     }
 
-    @NonNull
+    /**
+     * Returns the current user engagement mode flags for this window.
+     *
+     * @return The current {@link EngagementModeFlags}.
+     */
+    @RequiresVendorApiLevel(level = 10)
+    @EngagementModeFlags
+    public int getEngagementModeFlags() {
+        return mEngagementModeFlags;
+    }
+
+    /**
+     * Checks if a specific flag is present in the engagement mode.
+     *
+     * @param flag The specific {@link EngagementModeFlags} flag to check for.
+     * @return {@code true} if the flag is set, {@code false} otherwise.
+     */
+    @RequiresVendorApiLevel(level = 10)
+    public boolean hasEngagementModeFlag(@EngagementModeFlags int flag) {
+        return (mEngagementModeFlags & flag) == flag;
+    }
+
     @Override
-    public String toString() {
+    public @NonNull String toString() {
         StringBuilder sb = new StringBuilder();
         sb.append("ExtensionWindowLayoutInfo { ExtensionDisplayFeatures[ ");
         for (int i = 0; i < mDisplayFeatures.size(); i = i + 1) {
@@ -58,7 +120,7 @@
                 sb.append(", ");
             }
         }
-        sb.append(" ] }");
+        sb.append(" ], ExtensionEngagementModeFlags=").append(mEngagementModeFlags).append(" }");
         return sb.toString();
     }
 
@@ -70,16 +132,55 @@
         if (!(obj instanceof WindowLayoutInfo)) {
             return false;
         }
-        final WindowLayoutInfo
-                other = (WindowLayoutInfo) obj;
-        if (mDisplayFeatures == null) {
-            return other.mDisplayFeatures == null;
-        }
-        return mDisplayFeatures.equals(other.mDisplayFeatures);
+        final WindowLayoutInfo other = (WindowLayoutInfo) obj;
+        return mDisplayFeatures.equals(other.mDisplayFeatures)
+                && mEngagementModeFlags == other.mEngagementModeFlags;
     }
 
     @Override
     public int hashCode() {
-        return mDisplayFeatures != null ? mDisplayFeatures.size() : 0;
+        return Objects.hash(mDisplayFeatures, mEngagementModeFlags);
+    }
+
+    /** Builder for {@link WindowLayoutInfo}. */
+    public static final class Builder {
+        private @NonNull List<DisplayFeature> mDisplayFeatures = Collections.emptyList();
+        private @EngagementModeFlags int mEngagementModeFlags = DEFAULT_ENGAGEMENT_MODE;
+
+        /** Creates a new instance of the {@link Builder}. */
+        public Builder() {}
+
+        /**
+         * Sets the list of {@link DisplayFeature} present within the window.
+         *
+         * @param displayFeatures the list of {@link DisplayFeature} to set.
+         * @return this {@link Builder} instance.
+         */
+        public @NonNull Builder setDisplayFeatures(@NonNull List<DisplayFeature> displayFeatures) {
+            mDisplayFeatures = displayFeatures;
+            return this;
+        }
+
+        /**
+         * Sets the current user engagement mode flags for this window.
+         *
+         * @param flags the {@link EngagementModeFlags} to set.
+         * @return this {@link Builder} instance.
+         */
+        @RequiresVendorApiLevel(level = 10)
+        public @NonNull Builder setEngagementModeFlags(@EngagementModeFlags int flags) {
+            mEngagementModeFlags = flags;
+            return this;
+        }
+
+        /**
+         * Builds a new {@link WindowLayoutInfo} instance.
+         *
+         * @return a new {@link WindowLayoutInfo} instance.
+         */
+        @RequiresVendorApiLevel(level = 10)
+        public @NonNull WindowLayoutInfo build() {
+            return new WindowLayoutInfo(mDisplayFeatures, mEngagementModeFlags);
+        }
     }
 }
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/util/SetCompat.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/util/SetCompat.java
new file mode 100644
index 0000000..2893727
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/util/SetCompat.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 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 androidx.window.extensions.util;
+
+import android.os.Build;
+import android.util.ArraySet;
+
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+
+import org.jspecify.annotations.NonNull;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A {@link Set} wrapper for compatibility. It {@link ArraySet} if it's available, and uses other
+ * compatible {@link Set} class, otherwise.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public final class SetCompat {
+
+    private SetCompat() {}
+
+    /**
+     * Creates a {@link Set}.
+     *
+     * @param <T> the type of the {@link Set}.
+     */
+    public static <T> @NonNull Set<T> create() {
+        if (Build.VERSION.SDK_INT < 23) {
+            return new HashSet<>();
+        } else {
+            return Api23Impl.create();
+        }
+    }
+
+    @RequiresApi(23)
+    private static class Api23Impl {
+
+        static <T> @NonNull Set<T> create() {
+            return new ArraySet<>();
+        }
+    }
+}
diff --git a/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/util/SetUtilApi23.java b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/util/SetUtilApi23.java
new file mode 100644
index 0000000..4c7f3ef
--- /dev/null
+++ b/window_extensions/java/window/extensions/extensions/src/main/java/androidx/window/extensions/util/SetUtilApi23.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 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 androidx.window.extensions.util;
+
+import android.util.ArraySet;
+
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+
+import org.jspecify.annotations.NonNull;
+
+import java.util.Set;
+
+/** Set utilities for creating working with newer {@link ArraySet} apis. */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@RequiresApi(23)
+public final class SetUtilApi23 {
+
+    private SetUtilApi23() {}
+
+    /** Creates an instance of {@link ArraySet}. */
+    public static <T> @NonNull Set<T> createSet() {
+        return new ArraySet<>();
+    }
+}
diff --git a/window_extensions/sources.txt b/window_extensions/sources.txt
index 2ccdd8c..1d1ddf1 100644
--- a/window_extensions/sources.txt
+++ b/window_extensions/sources.txt
@@ -5,18 +5,34 @@
 window/extensions/extensions/src/main/java/androidx/window/extensions/area/ExtensionWindowAreaStatus.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/area/WindowAreaComponent.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingComponent.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityEmbeddingOptionsProperties.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityRule.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStackAttributesCalculatorParams.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStackAttributes.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ActivityStack.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/AnimationBackground.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/AnimationParams.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/DividerAttributes.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/EmbeddedActivityWindowInfo.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/EmbeddingRule.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/ParentContainerInfo.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributesCalculatorParams.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitAttributes.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitInfo.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitPairRule.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitPinRule.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitPlaceholderRule.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/SplitRule.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/WindowAttributes.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/embedding/WindowMetricsCompat.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/layout/DisplayFeature.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/layout/DisplayFoldFeature.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/layout/FoldingFeature.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/layout/SupportedWindowFeatures.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutComponent.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/layout/WindowLayoutInfo.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/RequiresVendorApiLevel.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/util/SetCompat.java
+window/extensions/extensions/src/main/java/androidx/window/extensions/util/SetUtilApi23.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensions.java
 window/extensions/extensions/src/main/java/androidx/window/extensions/WindowExtensionsProvider.java