Merge "Deprecate TextInputService and related APIs." into androidx-main
diff --git a/appcompat/appcompat-resources/api/restricted_current.txt b/appcompat/appcompat-resources/api/restricted_current.txt
index 1278c5d..4b180e0 100644
--- a/appcompat/appcompat-resources/api/restricted_current.txt
+++ b/appcompat/appcompat-resources/api/restricted_current.txt
@@ -98,7 +98,7 @@
     method public int getColor(int) throws android.content.res.Resources.NotFoundException;
     method public android.content.res.ColorStateList! getColorStateList(int) throws android.content.res.Resources.NotFoundException;
     method public android.graphics.drawable.Drawable! getDrawable(int) throws android.content.res.Resources.NotFoundException;
-    method @RequiresApi(15) public android.graphics.drawable.Drawable! getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException;
+    method public android.graphics.drawable.Drawable! getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException;
     method public android.graphics.Movie! getMovie(int) throws android.content.res.Resources.NotFoundException;
     method public static boolean isCompatVectorFromResourcesEnabled();
     method public static void setCompatVectorFromResourcesEnabled(boolean);
diff --git a/appcompat/appcompat-resources/src/main/java/androidx/appcompat/graphics/drawable/AnimatedStateListDrawableCompat.java b/appcompat/appcompat-resources/src/main/java/androidx/appcompat/graphics/drawable/AnimatedStateListDrawableCompat.java
index 02e7743..ecff44f 100644
--- a/appcompat/appcompat-resources/src/main/java/androidx/appcompat/graphics/drawable/AnimatedStateListDrawableCompat.java
+++ b/appcompat/appcompat-resources/src/main/java/androidx/appcompat/graphics/drawable/AnimatedStateListDrawableCompat.java
@@ -30,7 +30,6 @@
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.StateSet;
@@ -396,9 +395,7 @@
             @SuppressLint("ObjectAnimatorBinding")
             final ObjectAnimator anim =
                     ObjectAnimator.ofInt(ad, "currentIndex", fromFrame, toFrame);
-            if (SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-                Compatibility.Api18Impl.setAutoCancel(anim, true);
-            }
+            anim.setAutoCancel(true);
             anim.setDuration(interp.getTotalDuration());
             anim.setInterpolator(interp);
             mHasReversibleFlag = hasReversibleFlag;
diff --git a/appcompat/appcompat-resources/src/main/java/androidx/appcompat/resources/Compatibility.java b/appcompat/appcompat-resources/src/main/java/androidx/appcompat/resources/Compatibility.java
index 1dd7e91..31658ce 100644
--- a/appcompat/appcompat-resources/src/main/java/androidx/appcompat/resources/Compatibility.java
+++ b/appcompat/appcompat-resources/src/main/java/androidx/appcompat/resources/Compatibility.java
@@ -16,12 +16,10 @@
 
 package androidx.appcompat.resources;
 
-import android.animation.ObjectAnimator;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.util.TypedValue;
 
 import androidx.annotation.DoNotInline;
 import androidx.annotation.NonNull;
@@ -70,29 +68,4 @@
             return Drawable.createFromXmlInner(r, parser, attrs, theme);
         }
     }
-
-    @RequiresApi(18)
-    public static class Api18Impl {
-        private Api18Impl() {
-            // This class is not instantiable.
-        }
-
-        @DoNotInline
-        public static void setAutoCancel(@NonNull ObjectAnimator objectAnimator, boolean cancel) {
-            objectAnimator.setAutoCancel(cancel);
-        }
-    }
-
-    @RequiresApi(15)
-    public static class Api15Impl {
-        private Api15Impl() {
-            // This class is not instantiable.
-        }
-
-        @DoNotInline
-        public static void getValueForDensity(@NonNull Resources resources, int id, int density,
-                @NonNull TypedValue outValue, boolean resolveRefs) {
-            resources.getValueForDensity(id, density, outValue, resolveRefs);
-        }
-    }
 }
diff --git a/appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/ResourcesWrapper.java b/appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/ResourcesWrapper.java
index b854a9e..1ddfb16 100644
--- a/appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/ResourcesWrapper.java
+++ b/appcompat/appcompat-resources/src/main/java/androidx/appcompat/widget/ResourcesWrapper.java
@@ -29,7 +29,6 @@
 import android.util.TypedValue;
 
 import androidx.annotation.RequiresApi;
-import androidx.appcompat.resources.Compatibility;
 import androidx.core.content.res.ResourcesCompat;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -156,7 +155,6 @@
     }
 
     @SuppressWarnings("deprecation")
-    @RequiresApi(15)
     @Override
     public Drawable getDrawableForDensity(int id, int density) throws NotFoundException {
         // If the developer only overrode the three-arg method, this will cause issues; however,
@@ -235,11 +233,10 @@
         mResources.getValue(id, outValue, resolveRefs);
     }
 
-    @RequiresApi(15)
     @Override
     public void getValueForDensity(int id, int density, TypedValue outValue, boolean resolveRefs)
             throws NotFoundException {
-        Compatibility.Api15Impl.getValueForDensity(mResources, id, density, outValue, resolveRefs);
+        mResources.getValueForDensity(id, density, outValue, resolveRefs);
     }
 
     @Override
diff --git a/appsearch/appsearch-play-services-storage/api/current.txt b/appsearch/appsearch-play-services-storage/api/current.txt
index 8d9c55f..77fe2c7 100644
--- a/appsearch/appsearch-play-services-storage/api/current.txt
+++ b/appsearch/appsearch-play-services-storage/api/current.txt
@@ -7,20 +7,24 @@
   }
 
   public static final class PlayServicesStorage.GlobalSearchContext {
+    method public java.util.concurrent.Executor getWorkerExecutor();
   }
 
   public static final class PlayServicesStorage.GlobalSearchContext.Builder {
     ctor public PlayServicesStorage.GlobalSearchContext.Builder(android.content.Context);
     method public androidx.appsearch.playservicesstorage.PlayServicesStorage.GlobalSearchContext build();
+    method public androidx.appsearch.playservicesstorage.PlayServicesStorage.GlobalSearchContext.Builder setWorkerExecutor(java.util.concurrent.Executor);
   }
 
   public static final class PlayServicesStorage.SearchContext {
     method public String getDatabaseName();
+    method public java.util.concurrent.Executor getWorkerExecutor();
   }
 
   public static final class PlayServicesStorage.SearchContext.Builder {
     ctor public PlayServicesStorage.SearchContext.Builder(android.content.Context, String);
     method public androidx.appsearch.playservicesstorage.PlayServicesStorage.SearchContext build();
+    method public androidx.appsearch.playservicesstorage.PlayServicesStorage.SearchContext.Builder setWorkerExecutor(java.util.concurrent.Executor);
   }
 
 }
diff --git a/appsearch/appsearch-play-services-storage/api/restricted_current.txt b/appsearch/appsearch-play-services-storage/api/restricted_current.txt
index 8d9c55f..77fe2c7 100644
--- a/appsearch/appsearch-play-services-storage/api/restricted_current.txt
+++ b/appsearch/appsearch-play-services-storage/api/restricted_current.txt
@@ -7,20 +7,24 @@
   }
 
   public static final class PlayServicesStorage.GlobalSearchContext {
+    method public java.util.concurrent.Executor getWorkerExecutor();
   }
 
   public static final class PlayServicesStorage.GlobalSearchContext.Builder {
     ctor public PlayServicesStorage.GlobalSearchContext.Builder(android.content.Context);
     method public androidx.appsearch.playservicesstorage.PlayServicesStorage.GlobalSearchContext build();
+    method public androidx.appsearch.playservicesstorage.PlayServicesStorage.GlobalSearchContext.Builder setWorkerExecutor(java.util.concurrent.Executor);
   }
 
   public static final class PlayServicesStorage.SearchContext {
     method public String getDatabaseName();
+    method public java.util.concurrent.Executor getWorkerExecutor();
   }
 
   public static final class PlayServicesStorage.SearchContext.Builder {
     ctor public PlayServicesStorage.SearchContext.Builder(android.content.Context, String);
     method public androidx.appsearch.playservicesstorage.PlayServicesStorage.SearchContext build();
+    method public androidx.appsearch.playservicesstorage.PlayServicesStorage.SearchContext.Builder setWorkerExecutor(java.util.concurrent.Executor);
   }
 
 }
diff --git a/appsearch/appsearch-play-services-storage/build.gradle b/appsearch/appsearch-play-services-storage/build.gradle
index 27b0fba..4fbcd2fa 100644
--- a/appsearch/appsearch-play-services-storage/build.gradle
+++ b/appsearch/appsearch-play-services-storage/build.gradle
@@ -50,4 +50,7 @@
 
 android {
     namespace "androidx.appsearch.playservicesstorage"
+     defaultConfig {
+        minSdkVersion 19
+    }
 }
diff --git a/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/GlobalSearchSessionImpl.java b/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/GlobalSearchSessionImpl.java
index dc693e8..61c90ac 100644
--- a/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/GlobalSearchSessionImpl.java
+++ b/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/GlobalSearchSessionImpl.java
@@ -54,12 +54,15 @@
 
     private final GlobalSearchClient mGmsClient;
     private final Features mFeatures;
+    private final Executor mExecutor;
 
     GlobalSearchSessionImpl(
             @NonNull GlobalSearchClient gmsClient,
-            @NonNull Features features) {
+            @NonNull Features features,
+            @NonNull Executor executor) {
         mGmsClient = Preconditions.checkNotNull(gmsClient);
         mFeatures = Preconditions.checkNotNull(features);
+        mExecutor = Preconditions.checkNotNull(executor);
     }
     @NonNull
     @Override
@@ -70,7 +73,8 @@
                 mGmsClient.getByDocumentId(packageName, databaseName,
                         RequestToGmsConverter.toGmsGetByDocumentIdRequest(request)),
                 result -> AppSearchResultToGmsConverter.gmsAppSearchBatchResultToJetpack(
-                        result, GenericDocumentToGmsConverter::toJetpackGenericDocument));
+                        result, GenericDocumentToGmsConverter::toJetpackGenericDocument),
+                mExecutor);
     }
 
     @NonNull
@@ -79,7 +83,7 @@
         com.google.android.gms.appsearch.SearchResults searchResults =
                 mGmsClient.search(queryExpression,
                         SearchSpecToGmsConverter.toGmsSearchSpec(searchSpec));
-        return new SearchResultsImpl(searchResults, searchSpec);
+        return new SearchResultsImpl(searchResults, mExecutor);
     }
 
     @NonNull
@@ -87,7 +91,8 @@
     public ListenableFuture reportSystemUsageAsync(
             @NonNull ReportSystemUsageRequest request) {
         Task flushTask = Tasks.forResult(null);
-        return AppSearchTaskFutures.toListenableFuture(flushTask, /* valueMapper= */ i-> i);
+        return AppSearchTaskFutures.toListenableFuture(flushTask, /* valueMapper= */ i-> i,
+                mExecutor);
     }
 
     @NonNull
@@ -96,7 +101,7 @@
             @NonNull String databaseName) {
         return AppSearchTaskFutures.toListenableFuture(
                 mGmsClient.getSchema(packageName, databaseName),
-                GetSchemaResponseToGmsConverter::toJetpackGetSchemaResponse);
+                GetSchemaResponseToGmsConverter::toJetpackGetSchemaResponse, mExecutor);
     }
 
     @NonNull
diff --git a/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/PlayServicesStorage.java b/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/PlayServicesStorage.java
index eab92f9..ca2bee2 100644
--- a/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/PlayServicesStorage.java
+++ b/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/PlayServicesStorage.java
@@ -26,10 +26,15 @@
 
 import com.google.android.gms.appsearch.AppSearch;
 import com.google.android.gms.appsearch.AppSearchClient;
+import com.google.android.gms.appsearch.AppSearchOptions;
 import com.google.android.gms.appsearch.GlobalSearchClient;
 import com.google.android.gms.tasks.Task;
 import com.google.common.util.concurrent.ListenableFuture;
 
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
 /**
  * An AppSearch storage system which stores data in the central AppSearch service in Google
  * Play Services.
@@ -43,10 +48,13 @@
     public static final class SearchContext {
         final Context mContext;
         final String mDatabaseName;
+        final Executor mExecutor;
 
-        SearchContext(@NonNull Context context, @NonNull String databaseName) {
+        SearchContext(@NonNull Context context, @NonNull String databaseName,
+                @NonNull Executor executor) {
             mContext = Preconditions.checkNotNull(context);
             mDatabaseName = Preconditions.checkNotNull(databaseName);
+            mExecutor = Preconditions.checkNotNull(executor);
         }
 
         /**
@@ -57,10 +65,26 @@
             return mDatabaseName;
         }
 
+        /**
+         * Returns the worker executor associated with {@link AppSearchSession}.
+         *
+         * 

If an executor is not provided to {@link Builder}, the AppSearch default executor will + * be returned. You should never cast the executor to + * {@link java.util.concurrent.ExecutorService} and call + * {@link ExecutorService#shutdownNow()}. It will cancel the futures it's returned. And + * since {@link Executor#execute} won't return anything, we will hang forever waiting for + * the execution. + */ + @NonNull + public Executor getWorkerExecutor() { + return mExecutor; + } + /** Builder for {@link SearchContext} objects. */ public static final class Builder { private final Context mContext; private final String mDatabaseName; + private Executor mExecutor; /** * Creates a {@link SearchContext.Builder} instance. @@ -89,10 +113,26 @@ mDatabaseName = databaseName; } + /** + * Sets the worker executor associated with {@link AppSearchSession}. + * + *

If an executor is not provided, the AppSearch default executor will be used. + * + * @param executor the worker executor used to run heavy background tasks. + */ + @NonNull + public Builder setWorkerExecutor(@NonNull Executor executor) { + mExecutor = Preconditions.checkNotNull(executor); + return this; + } + /** Builds a {@link SearchContext} instance. */ @NonNull public SearchContext build() { - return new SearchContext(mContext, mDatabaseName); + if (mExecutor == null) { + mExecutor = EXECUTOR; + } + return new SearchContext(mContext, mDatabaseName, mExecutor); } } } @@ -100,27 +140,68 @@ /** Contains information relevant to creating a global search session. */ public static final class GlobalSearchContext { final Context mContext; + final Executor mExecutor; - GlobalSearchContext(@NonNull Context context) { + GlobalSearchContext(@NonNull Context context, Executor executor) { mContext = Preconditions.checkNotNull(context); + mExecutor = Preconditions.checkNotNull(executor); + } + + /** + * Returns the worker executor associated with {@link GlobalSearchSession}. + * + *

If an executor is not provided to {@link Builder}, the AppSearch default executor will + * be returned. You should never cast the executor to + * {@link java.util.concurrent.ExecutorService} and call + * {@link ExecutorService#shutdownNow()}. It will cancel the futures it's returned. And + * since {@link Executor#execute} won't return anything, we will hang forever waiting for + * the execution. + */ + @NonNull + public Executor getWorkerExecutor() { + return mExecutor; } /** Builder for {@link GlobalSearchContext} objects. */ public static final class Builder { private final Context mContext; + private Executor mExecutor; public Builder(@NonNull Context context) { mContext = Preconditions.checkNotNull(context); } + /** + * Sets the worker executor associated with {@link GlobalSearchSession}. + * + *

If an executor is not provided, the AppSearch default executor will be used. + * + * @param executor the worker executor used to run heavy background tasks. + */ + @NonNull + public Builder setWorkerExecutor(@NonNull Executor executor) { + Preconditions.checkNotNull(executor); + mExecutor = executor; + return this; + } + /** Builds a {@link GlobalSearchContext} instance. */ @NonNull public GlobalSearchContext build() { - return new GlobalSearchContext(mContext); + if (mExecutor == null) { + mExecutor = EXECUTOR; + } + return new GlobalSearchContext(mContext, mExecutor); } } } + // Never call Executor.shutdownNow(), it will cancel the futures it's returned. And since + // execute() won't return anything, we will hang forever waiting for the execution. + // AppSearch multi-thread execution is guarded by Read & Write Lock in AppSearchImpl, all + // mutate requests will need to gain write lock and query requests need to gain read lock. + static final Executor EXECUTOR = Executors.newCachedThreadPool(); + /** * Opens a new {@link AppSearchSession} on this storage. * @@ -132,10 +213,14 @@ @NonNull SearchContext context) { Preconditions.checkNotNull(context); Task appSearchClientTask = AppSearch - .createAppSearchClient(context.mContext); + .createAppSearchClient(context.mContext, new AppSearchOptions.Builder() + .setWorkerExecutor(context.mExecutor) + .build()); return AppSearchTaskFutures.toListenableFuture( appSearchClientTask, - task -> new SearchSessionImpl(task, new FeaturesImpl(), context.mDatabaseName)); + task -> new SearchSessionImpl(task, new FeaturesImpl(), context.mDatabaseName, + context.mExecutor), + context.mExecutor); } /** @@ -149,9 +234,12 @@ @NonNull GlobalSearchContext context) { Preconditions.checkNotNull(context); Task globalSearchClientTask = AppSearch - .createGlobalSearchClient(context.mContext); + .createGlobalSearchClient(context.mContext, new AppSearchOptions.Builder() + .setWorkerExecutor(context.mExecutor) + .build()); return AppSearchTaskFutures.toListenableFuture( globalSearchClientTask, - task -> new GlobalSearchSessionImpl(task, new FeaturesImpl())); + task -> new GlobalSearchSessionImpl(task, new FeaturesImpl(), context.mExecutor), + context.mExecutor); } }

diff --git a/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/SearchResultsImpl.java b/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/SearchResultsImpl.java
index ba23844..3a50203 100644
--- a/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/SearchResultsImpl.java
+++ b/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/SearchResultsImpl.java
@@ -20,7 +20,6 @@
 import androidx.annotation.RestrictTo;
 import androidx.appsearch.app.SearchResult;
 import androidx.appsearch.app.SearchResults;
-import androidx.appsearch.app.SearchSpec;
 import androidx.appsearch.playservicesstorage.converter.SearchResultToGmsConverter;
 import androidx.appsearch.playservicesstorage.util.AppSearchTaskFutures;
 import androidx.core.util.Preconditions;
@@ -28,6 +27,7 @@
 import com.google.common.util.concurrent.ListenableFuture;
 
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
  * GooglePlayService's implementation of {@link SearchResults} which proxies to the
@@ -37,11 +37,13 @@
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 class SearchResultsImpl implements SearchResults {
     private final com.google.android.gms.appsearch.SearchResults mGmsResults;
+    private final Executor mExecutor;
 
     SearchResultsImpl(
             @NonNull com.google.android.gms.appsearch.SearchResults gmsResults,
-            @NonNull SearchSpec searchSpec) {
+            @NonNull Executor executor) {
         mGmsResults = Preconditions.checkNotNull(gmsResults);
+        mExecutor = Preconditions.checkNotNull(executor);
     }
 
     @Override
@@ -49,7 +51,8 @@
     public ListenableFuture> getNextPageAsync() {
         return AppSearchTaskFutures.toListenableFuture(
                 mGmsResults.getNextPage(),
-                SearchResultToGmsConverter::toJetpackSearchResultList
+                SearchResultToGmsConverter::toJetpackSearchResultList,
+                mExecutor
         );
     }
 
diff --git a/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/SearchSessionImpl.java b/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/SearchSessionImpl.java
index e34c08c..df99af7 100644
--- a/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/SearchSessionImpl.java
+++ b/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/SearchSessionImpl.java
@@ -52,6 +52,7 @@
 import java.io.Closeable;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Executor;
 
 /**
  * An implementation of {@link AppSearchSession} which proxies to a Google Play Service's
@@ -62,15 +63,17 @@
     private final AppSearchClient mGmsClient;
     private final Features mFeatures;
     private final String mDatabaseName;
-
+    private final Executor mExecutor;
 
     SearchSessionImpl(
             @NonNull AppSearchClient gmsClient,
             @NonNull Features features,
-            @NonNull String databaseName) {
+            @NonNull String databaseName,
+            @NonNull Executor executor) {
         mGmsClient = Preconditions.checkNotNull(gmsClient);
         mFeatures = Preconditions.checkNotNull(features);
         mDatabaseName = Preconditions.checkNotNull(databaseName);
+        mExecutor = Preconditions.checkNotNull(executor);
     }
 
     @NonNull
@@ -82,7 +85,7 @@
                         SetSchemaRequestToGmsConverter.toGmsSetSchemaRequest(
                                 request),
                         mDatabaseName),
-                SetSchemaRequestToGmsConverter::toJetpackSetSchemaResponse);
+                SetSchemaRequestToGmsConverter::toJetpackSetSchemaResponse, mExecutor);
     }
 
     @NonNull
@@ -90,7 +93,7 @@
     public ListenableFuture getSchemaAsync() {
         return AppSearchTaskFutures.toListenableFuture(
                 mGmsClient.getSchema(mDatabaseName),
-                GetSchemaResponseToGmsConverter::toJetpackGetSchemaResponse);
+                GetSchemaResponseToGmsConverter::toJetpackGetSchemaResponse, mExecutor);
     }
 
     @NonNull
@@ -98,7 +101,7 @@
     public ListenableFuture> getNamespacesAsync() {
         return AppSearchTaskFutures.toListenableFuture(
                 mGmsClient.getNamespaces(mDatabaseName),
-                /* valueMapper= */ i -> i);
+                /* valueMapper= */ i -> i, mExecutor);
     }
 
     @NonNull
@@ -111,7 +114,7 @@
                         RequestToGmsConverter.toGmsPutDocumentsRequest(request),
                         mDatabaseName),
                 result -> AppSearchResultToGmsConverter.gmsAppSearchBatchResultToJetpack(
-                        result, /* valueMapper= */ i -> i));
+                        result, /* valueMapper= */ i -> i), mExecutor);
     }
 
     @NonNull
@@ -124,7 +127,8 @@
                         RequestToGmsConverter.toGmsGetByDocumentIdRequest(request),
                         mDatabaseName),
                 result -> AppSearchResultToGmsConverter.gmsAppSearchBatchResultToJetpack(
-                                result, GenericDocumentToGmsConverter::toJetpackGenericDocument));
+                                result, GenericDocumentToGmsConverter::toJetpackGenericDocument),
+                mExecutor);
     }
 
     @NonNull
@@ -137,7 +141,7 @@
                         queryExpression,
                         SearchSpecToGmsConverter.toGmsSearchSpec(searchSpec),
                         mDatabaseName);
-        return new SearchResultsImpl(gmsSearchResults, searchSpec);
+        return new SearchResultsImpl(gmsSearchResults, mExecutor);
     }
 
     @NonNull
@@ -158,7 +162,7 @@
                 mGmsClient.reportUsage(
                         RequestToGmsConverter.toGmsReportUsageRequest(request),
                         mDatabaseName),
-                /* valueMapper= */ i -> i);
+                /* valueMapper= */ i -> i, mExecutor);
     }
 
     @NonNull
@@ -172,7 +176,7 @@
                                 .toGmsRemoveByDocumentIdRequest(request),
                         mDatabaseName),
                 result -> AppSearchResultToGmsConverter.gmsAppSearchBatchResultToJetpack(
-                        result, /* valueMapper= */ i -> i));
+                        result, /* valueMapper= */ i -> i), mExecutor);
     }
 
     @NonNull
@@ -185,7 +189,7 @@
                         queryExpression,
                         SearchSpecToGmsConverter.toGmsSearchSpec(searchSpec),
                         mDatabaseName),
-                /* valueMapper= */ i -> i);
+                /* valueMapper= */ i -> i, mExecutor);
     }
 
     @NonNull
@@ -193,14 +197,15 @@
     public ListenableFuture getStorageInfoAsync() {
         return AppSearchTaskFutures.toListenableFuture(
                 mGmsClient.getStorageInfo(mDatabaseName),
-                ResponseToGmsConverter::toJetpackStorageInfo);
+                ResponseToGmsConverter::toJetpackStorageInfo, mExecutor);
     }
 
     @NonNull
     @Override
     public ListenableFuture requestFlushAsync() {
         Task flushTask = Tasks.forResult(null);
-        return AppSearchTaskFutures.toListenableFuture(flushTask, /* valueMapper= */ i-> i);
+        return AppSearchTaskFutures.toListenableFuture(flushTask, /* valueMapper= */ i-> i,
+                mExecutor);
     }
 
     @NonNull
diff --git a/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/util/AppSearchTaskFutures.java b/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/util/AppSearchTaskFutures.java
index d737512a..04e80c1 100644
--- a/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/util/AppSearchTaskFutures.java
+++ b/appsearch/appsearch-play-services-storage/src/main/java/androidx/appsearch/playservicesstorage/util/AppSearchTaskFutures.java
@@ -30,12 +30,12 @@
 import com.google.android.gms.tasks.Task;
 import com.google.common.util.concurrent.ListenableFuture;
 
+import java.util.concurrent.Executor;
+
 /** Utilities for converting {@link Task} to {@link ListenableFuture}. */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public class AppSearchTaskFutures {
-
     private static final String TAG = "AppSearchTaskFutures";
-
     private AppSearchTaskFutures() {}
 
     /**
@@ -43,13 +43,19 @@
      * androidx apis.
      * 

Note: Calling {@link java.util.concurrent.Future#cancel(boolean)} on the returned result * is a no-op since {@link Task} has no equivalent method. + * + * @param task The {@link Task} that needs to be converted to {@link ListenableFuture}. + * @param valueMapper The transformation function to apply to the task's result. + * @param executor The {@link Executor} to execute task's onCompleteListener logic. */ @NonNull public static ListenableFuture toListenableFuture( @NonNull Task task, - @NonNull Function valueMapper) { + @NonNull Function valueMapper, + @NonNull Executor executor) { return CallbackToFutureAdapter.getFuture( completer -> task.addOnCompleteListener( + executor, completedTask -> { if (completedTask.isCanceled()) { completer.setCancelled();

diff --git a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt
index fa4f233..711330c 100644
--- a/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt
+++ b/benchmark/benchmark-common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt
@@ -17,7 +17,6 @@
 package androidx.benchmark
 
 import android.Manifest
-import android.os.Build
 import androidx.benchmark.BenchmarkState.Companion.ExperimentalExternalReport
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.FlakyTest
@@ -168,8 +167,7 @@
             if (simplifiedTimingOnlyMode) 0 else BenchmarkState.REPEAT_COUNT_ALLOCATION
         val expectedCount = report.warmupIterations +
             report.repeatIterations * expectedRepeatCount +
-            // method tracing phase by default only when API in 22..33, and simplified timing off
-            if (Build.VERSION.SDK_INT in 22..30 && !simplifiedTimingOnlyMode) 1 else 0
+            if (Arguments.profiler == MethodTracing && !simplifiedTimingOnlyMode) 1 else 0
         assertEquals(expectedCount, total)
 
         if (Arguments.iterations != null) {
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
index 9531d74..da4e257 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Arguments.kt
@@ -16,7 +16,6 @@
 
 package androidx.benchmark
 
-import android.os.Build
 import android.os.Bundle
 import android.util.Log
 import androidx.annotation.RestrictTo
@@ -91,14 +90,11 @@
         val argumentName = "profiling.mode"
         val argumentValue = getBenchmarkArgument(argumentName, "DEFAULT_VAL")
         if (argumentValue == "DEFAULT_VAL") {
-            return if (Build.VERSION.SDK_INT in 22..30) {
-                MethodTracing to true
-            } else {
-                // Method tracing can corrupt the stack on API 21, see b/300658578
-                // On API 31+ (where ART mainline updates are available), it causes regressions in
-                // jit behavior, see b/303686344
-                null to true
-            }
+            // NOTE: Method tracing currently off by default, as it is unsafe in many OS versions
+            // API 21 (b/300658578) Can corrupt the stack
+            // API 29/30 (b/313868903) causes regressions in subsequent benchmark runs, but no jit
+            // API 31+ (b/303686344) can causes regressions with jit depending on mainline version
+            return null to true
         }
 
         val profiler = Profiler.getByName(argumentValue)
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
index a4c6c70..6932f78 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
@@ -1359,25 +1359,26 @@
         if (!extension.runProjectParser) return@whenReady
 
         val parsed = project.parse()
+        val errorPrefix = "ProjectParser error parsing ${project.path}."
         check(extension.type == parsed.libraryType) {
-            "ProjectParser incorrectly computed libraryType = ${parsed.libraryType} " +
+            "$errorPrefix Incorrectly computed libraryType = ${parsed.libraryType} " +
                 "instead of ${extension.type}"
         }
         check(extension.publish == parsed.publish) {
-            "ProjectParser incorrectly computed publish = ${parsed.publish} " +
+            "$errorPrefix Incorrectly computed publish = ${parsed.publish} " +
                 "instead of ${extension.publish}"
         }
         check(extension.shouldPublish() == parsed.shouldPublish()) {
-            "ProjectParser incorrectly computed shouldPublish() = ${parsed.shouldPublish()} " +
+            "$errorPrefix Incorrectly computed shouldPublish() = ${parsed.shouldPublish()} " +
                 "instead of ${extension.shouldPublish()}"
         }
         check(extension.shouldRelease() == parsed.shouldRelease()) {
-            "ProjectParser incorrectly computed shouldRelease() = ${parsed.shouldRelease()} " +
+            "$errorPrefix Incorrectly computed shouldRelease() = ${parsed.shouldRelease()} " +
                 "instead of ${extension.shouldRelease()}"
         }
         check(extension.projectDirectlySpecifiesMavenVersion == parsed.specifiesVersion) {
-            "ProjectParser incorrectly computed specifiesVersion = ${parsed.specifiesVersion}" +
-                "instead of ${extension.projectDirectlySpecifiesMavenVersion}"
+            "$errorPrefix Incorrectly computed specifiesVersion = ${parsed.specifiesVersion} " +
+                " instead of ${extension.projectDirectlySpecifiesMavenVersion}"
         }
     }
 }
diff --git a/compose/material3/material3-adaptive/benchmark/build.gradle b/compose/material3/material3-adaptive/benchmark/build.gradle
new file mode 100644
index 0000000..48f6444
--- /dev/null
+++ b/compose/material3/material3-adaptive/benchmark/build.gradle
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("AndroidXComposePlugin")
+    id("org.jetbrains.kotlin.android")
+    id("androidx.benchmark")
+}
+
+dependencies {
+    androidTestImplementation(project(":compose:material3:material3-adaptive"))
+    androidTestImplementation(project(":benchmark:benchmark-junit4"))
+    androidTestImplementation(project(":compose:runtime:runtime"))
+    androidTestImplementation(project(":compose:benchmark-utils"))
+    androidTestImplementation(libs.testRules)
+    androidTestImplementation(libs.kotlinStdlib)
+    androidTestImplementation(libs.kotlinTestCommon)
+    androidTestImplementation(libs.junit)
+}
+
+android {
+    namespace "androidx.compose.material3.adaptive.benchmark"
+}
diff --git a/compose/material3/material3-adaptive/benchmark/src/androidTest/java/androidx/compose/material3/adaptive/benchmark/ListDetailPaneScaffoldBenchmark.kt b/compose/material3/material3-adaptive/benchmark/src/androidTest/java/androidx/compose/material3/adaptive/benchmark/ListDetailPaneScaffoldBenchmark.kt
new file mode 100644
index 0000000..9f22773
--- /dev/null
+++ b/compose/material3/material3-adaptive/benchmark/src/androidTest/java/androidx/compose/material3/adaptive/benchmark/ListDetailPaneScaffoldBenchmark.kt
@@ -0,0 +1,180 @@
+/*
+ * 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.compose.material3.adaptive.benchmark
+
+import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
+import androidx.compose.material3.adaptive.ListDetailPaneScaffold
+import androidx.compose.material3.adaptive.ListDetailPaneScaffoldRole
+import androidx.compose.material3.adaptive.calculateListDetailPaneScaffoldState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.testutils.benchmark.ComposeBenchmarkRule
+import androidx.compose.testutils.benchmark.benchmarkFirstCompose
+import androidx.compose.testutils.benchmark.benchmarkToFirstPixel
+import androidx.compose.testutils.benchmark.toggleStateBenchmarkComposeMeasureLayout
+import androidx.compose.ui.graphics.Color
+import org.junit.Rule
+import org.junit.Test
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+class ListDetailPaneScaffoldBenchmark {
+    @get:Rule
+    val benchmarkRule = ComposeBenchmarkRule()
+
+    @Test
+    fun singlePane_firstPixel() {
+        benchmarkRule.benchmarkToFirstPixel {
+            ListDetailPaneScaffoldTestCase().apply {
+                currentScaffoldDirective = singlePaneDirective
+            }
+        }
+    }
+
+    @Test
+    fun dualPane_firstPixel() {
+        benchmarkRule.benchmarkToFirstPixel {
+            ListDetailPaneScaffoldTestCase().apply {
+                currentScaffoldDirective = dualPaneDirective
+            }
+        }
+    }
+
+    @Test
+    fun singlePane_firstCompose() {
+        benchmarkRule.benchmarkFirstCompose {
+            ListDetailPaneScaffoldTestCase().apply {
+                currentScaffoldDirective = singlePaneDirective
+            }
+        }
+    }
+
+    @Test
+    fun dualPane_firstCompose() {
+        benchmarkRule.benchmarkFirstCompose {
+            ListDetailPaneScaffoldTestCase().apply {
+                currentScaffoldDirective = dualPaneDirective
+            }
+        }
+    }
+
+    @Test
+    fun singlePane_navigateToDetail() {
+        benchmarkRule.toggleStateBenchmarkComposeMeasureLayout(
+            {
+                object : ListDetailPaneScaffoldTestCase() {
+                    override fun toggleState() {
+                        currentDestination =
+                            if (currentDestination == ListDetailPaneScaffoldRole.List) {
+                                ListDetailPaneScaffoldRole.Detail
+                            } else {
+                                ListDetailPaneScaffoldRole.List
+                            }
+                    }
+                }.apply {
+                    currentScaffoldDirective = singlePaneDirective
+                }
+            }
+        )
+    }
+
+    @Test
+    fun dualPane_navigateToExtra() {
+        benchmarkRule.toggleStateBenchmarkComposeMeasureLayout(
+            {
+                object : ListDetailPaneScaffoldTestCase() {
+                    override fun toggleState() {
+                        currentDestination =
+                            if (currentDestination == ListDetailPaneScaffoldRole.List) {
+                                ListDetailPaneScaffoldRole.Extra
+                            } else {
+                                ListDetailPaneScaffoldRole.List
+                            }
+                    }
+                }.apply {
+                    currentScaffoldDirective = dualPaneDirective
+                }
+            }
+        )
+    }
+
+    @Test
+    fun singlePane_navigateToDetail_animated() {
+        benchmarkRule.toggleStateBenchmarkComposeMeasureLayout(
+            {
+                object : ListDetailPaneScaffoldTestCase(animated = true) {
+                    override fun toggleState() {
+                        currentDestination =
+                            if (currentDestination == ListDetailPaneScaffoldRole.List) {
+                                ListDetailPaneScaffoldRole.Detail
+                            } else {
+                                ListDetailPaneScaffoldRole.List
+                            }
+                    }
+                }.apply {
+                    currentScaffoldDirective = singlePaneDirective
+                }
+            },
+            // For skipping animations
+            assertOneRecomposition = false
+        )
+    }
+
+    @Test
+    fun dualPane_navigateToExtra_animated() {
+        benchmarkRule.toggleStateBenchmarkComposeMeasureLayout(
+            {
+                object : ListDetailPaneScaffoldTestCase(animated = true) {
+                    override fun toggleState() {
+                        currentDestination =
+                            if (currentDestination == ListDetailPaneScaffoldRole.List) {
+                                ListDetailPaneScaffoldRole.Extra
+                            } else {
+                                ListDetailPaneScaffoldRole.List
+                            }
+                    }
+                }.apply {
+                    currentScaffoldDirective = dualPaneDirective
+                }
+            },
+            // For skipping animations
+            assertOneRecomposition = false
+        )
+    }
+}
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+internal open class ListDetailPaneScaffoldTestCase(
+    animated: Boolean = false
+) : ThreePaneScaffoldTestCase(animated) {
+    override var currentDestination by mutableStateOf(ListDetailPaneScaffoldRole.List)
+
+    @Composable
+    override fun MeasuredContent() {
+        ListDetailPaneScaffold(
+            scaffoldState = calculateListDetailPaneScaffoldState(
+                scaffoldDirective = currentScaffoldDirective,
+                currentPaneDestination = currentDestination
+            ),
+            listPane = { TestPane(Color.Red) },
+            extraPane = { TestPane(Color.Blue) }
+        ) {
+            TestPane(Color.Yellow)
+        }
+    }
+}
diff --git a/compose/material3/material3-adaptive/benchmark/src/androidTest/java/androidx/compose/material3/adaptive/benchmark/SupportingPaneScaffoldBenchmark.kt b/compose/material3/material3-adaptive/benchmark/src/androidTest/java/androidx/compose/material3/adaptive/benchmark/SupportingPaneScaffoldBenchmark.kt
new file mode 100644
index 0000000..b867976
--- /dev/null
+++ b/compose/material3/material3-adaptive/benchmark/src/androidTest/java/androidx/compose/material3/adaptive/benchmark/SupportingPaneScaffoldBenchmark.kt
@@ -0,0 +1,180 @@
+/*
+ * 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.compose.material3.adaptive.benchmark
+
+import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
+import androidx.compose.material3.adaptive.SupportingPaneScaffold
+import androidx.compose.material3.adaptive.SupportingPaneScaffoldRole
+import androidx.compose.material3.adaptive.calculateSupportingPaneScaffoldState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.testutils.benchmark.ComposeBenchmarkRule
+import androidx.compose.testutils.benchmark.benchmarkFirstCompose
+import androidx.compose.testutils.benchmark.benchmarkToFirstPixel
+import androidx.compose.testutils.benchmark.toggleStateBenchmarkComposeMeasureLayout
+import androidx.compose.ui.graphics.Color
+import org.junit.Rule
+import org.junit.Test
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+class SupportingPaneScaffoldBenchmark {
+    @get:Rule
+    val benchmarkRule = ComposeBenchmarkRule()
+
+    @Test
+    fun singlePane_firstPixel() {
+        benchmarkRule.benchmarkToFirstPixel {
+            SupportingPaneScaffoldTestCase().apply {
+                currentScaffoldDirective = singlePaneDirective
+            }
+        }
+    }
+
+    @Test
+    fun dualPane_firstPixel() {
+        benchmarkRule.benchmarkToFirstPixel {
+            SupportingPaneScaffoldTestCase().apply {
+                currentScaffoldDirective = dualPaneDirective
+            }
+        }
+    }
+
+    @Test
+    fun singlePane_firstCompose() {
+        benchmarkRule.benchmarkFirstCompose {
+            SupportingPaneScaffoldTestCase().apply {
+                currentScaffoldDirective = singlePaneDirective
+            }
+        }
+    }
+
+    @Test
+    fun dualPane_firstCompose() {
+        benchmarkRule.benchmarkFirstCompose {
+            SupportingPaneScaffoldTestCase().apply {
+                currentScaffoldDirective = dualPaneDirective
+            }
+        }
+    }
+
+    @Test
+    fun singlePane_navigateBetweenMainAndSupporting() {
+        benchmarkRule.toggleStateBenchmarkComposeMeasureLayout(
+            {
+                object : SupportingPaneScaffoldTestCase() {
+                    override fun toggleState() {
+                        currentDestination =
+                            if (currentDestination == SupportingPaneScaffoldRole.Main) {
+                                SupportingPaneScaffoldRole.Supporting
+                            } else {
+                                SupportingPaneScaffoldRole.Main
+                            }
+                    }
+                }.apply {
+                    currentScaffoldDirective = singlePaneDirective
+                }
+            }
+        )
+    }
+
+    @Test
+    fun dualPane_navigateToExtra() {
+        benchmarkRule.toggleStateBenchmarkComposeMeasureLayout(
+            {
+                object : SupportingPaneScaffoldTestCase() {
+                    override fun toggleState() {
+                        currentDestination =
+                            if (currentDestination == SupportingPaneScaffoldRole.Main) {
+                                SupportingPaneScaffoldRole.Extra
+                            } else {
+                                SupportingPaneScaffoldRole.Main
+                            }
+                    }
+                }.apply {
+                    currentScaffoldDirective = dualPaneDirective
+                }
+            }
+        )
+    }
+
+    @Test
+    fun singlePane_navigateToSupporting_animated() {
+        benchmarkRule.toggleStateBenchmarkComposeMeasureLayout(
+            {
+                object : SupportingPaneScaffoldTestCase(animated = true) {
+                    override fun toggleState() {
+                        currentDestination =
+                            if (currentDestination == SupportingPaneScaffoldRole.Main) {
+                                SupportingPaneScaffoldRole.Supporting
+                            } else {
+                                SupportingPaneScaffoldRole.Main
+                            }
+                    }
+                }.apply {
+                    currentScaffoldDirective = singlePaneDirective
+                }
+            },
+            // For skipping animations
+            assertOneRecomposition = false
+        )
+    }
+
+    @Test
+    fun dualPane_navigateToExtra_animated() {
+        benchmarkRule.toggleStateBenchmarkComposeMeasureLayout(
+            {
+                object : SupportingPaneScaffoldTestCase(animated = true) {
+                    override fun toggleState() {
+                        currentDestination =
+                            if (currentDestination == SupportingPaneScaffoldRole.Main) {
+                                SupportingPaneScaffoldRole.Extra
+                            } else {
+                                SupportingPaneScaffoldRole.Main
+                            }
+                    }
+                }.apply {
+                    currentScaffoldDirective = dualPaneDirective
+                }
+            },
+            // For skipping animations
+            assertOneRecomposition = false
+        )
+    }
+}
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+internal open class SupportingPaneScaffoldTestCase(
+    animated: Boolean = false
+) : ThreePaneScaffoldTestCase(animated) {
+    override var currentDestination by mutableStateOf(SupportingPaneScaffoldRole.Main)
+
+    @Composable
+    override fun MeasuredContent() {
+        SupportingPaneScaffold(
+            scaffoldState = calculateSupportingPaneScaffoldState(
+                scaffoldDirective = currentScaffoldDirective,
+                currentPaneDestination = currentDestination
+            ),
+            supportingPane = { TestPane(Color.Red) },
+            extraPane = { TestPane(Color.Blue) }
+        ) {
+            TestPane(Color.Yellow)
+        }
+    }
+}
diff --git a/compose/material3/material3-adaptive/benchmark/src/androidTest/java/androidx/compose/material3/adaptive/benchmark/TestUtils.kt b/compose/material3/material3-adaptive/benchmark/src/androidTest/java/androidx/compose/material3/adaptive/benchmark/TestUtils.kt
new file mode 100644
index 0000000..eda6035
--- /dev/null
+++ b/compose/material3/material3-adaptive/benchmark/src/androidTest/java/androidx/compose/material3/adaptive/benchmark/TestUtils.kt
@@ -0,0 +1,80 @@
+/*
+ * 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.compose.material3.adaptive.benchmark
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.adaptive.AnimatedPane
+import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
+import androidx.compose.material3.adaptive.PaneScaffoldDirective
+import androidx.compose.material3.adaptive.ThreePaneScaffoldRole
+import androidx.compose.material3.adaptive.ThreePaneScaffoldScope
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.testutils.LayeredComposeTestCase
+import androidx.compose.testutils.ToggleableTestCase
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+val singlePaneDirective = PaneScaffoldDirective(
+    contentPadding = PaddingValues(16.dp),
+    maxHorizontalPartitions = 1,
+    horizontalPartitionSpacerSize = 0.dp,
+    maxVerticalPartitions = 1,
+    verticalPartitionSpacerSize = 0.dp,
+    excludedBounds = emptyList()
+)
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+val dualPaneDirective = PaneScaffoldDirective(
+    contentPadding = PaddingValues(24.dp),
+    maxHorizontalPartitions = 2,
+    horizontalPartitionSpacerSize = 24.dp,
+    maxVerticalPartitions = 1,
+    verticalPartitionSpacerSize = 0.dp,
+    excludedBounds = emptyList()
+)
+
+@OptIn(ExperimentalMaterial3AdaptiveApi::class)
+internal abstract class ThreePaneScaffoldTestCase(
+    private val animated: Boolean
+) : LayeredComposeTestCase(), ToggleableTestCase {
+    var currentScaffoldDirective by mutableStateOf(singlePaneDirective)
+    abstract var currentDestination: ThreePaneScaffoldRole
+
+    override fun toggleState() {}
+
+    @Composable
+    fun ThreePaneScaffoldScope.TestPane(color: Color) {
+        val content = @Composable {
+            Box(modifier = Modifier.fillMaxSize().background(color))
+        }
+        if (animated) {
+            AnimatedPane(Modifier) {
+                content()
+            }
+        } else {
+            content()
+        }
+    }
+}
diff --git a/compose/material3/material3/api/1.2.0-beta01.txt b/compose/material3/material3/api/1.2.0-beta01.txt
index 50beef8..e966507 100644
--- a/compose/material3/material3/api/1.2.0-beta01.txt
+++ b/compose/material3/material3/api/1.2.0-beta01.txt
@@ -1537,39 +1537,39 @@
   }
 
   public final class SwipeToDismissBoxKt {
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1 background, kotlin.jvm.functions.Function1 dismissContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set directions);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismissBox(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1 backgroundContent, optional androidx.compose.ui.Modifier modifier, optional boolean enableDismissFromStartToEnd, optional boolean enableDismissFromEndToStart, kotlin.jvm.functions.Function1 content);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SwipeToDismissState rememberSwipeToDismissState(optional androidx.compose.material3.SwipeToDismissValue initialValue, optional kotlin.jvm.functions.Function1 confirmValueChange, optional kotlin.jvm.functions.Function1 positionalThreshold);
+    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material3.SwipeToDismissBoxState state, kotlin.jvm.functions.Function1 background, kotlin.jvm.functions.Function1 dismissContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set directions);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismissBox(androidx.compose.material3.SwipeToDismissBoxState state, kotlin.jvm.functions.Function1 backgroundContent, optional androidx.compose.ui.Modifier modifier, optional boolean enableDismissFromStartToEnd, optional boolean enableDismissFromEndToStart, kotlin.jvm.functions.Function1 content);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SwipeToDismissBoxState rememberSwipeToDismissBoxState(optional androidx.compose.material3.SwipeToDismissBoxValue initialValue, optional kotlin.jvm.functions.Function1 confirmValueChange, optional kotlin.jvm.functions.Function1 positionalThreshold);
   }
 
-  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissState {
-    ctor public SwipeToDismissState(androidx.compose.material3.SwipeToDismissValue initialValue, androidx.compose.ui.unit.Density density, optional kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold);
-    method public suspend Object? dismiss(androidx.compose.material3.SwipeToDismissValue direction, kotlin.coroutines.Continuation);
-    method public androidx.compose.material3.SwipeToDismissValue getCurrentValue();
-    method public androidx.compose.material3.SwipeToDismissValue getDismissDirection();
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissBoxState {
+    ctor public SwipeToDismissBoxState(androidx.compose.material3.SwipeToDismissBoxValue initialValue, androidx.compose.ui.unit.Density density, optional kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold);
+    method public suspend Object? dismiss(androidx.compose.material3.SwipeToDismissBoxValue direction, kotlin.coroutines.Continuation);
+    method public androidx.compose.material3.SwipeToDismissBoxValue getCurrentValue();
+    method public androidx.compose.material3.SwipeToDismissBoxValue getDismissDirection();
     method @FloatRange(from=0.0, to=1.0) public float getProgress();
-    method public androidx.compose.material3.SwipeToDismissValue getTargetValue();
+    method public androidx.compose.material3.SwipeToDismissBoxValue getTargetValue();
     method @Deprecated public boolean isDismissed(androidx.compose.material3.DismissDirection direction);
     method public float requireOffset();
     method public suspend Object? reset(kotlin.coroutines.Continuation);
-    method public suspend Object? snapTo(androidx.compose.material3.SwipeToDismissValue targetValue, kotlin.coroutines.Continuation);
-    property public final androidx.compose.material3.SwipeToDismissValue currentValue;
-    property public final androidx.compose.material3.SwipeToDismissValue dismissDirection;
+    method public suspend Object? snapTo(androidx.compose.material3.SwipeToDismissBoxValue targetValue, kotlin.coroutines.Continuation);
+    property public final androidx.compose.material3.SwipeToDismissBoxValue currentValue;
+    property public final androidx.compose.material3.SwipeToDismissBoxValue dismissDirection;
     property @FloatRange(from=0.0, to=1.0) public final float progress;
-    property public final androidx.compose.material3.SwipeToDismissValue targetValue;
-    field public static final androidx.compose.material3.SwipeToDismissState.Companion Companion;
+    property public final androidx.compose.material3.SwipeToDismissBoxValue targetValue;
+    field public static final androidx.compose.material3.SwipeToDismissBoxState.Companion Companion;
   }
 
-  public static final class SwipeToDismissState.Companion {
-    method public androidx.compose.runtime.saveable.Saver Saver(kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold, androidx.compose.ui.unit.Density density);
+  public static final class SwipeToDismissBoxState.Companion {
+    method public androidx.compose.runtime.saveable.Saver Saver(kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold, androidx.compose.ui.unit.Density density);
   }
 
-  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SwipeToDismissValue {
-    method public static androidx.compose.material3.SwipeToDismissValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
-    method public static androidx.compose.material3.SwipeToDismissValue[] values();
-    enum_constant public static final androidx.compose.material3.SwipeToDismissValue EndToStart;
-    enum_constant public static final androidx.compose.material3.SwipeToDismissValue Settled;
-    enum_constant public static final androidx.compose.material3.SwipeToDismissValue StartToEnd;
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SwipeToDismissBoxValue {
+    method public static androidx.compose.material3.SwipeToDismissBoxValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.SwipeToDismissBoxValue[] values();
+    enum_constant public static final androidx.compose.material3.SwipeToDismissBoxValue EndToStart;
+    enum_constant public static final androidx.compose.material3.SwipeToDismissBoxValue Settled;
+    enum_constant public static final androidx.compose.material3.SwipeToDismissBoxValue StartToEnd;
   }
 
   @androidx.compose.runtime.Immutable public final class SwitchColors {
diff --git a/compose/material3/material3/api/current.txt b/compose/material3/material3/api/current.txt
index 50beef8..e966507 100644
--- a/compose/material3/material3/api/current.txt
+++ b/compose/material3/material3/api/current.txt
@@ -1537,39 +1537,39 @@
   }
 
   public final class SwipeToDismissBoxKt {
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1 background, kotlin.jvm.functions.Function1 dismissContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set directions);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismissBox(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1 backgroundContent, optional androidx.compose.ui.Modifier modifier, optional boolean enableDismissFromStartToEnd, optional boolean enableDismissFromEndToStart, kotlin.jvm.functions.Function1 content);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SwipeToDismissState rememberSwipeToDismissState(optional androidx.compose.material3.SwipeToDismissValue initialValue, optional kotlin.jvm.functions.Function1 confirmValueChange, optional kotlin.jvm.functions.Function1 positionalThreshold);
+    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material3.SwipeToDismissBoxState state, kotlin.jvm.functions.Function1 background, kotlin.jvm.functions.Function1 dismissContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set directions);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismissBox(androidx.compose.material3.SwipeToDismissBoxState state, kotlin.jvm.functions.Function1 backgroundContent, optional androidx.compose.ui.Modifier modifier, optional boolean enableDismissFromStartToEnd, optional boolean enableDismissFromEndToStart, kotlin.jvm.functions.Function1 content);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SwipeToDismissBoxState rememberSwipeToDismissBoxState(optional androidx.compose.material3.SwipeToDismissBoxValue initialValue, optional kotlin.jvm.functions.Function1 confirmValueChange, optional kotlin.jvm.functions.Function1 positionalThreshold);
   }
 
-  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissState {
-    ctor public SwipeToDismissState(androidx.compose.material3.SwipeToDismissValue initialValue, androidx.compose.ui.unit.Density density, optional kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold);
-    method public suspend Object? dismiss(androidx.compose.material3.SwipeToDismissValue direction, kotlin.coroutines.Continuation);
-    method public androidx.compose.material3.SwipeToDismissValue getCurrentValue();
-    method public androidx.compose.material3.SwipeToDismissValue getDismissDirection();
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissBoxState {
+    ctor public SwipeToDismissBoxState(androidx.compose.material3.SwipeToDismissBoxValue initialValue, androidx.compose.ui.unit.Density density, optional kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold);
+    method public suspend Object? dismiss(androidx.compose.material3.SwipeToDismissBoxValue direction, kotlin.coroutines.Continuation);
+    method public androidx.compose.material3.SwipeToDismissBoxValue getCurrentValue();
+    method public androidx.compose.material3.SwipeToDismissBoxValue getDismissDirection();
     method @FloatRange(from=0.0, to=1.0) public float getProgress();
-    method public androidx.compose.material3.SwipeToDismissValue getTargetValue();
+    method public androidx.compose.material3.SwipeToDismissBoxValue getTargetValue();
     method @Deprecated public boolean isDismissed(androidx.compose.material3.DismissDirection direction);
     method public float requireOffset();
     method public suspend Object? reset(kotlin.coroutines.Continuation);
-    method public suspend Object? snapTo(androidx.compose.material3.SwipeToDismissValue targetValue, kotlin.coroutines.Continuation);
-    property public final androidx.compose.material3.SwipeToDismissValue currentValue;
-    property public final androidx.compose.material3.SwipeToDismissValue dismissDirection;
+    method public suspend Object? snapTo(androidx.compose.material3.SwipeToDismissBoxValue targetValue, kotlin.coroutines.Continuation);
+    property public final androidx.compose.material3.SwipeToDismissBoxValue currentValue;
+    property public final androidx.compose.material3.SwipeToDismissBoxValue dismissDirection;
     property @FloatRange(from=0.0, to=1.0) public final float progress;
-    property public final androidx.compose.material3.SwipeToDismissValue targetValue;
-    field public static final androidx.compose.material3.SwipeToDismissState.Companion Companion;
+    property public final androidx.compose.material3.SwipeToDismissBoxValue targetValue;
+    field public static final androidx.compose.material3.SwipeToDismissBoxState.Companion Companion;
   }
 
-  public static final class SwipeToDismissState.Companion {
-    method public androidx.compose.runtime.saveable.Saver Saver(kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold, androidx.compose.ui.unit.Density density);
+  public static final class SwipeToDismissBoxState.Companion {
+    method public androidx.compose.runtime.saveable.Saver Saver(kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold, androidx.compose.ui.unit.Density density);
   }
 
-  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SwipeToDismissValue {
-    method public static androidx.compose.material3.SwipeToDismissValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
-    method public static androidx.compose.material3.SwipeToDismissValue[] values();
-    enum_constant public static final androidx.compose.material3.SwipeToDismissValue EndToStart;
-    enum_constant public static final androidx.compose.material3.SwipeToDismissValue Settled;
-    enum_constant public static final androidx.compose.material3.SwipeToDismissValue StartToEnd;
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SwipeToDismissBoxValue {
+    method public static androidx.compose.material3.SwipeToDismissBoxValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.SwipeToDismissBoxValue[] values();
+    enum_constant public static final androidx.compose.material3.SwipeToDismissBoxValue EndToStart;
+    enum_constant public static final androidx.compose.material3.SwipeToDismissBoxValue Settled;
+    enum_constant public static final androidx.compose.material3.SwipeToDismissBoxValue StartToEnd;
   }
 
   @androidx.compose.runtime.Immutable public final class SwitchColors {
diff --git a/compose/material3/material3/api/restricted_1.2.0-beta01.txt b/compose/material3/material3/api/restricted_1.2.0-beta01.txt
index 50beef8..e966507 100644
--- a/compose/material3/material3/api/restricted_1.2.0-beta01.txt
+++ b/compose/material3/material3/api/restricted_1.2.0-beta01.txt
@@ -1537,39 +1537,39 @@
   }
 
   public final class SwipeToDismissBoxKt {
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1 background, kotlin.jvm.functions.Function1 dismissContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set directions);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismissBox(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1 backgroundContent, optional androidx.compose.ui.Modifier modifier, optional boolean enableDismissFromStartToEnd, optional boolean enableDismissFromEndToStart, kotlin.jvm.functions.Function1 content);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SwipeToDismissState rememberSwipeToDismissState(optional androidx.compose.material3.SwipeToDismissValue initialValue, optional kotlin.jvm.functions.Function1 confirmValueChange, optional kotlin.jvm.functions.Function1 positionalThreshold);
+    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material3.SwipeToDismissBoxState state, kotlin.jvm.functions.Function1 background, kotlin.jvm.functions.Function1 dismissContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set directions);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismissBox(androidx.compose.material3.SwipeToDismissBoxState state, kotlin.jvm.functions.Function1 backgroundContent, optional androidx.compose.ui.Modifier modifier, optional boolean enableDismissFromStartToEnd, optional boolean enableDismissFromEndToStart, kotlin.jvm.functions.Function1 content);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SwipeToDismissBoxState rememberSwipeToDismissBoxState(optional androidx.compose.material3.SwipeToDismissBoxValue initialValue, optional kotlin.jvm.functions.Function1 confirmValueChange, optional kotlin.jvm.functions.Function1 positionalThreshold);
   }
 
-  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissState {
-    ctor public SwipeToDismissState(androidx.compose.material3.SwipeToDismissValue initialValue, androidx.compose.ui.unit.Density density, optional kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold);
-    method public suspend Object? dismiss(androidx.compose.material3.SwipeToDismissValue direction, kotlin.coroutines.Continuation);
-    method public androidx.compose.material3.SwipeToDismissValue getCurrentValue();
-    method public androidx.compose.material3.SwipeToDismissValue getDismissDirection();
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissBoxState {
+    ctor public SwipeToDismissBoxState(androidx.compose.material3.SwipeToDismissBoxValue initialValue, androidx.compose.ui.unit.Density density, optional kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold);
+    method public suspend Object? dismiss(androidx.compose.material3.SwipeToDismissBoxValue direction, kotlin.coroutines.Continuation);
+    method public androidx.compose.material3.SwipeToDismissBoxValue getCurrentValue();
+    method public androidx.compose.material3.SwipeToDismissBoxValue getDismissDirection();
     method @FloatRange(from=0.0, to=1.0) public float getProgress();
-    method public androidx.compose.material3.SwipeToDismissValue getTargetValue();
+    method public androidx.compose.material3.SwipeToDismissBoxValue getTargetValue();
     method @Deprecated public boolean isDismissed(androidx.compose.material3.DismissDirection direction);
     method public float requireOffset();
     method public suspend Object? reset(kotlin.coroutines.Continuation);
-    method public suspend Object? snapTo(androidx.compose.material3.SwipeToDismissValue targetValue, kotlin.coroutines.Continuation);
-    property public final androidx.compose.material3.SwipeToDismissValue currentValue;
-    property public final androidx.compose.material3.SwipeToDismissValue dismissDirection;
+    method public suspend Object? snapTo(androidx.compose.material3.SwipeToDismissBoxValue targetValue, kotlin.coroutines.Continuation);
+    property public final androidx.compose.material3.SwipeToDismissBoxValue currentValue;
+    property public final androidx.compose.material3.SwipeToDismissBoxValue dismissDirection;
     property @FloatRange(from=0.0, to=1.0) public final float progress;
-    property public final androidx.compose.material3.SwipeToDismissValue targetValue;
-    field public static final androidx.compose.material3.SwipeToDismissState.Companion Companion;
+    property public final androidx.compose.material3.SwipeToDismissBoxValue targetValue;
+    field public static final androidx.compose.material3.SwipeToDismissBoxState.Companion Companion;
   }
 
-  public static final class SwipeToDismissState.Companion {
-    method public androidx.compose.runtime.saveable.Saver Saver(kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold, androidx.compose.ui.unit.Density density);
+  public static final class SwipeToDismissBoxState.Companion {
+    method public androidx.compose.runtime.saveable.Saver Saver(kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold, androidx.compose.ui.unit.Density density);
   }
 
-  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SwipeToDismissValue {
-    method public static androidx.compose.material3.SwipeToDismissValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
-    method public static androidx.compose.material3.SwipeToDismissValue[] values();
-    enum_constant public static final androidx.compose.material3.SwipeToDismissValue EndToStart;
-    enum_constant public static final androidx.compose.material3.SwipeToDismissValue Settled;
-    enum_constant public static final androidx.compose.material3.SwipeToDismissValue StartToEnd;
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SwipeToDismissBoxValue {
+    method public static androidx.compose.material3.SwipeToDismissBoxValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.SwipeToDismissBoxValue[] values();
+    enum_constant public static final androidx.compose.material3.SwipeToDismissBoxValue EndToStart;
+    enum_constant public static final androidx.compose.material3.SwipeToDismissBoxValue Settled;
+    enum_constant public static final androidx.compose.material3.SwipeToDismissBoxValue StartToEnd;
   }
 
   @androidx.compose.runtime.Immutable public final class SwitchColors {
diff --git a/compose/material3/material3/api/restricted_current.txt b/compose/material3/material3/api/restricted_current.txt
index 50beef8..e966507 100644
--- a/compose/material3/material3/api/restricted_current.txt
+++ b/compose/material3/material3/api/restricted_current.txt
@@ -1537,39 +1537,39 @@
   }
 
   public final class SwipeToDismissBoxKt {
-    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1 background, kotlin.jvm.functions.Function1 dismissContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set directions);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismissBox(androidx.compose.material3.SwipeToDismissState state, kotlin.jvm.functions.Function1 backgroundContent, optional androidx.compose.ui.Modifier modifier, optional boolean enableDismissFromStartToEnd, optional boolean enableDismissFromEndToStart, kotlin.jvm.functions.Function1 content);
-    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SwipeToDismissState rememberSwipeToDismissState(optional androidx.compose.material3.SwipeToDismissValue initialValue, optional kotlin.jvm.functions.Function1 confirmValueChange, optional kotlin.jvm.functions.Function1 positionalThreshold);
+    method @Deprecated @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismiss(androidx.compose.material3.SwipeToDismissBoxState state, kotlin.jvm.functions.Function1 background, kotlin.jvm.functions.Function1 dismissContent, optional androidx.compose.ui.Modifier modifier, optional java.util.Set directions);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static void SwipeToDismissBox(androidx.compose.material3.SwipeToDismissBoxState state, kotlin.jvm.functions.Function1 backgroundContent, optional androidx.compose.ui.Modifier modifier, optional boolean enableDismissFromStartToEnd, optional boolean enableDismissFromEndToStart, kotlin.jvm.functions.Function1 content);
+    method @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api @androidx.compose.runtime.Composable public static androidx.compose.material3.SwipeToDismissBoxState rememberSwipeToDismissBoxState(optional androidx.compose.material3.SwipeToDismissBoxValue initialValue, optional kotlin.jvm.functions.Function1 confirmValueChange, optional kotlin.jvm.functions.Function1 positionalThreshold);
   }
 
-  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissState {
-    ctor public SwipeToDismissState(androidx.compose.material3.SwipeToDismissValue initialValue, androidx.compose.ui.unit.Density density, optional kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold);
-    method public suspend Object? dismiss(androidx.compose.material3.SwipeToDismissValue direction, kotlin.coroutines.Continuation);
-    method public androidx.compose.material3.SwipeToDismissValue getCurrentValue();
-    method public androidx.compose.material3.SwipeToDismissValue getDismissDirection();
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public final class SwipeToDismissBoxState {
+    ctor public SwipeToDismissBoxState(androidx.compose.material3.SwipeToDismissBoxValue initialValue, androidx.compose.ui.unit.Density density, optional kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold);
+    method public suspend Object? dismiss(androidx.compose.material3.SwipeToDismissBoxValue direction, kotlin.coroutines.Continuation);
+    method public androidx.compose.material3.SwipeToDismissBoxValue getCurrentValue();
+    method public androidx.compose.material3.SwipeToDismissBoxValue getDismissDirection();
     method @FloatRange(from=0.0, to=1.0) public float getProgress();
-    method public androidx.compose.material3.SwipeToDismissValue getTargetValue();
+    method public androidx.compose.material3.SwipeToDismissBoxValue getTargetValue();
     method @Deprecated public boolean isDismissed(androidx.compose.material3.DismissDirection direction);
     method public float requireOffset();
     method public suspend Object? reset(kotlin.coroutines.Continuation);
-    method public suspend Object? snapTo(androidx.compose.material3.SwipeToDismissValue targetValue, kotlin.coroutines.Continuation);
-    property public final androidx.compose.material3.SwipeToDismissValue currentValue;
-    property public final androidx.compose.material3.SwipeToDismissValue dismissDirection;
+    method public suspend Object? snapTo(androidx.compose.material3.SwipeToDismissBoxValue targetValue, kotlin.coroutines.Continuation);
+    property public final androidx.compose.material3.SwipeToDismissBoxValue currentValue;
+    property public final androidx.compose.material3.SwipeToDismissBoxValue dismissDirection;
     property @FloatRange(from=0.0, to=1.0) public final float progress;
-    property public final androidx.compose.material3.SwipeToDismissValue targetValue;
-    field public static final androidx.compose.material3.SwipeToDismissState.Companion Companion;
+    property public final androidx.compose.material3.SwipeToDismissBoxValue targetValue;
+    field public static final androidx.compose.material3.SwipeToDismissBoxState.Companion Companion;
   }
 
-  public static final class SwipeToDismissState.Companion {
-    method public androidx.compose.runtime.saveable.Saver Saver(kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold, androidx.compose.ui.unit.Density density);
+  public static final class SwipeToDismissBoxState.Companion {
+    method public androidx.compose.runtime.saveable.Saver Saver(kotlin.jvm.functions.Function1 confirmValueChange, kotlin.jvm.functions.Function1 positionalThreshold, androidx.compose.ui.unit.Density density);
   }
 
-  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SwipeToDismissValue {
-    method public static androidx.compose.material3.SwipeToDismissValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
-    method public static androidx.compose.material3.SwipeToDismissValue[] values();
-    enum_constant public static final androidx.compose.material3.SwipeToDismissValue EndToStart;
-    enum_constant public static final androidx.compose.material3.SwipeToDismissValue Settled;
-    enum_constant public static final androidx.compose.material3.SwipeToDismissValue StartToEnd;
+  @SuppressCompatibility @androidx.compose.material3.ExperimentalMaterial3Api public enum SwipeToDismissBoxValue {
+    method public static androidx.compose.material3.SwipeToDismissBoxValue valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException;
+    method public static androidx.compose.material3.SwipeToDismissBoxValue[] values();
+    enum_constant public static final androidx.compose.material3.SwipeToDismissBoxValue EndToStart;
+    enum_constant public static final androidx.compose.material3.SwipeToDismissBoxValue Settled;
+    enum_constant public static final androidx.compose.material3.SwipeToDismissBoxValue StartToEnd;
   }
 
   @androidx.compose.runtime.Immutable public final class SwitchColors {
diff --git a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/SwipeToDismissDemo.kt b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/SwipeToDismissDemo.kt
index f751e9f..cecf379 100644
--- a/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/SwipeToDismissDemo.kt
+++ b/compose/material3/material3/integration-tests/material3-demos/src/main/java/androidx/compose/material3/demos/SwipeToDismissDemo.kt
@@ -32,9 +32,9 @@
 import androidx.compose.material3.Icon
 import androidx.compose.material3.ListItem
 import androidx.compose.material3.SwipeToDismissBox
-import androidx.compose.material3.SwipeToDismissValue
+import androidx.compose.material3.SwipeToDismissBoxValue
 import androidx.compose.material3.Text
-import androidx.compose.material3.rememberSwipeToDismissState
+import androidx.compose.material3.rememberSwipeToDismissBoxState
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -83,10 +83,10 @@
             var unread by remember { mutableStateOf(false) }
             val scope = rememberCoroutineScope()
 
-            val dismissState = rememberSwipeToDismissState(
+            val dismissState = rememberSwipeToDismissBoxState(
                 confirmValueChange = {
-                    if (it == SwipeToDismissValue.StartToEnd) unread = !unread
-                    it != SwipeToDismissValue.StartToEnd
+                    if (it == SwipeToDismissBoxValue.StartToEnd) unread = !unread
+                    it != SwipeToDismissBoxValue.StartToEnd
                 },
                 positionalThreshold = { distance -> distance * .25f }
             )
@@ -97,23 +97,23 @@
                     val direction = dismissState.dismissDirection
                     val color by animateColorAsState(
                         when (dismissState.targetValue) {
-                            SwipeToDismissValue.Settled -> Color.LightGray
-                            SwipeToDismissValue.StartToEnd -> Color.Green
-                            SwipeToDismissValue.EndToStart -> Color.Red
+                            SwipeToDismissBoxValue.Settled -> Color.LightGray
+                            SwipeToDismissBoxValue.StartToEnd -> Color.Green
+                            SwipeToDismissBoxValue.EndToStart -> Color.Red
                         }
                     )
                     val alignment = when (direction) {
-                        SwipeToDismissValue.StartToEnd,
-                        SwipeToDismissValue.Settled -> Alignment.CenterStart
-                        SwipeToDismissValue.EndToStart -> Alignment.CenterEnd
+                        SwipeToDismissBoxValue.StartToEnd,
+                        SwipeToDismissBoxValue.Settled -> Alignment.CenterStart
+                        SwipeToDismissBoxValue.EndToStart -> Alignment.CenterEnd
                     }
                     val icon = when (direction) {
-                        SwipeToDismissValue.StartToEnd,
-                        SwipeToDismissValue.Settled -> Icons.Default.Done
-                        SwipeToDismissValue.EndToStart -> Icons.Default.Delete
+                        SwipeToDismissBoxValue.StartToEnd,
+                        SwipeToDismissBoxValue.Settled -> Icons.Default.Done
+                        SwipeToDismissBoxValue.EndToStart -> Icons.Default.Delete
                     }
                     val scale by animateFloatAsState(
-                        if (dismissState.targetValue == SwipeToDismissValue.Settled)
+                        if (dismissState.targetValue == SwipeToDismissBoxValue.Settled)
                             0.75f else 1f
                     )
                     Box(
@@ -143,7 +143,7 @@
                                 CustomAccessibilityAction(label) { unread = !unread; true },
                                 CustomAccessibilityAction("Delete") {
                                     scope.launch {
-                                        dismissState.dismiss(SwipeToDismissValue.EndToStart)
+                                        dismissState.dismiss(SwipeToDismissBoxValue.EndToStart)
                                     }
                                     true
                                 }
diff --git a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SwipeToDismissSamples.kt b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SwipeToDismissSamples.kt
index b883b78..43d0a6b 100644
--- a/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SwipeToDismissSamples.kt
+++ b/compose/material3/material3/samples/src/main/java/androidx/compose/material3/samples/SwipeToDismissSamples.kt
@@ -26,9 +26,9 @@
 import androidx.compose.material3.HorizontalDivider
 import androidx.compose.material3.ListItem
 import androidx.compose.material3.SwipeToDismissBox
-import androidx.compose.material3.SwipeToDismissValue
+import androidx.compose.material3.SwipeToDismissBoxValue
 import androidx.compose.material3.Text
-import androidx.compose.material3.rememberSwipeToDismissState
+import androidx.compose.material3.rememberSwipeToDismissBoxState
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
@@ -40,15 +40,15 @@
 @Composable
 @ExperimentalMaterial3Api
 fun SwipeToDismissListItems() {
-    val dismissState = rememberSwipeToDismissState()
+    val dismissState = rememberSwipeToDismissBoxState()
     SwipeToDismissBox(
         state = dismissState,
         backgroundContent = {
             val color by animateColorAsState(
                 when (dismissState.targetValue) {
-                    SwipeToDismissValue.Settled -> Color.LightGray
-                    SwipeToDismissValue.StartToEnd -> Color.Green
-                    SwipeToDismissValue.EndToStart -> Color.Red
+                    SwipeToDismissBoxValue.Settled -> Color.LightGray
+                    SwipeToDismissBoxValue.StartToEnd -> Color.Green
+                    SwipeToDismissBoxValue.EndToStart -> Color.Red
                 }
             )
             Box(Modifier.fillMaxSize().background(color))
diff --git a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SwipeToDismissTest.kt b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SwipeToDismissTest.kt
index 05a5858..3997f34 100644
--- a/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SwipeToDismissTest.kt
+++ b/compose/material3/material3/src/androidInstrumentedTest/kotlin/androidx/compose/material3/SwipeToDismissTest.kt
@@ -69,7 +69,7 @@
     fun swipeDismiss_testOffset_whenDefault() {
         rule.setContent {
             SwipeToDismissBox(
-                state = rememberSwipeToDismissState(SwipeToDismissValue.Settled),
+                state = rememberSwipeToDismissBoxState(SwipeToDismissBoxValue.Settled),
                 backgroundContent = { }
             ) {
                     Box(
@@ -87,7 +87,7 @@
     fun swipeDismiss_testOffset_whenDismissedToEnd() {
         rule.setContent {
             SwipeToDismissBox(
-                state = rememberSwipeToDismissState(SwipeToDismissValue.StartToEnd),
+                state = rememberSwipeToDismissBoxState(SwipeToDismissBoxValue.StartToEnd),
                 backgroundContent = { }
             ) {
                     Box(
@@ -106,7 +106,7 @@
     fun swipeDismiss_testOffset_whenDismissedToStart() {
         rule.setContent {
             SwipeToDismissBox(
-                state = rememberSwipeToDismissState(SwipeToDismissValue.EndToStart),
+                state = rememberSwipeToDismissBoxState(SwipeToDismissBoxValue.EndToStart),
                 backgroundContent = { },
             ) {
                     Box(
@@ -125,7 +125,7 @@
     fun swipeDismiss_testBackgroundMatchesContentSize() {
         rule.setContent {
             SwipeToDismissBox(
-                state = rememberSwipeToDismissState(SwipeToDismissValue.Settled),
+                state = rememberSwipeToDismissBoxState(SwipeToDismissBoxValue.Settled),
                 backgroundContent = {
                     Box(
                         Modifier
@@ -142,11 +142,11 @@
 
     @Test
     fun swipeDismiss_dismissBySwipe_toEnd() {
-        lateinit var swipeToDismissState: SwipeToDismissState
+        lateinit var swipeToDismissBoxState: SwipeToDismissBoxState
         rule.setContent {
-            swipeToDismissState = rememberSwipeToDismissState(SwipeToDismissValue.Settled)
+            swipeToDismissBoxState = rememberSwipeToDismissBoxState(SwipeToDismissBoxValue.Settled)
             SwipeToDismissBox(
-                state = swipeToDismissState,
+                state = swipeToDismissBoxState,
                 modifier = Modifier.testTag(swipeDismissTag),
                 enableDismissFromStartToEnd = true,
                 enableDismissFromEndToStart = false,
@@ -159,17 +159,18 @@
         advanceClock()
 
         rule.runOnIdle {
-            assertThat(swipeToDismissState.currentValue).isEqualTo(SwipeToDismissValue.StartToEnd)
+            assertThat(swipeToDismissBoxState.currentValue)
+                .isEqualTo(SwipeToDismissBoxValue.StartToEnd)
         }
     }
 
     @Test
     fun swipeDismiss_dismissBySwipe_toStart() {
-        lateinit var swipeToDismissState: SwipeToDismissState
+        lateinit var swipeToDismissBoxState: SwipeToDismissBoxState
         rule.setContent {
-            swipeToDismissState = rememberSwipeToDismissState(SwipeToDismissValue.Settled)
+            swipeToDismissBoxState = rememberSwipeToDismissBoxState(SwipeToDismissBoxValue.Settled)
             SwipeToDismissBox(
-                state = swipeToDismissState,
+                state = swipeToDismissBoxState,
                 modifier = Modifier.testTag(swipeDismissTag),
                 enableDismissFromStartToEnd = false,
                 enableDismissFromEndToStart = true,
@@ -182,18 +183,19 @@
         advanceClock()
 
         rule.runOnIdle {
-            assertThat(swipeToDismissState.currentValue).isEqualTo(SwipeToDismissValue.EndToStart)
+            assertThat(swipeToDismissBoxState.currentValue)
+                .isEqualTo(SwipeToDismissBoxValue.EndToStart)
         }
     }
 
     @Test
     fun swipeDismiss_dismissBySwipe_toEnd_rtl() {
-        lateinit var swipeToDismissState: SwipeToDismissState
+        lateinit var swipeToDismissBoxState: SwipeToDismissBoxState
         rule.setContent {
-            swipeToDismissState = rememberSwipeToDismissState()
+            swipeToDismissBoxState = rememberSwipeToDismissBoxState()
             CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
                 SwipeToDismissBox(
-                    state = swipeToDismissState,
+                    state = swipeToDismissBoxState,
                     modifier = Modifier.testTag(swipeDismissTag),
                     enableDismissFromStartToEnd = true,
                     enableDismissFromEndToStart = false,
@@ -207,18 +209,19 @@
         advanceClock()
 
         rule.runOnIdle {
-            assertThat(swipeToDismissState.currentValue).isEqualTo(SwipeToDismissValue.StartToEnd)
+            assertThat(swipeToDismissBoxState.currentValue)
+                .isEqualTo(SwipeToDismissBoxValue.StartToEnd)
         }
     }
 
     @Test
     fun swipeDismiss_dismissBySwipe_toStart_rtl() {
-        lateinit var swipeToDismissState: SwipeToDismissState
+        lateinit var swipeToDismissBoxState: SwipeToDismissBoxState
         rule.setContent {
-            swipeToDismissState = rememberSwipeToDismissState(SwipeToDismissValue.Settled)
+            swipeToDismissBoxState = rememberSwipeToDismissBoxState(SwipeToDismissBoxValue.Settled)
             CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Rtl) {
                 SwipeToDismissBox(
-                    state = swipeToDismissState,
+                    state = swipeToDismissBoxState,
                     modifier = Modifier.testTag(swipeDismissTag),
                     enableDismissFromStartToEnd = false,
                     enableDismissFromEndToStart = true,
@@ -232,17 +235,18 @@
         advanceClock()
 
         rule.runOnIdle {
-            assertThat(swipeToDismissState.currentValue).isEqualTo(SwipeToDismissValue.EndToStart)
+            assertThat(swipeToDismissBoxState.currentValue)
+                .isEqualTo(SwipeToDismissBoxValue.EndToStart)
         }
     }
 
     @Test
     fun swipeDismiss_dismissBySwipe_disabled() {
-        lateinit var swipeToDismissState: SwipeToDismissState
+        lateinit var swipeToDismissBoxState: SwipeToDismissBoxState
         rule.setContent {
-            swipeToDismissState = rememberSwipeToDismissState(SwipeToDismissValue.Settled)
+            swipeToDismissBoxState = rememberSwipeToDismissBoxState(SwipeToDismissBoxValue.Settled)
             SwipeToDismissBox(
-                state = swipeToDismissState,
+                state = swipeToDismissBoxState,
                 modifier = Modifier.testTag(swipeDismissTag),
                 enableDismissFromStartToEnd = false,
                 enableDismissFromEndToStart = false,
@@ -255,7 +259,8 @@
         advanceClock()
 
         rule.runOnIdle {
-            assertThat(swipeToDismissState.currentValue).isEqualTo(SwipeToDismissValue.Settled)
+            assertThat(swipeToDismissBoxState.currentValue)
+                .isEqualTo(SwipeToDismissBoxValue.Settled)
         }
 
         rule.onNodeWithTag(swipeDismissTag).performTouchInput { swipeLeft() }
@@ -263,7 +268,8 @@
         advanceClock()
 
         rule.runOnIdle {
-            assertThat(swipeToDismissState.currentValue).isEqualTo(SwipeToDismissValue.Settled)
+            assertThat(swipeToDismissBoxState.currentValue)
+                .isEqualTo(SwipeToDismissBoxValue.Settled)
         }
     }
 
@@ -278,7 +284,7 @@
         lateinit var lazyState: LazyListState
         lateinit var scope: CoroutineScope
         val amountOfItems = 100
-        val composedItems = mutableMapOf()
+        val composedItems = mutableMapOf()
 
         rule.setContent {
             scope = rememberCoroutineScope()
@@ -286,9 +292,9 @@
                 lazyState = rememberLazyListState()
                 LazyColumn(state = lazyState) {
                     items(amountOfItems, key = { item -> item }) { index ->
-                        composedItems[index] = rememberSwipeToDismissState()
+                        composedItems[index] = rememberSwipeToDismissBoxState()
                         val isDismissed =
-                            composedItems[index]!!.currentValue == SwipeToDismissValue.EndToStart
+                            composedItems[index]!!.currentValue == SwipeToDismissBoxValue.EndToStart
                         AnimatedVisibility(visible = !isDismissed) {
                             SwipeToDismissBox(
                                 modifier = Modifier
@@ -325,7 +331,7 @@
 
         // Dismiss an item so that the lazy layout is required to compose a new item
         scope.launch {
-            composedItems[initiallyVisibleItems - 1]!!.dismiss(SwipeToDismissValue.EndToStart)
+            composedItems[initiallyVisibleItems - 1]!!.dismiss(SwipeToDismissBoxValue.EndToStart)
         }
         rule.waitForIdle()
 
diff --git a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SwipeToDismissBox.kt b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SwipeToDismissBox.kt
index ebbe7c7..0b492f03 100644
--- a/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SwipeToDismissBox.kt
+++ b/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/SwipeToDismissBox.kt
@@ -21,7 +21,7 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.RowScope
-import androidx.compose.material3.SwipeToDismissState.Companion.Saver
+import androidx.compose.material3.SwipeToDismissBoxState.Companion.Saver
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.Saver
@@ -47,7 +47,7 @@
  * The directions in which a [SwipeToDismissBox] can be dismissed.
  */
 @ExperimentalMaterial3Api
-enum class SwipeToDismissValue {
+enum class SwipeToDismissBoxValue {
     /**
      * Can be dismissed by swiping in the reading direction.
      */
@@ -76,10 +76,10 @@
  * subtracted from/to the origin offset. It should always be a positive value.
  */
 @ExperimentalMaterial3Api
-class SwipeToDismissState(
-    initialValue: SwipeToDismissValue,
+class SwipeToDismissBoxState(
+    initialValue: SwipeToDismissBoxValue,
     internal val density: Density,
-    confirmValueChange: (SwipeToDismissValue) -> Boolean = { true },
+    confirmValueChange: (SwipeToDismissBoxValue) -> Boolean = { true },
     positionalThreshold: (totalDistance: Float) -> Float
 ) {
     internal val anchoredDraggableState = AnchoredDraggableState(
@@ -100,16 +100,16 @@
     fun requireOffset(): Float = anchoredDraggableState.requireOffset()
 
     /**
-     * The current state value of the [SwipeToDismissState].
+     * The current state value of the [SwipeToDismissBoxState].
      */
-    val currentValue: SwipeToDismissValue get() = anchoredDraggableState.currentValue
+    val currentValue: SwipeToDismissBoxValue get() = anchoredDraggableState.currentValue
 
     /**
      * The target state. This is the closest state to the current offset (taking into account
      * positional thresholds). If no interactions like animations or drags are in progress, this
      * will be the current state.
      */
-    val targetValue: SwipeToDismissValue get() = anchoredDraggableState.targetValue
+    val targetValue: SwipeToDismissBoxValue get() = anchoredDraggableState.targetValue
 
     /**
      * The fraction of the progress going from currentValue to targetValue, within [0f..1f] bounds.
@@ -123,10 +123,11 @@
      * Use this to change the background of the [SwipeToDismissBox] if you want different actions on each
      * side.
      */
-    val dismissDirection: SwipeToDismissValue
+    val dismissDirection: SwipeToDismissBoxValue
         get() = if (offset == 0f || offset.isNaN())
-            SwipeToDismissValue.Settled
-        else if (offset > 0f) SwipeToDismissValue.StartToEnd else SwipeToDismissValue.EndToStart
+            SwipeToDismissBoxValue.Settled
+        else if (offset > 0f)
+            SwipeToDismissBoxValue.StartToEnd else SwipeToDismissBoxValue.EndToStart
 
     /**
      * Whether the component has been dismissed in the given [direction].
@@ -134,7 +135,7 @@
      * @param direction The dismiss direction.
      */
     @Deprecated(
-        message = "DismissDirection is no longer used by SwipeToDismissState. Please compare " +
+        message = "DismissDirection is no longer used by SwipeToDismissBoxState. Please compare " +
             "currentValue against SwipeToDismissValue instead.",
         level = DeprecationLevel.HIDDEN
     )
@@ -142,9 +143,9 @@
     fun isDismissed(direction: DismissDirection): Boolean {
         return currentValue == (
                 if (direction == DismissDirection.StartToEnd) {
-                    SwipeToDismissValue.StartToEnd
+                    SwipeToDismissBoxValue.StartToEnd
                 } else {
-                    SwipeToDismissValue.EndToStart
+                    SwipeToDismissBoxValue.EndToStart
                 }
             )
     }
@@ -154,7 +155,7 @@
      *
      * @param targetValue The new target value
      */
-    suspend fun snapTo(targetValue: SwipeToDismissValue) {
+    suspend fun snapTo(targetValue: SwipeToDismissBoxValue) {
         anchoredDraggableState.snapTo(targetValue)
     }
 
@@ -166,7 +167,7 @@
      * @return the reason the reset animation ended
      */
     suspend fun reset() = anchoredDraggableState.animateTo(
-        targetValue = SwipeToDismissValue.Settled
+        targetValue = SwipeToDismissBoxValue.Settled
     )
 
     /**
@@ -175,23 +176,23 @@
      *
      * @param direction The dismiss direction.
      */
-    suspend fun dismiss(direction: SwipeToDismissValue) {
+    suspend fun dismiss(direction: SwipeToDismissBoxValue) {
         anchoredDraggableState.animateTo(targetValue = direction)
     }
 
     companion object {
 
         /**
-         * The default [Saver] implementation for [SwipeToDismissState].
+         * The default [Saver] implementation for [SwipeToDismissBoxState].
          */
         fun Saver(
-            confirmValueChange: (SwipeToDismissValue) -> Boolean,
+            confirmValueChange: (SwipeToDismissBoxValue) -> Boolean,
             positionalThreshold: (totalDistance: Float) -> Float,
             density: Density
-        ) = Saver(
+        ) = Saver(
             save = { it.currentValue },
             restore = {
-                SwipeToDismissState(
+                SwipeToDismissBoxState(
                     it, density, confirmValueChange, positionalThreshold
                 )
             }
@@ -200,7 +201,7 @@
 }
 
 /**
- * Create and [remember] a [SwipeToDismissState].
+ * Create and [remember] a [SwipeToDismissBoxState].
  *
  * @param initialValue The initial value of the state.
  * @param confirmValueChange Optional callback invoked to confirm or veto a pending state change.
@@ -211,12 +212,12 @@
  */
 @Composable
 @ExperimentalMaterial3Api
-fun rememberSwipeToDismissState(
-    initialValue: SwipeToDismissValue = SwipeToDismissValue.Settled,
-    confirmValueChange: (SwipeToDismissValue) -> Boolean = { true },
+fun rememberSwipeToDismissBoxState(
+    initialValue: SwipeToDismissBoxValue = SwipeToDismissBoxValue.Settled,
+    confirmValueChange: (SwipeToDismissBoxValue) -> Boolean = { true },
     positionalThreshold: (totalDistance: Float) -> Float =
         SwipeToDismissBoxDefaults.positionalThreshold,
-): SwipeToDismissState {
+): SwipeToDismissBoxState {
     val density = LocalDensity.current
     return rememberSaveable(
         saver = Saver(
@@ -225,7 +226,7 @@
             positionalThreshold = positionalThreshold
         )
     ) {
-        SwipeToDismissState(initialValue, density, confirmValueChange, positionalThreshold)
+        SwipeToDismissBoxState(initialValue, density, confirmValueChange, positionalThreshold)
     }
 }
 
@@ -251,19 +252,19 @@
 )
 @ExperimentalMaterial3Api
 fun SwipeToDismiss(
-    state: SwipeToDismissState,
+    state: SwipeToDismissBoxState,
     background: @Composable RowScope.() -> Unit,
     dismissContent: @Composable RowScope.() -> Unit,
     modifier: Modifier = Modifier,
-    directions: Set = setOf(SwipeToDismissValue.EndToStart,
-        SwipeToDismissValue.StartToEnd
+    directions: Set = setOf(SwipeToDismissBoxValue.EndToStart,
+        SwipeToDismissBoxValue.StartToEnd
     ),
 ) = SwipeToDismissBox(
     state = state,
     backgroundContent = background,
     modifier = modifier,
-    enableDismissFromStartToEnd = SwipeToDismissValue.StartToEnd in directions,
-    enableDismissFromEndToStart = SwipeToDismissValue.EndToStart in directions,
+    enableDismissFromStartToEnd = SwipeToDismissBoxValue.StartToEnd in directions,
+    enableDismissFromEndToStart = SwipeToDismissBoxValue.EndToStart in directions,
     content = dismissContent
 )
 
@@ -283,7 +284,7 @@
 @Composable
 @ExperimentalMaterial3Api
 fun SwipeToDismissBox(
-    state: SwipeToDismissState,
+    state: SwipeToDismissBoxState,
     backgroundContent: @Composable RowScope.() -> Unit,
     modifier: Modifier = Modifier,
     enableDismissFromStartToEnd: Boolean = true,
@@ -297,7 +298,7 @@
             .anchoredDraggable(
                 state = state.anchoredDraggableState,
                 orientation = Orientation.Horizontal,
-                enabled = state.currentValue == SwipeToDismissValue.Settled,
+                enabled = state.currentValue == SwipeToDismissBoxValue.Settled,
                 reverseDirection = isRtl,
             ),
         propagateMinConstraints = true
@@ -308,7 +309,7 @@
         )
         Row(
             content = content,
-            modifier = Modifier.swipeToDismissAnchors(
+            modifier = Modifier.swipeToDismissBoxAnchors(
                 state,
                 enableDismissFromStartToEnd,
                 enableDismissFromEndToStart
@@ -317,10 +318,10 @@
     }
 }
 
-/** Contains default values for [SwipeToDismissBox] and [SwipeToDismissState]. */
+/** Contains default values for [SwipeToDismissBox] and [SwipeToDismissBoxState]. */
 @ExperimentalMaterial3Api
 object SwipeToDismissBoxDefaults {
-    /** Default positional threshold of 56.dp for [SwipeToDismissState]. */
+    /** Default positional threshold of 56.dp for [SwipeToDismissBoxState]. */
     val positionalThreshold: (totalDistance: Float) -> Float
         @Composable get() = with(LocalDensity.current) {
             { 56.dp.toPx() }
@@ -332,8 +333,8 @@
  */
 @ExperimentalMaterial3Api
 @Deprecated(
-    message = "Dismiss direction is no longer used by SwipeToDismissState. Please use " +
-        "SwipeToDismissValue instead.",
+    message = "Dismiss direction is no longer used by SwipeToDismissBoxState. Please use " +
+        "SwipeToDismissBoxValue instead.",
     level = DeprecationLevel.WARNING
 )
 enum class DismissDirection {
@@ -349,12 +350,12 @@
 }
 
 /**
- * Possible values of [SwipeToDismissState].
+ * Possible values of [SwipeToDismissBoxState].
  */
 @ExperimentalMaterial3Api
 @Deprecated(
-    message = "DismissValue is no longer used by SwipeToDismissState. Please use " +
-        "SwipeToDismissValue instead.",
+    message = "DismissValue is no longer used by SwipeToDismissBoxState. Please use " +
+        "SwipeToDismissBoxValue instead.",
     level = DeprecationLevel.WARNING
 )
 enum class DismissValue {
@@ -377,8 +378,8 @@
 private val DismissThreshold = 125.dp
 
 @OptIn(ExperimentalMaterial3Api::class)
-private fun Modifier.swipeToDismissAnchors(
-    state: SwipeToDismissState,
+private fun Modifier.swipeToDismissBoxAnchors(
+    state: SwipeToDismissBoxState,
     enableDismissFromStartToEnd: Boolean,
     enableDismissFromEndToStart: Boolean
 ) = this then SwipeToDismissAnchorsElement(
@@ -389,7 +390,7 @@
 
 @OptIn(ExperimentalMaterial3Api::class)
 private class SwipeToDismissAnchorsElement(
-    private val state: SwipeToDismissState,
+    private val state: SwipeToDismissBoxState,
     private val enableDismissFromStartToEnd: Boolean,
     private val enableDismissFromEndToStart: Boolean,
 ) : ModifierNodeElement() {
@@ -433,7 +434,7 @@
 
 @OptIn(ExperimentalMaterial3Api::class)
 private class SwipeToDismissAnchorsNode(
-    var state: SwipeToDismissState,
+    var state: SwipeToDismissBoxState,
     var enableDismissFromStartToEnd: Boolean,
     var enableDismissFromEndToStart: Boolean,
 ) : Modifier.Node(), LayoutModifierNode {
@@ -454,12 +455,12 @@
         if (isLookingAhead || !didLookahead) {
             val width = placeable.width.toFloat()
             val newAnchors = DraggableAnchors {
-                SwipeToDismissValue.Settled at 0f
+                SwipeToDismissBoxValue.Settled at 0f
                 if (enableDismissFromStartToEnd) {
-                    SwipeToDismissValue.StartToEnd at width
+                    SwipeToDismissBoxValue.StartToEnd at width
                 }
                 if (enableDismissFromEndToStart) {
-                    SwipeToDismissValue.EndToStart at -width
+                    SwipeToDismissBoxValue.EndToStart at -width
                 }
             }
             state.anchoredDraggableState.updateAnchors(newAnchors)
diff --git a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/AndroidPointerInputTest.kt b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/AndroidPointerInputTest.kt
index 3642a41..407c8a6 100644
--- a/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/AndroidPointerInputTest.kt
+++ b/compose/ui/ui/src/androidInstrumentedTest/kotlin/androidx/compose/ui/input/pointer/AndroidPointerInputTest.kt
@@ -27,6 +27,7 @@
 import android.view.MotionEvent.ACTION_HOVER_EXIT
 import android.view.MotionEvent.ACTION_HOVER_MOVE
 import android.view.MotionEvent.ACTION_MOVE
+import android.view.MotionEvent.ACTION_OUTSIDE
 import android.view.MotionEvent.ACTION_POINTER_DOWN
 import android.view.MotionEvent.ACTION_POINTER_INDEX_SHIFT
 import android.view.MotionEvent.ACTION_POINTER_UP
@@ -1181,6 +1182,206 @@
         }
     }
 
+    /*
+     * This is a simple test that makes sure a bad ACTION_OUTSIDE MotionEvent doesn't negatively
+     * impact Compose (b/299074463#comment31). (We actually ignore them in Compose.)
+     * The event order of MotionEvents:
+     *   1. Hover enter on box 1
+     *   2. Hover move into box 2
+     *   3. Hover exit on box 2
+     *   4. Outside event on box 3
+     *   5. Down on box 2
+     *   6. Up on box 2
+     */
+    @Test
+    fun hoverAndClickMotionEvent_badOutsideMotionEvent_outsideMotionEventIgnored() {
+        // --> Arrange
+        var box1LayoutCoordinates: LayoutCoordinates? = null
+        var box2LayoutCoordinates: LayoutCoordinates? = null
+        var box3LayoutCoordinates: LayoutCoordinates? = null
+
+        val setUpFinishedLatch = CountDownLatch(1)
+        // One less than total because outside is not sent to Compose.
+        val totalEventLatch = CountDownLatch(5)
+
+        // Events for Box 1
+        var enterBox1 = false
+        var exitBox1 = false
+
+        // Events for Box 2
+        var enterBox2 = false
+        var exitBox2 = false
+        var pressBox2 = false
+        var releaseBox2 = false
+
+        // All other events that should never be triggered in this test
+        var eventsThatShouldNotTrigger = false
+
+        var pointerEvent: PointerEvent? = null
+
+        rule.runOnUiThread {
+            container.setContent {
+                Column(
+                    Modifier
+                        .fillMaxSize()
+                        .onGloballyPositioned {
+                            setUpFinishedLatch.countDown()
+                        }
+                        .pointerInput(Unit) {
+                            awaitPointerEventScope {
+                                while (true) {
+                                    awaitPointerEvent()
+                                    totalEventLatch.countDown()
+                                }
+                            }
+                        }
+                ) {
+                    // Box 1
+                    Box(
+                        Modifier
+                            .size(50.dp)
+                            .onGloballyPositioned {
+                                box1LayoutCoordinates = it
+                            }
+                            .pointerInput(Unit) {
+                                awaitPointerEventScope {
+                                    while (true) {
+                                        pointerEvent = awaitPointerEvent()
+
+                                        when (pointerEvent!!.type) {
+                                            PointerEventType.Enter -> {
+                                                enterBox1 = true
+                                            }
+                                            PointerEventType.Exit -> {
+                                                exitBox1 = true
+                                            }
+                                            else -> {
+                                                eventsThatShouldNotTrigger = true
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                    ) { }
+
+                    // Box 2
+                    Box(
+                        Modifier
+                            .size(50.dp)
+                            .onGloballyPositioned {
+                                box2LayoutCoordinates = it
+                            }
+                            .pointerInput(Unit) {
+                                awaitPointerEventScope {
+                                    while (true) {
+                                        pointerEvent = awaitPointerEvent()
+
+                                        when (pointerEvent!!.type) {
+                                            PointerEventType.Enter -> {
+                                                enterBox2 = true
+                                            }
+                                            PointerEventType.Press -> {
+                                                pressBox2 = true
+                                            }
+                                            PointerEventType.Release -> {
+                                                releaseBox2 = true
+                                            }
+                                            PointerEventType.Exit -> {
+                                                exitBox2 = true
+                                            }
+                                            else -> {
+                                                eventsThatShouldNotTrigger = true
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                    ) { }
+
+                    // Box 3
+                    Box(
+                        Modifier
+                            .size(50.dp)
+                            .onGloballyPositioned {
+                                box3LayoutCoordinates = it
+                            }
+                            .pointerInput(Unit) {
+                                awaitPointerEventScope {
+                                    while (true) {
+                                        pointerEvent = awaitPointerEvent()
+                                        eventsThatShouldNotTrigger = true
+                                    }
+                                }
+                            }
+                    ) { }
+                }
+            }
+        }
+        // Ensure Arrange (setup) step is finished
+        assertTrue(setUpFinishedLatch.await(1, TimeUnit.SECONDS))
+
+        // --> Act + Assert (interwoven)
+        // Hover Enter on Box 1
+        dispatchMouseEvent(ACTION_HOVER_ENTER, box1LayoutCoordinates!!)
+        rule.runOnUiThread {
+            assertThat(enterBox1).isTrue()
+            assertThat(pointerEvent).isNotNull()
+            assertThat(eventsThatShouldNotTrigger).isFalse()
+            assertHoverEvent(pointerEvent!!, isEnter = true)
+        }
+
+        // Hover Move to Box 2
+        pointerEvent = null // Reset before each event
+        dispatchMouseEvent(ACTION_HOVER_MOVE, box2LayoutCoordinates!!)
+        rule.runOnUiThread {
+            assertThat(exitBox1).isTrue()
+            assertThat(enterBox2).isTrue()
+            assertThat(pointerEvent).isNotNull()
+            assertThat(eventsThatShouldNotTrigger).isFalse()
+            assertHoverEvent(pointerEvent!!, isEnter = true)
+        }
+
+        // Hover Exit on Box 2
+        pointerEvent = null // Reset before each event
+        dispatchMouseEvent(ACTION_HOVER_EXIT, box2LayoutCoordinates!!)
+
+        rule.runOnUiThread {
+            assertThat(exitBox2).isTrue()
+            assertThat(pointerEvent).isNotNull()
+            assertThat(eventsThatShouldNotTrigger).isFalse()
+        }
+
+        // Outside event with Box 3 coordinates
+        pointerEvent = null // Reset before each event
+        dispatchMouseEvent(ACTION_OUTSIDE, box3LayoutCoordinates!!)
+
+        // No Compose event should be triggered (b/299074463#comment31)
+        rule.runOnUiThread {
+            assertThat(eventsThatShouldNotTrigger).isFalse()
+            assertThat(pointerEvent).isNull()
+        }
+
+        // Press on Box 2
+        pointerEvent = null // Reset before each event
+        dispatchMouseEvent(ACTION_DOWN, box2LayoutCoordinates!!)
+        rule.runOnUiThread {
+            assertThat(pressBox2).isTrue()
+            assertThat(eventsThatShouldNotTrigger).isFalse()
+            assertThat(pointerEvent).isNotNull()
+        }
+
+        // Release on Box 2
+        pointerEvent = null // Reset before each event
+        dispatchMouseEvent(ACTION_UP, box2LayoutCoordinates!!)
+        rule.runOnUiThread {
+            assertThat(releaseBox2).isTrue()
+            assertThat(eventsThatShouldNotTrigger).isFalse()
+            assertThat(pointerEvent).isNotNull()
+        }
+
+        assertTrue(totalEventLatch.await(1, TimeUnit.SECONDS))
+    }
+
     @Test
     fun dispatchHoverMove() {
         var layoutCoordinates: LayoutCoordinates? = null
@@ -1890,6 +2091,7 @@
         }
     }
 
+    // TODO (jjw): Another option
     @Test
     fun syntheticEventSentAfterUp() {
         val eventLog = mutableListOf()
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/MotionEventAdapter.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/MotionEventAdapter.android.kt
index cf0b7e1..1882f1c 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/MotionEventAdapter.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/input/pointer/MotionEventAdapter.android.kt
@@ -25,6 +25,7 @@
 import android.view.MotionEvent.ACTION_HOVER_ENTER
 import android.view.MotionEvent.ACTION_HOVER_EXIT
 import android.view.MotionEvent.ACTION_HOVER_MOVE
+import android.view.MotionEvent.ACTION_OUTSIDE
 import android.view.MotionEvent.ACTION_POINTER_DOWN
 import android.view.MotionEvent.ACTION_POINTER_UP
 import android.view.MotionEvent.ACTION_SCROLL
@@ -85,7 +86,7 @@
         positionCalculator: PositionCalculator
     ): PointerInputEvent? {
         val action = motionEvent.actionMasked
-        if (action == ACTION_CANCEL) {
+        if (action == ACTION_CANCEL || action == ACTION_OUTSIDE) {
             motionEventToComposePointerIdMap.clear()
             canHover.clear()
             return null
diff --git a/core/core/src/main/java/androidx/core/app/NotificationCompat.java b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
index 33b1459..d684a7b 100644
--- a/core/core/src/main/java/androidx/core/app/NotificationCompat.java
+++ b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
@@ -5622,8 +5622,8 @@
         @Override
         public void apply(NotificationBuilderWithBuilderAccessor builder) {
             if (Build.VERSION.SDK_INT >= 24) {
-                Api16Impl.setStyle(builder.getBuilder(),
-                        Api24Impl.createDecoratedCustomViewStyle());
+                Notification.Builder builder1 = builder.getBuilder();
+                builder1.setStyle(Api24Impl.createDecoratedCustomViewStyle());
 
             }
         }
@@ -5737,51 +5737,12 @@
             if (!tombstone) {
                 button.setOnClickPendingIntent(R.id.action_container, action.actionIntent);
             }
-            if (Build.VERSION.SDK_INT >= 15) {
-                Api15Impl.setContentDescription(button, R.id.action_container, action.title);
-            }
+            button.setContentDescription(R.id.action_container, action.title);
             return button;
         }
 
         /**
          * A class for wrapping calls to {@link Notification.DecoratedCustomViewStyle} methods which
-         * were added in API 15; these calls must be wrapped to avoid performance issues.
-         * See the UnsafeNewApiCall lint rule for more details.
-         */
-        @RequiresApi(15)
-        static class Api15Impl {
-            private Api15Impl() { }
-
-            @DoNotInline
-            static void setContentDescription(RemoteViews remoteViews, int viewId,
-                    CharSequence contentDescription) {
-                remoteViews.setContentDescription(viewId, contentDescription);
-            }
-        }
-
-        /**
-         * A class for wrapping calls to {@link Notification.DecoratedCustomViewStyle} methods which
-         * were added in API 16; these calls must be wrapped to avoid performance issues.
-         * See the UnsafeNewApiCall lint rule for more details.
-         * Note that the runtime converts NewApi classes to Object during init, but only for
-         * initialized classes; if setStyle is passed style objects from newer API versions, if
-         * the type of those objects will be unknown, and a VerifyError will occur. To prevent
-         * this, we explicitly cast the provided style Object to Notification.Style.
-         */
-        @RequiresApi(16)
-        static class Api16Impl {
-            private Api16Impl() { }
-
-            @DoNotInline
-            static Notification.Builder setStyle(Notification.Builder builder,
-                    Object style) {
-                return builder.setStyle((Notification.Style) style);
-            }
-
-        }
-
-        /**
-         * A class for wrapping calls to {@link Notification.DecoratedCustomViewStyle} methods which
          * were added in API 24; these calls must be wrapped to avoid performance issues.
          * See the UnsafeNewApiCall lint rule for more details.
          */
@@ -5790,7 +5751,7 @@
             private Api24Impl() { }
 
             @DoNotInline
-            static Notification.DecoratedCustomViewStyle createDecoratedCustomViewStyle() {
+            static Notification.Style createDecoratedCustomViewStyle() {
                 return new Notification.DecoratedCustomViewStyle();
             }
 
diff --git a/core/core/src/main/java/androidx/core/content/IntentCompat.java b/core/core/src/main/java/androidx/core/content/IntentCompat.java
index db25773..0e4196d 100644
--- a/core/core/src/main/java/androidx/core/content/IntentCompat.java
+++ b/core/core/src/main/java/androidx/core/content/IntentCompat.java
@@ -120,16 +120,7 @@
     @NonNull
     public static Intent makeMainSelectorActivity(@NonNull String selectorAction,
             @NonNull String selectorCategory) {
-        if (Build.VERSION.SDK_INT >= 15) {
-            return Api15Impl.makeMainSelectorActivity(selectorAction, selectorCategory);
-        } else {
-            // Before api 15 you couldn't set a selector intent.
-            // Fall back and just return an intent with the requested action/category,
-            // even though it won't be a proper "main" intent.
-            Intent intent = new Intent(selectorAction);
-            intent.addCategory(selectorCategory);
-            return intent;
-        }
+        return Intent.makeMainSelectorActivity(selectorAction, selectorCategory);
     }
 
     /**
@@ -298,18 +289,6 @@
         }
     }
 
-    @RequiresApi(15)
-    static class Api15Impl {
-        private Api15Impl() {
-            // This class is not instantiable.
-        }
-
-        @DoNotInline
-        static Intent makeMainSelectorActivity(String selectorAction, String selectorCategory) {
-            return Intent.makeMainSelectorActivity(selectorAction, selectorCategory);
-        }
-    }
-
     @RequiresApi(33)
     static class Api33Impl {
         private Api33Impl() {
diff --git a/core/core/src/main/java/androidx/core/content/IntentSanitizer.java b/core/core/src/main/java/androidx/core/content/IntentSanitizer.java
index aab9a33..421ba7c 100644
--- a/core/core/src/main/java/androidx/core/content/IntentSanitizer.java
+++ b/core/core/src/main/java/androidx/core/content/IntentSanitizer.java
@@ -207,10 +207,8 @@
             }
         }
 
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
-            Api16Impl.sanitizeClipData(in, intent, mAllowedClipData, mAllowClipDataText,
-                    mAllowedClipDataUri, penalty);
-        }
+        sanitizeClipData(in, intent, mAllowedClipData, mAllowClipDataText, mAllowedClipDataUri,
+                penalty);
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
             if (mAllowIdentifier) {
@@ -220,12 +218,10 @@
             }
         }
 
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
-            if (mAllowSelector) {
-                Api15Impl.setSelector(intent, Api15Impl.getSelector(in));
-            } else if (Api15Impl.getSelector(in) != null) {
-                penalty.accept("Selector is not allowed: " + Api15Impl.getSelector(in));
-            }
+        if (mAllowSelector) {
+            intent.setSelector(in.getSelector());
+        } else if (in.getSelector() != null) {
+            penalty.accept("Selector is not allowed: " + in.getSelector());
         }
 
         if (mAllowSourceBounds) {
@@ -879,113 +875,89 @@
         }
     }
 
-    @RequiresApi(15)
-    private static class Api15Impl {
-        private Api15Impl() {
-            // This class is not instantiable.
-        }
+    static void sanitizeClipData(@NonNull Intent in, Intent out,
+            Predicate mAllowedClipData,
+            boolean mAllowClipDataText,
+            Predicate mAllowedClipDataUri, Consumer penalty) {
+        ClipData clipData = in.getClipData();
 
-        @DoNotInline
-        static void setSelector(Intent intent, Intent selector) {
-            intent.setSelector(selector);
-        }
+        if (clipData == null) return;
 
-        @DoNotInline
-        static Intent getSelector(Intent intent) {
-            return intent.getSelector();
+        ClipData newClipData = null;
+        if (mAllowedClipData != null && mAllowedClipData.test(clipData)) {
+            out.setClipData(clipData);
+        } else {
+            for (int i = 0; i < clipData.getItemCount(); i++) {
+                ClipData.Item item = clipData.getItemAt(i);
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+                    Api31Impl.checkOtherMembers(i, item, penalty);
+                } else {
+                    checkOtherMembers(i, item, penalty);
+                }
+
+                CharSequence itemText = null;
+                if (mAllowClipDataText) {
+                    itemText = item.getText();
+                } else {
+                    if (item.getText() != null) {
+                        penalty.accept(
+                                "Item text cannot contain value. Item position: " + i + "."
+                                        + " Text: " + item.getText());
+                    }
+                }
+
+                Uri itemUri = null;
+                if (mAllowedClipDataUri == null) {
+                    if (item.getUri() != null) {
+                        penalty.accept(
+                                "Item URI is not allowed. Item position: " + i + ". URI: "
+                                        + item.getUri());
+                    }
+                } else {
+                    if (item.getUri() == null || mAllowedClipDataUri.test(item.getUri())) {
+                        itemUri = item.getUri();
+                    } else {
+                        penalty.accept(
+                                "Item URI is not allowed. Item position: " + i + ". URI: "
+                                        + item.getUri());
+                    }
+                }
+
+                if (itemText != null || itemUri != null) {
+                    if (newClipData == null) {
+                        newClipData = new ClipData(clipData.getDescription(),
+                                new ClipData.Item(itemText, null, itemUri));
+                    } else {
+                        newClipData.addItem(new ClipData.Item(itemText, null, itemUri));
+                    }
+                }
+            }
+            if (newClipData != null) {
+                out.setClipData(newClipData);
+            }
         }
     }
 
-    @RequiresApi(16)
-    private static class Api16Impl {
-        private Api16Impl() {
+    private static void checkOtherMembers(int i, ClipData.Item item, Consumer penalty) {
+        if (item.getHtmlText() != null || item.getIntent() != null) {
+            penalty.accept("ClipData item at position " + i + " contains htmlText, "
+                    + "textLinks or intent: " + item);
+        }
+    }
+
+    @RequiresApi(31)
+    private static class Api31Impl {
+        private Api31Impl() {
         }
 
         @DoNotInline
-        static void sanitizeClipData(@NonNull Intent in, Intent out,
-                Predicate mAllowedClipData,
-                boolean mAllowClipDataText,
-                Predicate mAllowedClipDataUri, Consumer penalty) {
-            ClipData clipData = in.getClipData();
-
-            if (clipData == null) return;
-
-            ClipData newClipData = null;
-            if (mAllowedClipData != null && mAllowedClipData.test(clipData)) {
-                out.setClipData(clipData);
-            } else {
-                for (int i = 0; i < clipData.getItemCount(); i++) {
-                    ClipData.Item item = clipData.getItemAt(i);
-                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
-                        Api31Impl.checkOtherMembers(i, item, penalty);
-                    } else {
-                        checkOtherMembers(i, item, penalty);
-                    }
-
-                    CharSequence itemText = null;
-                    if (mAllowClipDataText) {
-                        itemText = item.getText();
-                    } else {
-                        if (item.getText() != null) {
-                            penalty.accept(
-                                    "Item text cannot contain value. Item position: " + i + "."
-                                            + " Text: " + item.getText());
-                        }
-                    }
-
-                    Uri itemUri = null;
-                    if (mAllowedClipDataUri == null) {
-                        if (item.getUri() != null) {
-                            penalty.accept(
-                                    "Item URI is not allowed. Item position: " + i + ". URI: "
-                                            + item.getUri());
-                        }
-                    } else {
-                        if (item.getUri() == null || mAllowedClipDataUri.test(item.getUri())) {
-                            itemUri = item.getUri();
-                        } else {
-                            penalty.accept(
-                                    "Item URI is not allowed. Item position: " + i + ". URI: "
-                                            + item.getUri());
-                        }
-                    }
-
-                    if (itemText != null || itemUri != null) {
-                        if (newClipData == null) {
-                            newClipData = new ClipData(clipData.getDescription(),
-                                    new ClipData.Item(itemText, null, itemUri));
-                        } else {
-                            newClipData.addItem(new ClipData.Item(itemText, null, itemUri));
-                        }
-                    }
-                }
-                if (newClipData != null) {
-                    out.setClipData(newClipData);
-                }
-            }
-        }
-
-        private static void checkOtherMembers(int i, ClipData.Item item, Consumer penalty) {
-            if (item.getHtmlText() != null || item.getIntent() != null) {
+        static void checkOtherMembers(int i, ClipData.Item item, Consumer penalty) {
+            if (item.getHtmlText() != null || item.getIntent() != null
+                    || item.getTextLinks() != null) {
                 penalty.accept("ClipData item at position " + i + " contains htmlText, "
                         + "textLinks or intent: " + item);
             }
         }
-
-        @RequiresApi(31)
-        private static class Api31Impl {
-            private Api31Impl() {
-            }
-
-            @DoNotInline
-            static void checkOtherMembers(int i, ClipData.Item item, Consumer penalty) {
-                if (item.getHtmlText() != null || item.getIntent() != null
-                        || item.getTextLinks() != null) {
-                    penalty.accept("ClipData item at position " + i + " contains htmlText, "
-                            + "textLinks or intent: " + item);
-                }
-            }
-        }
     }
 
     @RequiresApi(29)
diff --git a/core/core/src/main/java/androidx/core/content/res/ResourcesCompat.java b/core/core/src/main/java/androidx/core/content/res/ResourcesCompat.java
index 681aa16..a46e557 100644
--- a/core/core/src/main/java/androidx/core/content/res/ResourcesCompat.java
+++ b/core/core/src/main/java/androidx/core/content/res/ResourcesCompat.java
@@ -170,10 +170,8 @@
             int density, @Nullable Theme theme) throws NotFoundException {
         if (SDK_INT >= 21) {
             return Api21Impl.getDrawableForDensity(res, id, density, theme);
-        } else if (SDK_INT >= 15) {
-            return Api15Impl.getDrawableForDensity(res, id, density);
         } else {
-            return res.getDrawable(id);
+            return res.getDrawableForDensity(id, density);
         }
     }
 
@@ -713,19 +711,6 @@
         }
     }
 
-    @RequiresApi(15)
-    static class Api15Impl {
-        private Api15Impl() {
-            // This class is not instantiable.
-        }
-
-        @DoNotInline
-        static Drawable getDrawableForDensity(Resources resources, int id, int density) {
-            return resources.getDrawableForDensity(id, density);
-        }
-
-    }
-
     private ResourcesCompat() {
     }
 
diff --git a/core/core/src/main/java/androidx/core/database/CursorWindowCompat.java b/core/core/src/main/java/androidx/core/database/CursorWindowCompat.java
index 03b0c8f..a2c5681 100644
--- a/core/core/src/main/java/androidx/core/database/CursorWindowCompat.java
+++ b/core/core/src/main/java/androidx/core/database/CursorWindowCompat.java
@@ -43,10 +43,8 @@
     public static CursorWindow create(@Nullable String name, long windowSizeBytes) {
         if (Build.VERSION.SDK_INT >= 28) {
             return Api28Impl.createCursorWindow(name, windowSizeBytes);
-        } else if (Build.VERSION.SDK_INT >= 15) {
-            return Api15Impl.createCursorWindow(name);
         } else {
-            return new CursorWindow(false);
+            return new CursorWindow(name);
         }
     }
 
@@ -61,16 +59,4 @@
             return new CursorWindow(name, windowSizeBytes);
         }
     }
-
-    @RequiresApi(15)
-    static class Api15Impl {
-        private Api15Impl() {
-            // This class is not instantiable.
-        }
-
-        @DoNotInline
-        static CursorWindow createCursorWindow(String name) {
-            return new CursorWindow(name);
-        }
-    }
 }
diff --git a/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/EmojiExtractTextLayoutTest.java b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/EmojiExtractTextLayoutTest.java
index c7995bf..458819de 100644
--- a/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/EmojiExtractTextLayoutTest.java
+++ b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/EmojiExtractTextLayoutTest.java
@@ -31,14 +31,12 @@
 
 import android.content.Context;
 import android.inputmethodservice.InputMethodService;
-import android.os.Build;
 import android.text.InputType;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.inputmethod.EditorInfo;
 
-import androidx.annotation.RequiresApi;
 import androidx.emoji2.text.EmojiCompat;
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.core.app.ApplicationProvider;
@@ -150,7 +148,6 @@
                 eq(EmojiCompat.REPLACE_STRATEGY_NON_EXISTENT));
     }
 
-    @RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
     @Test
     @UiThreadTest
     public void testOnUpdateExtractingViews() {
@@ -179,7 +176,6 @@
         assertTrue(extractButton.hasOnClickListeners());
     }
 
-    @RequiresApi(api = Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
     @Test
     @UiThreadTest
     public void testOnUpdateExtractingViews_hidesAccessoriesIfNoAction() {
diff --git a/glance/glance-preview/api/current.txt b/glance/glance-preview/api/current.txt
index 46a9a9d..fc59a6d 100644
--- a/glance/glance-preview/api/current.txt
+++ b/glance/glance-preview/api/current.txt
@@ -4,13 +4,13 @@
   @SuppressCompatibility @kotlin.RequiresOptIn(message="This API is experimental and is likely to change in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalGlancePreviewApi {
   }
 
-  @SuppressCompatibility @androidx.glance.preview.ExperimentalGlancePreviewApi @kotlin.annotation.Repeatable @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public @interface GlancePreview {
+  @SuppressCompatibility @androidx.glance.preview.ExperimentalGlancePreviewApi @kotlin.annotation.Repeatable @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public @interface Preview {
     method public abstract String surface();
     property public abstract String surface;
   }
 
-  @SuppressCompatibility @androidx.glance.preview.ExperimentalGlancePreviewApi @kotlin.annotation.Repeatable @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public static @interface GlancePreview.Container {
-    method public abstract androidx.glance.preview.GlancePreview[] value();
+  @SuppressCompatibility @androidx.glance.preview.ExperimentalGlancePreviewApi @kotlin.annotation.Repeatable @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public static @interface Preview.Container {
+    method public abstract androidx.glance.preview.Preview[] value();
   }
 
   @SuppressCompatibility @androidx.glance.preview.ExperimentalGlancePreviewApi public final class Surfaces {
diff --git a/glance/glance-preview/api/restricted_current.txt b/glance/glance-preview/api/restricted_current.txt
index 46a9a9d..fc59a6d 100644
--- a/glance/glance-preview/api/restricted_current.txt
+++ b/glance/glance-preview/api/restricted_current.txt
@@ -4,13 +4,13 @@
   @SuppressCompatibility @kotlin.RequiresOptIn(message="This API is experimental and is likely to change in the future.") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) public @interface ExperimentalGlancePreviewApi {
   }
 
-  @SuppressCompatibility @androidx.glance.preview.ExperimentalGlancePreviewApi @kotlin.annotation.Repeatable @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public @interface GlancePreview {
+  @SuppressCompatibility @androidx.glance.preview.ExperimentalGlancePreviewApi @kotlin.annotation.Repeatable @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public @interface Preview {
     method public abstract String surface();
     property public abstract String surface;
   }
 
-  @SuppressCompatibility @androidx.glance.preview.ExperimentalGlancePreviewApi @kotlin.annotation.Repeatable @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public static @interface GlancePreview.Container {
-    method public abstract androidx.glance.preview.GlancePreview[] value();
+  @SuppressCompatibility @androidx.glance.preview.ExperimentalGlancePreviewApi @kotlin.annotation.Repeatable @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.SOURCE) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS, kotlin.annotation.AnnotationTarget.FUNCTION}) public static @interface Preview.Container {
+    method public abstract androidx.glance.preview.Preview[] value();
   }
 
   @SuppressCompatibility @androidx.glance.preview.ExperimentalGlancePreviewApi public final class Surfaces {
diff --git a/glance/glance-preview/src/main/java/androidx/glance/preview/GlancePreview.kt b/glance/glance-preview/src/main/java/androidx/glance/preview/Preview.kt
similarity index 93%
rename from glance/glance-preview/src/main/java/androidx/glance/preview/GlancePreview.kt
rename to glance/glance-preview/src/main/java/androidx/glance/preview/Preview.kt
index cdc9027..fb20c35 100644
--- a/glance/glance-preview/src/main/java/androidx/glance/preview/GlancePreview.kt
+++ b/glance/glance-preview/src/main/java/androidx/glance/preview/Preview.kt
@@ -26,4 +26,4 @@
 )
 @ExperimentalGlancePreviewApi
 @Repeatable
-annotation class GlancePreview(@Surface val surface: String)
+annotation class Preview(@Surface val surface: String)
diff --git a/glance/glance-preview/src/main/java/androidx/glance/preview/Surface.kt b/glance/glance-preview/src/main/java/androidx/glance/preview/Surface.kt
index 6e118cf..e543b6f 100644
--- a/glance/glance-preview/src/main/java/androidx/glance/preview/Surface.kt
+++ b/glance/glance-preview/src/main/java/androidx/glance/preview/Surface.kt
@@ -22,7 +22,7 @@
 /**
  * The list of glance surfaces that have preview available. The list will grow as more glance
  * surfaces are added and allow the preview functionality. Items should be used as values for
- * surface parameter in [GlancePreview] annotation.
+ * surface parameter in glance [Preview] annotation.
  */
 @ExperimentalGlancePreviewApi
 object Surfaces {
@@ -33,7 +33,7 @@
 /**
  * The annotation that ensures that the variable value is strictly a recognized glance surface.
  *
- * @see GlancePreview annotation
+ * @see glance [Preview] annotation
  */
 @Retention(AnnotationRetention.SOURCE)
 @OptIn(ExperimentalGlancePreviewApi::class)
diff --git a/media/media/src/main/java/androidx/media/app/NotificationCompat.java b/media/media/src/main/java/androidx/media/app/NotificationCompat.java
index 56928a6..bde7799 100644
--- a/media/media/src/main/java/androidx/media/app/NotificationCompat.java
+++ b/media/media/src/main/java/androidx/media/app/NotificationCompat.java
@@ -320,9 +320,8 @@
             if (!tombstone) {
                 button.setOnClickPendingIntent(R.id.action0, action.getActionIntent());
             }
-            if (Build.VERSION.SDK_INT >= 15) {
-                Api15Impl.setContentDescription(button, R.id.action0, action.getTitle());
-            }
+            CharSequence contentDescription = action.getTitle();
+            button.setContentDescription(R.id.action0, contentDescription);
             return button;
         }
 
@@ -539,17 +538,6 @@
         }
     }
 
-    @RequiresApi(15)
-    private static class Api15Impl {
-        private Api15Impl() {}
-
-        @DoNotInline
-        static void setContentDescription(RemoteViews remoteViews, int viewId,
-                CharSequence contentDescription) {
-            remoteViews.setContentDescription(viewId, contentDescription);
-        }
-    }
-
     @RequiresApi(21)
     private static class Api21Impl {
         private Api21Impl() {}
diff --git a/metrics/metrics-performance/src/androidTest/java/androidx/metrics/performance/test/JankStatsTest.kt b/metrics/metrics-performance/src/androidTest/java/androidx/metrics/performance/test/JankStatsTest.kt
index 1e9c73d..5f5f9ec 100644
--- a/metrics/metrics-performance/src/androidTest/java/androidx/metrics/performance/test/JankStatsTest.kt
+++ b/metrics/metrics-performance/src/androidTest/java/androidx/metrics/performance/test/JankStatsTest.kt
@@ -15,7 +15,6 @@
  */
 package androidx.metrics.performance.test
 
-import android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1
 import android.view.Choreographer
 import androidx.metrics.performance.FrameData
 import androidx.metrics.performance.FrameDataApi24
@@ -28,7 +27,6 @@
 import androidx.test.ext.junit.rules.ActivityScenarioRule
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
-import androidx.test.filters.SdkSuppress
 import java.util.concurrent.CountDownLatch
 import java.util.concurrent.TimeUnit
 import kotlin.math.max
@@ -430,23 +428,6 @@
         latchedListener.reset()
     }
 
-    /**
-     * JankStats doesn't do anything pre API 16. But it would be nice to not crash running
-     * code that calls JankStats functionality on that version. This test just calls basic APIs
-     * to make sure they don't crash.
-     */
-    @SdkSuppress(maxSdkVersion = ICE_CREAM_SANDWICH_MR1)
-    @Test
-    fun testPreAPI16() {
-        delayedActivityRule.getScenario().onActivity {
-            val state0 = StateInfo("Testing State 0", "sampleStateA")
-            val state1 = StateInfo("Testing State 1", "sampleStateB")
-            metricsState.putState(state0.key, state0.value)
-            metricsState.putSingleFrameState(state1.key, state1.value)
-        }
-        runDelayTest(0, NUM_FRAMES, latchedListener)
-    }
-
     @Test
     fun testComplexFrameStateData() {
         initFramePipeline()
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewBasicTest.java b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewBasicTest.java
index de765ab3..f524970 100644
--- a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewBasicTest.java
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/RecyclerViewBasicTest.java
@@ -554,15 +554,10 @@
         measure();
         layout();
 
-        boolean isIcsOrLower = Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1;
-
-        // On API 15 and lower, focus forward get's translated to focus down.
-        View expected = isIcsOrLower ? focusAdapter.mBottomRight : focusAdapter.mBottomLeft;
+        View expected = focusAdapter.mBottomLeft;
         assertEquals(expected, focusAdapter.mTopRight.focusSearch(View.FOCUS_FORWARD));
 
-        // On API 15 and lower, focus forward get's translated to focus down, which in this case
-        // runs out of the RecyclerView, thus returning null.
-        expected = isIcsOrLower ? null : focusAdapter.mBottomRight;
+        expected = focusAdapter.mBottomRight;
         assertSame(expected, focusAdapter.mBottomLeft.focusSearch(View.FOCUS_FORWARD));
 
         // we don't want looping within RecyclerView
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/SuspendingQueryTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/SuspendingQueryTest.kt
index 37f6425..5356759 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/SuspendingQueryTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/SuspendingQueryTest.kt
@@ -17,7 +17,6 @@
 package androidx.room.integration.kotlintestapp.test
 
 import android.content.Context
-import android.os.Build
 import android.os.StrictMode
 import android.os.StrictMode.ThreadPolicy
 import androidx.arch.core.executor.ArchTaskExecutor
@@ -1017,16 +1016,11 @@
                     database.endTransaction()
                 }
             } catch (ex: IllegalStateException) {
-                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
-                    assertThat(ex).hasMessageThat()
-                        .contains(
-                            "Cannot perform this operation because there is no current " +
-                                "transaction"
-                        )
-                } else {
-                    assertThat(ex).hasMessageThat()
-                        .contains("Don't have database lock")
-                }
+                assertThat(ex).hasMessageThat()
+                    .contains(
+                        "Cannot perform this operation because there is no current " +
+                            "transaction"
+                    )
             }
         }
     }
@@ -1044,16 +1038,11 @@
                     throw RuntimeException()
                 }
             } catch (ex: IllegalStateException) {
-                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
-                    assertThat(ex).hasMessageThat()
-                        .contains(
-                            "Cannot perform this operation because there is no current " +
-                                "transaction"
-                        )
-                } else {
-                    assertThat(ex).hasMessageThat()
-                        .contains("Don't have database lock")
-                }
+                assertThat(ex).hasMessageThat()
+                    .contains(
+                        "Cannot perform this operation because there is no current " +
+                            "transaction"
+                    )
             }
         }
     }
diff --git a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/CursorUtil.android.kt b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/CursorUtil.android.kt
index 6e94283..b079c79 100644
--- a/room/room-runtime/src/androidMain/kotlin/androidx/room/util/CursorUtil.android.kt
+++ b/room/room-runtime/src/androidMain/kotlin/androidx/room/util/CursorUtil.android.kt
@@ -142,15 +142,7 @@
  * closes the Cursor.
  */
 inline fun  Cursor.useCursor(block: (Cursor) -> R): R {
-    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
-        return this.use(block)
-    } else {
-        try {
-            return block(this)
-        } finally {
-            this.close()
-        }
-    }
+    return this.use(block)
 }
 
 /**
diff --git a/settings.gradle b/settings.gradle
index 8160f4c..114e351 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -505,6 +505,7 @@
 includeProject(":compose:material3:benchmark", [BuildType.COMPOSE])
 includeProject(":compose:material3:material3-adaptive", [BuildType.COMPOSE])
 includeProject(":compose:material3:material3-adaptive:material3-adaptive-samples", "compose/material3/material3-adaptive/samples", [BuildType.COMPOSE])
+includeProject(":compose:material3:material3-adaptive:material3-adaptive-benchmark", "compose/material3/material3-adaptive/benchmark", [BuildType.COMPOSE])
 includeProject(":compose:material3:material3-adaptive-navigation-suite", [BuildType.COMPOSE])
 includeProject(":compose:material3:material3-adaptive-navigation-suite:material3-adaptive-navigation-suite-samples", "compose/material3/material3-adaptive-navigation-suite/samples", [BuildType.COMPOSE])
 includeProject(":compose:material3:material3-common", [BuildType.COMPOSE])
diff --git a/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
index 721e6f1..48f23b3 100644
--- a/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
+++ b/viewpager2/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
@@ -403,12 +403,6 @@
         }
 
         waitForRenderLatch.await(5, TimeUnit.SECONDS)
-
-        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
-            // Give slow devices some time to warm up,
-            // to prevent severe frame drops in the smooth scroll
-            Thread.sleep(1000)
-        }
     }
 
     fun ViewPager2.addWaitForLayoutChangeLatch(): CountDownLatch {