Merge "BanTargetApiAnnotation check now actually looks for the annotation and not usages of methods annotated by it." into androidx-master-dev
diff --git a/activity/activity-ktx/api/1.2.0-beta01.txt b/activity/activity-ktx/api/1.2.0-beta01.txt
new file mode 100644
index 0000000..ec6569a
--- /dev/null
+++ b/activity/activity-ktx/api/1.2.0-beta01.txt
@@ -0,0 +1,40 @@
+// Signature format: 3.0
+package androidx.activity {
+
+  public final class ActivityViewModelLazyKt {
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! viewModels(androidx.activity.ComponentActivity, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+  }
+
+  public final class OnBackPressedDispatcherKt {
+    method public static androidx.activity.OnBackPressedCallback addCallback(androidx.activity.OnBackPressedDispatcher, androidx.lifecycle.LifecycleOwner? owner = null, boolean enabled = true, kotlin.jvm.functions.Function1<? super androidx.activity.OnBackPressedCallback,kotlin.Unit> onBackPressed);
+  }
+
+}
+
+package androidx.activity.contextaware {
+
+  public final class ContextAwareKt {
+    method public static suspend inline <R> Object? withContextAvailable(androidx.activity.contextaware.ContextAware, kotlin.jvm.functions.Function1<? super android.content.Context,? extends R> onContextAvailable, kotlin.coroutines.Continuation<? super R> p);
+  }
+
+}
+
+package androidx.activity.result {
+
+  public final class ActivityResultCallerKt {
+    method public static <I, O> androidx.activity.result.ActivityResultLauncher<kotlin.Unit> registerForActivityResult(androidx.activity.result.ActivityResultCaller, androidx.activity.result.contract.ActivityResultContract<I,O> contract, I? input, androidx.activity.result.ActivityResultRegistry registry, kotlin.jvm.functions.Function1<? super O,kotlin.Unit> callback);
+    method public static <I, O> androidx.activity.result.ActivityResultLauncher<kotlin.Unit> registerForActivityResult(androidx.activity.result.ActivityResultCaller, androidx.activity.result.contract.ActivityResultContract<I,O> contract, I? input, kotlin.jvm.functions.Function1<? super O,kotlin.Unit> callback);
+  }
+
+  public final class ActivityResultKt {
+    method public static operator int component1(androidx.activity.result.ActivityResult);
+    method public static operator android.content.Intent? component2(androidx.activity.result.ActivityResult);
+  }
+
+  public final class ActivityResultLauncherKt {
+    method public static void launch(androidx.activity.result.ActivityResultLauncher<java.lang.Void>, androidx.core.app.ActivityOptionsCompat? options = null);
+    method public static void launchUnit(androidx.activity.result.ActivityResultLauncher<kotlin.Unit>, androidx.core.app.ActivityOptionsCompat? options = null);
+  }
+
+}
+
diff --git a/activity/activity-ktx/api/public_plus_experimental_1.2.0-beta01.txt b/activity/activity-ktx/api/public_plus_experimental_1.2.0-beta01.txt
new file mode 100644
index 0000000..ec6569a
--- /dev/null
+++ b/activity/activity-ktx/api/public_plus_experimental_1.2.0-beta01.txt
@@ -0,0 +1,40 @@
+// Signature format: 3.0
+package androidx.activity {
+
+  public final class ActivityViewModelLazyKt {
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! viewModels(androidx.activity.ComponentActivity, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+  }
+
+  public final class OnBackPressedDispatcherKt {
+    method public static androidx.activity.OnBackPressedCallback addCallback(androidx.activity.OnBackPressedDispatcher, androidx.lifecycle.LifecycleOwner? owner = null, boolean enabled = true, kotlin.jvm.functions.Function1<? super androidx.activity.OnBackPressedCallback,kotlin.Unit> onBackPressed);
+  }
+
+}
+
+package androidx.activity.contextaware {
+
+  public final class ContextAwareKt {
+    method public static suspend inline <R> Object? withContextAvailable(androidx.activity.contextaware.ContextAware, kotlin.jvm.functions.Function1<? super android.content.Context,? extends R> onContextAvailable, kotlin.coroutines.Continuation<? super R> p);
+  }
+
+}
+
+package androidx.activity.result {
+
+  public final class ActivityResultCallerKt {
+    method public static <I, O> androidx.activity.result.ActivityResultLauncher<kotlin.Unit> registerForActivityResult(androidx.activity.result.ActivityResultCaller, androidx.activity.result.contract.ActivityResultContract<I,O> contract, I? input, androidx.activity.result.ActivityResultRegistry registry, kotlin.jvm.functions.Function1<? super O,kotlin.Unit> callback);
+    method public static <I, O> androidx.activity.result.ActivityResultLauncher<kotlin.Unit> registerForActivityResult(androidx.activity.result.ActivityResultCaller, androidx.activity.result.contract.ActivityResultContract<I,O> contract, I? input, kotlin.jvm.functions.Function1<? super O,kotlin.Unit> callback);
+  }
+
+  public final class ActivityResultKt {
+    method public static operator int component1(androidx.activity.result.ActivityResult);
+    method public static operator android.content.Intent? component2(androidx.activity.result.ActivityResult);
+  }
+
+  public final class ActivityResultLauncherKt {
+    method public static void launch(androidx.activity.result.ActivityResultLauncher<java.lang.Void>, androidx.core.app.ActivityOptionsCompat? options = null);
+    method public static void launchUnit(androidx.activity.result.ActivityResultLauncher<kotlin.Unit>, androidx.core.app.ActivityOptionsCompat? options = null);
+  }
+
+}
+
diff --git a/activity/activity-ktx/api/res-1.2.0-beta01.txt b/activity/activity-ktx/api/res-1.2.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/activity/activity-ktx/api/res-1.2.0-beta01.txt
diff --git a/activity/activity-ktx/api/restricted_1.2.0-beta01.txt b/activity/activity-ktx/api/restricted_1.2.0-beta01.txt
new file mode 100644
index 0000000..ec6569a
--- /dev/null
+++ b/activity/activity-ktx/api/restricted_1.2.0-beta01.txt
@@ -0,0 +1,40 @@
+// Signature format: 3.0
+package androidx.activity {
+
+  public final class ActivityViewModelLazyKt {
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! viewModels(androidx.activity.ComponentActivity, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+  }
+
+  public final class OnBackPressedDispatcherKt {
+    method public static androidx.activity.OnBackPressedCallback addCallback(androidx.activity.OnBackPressedDispatcher, androidx.lifecycle.LifecycleOwner? owner = null, boolean enabled = true, kotlin.jvm.functions.Function1<? super androidx.activity.OnBackPressedCallback,kotlin.Unit> onBackPressed);
+  }
+
+}
+
+package androidx.activity.contextaware {
+
+  public final class ContextAwareKt {
+    method public static suspend inline <R> Object? withContextAvailable(androidx.activity.contextaware.ContextAware, kotlin.jvm.functions.Function1<? super android.content.Context,? extends R> onContextAvailable, kotlin.coroutines.Continuation<? super R> p);
+  }
+
+}
+
+package androidx.activity.result {
+
+  public final class ActivityResultCallerKt {
+    method public static <I, O> androidx.activity.result.ActivityResultLauncher<kotlin.Unit> registerForActivityResult(androidx.activity.result.ActivityResultCaller, androidx.activity.result.contract.ActivityResultContract<I,O> contract, I? input, androidx.activity.result.ActivityResultRegistry registry, kotlin.jvm.functions.Function1<? super O,kotlin.Unit> callback);
+    method public static <I, O> androidx.activity.result.ActivityResultLauncher<kotlin.Unit> registerForActivityResult(androidx.activity.result.ActivityResultCaller, androidx.activity.result.contract.ActivityResultContract<I,O> contract, I? input, kotlin.jvm.functions.Function1<? super O,kotlin.Unit> callback);
+  }
+
+  public final class ActivityResultKt {
+    method public static operator int component1(androidx.activity.result.ActivityResult);
+    method public static operator android.content.Intent? component2(androidx.activity.result.ActivityResult);
+  }
+
+  public final class ActivityResultLauncherKt {
+    method public static void launch(androidx.activity.result.ActivityResultLauncher<java.lang.Void>, androidx.core.app.ActivityOptionsCompat? options = null);
+    method public static void launchUnit(androidx.activity.result.ActivityResultLauncher<kotlin.Unit>, androidx.core.app.ActivityOptionsCompat? options = null);
+  }
+
+}
+
diff --git a/activity/activity/api/1.2.0-beta01.txt b/activity/activity/api/1.2.0-beta01.txt
new file mode 100644
index 0000000..4e9dd74
--- /dev/null
+++ b/activity/activity/api/1.2.0-beta01.txt
@@ -0,0 +1,259 @@
+// Signature format: 3.0
+package androidx.activity {
+
+  public class ComponentActivity extends android.app.Activity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.activity.contextaware.ContextAware androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+    ctor public ComponentActivity();
+    ctor @ContentView public ComponentActivity(@LayoutRes int);
+    method public final void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public final androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+    method @Deprecated public Object? getLastCustomNonConfigurationInstance();
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+    method public final androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+    method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+    method public androidx.lifecycle.ViewModelStore getViewModelStore();
+    method @Deprecated @CallSuper protected void onActivityResult(int, int, android.content.Intent?);
+    method @Deprecated @CallSuper public void onRequestPermissionsResult(int, String![], int[]);
+    method @Deprecated public Object? onRetainCustomNonConfigurationInstance();
+    method public final Object? onRetainNonConfigurationInstance();
+    method public android.content.Context? peekAvailableContext();
+    method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+    method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+    method public final void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method @Deprecated public void startActivityForResult(android.content.Intent!, int);
+    method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
+    method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int) throws android.content.IntentSender.SendIntentException;
+    method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+  }
+
+  public abstract class OnBackPressedCallback {
+    ctor public OnBackPressedCallback(boolean);
+    method @MainThread public abstract void handleOnBackPressed();
+    method @MainThread public final boolean isEnabled();
+    method @MainThread public final void remove();
+    method @MainThread public final void setEnabled(boolean);
+  }
+
+  public final class OnBackPressedDispatcher {
+    ctor public OnBackPressedDispatcher();
+    ctor public OnBackPressedDispatcher(Runnable?);
+    method @MainThread public void addCallback(androidx.activity.OnBackPressedCallback);
+    method @MainThread public void addCallback(androidx.lifecycle.LifecycleOwner, androidx.activity.OnBackPressedCallback);
+    method @MainThread public boolean hasEnabledCallbacks();
+    method @MainThread public void onBackPressed();
+  }
+
+  public interface OnBackPressedDispatcherOwner extends androidx.lifecycle.LifecycleOwner {
+    method public androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+  }
+
+}
+
+package androidx.activity.contextaware {
+
+  public interface ContextAware {
+    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public android.content.Context? peekAvailableContext();
+    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+  }
+
+  public final class ContextAwareHelper {
+    ctor public ContextAwareHelper();
+    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public void clearAvailableContext();
+    method public void dispatchOnContextAvailable(android.content.Context);
+    method public android.content.Context? peekAvailableContext();
+    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+  }
+
+  public interface OnContextAvailableListener {
+    method public void onContextAvailable(android.content.Context);
+  }
+
+}
+
+package androidx.activity.result {
+
+  public final class ActivityResult implements android.os.Parcelable {
+    ctor public ActivityResult(int, android.content.Intent?);
+    method public int describeContents();
+    method public android.content.Intent? getData();
+    method public int getResultCode();
+    method public static String resultCodeToString(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.activity.result.ActivityResult!> CREATOR;
+  }
+
+  public interface ActivityResultCallback<O> {
+    method public void onActivityResult(O!);
+  }
+
+  public interface ActivityResultCaller {
+    method public <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+    method public <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+  }
+
+  public abstract class ActivityResultLauncher<I> {
+    ctor public ActivityResultLauncher();
+    method public abstract androidx.activity.result.contract.ActivityResultContract<I!,?> getContract();
+    method public void launch(I!);
+    method public abstract void launch(I!, androidx.core.app.ActivityOptionsCompat?);
+    method @MainThread public abstract void unregister();
+  }
+
+  public abstract class ActivityResultRegistry {
+    ctor public ActivityResultRegistry();
+    method @MainThread public final boolean dispatchResult(int, int, android.content.Intent?);
+    method @MainThread public final <O> boolean dispatchResult(int, O!);
+    method @MainThread public abstract <I, O> void onLaunch(int, androidx.activity.result.contract.ActivityResultContract<I!,O!>, I!, androidx.core.app.ActivityOptionsCompat?);
+    method public final void onRestoreInstanceState(android.os.Bundle?);
+    method public final void onSaveInstanceState(android.os.Bundle);
+    method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> register(String, androidx.lifecycle.LifecycleOwner, androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+    method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> register(String, androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+  }
+
+  public interface ActivityResultRegistryOwner {
+    method public androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
+  }
+
+  public final class IntentSenderRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.Intent? getFillInIntent();
+    method public int getFlagsMask();
+    method public int getFlagsValues();
+    method public android.content.IntentSender getIntentSender();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.activity.result.IntentSenderRequest!> CREATOR;
+  }
+
+  public static final class IntentSenderRequest.Builder {
+    ctor public IntentSenderRequest.Builder(android.content.IntentSender);
+    ctor public IntentSenderRequest.Builder(android.app.PendingIntent);
+    method public androidx.activity.result.IntentSenderRequest build();
+    method public androidx.activity.result.IntentSenderRequest.Builder setFillInIntent(android.content.Intent?);
+    method public androidx.activity.result.IntentSenderRequest.Builder setFlags(int, int);
+  }
+
+}
+
+package androidx.activity.result.contract {
+
+  public abstract class ActivityResultContract<I, O> {
+    ctor public ActivityResultContract();
+    method public abstract android.content.Intent createIntent(android.content.Context, I!);
+    method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<O!>? getSynchronousResult(android.content.Context, I!);
+    method public abstract O! parseResult(int, android.content.Intent?);
+  }
+
+  public static final class ActivityResultContract.SynchronousResult<T> {
+    ctor public ActivityResultContract.SynchronousResult(T!);
+    method public T! getValue();
+  }
+
+  public final class ActivityResultContracts {
+  }
+
+  public static class ActivityResultContracts.CreateDocument extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,android.net.Uri> {
+    ctor public ActivityResultContracts.CreateDocument();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String);
+    method public final android.net.Uri? parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.GetContent extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,android.net.Uri> {
+    ctor public ActivityResultContracts.GetContent();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String);
+    method public final android.net.Uri? parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.GetMultipleContents extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,java.util.List<android.net.Uri>> {
+    ctor public ActivityResultContracts.GetMultipleContents();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.List<android.net.Uri!>!>? getSynchronousResult(android.content.Context, String);
+    method public final java.util.List<android.net.Uri!> parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.OpenDocument extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],android.net.Uri> {
+    ctor public ActivityResultContracts.OpenDocument();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, String![]);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String![]);
+    method public final android.net.Uri? parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.OpenDocumentTree extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,android.net.Uri> {
+    ctor public ActivityResultContracts.OpenDocumentTree();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri?);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, android.net.Uri?);
+    method public final android.net.Uri? parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.OpenMultipleDocuments extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],java.util.List<android.net.Uri>> {
+    ctor public ActivityResultContracts.OpenMultipleDocuments();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, String![]);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.List<android.net.Uri!>!>? getSynchronousResult(android.content.Context, String![]);
+    method public final java.util.List<android.net.Uri!> parseResult(int, android.content.Intent?);
+  }
+
+  public static final class ActivityResultContracts.PickContact extends androidx.activity.result.contract.ActivityResultContract<java.lang.Void,android.net.Uri> {
+    ctor public ActivityResultContracts.PickContact();
+    method public android.content.Intent createIntent(android.content.Context, Void?);
+    method public android.net.Uri? parseResult(int, android.content.Intent?);
+  }
+
+  public static final class ActivityResultContracts.RequestMultiplePermissions extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],java.util.Map<java.lang.String,java.lang.Boolean>> {
+    ctor public ActivityResultContracts.RequestMultiplePermissions();
+    method public android.content.Intent createIntent(android.content.Context, String![]);
+    method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.Map<java.lang.String!,java.lang.Boolean!>!>? getSynchronousResult(android.content.Context, String![]?);
+    method public java.util.Map<java.lang.String!,java.lang.Boolean!> parseResult(int, android.content.Intent?);
+    field public static final String ACTION_REQUEST_PERMISSIONS = "androidx.activity.result.contract.action.REQUEST_PERMISSIONS";
+    field public static final String EXTRA_PERMISSIONS = "androidx.activity.result.contract.extra.PERMISSIONS";
+    field public static final String EXTRA_PERMISSION_GRANT_RESULTS = "androidx.activity.result.contract.extra.PERMISSION_GRANT_RESULTS";
+  }
+
+  public static final class ActivityResultContracts.RequestPermission extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,java.lang.Boolean> {
+    ctor public ActivityResultContracts.RequestPermission();
+    method public android.content.Intent createIntent(android.content.Context, String);
+    method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.lang.Boolean!>? getSynchronousResult(android.content.Context, String?);
+    method public Boolean parseResult(int, android.content.Intent?);
+  }
+
+  public static final class ActivityResultContracts.StartActivityForResult extends androidx.activity.result.contract.ActivityResultContract<android.content.Intent,androidx.activity.result.ActivityResult> {
+    ctor public ActivityResultContracts.StartActivityForResult();
+    method public android.content.Intent createIntent(android.content.Context, android.content.Intent);
+    method public androidx.activity.result.ActivityResult parseResult(int, android.content.Intent?);
+    field public static final String EXTRA_ACTIVITY_OPTIONS_BUNDLE = "androidx.activity.result.contract.extra.ACTIVITY_OPTIONS_BUNDLE";
+  }
+
+  public static final class ActivityResultContracts.StartIntentSenderForResult extends androidx.activity.result.contract.ActivityResultContract<androidx.activity.result.IntentSenderRequest,androidx.activity.result.ActivityResult> {
+    ctor public ActivityResultContracts.StartIntentSenderForResult();
+    method public android.content.Intent createIntent(android.content.Context, androidx.activity.result.IntentSenderRequest);
+    method public androidx.activity.result.ActivityResult parseResult(int, android.content.Intent?);
+    field public static final String ACTION_INTENT_SENDER_REQUEST = "androidx.activity.result.contract.action.INTENT_SENDER_REQUEST";
+    field public static final String EXTRA_INTENT_SENDER_REQUEST = "androidx.activity.result.contract.extra.INTENT_SENDER_REQUEST";
+    field public static final String EXTRA_SEND_INTENT_EXCEPTION = "androidx.activity.result.contract.extra.SEND_INTENT_EXCEPTION";
+  }
+
+  public static class ActivityResultContracts.TakePicture extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,java.lang.Boolean> {
+    ctor public ActivityResultContracts.TakePicture();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.lang.Boolean!>? getSynchronousResult(android.content.Context, android.net.Uri);
+    method public final Boolean parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.TakePicturePreview extends androidx.activity.result.contract.ActivityResultContract<java.lang.Void,android.graphics.Bitmap> {
+    ctor public ActivityResultContracts.TakePicturePreview();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, Void?);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.graphics.Bitmap!>? getSynchronousResult(android.content.Context, Void?);
+    method public final android.graphics.Bitmap? parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.TakeVideo extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,android.graphics.Bitmap> {
+    ctor public ActivityResultContracts.TakeVideo();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.graphics.Bitmap!>? getSynchronousResult(android.content.Context, android.net.Uri);
+    method public final android.graphics.Bitmap? parseResult(int, android.content.Intent?);
+  }
+
+}
+
diff --git a/activity/activity/api/public_plus_experimental_1.2.0-beta01.txt b/activity/activity/api/public_plus_experimental_1.2.0-beta01.txt
new file mode 100644
index 0000000..823a4ed
--- /dev/null
+++ b/activity/activity/api/public_plus_experimental_1.2.0-beta01.txt
@@ -0,0 +1,258 @@
+// Signature format: 3.0
+package androidx.activity {
+
+  public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.activity.contextaware.ContextAware androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+    ctor public ComponentActivity();
+    ctor @ContentView public ComponentActivity(@LayoutRes int);
+    method public final void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public final androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+    method @Deprecated public Object? getLastCustomNonConfigurationInstance();
+    method public final androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+    method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+    method public androidx.lifecycle.ViewModelStore getViewModelStore();
+    method @Deprecated @CallSuper protected void onActivityResult(int, int, android.content.Intent?);
+    method @Deprecated @CallSuper public void onRequestPermissionsResult(int, String![], int[]);
+    method @Deprecated public Object? onRetainCustomNonConfigurationInstance();
+    method public final Object? onRetainNonConfigurationInstance();
+    method public android.content.Context? peekAvailableContext();
+    method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+    method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+    method public final void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method @Deprecated public void startActivityForResult(android.content.Intent!, int);
+    method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
+    method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int) throws android.content.IntentSender.SendIntentException;
+    method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+  }
+
+  public abstract class OnBackPressedCallback {
+    ctor public OnBackPressedCallback(boolean);
+    method @MainThread public abstract void handleOnBackPressed();
+    method @MainThread public final boolean isEnabled();
+    method @MainThread public final void remove();
+    method @MainThread public final void setEnabled(boolean);
+  }
+
+  public final class OnBackPressedDispatcher {
+    ctor public OnBackPressedDispatcher();
+    ctor public OnBackPressedDispatcher(Runnable?);
+    method @MainThread public void addCallback(androidx.activity.OnBackPressedCallback);
+    method @MainThread public void addCallback(androidx.lifecycle.LifecycleOwner, androidx.activity.OnBackPressedCallback);
+    method @MainThread public boolean hasEnabledCallbacks();
+    method @MainThread public void onBackPressed();
+  }
+
+  public interface OnBackPressedDispatcherOwner extends androidx.lifecycle.LifecycleOwner {
+    method public androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+  }
+
+}
+
+package androidx.activity.contextaware {
+
+  public interface ContextAware {
+    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public android.content.Context? peekAvailableContext();
+    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+  }
+
+  public final class ContextAwareHelper {
+    ctor public ContextAwareHelper();
+    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public void clearAvailableContext();
+    method public void dispatchOnContextAvailable(android.content.Context);
+    method public android.content.Context? peekAvailableContext();
+    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+  }
+
+  public interface OnContextAvailableListener {
+    method public void onContextAvailable(android.content.Context);
+  }
+
+}
+
+package androidx.activity.result {
+
+  public final class ActivityResult implements android.os.Parcelable {
+    ctor public ActivityResult(int, android.content.Intent?);
+    method public int describeContents();
+    method public android.content.Intent? getData();
+    method public int getResultCode();
+    method public static String resultCodeToString(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.activity.result.ActivityResult!> CREATOR;
+  }
+
+  public interface ActivityResultCallback<O> {
+    method public void onActivityResult(O!);
+  }
+
+  public interface ActivityResultCaller {
+    method public <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+    method public <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+  }
+
+  public abstract class ActivityResultLauncher<I> {
+    ctor public ActivityResultLauncher();
+    method public abstract androidx.activity.result.contract.ActivityResultContract<I!,?> getContract();
+    method public void launch(I!);
+    method public abstract void launch(I!, androidx.core.app.ActivityOptionsCompat?);
+    method @MainThread public abstract void unregister();
+  }
+
+  public abstract class ActivityResultRegistry {
+    ctor public ActivityResultRegistry();
+    method @MainThread public final boolean dispatchResult(int, int, android.content.Intent?);
+    method @MainThread public final <O> boolean dispatchResult(int, O!);
+    method @MainThread public abstract <I, O> void onLaunch(int, androidx.activity.result.contract.ActivityResultContract<I!,O!>, I!, androidx.core.app.ActivityOptionsCompat?);
+    method public final void onRestoreInstanceState(android.os.Bundle?);
+    method public final void onSaveInstanceState(android.os.Bundle);
+    method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> register(String, androidx.lifecycle.LifecycleOwner, androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+    method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> register(String, androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+  }
+
+  public interface ActivityResultRegistryOwner {
+    method public androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
+  }
+
+  public final class IntentSenderRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.Intent? getFillInIntent();
+    method public int getFlagsMask();
+    method public int getFlagsValues();
+    method public android.content.IntentSender getIntentSender();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.activity.result.IntentSenderRequest!> CREATOR;
+  }
+
+  public static final class IntentSenderRequest.Builder {
+    ctor public IntentSenderRequest.Builder(android.content.IntentSender);
+    ctor public IntentSenderRequest.Builder(android.app.PendingIntent);
+    method public androidx.activity.result.IntentSenderRequest build();
+    method public androidx.activity.result.IntentSenderRequest.Builder setFillInIntent(android.content.Intent?);
+    method public androidx.activity.result.IntentSenderRequest.Builder setFlags(int, int);
+  }
+
+}
+
+package androidx.activity.result.contract {
+
+  public abstract class ActivityResultContract<I, O> {
+    ctor public ActivityResultContract();
+    method public abstract android.content.Intent createIntent(android.content.Context, I!);
+    method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<O!>? getSynchronousResult(android.content.Context, I!);
+    method public abstract O! parseResult(int, android.content.Intent?);
+  }
+
+  public static final class ActivityResultContract.SynchronousResult<T> {
+    ctor public ActivityResultContract.SynchronousResult(T!);
+    method public T! getValue();
+  }
+
+  public final class ActivityResultContracts {
+  }
+
+  public static class ActivityResultContracts.CreateDocument extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,android.net.Uri> {
+    ctor public ActivityResultContracts.CreateDocument();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String);
+    method public final android.net.Uri? parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.GetContent extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,android.net.Uri> {
+    ctor public ActivityResultContracts.GetContent();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String);
+    method public final android.net.Uri? parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.GetMultipleContents extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,java.util.List<android.net.Uri>> {
+    ctor public ActivityResultContracts.GetMultipleContents();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.List<android.net.Uri!>!>? getSynchronousResult(android.content.Context, String);
+    method public final java.util.List<android.net.Uri!> parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.OpenDocument extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],android.net.Uri> {
+    ctor public ActivityResultContracts.OpenDocument();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, String![]);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String![]);
+    method public final android.net.Uri? parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.OpenDocumentTree extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,android.net.Uri> {
+    ctor public ActivityResultContracts.OpenDocumentTree();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri?);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, android.net.Uri?);
+    method public final android.net.Uri? parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.OpenMultipleDocuments extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],java.util.List<android.net.Uri>> {
+    ctor public ActivityResultContracts.OpenMultipleDocuments();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, String![]);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.List<android.net.Uri!>!>? getSynchronousResult(android.content.Context, String![]);
+    method public final java.util.List<android.net.Uri!> parseResult(int, android.content.Intent?);
+  }
+
+  public static final class ActivityResultContracts.PickContact extends androidx.activity.result.contract.ActivityResultContract<java.lang.Void,android.net.Uri> {
+    ctor public ActivityResultContracts.PickContact();
+    method public android.content.Intent createIntent(android.content.Context, Void?);
+    method public android.net.Uri? parseResult(int, android.content.Intent?);
+  }
+
+  public static final class ActivityResultContracts.RequestMultiplePermissions extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],java.util.Map<java.lang.String,java.lang.Boolean>> {
+    ctor public ActivityResultContracts.RequestMultiplePermissions();
+    method public android.content.Intent createIntent(android.content.Context, String![]);
+    method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.Map<java.lang.String!,java.lang.Boolean!>!>? getSynchronousResult(android.content.Context, String![]?);
+    method public java.util.Map<java.lang.String!,java.lang.Boolean!> parseResult(int, android.content.Intent?);
+    field public static final String ACTION_REQUEST_PERMISSIONS = "androidx.activity.result.contract.action.REQUEST_PERMISSIONS";
+    field public static final String EXTRA_PERMISSIONS = "androidx.activity.result.contract.extra.PERMISSIONS";
+    field public static final String EXTRA_PERMISSION_GRANT_RESULTS = "androidx.activity.result.contract.extra.PERMISSION_GRANT_RESULTS";
+  }
+
+  public static final class ActivityResultContracts.RequestPermission extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,java.lang.Boolean> {
+    ctor public ActivityResultContracts.RequestPermission();
+    method public android.content.Intent createIntent(android.content.Context, String);
+    method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.lang.Boolean!>? getSynchronousResult(android.content.Context, String?);
+    method public Boolean parseResult(int, android.content.Intent?);
+  }
+
+  public static final class ActivityResultContracts.StartActivityForResult extends androidx.activity.result.contract.ActivityResultContract<android.content.Intent,androidx.activity.result.ActivityResult> {
+    ctor public ActivityResultContracts.StartActivityForResult();
+    method public android.content.Intent createIntent(android.content.Context, android.content.Intent);
+    method public androidx.activity.result.ActivityResult parseResult(int, android.content.Intent?);
+    field public static final String EXTRA_ACTIVITY_OPTIONS_BUNDLE = "androidx.activity.result.contract.extra.ACTIVITY_OPTIONS_BUNDLE";
+  }
+
+  public static final class ActivityResultContracts.StartIntentSenderForResult extends androidx.activity.result.contract.ActivityResultContract<androidx.activity.result.IntentSenderRequest,androidx.activity.result.ActivityResult> {
+    ctor public ActivityResultContracts.StartIntentSenderForResult();
+    method public android.content.Intent createIntent(android.content.Context, androidx.activity.result.IntentSenderRequest);
+    method public androidx.activity.result.ActivityResult parseResult(int, android.content.Intent?);
+    field public static final String ACTION_INTENT_SENDER_REQUEST = "androidx.activity.result.contract.action.INTENT_SENDER_REQUEST";
+    field public static final String EXTRA_INTENT_SENDER_REQUEST = "androidx.activity.result.contract.extra.INTENT_SENDER_REQUEST";
+    field public static final String EXTRA_SEND_INTENT_EXCEPTION = "androidx.activity.result.contract.extra.SEND_INTENT_EXCEPTION";
+  }
+
+  public static class ActivityResultContracts.TakePicture extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,java.lang.Boolean> {
+    ctor public ActivityResultContracts.TakePicture();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.lang.Boolean!>? getSynchronousResult(android.content.Context, android.net.Uri);
+    method public final Boolean parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.TakePicturePreview extends androidx.activity.result.contract.ActivityResultContract<java.lang.Void,android.graphics.Bitmap> {
+    ctor public ActivityResultContracts.TakePicturePreview();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, Void?);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.graphics.Bitmap!>? getSynchronousResult(android.content.Context, Void?);
+    method public final android.graphics.Bitmap? parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.TakeVideo extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,android.graphics.Bitmap> {
+    ctor public ActivityResultContracts.TakeVideo();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.graphics.Bitmap!>? getSynchronousResult(android.content.Context, android.net.Uri);
+    method public final android.graphics.Bitmap? parseResult(int, android.content.Intent?);
+  }
+
+}
+
diff --git a/activity/activity/api/res-1.2.0-beta01.txt b/activity/activity/api/res-1.2.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/activity/activity/api/res-1.2.0-beta01.txt
diff --git a/activity/activity/api/restricted_1.2.0-beta01.txt b/activity/activity/api/restricted_1.2.0-beta01.txt
new file mode 100644
index 0000000..823a4ed
--- /dev/null
+++ b/activity/activity/api/restricted_1.2.0-beta01.txt
@@ -0,0 +1,258 @@
+// Signature format: 3.0
+package androidx.activity {
+
+  public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.activity.result.ActivityResultCaller androidx.activity.result.ActivityResultRegistryOwner androidx.activity.contextaware.ContextAware androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+    ctor public ComponentActivity();
+    ctor @ContentView public ComponentActivity(@LayoutRes int);
+    method public final void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public final androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+    method @Deprecated public Object? getLastCustomNonConfigurationInstance();
+    method public final androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+    method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+    method public androidx.lifecycle.ViewModelStore getViewModelStore();
+    method @Deprecated @CallSuper protected void onActivityResult(int, int, android.content.Intent?);
+    method @Deprecated @CallSuper public void onRequestPermissionsResult(int, String![], int[]);
+    method @Deprecated public Object? onRetainCustomNonConfigurationInstance();
+    method public final Object? onRetainNonConfigurationInstance();
+    method public android.content.Context? peekAvailableContext();
+    method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+    method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+    method public final void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method @Deprecated public void startActivityForResult(android.content.Intent!, int);
+    method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
+    method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int) throws android.content.IntentSender.SendIntentException;
+    method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+  }
+
+  public abstract class OnBackPressedCallback {
+    ctor public OnBackPressedCallback(boolean);
+    method @MainThread public abstract void handleOnBackPressed();
+    method @MainThread public final boolean isEnabled();
+    method @MainThread public final void remove();
+    method @MainThread public final void setEnabled(boolean);
+  }
+
+  public final class OnBackPressedDispatcher {
+    ctor public OnBackPressedDispatcher();
+    ctor public OnBackPressedDispatcher(Runnable?);
+    method @MainThread public void addCallback(androidx.activity.OnBackPressedCallback);
+    method @MainThread public void addCallback(androidx.lifecycle.LifecycleOwner, androidx.activity.OnBackPressedCallback);
+    method @MainThread public boolean hasEnabledCallbacks();
+    method @MainThread public void onBackPressed();
+  }
+
+  public interface OnBackPressedDispatcherOwner extends androidx.lifecycle.LifecycleOwner {
+    method public androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
+  }
+
+}
+
+package androidx.activity.contextaware {
+
+  public interface ContextAware {
+    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public android.content.Context? peekAvailableContext();
+    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+  }
+
+  public final class ContextAwareHelper {
+    ctor public ContextAwareHelper();
+    method public void addOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+    method public void clearAvailableContext();
+    method public void dispatchOnContextAvailable(android.content.Context);
+    method public android.content.Context? peekAvailableContext();
+    method public void removeOnContextAvailableListener(androidx.activity.contextaware.OnContextAvailableListener);
+  }
+
+  public interface OnContextAvailableListener {
+    method public void onContextAvailable(android.content.Context);
+  }
+
+}
+
+package androidx.activity.result {
+
+  public final class ActivityResult implements android.os.Parcelable {
+    ctor public ActivityResult(int, android.content.Intent?);
+    method public int describeContents();
+    method public android.content.Intent? getData();
+    method public int getResultCode();
+    method public static String resultCodeToString(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.activity.result.ActivityResult!> CREATOR;
+  }
+
+  public interface ActivityResultCallback<O> {
+    method public void onActivityResult(O!);
+  }
+
+  public interface ActivityResultCaller {
+    method public <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+    method public <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+  }
+
+  public abstract class ActivityResultLauncher<I> {
+    ctor public ActivityResultLauncher();
+    method public abstract androidx.activity.result.contract.ActivityResultContract<I!,?> getContract();
+    method public void launch(I!);
+    method public abstract void launch(I!, androidx.core.app.ActivityOptionsCompat?);
+    method @MainThread public abstract void unregister();
+  }
+
+  public abstract class ActivityResultRegistry {
+    ctor public ActivityResultRegistry();
+    method @MainThread public final boolean dispatchResult(int, int, android.content.Intent?);
+    method @MainThread public final <O> boolean dispatchResult(int, O!);
+    method @MainThread public abstract <I, O> void onLaunch(int, androidx.activity.result.contract.ActivityResultContract<I!,O!>, I!, androidx.core.app.ActivityOptionsCompat?);
+    method public final void onRestoreInstanceState(android.os.Bundle?);
+    method public final void onSaveInstanceState(android.os.Bundle);
+    method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> register(String, androidx.lifecycle.LifecycleOwner, androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+    method public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> register(String, androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+  }
+
+  public interface ActivityResultRegistryOwner {
+    method public androidx.activity.result.ActivityResultRegistry getActivityResultRegistry();
+  }
+
+  public final class IntentSenderRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.Intent? getFillInIntent();
+    method public int getFlagsMask();
+    method public int getFlagsValues();
+    method public android.content.IntentSender getIntentSender();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.activity.result.IntentSenderRequest!> CREATOR;
+  }
+
+  public static final class IntentSenderRequest.Builder {
+    ctor public IntentSenderRequest.Builder(android.content.IntentSender);
+    ctor public IntentSenderRequest.Builder(android.app.PendingIntent);
+    method public androidx.activity.result.IntentSenderRequest build();
+    method public androidx.activity.result.IntentSenderRequest.Builder setFillInIntent(android.content.Intent?);
+    method public androidx.activity.result.IntentSenderRequest.Builder setFlags(int, int);
+  }
+
+}
+
+package androidx.activity.result.contract {
+
+  public abstract class ActivityResultContract<I, O> {
+    ctor public ActivityResultContract();
+    method public abstract android.content.Intent createIntent(android.content.Context, I!);
+    method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<O!>? getSynchronousResult(android.content.Context, I!);
+    method public abstract O! parseResult(int, android.content.Intent?);
+  }
+
+  public static final class ActivityResultContract.SynchronousResult<T> {
+    ctor public ActivityResultContract.SynchronousResult(T!);
+    method public T! getValue();
+  }
+
+  public final class ActivityResultContracts {
+  }
+
+  public static class ActivityResultContracts.CreateDocument extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,android.net.Uri> {
+    ctor public ActivityResultContracts.CreateDocument();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String);
+    method public final android.net.Uri? parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.GetContent extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,android.net.Uri> {
+    ctor public ActivityResultContracts.GetContent();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String);
+    method public final android.net.Uri? parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.GetMultipleContents extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,java.util.List<android.net.Uri>> {
+    ctor public ActivityResultContracts.GetMultipleContents();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, String);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.List<android.net.Uri!>!>? getSynchronousResult(android.content.Context, String);
+    method public final java.util.List<android.net.Uri!> parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.OpenDocument extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],android.net.Uri> {
+    ctor public ActivityResultContracts.OpenDocument();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, String![]);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, String![]);
+    method public final android.net.Uri? parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.OpenDocumentTree extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,android.net.Uri> {
+    ctor public ActivityResultContracts.OpenDocumentTree();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri?);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.net.Uri!>? getSynchronousResult(android.content.Context, android.net.Uri?);
+    method public final android.net.Uri? parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.OpenMultipleDocuments extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],java.util.List<android.net.Uri>> {
+    ctor public ActivityResultContracts.OpenMultipleDocuments();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, String![]);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.List<android.net.Uri!>!>? getSynchronousResult(android.content.Context, String![]);
+    method public final java.util.List<android.net.Uri!> parseResult(int, android.content.Intent?);
+  }
+
+  public static final class ActivityResultContracts.PickContact extends androidx.activity.result.contract.ActivityResultContract<java.lang.Void,android.net.Uri> {
+    ctor public ActivityResultContracts.PickContact();
+    method public android.content.Intent createIntent(android.content.Context, Void?);
+    method public android.net.Uri? parseResult(int, android.content.Intent?);
+  }
+
+  public static final class ActivityResultContracts.RequestMultiplePermissions extends androidx.activity.result.contract.ActivityResultContract<java.lang.String[],java.util.Map<java.lang.String,java.lang.Boolean>> {
+    ctor public ActivityResultContracts.RequestMultiplePermissions();
+    method public android.content.Intent createIntent(android.content.Context, String![]);
+    method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.util.Map<java.lang.String!,java.lang.Boolean!>!>? getSynchronousResult(android.content.Context, String![]?);
+    method public java.util.Map<java.lang.String!,java.lang.Boolean!> parseResult(int, android.content.Intent?);
+    field public static final String ACTION_REQUEST_PERMISSIONS = "androidx.activity.result.contract.action.REQUEST_PERMISSIONS";
+    field public static final String EXTRA_PERMISSIONS = "androidx.activity.result.contract.extra.PERMISSIONS";
+    field public static final String EXTRA_PERMISSION_GRANT_RESULTS = "androidx.activity.result.contract.extra.PERMISSION_GRANT_RESULTS";
+  }
+
+  public static final class ActivityResultContracts.RequestPermission extends androidx.activity.result.contract.ActivityResultContract<java.lang.String,java.lang.Boolean> {
+    ctor public ActivityResultContracts.RequestPermission();
+    method public android.content.Intent createIntent(android.content.Context, String);
+    method public androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.lang.Boolean!>? getSynchronousResult(android.content.Context, String?);
+    method public Boolean parseResult(int, android.content.Intent?);
+  }
+
+  public static final class ActivityResultContracts.StartActivityForResult extends androidx.activity.result.contract.ActivityResultContract<android.content.Intent,androidx.activity.result.ActivityResult> {
+    ctor public ActivityResultContracts.StartActivityForResult();
+    method public android.content.Intent createIntent(android.content.Context, android.content.Intent);
+    method public androidx.activity.result.ActivityResult parseResult(int, android.content.Intent?);
+    field public static final String EXTRA_ACTIVITY_OPTIONS_BUNDLE = "androidx.activity.result.contract.extra.ACTIVITY_OPTIONS_BUNDLE";
+  }
+
+  public static final class ActivityResultContracts.StartIntentSenderForResult extends androidx.activity.result.contract.ActivityResultContract<androidx.activity.result.IntentSenderRequest,androidx.activity.result.ActivityResult> {
+    ctor public ActivityResultContracts.StartIntentSenderForResult();
+    method public android.content.Intent createIntent(android.content.Context, androidx.activity.result.IntentSenderRequest);
+    method public androidx.activity.result.ActivityResult parseResult(int, android.content.Intent?);
+    field public static final String ACTION_INTENT_SENDER_REQUEST = "androidx.activity.result.contract.action.INTENT_SENDER_REQUEST";
+    field public static final String EXTRA_INTENT_SENDER_REQUEST = "androidx.activity.result.contract.extra.INTENT_SENDER_REQUEST";
+    field public static final String EXTRA_SEND_INTENT_EXCEPTION = "androidx.activity.result.contract.extra.SEND_INTENT_EXCEPTION";
+  }
+
+  public static class ActivityResultContracts.TakePicture extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,java.lang.Boolean> {
+    ctor public ActivityResultContracts.TakePicture();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<java.lang.Boolean!>? getSynchronousResult(android.content.Context, android.net.Uri);
+    method public final Boolean parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.TakePicturePreview extends androidx.activity.result.contract.ActivityResultContract<java.lang.Void,android.graphics.Bitmap> {
+    ctor public ActivityResultContracts.TakePicturePreview();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, Void?);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.graphics.Bitmap!>? getSynchronousResult(android.content.Context, Void?);
+    method public final android.graphics.Bitmap? parseResult(int, android.content.Intent?);
+  }
+
+  public static class ActivityResultContracts.TakeVideo extends androidx.activity.result.contract.ActivityResultContract<android.net.Uri,android.graphics.Bitmap> {
+    ctor public ActivityResultContracts.TakeVideo();
+    method @CallSuper public android.content.Intent createIntent(android.content.Context, android.net.Uri);
+    method public final androidx.activity.result.contract.ActivityResultContract.SynchronousResult<android.graphics.Bitmap!>? getSynchronousResult(android.content.Context, android.net.Uri);
+    method public final android.graphics.Bitmap? parseResult(int, android.content.Intent?);
+  }
+
+}
+
diff --git a/activity/activity/src/main/java/androidx/activity/result/ActivityResultRegistry.java b/activity/activity/src/main/java/androidx/activity/result/ActivityResultRegistry.java
index 1b08ee8..99193f8 100644
--- a/activity/activity/src/main/java/androidx/activity/result/ActivityResultRegistry.java
+++ b/activity/activity/src/main/java/androidx/activity/result/ActivityResultRegistry.java
@@ -58,8 +58,10 @@
 
     private static final String LOG_TAG = "ActivityResultRegistry";
 
+    private static final int INITIAL_REQUEST_CODE_VALUE = 0x00010000;
+
     // Use upper 16 bits for request codes
-    private final AtomicInteger mNextRc = new AtomicInteger(0x00010000);
+    private final AtomicInteger mNextRc = new AtomicInteger(INITIAL_REQUEST_CODE_VALUE);
     private final Map<Integer, String> mRcToKey = new HashMap<>();
     private final Map<String, Integer> mKeyToRc = new HashMap<>();
     private final Map<String, LifecycleContainer> mKeyToLifecycleContainers = new HashMap<>();
@@ -278,7 +280,7 @@
         for (int i = 0; i < numKeys; i++) {
             bindRcKey(rcs.get(i), keys.get(i));
         }
-        mNextRc.set(numKeys);
+        mNextRc.set(INITIAL_REQUEST_CODE_VALUE + numKeys);
         mPendingResults.putAll(
                 savedInstanceState.getBundle(KEY_COMPONENT_ACTIVITY_PENDING_RESULTS));
     }
diff --git a/appcompat/appcompat-lint/build.gradle b/appcompat/appcompat-lint/build.gradle
index da60f47..51a3871 100644
--- a/appcompat/appcompat-lint/build.gradle
+++ b/appcompat/appcompat-lint/build.gradle
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+
+import androidx.build.CompilationTarget
 import androidx.build.LibraryGroups
 import androidx.build.LibraryVersions
 import androidx.build.Publish
@@ -38,6 +40,7 @@
     name = "AppCompat Lint Checks"
     toolingProject = true
     publish = Publish.NONE
+    compilationTarget = CompilationTarget.HOST
     mavenVersion = LibraryVersions.APPCOMPAT
     mavenGroup = LibraryGroups.APPCOMPAT
     inceptionYear = "2019"
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-hdpi/abc_ic_menu_copy_mtrl_am_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-hdpi/abc_ic_menu_copy_mtrl_am_alpha.png
deleted file mode 100644
index a262b0c..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-hdpi/abc_ic_menu_copy_mtrl_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-hdpi/abc_ic_menu_cut_mtrl_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-hdpi/abc_ic_menu_cut_mtrl_alpha.png
deleted file mode 100644
index d8eaf07..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-hdpi/abc_ic_menu_cut_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-mdpi/abc_ic_menu_copy_mtrl_am_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-mdpi/abc_ic_menu_copy_mtrl_am_alpha.png
deleted file mode 100644
index 254f806..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-mdpi/abc_ic_menu_copy_mtrl_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-mdpi/abc_ic_menu_cut_mtrl_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-mdpi/abc_ic_menu_cut_mtrl_alpha.png
deleted file mode 100644
index f9cba8f..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-mdpi/abc_ic_menu_cut_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-xhdpi/abc_ic_menu_copy_mtrl_am_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-xhdpi/abc_ic_menu_copy_mtrl_am_alpha.png
deleted file mode 100644
index 198a842..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-xhdpi/abc_ic_menu_copy_mtrl_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-xhdpi/abc_ic_menu_cut_mtrl_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-xhdpi/abc_ic_menu_cut_mtrl_alpha.png
deleted file mode 100644
index 87bf8d3..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-xhdpi/abc_ic_menu_cut_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxhdpi/abc_ic_menu_copy_mtrl_am_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-xxhdpi/abc_ic_menu_copy_mtrl_am_alpha.png
deleted file mode 100644
index 284c3c2..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxhdpi/abc_ic_menu_copy_mtrl_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxhdpi/abc_ic_menu_cut_mtrl_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-xxhdpi/abc_ic_menu_cut_mtrl_alpha.png
deleted file mode 100644
index 3cdb6cf..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxhdpi/abc_ic_menu_cut_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxxhdpi/abc_ic_menu_copy_mtrl_am_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-xxxhdpi/abc_ic_menu_copy_mtrl_am_alpha.png
deleted file mode 100644
index 7d4c690..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxxhdpi/abc_ic_menu_copy_mtrl_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxxhdpi/abc_ic_menu_cut_mtrl_alpha.png b/appcompat/appcompat/src/main/res/drawable-ldrtl-xxxhdpi/abc_ic_menu_cut_mtrl_alpha.png
deleted file mode 100644
index 90fe333..0000000
--- a/appcompat/appcompat/src/main/res/drawable-ldrtl-xxxhdpi/abc_ic_menu_cut_mtrl_alpha.png
+++ /dev/null
Binary files differ
diff --git a/appcompat/appcompat/src/main/res/values-as/strings.xml b/appcompat/appcompat/src/main/res/values-as/strings.xml
index 1a3b4a1..4314fe9 100644
--- a/appcompat/appcompat/src/main/res/values-as/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-as/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_action_bar_up_description" msgid="8388173803310557296">"ওপৰলৈ যাওক"</string>
     <string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"অধিক বিকল্প"</string>
     <string name="abc_toolbar_collapse_description" msgid="1656852541809559762">"সংকোচন কৰক"</string>
-    <string name="abc_searchview_description_search" msgid="3417662926640357176">"সন্ধান"</string>
+    <string name="abc_searchview_description_search" msgid="3417662926640357176">"Search"</string>
     <string name="abc_search_hint" msgid="7208076849092622260">"সন্ধান কৰক…"</string>
     <string name="abc_searchview_description_query" msgid="693312494995508443">"সন্ধান কৰা প্ৰশ্ন"</string>
     <string name="abc_searchview_description_clear" msgid="3741173234950517107">"সন্ধান কৰা প্ৰশ্ন মচক"</string>
@@ -33,7 +33,7 @@
     <string name="abc_shareactionprovider_share_with" msgid="8875138169939072951">"ইয়াৰ জৰিয়তে শ্বেয়াৰ কৰক"</string>
     <string name="abc_capital_on" msgid="884982626291842264">"অন"</string>
     <string name="abc_capital_off" msgid="4215997306490295099">"অফ"</string>
-    <string name="search_menu_title" msgid="6264217191555673260">"সন্ধান"</string>
+    <string name="search_menu_title" msgid="6264217191555673260">"Search"</string>
     <string name="abc_prepend_shortcut_label" msgid="5520303668377388990">"Menu+"</string>
     <string name="abc_menu_meta_shortcut_label" msgid="4192209724446364286">"Meta+"</string>
     <string name="abc_menu_ctrl_shortcut_label" msgid="2223301931652355242">"Ctrl+"</string>
diff --git a/appcompat/appcompat/src/main/res/values-cs/strings.xml b/appcompat/appcompat/src/main/res/values-cs/strings.xml
index d38f873..907c0fe 100644
--- a/appcompat/appcompat/src/main/res/values-cs/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-cs/strings.xml
@@ -19,7 +19,7 @@
     <string name="abc_action_mode_done" msgid="4692188335987374352">"Hotovo"</string>
     <string name="abc_action_bar_home_description" msgid="5976598919945601918">"Přejít na plochu"</string>
     <string name="abc_action_bar_up_description" msgid="8388173803310557296">"Přejít nahoru"</string>
-    <string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"Více možností"</string>
+    <string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"Další možnosti"</string>
     <string name="abc_toolbar_collapse_description" msgid="1656852541809559762">"Sbalit"</string>
     <string name="abc_searchview_description_search" msgid="3417662926640357176">"Hledat"</string>
     <string name="abc_search_hint" msgid="7208076849092622260">"Vyhledat…"</string>
diff --git a/appcompat/appcompat/src/main/res/values-kn/strings.xml b/appcompat/appcompat/src/main/res/values-kn/strings.xml
index 40454c7..9a11465 100644
--- a/appcompat/appcompat/src/main/res/values-kn/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-kn/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_action_bar_up_description" msgid="8388173803310557296">"ಮೇಲಕ್ಕೆ ನ್ಯಾವಿಗೇಟ್ ಮಾಡಿ"</string>
     <string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"ಇನ್ನಷ್ಟು ಆಯ್ಕೆಗಳು"</string>
     <string name="abc_toolbar_collapse_description" msgid="1656852541809559762">"ಕುಗ್ಗಿಸಿ"</string>
-    <string name="abc_searchview_description_search" msgid="3417662926640357176">"ಹುಡುಕಿ"</string>
+    <string name="abc_searchview_description_search" msgid="3417662926640357176">"Search"</string>
     <string name="abc_search_hint" msgid="7208076849092622260">"ಹುಡುಕಿ…"</string>
     <string name="abc_searchview_description_query" msgid="693312494995508443">"ಪ್ರಶ್ನೆಯನ್ನು ಹುಡುಕಿ"</string>
     <string name="abc_searchview_description_clear" msgid="3741173234950517107">"ಪ್ರಶ್ನೆಯನ್ನು ತೆರವುಗೊಳಿಸಿ"</string>
@@ -33,7 +33,7 @@
     <string name="abc_shareactionprovider_share_with" msgid="8875138169939072951">"ಇವರೊಂದಿಗೆ ಹಂಚಿಕೊಳ್ಳಿ"</string>
     <string name="abc_capital_on" msgid="884982626291842264">"ಆನ್"</string>
     <string name="abc_capital_off" msgid="4215997306490295099">"ಆಫ್"</string>
-    <string name="search_menu_title" msgid="6264217191555673260">"ಹುಡುಕಿ"</string>
+    <string name="search_menu_title" msgid="6264217191555673260">"Search"</string>
     <string name="abc_prepend_shortcut_label" msgid="5520303668377388990">"Menu+"</string>
     <string name="abc_menu_meta_shortcut_label" msgid="4192209724446364286">"Meta+"</string>
     <string name="abc_menu_ctrl_shortcut_label" msgid="2223301931652355242">"Ctrl+"</string>
diff --git a/appcompat/appcompat/src/main/res/values-ml/strings.xml b/appcompat/appcompat/src/main/res/values-ml/strings.xml
index 2acae41..242ec2c 100644
--- a/appcompat/appcompat/src/main/res/values-ml/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-ml/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_action_bar_up_description" msgid="8388173803310557296">"മുകളിലേക്ക് പോവുക"</string>
     <string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"കൂടുതൽ ഓപ്ഷനുകൾ"</string>
     <string name="abc_toolbar_collapse_description" msgid="1656852541809559762">"ചുരുക്കുക"</string>
-    <string name="abc_searchview_description_search" msgid="3417662926640357176">"തിരയുക"</string>
+    <string name="abc_searchview_description_search" msgid="3417662926640357176">"Search"</string>
     <string name="abc_search_hint" msgid="7208076849092622260">"തിരയുക…"</string>
     <string name="abc_searchview_description_query" msgid="693312494995508443">"ചോദ്യം തിരയുക"</string>
     <string name="abc_searchview_description_clear" msgid="3741173234950517107">"ചോദ്യം മായ്‌ക്കുക"</string>
@@ -33,7 +33,7 @@
     <string name="abc_shareactionprovider_share_with" msgid="8875138169939072951">"ഇനിപ്പറയുന്നതുമായി പങ്കിടുക"</string>
     <string name="abc_capital_on" msgid="884982626291842264">"ഓൺ"</string>
     <string name="abc_capital_off" msgid="4215997306490295099">"ഓഫ്"</string>
-    <string name="search_menu_title" msgid="6264217191555673260">"തിരയുക"</string>
+    <string name="search_menu_title" msgid="6264217191555673260">"Search"</string>
     <string name="abc_prepend_shortcut_label" msgid="5520303668377388990">"മെനു+"</string>
     <string name="abc_menu_meta_shortcut_label" msgid="4192209724446364286">"മെറ്റ+"</string>
     <string name="abc_menu_ctrl_shortcut_label" msgid="2223301931652355242">"Ctrl+"</string>
diff --git a/appcompat/appcompat/src/main/res/values-mr/strings.xml b/appcompat/appcompat/src/main/res/values-mr/strings.xml
index 4bc6cb1..f4adb38 100644
--- a/appcompat/appcompat/src/main/res/values-mr/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-mr/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_action_bar_up_description" msgid="8388173803310557296">"वर नेव्‍हिगेट करा"</string>
     <string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"आणखी पर्याय"</string>
     <string name="abc_toolbar_collapse_description" msgid="1656852541809559762">"कोलॅप्स करा"</string>
-    <string name="abc_searchview_description_search" msgid="3417662926640357176">"शोध"</string>
+    <string name="abc_searchview_description_search" msgid="3417662926640357176">"Search"</string>
     <string name="abc_search_hint" msgid="7208076849092622260">"शोधा…"</string>
     <string name="abc_searchview_description_query" msgid="693312494995508443">"शोध क्वेरी"</string>
     <string name="abc_searchview_description_clear" msgid="3741173234950517107">"क्‍वेरी साफ करा"</string>
@@ -33,7 +33,7 @@
     <string name="abc_shareactionprovider_share_with" msgid="8875138169939072951">"यांच्यासोबत शेअर करा"</string>
     <string name="abc_capital_on" msgid="884982626291842264">"सुरू"</string>
     <string name="abc_capital_off" msgid="4215997306490295099">"बंद"</string>
-    <string name="search_menu_title" msgid="6264217191555673260">"शोध"</string>
+    <string name="search_menu_title" msgid="6264217191555673260">"Search"</string>
     <string name="abc_prepend_shortcut_label" msgid="5520303668377388990">"मेनू+"</string>
     <string name="abc_menu_meta_shortcut_label" msgid="4192209724446364286">"Meta+"</string>
     <string name="abc_menu_ctrl_shortcut_label" msgid="2223301931652355242">"Ctrl+"</string>
diff --git a/appcompat/appcompat/src/main/res/values-nl/strings.xml b/appcompat/appcompat/src/main/res/values-nl/strings.xml
index 0e0db0a..2a6959d 100644
--- a/appcompat/appcompat/src/main/res/values-nl/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-nl/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="abc_action_mode_done" msgid="4692188335987374352">"Gereed"</string>
+    <string name="abc_action_mode_done" msgid="4692188335987374352">"Klaar"</string>
     <string name="abc_action_bar_home_description" msgid="5976598919945601918">"Navigeren naar startpositie"</string>
     <string name="abc_action_bar_up_description" msgid="8388173803310557296">"Omhoog navigeren"</string>
     <string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"Meer opties"</string>
diff --git a/appcompat/appcompat/src/main/res/values-or/strings.xml b/appcompat/appcompat/src/main/res/values-or/strings.xml
index c1af6db..6f29662 100644
--- a/appcompat/appcompat/src/main/res/values-or/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-or/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_action_bar_up_description" msgid="8388173803310557296">"ଉପରକୁ ନେଭିଗେଟ୍ କରନ୍ତୁ"</string>
     <string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"ଅଧିକ ବିକଳ୍ପ"</string>
     <string name="abc_toolbar_collapse_description" msgid="1656852541809559762">"ସଂକୁଚିତ କରନ୍ତୁ"</string>
-    <string name="abc_searchview_description_search" msgid="3417662926640357176">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
+    <string name="abc_searchview_description_search" msgid="3417662926640357176">"Search"</string>
     <string name="abc_search_hint" msgid="7208076849092622260">"ସର୍ଚ୍ଚ କରନ୍ତୁ…"</string>
     <string name="abc_searchview_description_query" msgid="693312494995508443">"ସର୍ଚ୍ଚ କ୍ୱେରୀ"</string>
     <string name="abc_searchview_description_clear" msgid="3741173234950517107">"କ୍ୱେରୀ ଖାଲି କରନ୍ତୁ"</string>
@@ -33,7 +33,7 @@
     <string name="abc_shareactionprovider_share_with" msgid="8875138169939072951">"ଏହାଙ୍କ ସହ ସେୟାର୍‌ କରନ୍ତୁ"</string>
     <string name="abc_capital_on" msgid="884982626291842264">"ଅନ୍"</string>
     <string name="abc_capital_off" msgid="4215997306490295099">"ବନ୍ଦ"</string>
-    <string name="search_menu_title" msgid="6264217191555673260">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
+    <string name="search_menu_title" msgid="6264217191555673260">"Search"</string>
     <string name="abc_prepend_shortcut_label" msgid="5520303668377388990">"ମେନୁ"</string>
     <string name="abc_menu_meta_shortcut_label" msgid="4192209724446364286">"Meta+"</string>
     <string name="abc_menu_ctrl_shortcut_label" msgid="2223301931652355242">"Ctrl+"</string>
diff --git a/appcompat/appcompat/src/main/res/values-te/strings.xml b/appcompat/appcompat/src/main/res/values-te/strings.xml
index 80f7d0d..9a284b7 100644
--- a/appcompat/appcompat/src/main/res/values-te/strings.xml
+++ b/appcompat/appcompat/src/main/res/values-te/strings.xml
@@ -21,7 +21,7 @@
     <string name="abc_action_bar_up_description" msgid="8388173803310557296">"పైకి నావిగేట్ చేస్తుంది"</string>
     <string name="abc_action_menu_overflow_description" msgid="3937310113216875497">"మరిన్ని ఎంపికలు"</string>
     <string name="abc_toolbar_collapse_description" msgid="1656852541809559762">"కుదిస్తుంది"</string>
-    <string name="abc_searchview_description_search" msgid="3417662926640357176">"శోధన"</string>
+    <string name="abc_searchview_description_search" msgid="3417662926640357176">"సెర్చ్"</string>
     <string name="abc_search_hint" msgid="7208076849092622260">"వెతకండి…"</string>
     <string name="abc_searchview_description_query" msgid="693312494995508443">"శోధన ప్రశ్న"</string>
     <string name="abc_searchview_description_clear" msgid="3741173234950517107">"ప్రశ్నను తీసివేస్తుంది"</string>
@@ -33,7 +33,7 @@
     <string name="abc_shareactionprovider_share_with" msgid="8875138169939072951">"వీరితో షేర్ చేస్తుంది"</string>
     <string name="abc_capital_on" msgid="884982626291842264">"ఆన్"</string>
     <string name="abc_capital_off" msgid="4215997306490295099">"ఆఫ్"</string>
-    <string name="search_menu_title" msgid="6264217191555673260">"శోధన"</string>
+    <string name="search_menu_title" msgid="6264217191555673260">"సెర్చ్"</string>
     <string name="abc_prepend_shortcut_label" msgid="5520303668377388990">"Menu+"</string>
     <string name="abc_menu_meta_shortcut_label" msgid="4192209724446364286">"Meta+"</string>
     <string name="abc_menu_ctrl_shortcut_label" msgid="2223301931652355242">"Ctrl+"</string>
diff --git a/appsearch/appsearch/api/current.txt b/appsearch/appsearch/api/current.txt
index 1c5f6a9..a663d92 100644
--- a/appsearch/appsearch/api/current.txt
+++ b/appsearch/appsearch/api/current.txt
@@ -177,6 +177,54 @@
     method public BuilderType setTtlMillis(long);
   }
 
+  public final class MatchInfo {
+    method public CharSequence getExactMatch();
+    method public androidx.appsearch.app.MatchInfo.MatchRange getExactMatchPosition();
+    method public String getFullText();
+    method public String getPropertyPath();
+    method public CharSequence getSnippet();
+    method public androidx.appsearch.app.MatchInfo.MatchRange getSnippetPosition();
+  }
+
+  public static class MatchInfo.MatchRange {
+    method public int getEnd();
+    method public int getStart();
+  }
+
+  public final class SearchResults implements java.io.Closeable {
+    method public void close();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchResult<java.util.List<androidx.appsearch.app.SearchResults.Result!>!>!> getNextPage();
+  }
+
+  public static final class SearchResults.Result {
+    method public androidx.appsearch.app.GenericDocument getDocument();
+    method public java.util.List<androidx.appsearch.app.MatchInfo!>? getMatches();
+  }
+
+  public final class SearchSpec {
+    field public static final int ORDER_ASCENDING = 1; // 0x1
+    field public static final int ORDER_DESCENDING = 0; // 0x0
+    field public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2; // 0x2
+    field public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1; // 0x1
+    field public static final int RANKING_STRATEGY_NONE = 0; // 0x0
+    field public static final int TERM_MATCH_EXACT_ONLY = 1; // 0x1
+    field public static final int TERM_MATCH_PREFIX = 2; // 0x2
+  }
+
+  public static final class SearchSpec.Builder {
+    ctor public SearchSpec.Builder();
+    method public androidx.appsearch.app.SearchSpec build();
+    method public androidx.appsearch.app.SearchSpec.Builder setMaxSnippetSize(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setNamespaces(java.lang.String!...);
+    method public androidx.appsearch.app.SearchSpec.Builder setNumPerPage(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setOrder(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setRankingStrategy(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setSchemaTypes(java.lang.String!...);
+    method public androidx.appsearch.app.SearchSpec.Builder setSnippetCount(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setSnippetCountPerProperty(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setTermMatch(int);
+  }
+
 }
 
 package androidx.appsearch.exceptions {
diff --git a/appsearch/appsearch/api/public_plus_experimental_current.txt b/appsearch/appsearch/api/public_plus_experimental_current.txt
index 1c5f6a9..a663d92 100644
--- a/appsearch/appsearch/api/public_plus_experimental_current.txt
+++ b/appsearch/appsearch/api/public_plus_experimental_current.txt
@@ -177,6 +177,54 @@
     method public BuilderType setTtlMillis(long);
   }
 
+  public final class MatchInfo {
+    method public CharSequence getExactMatch();
+    method public androidx.appsearch.app.MatchInfo.MatchRange getExactMatchPosition();
+    method public String getFullText();
+    method public String getPropertyPath();
+    method public CharSequence getSnippet();
+    method public androidx.appsearch.app.MatchInfo.MatchRange getSnippetPosition();
+  }
+
+  public static class MatchInfo.MatchRange {
+    method public int getEnd();
+    method public int getStart();
+  }
+
+  public final class SearchResults implements java.io.Closeable {
+    method public void close();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchResult<java.util.List<androidx.appsearch.app.SearchResults.Result!>!>!> getNextPage();
+  }
+
+  public static final class SearchResults.Result {
+    method public androidx.appsearch.app.GenericDocument getDocument();
+    method public java.util.List<androidx.appsearch.app.MatchInfo!>? getMatches();
+  }
+
+  public final class SearchSpec {
+    field public static final int ORDER_ASCENDING = 1; // 0x1
+    field public static final int ORDER_DESCENDING = 0; // 0x0
+    field public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2; // 0x2
+    field public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1; // 0x1
+    field public static final int RANKING_STRATEGY_NONE = 0; // 0x0
+    field public static final int TERM_MATCH_EXACT_ONLY = 1; // 0x1
+    field public static final int TERM_MATCH_PREFIX = 2; // 0x2
+  }
+
+  public static final class SearchSpec.Builder {
+    ctor public SearchSpec.Builder();
+    method public androidx.appsearch.app.SearchSpec build();
+    method public androidx.appsearch.app.SearchSpec.Builder setMaxSnippetSize(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setNamespaces(java.lang.String!...);
+    method public androidx.appsearch.app.SearchSpec.Builder setNumPerPage(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setOrder(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setRankingStrategy(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setSchemaTypes(java.lang.String!...);
+    method public androidx.appsearch.app.SearchSpec.Builder setSnippetCount(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setSnippetCountPerProperty(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setTermMatch(int);
+  }
+
 }
 
 package androidx.appsearch.exceptions {
diff --git a/appsearch/appsearch/api/restricted_current.txt b/appsearch/appsearch/api/restricted_current.txt
index 1c5f6a9..a663d92 100644
--- a/appsearch/appsearch/api/restricted_current.txt
+++ b/appsearch/appsearch/api/restricted_current.txt
@@ -177,6 +177,54 @@
     method public BuilderType setTtlMillis(long);
   }
 
+  public final class MatchInfo {
+    method public CharSequence getExactMatch();
+    method public androidx.appsearch.app.MatchInfo.MatchRange getExactMatchPosition();
+    method public String getFullText();
+    method public String getPropertyPath();
+    method public CharSequence getSnippet();
+    method public androidx.appsearch.app.MatchInfo.MatchRange getSnippetPosition();
+  }
+
+  public static class MatchInfo.MatchRange {
+    method public int getEnd();
+    method public int getStart();
+  }
+
+  public final class SearchResults implements java.io.Closeable {
+    method public void close();
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.appsearch.app.AppSearchResult<java.util.List<androidx.appsearch.app.SearchResults.Result!>!>!> getNextPage();
+  }
+
+  public static final class SearchResults.Result {
+    method public androidx.appsearch.app.GenericDocument getDocument();
+    method public java.util.List<androidx.appsearch.app.MatchInfo!>? getMatches();
+  }
+
+  public final class SearchSpec {
+    field public static final int ORDER_ASCENDING = 1; // 0x1
+    field public static final int ORDER_DESCENDING = 0; // 0x0
+    field public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2; // 0x2
+    field public static final int RANKING_STRATEGY_DOCUMENT_SCORE = 1; // 0x1
+    field public static final int RANKING_STRATEGY_NONE = 0; // 0x0
+    field public static final int TERM_MATCH_EXACT_ONLY = 1; // 0x1
+    field public static final int TERM_MATCH_PREFIX = 2; // 0x2
+  }
+
+  public static final class SearchSpec.Builder {
+    ctor public SearchSpec.Builder();
+    method public androidx.appsearch.app.SearchSpec build();
+    method public androidx.appsearch.app.SearchSpec.Builder setMaxSnippetSize(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setNamespaces(java.lang.String!...);
+    method public androidx.appsearch.app.SearchSpec.Builder setNumPerPage(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setOrder(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setRankingStrategy(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setSchemaTypes(java.lang.String!...);
+    method public androidx.appsearch.app.SearchSpec.Builder setSnippetCount(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setSnippetCountPerProperty(int);
+    method public androidx.appsearch.app.SearchSpec.Builder setTermMatch(int);
+  }
+
 }
 
 package androidx.appsearch.exceptions {
diff --git a/appsearch/appsearch/build.gradle b/appsearch/appsearch/build.gradle
index db965f0..2e4e0c8 100644
--- a/appsearch/appsearch/build.gradle
+++ b/appsearch/appsearch/build.gradle
@@ -32,21 +32,6 @@
     }
 }
 
-// Add :icing as jarjar dependency
-// TODO(b/163453135): this code should be ported to use bundles instead of protos, and this
-//  dependency removed. It should exist ONLY inside appsearch:local-backend.
-android.libraryVariants.all { variant ->
-    def variantName = variant.name
-    def suffix = variantName.capitalize()
-    def jarjarConfigName = "jarjar${suffix}"
-    def jarjarConf = configurations.register(jarjarConfigName)
-    // Treat icing-java as a local jar and package it inside the aar.
-    dependencies.add(jarjarConfigName, project.dependencies.project(
-            path: ":icing",
-            configuration: jarjarConfigName))
-    dependencies.add("${variantName}Implementation", files(jarjarConf))
-}
-
 dependencies {
     api('androidx.annotation:annotation:1.1.0')
 
@@ -63,7 +48,6 @@
     // This dependency is unused by the test implementation, but it's here to validate that
     // icing's jarjar'ing of the Protobuf_lite doesn't conflict with external dependencies.
     androidTestImplementation(PROTOBUF_LITE)
-
 }
 
 // Create a jar for use by appsearch-compiler:test
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTest.java
new file mode 100644
index 0000000..6b41cb9
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AnnotationProcessorTest.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2020 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.appsearch.app;
+
+import static androidx.appsearch.app.AppSearchTestUtils.checkIsBatchResultSuccess;
+import static androidx.appsearch.app.AppSearchTestUtils.checkIsResultSuccess;
+import static androidx.appsearch.app.AppSearchTestUtils.doQuery;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import androidx.appsearch.annotation.AppSearchDocument;
+import androidx.appsearch.localbackend.LocalBackend;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+public class AnnotationProcessorTest {
+    private AppSearchManager mAppSearchManager;
+
+    @Before
+    public void setUp() throws Exception {
+        Context context = ApplicationProvider.getApplicationContext();
+        LocalBackend backend = LocalBackend.getInstance(context).getResultValue();
+        mAppSearchManager = checkIsResultSuccess(new AppSearchManager.Builder()
+                .setDatabaseName("testDb").setBackend(backend).build());
+
+        // Remove all documents from any instances that may have been created in the tests.
+        backend.resetAllDatabases().getResultValue();
+    }
+
+    @AppSearchDocument
+    static class Gift {
+        @AppSearchDocument.Uri String mUri;
+
+        // Collections
+        @AppSearchDocument.Property Collection<Long> mLongCollection;         // 1a
+//        @AppSearchDocument.Property Collection<Integer> mCollectInteger;   // 1a
+        @AppSearchDocument.Property Collection<Double> mCollectDouble;     // 1a
+//        @AppSearchDocument.Property Collection<Float> mCollectFloat;       // 1a
+        @AppSearchDocument.Property Collection<Boolean> mCollectBoolean;   // 1a
+        @AppSearchDocument.Property Collection<byte[]> mCollectByteArr;    // 1a
+        @AppSearchDocument.Property Collection<String> mCollectString;     // 1b
+        @AppSearchDocument.Property Collection<Gift> mCollectGift;         // 1c
+
+        // Arrays
+        @AppSearchDocument.Property Long[] mArrBoxLong;         // 2a
+        @AppSearchDocument.Property long[] mArrUnboxLong;       // 2b
+//        @AppSearchDocument.Property Integer[] mArrBoxInteger;   // 2a
+//        @AppSearchDocument.Property int[] mArrUnboxInt;         // 2a
+        @AppSearchDocument.Property Double[] mArrBoxDouble;     // 2a
+        @AppSearchDocument.Property double[] mArrUnboxDouble;   // 2b
+//        @AppSearchDocument.Property Float[] mArrBoxFloat;       // 2a
+//        @AppSearchDocument.Property float[] mArrUnboxFloat;     // 2a
+        @AppSearchDocument.Property Boolean[] mArrBoxBoolean;   // 2a
+        @AppSearchDocument.Property boolean[] mArrUnboxBoolean; // 2b
+        @AppSearchDocument.Property byte[][] mArrUnboxByteArr;  // 2b
+        @AppSearchDocument.Property Byte[] mBoxByteArr;         // 2a
+        @AppSearchDocument.Property String[] mArrString;        // 2b
+//        @AppSearchDocument.Property Gift[] mArrGift;            // 2c
+
+        // Single values
+        @AppSearchDocument.Property String mString;        // 3a
+        @AppSearchDocument.Property Long mBoxLong;         // 3a
+        @AppSearchDocument.Property long mUnboxLong;       // 3b
+//        @AppSearchDocument.Property Integer mBoxInteger;   // 3a
+//        @AppSearchDocument.Property int mUnboxInt;         // 3b
+        @AppSearchDocument.Property Double mBoxDouble;     // 3a
+        @AppSearchDocument.Property double mUnboxDouble;   // 3b
+//        @AppSearchDocument.Property Float mBoxFloat;       // 3a
+//        @AppSearchDocument.Property float mUnboxFloat;     // 3b
+        @AppSearchDocument.Property Boolean mBoxBoolean;   // 3a
+        @AppSearchDocument.Property boolean mUnboxBoolean; // 3b
+        @AppSearchDocument.Property byte[] mUnboxByteArr;  // 3a
+//        @AppSearchDocument.Property Gift mGift;            // 3c
+
+        @Override
+        public boolean equals(Object other) {
+            if (this == other) {
+                return true;
+            }
+            if (!(other instanceof Gift)) {
+                return false;
+            }
+            Gift otherGift = (Gift) other;
+            assertThat(otherGift.mUri).isEqualTo(this.mUri);
+            assertThat(otherGift.mArrBoxBoolean).isEqualTo(this.mArrBoxBoolean);
+            assertThat(otherGift.mArrBoxDouble).isEqualTo(this.mArrBoxDouble);
+            assertThat(otherGift.mArrBoxLong).isEqualTo(this.mArrBoxLong);
+            assertThat(otherGift.mArrString).isEqualTo(this.mArrString);
+            assertThat(otherGift.mBoxByteArr).isEqualTo(this.mBoxByteArr);
+            assertThat(otherGift.mArrUnboxBoolean).isEqualTo(this.mArrUnboxBoolean);
+            assertThat(otherGift.mArrUnboxByteArr).isEqualTo(this.mArrUnboxByteArr);
+            assertThat(otherGift.mArrUnboxDouble).isEqualTo(this.mArrUnboxDouble);
+            assertThat(otherGift.mArrUnboxLong).isEqualTo(this.mArrUnboxLong);
+
+            assertThat(otherGift.mLongCollection).isEqualTo(this.mLongCollection);
+            assertThat(otherGift.mCollectBoolean).isEqualTo(this.mCollectBoolean);
+            assertThat(otherGift.mCollectString).isEqualTo(this.mCollectString);
+            assertThat(otherGift.mCollectDouble).isEqualTo(this.mCollectDouble);
+            assertThat(otherGift.mCollectGift).isEqualTo(this.mCollectGift);
+            checkCollectByteArr(otherGift.mCollectByteArr, this.mCollectByteArr);
+
+            assertThat(otherGift.mString).isEqualTo(this.mString);
+            assertThat(otherGift.mBoxLong).isEqualTo(this.mBoxLong);
+            assertThat(otherGift.mUnboxLong).isEqualTo(this.mUnboxLong);
+            assertThat(otherGift.mBoxDouble).isEqualTo(this.mBoxDouble);
+            assertThat(otherGift.mUnboxDouble).isEqualTo(this.mUnboxDouble);
+            assertThat(otherGift.mBoxBoolean).isEqualTo(this.mBoxBoolean);
+            assertThat(otherGift.mUnboxBoolean).isEqualTo(this.mUnboxBoolean);
+            assertThat(otherGift.mUnboxByteArr).isEqualTo(this.mUnboxByteArr);
+            return true;
+        }
+
+        void checkCollectByteArr(Collection<byte[]> first, Collection<byte[]> second) {
+            if (first == null && second == null) {
+                return;
+            }
+            assertThat(first).isNotNull();
+            assertThat(second).isNotNull();
+            assertThat(first.toArray()).isEqualTo(second.toArray());
+        }
+    }
+
+    @Test
+    public void testAnnotationProcessor() throws Exception {
+        //TODO(b/156296904) add test for int, float, GenericDocument, and class with
+        // @AppSearchDocument annotation
+        checkIsResultSuccess(mAppSearchManager.setSchema(
+                new AppSearchManager.SetSchemaRequest.Builder()
+                        .addDataClass(Gift.class)
+                        .build()));
+
+        // Create a Gift object and assign values.
+        Gift inputDataClass = new Gift();
+        inputDataClass.mUri = "gift.uri";
+
+        inputDataClass.mArrBoxBoolean = new Boolean[]{true, false};
+        inputDataClass.mArrBoxDouble = new Double[]{0.0, 1.0};
+        inputDataClass.mArrBoxLong = new Long[]{6L, 7L};
+        inputDataClass.mArrString = new String[]{"cat", "dog"};
+        inputDataClass.mBoxByteArr = new Byte[]{8, 9};
+        inputDataClass.mArrUnboxBoolean = new boolean[]{false, true};
+        inputDataClass.mArrUnboxByteArr = new byte[][]{{0, 1}, {2, 3}};
+        inputDataClass.mArrUnboxDouble = new double[]{1.0, 0.0};
+        inputDataClass.mArrUnboxLong = new long[]{7, 6};
+
+        Gift innerGift1 = new Gift();
+        innerGift1.mUri = "innerGift.uri1";
+        Gift innerGift2 = new Gift();
+        innerGift2.mUri = "innerGift.uri2";
+        inputDataClass.mLongCollection = Arrays.asList(inputDataClass.mArrBoxLong);
+        inputDataClass.mCollectBoolean = Arrays.asList(inputDataClass.mArrBoxBoolean);
+        inputDataClass.mCollectString = Arrays.asList(inputDataClass.mArrString);
+        inputDataClass.mCollectDouble = Arrays.asList(inputDataClass.mArrBoxDouble);
+        inputDataClass.mCollectByteArr = Arrays.asList(inputDataClass.mArrUnboxByteArr);
+        inputDataClass.mCollectGift = Arrays.asList(innerGift1, innerGift2);
+
+        inputDataClass.mString = "String";
+        inputDataClass.mBoxLong = 1L;
+        inputDataClass.mUnboxLong = 2L;
+        inputDataClass.mBoxDouble = 5.0;
+        inputDataClass.mUnboxDouble = 6.0;
+        inputDataClass.mBoxBoolean = true;
+        inputDataClass.mUnboxBoolean = false;
+        inputDataClass.mUnboxByteArr = new byte[]{1, 2, 3};
+
+        // Index the Gift document and query it.
+        checkIsBatchResultSuccess(mAppSearchManager.putDocuments(
+                new AppSearchManager.PutDocumentsRequest.Builder()
+                        .addDataClass(inputDataClass).build()));
+        List<GenericDocument> searchResults = doQuery(mAppSearchManager, "");
+        assertThat(searchResults).hasSize(1);
+
+        // Create DataClassFactory for Gift.
+        DataClassFactoryRegistry registry = DataClassFactoryRegistry.getInstance();
+        DataClassFactory<Gift> factory = registry.getOrCreateFactory(Gift.class);
+
+        // Convert GenericDocument to Gift and check values.
+        Gift outputDataClass = factory.fromGenericDocument(searchResults.get((0)));
+        assertThat(outputDataClass).isEqualTo(inputDataClass);
+    }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchManagerTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchManagerTest.java
index 6b7edaa..b971dce 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchManagerTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchManagerTest.java
@@ -20,6 +20,10 @@
 import static androidx.appsearch.app.AppSearchManager.PutDocumentsRequest;
 import static androidx.appsearch.app.AppSearchManager.RemoveDocumentsRequest;
 import static androidx.appsearch.app.AppSearchManager.SetSchemaRequest;
+import static androidx.appsearch.app.AppSearchTestUtils.checkIsBatchResultSuccess;
+import static androidx.appsearch.app.AppSearchTestUtils.checkIsResultSuccess;
+import static androidx.appsearch.app.AppSearchTestUtils.doGet;
+import static androidx.appsearch.app.AppSearchTestUtils.doQuery;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -32,8 +36,6 @@
 import androidx.appsearch.localbackend.LocalBackend;
 import androidx.test.core.app.ApplicationProvider;
 
-import junit.framework.AssertionFailedError;
-
 import org.junit.Before;
 import org.junit.Test;
 
@@ -41,7 +43,6 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import java.util.concurrent.Future;
 
 public class AppSearchManagerTest {
     private AppSearchManager mDb1;
@@ -50,7 +51,7 @@
     @Before
     public void setUp() throws Exception {
         Context context = ApplicationProvider.getApplicationContext();
-        LocalBackend backend = new LocalBackend.Builder(context).build().getResultValue();
+        LocalBackend backend = LocalBackend.getInstance(context).getResultValue();
         mDb1 = checkIsResultSuccess(new AppSearchManager.Builder()
                 .setDatabaseName("testDb1").setBackend(backend).build());
         mDb2 = checkIsResultSuccess(new AppSearchManager.Builder()
@@ -443,7 +444,7 @@
         // Set number of results per page is 7.
         SearchResults searchResults = mDb1.query("body",
                 new SearchSpec.Builder()
-                        .setTermMatchType(SearchSpec.TERM_MATCH_TYPE_EXACT_ONLY)
+                        .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
                         .setNumPerPage(7)
                         .build());
         List<GenericDocument> documents = new ArrayList<>();
@@ -503,7 +504,7 @@
         // Query only for Document
         results = doQuery(mDb1, "body", new SearchSpec.Builder()
                 .setSchemaTypes("Generic")
-                .setTermMatchType(SearchSpec.TERM_MATCH_TYPE_EXACT_ONLY)
+                .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
                 .build());
         assertThat(results).hasSize(1);
         assertThat(results).containsExactly(inDoc);
@@ -547,7 +548,7 @@
         results = doQuery(mDb1, "body",
                 new SearchSpec.Builder()
                         .setNamespaces("expectedNamespace")
-                        .setTermMatchType(SearchSpec.TERM_MATCH_TYPE_EXACT_ONLY)
+                        .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
                         .build());
         assertThat(results).hasSize(1);
         assertThat(results).containsExactly(expectedEmail);
@@ -623,15 +624,15 @@
         SearchResults searchResults = mDb1.query("foo",
                 new SearchSpec.Builder()
                         .setSchemaTypes("Generic")
-                        .setNumToSnippet(1)
-                        .setNumMatchesPerProperty(1)
+                        .setSnippetCount(1)
+                        .setSnippetCountPerProperty(1)
                         .setMaxSnippetSize(10)
-                        .setTermMatchType(SearchSpec.TERM_MATCH_TYPE_PREFIX)
+                        .setTermMatch(SearchSpec.TERM_MATCH_PREFIX)
                         .build());
         List<SearchResults.Result> results = checkIsResultSuccess(searchResults.getNextPage());
         assertThat(results).hasSize(1);
 
-        List<MatchInfo> matchInfos = results.get(0).getMatchInfo();
+        List<MatchInfo> matchInfos = results.get(0).getMatches();
         assertThat(matchInfos).isNotNull();
         assertThat(matchInfos).hasSize(1);
         MatchInfo matchInfo = matchInfos.get(0);
@@ -1059,57 +1060,4 @@
                 () -> appSearchBuilder.setDatabaseName("/testDatabaseNameStartWith"));
         assertThat(e).hasMessageThat().isEqualTo("Database name cannot contain '/'");
     }
-
-    private static List<GenericDocument> doGet(
-            AppSearchManager instance, String namespace, String... uris) throws Exception {
-        AppSearchBatchResult<String, GenericDocument> result = checkIsBatchResultSuccess(
-                instance.getDocuments(new GetDocumentsRequest.Builder()
-                        .setNamespace(namespace).addUris(uris).build()));
-        assertThat(result.getSuccesses()).hasSize(uris.length);
-        assertThat(result.getFailures()).isEmpty();
-        List<GenericDocument> list = new ArrayList<>(uris.length);
-        for (String uri : uris) {
-            list.add(result.getSuccesses().get(uri));
-        }
-        return list;
-    }
-
-    private List<GenericDocument> doQuery(
-            AppSearchManager instance, String queryExpression, SearchSpec spec)
-            throws Exception {
-        SearchResults searchResults = instance.query(queryExpression, spec);
-        List<SearchResults.Result> results = checkIsResultSuccess(searchResults.getNextPage());
-        List<GenericDocument> documents = new ArrayList<>();
-        while (results.size() > 0) {
-            for (SearchResults.Result result : results) {
-                documents.add(result.getDocument());
-            }
-            results = checkIsResultSuccess(searchResults.getNextPage());
-        }
-        return documents;
-    }
-
-    private List<GenericDocument> doQuery(AppSearchManager instance, String queryExpression)
-            throws Exception {
-        return doQuery(instance, queryExpression, new SearchSpec.Builder()
-                .setTermMatchType(SearchSpec.TERM_MATCH_TYPE_EXACT_ONLY)
-                .build());
-    }
-
-    private static <K, V> AppSearchBatchResult<K, V> checkIsBatchResultSuccess(
-            Future<AppSearchBatchResult<K, V>> future) throws Exception {
-        AppSearchBatchResult<K, V> result = future.get();
-        if (!result.isSuccess()) {
-            throw new AssertionFailedError("AppSearchBatchResult not successful: " + result);
-        }
-        return result;
-    }
-
-    private static <V> V checkIsResultSuccess(Future<AppSearchResult<V>> future) throws Exception {
-        AppSearchResult<V> result = future.get();
-        if (!result.isSuccess()) {
-            throw new AssertionFailedError("AppSearchResult not successful: " + result);
-        }
-        return result.getResultValue();
-    }
 }
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchSchemaTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchSchemaTest.java
index 217f825..01bc50a 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchSchemaTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchSchemaTest.java
@@ -25,105 +25,11 @@
 import androidx.appsearch.exceptions.IllegalSchemaException;
 import androidx.test.filters.SmallTest;
 
-import com.google.android.icing.proto.IndexingConfig;
-import com.google.android.icing.proto.PropertyConfigProto;
-import com.google.android.icing.proto.SchemaTypeConfigProto;
-import com.google.android.icing.proto.TermMatchType;
-
 import org.junit.Test;
 
 @SmallTest
 public class AppSearchSchemaTest {
     @Test
-    public void testGetProto_Email() {
-        AppSearchSchema emailSchema = new AppSearchSchema.Builder("Email")
-                .addProperty(new PropertyConfig.Builder("subject")
-                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
-                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
-                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
-                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
-                        .build()
-                ).addProperty(new PropertyConfig.Builder("body")
-                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
-                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
-                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
-                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
-                        .build()
-                ).build();
-
-        SchemaTypeConfigProto expectedEmailProto = SchemaTypeConfigProto.newBuilder()
-                .setSchemaType("Email")
-                .addProperties(PropertyConfigProto.newBuilder()
-                        .setPropertyName("subject")
-                        .setDataType(PropertyConfigProto.DataType.Code.STRING)
-                        .setSchemaType("")
-                        .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
-                        .setIndexingConfig(
-                                com.google.android.icing.proto.IndexingConfig.newBuilder()
-                                        .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
-                                        .setTermMatchType(TermMatchType.Code.PREFIX)
-                        )
-                ).addProperties(PropertyConfigProto.newBuilder()
-                        .setPropertyName("body")
-                        .setDataType(PropertyConfigProto.DataType.Code.STRING)
-                        .setSchemaType("")
-                        .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
-                        .setIndexingConfig(
-                                com.google.android.icing.proto.IndexingConfig.newBuilder()
-                                        .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
-                                        .setTermMatchType(TermMatchType.Code.PREFIX)
-                        )
-                ).build();
-
-        assertThat(SchemaToProtoConverter.convert(emailSchema)).isEqualTo(expectedEmailProto);
-    }
-
-    @Test
-    public void testGetProto_MusicRecording() {
-        AppSearchSchema musicRecordingSchema = new AppSearchSchema.Builder("MusicRecording")
-                .addProperty(new PropertyConfig.Builder("artist")
-                        .setDataType(PropertyConfig.DATA_TYPE_STRING)
-                        .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
-                        .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
-                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
-                        .build()
-                ).addProperty(new PropertyConfig.Builder("pubDate")
-                        .setDataType(PropertyConfig.DATA_TYPE_INT64)
-                        .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
-                        .setIndexingType(PropertyConfig.INDEXING_TYPE_NONE)
-                        .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_NONE)
-                        .build()
-                ).build();
-
-        SchemaTypeConfigProto expectedMusicRecordingProto = SchemaTypeConfigProto.newBuilder()
-                .setSchemaType("MusicRecording")
-                .addProperties(PropertyConfigProto.newBuilder()
-                        .setPropertyName("artist")
-                        .setDataType(PropertyConfigProto.DataType.Code.STRING)
-                        .setSchemaType("")
-                        .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
-                        .setIndexingConfig(
-                                com.google.android.icing.proto.IndexingConfig.newBuilder()
-                                        .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
-                                        .setTermMatchType(TermMatchType.Code.PREFIX)
-                        )
-                ).addProperties(PropertyConfigProto.newBuilder()
-                        .setPropertyName("pubDate")
-                        .setDataType(PropertyConfigProto.DataType.Code.INT64)
-                        .setSchemaType("")
-                        .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
-                        .setIndexingConfig(
-                                com.google.android.icing.proto.IndexingConfig.newBuilder()
-                                        .setTokenizerType(IndexingConfig.TokenizerType.Code.NONE)
-                                        .setTermMatchType(TermMatchType.Code.UNKNOWN)
-                        )
-                ).build();
-
-        assertThat(SchemaToProtoConverter.convert(musicRecordingSchema))
-                .isEqualTo(expectedMusicRecordingProto);
-    }
-
-    @Test
     public void testInvalidEnums() {
         PropertyConfig.Builder builder = new PropertyConfig.Builder("test");
         assertThrows(IllegalArgumentException.class, () -> builder.setDataType(99));
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchTestUtils.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchTestUtils.java
new file mode 100644
index 0000000..0c0e417
--- /dev/null
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/AppSearchTestUtils.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2020 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.appsearch.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import junit.framework.AssertionFailedError;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Future;
+
+public class AppSearchTestUtils {
+
+    public static <V> V checkIsResultSuccess(Future<AppSearchResult<V>> future) throws Exception {
+        AppSearchResult<V> result = future.get();
+        if (!result.isSuccess()) {
+            throw new AssertionFailedError("AppSearchResult not successful: " + result);
+        }
+        return result.getResultValue();
+    }
+
+    public static List<GenericDocument> doGet(
+            AppSearchManager instance, String namespace, String... uris) throws Exception {
+        AppSearchBatchResult<String, GenericDocument> result = checkIsBatchResultSuccess(
+                instance.getDocuments(new AppSearchManager.GetDocumentsRequest.Builder()
+                        .setNamespace(namespace).addUris(uris).build()));
+        assertThat(result.getSuccesses()).hasSize(uris.length);
+        assertThat(result.getFailures()).isEmpty();
+        List<GenericDocument> list = new ArrayList<>(uris.length);
+        for (String uri : uris) {
+            list.add(result.getSuccesses().get(uri));
+        }
+        return list;
+    }
+
+    public static List<GenericDocument> doQuery(
+            AppSearchManager instance, String queryExpression, SearchSpec spec)
+            throws Exception {
+        SearchResults searchResults = instance.query(queryExpression, spec);
+        List<SearchResults.Result> results = checkIsResultSuccess(searchResults.getNextPage());
+        List<GenericDocument> documents = new ArrayList<>();
+        while (results.size() > 0) {
+            for (SearchResults.Result result : results) {
+                documents.add(result.getDocument());
+            }
+            results = checkIsResultSuccess(searchResults.getNextPage());
+        }
+        return documents;
+    }
+
+    public static List<GenericDocument> doQuery(AppSearchManager instance, String queryExpression)
+            throws Exception {
+        return doQuery(instance, queryExpression, new SearchSpec.Builder()
+                .setTermMatch(SearchSpec.TERM_MATCH_EXACT_ONLY)
+                .build());
+    }
+
+    public static <K, V> AppSearchBatchResult<K, V> checkIsBatchResultSuccess(
+            Future<AppSearchBatchResult<K, V>> future) throws Exception {
+        AppSearchBatchResult<K, V> result = future.get();
+        if (!result.isSuccess()) {
+            throw new AssertionFailedError("AppSearchBatchResult not successful: " + result);
+        }
+        return result;
+    }
+}
diff --git a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/GenericDocumentTest.java b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/GenericDocumentTest.java
index 71e05dc..bfbb9fd 100644
--- a/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/GenericDocumentTest.java
+++ b/appsearch/appsearch/src/androidTest/java/androidx/appsearch/app/GenericDocumentTest.java
@@ -22,26 +22,19 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.protobuf.ByteString;
-
 import org.junit.Test;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-
 @SmallTest
 public class GenericDocumentTest {
     private static final byte[] sByteArray1 = new byte[]{(byte) 1, (byte) 2, (byte) 3};
-    private static final byte[] sByteArray2 = new byte[]{(byte) 4, (byte) 5, (byte) 6};
+    private static final byte[] sByteArray2 = new byte[]{(byte) 4, (byte) 5, (byte) 6, (byte) 7};
     private static final GenericDocument sDocumentProperties1 = new GenericDocument
             .Builder("sDocumentProperties1", "sDocumentPropertiesSchemaType1")
+            .setCreationTimestampMillis(12345L)
             .build();
     private static final GenericDocument sDocumentProperties2 = new GenericDocument
             .Builder("sDocumentProperties2", "sDocumentPropertiesSchemaType2")
+            .setCreationTimestampMillis(6789L)
             .build();
 
     @Test
@@ -183,6 +176,49 @@
     }
 
     @Test
+    public void testDocument_ToString() throws Exception {
+        GenericDocument document = new GenericDocument.Builder("uri1", "schemaType1")
+                .setCreationTimestampMillis(5L)
+                .setProperty("longKey1", 1L, 2L, 3L)
+                .setProperty("doubleKey1", 1.0, 2.0, 3.0)
+                .setProperty("booleanKey1", true, false, true)
+                .setProperty("stringKey1", "String1", "String2", "String3")
+                .setProperty("byteKey1", sByteArray1, sByteArray2)
+                .setProperty("documentKey1", sDocumentProperties1, sDocumentProperties2)
+                .build();
+        String exceptedString = "{ key: 'creationTimestampMillis' value: 5 } "
+                + "{ key: 'namespace' value:  } "
+                + "{ key: 'properties' value: "
+                +       "{ key: 'booleanKey1' value: [ 'true' 'false' 'true' ] } "
+                +       "{ key: 'byteKey1' value: "
+                +             "{ key: 'byteArray' value: [ '1' '2' '3' ] } "
+                +             "{ key: 'byteArray' value: [ '4' '5' '6' '7' ] }  } "
+                +       "{ key: 'documentKey1' value: [ '"
+                +             "{ key: 'creationTimestampMillis' value: 12345 } "
+                +             "{ key: 'namespace' value:  } "
+                +             "{ key: 'properties' value:  } "
+                +             "{ key: 'schemaType' value: sDocumentPropertiesSchemaType1 } "
+                +             "{ key: 'score' value: 0 } "
+                +             "{ key: 'ttlMillis' value: 0 } "
+                +             "{ key: 'uri' value: sDocumentProperties1 } ' '"
+                +             "{ key: 'creationTimestampMillis' value: 6789 } "
+                +             "{ key: 'namespace' value:  } "
+                +             "{ key: 'properties' value:  } "
+                +             "{ key: 'schemaType' value: sDocumentPropertiesSchemaType2 } "
+                +             "{ key: 'score' value: 0 } "
+                +             "{ key: 'ttlMillis' value: 0 } "
+                +             "{ key: 'uri' value: sDocumentProperties2 } ' ] } "
+                +       "{ key: 'doubleKey1' value: [ '1.0' '2.0' '3.0' ] } "
+                +       "{ key: 'longKey1' value: [ '1' '2' '3' ] } "
+                +       "{ key: 'stringKey1' value: [ 'String1' 'String2' 'String3' ] }  } "
+                + "{ key: 'schemaType' value: schemaType1 } "
+                + "{ key: 'score' value: 0 } "
+                + "{ key: 'ttlMillis' value: 0 } "
+                + "{ key: 'uri' value: uri1 } ";
+        assertThat(document.toString()).isEqualTo(exceptedString);
+    }
+
+    @Test
     public void testDocumentGetValues_DifferentTypes() {
         GenericDocument document = new GenericDocument.Builder("uri1", "schemaType1")
                 .setScore(1)
@@ -215,50 +251,4 @@
         assertThrows(
                 IllegalArgumentException.class, () -> builder.setProperty("test", new boolean[]{}));
     }
-
-    @Test
-    public void testDocumentProtoPopulation() {
-        GenericDocument document = new GenericDocument.Builder("uri1", "schemaType1")
-                .setCreationTimestampMillis(5L)
-                .setScore(1)
-                .setTtlMillis(1L)
-                .setNamespace("namespace")
-                .setProperty("longKey1", 1L)
-                .setProperty("doubleKey1", 1.0)
-                .setProperty("booleanKey1", true)
-                .setProperty("stringKey1", "test-value1")
-                .setProperty("byteKey1", sByteArray1)
-                .setProperty("documentKey1", sDocumentProperties1)
-                .build();
-
-        // Create the Document proto. Need to sort the property order by key.
-        DocumentProto.Builder documentProtoBuilder = DocumentProto.newBuilder()
-                .setUri("uri1")
-                .setSchema("schemaType1")
-                .setCreationTimestampMs(5L)
-                .setScore(1)
-                .setTtlMs(1L)
-                .setNamespace("namespace");
-        HashMap<String, PropertyProto.Builder> propertyProtoMap = new HashMap<>();
-        propertyProtoMap.put("longKey1",
-                PropertyProto.newBuilder().setName("longKey1").addInt64Values(1L));
-        propertyProtoMap.put("doubleKey1",
-                PropertyProto.newBuilder().setName("doubleKey1").addDoubleValues(1.0));
-        propertyProtoMap.put("booleanKey1",
-                PropertyProto.newBuilder().setName("booleanKey1").addBooleanValues(true));
-        propertyProtoMap.put("stringKey1",
-                PropertyProto.newBuilder().setName("stringKey1").addStringValues("test-value1"));
-        propertyProtoMap.put("byteKey1",
-                PropertyProto.newBuilder().setName("byteKey1").addBytesValues(
-                        ByteString.copyFrom(sByteArray1)));
-        propertyProtoMap.put("documentKey1",
-                PropertyProto.newBuilder().setName("documentKey1")
-                        .addDocumentValues(sDocumentProperties1.getProto()));
-        List<String> sortedKey = new ArrayList<>(propertyProtoMap.keySet());
-        Collections.sort(sortedKey);
-        for (String key : sortedKey) {
-            documentProtoBuilder.addProperties(propertyProtoMap.get(key));
-        }
-        assertThat(document.getProto()).isEqualTo(documentProtoBuilder.build());
-    }
 }
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBackend.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBackend.java
index 3e073a4..580f3da 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBackend.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchBackend.java
@@ -16,9 +16,11 @@
 
 package androidx.appsearch.app;
 
+import androidx.annotation.AnyThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
 
 import java.io.Closeable;
 import java.util.List;
@@ -31,8 +33,10 @@
 * @hide
 */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@WorkerThread
 public interface AppSearchBackend {
     /** Returns {@code true} if this backend has been successfully initialized. */
+    @AnyThread
     boolean isInitialized();
 
     /**
@@ -125,6 +129,7 @@
      * Abstracts a returned search results object, where the pagination of the results can be
      * implemented.
      */
+    @WorkerThread
     interface BackendSearchResults extends Closeable {
 
         /**
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchManager.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchManager.java
index 7291c563..4a08c79 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchManager.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/AppSearchManager.java
@@ -98,8 +98,7 @@
         }
 
         /**
-         * Connects to the AppSearch database per this builder's configuration, and asynchronously
-         * returns the initialized instance.
+         * Asynchronously connects to the AppSearch backend and returns the initialized instance.
          */
         @NonNull
         public ListenableFuture<AppSearchResult<AppSearchManager>> build() {
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactory.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactory.java
index 9529a1b..5efb9a4 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactory.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactory.java
@@ -18,6 +18,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
+import androidx.appsearch.exceptions.AppSearchException;
 
 /**
  * An interface for factories which can convert between data classes and {@link GenericDocument}.
@@ -37,17 +38,17 @@
 
     /** Returns the schema for this data class. */
     @NonNull
-    AppSearchSchema getSchema();
+    AppSearchSchema getSchema() throws AppSearchException;
 
     /**
      * Converts an instance of the data class into a {@link androidx.appsearch.app.GenericDocument}.
      */
     @NonNull
-    GenericDocument toGenericDocument(@NonNull T dataClass);
+    GenericDocument toGenericDocument(@NonNull T dataClass) throws AppSearchException;
 
     /**
      * Converts a {@link androidx.appsearch.app.GenericDocument} into an instance of the data class.
      */
     @NonNull
-    T fromGenericDocument(@NonNull GenericDocument genericDoc);
+    T fromGenericDocument(@NonNull GenericDocument genericDoc) throws AppSearchException;
 }
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactoryRegistry.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactoryRegistry.java
index b59e399..9166357 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactoryRegistry.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/DataClassFactoryRegistry.java
@@ -109,12 +109,19 @@
                     "Failed to find simple name for data class \"" + dataClass
                             + "\". Perhaps it is anonymous?");
         }
+
+        // Creates factory class name under the package.
+        // For a class Foo annotated with @AppSearchDocument, we will generated a
+        // $$__AppSearch__Foo.class under the package.
+        // For an inner class Foo.Bar annotated with @AppSearchDocument, we will generated a
+        // $$__AppSearch__Foo$$__Bar.class under the package.
         String packageName = "";
         if (pkg != null) {
             packageName = pkg.getName() + ".";
-            simpleName = simpleName.substring(packageName.length());
+            simpleName = simpleName.substring(packageName.length()).replace(".", "$$__");
         }
         String factoryClassName = packageName + GEN_CLASS_PREFIX + simpleName;
+
         Class<?> factoryClass;
         try {
             factoryClass = Class.forName(factoryClassName);
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java
index f7ef7c4..83d746f 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/GenericDocument.java
@@ -17,22 +17,19 @@
 package androidx.appsearch.app;
 
 import android.annotation.SuppressLint;
+import android.os.Bundle;
 import android.util.Log;
 
 import androidx.annotation.IntRange;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.appsearch.exceptions.AppSearchException;
-import androidx.collection.ArrayMap;
 import androidx.core.util.Preconditions;
 
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.PropertyProto;
-import com.google.android.icing.protobuf.ByteString;
-
+import java.lang.reflect.Array;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Map;
+import java.util.Arrays;
+import java.util.Set;
 
 /**
  * Represents a document unit.
@@ -60,6 +57,21 @@
     /** The maximum number of indexed properties a document can have. */
     private static final int MAX_INDEXED_PROPERTIES = 16;
 
+    /** The default score of document. */
+    private static final int DEFAULT_SCORE = 0;
+
+    /** The default time-to-live in millisecond of a document, which is infinity. */
+    private static final long DEFAULT_TTL_MILLIS = 0L;
+
+    static final String SCHEMA_TYPE_FIELD = "schemaType";
+    static final String URI_FIELD = "uri";
+    static final String SCORE_FIELD = "score";
+    static final String TTL_MILLIS_FIELD = "ttlMillis";
+    static final String CREATION_TIMESTAMP_MILLIS_FIELD = "creationTimestampMillis";
+    static final String NAMESPACE_FIELD = "namespace";
+    static final String PROPERTIES_FIELD = "properties";
+    static final String BYTE_ARRAY_FIELD = "byteArray";
+
     /**
      * The maximum number of indexed properties a document can have.
      *
@@ -72,30 +84,36 @@
         return MAX_INDEXED_PROPERTIES;
     }
 
-    /**
-     * Contains {@link GenericDocument} basic information (uri, schemaType etc) and properties
-     * ordered by keys.
-     */
+    /** Contains {@link GenericDocument} basic information (uri, schemaType etc).*/
     @NonNull
-    private final DocumentProto mProto;
+    final Bundle mBundle;
 
-    /** Contains all properties in {@link #mProto} to support getting properties via keys. */
+    /** Contains all properties in {@link GenericDocument} to support getting properties via keys.*/
     @NonNull
-    private final Map<String, Object> mProperties;
+    final Bundle mProperties;
+
+    @NonNull
+    private final String mUri;
+    @NonNull
+    private final String mSchemaType;
+    private final long mCreationTimestampMillis;
+    @Nullable
+    private Integer mHashCode;
 
     /**
-     * Creates a new {@link GenericDocument}.
-     * @param proto Contains {@link GenericDocument} basic information (uri, schemaType etc) and
-     *               properties ordered by keys.
-     * @param propertiesMap Contains all properties in {@link #mProto} to support get properties
-     *                      via keys.
+     * Rebuilds a {@link GenericDocument} by the a bundle.
+     * @param bundle Contains {@link GenericDocument} basic information (uri, schemaType etc) and
+     *               a properties bundle contains all properties in {@link GenericDocument} to
+     *               support getting properties via keys.
      */
-    GenericDocument(@NonNull DocumentProto proto,
-            @NonNull Map<String, Object> propertiesMap) {
-        Preconditions.checkNotNull(proto);
-        Preconditions.checkNotNull(propertiesMap);
-        mProto = proto;
-        mProperties = propertiesMap;
+    GenericDocument(@NonNull Bundle bundle) {
+        Preconditions.checkNotNull(bundle);
+        mBundle = bundle;
+        mProperties = Preconditions.checkNotNull(bundle.getParcelable(PROPERTIES_FIELD));
+        mUri = Preconditions.checkNotNull(mBundle.getString(URI_FIELD));
+        mSchemaType = Preconditions.checkNotNull(mBundle.getString(SCHEMA_TYPE_FIELD));
+        mCreationTimestampMillis = mBundle.getLong(CREATION_TIMESTAMP_MILLIS_FIELD,
+                System.currentTimeMillis());
     }
 
     /**
@@ -104,89 +122,30 @@
      * <p>This method should be only used by constructor of a subclass.
      */
     protected GenericDocument(@NonNull GenericDocument document) {
-        this(document.mProto, document.mProperties);
-    }
-
-    GenericDocument(@NonNull DocumentProto documentProto) {
-        this(documentProto, new ArrayMap<>());
-        for (int i = 0; i < documentProto.getPropertiesCount(); i++) {
-            PropertyProto property = documentProto.getProperties(i);
-            String name = property.getName();
-            if (property.getStringValuesCount() > 0) {
-                String[] values = new String[property.getStringValuesCount()];
-                for (int j = 0; j < values.length; j++) {
-                    values[j] = property.getStringValues(j);
-                }
-                mProperties.put(name, values);
-            } else if (property.getInt64ValuesCount() > 0) {
-                long[] values = new long[property.getInt64ValuesCount()];
-                for (int j = 0; j < values.length; j++) {
-                    values[j] = property.getInt64Values(j);
-                }
-                mProperties.put(property.getName(), values);
-            } else if (property.getDoubleValuesCount() > 0) {
-                double[] values = new double[property.getDoubleValuesCount()];
-                for (int j = 0; j < values.length; j++) {
-                    values[j] = property.getDoubleValues(j);
-                }
-                mProperties.put(property.getName(), values);
-            } else if (property.getBooleanValuesCount() > 0) {
-                boolean[] values = new boolean[property.getBooleanValuesCount()];
-                for (int j = 0; j < values.length; j++) {
-                    values[j] = property.getBooleanValues(j);
-                }
-                mProperties.put(property.getName(), values);
-            } else if (property.getBytesValuesCount() > 0) {
-                byte[][] values = new byte[property.getBytesValuesCount()][];
-                for (int j = 0; j < values.length; j++) {
-                    values[j] = property.getBytesValues(j).toByteArray();
-                }
-                mProperties.put(name, values);
-            } else if (property.getDocumentValuesCount() > 0) {
-                GenericDocument[] values =
-                        new GenericDocument[property.getDocumentValuesCount()];
-                for (int j = 0; j < values.length; j++) {
-                    values[j] = new GenericDocument(property.getDocumentValues(j));
-                }
-                mProperties.put(name, values);
-            } else {
-                throw new IllegalStateException("Unknown type of value: " + name);
-            }
-        }
-    }
-
-    /**
-     * Get the {@link DocumentProto} of the {@link GenericDocument}.
-     *
-     * <p>The {@link DocumentProto} contains {@link GenericDocument}'s basic information and all
-     *    properties ordered by keys.
-     */
-    @NonNull
-    DocumentProto getProto() {
-        return mProto;
+        this(document.mBundle);
     }
 
     /** Returns the URI of the {@link GenericDocument}. */
     @NonNull
     public String getUri() {
-        return mProto.getUri();
+        return mUri;
     }
 
     /** Returns the namespace of the {@link GenericDocument}. */
     @NonNull
     public String getNamespace() {
-        return mProto.getNamespace();
+        return mBundle.getString(NAMESPACE_FIELD, DEFAULT_NAMESPACE);
     }
 
     /** Returns the schema type of the {@link GenericDocument}. */
     @NonNull
     public String getSchemaType() {
-        return mProto.getSchema();
+        return mSchemaType;
     }
 
     /** Returns the creation timestamp of the {@link GenericDocument}, in milliseconds. */
     public long getCreationTimestampMillis() {
-        return mProto.getCreationTimestampMs();
+        return mCreationTimestampMillis;
     }
 
     /**
@@ -196,7 +155,7 @@
      *    until the app is uninstalled.
      */
     public long getTtlMillis() {
-        return mProto.getTtlMs();
+        return mBundle.getLong(TTL_MILLIS_FIELD, DEFAULT_TTL_MILLIS);
     }
 
     /**
@@ -208,7 +167,7 @@
      * <p>The default value is 0.
      */
     public int getScore() {
-        return mProto.getScore();
+        return mBundle.getInt(SCORE_FIELD, DEFAULT_SCORE);
     }
 
     /**
@@ -388,9 +347,28 @@
      */
     @SuppressLint("ArrayReturn")
     @Nullable
+    @SuppressWarnings("unchecked")
     public byte[][] getPropertyBytesArray(@NonNull String key) {
         Preconditions.checkNotNull(key);
-        return getAndCastPropertyArray(key, byte[][].class);
+        ArrayList<Bundle> bundles = getAndCastPropertyArray(key, ArrayList.class);
+        if (bundles == null || bundles.size() == 0) {
+            return null;
+        }
+        byte[][] bytes = new byte[bundles.size()][];
+        for (int i = 0; i < bundles.size(); i++) {
+            Bundle bundle = bundles.get(i);
+            if (bundle == null) {
+                Log.e(TAG, "The inner bundle is null at " + i + ", for key: " + key);
+                continue;
+            }
+            byte[] innerBytes = bundle.getByteArray(BYTE_ARRAY_FIELD);
+            if (innerBytes == null) {
+                Log.e(TAG, "The bundle at " + i + " contains a null byte[].");
+                continue;
+            }
+            bytes[i] = innerBytes;
+        }
+        return bytes;
     }
 
     /**
@@ -404,7 +382,19 @@
     @Nullable
     public GenericDocument[] getPropertyDocumentArray(@NonNull String key) {
         Preconditions.checkNotNull(key);
-        return getAndCastPropertyArray(key, GenericDocument[].class);
+        Bundle[] bundles = getAndCastPropertyArray(key, Bundle[].class);
+        if (bundles == null || bundles.length == 0) {
+            return null;
+        }
+        GenericDocument[] documents = new GenericDocument[bundles.length];
+        for (int i = 0; i < bundles.length; i++) {
+            if (bundles[i] == null) {
+                Log.e(TAG, "The inner bundle is null at " + i + ", for key: " + key);
+                continue;
+            }
+            documents[i] = new GenericDocument(bundles[i]);
+        }
+        return documents;
     }
 
     /**
@@ -458,20 +448,203 @@
             return false;
         }
         GenericDocument otherDocument = (GenericDocument) other;
-        return this.mProto.equals(otherDocument.mProto);
+        return bundleEquals(this.mBundle, otherDocument.mBundle);
+    }
+
+    /**
+     * Deeply checks two bundle is equally or not.
+     * <p> Two bundle will be considered equally if they contains same content.
+     */
+    @SuppressWarnings("unchecked")
+    private static boolean bundleEquals(Bundle one, Bundle two) {
+        if (one.size() != two.size()) {
+            return false;
+        }
+        Set<String> keySetOne = one.keySet();
+        Object valueOne;
+        Object valueTwo;
+        // Bundle inherit its equals() from Object.java, which only compare their memory address.
+        // We should iterate all keys and check their presents and values in both bundle.
+        for (String key : keySetOne) {
+            valueOne = one.get(key);
+            valueTwo = two.get(key);
+            if (valueOne instanceof Bundle
+                    && valueTwo instanceof Bundle
+                    && !bundleEquals((Bundle) valueOne, (Bundle) valueTwo)) {
+                return false;
+            } else if (valueOne == null && (valueTwo != null || !two.containsKey(key))) {
+                // If we call bundle.get(key) when the 'key' doesn't actually exist in the
+                // bundle, we'll get  back a null. So make sure that both values are null and
+                // both keys exist in the bundle.
+                return false;
+            } else if (valueOne instanceof boolean[]) {
+                if (!(valueTwo instanceof boolean[])
+                        || !Arrays.equals((boolean[]) valueOne, (boolean[]) valueTwo)) {
+                    return false;
+                }
+            } else if (valueOne instanceof long[]) {
+                if (!(valueTwo instanceof long[])
+                        || !Arrays.equals((long[]) valueOne, (long[]) valueTwo)) {
+                    return false;
+                }
+            } else if (valueOne instanceof double[]) {
+                if (!(valueTwo instanceof double[])
+                        || !Arrays.equals((double[]) valueOne, (double[]) valueTwo)) {
+                    return false;
+                }
+            } else if (valueOne instanceof Bundle[]) {
+                if (!(valueTwo instanceof Bundle[])) {
+                    return false;
+                }
+                Bundle[] bundlesOne = (Bundle[]) valueOne;
+                Bundle[] bundlesTwo = (Bundle[]) valueTwo;
+                if (bundlesOne.length != bundlesTwo.length) {
+                    return false;
+                }
+                for (int i = 0; i < bundlesOne.length; i++) {
+                    if (!bundleEquals(bundlesOne[i], bundlesTwo[i])) {
+                        return false;
+                    }
+                }
+            } else if (valueOne instanceof ArrayList) {
+                if (!(valueTwo instanceof ArrayList)) {
+                    return false;
+                }
+                ArrayList<Bundle> bundlesOne = (ArrayList<Bundle>) valueOne;
+                ArrayList<Bundle> bundlesTwo = (ArrayList<Bundle>) valueTwo;
+                if (bundlesOne.size() != bundlesTwo.size()) {
+                    return false;
+                }
+                for (int i = 0; i < bundlesOne.size(); i++) {
+                    if (!bundleEquals(bundlesOne.get(i), bundlesTwo.get(i))) {
+                        return false;
+                    }
+                }
+            } else if (valueOne instanceof Object[]) {
+                if (!(valueTwo instanceof Object[])
+                        || !Arrays.equals((Object[]) valueOne, (Object[]) valueTwo)) {
+                    return false;
+                }
+            }
+        }
+        return true;
     }
 
     @Override
     public int hashCode() {
-        // Hash only proto is sufficient here since all properties in mProperties are ordered by
-        // keys and stored in proto.
-        return mProto.hashCode();
+        if (mHashCode == null) {
+            mHashCode = bundleHashCode(mBundle);
+        }
+        return mHashCode;
+    }
+
+    /**
+     * Calculates the hash code for a bundle.
+     * <p> The hash code is only effected by the content in the bundle. Bundles will get
+     * consistent hash code if they have same content.
+     */
+    @SuppressWarnings("unchecked")
+    private static int bundleHashCode(Bundle bundle) {
+        int[] hashCodes = new int[bundle.size()];
+        int i = 0;
+        // Bundle inherit its hashCode() from Object.java, which only relative to their memory
+        // address. Bundle doesn't have an order, so we should iterate all keys and combine
+        // their value's hashcode into an array. And use the hashcode of the array to be
+        // the hashcode of the bundle.
+        for (String key : bundle.keySet()) {
+            Object value = bundle.get(key);
+            if (value instanceof boolean[]) {
+                hashCodes[i++] = Arrays.hashCode((boolean[]) value);
+            } else if (value instanceof long[]) {
+                hashCodes[i++] = Arrays.hashCode((long[]) value);
+            } else if (value instanceof double[]) {
+                hashCodes[i++] = Arrays.hashCode((double[]) value);
+            } else if (value instanceof String[]) {
+                hashCodes[i++] = Arrays.hashCode((Object[]) value);
+            } else if (value instanceof Bundle) {
+                hashCodes[i++] = bundleHashCode((Bundle) value);
+            } else if (value instanceof Bundle[]) {
+                Bundle[] bundles = (Bundle[]) value;
+                int[] innerHashCodes = new int[bundles.length];
+                for (int j = 0; j < innerHashCodes.length; j++) {
+                    innerHashCodes[j] = bundleHashCode(bundles[j]);
+                }
+                hashCodes[i++] = Arrays.hashCode(innerHashCodes);
+            } else if (value instanceof ArrayList) {
+                ArrayList<Bundle> bundles = (ArrayList<Bundle>) value;
+                int[] innerHashCodes = new int[bundles.size()];
+                for (int j = 0; j < innerHashCodes.length; j++) {
+                    innerHashCodes[j] = bundleHashCode(bundles.get(j));
+                }
+                hashCodes[i++] = Arrays.hashCode(innerHashCodes);
+            } else {
+                hashCodes[i++] = value.hashCode();
+            }
+        }
+        return Arrays.hashCode(hashCodes);
     }
 
     @Override
     @NonNull
     public String toString() {
-        return mProto.toString();
+        return bundleToString(mBundle).toString();
+    }
+
+    @SuppressWarnings("unchecked")
+    private static StringBuilder bundleToString(Bundle bundle) {
+        StringBuilder stringBuilder = new StringBuilder();
+        try {
+            final Set<String> keySet = bundle.keySet();
+            String[] keys = keySet.toArray(new String[0]);
+            // Sort keys to make output deterministic. We need a custom comparator to handle
+            // nulls (arbitrarily putting them first, similar to Comparator.nullsFirst, which is
+            // only available since N).
+            Arrays.sort(
+                    keys,
+                    (@Nullable String s1, @Nullable String s2) -> {
+                        if (s1 == null) {
+                            return s2 == null ? 0 : -1;
+                        } else if (s2 == null) {
+                            return 1;
+                        } else {
+                            return s1.compareTo(s2);
+                        }
+                    });
+            for (String key : keys) {
+                stringBuilder.append("{ key: '").append(key).append("' value: ");
+                Object valueObject = bundle.get(key);
+                if (valueObject == null) {
+                    stringBuilder.append("<null>");
+                } else if (valueObject instanceof Bundle) {
+                    stringBuilder.append(bundleToString((Bundle) valueObject));
+                } else if (valueObject.getClass().isArray()) {
+                    stringBuilder.append("[ ");
+                    for (int i = 0; i < Array.getLength(valueObject); i++) {
+                        Object element = Array.get(valueObject, i);
+                        stringBuilder.append("'");
+                        if (element instanceof Bundle) {
+                            stringBuilder.append(bundleToString((Bundle) element));
+                        } else {
+                            stringBuilder.append(Array.get(valueObject, i));
+                        }
+                        stringBuilder.append("' ");
+                    }
+                    stringBuilder.append("]");
+                } else if (valueObject instanceof ArrayList) {
+                    for (Bundle innerBundle : (ArrayList<Bundle>) valueObject) {
+                        stringBuilder.append(bundleToString(innerBundle));
+                    }
+                } else {
+                    stringBuilder.append(valueObject.toString());
+                }
+                stringBuilder.append(" } ");
+            }
+        } catch (RuntimeException e) {
+            // Catch any exceptions here since corrupt Bundles can throw different types of
+            // exceptions (e.g. b/38445840 & b/68937025).
+            stringBuilder.append("<error>");
+        }
+        return stringBuilder;
     }
 
     /**
@@ -481,8 +654,8 @@
      */
     public static class Builder<BuilderType extends Builder> {
 
-        private final Map<String, Object> mProperties = new ArrayMap<>();
-        private final DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder();
+        private final Bundle mProperties = new Bundle();
+        private final Bundle mBundle = new Bundle();
         private final BuilderType mBuilderTypeInstance;
         private boolean mBuilt = false;
 
@@ -502,10 +675,15 @@
             Preconditions.checkNotNull(uri);
             Preconditions.checkNotNull(schemaType);
             mBuilderTypeInstance = (BuilderType) this;
-            mProtoBuilder.setUri(uri).setSchema(schemaType);
-            mProtoBuilder.setNamespace(DEFAULT_NAMESPACE);
+            mBundle.putString(GenericDocument.URI_FIELD, uri);
+            mBundle.putString(GenericDocument.SCHEMA_TYPE_FIELD, schemaType);
+            mBundle.putString(GenericDocument.NAMESPACE_FIELD, DEFAULT_NAMESPACE);
             // Set current timestamp for creation timestamp by default.
-            setCreationTimestampMillis(System.currentTimeMillis());
+            mBundle.putLong(GenericDocument.CREATION_TIMESTAMP_MILLIS_FIELD,
+                    System.currentTimeMillis());
+            mBundle.putLong(GenericDocument.TTL_MILLIS_FIELD, DEFAULT_TTL_MILLIS);
+            mBundle.putInt(GenericDocument.SCORE_FIELD, DEFAULT_SCORE);
+            mBundle.putBundle(PROPERTIES_FIELD, mProperties);
         }
 
         /**
@@ -515,7 +693,7 @@
          */
         @NonNull
         public BuilderType setNamespace(@NonNull String namespace) {
-            mProtoBuilder.setNamespace(namespace);
+            mBundle.putString(GenericDocument.NAMESPACE_FIELD, namespace);
             return mBuilderTypeInstance;
         }
 
@@ -533,7 +711,7 @@
             if (score < 0) {
                 throw new IllegalArgumentException("Document score cannot be negative.");
             }
-            mProtoBuilder.setScore(score);
+            mBundle.putInt(GenericDocument.SCORE_FIELD, score);
             return mBuilderTypeInstance;
         }
 
@@ -544,7 +722,8 @@
         @NonNull
         public BuilderType setCreationTimestampMillis(long creationTimestampMillis) {
             Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mProtoBuilder.setCreationTimestampMs(creationTimestampMillis);
+            mBundle.putLong(GenericDocument.CREATION_TIMESTAMP_MILLIS_FIELD,
+                    creationTimestampMillis);
             return mBuilderTypeInstance;
         }
 
@@ -563,7 +742,7 @@
             if (ttlMillis < 0) {
                 throw new IllegalArgumentException("Document ttlMillis cannot be negative.");
             }
-            mProtoBuilder.setTtlMs(ttlMillis);
+            mBundle.putLong(GenericDocument.TTL_MILLIS_FIELD, ttlMillis);
             return mBuilderTypeInstance;
         }
 
@@ -579,7 +758,7 @@
             Preconditions.checkState(!mBuilt, "Builder has already been used");
             Preconditions.checkNotNull(key);
             Preconditions.checkNotNull(values);
-            putInPropertyMap(key, values);
+            putInPropertyBundle(key, values);
             return mBuilderTypeInstance;
         }
 
@@ -595,7 +774,7 @@
             Preconditions.checkState(!mBuilt, "Builder has already been used");
             Preconditions.checkNotNull(key);
             Preconditions.checkNotNull(values);
-            putInPropertyMap(key, values);
+            putInPropertyBundle(key, values);
             return mBuilderTypeInstance;
         }
 
@@ -611,7 +790,7 @@
             Preconditions.checkState(!mBuilt, "Builder has already been used");
             Preconditions.checkNotNull(key);
             Preconditions.checkNotNull(values);
-            putInPropertyMap(key, values);
+            putInPropertyBundle(key, values);
             return mBuilderTypeInstance;
         }
 
@@ -627,7 +806,7 @@
             Preconditions.checkState(!mBuilt, "Builder has already been used");
             Preconditions.checkNotNull(key);
             Preconditions.checkNotNull(values);
-            putInPropertyMap(key, values);
+            putInPropertyBundle(key, values);
             return mBuilderTypeInstance;
         }
 
@@ -642,7 +821,7 @@
             Preconditions.checkState(!mBuilt, "Builder has already been used");
             Preconditions.checkNotNull(key);
             Preconditions.checkNotNull(values);
-            putInPropertyMap(key, values);
+            putInPropertyBundle(key, values);
             return mBuilderTypeInstance;
         }
 
@@ -658,11 +837,11 @@
             Preconditions.checkState(!mBuilt, "Builder has already been used");
             Preconditions.checkNotNull(key);
             Preconditions.checkNotNull(values);
-            putInPropertyMap(key, values);
+            putInPropertyBundle(key, values);
             return mBuilderTypeInstance;
         }
 
-        private void putInPropertyMap(@NonNull String key, @NonNull String[] values)
+        private void putInPropertyBundle(@NonNull String key, @NonNull String[] values)
                 throws IllegalArgumentException {
             validateRepeatedPropertyLength(key, values.length);
             for (int i = 0; i < values.length; i++) {
@@ -674,37 +853,54 @@
                             + MAX_STRING_LENGTH + ".");
                 }
             }
-            mProperties.put(key, values);
+            mProperties.putStringArray(key, values);
         }
 
-        private void putInPropertyMap(@NonNull String key, @NonNull boolean[] values) {
+        private void putInPropertyBundle(@NonNull String key, @NonNull boolean[] values) {
             validateRepeatedPropertyLength(key, values.length);
-            mProperties.put(key, values);
+            mProperties.putBooleanArray(key, values);
         }
 
-        private void putInPropertyMap(@NonNull String key, @NonNull double[] values) {
+        private void putInPropertyBundle(@NonNull String key, @NonNull double[] values) {
             validateRepeatedPropertyLength(key, values.length);
-            mProperties.put(key, values);
+            mProperties.putDoubleArray(key, values);
         }
 
-        private void putInPropertyMap(@NonNull String key, @NonNull long[] values) {
+        private void putInPropertyBundle(@NonNull String key, @NonNull long[] values) {
             validateRepeatedPropertyLength(key, values.length);
-            mProperties.put(key, values);
+            mProperties.putLongArray(key, values);
         }
 
-        private void putInPropertyMap(@NonNull String key, @NonNull byte[][] values) {
+        /**
+         * Converts and saves a byte[][] into {@link #mProperties}.
+         *
+         * <p>Bundle doesn't support for two dimension array byte[][], we are converting byte[][]
+         * into ArrayList<Bundle>, and each elements will contain a one dimension byte[].
+         */
+        private void putInPropertyBundle(@NonNull String key, @NonNull byte[][] values) {
             validateRepeatedPropertyLength(key, values.length);
-            mProperties.put(key, values);
+            ArrayList<Bundle> bundles = new ArrayList<>(values.length);
+            for (int i = 0; i < values.length; i++) {
+                if (values[i] == null) {
+                    throw new IllegalArgumentException("The byte[] at " + i + " is null.");
+                }
+                Bundle bundle = new Bundle();
+                bundle.putByteArray(BYTE_ARRAY_FIELD, values[i]);
+                bundles.add(bundle);
+            }
+            mProperties.putParcelableArrayList(key, bundles);
         }
 
-        private void putInPropertyMap(@NonNull String key, @NonNull GenericDocument[] values) {
+        private void putInPropertyBundle(@NonNull String key, @NonNull GenericDocument[] values) {
+            validateRepeatedPropertyLength(key, values.length);
+            Bundle[] documentBundles = new Bundle[values.length];
             for (int i = 0; i < values.length; i++) {
                 if (values[i] == null) {
                     throw new IllegalArgumentException("The document at " + i + " is null.");
                 }
+                documentBundles[i] = values[i].mBundle;
             }
-            validateRepeatedPropertyLength(key, values.length);
-            mProperties.put(key, values);
+            mProperties.putParcelableArray(key, documentBundles);
         }
 
         private static void validateRepeatedPropertyLength(@NonNull String key, int length) {
@@ -722,48 +918,8 @@
         @NonNull
         public GenericDocument build() {
             Preconditions.checkState(!mBuilt, "Builder has already been used");
-            // Build proto by sorting the keys in mProperties to exclude the influence of
-            // order. Therefore documents will generate same proto as long as the contents are
-            // same. Note that the order of repeated fields is still preserved.
-            ArrayList<String> keys = new ArrayList<>(mProperties.keySet());
-            Collections.sort(keys);
-            for (int i = 0; i < keys.size(); i++) {
-                String name = keys.get(i);
-                Object values = mProperties.get(name);
-                PropertyProto.Builder propertyProto = PropertyProto.newBuilder().setName(name);
-                if (values instanceof boolean[]) {
-                    for (boolean value : (boolean[]) values) {
-                        propertyProto.addBooleanValues(value);
-                    }
-                } else if (values instanceof long[]) {
-                    for (long value : (long[]) values) {
-                        propertyProto.addInt64Values(value);
-                    }
-                } else if (values instanceof double[]) {
-                    for (double value : (double[]) values) {
-                        propertyProto.addDoubleValues(value);
-                    }
-                } else if (values instanceof String[]) {
-                    for (String value : (String[]) values) {
-                        propertyProto.addStringValues(value);
-                    }
-                } else if (values instanceof GenericDocument[]) {
-                    for (GenericDocument value : (GenericDocument[]) values) {
-                        propertyProto.addDocumentValues(value.getProto());
-                    }
-                } else if (values instanceof byte[][]) {
-                    for (byte[] value : (byte[][]) values) {
-                        propertyProto.addBytesValues(ByteString.copyFrom(value));
-                    }
-                } else {
-                    throw new IllegalStateException(
-                            "Property \"" + name + "\" has unsupported value type \""
-                                    + values.getClass().getSimpleName() + "\"");
-                }
-                mProtoBuilder.addProperties(propertyProto);
-            }
             mBuilt = true;
-            return new GenericDocument(mProtoBuilder.build(), mProperties);
+            return new GenericDocument(mBundle);
         }
     }
 }
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/MatchInfo.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/MatchInfo.java
index 97acf36..bdc79f1 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/MatchInfo.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/MatchInfo.java
@@ -66,9 +66,7 @@
  * <p>{@link MatchInfo#getExactMatch()} returns "TestNameJr@gmail.com"
  * <p>{@link MatchInfo#getSnippetPosition()} returns [0, 20]
  * <p>{@link MatchInfo#getSnippet()} returns "TestNameJr@gmail.com"
- * @hide
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 // TODO(sidchhabra): Capture real snippet after integration with icingLib.
 public final class MatchInfo {
     // The path of the matching snippet property.
@@ -87,6 +85,7 @@
     private MatchRange mExactMatchRange;
     private MatchRange mWindowRange;
 
+
     MatchInfo(@NonNull Bundle bundle, @NonNull GenericDocument document) {
         mBundle = Preconditions.checkNotNull(bundle);
         Preconditions.checkNotNull(document);
@@ -173,7 +172,7 @@
 
     private CharSequence getSubstring(MatchRange range) {
         return getFullText()
-                .substring(range.getLower(), range.getUpper());
+                .substring(range.getStart(), range.getEnd());
     }
 
     /** Extracts the matching string from the document. */
@@ -200,33 +199,36 @@
      *
      */
     public static class MatchRange{
-        private final int mUpper;
-        private final int mLower;
+        private final int mEnd;
+        private final int mStart;
 
         /**
          * Creates a new immutable range.
-         * <p> The endpoints are {@code [lower, upper)}; that is the range is bounded. {@code lower}
-         * must be lesser or equal to {@code upper}.
+         * <p> The endpoints are {@code [start, end)}; that is the range is bounded. {@code start}
+         * must be lesser or equal to {@code end}.
          *
-         * @param lower The lower endpoint (inclusive)
-         * @param upper The upper endpoint (exclusive)
+         * @param start The start point (inclusive)
+         * @param end The end point (exclusive)
+         * @hide
          */
-        public MatchRange(int lower, int upper) {
-            if (lower > upper) {
-                throw new IllegalArgumentException("lower must be less than or equal to upper");
+        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+        public MatchRange(int start, int end) {
+            if (start > end) {
+                throw new IllegalArgumentException("Start point must be less than or equal to "
+                        + "end point");
             }
-            mLower = lower;
-            mUpper = upper;
+            mStart = start;
+            mEnd = end;
         }
 
-        /** Gets the lower endpoint (inclusive). */
-        public int getLower() {
-            return mLower;
+        /** Gets the start point (inclusive). */
+        public int getStart() {
+            return mStart;
         }
 
-        /** Gets the upper endpoint (exclusive). */
-        public int getUpper() {
-            return mUpper;
+        /** Gets the end point (exclusive). */
+        public int getEnd() {
+            return mEnd;
         }
 
         @Override
@@ -238,19 +240,19 @@
                 return false;
             }
             MatchRange otherMatchRange = (MatchRange) other;
-            return this.getLower() == otherMatchRange.getLower()
-                    && this.getUpper() == otherMatchRange.getUpper();
+            return this.getStart() == otherMatchRange.getStart()
+                    && this.getEnd() == otherMatchRange.getEnd();
         }
 
         @Override
         @NonNull
         public String toString() {
-            return "MatchRange { lower: " + mLower + " , upper: " + mUpper + "}";
+            return "MatchRange { start: " + mStart + " , end: " + mEnd + "}";
         }
 
         @Override
         public int hashCode() {
-            return ObjectsCompat.hash(mLower, mUpper);
+            return ObjectsCompat.hash(mStart, mEnd);
         }
     }
 
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResults.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResults.java
index e055395..24dd6ad 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResults.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchResults.java
@@ -20,7 +20,6 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
 import androidx.concurrent.futures.ResolvableFuture;
 
 import com.google.common.util.concurrent.ListenableFuture;
@@ -37,15 +36,14 @@
  * request.
  * <p>Should close this object after finish fetching results.
  * <p>This class is not thread safe.
- * @hide
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public final class SearchResults implements Closeable {
 
     private static final String TAG = "AppSearch-SearchResults";
     private final ExecutorService mExecutorService;
     private final AppSearchBackend.BackendSearchResults mBackendSearchResults;
 
+    /** @hide */
     public SearchResults(@NonNull ExecutorService executorService,
             @NonNull AppSearchBackend.BackendSearchResults backendSearchResults)  {
         mExecutorService = executorService;
@@ -97,17 +95,17 @@
 
         /**
          * Contains a list of Snippets that matched the request. Only populated when requested in
-         * both {@link SearchSpec.Builder#setNumToSnippet}
-         * and {@link SearchSpec.Builder#setNumMatchesPerProperty}.
+         * both {@link SearchSpec.Builder#setSnippetCount(int)}
+         * and {@link SearchSpec.Builder#setSnippetCountPerProperty(int)}.
          *
-         * @see #getMatchInfo()
+         * @see #getMatches()
          */
         @Nullable
-        private final List<MatchInfo> mMatchInfos;
+        private final List<MatchInfo> mMatches;
 
-        Result(@NonNull GenericDocument document, @Nullable List<MatchInfo> matchInfos) {
+        Result(@NonNull GenericDocument document, @Nullable List<MatchInfo> matches) {
             mDocument = document;
-            mMatchInfos = matchInfos;
+            mMatches = matches;
         }
 
         /**
@@ -121,18 +119,18 @@
 
         /**
          * Contains a list of Snippets that matched the request. Only populated when requested in
-         * both {@link SearchSpec.Builder#setNumToSnippet}
-         * and {@link SearchSpec.Builder#setNumMatchesPerProperty}.
+         * both {@link SearchSpec.Builder#setSnippetCount(int)}
+         * and {@link SearchSpec.Builder#setSnippetCountPerProperty(int)}.
          *
          * @return  List of matches based on {@link SearchSpec}, if snippeting is disabled and this
          * method is called it will return {@code null}. Users can also restrict snippet population
-         * using {@link SearchSpec.Builder#setNumToSnippet} and
-         * {@link SearchSpec.Builder#setNumMatchesPerProperty}, for all results after that value
-         * this method will return {@code null}.
+         * using {@link SearchSpec.Builder#setSnippetCount} and
+         * {@link SearchSpec.Builder#setSnippetCountPerProperty(int)}, for all results after that
+         * value this method will return {@code null}.
          */
         @Nullable
-        public List<MatchInfo> getMatchInfo() {
-            return mMatchInfos;
+        public List<MatchInfo> getMatches() {
+            return mMatches;
         }
     }
 }
diff --git a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSpec.java b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSpec.java
index 269af4b..a5cf9a2 100644
--- a/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSpec.java
+++ b/appsearch/appsearch/src/main/java/androidx/appsearch/app/SearchSpec.java
@@ -20,7 +20,6 @@
 
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
 import androidx.appsearch.exceptions.IllegalSearchSpecException;
 import androidx.core.util.Preconditions;
 
@@ -30,9 +29,7 @@
 /**
  * This class represents the specification logic for AppSearch. It can be used to set the type of
  * search, like prefix or exact only or apply filters to search for a specific schema type only etc.
- * @hide
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 // TODO(sidchhabra) : AddResultSpec fields for Snippets etc.
 public final class SearchSpec {
 
@@ -42,10 +39,14 @@
     static final String NUM_PER_PAGE_FIELD = "numPerPage";
     static final String RANKING_STRATEGY_FIELD = "rankingStrategy";
     static final String ORDER_FILED = "order";
-    static final String NUM_TO_SNIPPET_FIELD = "numToSnippet";
-    static final String NUM_MATCHED_PER_PROPERTY_FIELD = "numMatchedPerProperty";
+    static final String SNIPPET_COUNT_FIELD = "snippetCount";
+    static final String SNIPPET_COUNT_PER_PROPERTY_FIELD = "snippetCountPerProperty";
     static final String MAX_SNIPPET_FIELD = "maxSnippet";
     static final int DEFAULT_NUM_PER_PAGE = 10;
+    private static final int MAX_NUM_PER_PAGE = 10_000;
+    private static final int MAX_SNIPPET_COUNT = 10_000;
+    private static final int MAX_SNIPPET_PER_PROPERTY_COUNT = 10_000;
+    private static final int MAX_SNIPPET_SIZE_LIMIT = 10_000;
 
     private final Bundle mBundle;
 
@@ -60,28 +61,34 @@
         return mBundle;
     }
 
-    /** Term Match Type for the query. */
+    /**
+     * Term Match Type for the query.
+     * @hide
+     */
     // NOTE: The integer values of these constants must match the proto enum constants in
     // {@link com.google.android.icing.proto.SearchSpecProto.termMatchType}
     @IntDef(value = {
-            TERM_MATCH_TYPE_EXACT_ONLY,
-            TERM_MATCH_TYPE_PREFIX
+            TERM_MATCH_EXACT_ONLY,
+            TERM_MATCH_PREFIX
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface TermMatchTypeCode {}
+    public @interface TermMatchCode {}
 
     /**
      * Query terms will only match exact tokens in the index.
      * <p>Ex. A query term "foo" will only match indexed token "foo", and not "foot" or "football".
      */
-    public static final int TERM_MATCH_TYPE_EXACT_ONLY = 1;
+    public static final int TERM_MATCH_EXACT_ONLY = 1;
     /**
      * Query terms will match indexed tokens when the query term is a prefix of the token.
      * <p>Ex. A query term "foo" will match indexed tokens like "foo", "foot", and "football".
      */
-    public static final int TERM_MATCH_TYPE_PREFIX = 2;
+    public static final int TERM_MATCH_PREFIX = 2;
 
-    /** Ranking Strategy for query result.*/
+    /**
+     * Ranking Strategy for query result.
+     * @hide
+     */
     // NOTE: The integer values of these constants must match the proto enum constants in
     // {@link ScoringSpecProto.RankingStrategy.Code }
     @IntDef(value = {
@@ -99,7 +106,10 @@
     /** Ranked by document creation timestamps. */
     public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2;
 
-    /** Order for query result.*/
+    /**
+     * Order for query result.
+     * @hide
+     */
     // NOTE: The integer values of these constants must match the proto enum constants in
     // {@link ScoringSpecProto.Order.Code }
     @IntDef(value = {
@@ -127,13 +137,13 @@
         }
 
         /**
-         * Indicates how the query terms should match {@link TermMatchTypeCode} in the index.
+         * Indicates how the query terms should match {@code TermMatchCode} in the index.
          */
         @NonNull
-        public Builder setTermMatchType(@TermMatchTypeCode int termMatchTypeCode) {
+        public Builder setTermMatch(@TermMatchCode int termMatchTypeCode) {
             Preconditions.checkState(!mBuilt, "Builder has already been used");
-            Preconditions.checkArgumentInRange(termMatchTypeCode, TERM_MATCH_TYPE_EXACT_ONLY,
-                    TERM_MATCH_TYPE_PREFIX, "Term match type");
+            Preconditions.checkArgumentInRange(termMatchTypeCode, TERM_MATCH_EXACT_ONLY,
+                    TERM_MATCH_PREFIX, "Term match type");
             mBundle.putInt(TERM_MATCH_TYPE_FIELD, termMatchTypeCode);
             return this;
         }
@@ -166,14 +176,12 @@
 
         /**
          * Sets the number of results per page in the returned object.
-         * <p> The default number of results per page is 10.
+         * <p> The default number of results per page is 10. And should be set in range [0, 10k].
          */
         @NonNull
         public SearchSpec.Builder setNumPerPage(int numPerPage) {
             Preconditions.checkState(!mBuilt, "Builder has already been used");
-            if (numPerPage <= 0) {
-                throw new IllegalArgumentException("Invalid number per page :" + numPerPage);
-            }
+            Preconditions.checkArgumentInRange(numPerPage, 0, MAX_NUM_PER_PAGE, "NumPerPage");
             mBundle.putInt(NUM_PER_PAGE_FIELD, numPerPage);
             return this;
         }
@@ -203,28 +211,33 @@
         }
 
         /**
-         * Only the first {@code numToSnippet} documents based on the ranking strategy
+         * Only the first {@code snippetCount} documents based on the ranking strategy
          * will have snippet information provided.
          * <p>If set to 0 (default), snippeting is disabled and
-         * {@link SearchResults.Result#getMatchInfo} will return {@code null} for that result.
+         * {@link SearchResults.Result#getMatches} will return {@code null} for that result.
+         * <p>The value should be set in range[0, 10k].
          */
         @NonNull
-        public SearchSpec.Builder setNumToSnippet(int numToSnippet) {
+        public SearchSpec.Builder setSnippetCount(int snippetCount) {
             Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBundle.putInt(NUM_TO_SNIPPET_FIELD, numToSnippet);
+            Preconditions.checkArgumentInRange(snippetCount, 0, MAX_SNIPPET_COUNT, "snippetCount");
+            mBundle.putInt(SNIPPET_COUNT_FIELD, snippetCount);
             return this;
         }
 
         /**
-         * Only the first {@code numMatchesPerProperty} matches for a every property of
+         * Only the first {@code matchesCountPerProperty} matches for a every property of
          * {@link GenericDocument} will contain snippet information.
-         * <p>If set to 0, snippeting is disabled and {@link SearchResults.Result#getMatchInfo}
+         * <p>If set to 0, snippeting is disabled and {@link SearchResults.Result#getMatches}
          * will return {@code null} for that result.
+         * <p>The value should be set in range[0, 10k].
          */
         @NonNull
-        public SearchSpec.Builder setNumMatchesPerProperty(int numMatchesPerProperty) {
+        public SearchSpec.Builder setSnippetCountPerProperty(int snippetCountPerProperty) {
             Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBundle.putInt(NUM_MATCHED_PER_PROPERTY_FIELD, numMatchesPerProperty);
+            Preconditions.checkArgumentInRange(snippetCountPerProperty,
+                    0, MAX_SNIPPET_PER_PROPERTY_COUNT, "snippetCountPerProperty");
+            mBundle.putInt(SNIPPET_COUNT_PER_PROPERTY_FIELD, snippetCountPerProperty);
             return this;
         }
 
@@ -237,10 +250,13 @@
          * be returned. If matches enabled is also set to false, then snippeting is disabled.
          * <p>Ex. {@code maxSnippetSize} = 16. "foo bar baz bat rat" with a query of "baz" will
          * return a window of "bar baz bat" which is only 11 bytes long.
+         * <p>The value should be in range[0, 10k].
          */
         @NonNull
         public SearchSpec.Builder setMaxSnippetSize(int maxSnippetSize) {
             Preconditions.checkState(!mBuilt, "Builder has already been used");
+            Preconditions.checkArgumentInRange(
+                    maxSnippetSize, 0, MAX_SNIPPET_SIZE_LIMIT, "maxSnippetSize");
             mBundle.putInt(MAX_SNIPPET_FIELD, maxSnippetSize);
             return this;
         }
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java
index a71e334..9ee924a 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/CodeGenerator.java
@@ -72,8 +72,26 @@
         JavaFile.builder(mOutputPackage, mOutputClass).build().writeTo(folder);
     }
 
+    /**
+     * Creates factory class for any class annotated with
+     * {@link androidx.appsearch.annotation.AppSearchDocument}
+     * <p>Class Example 1:
+     *   For a class Foo annotated with @AppSearchDocument, we will generated a
+     *   $$__AppSearch__Foo.class under the output package.
+     * <p>Class Example 2:
+     *   For an inner class Foo.Bar annotated with @AppSearchDocument, we will generated a
+     *   $$__AppSearch__Foo$$__Bar.class under the output package.
+     */
     private TypeSpec createClass() throws ProcessingException {
-        String genClassName = GEN_CLASS_PREFIX + mModel.getClassElement().getSimpleName();
+        // Gets the full name of target class.
+        String qualifiedName = mModel.getClassElement().getQualifiedName().toString();
+        String packageName = mOutputPackage + ".";
+
+        // Creates the name of output class. $$__AppSearch__Foo for Foo, $$__AppSearch__Foo$$__Bar
+        // for inner class Foo.Bar.
+        String genClassName = GEN_CLASS_PREFIX
+                + qualifiedName.substring(packageName.length()).replace(".", "$$__");
+
         TypeName genClassType = TypeName.get(mModel.getClassElement().asType());
         TypeName factoryType = ParameterizedTypeName.get(
                 mHelper.getAppSearchClass("DataClassFactory"),
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java
index 91834ab..ec15c21 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/FromGenericDocumentCodeGenerator.java
@@ -32,6 +32,7 @@
 import java.util.Map;
 
 import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
 import javax.lang.model.element.Modifier;
 import javax.lang.model.element.VariableElement;
 import javax.lang.model.type.ArrayType;
@@ -74,7 +75,8 @@
                 .addModifiers(Modifier.PUBLIC)
                 .returns(classType)
                 .addAnnotation(Override.class)
-                .addParameter(mHelper.getAppSearchClass("GenericDocument"), "genericDoc");
+                .addParameter(mHelper.getAppSearchClass("GenericDocument"), "genericDoc")
+                .addException(mHelper.getAppSearchExceptionClass());
 
         unpackSpecialFields(methodBuilder);
 
@@ -115,8 +117,7 @@
         //       unboxing.
         //
         //   1b: ListCallArraysAsList
-        //       List contains String or GenericDocument.
-        //       We have to convert this from an array of String[] or GenericDocument[], but no
+        //       List contains String. We have to convert this from an array of String[], but no
         //       conversion of the collection elements is needed. We can use Arrays#asList for this.
         //
         //   1c: ListForLoopCallFromGenericDocument
@@ -138,8 +139,7 @@
         //       of unboxing.
         //
         //   2b: ArrayUseDirectly
-        //       Array is of type String[], long[], double[], boolean[], byte[][] or
-        //       GenericDocument[].
+        //       Array is of type String[], long[], double[], boolean[], byte[][].
         //       We can directly use this field with no conversion.
         //
         //   2c: ArrayForLoopCallFromGenericDocument
@@ -156,8 +156,7 @@
 
         // Scenario 3: Single valued fields
         //   3a: FieldUseDirectlyWithNullCheck
-        //       Field is of type String, Long, Integer, Double, Float, Boolean, byte[] or
-        //       GenericDocument.
+        //       Field is of type String, Long, Integer, Double, Float, Boolean, byte[].
         //       We can use this field directly, after testing for null. The java compiler will box
         //       or unbox as needed.
         //
@@ -201,12 +200,15 @@
         List<? extends TypeMirror> genericTypes =
                 ((DeclaredType) property.asType()).getTypeArguments();
         TypeMirror propertyType = genericTypes.get(0);
+        ParameterizedTypeName listTypeName = ParameterizedTypeName.get(ClassName.get(List.class),
+                TypeName.get(propertyType));
 
-        // TODO(b/156296904): Handle scenario 1c (ListForLoopCallFromGenericDocument)
         CodeBlock.Builder builder = CodeBlock.builder();
-        if (!tryListForLoopAssign(builder, fieldName, propertyName, propertyType)  // 1a
+        if (!tryListForLoopAssign(builder, fieldName, propertyName, propertyType, listTypeName)// 1a
                 && !tryListCallArraysAsList(
-                        builder, fieldName, propertyName, propertyType)) {  // 1b
+                        builder, fieldName, propertyName, propertyType, listTypeName)          // 1b
+                && !tryListForLoopCallFromGenericDocument(
+                        builder, fieldName, propertyName, propertyType, listTypeName)) {       // 1c
             // Scenario 1x
             throw new ProcessingException(
                     "Unhandled in property type (1x): " + property.asType().toString(), property);
@@ -225,7 +227,8 @@
             @NonNull CodeBlock.Builder method,
             @NonNull String fieldName,
             @NonNull String propertyName,
-            @NonNull TypeMirror propertyType) {
+            @NonNull TypeMirror propertyType,
+            @NonNull ParameterizedTypeName listTypeName) {
         Types typeUtil = mEnv.getTypeUtils();
         CodeBlock.Builder body = CodeBlock.builder();
 
@@ -259,9 +262,7 @@
 
         // Create the destination list
         body.addStatement(
-                "$T $NConv = null",
-                ParameterizedTypeName.get(ClassName.get(List.class), TypeName.get(propertyType)),
-                fieldName);
+                "$T $NConv = null", listTypeName, fieldName);
 
         // If not null, iterate and assign
         body
@@ -269,7 +270,7 @@
                 .addStatement(
                         "$NConv = new $T<>($NCopy.length)", fieldName, ArrayList.class, fieldName)
                 .add("for (int i = 0; i < $NCopy.length; i++) {\n", fieldName).indent()
-                .addStatement("$NConv.set(i, $NCopy[i])", fieldName, fieldName)
+                .addStatement("$NConv.add($NCopy[i])", fieldName, fieldName)
                 .unindent().add("}\n")
                 .unindent().add("}\n");
         method.add(body.build());
@@ -277,14 +278,14 @@
     }
 
     //   1b: ListCallArraysAsList
-    //       List contains String or GenericDocument.
-    //       We have to convert this from an array of String[] or GenericDocument[], but no
+    //       List contains String. We have to convert this from an array of String[], but no
     //       conversion of the collection elements is needed. We can use Arrays#asList for this.
     private boolean tryListCallArraysAsList(
             @NonNull CodeBlock.Builder method,
             @NonNull String fieldName,
             @NonNull String propertyName,
-            @NonNull TypeMirror propertyType) {
+            @NonNull TypeMirror propertyType,
+            @NonNull ParameterizedTypeName listTypeName) {
         Types typeUtil = mEnv.getTypeUtils();
         CodeBlock.Builder body = CodeBlock.builder();
 
@@ -293,20 +294,13 @@
                     "String[] $NCopy = genericDoc.getPropertyStringArray($S)",
                     fieldName, propertyName);
 
-        } else if (typeUtil.isSameType(propertyType, mHelper.mGenericDocumentType)) {
-            body.addStatement(
-                    "GenericDocument[] $NCopy = genericDoc.getPropertyDocumentArray($S)",
-                    fieldName, propertyName);
         } else {
             // This is not a type 1b list.
             return false;
         }
 
         // Create the destination list
-        body.addStatement(
-                "$T $NConv = null",
-                ParameterizedTypeName.get(ClassName.get(List.class), TypeName.get(propertyType)),
-                fieldName);
+        body.addStatement("$T $NConv = null", listTypeName, fieldName);
 
         // If not null, iterate and assign
         body
@@ -318,6 +312,59 @@
         return true;
     }
 
+    //   1c: ListForLoopCallFromGenericDocument
+    //       List contains a class which is annotated with @AppSearchDocument.
+    //       We have to convert this from an array of GenericDocument[], by reading each element
+    //       one-by-one and converting it through the standard conversion machinery.
+    private boolean tryListForLoopCallFromGenericDocument(
+            @NonNull CodeBlock.Builder method,
+            @NonNull String fieldName,
+            @NonNull String propertyName,
+            @NonNull TypeMirror propertyType,
+            @NonNull ParameterizedTypeName listTypeName)  {
+        Types typeUtil = mEnv.getTypeUtils();
+        CodeBlock.Builder body = CodeBlock.builder();
+
+        Element element = typeUtil.asElement(propertyType);
+        if (element == null) {
+            // The propertyType is not an element, this is not a type 1c list.
+            return false;
+        }
+        try {
+            mHelper.getAnnotation(element, IntrospectionHelper.APP_SEARCH_DOCUMENT_CLASS);
+        } catch (ProcessingException e) {
+            // The propertyType doesn't have @AppSearchDocument annotation, this is not a type 1c
+            // list.
+            return false;
+        }
+
+        body.addStatement(
+                "GenericDocument[] $NCopy = genericDoc.getPropertyDocumentArray($S)",
+                fieldName, propertyName);
+
+        // Create the destination list
+        body.addStatement("$T $NConv = null", listTypeName, fieldName);
+
+        // If not null, iterate and assign
+        body.add("if ($NCopy != null) {\n", fieldName).indent();
+        body.addStatement("$T factory = $T.getInstance().getOrCreateFactory($T.class)",
+                ParameterizedTypeName.get(mHelper.getAppSearchClass("DataClassFactory"),
+                        TypeName.get(propertyType)),
+                mHelper.getAppSearchClass("DataClassFactoryRegistry"), propertyType);
+        body.addStatement("$NConv = new $T<>($NCopy.length)", fieldName, ArrayList.class,
+                fieldName);
+
+        body.add("for (int i = 0; i < $NCopy.length; i++) {\n", fieldName).indent();
+        body.addStatement("$NConv.add(factory.fromGenericDocument($NCopy[i]))", fieldName,
+                fieldName);
+        body.unindent().add("}\n");
+
+        body.unindent().add("}\n");  //  if ($NCopy != null) {
+        method.add(body.build());
+
+        return true;
+    }
+
     /**
      * If the given field is an array, generates code to read it from a repeated GenericDocument
      * property and returns true. If the field is not an array, returns false.
@@ -386,7 +433,7 @@
 
         } else if (typeUtil.isSameType(propertyType, mHelper.mByteBoxType)) {
             body.addStatement(
-                    "byte[][] $NCopy = genericDoc.getPropertyBytesArray($S)",
+                    "byte[] $NCopy = genericDoc.getPropertyBytes($S)",
                     fieldName, propertyName);
 
         } else {
@@ -411,8 +458,7 @@
     }
 
     //   2b: ArrayUseDirectly
-    //       Array is of type String[], long[], double[], boolean[], byte[][] or
-    //       GenericDocument[].
+    //       Array is of type String[], long[], double[], boolean[], byte[][].
     //       We can directly use this field with no conversion.
     private boolean tryArrayUseDirectly(
             @NonNull CodeBlock.Builder method,
@@ -448,11 +494,6 @@
                     "byte[][] $NConv = genericDoc.getPropertyBytesArray($S)",
                     fieldName, propertyName);
 
-        } else if (typeUtil.isSameType(propertyType, mHelper.mGenericDocumentType)) {
-            body.addStatement(
-                    "GenericDocument[] $NConv = genericDoc.getPropertyDocumentArray($S)",
-                    fieldName, propertyName);
-
         } else {
             // This is not a type 2b array.
             return false;
@@ -485,8 +526,7 @@
     }
 
     //   3a: FieldUseDirectlyWithNullCheck
-    //       Field is of type String, Long, Integer, Double, Float, Boolean, byte[] or
-    //       GenericDocument.
+    //       Field is of type String, Long, Integer, Double, Float, Boolean, byte[].
     //       We can use this field directly, after testing for null. The java compiler will box
     //       or unbox as needed.
     private boolean tryFieldUseDirectlyWithNullCheck(
@@ -527,11 +567,6 @@
                     "byte[][] $NCopy = genericDoc.getPropertyBytesArray($S)",
                     fieldName, propertyName);
 
-        } else if (typeUtil.isSameType(propertyType, mHelper.mGenericDocumentType)) {
-            body.addStatement(
-                    "GenericDocument[] $NCopy = genericDoc.getPropertyDocumentArray($S)",
-                    fieldName, propertyName);
-
         } else {
             // This is not a type 3a field
             return false;
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
index eb9061c..0488796 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/IntrospectionHelper.java
@@ -42,6 +42,8 @@
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 class IntrospectionHelper {
     static final String APPSEARCH_PKG = "androidx.appsearch.app";
+    static final String APPSEARCH_EXCEPTION_PKG = "androidx.appsearch.exceptions";
+    static final String APPSEARCH_EXCEPTION_SIMPLE_NAME = "AppSearchException";
     static final String APP_SEARCH_DOCUMENT_CLASS =
             "androidx.appsearch.annotation.AppSearchDocument";
     static final String URI_CLASS =
@@ -60,7 +62,6 @@
     final TypeMirror mCollectionType;
     final TypeMirror mListType;
     final TypeMirror mStringType;
-    final TypeMirror mGenericDocumentType;
     final TypeMirror mIntegerBoxType;
     final TypeMirror mIntPrimitiveType;
     final TypeMirror mLongBoxType;
@@ -85,8 +86,6 @@
         mCollectionType = elementUtil.getTypeElement(Collection.class.getName()).asType();
         mListType = elementUtil.getTypeElement(List.class.getName()).asType();
         mStringType = elementUtil.getTypeElement(String.class.getName()).asType();
-        mGenericDocumentType = elementUtil.getTypeElement(
-                getAppSearchClass("GenericDocument").toString()).asType();
         mIntegerBoxType = elementUtil.getTypeElement(Integer.class.getName()).asType();
         mIntPrimitiveType = typeUtil.unboxedType(mIntegerBoxType);
         mLongBoxType = elementUtil.getTypeElement(Long.class.getName()).asType();
@@ -128,4 +127,8 @@
     public ClassName getAppSearchClass(String clazz, String... nested) {
         return ClassName.get(APPSEARCH_PKG, clazz, nested);
     }
+
+    public ClassName getAppSearchExceptionClass() {
+        return ClassName.get(APPSEARCH_EXCEPTION_PKG, APPSEARCH_EXCEPTION_SIMPLE_NAME);
+    }
 }
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/SchemaCodeGenerator.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/SchemaCodeGenerator.java
index b7fc514..0af8dc1 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/SchemaCodeGenerator.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/SchemaCodeGenerator.java
@@ -65,12 +65,6 @@
                         .initializer("$S", mModel.getSchemaName())
                         .build());
 
-        classBuilder.addField(
-                FieldSpec.builder(mHelper.getAppSearchClass("AppSearchSchema"), "SCHEMA")
-                        .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
-                        .initializer(createSchemaInitializer())
-                        .build());
-
         classBuilder.addMethod(
                 MethodSpec.methodBuilder("getSchemaType")
                         .addModifiers(Modifier.PUBLIC)
@@ -84,7 +78,8 @@
                         .addModifiers(Modifier.PUBLIC)
                         .returns(mHelper.getAppSearchClass("AppSearchSchema"))
                         .addAnnotation(Override.class)
-                        .addStatement("return SCHEMA")
+                        .addException(mHelper.getAppSearchExceptionClass())
+                        .addStatement("return $L", createSchemaInitializer())
                         .build());
     }
 
@@ -172,6 +167,11 @@
         }
         codeBlock.add("\n.setDataType($T)", propertyTypeEnum);
 
+        if (isPropertyDocument) {
+            codeBlock.add("\n.setSchemaType($T.getInstance()"
+                    + ".getOrCreateFactory($T.class).getSchemaType())",
+                    mHelper.getAppSearchClass("DataClassFactoryRegistry"), propertyType);
+        }
         // Find property cardinality
         ClassName cardinalityEnum;
         if (repeated) {
diff --git a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/ToGenericDocumentCodeGenerator.java b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/ToGenericDocumentCodeGenerator.java
index acaf09e..a6de552 100644
--- a/appsearch/compiler/src/main/java/androidx/appsearch/compiler/ToGenericDocumentCodeGenerator.java
+++ b/appsearch/compiler/src/main/java/androidx/appsearch/compiler/ToGenericDocumentCodeGenerator.java
@@ -29,6 +29,7 @@
 import java.util.Map;
 
 import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
 import javax.lang.model.element.Modifier;
 import javax.lang.model.element.VariableElement;
 import javax.lang.model.type.ArrayType;
@@ -71,7 +72,8 @@
                 .addModifiers(Modifier.PUBLIC)
                 .returns(mHelper.getAppSearchClass("GenericDocument"))
                 .addAnnotation(Override.class)
-                .addParameter(classType, "dataClass");
+                .addParameter(classType, "dataClass")
+                .addException(mHelper.getAppSearchExceptionClass());
 
         // Construct a new GenericDocument.Builder with the schema type and URI
         methodBuilder.addStatement("$T builder =\nnew $T<>($L, SCHEMA_TYPE)",
@@ -204,10 +206,10 @@
                 ((DeclaredType) property.asType()).getTypeArguments();
         TypeMirror propertyType = genericTypes.get(0);
 
-        // TODO(b/156296904): Handle scenario 1c (CollectionForLoopCallToGenericDocument)
-        if (!tryCollectionForLoopAssign(body, fieldName, propertyName, propertyType)  // 1a
-                && !tryCollectionCallToArray(
-                        body, fieldName, propertyName, propertyType)) {  // 1b
+        if (!tryCollectionForLoopAssign(body, fieldName, propertyName, propertyType)           // 1a
+                && !tryCollectionCallToArray(body, fieldName, propertyName, propertyType)      // 1b
+                && !tryCollectionForLoopCallToGenericDocument(
+                        body, fieldName, propertyName, propertyType)) {                        // 1c
             // Scenario 1x
             throw new ProcessingException(
                     "Unhandled out property type (1x): " + property.asType().toString(), property);
@@ -270,8 +272,7 @@
     }
 
     //   1b: CollectionCallToArray
-    //       Collection contains String or GenericDocument.
-    //       We have to convert this into an array of String[] or GenericDocument[], but no
+    //       Collection contains String. We have to convert this into an array of String[] or but no
     //       conversion of the collection elements is needed. We can use Collection#toArray for
     //       this.
     private boolean tryCollectionCallToArray(
@@ -287,11 +288,6 @@
             body.addStatement(
                     "String[] $NConv = $NCopy.toArray(new String[0])", fieldName, fieldName);
 
-        } else if (typeUtil.isSameType(propertyType, mHelper.mGenericDocumentType)) {
-            body.addStatement(
-                    "GenericDocument[] $NConv = $NCopy.toArray(new GenericDocument[0])", fieldName,
-                    fieldName);
-
         } else {
             // This is not a type 1b collection.
             return false;
@@ -305,6 +301,52 @@
         return true;
     }
 
+    //   1c: CollectionForLoopCallToGenericDocument
+    //       Collection contains a class which is annotated with @AppSearchDocument.
+    //       We have to convert this into an array of GenericDocument[], by reading each element
+    //       one-by-one and converting it through the standard conversion machinery.
+    private boolean tryCollectionForLoopCallToGenericDocument(
+            @NonNull CodeBlock.Builder method,
+            @NonNull String fieldName,
+            @NonNull String propertyName,
+            @NonNull TypeMirror propertyType) {
+        Types typeUtil = mEnv.getTypeUtils();
+        CodeBlock.Builder body = CodeBlock.builder()
+                .add("if ($NCopy != null) {\n", fieldName).indent();
+
+        Element element = typeUtil.asElement(propertyType);
+        if (element == null) {
+            // The propertyType is not an element, this is not a type 1c list.
+            return false;
+        }
+        try {
+            mHelper.getAnnotation(element, IntrospectionHelper.APP_SEARCH_DOCUMENT_CLASS);
+        } catch (ProcessingException e) {
+            // The propertyType doesn't have @AppSearchDocument annotation, this is not a type 1c
+            // list.
+            return false;
+        }
+
+        body.addStatement("GenericDocument[] $NConv = new GenericDocument[$NCopy.size()]",
+                fieldName, fieldName);
+        body.addStatement("$T factory = $T.getInstance().getOrCreateFactory($T.class)",
+                ParameterizedTypeName.get(mHelper.getAppSearchClass("DataClassFactory"),
+                        TypeName.get(propertyType)),
+                mHelper.getAppSearchClass("DataClassFactoryRegistry"), propertyType);
+
+        body.addStatement("int i = 0");
+        body.add("for ($T item : $NCopy) {\n", propertyType, fieldName).indent();
+        body.addStatement("$NConv[i++] = factory.toGenericDocument(item)", fieldName);
+
+        body.unindent().add("}\n");
+
+        body.addStatement("builder.setProperty($S, $NConv)", propertyName, fieldName)
+                .unindent().add("}\n");   //  if ($NCopy != null) {
+
+        method.add(body.build());
+        return true;
+    }
+
     /**
      * If the given field is an array, generates code to read it and convert it into a form suitable
      * for GenericDocument and returns true. If the field is not an array, returns false.
@@ -400,8 +442,7 @@
     }
 
     //   2b: ArrayUseDirectly
-    //       Array is of type String[], long[], double[], boolean[], byte[][] or
-    //       GenericDocument[].
+    //       Array is of type String[], long[], double[], boolean[], byte[][].
     //       We can directly use this field with no conversion.
     private boolean tryArrayUseDirectly(
             @NonNull CodeBlock.Builder method,
@@ -416,8 +457,7 @@
                 && !typeUtil.isSameType(propertyType, mHelper.mLongPrimitiveType)
                 && !typeUtil.isSameType(propertyType, mHelper.mDoublePrimitiveType)
                 && !typeUtil.isSameType(propertyType, mHelper.mBooleanPrimitiveType)
-                && !typeUtil.isSameType(propertyType, mHelper.mBytePrimitiveArrayType)
-                && !typeUtil.isSameType(propertyType, mHelper.mGenericDocumentType)) {
+                && !typeUtil.isSameType(propertyType, mHelper.mBytePrimitiveArrayType)) {
             // This is not a type 2b array.
             return false;
         }
@@ -453,8 +493,7 @@
     }
 
     //   3a: FieldUseDirectlyWithNullCheck
-    //       Field is of type String, Long, Integer, Double, Float, Boolean, byte[] or
-    //       GenericDocument.
+    //       Field is of type String, Long, Integer, Double, Float, Boolean, byte[].
     //       We can use this field directly, after testing for null. The java compiler will box
     //       or unbox as needed.
     private boolean tryFieldUseDirectlyWithNullCheck(
@@ -478,8 +517,7 @@
                 && !typeUtil.isSameType(propertyType, mHelper.mDoubleBoxType)
                 && !typeUtil.isSameType(propertyType, mHelper.mFloatBoxType)
                 && !typeUtil.isSameType(propertyType, mHelper.mBooleanBoxType)
-                && !typeUtil.isSameType(propertyType, mHelper.mBytePrimitiveArrayType)
-                && !typeUtil.isSameType(propertyType, mHelper.mGenericDocumentType)) {
+                && !typeUtil.isSameType(propertyType, mHelper.mBytePrimitiveArrayType)) {
             // This is not a type 3a field
             return false;
         }
diff --git a/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java b/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
index 1270853..fc10040 100644
--- a/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
+++ b/appsearch/compiler/src/test/java/androidx/appsearch/compiler/AppSearchCompilerTest.java
@@ -218,7 +218,7 @@
                         + "  void setPrice(int n) {}\n"
                         + "}\n");
         CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
-        checkEqualsGolden();
+        checkEqualsGolden("Gift.java");
     }
 
     @Test
@@ -293,7 +293,7 @@
                         + "  void setPrice(int n) {}\n"
                         + "}\n");
         CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
-        checkEqualsGolden();
+        checkEqualsGolden("Gift.java");
     }
 
     @Test
@@ -362,7 +362,7 @@
                         + "  public boolean getDog() { return dog; }\n"
                         + "}\n");
         CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
-        checkEqualsGolden();
+        checkEqualsGolden("Gift.java");
     }
 
     @Test
@@ -373,7 +373,7 @@
                         + "  @AppSearchDocument.Uri String uri;\n"
                         + "}\n");
         CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
-        checkEqualsGolden();
+        checkEqualsGolden("Gift.java");
     }
 
     @Test
@@ -389,7 +389,7 @@
                         + "  @AppSearchDocument.Property byte[] byteArray;\n"
                         + "}\n");
         CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
-        checkEqualsGolden();
+        checkEqualsGolden("Gift.java");
     }
 
     @Test
@@ -405,7 +405,7 @@
                         + "  @AppSearchDocument.Property(required=false) Float noReq;\n"
                         + "}\n");
         CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
-        checkEqualsGolden();
+        checkEqualsGolden("Gift.java");
     }
 
     @Test
@@ -426,7 +426,7 @@
                         //+ "  @AppSearchDocument.Property Gift documentProp;\n"
                         + "}\n");
         CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
-        checkEqualsGolden();
+        checkEqualsGolden("Gift.java");
     }
 
     @Test
@@ -442,7 +442,7 @@
                         + "  @AppSearchDocument.Property(tokenizerType=1) String tokPlain;\n"
                         + "}\n");
         CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
-        checkEqualsGolden();
+        checkEqualsGolden("Gift.java");
     }
 
     @Test
@@ -473,7 +473,7 @@
                         + "  @AppSearchDocument.Property(indexingType=2) String indexPrefix;\n"
                         + "}\n");
         CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
-        checkEqualsGolden();
+        checkEqualsGolden("Gift.java");
     }
 
     @Test
@@ -500,7 +500,7 @@
                         + "  @AppSearchDocument.Property(name=\"newName\") String oldName;\n"
                         + "}\n");
         CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
-        checkEqualsGolden();
+        checkEqualsGolden("Gift.java");
     }
 
     @Test
@@ -521,8 +521,7 @@
                         + "  @Property Collection<Boolean> collectBoolean;\n"   // 1a
                         + "  @Property Collection<byte[]> collectByteArr;\n"    // 1a
                         + "  @Property Collection<String> collectString;\n"     // 1b
-                        + "  @Property Collection<GenericDocument> collectGenDoc;\n" // 1b
-                        //+ "  @Property Collection<Gift> collectGift;\n"         // 1c
+                        + "  @Property Collection<Gift> collectGift;\n"         // 1c
                         + "\n"
                         + "  // Arrays\n"
                         + "  @Property Long[] arrBoxLong;\n"         // 2a
@@ -538,7 +537,6 @@
                         + "  @Property byte[][] arrUnboxByteArr;\n"  // 2b
                         + "  @Property Byte[] boxByteArr;\n"         // 2a
                         + "  @Property String[] arrString;\n"        // 2b
-                        + "  @Property GenericDocument[] arrGenDoc;\n" // 2b
                         //+ "  @Property Gift[] arrGift;\n"            // 2c
                         + "\n"
                         + "  // Single values\n"
@@ -554,11 +552,10 @@
                         + "  @Property Boolean boxBoolean;\n"   // 3a
                         + "  @Property boolean unboxBoolean;\n" // 3b
                         + "  @Property byte[] unboxByteArr;\n"  // 3a
-                        + "  @Property GenericDocument genDocument;\n" // 3a
                         //+ "  @Property Gift gift;\n"            // 3c
                         + "}\n");
         CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
-        checkEqualsGolden();
+        checkEqualsGolden("Gift.java");
     }
 
     @Test
@@ -637,7 +634,7 @@
                         + "  @AppSearchDocument.Score int score;\n"
                         + "}\n");
         CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
-        checkEqualsGolden();
+        checkEqualsGolden("Gift.java");
     }
 
     @Test
@@ -664,7 +661,23 @@
                         + "  public void setPrice(int price) { this.price = price; }\n"
                         + "}\n");
         CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
-        checkEqualsGolden();
+        checkEqualsGolden("Gift.java");
+    }
+
+    @Test
+    public void testInnerClass() throws Exception {
+        Compilation compilation = compile(
+                "import java.util.*;\n"
+                        + "import androidx.appsearch.app.GenericDocument;\n"
+                        + "public class Gift {\n"
+                        + "  @AppSearchDocument\n"
+                        + "  public static class InnerGift{\n"
+                        + "    @AppSearchDocument.Uri String uri;\n"
+                        + "    @Property String[] arrString;\n"        // 2b
+                        + "  }\n"
+                        + "}\n");
+        CompilationSubject.assertThat(compilation).succeededWithoutWarnings();
+        checkEqualsGolden("Gift$$__InnerGift.java");
     }
 
     private Compilation compile(String classBody) {
@@ -692,7 +705,7 @@
                 .compile(jfo);
     }
 
-    private void checkEqualsGolden() throws IOException {
+    private void checkEqualsGolden(String className) throws IOException {
         // Get the expected file contents
         String goldenResPath = "goldens/" + mTestName.getMethodName() + ".JAVA";
         String expected = "";
@@ -707,7 +720,7 @@
 
         // Get the actual file contents
         File actualPackageDir = new File(mGenFilesDir, "com/example/appsearch");
-        File actualPath = new File(actualPackageDir, CodeGenerator.GEN_CLASS_PREFIX + "Gift.java");
+        File actualPath = new File(actualPackageDir, CodeGenerator.GEN_CLASS_PREFIX + className);
         Truth.assertWithMessage("Path " + actualPath + " is not a file")
                 .that(actualPath.isFile()).isTrue();
         String actual = Files.asCharSource(actualPath, StandardCharsets.UTF_8).read();
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSingleTypes.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSingleTypes.JAVA
index da9aacc..299cccf 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSingleTypes.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSingleTypes.JAVA
@@ -3,6 +3,7 @@
 import androidx.appsearch.app.AppSearchSchema;
 import androidx.appsearch.app.DataClassFactory;
 import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
 import java.lang.Boolean;
 import java.lang.Double;
 import java.lang.Float;
@@ -14,63 +15,61 @@
 public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
   private static final String SCHEMA_TYPE = "Gift";
 
-  private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("stringProp")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("integerProp")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("longProp")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("floatProp")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("doubleProp")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("booleanProp")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("bytesProp")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .build();
-
   @Override
   public String getSchemaType() {
     return SCHEMA_TYPE;
   }
 
   @Override
-  public AppSearchSchema getSchema() {
-    return SCHEMA;
+  public AppSearchSchema getSchema() throws AppSearchException {
+    return new AppSearchSchema.Builder(SCHEMA_TYPE)
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("stringProp")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("integerProp")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("longProp")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("floatProp")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("doubleProp")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("booleanProp")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("bytesProp")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .build();
   }
 
   @Override
-  public GenericDocument toGenericDocument(Gift dataClass) {
+  public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
     GenericDocument.Builder<?> builder =
         new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
     String stringPropCopy = dataClass.stringProp;
@@ -105,7 +104,7 @@
   }
 
   @Override
-  public Gift fromGenericDocument(GenericDocument genericDoc) {
+  public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
     String uriConv = genericDoc.getUri();
     String[] stringPropCopy = genericDoc.getPropertyStringArray("stringProp");
     String stringPropConv = null;
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Field.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Field.JAVA
index 3843c23..278b64f 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Field.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Field.JAVA
@@ -3,33 +3,32 @@
 import androidx.appsearch.app.AppSearchSchema;
 import androidx.appsearch.app.DataClassFactory;
 import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
 import java.lang.Override;
 import java.lang.String;
 
 public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
   private static final String SCHEMA_TYPE = "Gift";
 
-  private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .build();
-
   @Override
   public String getSchemaType() {
     return SCHEMA_TYPE;
   }
 
   @Override
-  public AppSearchSchema getSchema() {
-    return SCHEMA;
+  public AppSearchSchema getSchema() throws AppSearchException {
+    return new AppSearchSchema.Builder(SCHEMA_TYPE)
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .build();
   }
 
   @Override
-  public GenericDocument toGenericDocument(Gift dataClass) {
+  public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
     GenericDocument.Builder<?> builder =
         new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
     String namespaceCopy = dataClass.namespace;
@@ -44,7 +43,7 @@
   }
 
   @Override
-  public Gift fromGenericDocument(GenericDocument genericDoc) {
+  public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
     String uriConv = genericDoc.getUri();
     String namespaceConv = genericDoc.getNamespace();
     long creationTsConv = genericDoc.getCreationTimestampMillis();
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Getter.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Getter.JAVA
index 1cf34f5..992674e 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Getter.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testAllSpecialFields_Getter.JAVA
@@ -3,33 +3,32 @@
 import androidx.appsearch.app.AppSearchSchema;
 import androidx.appsearch.app.DataClassFactory;
 import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
 import java.lang.Override;
 import java.lang.String;
 
 public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
   private static final String SCHEMA_TYPE = "Gift";
 
-  private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .build();
-
   @Override
   public String getSchemaType() {
     return SCHEMA_TYPE;
   }
 
   @Override
-  public AppSearchSchema getSchema() {
-    return SCHEMA;
+  public AppSearchSchema getSchema() throws AppSearchException {
+    return new AppSearchSchema.Builder(SCHEMA_TYPE)
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .build();
   }
 
   @Override
-  public GenericDocument toGenericDocument(Gift dataClass) {
+  public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
     GenericDocument.Builder<?> builder =
         new GenericDocument.Builder<>(dataClass.getUri(), SCHEMA_TYPE);
     builder.setCreationTimestampMillis(dataClass.getCreationTs());
@@ -40,7 +39,7 @@
   }
 
   @Override
-  public Gift fromGenericDocument(GenericDocument genericDoc) {
+  public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
     String uriConv = genericDoc.getUri();
     long creationTsConv = genericDoc.getCreationTimestampMillis();
     long ttlMsConv = genericDoc.getTtlMillis();
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCardinality.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCardinality.JAVA
index 3fc783e..732beed 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCardinality.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testCardinality.JAVA
@@ -3,6 +3,7 @@
 import androidx.appsearch.app.AppSearchSchema;
 import androidx.appsearch.app.DataClassFactory;
 import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
 import java.lang.Float;
 import java.lang.Override;
 import java.lang.String;
@@ -12,45 +13,43 @@
 public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
   private static final String SCHEMA_TYPE = "Gift";
 
-  private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("repeatReq")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("repeatNoReq")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("req")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("noReq")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .build();
-
   @Override
   public String getSchemaType() {
     return SCHEMA_TYPE;
   }
 
   @Override
-  public AppSearchSchema getSchema() {
-    return SCHEMA;
+  public AppSearchSchema getSchema() throws AppSearchException {
+    return new AppSearchSchema.Builder(SCHEMA_TYPE)
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("repeatReq")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("repeatNoReq")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("req")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("noReq")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .build();
   }
 
   @Override
-  public GenericDocument toGenericDocument(Gift dataClass) {
+  public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
     GenericDocument.Builder<?> builder =
         new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
     List<String> repeatReqCopy = dataClass.repeatReq;
@@ -75,7 +74,7 @@
   }
 
   @Override
-  public Gift fromGenericDocument(GenericDocument genericDoc) {
+  public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
     String uriConv = genericDoc.getUri();
     String[] repeatReqCopy = genericDoc.getPropertyStringArray("repeatReq");
     List<String> repeatReqConv = null;
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testDifferentTypeName.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testDifferentTypeName.JAVA
index 3d696f0..2c55500 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testDifferentTypeName.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testDifferentTypeName.JAVA
@@ -3,34 +3,33 @@
 import androidx.appsearch.app.AppSearchSchema;
 import androidx.appsearch.app.DataClassFactory;
 import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
 import java.lang.Override;
 import java.lang.String;
 
 public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
   private static final String SCHEMA_TYPE = "DifferentType";
 
-  private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
-    .build();
-
   @Override
   public String getSchemaType() {
     return SCHEMA_TYPE;
   }
 
   @Override
-  public AppSearchSchema getSchema() {
-    return SCHEMA;
+  public AppSearchSchema getSchema() throws AppSearchException {
+    return new AppSearchSchema.Builder(SCHEMA_TYPE)
+          .build();
   }
 
   @Override
-  public GenericDocument toGenericDocument(Gift dataClass) {
+  public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
     GenericDocument.Builder<?> builder =
         new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
     return builder.build();
   }
 
   @Override
-  public Gift fromGenericDocument(GenericDocument genericDoc) {
+  public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
     String uriConv = genericDoc.getUri();
     Gift dataClass = new Gift();
     dataClass.uri = uriConv;
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testIndexingType.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testIndexingType.JAVA
index 43dc25a..255d72c 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testIndexingType.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testIndexingType.JAVA
@@ -3,45 +3,44 @@
 import androidx.appsearch.app.AppSearchSchema;
 import androidx.appsearch.app.DataClassFactory;
 import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
 import java.lang.Override;
 import java.lang.String;
 
 public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
   private static final String SCHEMA_TYPE = "Gift";
 
-  private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("indexNone")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("indexExact")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("indexPrefix")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
-      .build())
-    .build();
-
   @Override
   public String getSchemaType() {
     return SCHEMA_TYPE;
   }
 
   @Override
-  public AppSearchSchema getSchema() {
-    return SCHEMA;
+  public AppSearchSchema getSchema() throws AppSearchException {
+    return new AppSearchSchema.Builder(SCHEMA_TYPE)
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("indexNone")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("indexExact")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("indexPrefix")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+            .build())
+          .build();
   }
 
   @Override
-  public GenericDocument toGenericDocument(Gift dataClass) {
+  public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
     GenericDocument.Builder<?> builder =
         new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
     String indexNoneCopy = dataClass.indexNone;
@@ -60,7 +59,7 @@
   }
 
   @Override
-  public Gift fromGenericDocument(GenericDocument genericDoc) {
+  public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
     String uriConv = genericDoc.getUri();
     String[] indexNoneCopy = genericDoc.getPropertyStringArray("indexNone");
     String indexNoneConv = null;
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testInnerClass.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testInnerClass.JAVA
new file mode 100644
index 0000000..9baf8f1
--- /dev/null
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testInnerClass.JAVA
@@ -0,0 +1,50 @@
+package com.example.appsearch;
+
+import androidx.appsearch.app.AppSearchSchema;
+import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
+import java.lang.Override;
+import java.lang.String;
+
+public class $$__AppSearch__Gift$$__InnerGift implements DataClassFactory<Gift.InnerGift> {
+  private static final String SCHEMA_TYPE = "InnerGift";
+
+  @Override
+  public String getSchemaType() {
+    return SCHEMA_TYPE;
+  }
+
+  @Override
+  public AppSearchSchema getSchema() throws AppSearchException {
+    return new AppSearchSchema.Builder(SCHEMA_TYPE)
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrString")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .build();
+  }
+
+  @Override
+  public GenericDocument toGenericDocument(Gift.InnerGift dataClass) throws AppSearchException {
+    GenericDocument.Builder<?> builder =
+        new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
+    String[] arrStringCopy = dataClass.arrString;
+    if (arrStringCopy != null) {
+      builder.setProperty("arrString", arrStringCopy);
+    }
+    return builder.build();
+  }
+
+  @Override
+  public Gift.InnerGift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
+    String uriConv = genericDoc.getUri();
+    String[] arrStringConv = genericDoc.getPropertyStringArray("arrString");
+    Gift.InnerGift dataClass = new Gift.InnerGift();
+    dataClass.uri = uriConv;
+    dataClass.arrString = arrStringConv;
+    return dataClass;
+  }
+}
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testPropertyName.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testPropertyName.JAVA
index 9140e149..c72e2a4 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testPropertyName.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testPropertyName.JAVA
@@ -3,33 +3,32 @@
 import androidx.appsearch.app.AppSearchSchema;
 import androidx.appsearch.app.DataClassFactory;
 import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
 import java.lang.Override;
 import java.lang.String;
 
 public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
   private static final String SCHEMA_TYPE = "Gift";
 
-  private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("newName")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .build();
-
   @Override
   public String getSchemaType() {
     return SCHEMA_TYPE;
   }
 
   @Override
-  public AppSearchSchema getSchema() {
-    return SCHEMA;
+  public AppSearchSchema getSchema() throws AppSearchException {
+    return new AppSearchSchema.Builder(SCHEMA_TYPE)
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("newName")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .build();
   }
 
   @Override
-  public GenericDocument toGenericDocument(Gift dataClass) {
+  public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
     GenericDocument.Builder<?> builder =
         new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
     String oldNameCopy = dataClass.oldName;
@@ -40,7 +39,7 @@
   }
 
   @Override
-  public Gift fromGenericDocument(GenericDocument genericDoc) {
+  public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
     String uriConv = genericDoc.getUri();
     String[] oldNameCopy = genericDoc.getPropertyStringArray("newName");
     String oldNameConv = null;
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRead_MultipleGetters.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRead_MultipleGetters.JAVA
index fdbae72..66c7ed7 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRead_MultipleGetters.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRead_MultipleGetters.JAVA
@@ -3,33 +3,32 @@
 import androidx.appsearch.app.AppSearchSchema;
 import androidx.appsearch.app.DataClassFactory;
 import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
 import java.lang.Override;
 import java.lang.String;
 
 public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
   private static final String SCHEMA_TYPE = "Gift";
 
-  private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .build();
-
   @Override
   public String getSchemaType() {
     return SCHEMA_TYPE;
   }
 
   @Override
-  public AppSearchSchema getSchema() {
-    return SCHEMA;
+  public AppSearchSchema getSchema() throws AppSearchException {
+    return new AppSearchSchema.Builder(SCHEMA_TYPE)
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .build();
   }
 
   @Override
-  public GenericDocument toGenericDocument(Gift dataClass) {
+  public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
     GenericDocument.Builder<?> builder =
         new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
     builder.setProperty("price", dataClass.getPrice());
@@ -37,7 +36,7 @@
   }
 
   @Override
-  public Gift fromGenericDocument(GenericDocument genericDoc) {
+  public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
     String uriConv = genericDoc.getUri();
     int priceConv = genericDoc.getPropertyLong("price");
     Gift dataClass = new Gift();
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRepeatedFields.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRepeatedFields.JAVA
index b0cece9..7ceb65d 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRepeatedFields.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testRepeatedFields.JAVA
@@ -3,6 +3,7 @@
 import androidx.appsearch.app.AppSearchSchema;
 import androidx.appsearch.app.DataClassFactory;
 import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
 import java.lang.Integer;
 import java.lang.Override;
 import java.lang.String;
@@ -14,45 +15,43 @@
 public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
   private static final String SCHEMA_TYPE = "Gift";
 
-  private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("listOfString")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("setOfInt")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("repeatedByteArray")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("byteArray")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .build();
-
   @Override
   public String getSchemaType() {
     return SCHEMA_TYPE;
   }
 
   @Override
-  public AppSearchSchema getSchema() {
-    return SCHEMA;
+  public AppSearchSchema getSchema() throws AppSearchException {
+    return new AppSearchSchema.Builder(SCHEMA_TYPE)
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("listOfString")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("setOfInt")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("repeatedByteArray")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("byteArray")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .build();
   }
 
   @Override
-  public GenericDocument toGenericDocument(Gift dataClass) {
+  public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
     GenericDocument.Builder<?> builder =
         new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
     List<String> listOfStringCopy = dataClass.listOfString;
@@ -81,7 +80,7 @@
   }
 
   @Override
-  public Gift fromGenericDocument(GenericDocument genericDoc) {
+  public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
     String uriConv = genericDoc.getUri();
     String[] listOfStringCopy = genericDoc.getPropertyStringArray("listOfString");
     List<String> listOfStringConv = null;
@@ -93,7 +92,7 @@
     if (setOfIntCopy != null) {
       setOfIntConv = new ArrayList<>(setOfIntCopy.length);
       for (int i = 0; i < setOfIntCopy.length; i++) {
-        setOfIntConv.set(i, setOfIntCopy[i]);
+        setOfIntConv.add(setOfIntCopy[i]);
       }
     }
     byte[][] repeatedByteArrayConv = genericDoc.getPropertyBytesArray("repeatedByteArray");
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuccessSimple.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuccessSimple.JAVA
index 66a5b03..ca57ea7 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuccessSimple.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testSuccessSimple.JAVA
@@ -3,45 +3,44 @@
 import androidx.appsearch.app.AppSearchSchema;
 import androidx.appsearch.app.DataClassFactory;
 import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
 import java.lang.Override;
 import java.lang.String;
 
 public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
   private static final String SCHEMA_TYPE = "Gift";
 
-  private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("cat")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("dog")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .build();
-
   @Override
   public String getSchemaType() {
     return SCHEMA_TYPE;
   }
 
   @Override
-  public AppSearchSchema getSchema() {
-    return SCHEMA;
+  public AppSearchSchema getSchema() throws AppSearchException {
+    return new AppSearchSchema.Builder(SCHEMA_TYPE)
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("cat")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("dog")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .build();
   }
 
   @Override
-  public GenericDocument toGenericDocument(Gift dataClass) {
+  public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
     GenericDocument.Builder<?> builder =
         new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
     builder.setProperty("price", dataClass.price);
@@ -51,7 +50,7 @@
   }
 
   @Override
-  public Gift fromGenericDocument(GenericDocument genericDoc) {
+  public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
     String uriConv = genericDoc.getUri();
     int priceConv = genericDoc.getPropertyLong("price");
     boolean catConv = genericDoc.getPropertyBoolean("cat");
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testToGenericDocument_AllSupportedTypes.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testToGenericDocument_AllSupportedTypes.JAVA
index 35b09a1..9e3c236 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testToGenericDocument_AllSupportedTypes.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testToGenericDocument_AllSupportedTypes.JAVA
@@ -2,7 +2,9 @@
 
 import androidx.appsearch.app.AppSearchSchema;
 import androidx.appsearch.app.DataClassFactory;
+import androidx.appsearch.app.DataClassFactoryRegistry;
 import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
 import java.lang.Boolean;
 import java.lang.Byte;
 import java.lang.Double;
@@ -19,231 +21,218 @@
 public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
   private static final String SCHEMA_TYPE = "Gift";
 
-  private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectLong")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectInteger")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectDouble")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectFloat")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectBoolean")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectByteArr")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectString")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectGenDoc")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxLong")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxLong")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxInteger")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxInt")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxDouble")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxDouble")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxFloat")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxFloat")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxBoolean")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxBoolean")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxByteArr")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxByteArr")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrString")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrGenDoc")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("string")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxLong")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxLong")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxInteger")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxInt")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxDouble")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxDouble")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxFloat")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxFloat")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxBoolean")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxBoolean")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxByteArr")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("genDocument")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .build();
-
   @Override
   public String getSchemaType() {
     return SCHEMA_TYPE;
   }
 
   @Override
-  public AppSearchSchema getSchema() {
-    return SCHEMA;
+  public AppSearchSchema getSchema() throws AppSearchException {
+    return new AppSearchSchema.Builder(SCHEMA_TYPE)
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectLong")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectInteger")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectDouble")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectFloat")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectBoolean")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectByteArr")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectString")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("collectGift")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOCUMENT)
+            .setSchemaType(DataClassFactoryRegistry.getInstance().getOrCreateFactory(Gift.class).getSchemaType())
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxLong")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxLong")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxInteger")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxInt")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxDouble")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxDouble")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxFloat")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxFloat")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrBoxBoolean")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxBoolean")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrUnboxByteArr")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxByteArr")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("arrString")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("string")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxLong")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxLong")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxInteger")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxInt")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxDouble")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxDouble")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxFloat")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxFloat")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_DOUBLE)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("boxBoolean")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxBoolean")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BOOLEAN)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("unboxByteArr")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_BYTES)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .build();
   }
 
   @Override
-  public GenericDocument toGenericDocument(Gift dataClass) {
+  public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
     GenericDocument.Builder<?> builder =
         new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
     Collection<Long> collectLongCopy = dataClass.collectLong;
@@ -305,10 +294,15 @@
       String[] collectStringConv = collectStringCopy.toArray(new String[0]);
       builder.setProperty("collectString", collectStringConv);
     }
-    Collection<GenericDocument> collectGenDocCopy = dataClass.collectGenDoc;
-    if (collectGenDocCopy != null) {
-      GenericDocument[] collectGenDocConv = collectGenDocCopy.toArray(new GenericDocument[0]);
-      builder.setProperty("collectGenDoc", collectGenDocConv);
+    Collection<Gift> collectGiftCopy = dataClass.collectGift;
+    if (collectGiftCopy != null) {
+      GenericDocument[] collectGiftConv = new GenericDocument[collectGiftCopy.size()];
+      DataClassFactory<Gift> factory = DataClassFactoryRegistry.getInstance().getOrCreateFactory(Gift.class);
+      int i = 0;
+      for (Gift item : collectGiftCopy) {
+        collectGiftConv[i++] = factory.toGenericDocument(item);
+      }
+      builder.setProperty("collectGift", collectGiftConv);
     }
     Long[] arrBoxLongCopy = dataClass.arrBoxLong;
     if (arrBoxLongCopy != null) {
@@ -394,10 +388,6 @@
     if (arrStringCopy != null) {
       builder.setProperty("arrString", arrStringCopy);
     }
-    GenericDocument[] arrGenDocCopy = dataClass.arrGenDoc;
-    if (arrGenDocCopy != null) {
-      builder.setProperty("arrGenDoc", arrGenDocCopy);
-    }
     String stringCopy = dataClass.string;
     if (stringCopy != null) {
       builder.setProperty("string", stringCopy);
@@ -431,22 +421,18 @@
     if (unboxByteArrCopy != null) {
       builder.setProperty("unboxByteArr", unboxByteArrCopy);
     }
-    GenericDocument genDocumentCopy = dataClass.genDocument;
-    if (genDocumentCopy != null) {
-      builder.setProperty("genDocument", genDocumentCopy);
-    }
     return builder.build();
   }
 
   @Override
-  public Gift fromGenericDocument(GenericDocument genericDoc) {
+  public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
     String uriConv = genericDoc.getUri();
     long[] collectLongCopy = genericDoc.getPropertyLongArray("collectLong");
     List<Long> collectLongConv = null;
     if (collectLongCopy != null) {
       collectLongConv = new ArrayList<>(collectLongCopy.length);
       for (int i = 0; i < collectLongCopy.length; i++) {
-        collectLongConv.set(i, collectLongCopy[i]);
+        collectLongConv.add(collectLongCopy[i]);
       }
     }
     long[] collectIntegerCopy = genericDoc.getPropertyLongArray("collectInteger");
@@ -454,7 +440,7 @@
     if (collectIntegerCopy != null) {
       collectIntegerConv = new ArrayList<>(collectIntegerCopy.length);
       for (int i = 0; i < collectIntegerCopy.length; i++) {
-        collectIntegerConv.set(i, collectIntegerCopy[i]);
+        collectIntegerConv.add(collectIntegerCopy[i]);
       }
     }
     double[] collectDoubleCopy = genericDoc.getPropertyDoubleArray("collectDouble");
@@ -462,7 +448,7 @@
     if (collectDoubleCopy != null) {
       collectDoubleConv = new ArrayList<>(collectDoubleCopy.length);
       for (int i = 0; i < collectDoubleCopy.length; i++) {
-        collectDoubleConv.set(i, collectDoubleCopy[i]);
+        collectDoubleConv.add(collectDoubleCopy[i]);
       }
     }
     double[] collectFloatCopy = genericDoc.getPropertyDoubleArray("collectFloat");
@@ -470,7 +456,7 @@
     if (collectFloatCopy != null) {
       collectFloatConv = new ArrayList<>(collectFloatCopy.length);
       for (int i = 0; i < collectFloatCopy.length; i++) {
-        collectFloatConv.set(i, collectFloatCopy[i]);
+        collectFloatConv.add(collectFloatCopy[i]);
       }
     }
     boolean[] collectBooleanCopy = genericDoc.getPropertyBooleanArray("collectBoolean");
@@ -478,7 +464,7 @@
     if (collectBooleanCopy != null) {
       collectBooleanConv = new ArrayList<>(collectBooleanCopy.length);
       for (int i = 0; i < collectBooleanCopy.length; i++) {
-        collectBooleanConv.set(i, collectBooleanCopy[i]);
+        collectBooleanConv.add(collectBooleanCopy[i]);
       }
     }
     byte[][] collectByteArrCopy = genericDoc.getPropertyBytesArray("collectByteArr");
@@ -486,7 +472,7 @@
     if (collectByteArrCopy != null) {
       collectByteArrConv = new ArrayList<>(collectByteArrCopy.length);
       for (int i = 0; i < collectByteArrCopy.length; i++) {
-        collectByteArrConv.set(i, collectByteArrCopy[i]);
+        collectByteArrConv.add(collectByteArrCopy[i]);
       }
     }
     String[] collectStringCopy = genericDoc.getPropertyStringArray("collectString");
@@ -494,10 +480,14 @@
     if (collectStringCopy != null) {
       collectStringConv = Arrays.asList(collectStringCopy);
     }
-    GenericDocument[] collectGenDocCopy = genericDoc.getPropertyDocumentArray("collectGenDoc");
-    List<GenericDocument> collectGenDocConv = null;
-    if (collectGenDocCopy != null) {
-      collectGenDocConv = Arrays.asList(collectGenDocCopy);
+    GenericDocument[] collectGiftCopy = genericDoc.getPropertyDocumentArray("collectGift");
+    List<Gift> collectGiftConv = null;
+    if (collectGiftCopy != null) {
+      DataClassFactory<Gift> factory = DataClassFactoryRegistry.getInstance().getOrCreateFactory(Gift.class);
+      collectGiftConv = new ArrayList<>(collectGiftCopy.length);
+      for (int i = 0; i < collectGiftCopy.length; i++) {
+        collectGiftConv.add(factory.fromGenericDocument(collectGiftCopy[i]));
+      }
     }
     long[] arrBoxLongCopy = genericDoc.getPropertyLongArray("arrBoxLong");
     Long[] arrBoxLongConv = null;
@@ -559,7 +549,7 @@
     }
     boolean[] arrUnboxBooleanConv = genericDoc.getPropertyBooleanArray("arrUnboxBoolean");
     byte[][] arrUnboxByteArrConv = genericDoc.getPropertyBytesArray("arrUnboxByteArr");
-    byte[][] boxByteArrCopy = genericDoc.getPropertyBytesArray("boxByteArr");
+    byte[] boxByteArrCopy = genericDoc.getPropertyBytes("boxByteArr");
     Byte[] boxByteArrConv = null;
     if (boxByteArrCopy != null) {
       boxByteArrConv = new Byte[boxByteArrCopy.length];
@@ -568,7 +558,6 @@
       }
     }
     String[] arrStringConv = genericDoc.getPropertyStringArray("arrString");
-    GenericDocument[] arrGenDocConv = genericDoc.getPropertyDocumentArray("arrGenDoc");
     String[] stringCopy = genericDoc.getPropertyStringArray("string");
     String stringConv = null;
     if (stringCopy != null && stringCopy.length != 0) {
@@ -609,11 +598,6 @@
     if (unboxByteArrCopy != null && unboxByteArrCopy.length != 0) {
       unboxByteArrConv = unboxByteArrCopy[0];
     }
-    GenericDocument[] genDocumentCopy = genericDoc.getPropertyDocumentArray("genDocument");
-    GenericDocument genDocumentConv = null;
-    if (genDocumentCopy != null && genDocumentCopy.length != 0) {
-      genDocumentConv = genDocumentCopy[0];
-    }
     Gift dataClass = new Gift();
     dataClass.uri = uriConv;
     dataClass.collectLong = collectLongConv;
@@ -623,7 +607,7 @@
     dataClass.collectBoolean = collectBooleanConv;
     dataClass.collectByteArr = collectByteArrConv;
     dataClass.collectString = collectStringConv;
-    dataClass.collectGenDoc = collectGenDocConv;
+    dataClass.collectGift = collectGiftConv;
     dataClass.arrBoxLong = arrBoxLongConv;
     dataClass.arrUnboxLong = arrUnboxLongConv;
     dataClass.arrBoxInteger = arrBoxIntegerConv;
@@ -637,7 +621,6 @@
     dataClass.arrUnboxByteArr = arrUnboxByteArrConv;
     dataClass.boxByteArr = boxByteArrConv;
     dataClass.arrString = arrStringConv;
-    dataClass.arrGenDoc = arrGenDocConv;
     dataClass.string = stringConv;
     dataClass.boxLong = boxLongConv;
     dataClass.unboxLong = unboxLongConv;
@@ -650,7 +633,6 @@
     dataClass.boxBoolean = boxBooleanConv;
     dataClass.unboxBoolean = unboxBooleanConv;
     dataClass.unboxByteArr = unboxByteArrConv;
-    dataClass.genDocument = genDocumentConv;
     return dataClass;
   }
 }
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testTokenizerType.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testTokenizerType.JAVA
index 6644954..4610d01 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testTokenizerType.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testTokenizerType.JAVA
@@ -3,39 +3,38 @@
 import androidx.appsearch.app.AppSearchSchema;
 import androidx.appsearch.app.DataClassFactory;
 import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
 import java.lang.Override;
 import java.lang.String;
 
 public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
   private static final String SCHEMA_TYPE = "Gift";
 
-  private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("tokNone")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("tokPlain")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .build();
-
   @Override
   public String getSchemaType() {
     return SCHEMA_TYPE;
   }
 
   @Override
-  public AppSearchSchema getSchema() {
-    return SCHEMA;
+  public AppSearchSchema getSchema() throws AppSearchException {
+    return new AppSearchSchema.Builder(SCHEMA_TYPE)
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("tokNone")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("tokPlain")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .build();
   }
 
   @Override
-  public GenericDocument toGenericDocument(Gift dataClass) {
+  public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
     GenericDocument.Builder<?> builder =
         new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
     String tokNoneCopy = dataClass.tokNone;
@@ -50,7 +49,7 @@
   }
 
   @Override
-  public Gift fromGenericDocument(GenericDocument genericDoc) {
+  public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
     String uriConv = genericDoc.getUri();
     String[] tokNoneCopy = genericDoc.getPropertyStringArray("tokNone");
     String tokNoneConv = null;
diff --git a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_MultipleSetters.JAVA b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_MultipleSetters.JAVA
index fdbae72..66c7ed7 100644
--- a/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_MultipleSetters.JAVA
+++ b/appsearch/compiler/src/test/resources/androidx/appsearch/compiler/goldens/testWrite_MultipleSetters.JAVA
@@ -3,33 +3,32 @@
 import androidx.appsearch.app.AppSearchSchema;
 import androidx.appsearch.app.DataClassFactory;
 import androidx.appsearch.app.GenericDocument;
+import androidx.appsearch.exceptions.AppSearchException;
 import java.lang.Override;
 import java.lang.String;
 
 public class $$__AppSearch__Gift implements DataClassFactory<Gift> {
   private static final String SCHEMA_TYPE = "Gift";
 
-  private static final AppSearchSchema SCHEMA = new AppSearchSchema.Builder(SCHEMA_TYPE)
-    .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
-      .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
-      .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
-      .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
-      .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
-      .build())
-    .build();
-
   @Override
   public String getSchemaType() {
     return SCHEMA_TYPE;
   }
 
   @Override
-  public AppSearchSchema getSchema() {
-    return SCHEMA;
+  public AppSearchSchema getSchema() throws AppSearchException {
+    return new AppSearchSchema.Builder(SCHEMA_TYPE)
+          .addProperty(new AppSearchSchema.PropertyConfig.Builder("price")
+            .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+            .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+            .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+            .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+            .build())
+          .build();
   }
 
   @Override
-  public GenericDocument toGenericDocument(Gift dataClass) {
+  public GenericDocument toGenericDocument(Gift dataClass) throws AppSearchException {
     GenericDocument.Builder<?> builder =
         new GenericDocument.Builder<>(dataClass.uri, SCHEMA_TYPE);
     builder.setProperty("price", dataClass.getPrice());
@@ -37,7 +36,7 @@
   }
 
   @Override
-  public Gift fromGenericDocument(GenericDocument genericDoc) {
+  public Gift fromGenericDocument(GenericDocument genericDoc) throws AppSearchException {
     String uriConv = genericDoc.getUri();
     int priceConv = genericDoc.getPropertyLong("price");
     Gift dataClass = new Gift();
diff --git a/appsearch/export_to_framework.py b/appsearch/export_to_framework.py
new file mode 100755
index 0000000..c726855
--- /dev/null
+++ b/appsearch/export_to_framework.py
@@ -0,0 +1,213 @@
+#!/usr/bin/env python3
+# Copyright (C) 2020 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.
+
+# Exports AppSearch Androidx code to Framework
+#
+# NOTE: This will remove and replace all files in the
+# frameworks/base/apex/appsearch path.
+#
+# Example usage (from root dir of androidx workspace):
+#   $ ./frameworks/support/appsearch/export_to_framework.py "$HOME/android/master"
+import os
+import re
+import sys
+
+
+JETPACK_API_ROOT = 'appsearch/src/main/java/androidx/appsearch'
+JETPACK_IMPL_ROOT = 'local-backend/src/main/java/androidx/appsearch'
+JETPACK_IMPL_TEST_ROOT = 'local-backend/src/androidTest/java/androidx/appsearch'
+FRAMEWORK_API_ROOT = 'framework/java/android/app/appsearch'
+FRAMEWORK_IMPL_ROOT = 'service/java/com/android/server/appsearch/external'
+FRAMEWORK_IMPL_TEST_ROOT = (
+        '../../services/tests/servicestests/src/'
+        'com/android/server/appsearch/external')
+
+
+def _PruneDir(dest_dir, allow_list=None):
+    all_files = []
+    for walk_path, walk_folders, walk_files in os.walk(dest_dir):
+        for walk_filename in walk_files:
+            abs_path = os.path.join(walk_path, walk_filename)
+            all_files.append(abs_path)
+
+    for abs_path in all_files:
+        rel_path = os.path.relpath(abs_path, dest_dir)
+        if allow_list and rel_path in allow_list:
+            print('Prune: skip "%s"' % abs_path)
+        else:
+            print('Prune: remove "%s"' % abs_path)
+            os.remove(abs_path)
+
+
+def _TransformAndCopyFile(source_path, dest_path, transform_func=None):
+    print('Copy: "%s" -> "%s"' % (source_path, dest_path), file=sys.stderr)
+    with open(source_path, 'r') as fh:
+      contents = fh.read()
+    if transform_func:
+      contents = transform_func(contents)
+    os.makedirs(os.path.dirname(dest_path), exist_ok=True)
+    with open(dest_path, 'w') as fh:
+      fh.write(contents)
+
+
+def _TransformCommonCode(contents):
+    contents = (contents
+        .replace('androidx.appsearch.app', 'android.app.appsearch')
+        .replace('androidx.appsearch', 'android.app.appsearch')
+        .replace(
+                'androidx.annotation.GuardedBy',
+                'com.android.internal.annotations.GuardedBy')
+        .replace(
+                'androidx.annotation.VisibleForTesting',
+                'com.android.internal.annotations.VisibleForTesting')
+        .replace('androidx.collection.ArraySet', 'android.util.ArraySet')
+        .replace(
+                'androidx.core.util.Preconditions',
+                'com.android.internal.util.Preconditions')
+        .replace('import androidx.annotation.RestrictTo;', '')
+        .replace('@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)', '')
+        .replace('androidx', 'android')
+    )
+    return contents
+
+
+def _TransformApiCode(contents):
+    contents = (contents
+        .replace(
+                'package androidx.appsearch.app;',
+                'package android.app.appsearch;')
+    )
+    return _TransformCommonCode(contents)
+
+
+def _TransformImplCode(contents):
+    contents = (contents
+        .replace(
+                'package androidx.appsearch',
+                'package com.android.server.appsearch.external')
+    )
+    return _TransformCommonCode(contents)
+
+
+def _TransformImplTestCode(contents):
+    return (_TransformImplCode(contents)
+        .replace(
+                'com.google.android.icing.proto.',
+                'com.android.server.appsearch.proto.')
+        .replace('org.junit.Assert.assertThrows',
+                 'org.testng.Assert.expectThrows')
+        .replace('assertThrows(', 'expectThrows(')
+    )
+
+
+def _CopyAllApi(source_dir, dest_dir):
+    api_source_dir = os.path.join(source_dir, JETPACK_API_ROOT)
+    api_dest_dir = os.path.join(dest_dir, FRAMEWORK_API_ROOT)
+    # Prune existing files
+    _PruneDir(api_dest_dir, allow_list=[
+        'AppSearchManager.java',
+        'AppSearchManagerFrameworkInitializer.java',
+        'IAppSearchManager.aidl',
+    ])
+
+    # Copy new files
+    for currentpath, folders, files in os.walk(api_source_dir):
+        dir_rel_to_root = os.path.relpath(currentpath, api_source_dir)
+        for filename in files:
+            # Copy all files, except those in the following block list
+            source_abs_path = os.path.join(currentpath, filename)
+            rel_to_api = os.path.relpath(source_abs_path, api_source_dir)
+            if rel_to_api in ('app/AppSearchManager.java'):
+                print('Skipping copy: "%s"' % rel_to_api)
+                continue
+
+            # Figure out what folder to place them into
+            if dir_rel_to_root == 'app':
+                # Files in the 'app' folder live in the root of the platform
+                # tree
+                dest_path = os.path.join(api_dest_dir, filename)
+            else:
+                dest_path = os.path.join(
+                        api_dest_dir, dir_rel_to_root, filename)
+            _TransformAndCopyFile(source_abs_path, dest_path, _TransformApiCode)
+
+
+def _TransformAndCopyFolder(
+        source_dir, dest_dir, transform_func=None, block_list=None):
+    for currentpath, folders, files in os.walk(source_dir):
+        dir_rel_to_root = os.path.relpath(currentpath, source_dir)
+        for filename in files:
+            # Copy all files, except those in the block list
+            source_abs_path = os.path.join(currentpath, filename)
+            rel_to_source = os.path.relpath(source_abs_path, source_dir)
+            if block_list and rel_to_source in block_list:
+                print('Skipping copy: "%s"' % rel_to_source)
+                continue
+
+            dest_path = os.path.join(dest_dir, dir_rel_to_root, filename)
+            _TransformAndCopyFile(source_abs_path, dest_path, transform_func)
+
+
+def _CopyAllImpl(source_dir, dest_dir):
+    impl_source_dir = os.path.join(source_dir, JETPACK_IMPL_ROOT)
+    impl_test_source_dir = os.path.join(source_dir, JETPACK_IMPL_TEST_ROOT)
+    impl_dest_dir = os.path.join(dest_dir, FRAMEWORK_IMPL_ROOT)
+    impl_test_dest_dir = os.path.join(dest_dir, FRAMEWORK_IMPL_TEST_ROOT)
+
+    # Prune
+    _PruneDir(impl_dest_dir)
+    _PruneDir(impl_test_dest_dir)
+
+    # Copy impl classes
+    _TransformAndCopyFolder(
+            impl_source_dir, impl_dest_dir,
+            transform_func=_TransformImplCode,
+            block_list=[
+                'localbackend/LocalBackend.java',
+            ])
+
+    # Copy servicestests
+    _TransformAndCopyFolder(
+            impl_test_source_dir, impl_test_dest_dir,
+            transform_func=_TransformImplTestCode,
+            block_list=[
+                'localbackend/LocalBackendTest.java',
+            ])
+
+
+def _CopyMain(source_dir, dest_dir):
+    #_CopyAllApi(source_dir, dest_dir)
+    _CopyAllImpl(source_dir, dest_dir)
+
+
+if __name__ == '__main__':
+    if len(sys.argv) != 2:
+        print('Usage: %s <path/to/frameworks/base>' % sys.argv[0],
+              file=sys.stderr)
+        sys.exit(1)
+    source_dir = os.path.normpath(os.path.dirname(sys.argv[0]))
+    dest_dir = os.path.normpath(sys.argv[1])
+    if os.path.basename(dest_dir) == 'appsearch':
+        pass
+    elif os.path.basename(dest_dir) == 'base':
+        dest_dir = os.path.join(dest_dir, 'apex/appsearch')
+    else:
+        dest_dir = os.path.join(dest_dir, 'frameworks/base/apex/appsearch')
+    if not os.path.isdir(dest_dir):
+        print('Destination path "%s" does not exist or is not a directory' % (
+                dest_dir),
+              file=sys.stderr)
+        sys.exit(1)
+    _CopyMain(source_dir, dest_dir)
diff --git a/appsearch/local-backend/src/androidTest/java/androidx/appsearch/app/GenericDocumentToProtoConverterTest.java b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/app/GenericDocumentToProtoConverterTest.java
new file mode 100644
index 0000000..23571fc
--- /dev/null
+++ b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/app/GenericDocumentToProtoConverterTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2020 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.appsearch.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.PropertyProto;
+import com.google.android.icing.protobuf.ByteString;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+public class GenericDocumentToProtoConverterTest {
+    private static final byte[] BYTE_ARRAY_1 = new byte[]{(byte) 1, (byte) 2, (byte) 3};
+    private static final byte[] BYTE_ARRAY_2 = new byte[]{(byte) 4, (byte) 5, (byte) 6, (byte) 7};
+    private static final GenericDocument DOCUMENT_PROPERTIES_1 = new GenericDocument
+            .Builder("sDocumentProperties1", "sDocumentPropertiesSchemaType1")
+            .setCreationTimestampMillis(12345L)
+            .build();
+    private static final GenericDocument DOCUMENT_PROPERTIES_2 = new GenericDocument
+            .Builder("sDocumentProperties2", "sDocumentPropertiesSchemaType2")
+            .setCreationTimestampMillis(6789L)
+            .build();
+
+    @Test
+    public void testDocumentProtoConvert() {
+        GenericDocument document = new GenericDocument.Builder("uri1", "schemaType1")
+                .setCreationTimestampMillis(5L)
+                .setScore(1)
+                .setTtlMillis(1L)
+                .setNamespace("namespace")
+                .setProperty("longKey1", 1L)
+                .setProperty("doubleKey1", 1.0)
+                .setProperty("booleanKey1", true)
+                .setProperty("stringKey1", "test-value1")
+                .setProperty("byteKey1", BYTE_ARRAY_1, BYTE_ARRAY_2)
+                .setProperty("documentKey1", DOCUMENT_PROPERTIES_1)
+                .setProperty(GenericDocument.PROPERTIES_FIELD, DOCUMENT_PROPERTIES_2)
+                .build();
+
+        // Create the Document proto. Need to sort the property order by key.
+        DocumentProto.Builder documentProtoBuilder = DocumentProto.newBuilder()
+                .setUri("uri1")
+                .setSchema("schemaType1")
+                .setCreationTimestampMs(5L)
+                .setScore(1)
+                .setTtlMs(1L)
+                .setNamespace("namespace");
+        HashMap<String, PropertyProto.Builder> propertyProtoMap = new HashMap<>();
+        propertyProtoMap.put("longKey1",
+                PropertyProto.newBuilder().setName("longKey1").addInt64Values(1L));
+        propertyProtoMap.put("doubleKey1",
+                PropertyProto.newBuilder().setName("doubleKey1").addDoubleValues(1.0));
+        propertyProtoMap.put("booleanKey1",
+                PropertyProto.newBuilder().setName("booleanKey1").addBooleanValues(true));
+        propertyProtoMap.put("stringKey1",
+                PropertyProto.newBuilder().setName("stringKey1").addStringValues("test-value1"));
+        propertyProtoMap.put("byteKey1",
+                PropertyProto.newBuilder().setName("byteKey1")
+                        .addBytesValues(ByteString.copyFrom(BYTE_ARRAY_1))
+                        .addBytesValues(ByteString.copyFrom(BYTE_ARRAY_2)));
+        propertyProtoMap.put("documentKey1",
+                PropertyProto.newBuilder().setName("documentKey1")
+                        .addDocumentValues(
+                                GenericDocumentToProtoConverter.convert(DOCUMENT_PROPERTIES_1)));
+        propertyProtoMap.put(GenericDocument.PROPERTIES_FIELD,
+                PropertyProto.newBuilder().setName(GenericDocument.PROPERTIES_FIELD)
+                        .addDocumentValues(
+                                GenericDocumentToProtoConverter.convert(DOCUMENT_PROPERTIES_2)));
+        List<String> sortedKey = new ArrayList<>(propertyProtoMap.keySet());
+        Collections.sort(sortedKey);
+        for (String key : sortedKey) {
+            documentProtoBuilder.addProperties(propertyProtoMap.get(key));
+        }
+        DocumentProto documentProto = documentProtoBuilder.build();
+        assertThat(GenericDocumentToProtoConverter.convert(document))
+                .isEqualTo(documentProto);
+        assertThat(document).isEqualTo(GenericDocumentToProtoConverter.convert(documentProto));
+    }
+}
diff --git a/appsearch/local-backend/src/androidTest/java/androidx/appsearch/app/SchemaToProtoConverterTest.java b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/app/SchemaToProtoConverterTest.java
new file mode 100644
index 0000000..0d0ec8c
--- /dev/null
+++ b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/app/SchemaToProtoConverterTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2020 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.appsearch.app;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.android.icing.proto.IndexingConfig;
+import com.google.android.icing.proto.PropertyConfigProto;
+import com.google.android.icing.proto.SchemaTypeConfigProto;
+import com.google.android.icing.proto.TermMatchType;
+
+import org.junit.Test;
+
+public class SchemaToProtoConverterTest {
+    @Test
+    public void testGetProto_Email() {
+        AppSearchSchema emailSchema = new AppSearchSchema.Builder("Email")
+                .addProperty(new AppSearchSchema.PropertyConfig.Builder("subject")
+                        .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                        .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                        .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+                        .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                        .build()
+                ).addProperty(new AppSearchSchema.PropertyConfig.Builder("body")
+                        .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                        .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                        .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+                        .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                        .build()
+                ).build();
+
+        SchemaTypeConfigProto expectedEmailProto = SchemaTypeConfigProto.newBuilder()
+                .setSchemaType("Email")
+                .addProperties(PropertyConfigProto.newBuilder()
+                        .setPropertyName("subject")
+                        .setDataType(PropertyConfigProto.DataType.Code.STRING)
+                        .setSchemaType("")
+                        .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+                        .setIndexingConfig(
+                                com.google.android.icing.proto.IndexingConfig.newBuilder()
+                                        .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
+                                        .setTermMatchType(TermMatchType.Code.PREFIX)
+                        )
+                ).addProperties(PropertyConfigProto.newBuilder()
+                        .setPropertyName("body")
+                        .setDataType(PropertyConfigProto.DataType.Code.STRING)
+                        .setSchemaType("")
+                        .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+                        .setIndexingConfig(
+                                com.google.android.icing.proto.IndexingConfig.newBuilder()
+                                        .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
+                                        .setTermMatchType(TermMatchType.Code.PREFIX)
+                        )
+                ).build();
+
+        assertThat(SchemaToProtoConverter.convert(emailSchema)).isEqualTo(expectedEmailProto);
+    }
+
+    @Test
+    public void testGetProto_MusicRecording() {
+        AppSearchSchema musicRecordingSchema = new AppSearchSchema.Builder("MusicRecording")
+                .addProperty(new AppSearchSchema.PropertyConfig.Builder("artist")
+                        .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+                        .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+                        .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+                        .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+                        .build()
+                ).addProperty(new AppSearchSchema.PropertyConfig.Builder("pubDate")
+                        .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+                        .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+                        .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+                        .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+                        .build()
+                ).build();
+
+        SchemaTypeConfigProto expectedMusicRecordingProto = SchemaTypeConfigProto.newBuilder()
+                .setSchemaType("MusicRecording")
+                .addProperties(PropertyConfigProto.newBuilder()
+                        .setPropertyName("artist")
+                        .setDataType(PropertyConfigProto.DataType.Code.STRING)
+                        .setSchemaType("")
+                        .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
+                        .setIndexingConfig(
+                                com.google.android.icing.proto.IndexingConfig.newBuilder()
+                                        .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
+                                        .setTermMatchType(TermMatchType.Code.PREFIX)
+                        )
+                ).addProperties(PropertyConfigProto.newBuilder()
+                        .setPropertyName("pubDate")
+                        .setDataType(PropertyConfigProto.DataType.Code.INT64)
+                        .setSchemaType("")
+                        .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+                        .setIndexingConfig(
+                                com.google.android.icing.proto.IndexingConfig.newBuilder()
+                                        .setTokenizerType(IndexingConfig.TokenizerType.Code.NONE)
+                                        .setTermMatchType(TermMatchType.Code.UNKNOWN)
+                        )
+                ).build();
+
+        assertThat(SchemaToProtoConverter.convert(musicRecordingSchema))
+                .isEqualTo(expectedMusicRecordingProto);
+    }
+}
diff --git a/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/AppSearchImplTest.java b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/AppSearchImplTest.java
index b400c41..046d19d 100644
--- a/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/AppSearchImplTest.java
+++ b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/AppSearchImplTest.java
@@ -21,7 +21,6 @@
 import static org.junit.Assert.assertThrows;
 
 import androidx.appsearch.exceptions.AppSearchException;
-import androidx.test.core.app.ApplicationProvider;
 
 import com.google.android.icing.proto.DocumentProto;
 import com.google.android.icing.proto.GetOptimizeInfoResultProto;
@@ -38,18 +37,21 @@
 import com.google.android.icing.proto.TermMatchType;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
 
 import java.util.Set;
 
 public class AppSearchImplTest {
+    @Rule
+    public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
     private AppSearchImpl mAppSearchImpl;
 
     @Before
     public void setUp() throws Exception {
-        mAppSearchImpl = AppSearchImpl.getInstance();
-        mAppSearchImpl.initialize(ApplicationProvider.getApplicationContext());
-        mAppSearchImpl.reset();
+        mAppSearchImpl = new AppSearchImpl(mTemporaryFolder.newFolder());
+        mAppSearchImpl.initialize();
     }
 
     /**
@@ -226,7 +228,7 @@
     }
 
     @Test
-    public void testQueryEmptyDatabase() throws AppSearchException, InterruptedException {
+    public void testQueryEmptyDatabase() throws Exception {
         SearchResultProto searchResultProto = mAppSearchImpl.query("EmptyDatabase",
                 SearchSpecProto.getDefaultInstance(),
                 ResultSpecProto.getDefaultInstance(), ScoringSpecProto.getDefaultInstance());
@@ -235,8 +237,7 @@
     }
 
     @Test
-    public void testRemoveEmptyDatabase_NoExceptionThrown()
-            throws AppSearchException, InterruptedException {
+    public void testRemoveEmptyDatabase_NoExceptionThrown() throws Exception {
         mAppSearchImpl.removeByType("EmptyDatabase", "FakeType");
         mAppSearchImpl.removeByNamespace("EmptyDatabase", "FakeNamespace");
         mAppSearchImpl.removeAll("EmptyDatabase");
diff --git a/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/LocalBackendTest.java b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/LocalBackendTest.java
new file mode 100644
index 0000000..565470e
--- /dev/null
+++ b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/LocalBackendTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2020 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.appsearch.localbackend;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Test;
+
+public class LocalBackendTest {
+    @Test
+    public void testSameInstance() {
+        LocalBackend b1 = LocalBackend.getInstance(ApplicationProvider.getApplicationContext())
+                .getResultValue();
+        LocalBackend b2 = LocalBackend.getInstance(ApplicationProvider.getApplicationContext())
+                .getResultValue();
+        assertThat(b1).isSameInstanceAs(b2);
+    }
+
+    @Test
+    public void testInitBlocking() {
+        LocalBackend backend = LocalBackend.getInstance(ApplicationProvider.getApplicationContext())
+                .getResultValue();
+        assertThat(backend.isInitialized()).isFalse();
+        Thread t = new Thread(() -> {
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+            backend.initialize().getResultValue();
+        });
+        t.setDaemon(true);
+        t.setName("startInit");
+        long startNs = System.nanoTime();
+        t.start();
+        backend.removeAll("db").getResultValue();
+        long endNs = System.nanoTime();
+        long elapsedMs = (endNs - startNs) / 1000 / 1000;
+        assertThat(elapsedMs).isAtLeast(1000);
+        assertThat(backend.isInitialized()).isTrue();
+    }
+}
diff --git a/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/SnippetTest.java b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/SnippetTest.java
index 258be8a..715b8f6 100644
--- a/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/SnippetTest.java
+++ b/appsearch/local-backend/src/androidTest/java/androidx/appsearch/localbackend/SnippetTest.java
@@ -83,7 +83,7 @@
         for (SearchResultProto.ResultProto proto : searchResultProto.getResultsList()) {
             SearchResults.Result result =
                     SearchResultToProtoConverter.convert(proto);
-            MatchInfo match = result.getMatchInfo().get(0);
+            MatchInfo match = result.getMatches().get(0);
             assertThat(match.getPropertyPath()).isEqualTo(propertyKeyString);
             assertThat(match.getFullText()).isEqualTo(propertyValueString);
             assertThat(match.getExactMatch()).isEqualTo(exactMatch);
@@ -130,7 +130,7 @@
         for (SearchResultProto.ResultProto proto : searchResultProto.getResultsList()) {
             SearchResults.Result result =
                     SearchResultToProtoConverter.convert(proto);
-            assertThat(result.getMatchInfo()).isEqualTo(null);
+            assertThat(result.getMatches()).isEqualTo(null);
         }
     }
 
@@ -193,7 +193,7 @@
             SearchResults.Result result =
                     SearchResultToProtoConverter.convert(proto);
 
-            MatchInfo match1 = result.getMatchInfo().get(0);
+            MatchInfo match1 = result.getMatches().get(0);
             assertThat(match1.getPropertyPath()).isEqualTo("sender.name");
             assertThat(match1.getFullText()).isEqualTo("Test Name Jr.");
             assertThat(match1.getExactMatchPosition()).isEqualTo(
@@ -203,7 +203,7 @@
                     new MatchInfo.MatchRange(/*lower=*/0, /*upper=*/9));
             assertThat(match1.getSnippet()).isEqualTo("Test Name");
 
-            MatchInfo match2 = result.getMatchInfo().get(1);
+            MatchInfo match2 = result.getMatches().get(1);
             assertThat(match2.getPropertyPath()).isEqualTo("sender.email");
             assertThat(match2.getFullText()).isEqualTo("TestNameJr@gmail.com");
             assertThat(match2.getExactMatchPosition()).isEqualTo(
diff --git a/appsearch/local-backend/src/main/java/androidx/appsearch/app/GenericDocumentToProtoConverter.java b/appsearch/local-backend/src/main/java/androidx/appsearch/app/GenericDocumentToProtoConverter.java
index 325f25a..155dde5 100644
--- a/appsearch/local-backend/src/main/java/androidx/appsearch/app/GenericDocumentToProtoConverter.java
+++ b/appsearch/local-backend/src/main/java/androidx/appsearch/app/GenericDocumentToProtoConverter.java
@@ -16,11 +16,18 @@
 
 package androidx.appsearch.app;
 
+import android.os.Bundle;
+
 import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 import androidx.core.util.Preconditions;
 
 import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.PropertyProto;
+import com.google.android.icing.protobuf.ByteString;
+
+import java.util.ArrayList;
+import java.util.Collections;
 
 /**
  * Translates a {@link GenericDocument} into a {@link DocumentProto}.
@@ -32,15 +39,112 @@
 
     /** Converts a {@link GenericDocument} into a {@link DocumentProto}. */
     @NonNull
+    @SuppressWarnings("unchecked")
     public static DocumentProto convert(@NonNull GenericDocument document) {
         Preconditions.checkNotNull(document);
-        return document.getProto();
+        DocumentProto.Builder mProtoBuilder = DocumentProto.newBuilder();
+        mProtoBuilder.setUri(document.getUri())
+                .setSchema(document.getSchemaType())
+                .setNamespace(document.getNamespace())
+                .setScore(document.getScore())
+                .setTtlMs(document.getTtlMillis())
+                .setCreationTimestampMs(document.getCreationTimestampMillis());
+        ArrayList<String> keys = new ArrayList<>(document.mProperties.keySet());
+        Collections.sort(keys);
+        for (int i = 0; i < keys.size(); i++) {
+            String name = keys.get(i);
+            Object values = document.mProperties.get(name);
+            PropertyProto.Builder propertyProto = PropertyProto.newBuilder().setName(name);
+            if (values instanceof boolean[]) {
+                for (boolean value : (boolean[]) values) {
+                    propertyProto.addBooleanValues(value);
+                }
+            } else if (values instanceof long[]) {
+                for (long value : (long[]) values) {
+                    propertyProto.addInt64Values(value);
+                }
+            } else if (values instanceof double[]) {
+                for (double value : (double[]) values) {
+                    propertyProto.addDoubleValues(value);
+                }
+            } else if (values instanceof String[]) {
+                for (String value : (String[]) values) {
+                    propertyProto.addStringValues(value);
+                }
+            } else if (values instanceof ArrayList) {
+                for (Bundle bundle : (ArrayList<Bundle>) values) {
+                    propertyProto.addBytesValues(ByteString.copyFrom(
+                            bundle.getByteArray(GenericDocument.BYTE_ARRAY_FIELD)));
+                }
+            } else if (values instanceof Bundle[]) {
+                for (Bundle bundle : (Bundle[]) values) {
+                    propertyProto.addDocumentValues(convert(new GenericDocument(bundle)));
+                }
+            } else {
+                throw new IllegalStateException(
+                        "Property \"" + name + "\" has unsupported value type \""
+                                + values.getClass().getSimpleName() + "\"");
+            }
+            mProtoBuilder.addProperties(propertyProto);
+        }
+        return mProtoBuilder.build();
     }
 
     /** Converts a {@link DocumentProto} into a {@link GenericDocument}. */
     @NonNull
     public static GenericDocument convert(@NonNull DocumentProto proto) {
         Preconditions.checkNotNull(proto);
-        return new GenericDocument(proto);
+        GenericDocument.Builder documentBuilder =
+                new GenericDocument.Builder<>(proto.getUri(), proto.getSchema())
+                        .setNamespace(proto.getNamespace())
+                        .setScore(proto.getScore())
+                        .setTtlMillis(proto.getTtlMs())
+                        .setCreationTimestampMillis(proto.getCreationTimestampMs());
+
+        for (int i = 0; i < proto.getPropertiesCount(); i++) {
+            PropertyProto property = proto.getProperties(i);
+            String name = property.getName();
+            if (property.getBooleanValuesCount() > 0) {
+                boolean[] values = new boolean[property.getBooleanValuesCount()];
+                for (int j = 0; j < values.length; j++) {
+                    values[j] = property.getBooleanValues(j);
+                }
+                documentBuilder.setProperty(name, values);
+            } else if (property.getInt64ValuesCount() > 0) {
+                long[] values = new long[property.getInt64ValuesCount()];
+                for (int j = 0; j < values.length; j++) {
+                    values[j] = property.getInt64Values(j);
+                }
+                documentBuilder.setProperty(name, values);
+            } else if (property.getDoubleValuesCount() > 0) {
+                double[] values = new double[property.getDoubleValuesCount()];
+                for (int j = 0; j < values.length; j++) {
+                    values[j] = property.getDoubleValues(j);
+                }
+                documentBuilder.setProperty(name, values);
+            } else if (property.getStringValuesCount() > 0) {
+                String[] values = new String[property.getStringValuesCount()];
+                for (int j = 0; j < values.length; j++) {
+                    values[j] = property.getStringValues(j);
+                }
+                documentBuilder.setProperty(name, values);
+            } else if (property.getBytesValuesCount() > 0) {
+                byte[][] values = new byte[property.getBytesValuesCount()][];
+                for (int j = 0; j < values.length; j++) {
+                    values[j] = property.getBytesValues(j).toByteArray();
+                }
+                documentBuilder.setProperty(name, values);
+            } else if (property.getDocumentValuesCount() > 0) {
+                GenericDocument[] values =
+                        new GenericDocument[property.getDocumentValuesCount()];
+                for (int j = 0; j < values.length; j++) {
+                    values[j] = new GenericDocument(convert(property.getDocumentValues(j)));
+                }
+                documentBuilder.setProperty(name, values);
+            } else {
+                throw new IllegalStateException("Unknown type of value: " + name);
+            }
+        }
+        return documentBuilder.build();
     }
 }
diff --git a/appsearch/local-backend/src/main/java/androidx/appsearch/app/SearchSpecToProtoConverter.java b/appsearch/local-backend/src/main/java/androidx/appsearch/app/SearchSpecToProtoConverter.java
index 00cb905d..1250f37 100644
--- a/appsearch/local-backend/src/main/java/androidx/appsearch/app/SearchSpecToProtoConverter.java
+++ b/appsearch/local-backend/src/main/java/androidx/appsearch/app/SearchSpecToProtoConverter.java
@@ -71,9 +71,9 @@
                 .setNumPerPage(bundle.getInt(
                         SearchSpec.NUM_PER_PAGE_FIELD, SearchSpec.DEFAULT_NUM_PER_PAGE))
                 .setSnippetSpec(ResultSpecProto.SnippetSpecProto.newBuilder()
-                        .setNumToSnippet(bundle.getInt(SearchSpec.NUM_TO_SNIPPET_FIELD))
+                        .setNumToSnippet(bundle.getInt(SearchSpec.SNIPPET_COUNT_FIELD))
                         .setNumMatchesPerProperty(
-                                bundle.getInt(SearchSpec.NUM_MATCHED_PER_PROPERTY_FIELD))
+                                bundle.getInt(SearchSpec.SNIPPET_COUNT_PER_PROPERTY_FIELD))
                         .setMaxWindowBytes(bundle.getInt(SearchSpec.MAX_SNIPPET_FIELD)))
                 .build();
 
diff --git a/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/AppSearchImpl.java b/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/AppSearchImpl.java
index ddd3b91..30acc31 100644
--- a/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/AppSearchImpl.java
+++ b/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/AppSearchImpl.java
@@ -16,14 +16,15 @@
 
 package androidx.appsearch.localbackend;
 
-import android.content.Context;
 import android.util.Log;
 
+import androidx.annotation.AnyThread;
 import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
 import androidx.appsearch.app.AppSearchResult;
 import androidx.appsearch.exceptions.AppSearchException;
 
@@ -52,66 +53,67 @@
 import com.google.android.icing.proto.SetSchemaResultProto;
 import com.google.android.icing.proto.StatusProto;
 
-import java.io.IOException;
+import java.io.File;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
-
 /**
  * Manages interaction with the native IcingSearchEngine and other components to implement AppSearch
  * functionality.
  *
- * <p>Callers should use {@link #getInstance} to retrieve the singleton instance and call
- * {@link #initialize} before using the class.
+ * <p>Callers should call {@link #initialize} before using the AppSearchImpl instance. Never create
+ * two instances using the same folder.
  *
- * <p>The singleton instance of {@link AppSearchImpl} supports all instances of
- * {@link androidx.appsearch.app.AppSearchManager} with different database name. All logically
- * isolated schemas and documents will be physically saved together in IcingSearchEngine.
- * The way to isolated those schemas and documents for different database:
+ * <p>A single instance of {@link AppSearchImpl} can support all databases. Schemas and documents
+ * are physically saved together in {@link IcingSearchEngine}, but logically isolated:
  * <ul>
  *      <li>Rewrite SchemaType in SchemaProto by adding database name prefix and save into
- *          SchemaTypes set in {@link #setSchema(String, SchemaProto, boolean)}.
+ *          SchemaTypes set in {@link #setSchema}.
  *      <li>Rewrite namespace and SchemaType in DocumentProto by adding database name prefix and
- *          save to namespaces set in {@link #putDocument(String, DocumentProto)}.
- *      <li>Remove database name prefix when retrieve documents in
- *          {@link #getDocument(String, String, String)}, and
- *          {@link #query(String, SearchSpecProto, ResultSpecProto, ScoringSpecProto)}.
+ *          save to namespaces set in {@link #putDocument}.
+ *      <li>Remove database name prefix when retrieve documents in {@link #getDocument} and
+ *          {@link #query}.
  *      <li>Rewrite filters in {@link SearchSpecProto} to have all namespaces and schema types of
- *          the queried database when user using empty filters in
- *          {@link #query(String, SearchSpecProto, ResultSpecProto, ScoringSpecProto)}.
+ *          the queried database when user using empty filters in {@link #query}.
  * </ul>
  *
  * <p>Methods in this class belong to two groups, the query group and the mutate group.
  * <ul>
- *     <li>All methods are going to modify global parameters and data in Icing should be executed
- *     under WRITE lock to keep thread safety.
- *     <li>All methods are going to access global parameters or query data from Icing
- *     should be executed under READ lock to improve query performance.
+ *     <li>All methods are going to modify global parameters and data in Icing are executed under
+ *         WRITE lock to keep thread safety.
+ *     <li>All methods are going to access global parameters or query data from Icing are executed
+ *         under READ lock to improve query performance.
  * </ul>
+ *
+ * <p>This class is thread safe.
  * @hide
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+@WorkerThread
 public final class AppSearchImpl {
-    private static volatile AppSearchImpl sInstance;
     private static final String TAG = "AppSearchImpl";
-    private static final String ICING_DIR = "/icing";
+
     @VisibleForTesting
     static final int OPTIMIZE_THRESHOLD_DOC_COUNT = 1000;
     @VisibleForTesting
     static final int OPTIMIZE_THRESHOLD_BYTES = 1_000_000; // 1MB
     @VisibleForTesting
     static final int CHECK_OPTIMIZE_INTERVAL = 100;
-    private final ReentrantReadWriteLock mReadWriteLock = new ReentrantReadWriteLock();
+
+    private final ReadWriteLock mReadWriteLock = new ReentrantReadWriteLock();
     private final CountDownLatch mInitCompleteLatch = new CountDownLatch(1);
+    private final File mIcingDir;
+    private IcingSearchEngine mIcingSearchEngine;
+
     // The map contains schemaTypes and namespaces for all database. All values in the map have
     // been already added database name prefix.
-    private final HashMap<String, Set<String>> mSchemaMap = new HashMap<>();
-    private final HashMap<String, Set<String>> mNamespaceMap = new HashMap<>();
-    private IcingSearchEngine mIcingSearchEngine;
-    private volatile boolean mInitialized = false;
+    private final Map<String, Set<String>> mSchemaMap = new HashMap<>();
+    private final Map<String, Set<String>> mNamespaceMap = new HashMap<>();
 
     /**
      * The counter to check when to call {@link #checkForOptimize(boolean)}. The interval is
@@ -119,20 +121,10 @@
      */
     private int mOptimizeIntervalCount = 0;
 
-    /** Gets the singleton instance of {@link AppSearchImpl} */
-    @NonNull
-    public static AppSearchImpl getInstance() {
-        if (sInstance == null) {
-            synchronized (AppSearchImpl.class) {
-                if (sInstance == null) {
-                    sInstance = new AppSearchImpl();
-                }
-            }
-        }
-        return sInstance;
-    }
-
-    private AppSearchImpl() {
+    /** Creates an instance of {@link AppSearchImpl} which writes data to the given folder. */
+    @AnyThread
+    public AppSearchImpl(@NonNull File icingDir) {
+        mIcingDir = icingDir;
     }
 
     /**
@@ -140,10 +132,9 @@
      *
      * <p>This method belongs to mutate group.
      *
-     * @throws IOException        on error opening directory.
      * @throws AppSearchException on IcingSearchEngine error.
      */
-    public void initialize(@NonNull Context context) throws IOException, AppSearchException {
+    public void initialize() throws AppSearchException {
         if (isInitialized()) {
             return;
         }
@@ -155,9 +146,8 @@
             if (isInitialized()) {
                 return;
             }
-
-            IcingSearchEngineOptions options = IcingSearchEngineOptions.newBuilder().setBaseDir(
-                    context.getFilesDir().getCanonicalPath() + ICING_DIR).build();
+            IcingSearchEngineOptions options = IcingSearchEngineOptions.newBuilder()
+                    .setBaseDir(mIcingDir.getAbsolutePath()).build();
             mIcingSearchEngine = new IcingSearchEngine(options);
 
             InitializeResultProto initializeResultProto = mIcingSearchEngine.initialize();
@@ -180,7 +170,6 @@
             for (String qualifiedNamespace : getAllNamespacesResultProto.getNamespacesList()) {
                 addToMap(mNamespaceMap, getDatabaseName(qualifiedNamespace), qualifiedNamespace);
             }
-            mInitialized = true;
             mInitCompleteLatch.countDown();
             if (!isReset) {
                 checkForOptimize(/* force= */ true);
@@ -191,8 +180,9 @@
     }
 
     /** Checks if the internal state of {@link AppSearchImpl} has been initialized. */
+    @AnyThread
     public boolean isInitialized() {
-        return mInitialized;
+        return mInitCompleteLatch.getCount() == 0;
     }
 
     /**
@@ -209,7 +199,7 @@
      */
     public void setSchema(@NonNull String databaseName, @NonNull SchemaProto origSchema,
             boolean forceOverride) throws AppSearchException, InterruptedException {
-        checkInitialized();
+        awaitInitialized();
 
         SchemaProto schemaProto = getSchemaProto();
 
@@ -251,7 +241,7 @@
      */
     public void putDocument(@NonNull String databaseName, @NonNull DocumentProto document)
             throws AppSearchException, InterruptedException {
-        checkInitialized();
+        awaitInitialized();
 
         DocumentProto.Builder documentBuilder = document.toBuilder();
         rewriteDocumentTypes(getDatabasePrefix(databaseName), documentBuilder, /*add=*/ true);
@@ -285,7 +275,7 @@
     @Nullable
     public DocumentProto getDocument(@NonNull String databaseName, @NonNull String namespace,
             @NonNull String uri) throws AppSearchException, InterruptedException {
-        checkInitialized();
+        awaitInitialized();
         GetResultProto getResultProto;
         mReadWriteLock.readLock().lock();
         try {
@@ -321,7 +311,7 @@
             @NonNull SearchSpecProto searchSpec,
             @NonNull ResultSpecProto resultSpec,
             @NonNull ScoringSpecProto scoringSpec) throws AppSearchException, InterruptedException {
-        checkInitialized();
+        awaitInitialized();
 
         SearchSpecProto.Builder searchSpecBuilder = searchSpec.toBuilder();
         SearchResultProto searchResultProto;
@@ -362,7 +352,7 @@
     @NonNull
     public SearchResultProto getNextPage(@NonNull String databaseName, long nextPageToken)
             throws AppSearchException, InterruptedException {
-        checkInitialized();
+        awaitInitialized();
 
         SearchResultProto searchResultProto = mIcingSearchEngine.getNextPage(nextPageToken);
         checkSuccess(searchResultProto.getStatus());
@@ -377,10 +367,8 @@
      * @param nextPageToken The token of pre-loaded results of previously executed query to be
      *                      Invalidated.
      */
-    public void invalidateNextPageToken(long nextPageToken)
-            throws AppSearchException, InterruptedException {
-        checkInitialized();
-
+    public void invalidateNextPageToken(long nextPageToken) throws InterruptedException {
+        awaitInitialized();
         mIcingSearchEngine.invalidateNextPageToken(nextPageToken);
     }
 
@@ -397,7 +385,7 @@
      */
     public void remove(@NonNull String databaseName, @NonNull String namespace,
             @NonNull String uri) throws AppSearchException, InterruptedException {
-        checkInitialized();
+        awaitInitialized();
 
         String qualifiedNamespace = getDatabasePrefix(databaseName) + namespace;
         DeleteResultProto deleteResultProto;
@@ -423,7 +411,7 @@
      */
     public void removeByType(@NonNull String databaseName, @NonNull String schemaType)
             throws AppSearchException, InterruptedException {
-        checkInitialized();
+        awaitInitialized();
 
         String qualifiedType = getDatabasePrefix(databaseName) + schemaType;
         DeleteBySchemaTypeResultProto deleteBySchemaTypeResultProto;
@@ -453,7 +441,7 @@
      */
     public void removeByNamespace(@NonNull String databaseName, @NonNull String namespace)
             throws AppSearchException, InterruptedException {
-        checkInitialized();
+        awaitInitialized();
 
         String qualifiedNamespace = getDatabasePrefix(databaseName) + namespace;
         DeleteByNamespaceResultProto deleteByNamespaceResultProto;
@@ -485,7 +473,7 @@
      */
     public void removeAll(@NonNull String databaseName)
             throws AppSearchException, InterruptedException {
-        checkInitialized();
+        awaitInitialized();
         mReadWriteLock.writeLock().lock();
         try {
             Set<String> existingNamespaces = mNamespaceMap.get(databaseName);
@@ -518,8 +506,6 @@
      */
     @VisibleForTesting
     public void reset() throws AppSearchException {
-        // Clear data from IcingSearchEngine.
-
         ResetResultProto resetResultProto;
         mReadWriteLock.writeLock().lock();
         try {
@@ -662,8 +648,6 @@
      * safety.
      * @return false if the current database is brand new and contains nothing. We should just
      * return an empty query result to user.
-     * @throws AppSearchException if there is no schema type or document has been saved in this
-     * database.
      */
     @VisibleForTesting
     @GuardedBy("mReadWriteLock")
@@ -739,8 +723,7 @@
     }
 
     @GuardedBy("mReadWriteLock")
-    private void addToMap(HashMap<String, Set<String>> map, String databaseName,
-            String prefixedValue) {
+    private void addToMap(Map<String, Set<String>> map, String databaseName, String prefixedValue) {
         Set<String> values = map.get(databaseName);
         if (values == null) {
             values = new HashSet<>();
@@ -750,17 +733,12 @@
     }
 
     /**
-     * Ensure the instance is intialized.
+     * Waits for the instance to become initialized.
      *
-     * @throws AppSearchException if not.
-     * @throws InterruptedException if the current thread was interrupted during execution.
+     * @throws InterruptedException if the current thread was interrupted during waiting.
      */
-    private void checkInitialized() throws AppSearchException, InterruptedException {
+    private void awaitInitialized() throws InterruptedException {
         mInitCompleteLatch.await();
-        if (!isInitialized()) {
-            throw new AppSearchException(AppSearchResult.RESULT_INTERNAL_ERROR,
-                    "Accessing an uninitialized AppSearchImpl");
-        }
     }
 
     /**
diff --git a/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/LocalBackend.java b/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/LocalBackend.java
index 426adb2..ef1329d 100644
--- a/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/LocalBackend.java
+++ b/appsearch/local-backend/src/main/java/androidx/appsearch/localbackend/LocalBackend.java
@@ -17,9 +17,11 @@
 package androidx.appsearch.localbackend;
 
 import static androidx.appsearch.app.AppSearchResult.newFailedResult;
+import static androidx.appsearch.app.AppSearchResult.newSuccessfulResult;
 
 import android.content.Context;
 
+import androidx.annotation.AnyThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.VisibleForTesting;
@@ -44,6 +46,7 @@
 import com.google.android.icing.proto.SearchResultProto;
 import com.google.android.icing.proto.SearchSpecProto;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.List;
 
@@ -54,35 +57,38 @@
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public class LocalBackend implements AppSearchBackend {
-    private final Context mContext;
+    private static final String ICING_DIR = "icing";
+
+    private static volatile AppSearchResult<LocalBackend> sInstance;
+
     final AppSearchImpl mAppSearchImpl;
 
-    /** Builder class for {@link LocalBackend} objects. */
-    public static final class Builder {
-        private final Context mContext;
-        private boolean mBuilt = false;
-
-        /** Constructs a new Builder with default settings using the provided {@code context}. */
-        public Builder(@NonNull Context context) {
-            Preconditions.checkNotNull(context);
-            mContext = context;
+    /**
+     * Returns an instance of {@link LocalBackend}.
+     *
+     * <p>If no instance exists, one will be created using the provided {@code context}, but not
+     * initialized.
+     *
+     * <p>You must call {@link #initialize} before using it.
+     */
+    @AnyThread
+    @NonNull
+    public static AppSearchResult<LocalBackend> getInstance(@NonNull Context context) {
+        Preconditions.checkNotNull(context);
+        if (sInstance == null) {
+            synchronized (LocalBackend.class) {
+                if (sInstance == null) {
+                    File icingDir = new File(context.getFilesDir(), ICING_DIR);
+                    sInstance = newSuccessfulResult(new LocalBackend(icingDir));
+                }
+            }
         }
-
-        /**
-         * Connects to the AppSearch database per this builder's configuration, and asynchronously
-         * returns the initialized instance.
-         */
-        @NonNull
-        public AppSearchResult<LocalBackend> build() {
-            Preconditions.checkState(!mBuilt, "Builder has already been used");
-            mBuilt = true;
-            return AppSearchResult.newSuccessfulResult(new LocalBackend(mContext));
-        }
+        return sInstance;
     }
 
-    LocalBackend(@NonNull Context context) {
-        mContext = context;
-        mAppSearchImpl = AppSearchImpl.getInstance();
+    @AnyThread
+    private LocalBackend(@NonNull File icingDir) {
+        mAppSearchImpl = new AppSearchImpl(icingDir);
     }
 
     @Override
@@ -95,7 +101,7 @@
     public AppSearchResult<Void> initialize() {
         if (!mAppSearchImpl.isInitialized()) {
             try {
-                mAppSearchImpl.initialize(mContext);
+                mAppSearchImpl.initialize();
             } catch (Throwable t) {
                 return throwableToFailedResult(t);
             }
@@ -347,7 +353,7 @@
         public void close() throws IOException {
             try {
                 mAppSearchImpl.invalidateNextPageToken(mNextPageToken);
-            } catch (AppSearchException | InterruptedException e) {
+            } catch (InterruptedException e) {
                 throw new IOException(e);
             }
         }
diff --git a/autofill/autofill/api/1.1.0-beta01.txt b/autofill/autofill/api/1.1.0-beta01.txt
new file mode 100644
index 0000000..98cfd23
--- /dev/null
+++ b/autofill/autofill/api/1.1.0-beta01.txt
@@ -0,0 +1,180 @@
+// Signature format: 3.0
+package androidx.autofill {
+
+  public final class HintConstants {
+    method public static String generateSmsOtpHintForCharacterPosition(int);
+    field public static final String AUTOFILL_HINT_BIRTH_DATE_DAY = "birthDateDay";
+    field public static final String AUTOFILL_HINT_BIRTH_DATE_FULL = "birthDateFull";
+    field public static final String AUTOFILL_HINT_BIRTH_DATE_MONTH = "birthDateMonth";
+    field public static final String AUTOFILL_HINT_BIRTH_DATE_YEAR = "birthDateYear";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = "creditCardExpirationDate";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = "creditCardExpirationMonth";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = "creditCardExpirationYear";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode";
+    field public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress";
+    field public static final String AUTOFILL_HINT_GENDER = "gender";
+    field @Deprecated public static final String AUTOFILL_HINT_NAME = "name";
+    field public static final String AUTOFILL_HINT_NEW_PASSWORD = "newPassword";
+    field public static final String AUTOFILL_HINT_NEW_USERNAME = "newUsername";
+    field public static final String AUTOFILL_HINT_PASSWORD = "password";
+    field public static final String AUTOFILL_HINT_PERSON_NAME = "personName";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_FAMILY = "personFamilyName";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_GIVEN = "personGivenName";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_MIDDLE = "personMiddleName";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_MIDDLE_INITIAL = "personMiddleInitial";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_PREFIX = "personNamePrefix";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_SUFFIX = "personNameSuffix";
+    field @Deprecated public static final String AUTOFILL_HINT_PHONE = "phone";
+    field public static final String AUTOFILL_HINT_PHONE_COUNTRY_CODE = "phoneCountryCode";
+    field public static final String AUTOFILL_HINT_PHONE_NATIONAL = "phoneNational";
+    field public static final String AUTOFILL_HINT_PHONE_NUMBER = "phoneNumber";
+    field public static final String AUTOFILL_HINT_PHONE_NUMBER_DEVICE = "phoneNumberDevice";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_COUNTRY = "addressCountry";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_ADDRESS = "extendedAddress";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_POSTAL_CODE = "extendedPostalCode";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_LOCALITY = "addressLocality";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_REGION = "addressRegion";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_STREET_ADDRESS = "streetAddress";
+    field public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode";
+    field public static final String AUTOFILL_HINT_SMS_OTP = "smsOTPCode";
+    field public static final String AUTOFILL_HINT_USERNAME = "username";
+  }
+
+}
+
+package androidx.autofill.inline {
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class Renderer {
+    method public static android.app.PendingIntent? getAttributionIntent(android.app.slice.Slice);
+    method public static android.os.Bundle getSupportedInlineUiVersionsAsBundle();
+    method public static android.view.View? render(android.content.Context, android.app.slice.Slice, android.os.Bundle);
+  }
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class SuggestionHintConstants {
+    field public static final String SUGGESTION_HINT_CLIPBOARD_CONTENT = "clipboardContent";
+    field public static final String SUGGESTION_HINT_SMART_REPLY = "smartReply";
+  }
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class UiVersions {
+    method public static java.util.List<java.lang.String!> getVersions(android.os.Bundle);
+    method public static androidx.autofill.inline.UiVersions.StylesBuilder newStylesBuilder();
+    field public static final String INLINE_UI_VERSION_1 = "androidx.autofill.inline.ui.version:v1";
+  }
+
+  public static interface UiVersions.Content {
+    method public android.app.slice.Slice getSlice();
+  }
+
+  public static interface UiVersions.Style {
+  }
+
+  public static final class UiVersions.StylesBuilder {
+    method public androidx.autofill.inline.UiVersions.StylesBuilder addStyle(androidx.autofill.inline.UiVersions.Style);
+    method public android.os.Bundle build();
+  }
+
+}
+
+package androidx.autofill.inline.common {
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class ImageViewStyle extends androidx.autofill.inline.common.ViewStyle {
+  }
+
+  public static final class ImageViewStyle.Builder {
+    ctor public ImageViewStyle.Builder();
+    method public androidx.autofill.inline.common.ImageViewStyle build();
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setBackgroundColor(int);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setLayoutMargin(int, int, int, int);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setMaxHeight(int);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setMaxWidth(int);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setPadding(int, int, int, int);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setScaleType(android.widget.ImageView.ScaleType);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setTintList(android.content.res.ColorStateList);
+  }
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class TextViewStyle extends androidx.autofill.inline.common.ViewStyle {
+  }
+
+  public static final class TextViewStyle.Builder {
+    ctor public TextViewStyle.Builder();
+    method public androidx.autofill.inline.common.TextViewStyle build();
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setBackgroundColor(int);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setLayoutMargin(int, int, int, int);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setPadding(int, int, int, int);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setTextColor(@ColorInt int);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setTextSize(float);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setTextSize(int, float);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setTypeface(String, int);
+  }
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public class ViewStyle {
+  }
+
+  public static final class ViewStyle.Builder {
+    ctor public ViewStyle.Builder();
+    method public androidx.autofill.inline.common.ViewStyle build();
+    method public androidx.autofill.inline.common.ViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+    method public androidx.autofill.inline.common.ViewStyle.Builder setBackgroundColor(int);
+    method public androidx.autofill.inline.common.ViewStyle.Builder setLayoutMargin(int, int, int, int);
+    method public androidx.autofill.inline.common.ViewStyle.Builder setPadding(int, int, int, int);
+  }
+
+}
+
+package androidx.autofill.inline.v1 {
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class InlineSuggestionUi {
+    method public static androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder newContentBuilder(android.app.PendingIntent);
+    method public static androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder newStyleBuilder();
+  }
+
+  public static final class InlineSuggestionUi.Content implements androidx.autofill.inline.UiVersions.Content {
+    method public android.app.PendingIntent? getAttributionIntent();
+    method public CharSequence? getContentDescription();
+    method public android.graphics.drawable.Icon? getEndIcon();
+    method public final android.app.slice.Slice getSlice();
+    method public android.graphics.drawable.Icon? getStartIcon();
+    method public CharSequence? getSubtitle();
+    method public CharSequence? getTitle();
+  }
+
+  public static final class InlineSuggestionUi.Content.Builder {
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content build();
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setContentDescription(CharSequence);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setEndIcon(android.graphics.drawable.Icon);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setHints(java.util.List<java.lang.String!>);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setStartIcon(android.graphics.drawable.Icon);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setSubtitle(CharSequence);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setTitle(CharSequence);
+  }
+
+  public static final class InlineSuggestionUi.Style implements androidx.autofill.inline.UiVersions.Style {
+    method public androidx.autofill.inline.common.ViewStyle? getChipStyle();
+    method public androidx.autofill.inline.common.ImageViewStyle? getEndIconStyle();
+    method public int getLayoutDirection();
+    method public androidx.autofill.inline.common.ImageViewStyle? getSingleIconChipIconStyle();
+    method public androidx.autofill.inline.common.ViewStyle? getSingleIconChipStyle();
+    method public androidx.autofill.inline.common.ImageViewStyle? getStartIconStyle();
+    method public androidx.autofill.inline.common.TextViewStyle? getSubtitleStyle();
+    method public androidx.autofill.inline.common.TextViewStyle? getTitleStyle();
+  }
+
+  public static final class InlineSuggestionUi.Style.Builder {
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style build();
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setChipStyle(androidx.autofill.inline.common.ViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setEndIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setLayoutDirection(int);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSingleIconChipIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSingleIconChipStyle(androidx.autofill.inline.common.ViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setStartIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSubtitleStyle(androidx.autofill.inline.common.TextViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setTitleStyle(androidx.autofill.inline.common.TextViewStyle);
+  }
+
+}
+
diff --git a/autofill/autofill/api/public_plus_experimental_1.1.0-beta01.txt b/autofill/autofill/api/public_plus_experimental_1.1.0-beta01.txt
new file mode 100644
index 0000000..98cfd23
--- /dev/null
+++ b/autofill/autofill/api/public_plus_experimental_1.1.0-beta01.txt
@@ -0,0 +1,180 @@
+// Signature format: 3.0
+package androidx.autofill {
+
+  public final class HintConstants {
+    method public static String generateSmsOtpHintForCharacterPosition(int);
+    field public static final String AUTOFILL_HINT_BIRTH_DATE_DAY = "birthDateDay";
+    field public static final String AUTOFILL_HINT_BIRTH_DATE_FULL = "birthDateFull";
+    field public static final String AUTOFILL_HINT_BIRTH_DATE_MONTH = "birthDateMonth";
+    field public static final String AUTOFILL_HINT_BIRTH_DATE_YEAR = "birthDateYear";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = "creditCardExpirationDate";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = "creditCardExpirationMonth";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = "creditCardExpirationYear";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode";
+    field public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress";
+    field public static final String AUTOFILL_HINT_GENDER = "gender";
+    field @Deprecated public static final String AUTOFILL_HINT_NAME = "name";
+    field public static final String AUTOFILL_HINT_NEW_PASSWORD = "newPassword";
+    field public static final String AUTOFILL_HINT_NEW_USERNAME = "newUsername";
+    field public static final String AUTOFILL_HINT_PASSWORD = "password";
+    field public static final String AUTOFILL_HINT_PERSON_NAME = "personName";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_FAMILY = "personFamilyName";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_GIVEN = "personGivenName";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_MIDDLE = "personMiddleName";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_MIDDLE_INITIAL = "personMiddleInitial";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_PREFIX = "personNamePrefix";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_SUFFIX = "personNameSuffix";
+    field @Deprecated public static final String AUTOFILL_HINT_PHONE = "phone";
+    field public static final String AUTOFILL_HINT_PHONE_COUNTRY_CODE = "phoneCountryCode";
+    field public static final String AUTOFILL_HINT_PHONE_NATIONAL = "phoneNational";
+    field public static final String AUTOFILL_HINT_PHONE_NUMBER = "phoneNumber";
+    field public static final String AUTOFILL_HINT_PHONE_NUMBER_DEVICE = "phoneNumberDevice";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_COUNTRY = "addressCountry";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_ADDRESS = "extendedAddress";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_POSTAL_CODE = "extendedPostalCode";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_LOCALITY = "addressLocality";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_REGION = "addressRegion";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_STREET_ADDRESS = "streetAddress";
+    field public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode";
+    field public static final String AUTOFILL_HINT_SMS_OTP = "smsOTPCode";
+    field public static final String AUTOFILL_HINT_USERNAME = "username";
+  }
+
+}
+
+package androidx.autofill.inline {
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class Renderer {
+    method public static android.app.PendingIntent? getAttributionIntent(android.app.slice.Slice);
+    method public static android.os.Bundle getSupportedInlineUiVersionsAsBundle();
+    method public static android.view.View? render(android.content.Context, android.app.slice.Slice, android.os.Bundle);
+  }
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class SuggestionHintConstants {
+    field public static final String SUGGESTION_HINT_CLIPBOARD_CONTENT = "clipboardContent";
+    field public static final String SUGGESTION_HINT_SMART_REPLY = "smartReply";
+  }
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class UiVersions {
+    method public static java.util.List<java.lang.String!> getVersions(android.os.Bundle);
+    method public static androidx.autofill.inline.UiVersions.StylesBuilder newStylesBuilder();
+    field public static final String INLINE_UI_VERSION_1 = "androidx.autofill.inline.ui.version:v1";
+  }
+
+  public static interface UiVersions.Content {
+    method public android.app.slice.Slice getSlice();
+  }
+
+  public static interface UiVersions.Style {
+  }
+
+  public static final class UiVersions.StylesBuilder {
+    method public androidx.autofill.inline.UiVersions.StylesBuilder addStyle(androidx.autofill.inline.UiVersions.Style);
+    method public android.os.Bundle build();
+  }
+
+}
+
+package androidx.autofill.inline.common {
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class ImageViewStyle extends androidx.autofill.inline.common.ViewStyle {
+  }
+
+  public static final class ImageViewStyle.Builder {
+    ctor public ImageViewStyle.Builder();
+    method public androidx.autofill.inline.common.ImageViewStyle build();
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setBackgroundColor(int);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setLayoutMargin(int, int, int, int);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setMaxHeight(int);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setMaxWidth(int);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setPadding(int, int, int, int);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setScaleType(android.widget.ImageView.ScaleType);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setTintList(android.content.res.ColorStateList);
+  }
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class TextViewStyle extends androidx.autofill.inline.common.ViewStyle {
+  }
+
+  public static final class TextViewStyle.Builder {
+    ctor public TextViewStyle.Builder();
+    method public androidx.autofill.inline.common.TextViewStyle build();
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setBackgroundColor(int);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setLayoutMargin(int, int, int, int);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setPadding(int, int, int, int);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setTextColor(@ColorInt int);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setTextSize(float);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setTextSize(int, float);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setTypeface(String, int);
+  }
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public class ViewStyle {
+  }
+
+  public static final class ViewStyle.Builder {
+    ctor public ViewStyle.Builder();
+    method public androidx.autofill.inline.common.ViewStyle build();
+    method public androidx.autofill.inline.common.ViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+    method public androidx.autofill.inline.common.ViewStyle.Builder setBackgroundColor(int);
+    method public androidx.autofill.inline.common.ViewStyle.Builder setLayoutMargin(int, int, int, int);
+    method public androidx.autofill.inline.common.ViewStyle.Builder setPadding(int, int, int, int);
+  }
+
+}
+
+package androidx.autofill.inline.v1 {
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class InlineSuggestionUi {
+    method public static androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder newContentBuilder(android.app.PendingIntent);
+    method public static androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder newStyleBuilder();
+  }
+
+  public static final class InlineSuggestionUi.Content implements androidx.autofill.inline.UiVersions.Content {
+    method public android.app.PendingIntent? getAttributionIntent();
+    method public CharSequence? getContentDescription();
+    method public android.graphics.drawable.Icon? getEndIcon();
+    method public final android.app.slice.Slice getSlice();
+    method public android.graphics.drawable.Icon? getStartIcon();
+    method public CharSequence? getSubtitle();
+    method public CharSequence? getTitle();
+  }
+
+  public static final class InlineSuggestionUi.Content.Builder {
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content build();
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setContentDescription(CharSequence);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setEndIcon(android.graphics.drawable.Icon);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setHints(java.util.List<java.lang.String!>);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setStartIcon(android.graphics.drawable.Icon);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setSubtitle(CharSequence);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setTitle(CharSequence);
+  }
+
+  public static final class InlineSuggestionUi.Style implements androidx.autofill.inline.UiVersions.Style {
+    method public androidx.autofill.inline.common.ViewStyle? getChipStyle();
+    method public androidx.autofill.inline.common.ImageViewStyle? getEndIconStyle();
+    method public int getLayoutDirection();
+    method public androidx.autofill.inline.common.ImageViewStyle? getSingleIconChipIconStyle();
+    method public androidx.autofill.inline.common.ViewStyle? getSingleIconChipStyle();
+    method public androidx.autofill.inline.common.ImageViewStyle? getStartIconStyle();
+    method public androidx.autofill.inline.common.TextViewStyle? getSubtitleStyle();
+    method public androidx.autofill.inline.common.TextViewStyle? getTitleStyle();
+  }
+
+  public static final class InlineSuggestionUi.Style.Builder {
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style build();
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setChipStyle(androidx.autofill.inline.common.ViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setEndIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setLayoutDirection(int);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSingleIconChipIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSingleIconChipStyle(androidx.autofill.inline.common.ViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setStartIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSubtitleStyle(androidx.autofill.inline.common.TextViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setTitleStyle(androidx.autofill.inline.common.TextViewStyle);
+  }
+
+}
+
diff --git a/autofill/autofill/api/res-1.1.0-beta01.txt b/autofill/autofill/api/res-1.1.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/autofill/autofill/api/res-1.1.0-beta01.txt
diff --git a/autofill/autofill/api/restricted_1.1.0-beta01.txt b/autofill/autofill/api/restricted_1.1.0-beta01.txt
new file mode 100644
index 0000000..852dd23
--- /dev/null
+++ b/autofill/autofill/api/restricted_1.1.0-beta01.txt
@@ -0,0 +1,183 @@
+// Signature format: 3.0
+package androidx.autofill {
+
+  public final class HintConstants {
+    method public static String generateSmsOtpHintForCharacterPosition(int);
+    field public static final String AUTOFILL_HINT_BIRTH_DATE_DAY = "birthDateDay";
+    field public static final String AUTOFILL_HINT_BIRTH_DATE_FULL = "birthDateFull";
+    field public static final String AUTOFILL_HINT_BIRTH_DATE_MONTH = "birthDateMonth";
+    field public static final String AUTOFILL_HINT_BIRTH_DATE_YEAR = "birthDateYear";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = "creditCardExpirationDate";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = "creditCardExpirationMonth";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = "creditCardExpirationYear";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber";
+    field public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode";
+    field public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress";
+    field public static final String AUTOFILL_HINT_GENDER = "gender";
+    field @Deprecated public static final String AUTOFILL_HINT_NAME = "name";
+    field public static final String AUTOFILL_HINT_NEW_PASSWORD = "newPassword";
+    field public static final String AUTOFILL_HINT_NEW_USERNAME = "newUsername";
+    field public static final String AUTOFILL_HINT_PASSWORD = "password";
+    field public static final String AUTOFILL_HINT_PERSON_NAME = "personName";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_FAMILY = "personFamilyName";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_GIVEN = "personGivenName";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_MIDDLE = "personMiddleName";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_MIDDLE_INITIAL = "personMiddleInitial";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_PREFIX = "personNamePrefix";
+    field public static final String AUTOFILL_HINT_PERSON_NAME_SUFFIX = "personNameSuffix";
+    field @Deprecated public static final String AUTOFILL_HINT_PHONE = "phone";
+    field public static final String AUTOFILL_HINT_PHONE_COUNTRY_CODE = "phoneCountryCode";
+    field public static final String AUTOFILL_HINT_PHONE_NATIONAL = "phoneNational";
+    field public static final String AUTOFILL_HINT_PHONE_NUMBER = "phoneNumber";
+    field public static final String AUTOFILL_HINT_PHONE_NUMBER_DEVICE = "phoneNumberDevice";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_COUNTRY = "addressCountry";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_ADDRESS = "extendedAddress";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_EXTENDED_POSTAL_CODE = "extendedPostalCode";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_LOCALITY = "addressLocality";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_REGION = "addressRegion";
+    field public static final String AUTOFILL_HINT_POSTAL_ADDRESS_STREET_ADDRESS = "streetAddress";
+    field public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode";
+    field public static final String AUTOFILL_HINT_SMS_OTP = "smsOTPCode";
+    field public static final String AUTOFILL_HINT_USERNAME = "username";
+  }
+
+}
+
+package androidx.autofill.inline {
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class Renderer {
+    method public static android.app.PendingIntent? getAttributionIntent(android.app.slice.Slice);
+    method public static android.os.Bundle getSupportedInlineUiVersionsAsBundle();
+    method public static android.view.View? render(android.content.Context, android.app.slice.Slice, android.os.Bundle);
+  }
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class SuggestionHintConstants {
+    field public static final String SUGGESTION_HINT_CLIPBOARD_CONTENT = "clipboardContent";
+    field public static final String SUGGESTION_HINT_SMART_REPLY = "smartReply";
+  }
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class UiVersions {
+    method public static java.util.List<java.lang.String!> getVersions(android.os.Bundle);
+    method public static androidx.autofill.inline.UiVersions.StylesBuilder newStylesBuilder();
+    field public static final String INLINE_UI_VERSION_1 = "androidx.autofill.inline.ui.version:v1";
+  }
+
+  public static interface UiVersions.Content {
+    method public android.app.slice.Slice getSlice();
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @StringDef({androidx.autofill.inline.UiVersions.INLINE_UI_VERSION_1}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface UiVersions.InlineUiVersion {
+  }
+
+  public static interface UiVersions.Style {
+  }
+
+  public static final class UiVersions.StylesBuilder {
+    method public androidx.autofill.inline.UiVersions.StylesBuilder addStyle(androidx.autofill.inline.UiVersions.Style);
+    method public android.os.Bundle build();
+  }
+
+}
+
+package androidx.autofill.inline.common {
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class ImageViewStyle extends androidx.autofill.inline.common.ViewStyle {
+  }
+
+  public static final class ImageViewStyle.Builder {
+    ctor public ImageViewStyle.Builder();
+    method public androidx.autofill.inline.common.ImageViewStyle build();
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setBackgroundColor(int);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setLayoutMargin(int, int, int, int);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setMaxHeight(int);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setMaxWidth(int);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setPadding(int, int, int, int);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setScaleType(android.widget.ImageView.ScaleType);
+    method public androidx.autofill.inline.common.ImageViewStyle.Builder setTintList(android.content.res.ColorStateList);
+  }
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class TextViewStyle extends androidx.autofill.inline.common.ViewStyle {
+  }
+
+  public static final class TextViewStyle.Builder {
+    ctor public TextViewStyle.Builder();
+    method public androidx.autofill.inline.common.TextViewStyle build();
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setBackgroundColor(int);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setLayoutMargin(int, int, int, int);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setPadding(int, int, int, int);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setTextColor(@ColorInt int);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setTextSize(float);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setTextSize(int, float);
+    method public androidx.autofill.inline.common.TextViewStyle.Builder setTypeface(String, int);
+  }
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public class ViewStyle {
+  }
+
+  public static final class ViewStyle.Builder {
+    ctor public ViewStyle.Builder();
+    method public androidx.autofill.inline.common.ViewStyle build();
+    method public androidx.autofill.inline.common.ViewStyle.Builder setBackground(android.graphics.drawable.Icon);
+    method public androidx.autofill.inline.common.ViewStyle.Builder setBackgroundColor(int);
+    method public androidx.autofill.inline.common.ViewStyle.Builder setLayoutMargin(int, int, int, int);
+    method public androidx.autofill.inline.common.ViewStyle.Builder setPadding(int, int, int, int);
+  }
+
+}
+
+package androidx.autofill.inline.v1 {
+
+  @RequiresApi(api=android.os.Build.VERSION_CODES.R) public final class InlineSuggestionUi {
+    method public static androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder newContentBuilder(android.app.PendingIntent);
+    method public static androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder newStyleBuilder();
+  }
+
+  public static final class InlineSuggestionUi.Content implements androidx.autofill.inline.UiVersions.Content {
+    method public android.app.PendingIntent? getAttributionIntent();
+    method public CharSequence? getContentDescription();
+    method public android.graphics.drawable.Icon? getEndIcon();
+    method public final android.app.slice.Slice getSlice();
+    method public android.graphics.drawable.Icon? getStartIcon();
+    method public CharSequence? getSubtitle();
+    method public CharSequence? getTitle();
+  }
+
+  public static final class InlineSuggestionUi.Content.Builder {
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content build();
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setContentDescription(CharSequence);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setEndIcon(android.graphics.drawable.Icon);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setHints(java.util.List<java.lang.String!>);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setStartIcon(android.graphics.drawable.Icon);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setSubtitle(CharSequence);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Content.Builder setTitle(CharSequence);
+  }
+
+  public static final class InlineSuggestionUi.Style implements androidx.autofill.inline.UiVersions.Style {
+    method public androidx.autofill.inline.common.ViewStyle? getChipStyle();
+    method public androidx.autofill.inline.common.ImageViewStyle? getEndIconStyle();
+    method public int getLayoutDirection();
+    method public androidx.autofill.inline.common.ImageViewStyle? getSingleIconChipIconStyle();
+    method public androidx.autofill.inline.common.ViewStyle? getSingleIconChipStyle();
+    method public androidx.autofill.inline.common.ImageViewStyle? getStartIconStyle();
+    method public androidx.autofill.inline.common.TextViewStyle? getSubtitleStyle();
+    method public androidx.autofill.inline.common.TextViewStyle? getTitleStyle();
+  }
+
+  public static final class InlineSuggestionUi.Style.Builder {
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style build();
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setChipStyle(androidx.autofill.inline.common.ViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setEndIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setLayoutDirection(int);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSingleIconChipIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSingleIconChipStyle(androidx.autofill.inline.common.ViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setStartIconStyle(androidx.autofill.inline.common.ImageViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setSubtitleStyle(androidx.autofill.inline.common.TextViewStyle);
+    method public androidx.autofill.inline.v1.InlineSuggestionUi.Style.Builder setTitleStyle(androidx.autofill.inline.common.TextViewStyle);
+  }
+
+}
+
diff --git a/benchmark/OWNERS b/benchmark/OWNERS
index a69c988..171c5cc 100644
--- a/benchmark/OWNERS
+++ b/benchmark/OWNERS
@@ -1,2 +1,3 @@
 ccraik@google.com
 dustinlam@google.com
+rahulrav@google.com
diff --git a/benchmark/gradle-plugin/src/main/kotlin/androidx/benchmark/gradle/BenchmarkPlugin.kt b/benchmark/gradle-plugin/src/main/kotlin/androidx/benchmark/gradle/BenchmarkPlugin.kt
index f85b621..ec7b70d 100644
--- a/benchmark/gradle-plugin/src/main/kotlin/androidx/benchmark/gradle/BenchmarkPlugin.kt
+++ b/benchmark/gradle-plugin/src/main/kotlin/androidx/benchmark/gradle/BenchmarkPlugin.kt
@@ -89,25 +89,17 @@
 
         extension.configureTestBuildType(testBuildType)
 
-        // Registering this block as a configureEach callback is only necessary because Studio skips
-        // Gradle if there are no changes, which stops this plugin from being re-applied.
-        var enabledOutput = false
-        project.configurations.configureEach {
-            if (!enabledOutput &&
-                !project.rootProject.hasProperty("android.injected.invoked.from.ide") &&
-                !testInstrumentationArgs.containsKey("androidx.benchmark.output.enable")
-            ) {
-                enabledOutput = true
+        if (!project.rootProject.hasProperty("android.injected.invoked.from.ide") &&
+            !testInstrumentationArgs.containsKey("androidx.benchmark.output.enable")
+        ) {
+            // NOTE: This argument is checked by ResultWriter to enable CI reports.
+            defaultConfig.testInstrumentationRunnerArgument(
+                "androidx.benchmark.output.enable",
+                "true"
+            )
 
-                // NOTE: This argument is checked by ResultWriter to enable CI reports.
-                defaultConfig.testInstrumentationRunnerArgument(
-                    "androidx.benchmark.output.enable",
-                    "true"
-                )
-
-                if (!project.properties[ADDITIONAL_TEST_OUTPUT_KEY].toString().toBoolean()) {
-                    defaultConfig.testInstrumentationRunnerArgument("no-isolated-storage", "1")
-                }
+            if (!project.properties[ADDITIONAL_TEST_OUTPUT_KEY].toString().toBoolean()) {
+                defaultConfig.testInstrumentationRunnerArgument("no-isolated-storage", "1")
             }
         }
 
@@ -160,12 +152,13 @@
                         it.finalizedBy("benchmarkReport")
                     }
                 } else {
+                    val projectBuildDir = project.buildDir.path
                     project.tasks.named("connectedAndroidTest").configure {
                         it.doLast {
                             Log.logAndDisplay(
                                 Log.LogLevel.INFO,
                                 "Benchmark",
-                                "Benchmark report files generated at ${project.buildDir}" +
+                                "Benchmark report files generated at $projectBuildDir" +
                                         "/outputs/connected_android_test_additional_output"
                             )
                         }
diff --git a/benchmark/macro/build.gradle b/benchmark/macro/build.gradle
new file mode 100644
index 0000000..397dc2a
--- /dev/null
+++ b/benchmark/macro/build.gradle
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.Publish
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("kotlin-android")
+}
+
+android {
+    defaultConfig {
+        minSdkVersion 18
+    }
+}
+
+dependencies {
+    // TODO: remove, once we remove the minor usages in CrystalBall
+    implementation(GUAVA_ANDROID)
+
+    implementation("com.android:jank-helper:0.1.0")
+
+    api(JUNIT)
+    api(KOTLIN_STDLIB)
+
+    implementation("androidx.test:rules:1.3.0")
+    implementation("androidx.test:runner:1.3.0")
+    api("androidx.annotation:annotation:1.1.0")
+
+    implementation(ANDROIDX_TEST_EXT_JUNIT)
+    implementation(ANDROIDX_TEST_UIAUTOMATOR)
+}
+
+androidx {
+    name = "Android Benchmark - Macrobenchmark"
+    publish = Publish.NONE
+    mavenGroup = LibraryGroups.BENCHMARK
+    inceptionYear = "2020"
+    description = "Android Benchmark - Macrobenchmark"
+}
diff --git a/benchmark/macro/src/androidTest/AndroidManifest.xml b/benchmark/macro/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..bb07f93
--- /dev/null
+++ b/benchmark/macro/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2020 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.
+  -->
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="androidx.benchmark.macro.test">
+</manifest>
\ No newline at end of file
diff --git a/benchmark/macro/src/androidTest/java/JankCollectionHelperTest.kt b/benchmark/macro/src/androidTest/java/JankCollectionHelperTest.kt
new file mode 100644
index 0000000..b27fbf2
--- /dev/null
+++ b/benchmark/macro/src/androidTest/java/JankCollectionHelperTest.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 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.
+ */
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import com.android.helpers.JankCollectionHelper
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class JankCollectionHelperTest {
+    // Setting a minSdkVersion of 27 because JankHelper fails with an error on API 26.
+    // Needs a fix in JankHelper and re-import of prebults.
+    // https://android-build.googleplex.com/builds/tests/view?invocationId=I00300005943166534&redirect=http://sponge2/025964b6-d278-44a7-805c-56d8010935a8
+    @Test
+    @SdkSuppress(minSdkVersion = 27)
+    fun trivialTest() {
+        val helper = JankCollectionHelper()
+        assertTrue(helper.metrics.isNotEmpty())
+    }
+}
diff --git a/benchmark/macro/src/main/AndroidManifest.xml b/benchmark/macro/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a599d46
--- /dev/null
+++ b/benchmark/macro/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+<manifest package="androidx.benchmark.macro"/>
diff --git a/biometric/biometric/proguard-rules.pro b/biometric/biometric/proguard-rules.pro
index 7227001..dc9adc0 100644
--- a/biometric/biometric/proguard-rules.pro
+++ b/biometric/biometric/proguard-rules.pro
@@ -41,3 +41,7 @@
         class androidx.biometric.KeyguardUtils$Api* {
     <methods>;
 }
+-keepclassmembernames,allowobfuscation,allowshrinking
+        class androidx.biometric.PackageUtils$Api* {
+    <methods>;
+}
diff --git a/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java b/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java
index 3973edd..3c4097d 100644
--- a/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java
+++ b/biometric/biometric/src/main/java/androidx/biometric/BiometricFragment.java
@@ -122,11 +122,6 @@
     private static final int REQUEST_CONFIRM_CREDENTIAL = 1;
 
     /**
-     * Force the fingerprint dialog to appear for debugging. Must NOT be checked in as {@code true}.
-     */
-    private static final boolean DEBUG_FORCE_FINGERPRINT = false;
-
-    /**
      * An executor used by {@link android.hardware.biometrics.BiometricPrompt} to run framework
      * code.
      */
@@ -938,23 +933,40 @@
      * @return Whether this fragment should display the fingerprint dialog UI.
      */
     private boolean isUsingFingerprintDialog() {
-        return Build.VERSION.SDK_INT < Build.VERSION_CODES.P || shouldForceFingerprint();
+        return Build.VERSION.SDK_INT < Build.VERSION_CODES.P
+                || isFingerprintDialogNeededForCrypto()
+                || isFingerprintDialogNeededForErrorHandling();
     }
 
     /**
-     * Checks if this fragment should always display the fingerprint dialog authentication UI,
-     * regardless of Android version.
+     * Checks if this fragment should display the fingerprint dialog authentication UI for an
+     * ongoing crypto-based authentication attempt.
      *
-     * <p>This is needed to force some devices to fall back to fingerprint in order to support
-     * strong (crypto-based) authentication.
+     * @return Whether this fragment should display the fingerprint dialog UI.
      *
      * @see DeviceUtils#shouldUseFingerprintForCrypto(Context, String, String)
      */
-    private boolean shouldForceFingerprint() {
+    private boolean isFingerprintDialogNeededForCrypto() {
         final FragmentActivity activity = getActivity();
-        return DEBUG_FORCE_FINGERPRINT || (activity != null && mViewModel.getCryptoObject() != null
+        return activity != null
+                && mViewModel.getCryptoObject() != null
                 && DeviceUtils.shouldUseFingerprintForCrypto(
-                        activity, Build.MANUFACTURER, Build.MODEL));
+                        activity, Build.MANUFACTURER, Build.MODEL);
+    }
+
+    /**
+     * Checks if this fragment should invoke the fingerprint dialog, rather than the framework
+     * biometric prompt, to handle an authentication error.
+     *
+     * @return Whether this fragment should invoke the fingerprint dialog.
+     *
+     * @see DeviceUtils#shouldUseFingerprintForCrypto(Context, String, String)
+     */
+    private boolean isFingerprintDialogNeededForErrorHandling() {
+        // On API 28, BiometricPrompt internally calls FingerprintManager#getErrorString(), which
+        // requires fingerprint hardware to be present (b/151443237).
+        return Build.VERSION.SDK_INT == Build.VERSION_CODES.P
+                && !PackageUtils.hasSystemFeatureFingerprint(getContext());
     }
 
     /**
diff --git a/biometric/biometric/src/main/java/androidx/biometric/BiometricManager.java b/biometric/biometric/src/main/java/androidx/biometric/BiometricManager.java
index c827222..e2d9572 100644
--- a/biometric/biometric/src/main/java/androidx/biometric/BiometricManager.java
+++ b/biometric/biometric/src/main/java/androidx/biometric/BiometricManager.java
@@ -195,6 +195,14 @@
         boolean isDeviceSecuredWithCredential();
 
         /**
+         * Checks if the current device has a hardware sensor that may be used for fingerprint
+         * authentication.
+         *
+         * @return Whether the device has a fingerprint sensor.
+         */
+        boolean isFingerprintHardwarePresent();
+
+        /**
          * Checks if all biometric sensors on the device are known to meet or exceed the security
          * requirements for <strong>Class 3</strong> (formerly <strong>Strong</strong>).
          *
@@ -242,6 +250,11 @@
         }
 
         @Override
+        public boolean isFingerprintHardwarePresent() {
+            return PackageUtils.hasSystemFeatureFingerprint(mContext);
+        }
+
+        @Override
         public boolean isStrongBiometricGuaranteed() {
             return DeviceUtils.canAssumeStrongBiometrics(mContext, Build.MODEL);
         }
@@ -383,7 +396,11 @@
 
         // Non-fingerprint biometrics may be invoked but can't be checked on API 28.
         if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {
-            return canAuthenticateWithFingerprintOrUnknown();
+            // Having fingerprint hardware is a prerequisite, since BiometricPrompt internally
+            // calls FingerprintManager#getErrorString() on API 28 (b/151443237).
+            return mInjector.isFingerprintHardwarePresent()
+                    ? canAuthenticateWithFingerprintOrUnknown()
+                    : BIOMETRIC_ERROR_NO_HARDWARE;
         }
 
         // No non-fingerprint biometric APIs exist prior to API 28.
diff --git a/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java b/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
index 51f12a6..32843ea 100644
--- a/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
+++ b/biometric/biometric/src/main/java/androidx/biometric/FingerprintDialogFragment.java
@@ -133,12 +133,13 @@
     /**
      * An icon shown on the dialog during authentication.
      */
-    private ImageView mFingerprintIcon;
+    @Nullable private ImageView mFingerprintIcon;
 
     /**
      * Help text shown below the fingerprint icon on the dialog.
      */
     @SuppressWarnings("WeakerAccess") /* synthetic access */
+    @Nullable
     TextView mHelpMessageView;
 
     /**
@@ -179,22 +180,25 @@
                 .inflate(R.layout.fingerprint_dialog_layout, null);
 
         final TextView subtitleView = layout.findViewById(R.id.fingerprint_subtitle);
-        final TextView descriptionView = layout.findViewById(R.id.fingerprint_description);
-
-        final CharSequence subtitle = mViewModel.getSubtitle();
-        if (TextUtils.isEmpty(subtitle)) {
-            subtitleView.setVisibility(View.GONE);
-        } else {
-            subtitleView.setVisibility(View.VISIBLE);
-            subtitleView.setText(subtitle);
+        if (subtitleView != null) {
+            final CharSequence subtitle = mViewModel.getSubtitle();
+            if (TextUtils.isEmpty(subtitle)) {
+                subtitleView.setVisibility(View.GONE);
+            } else {
+                subtitleView.setVisibility(View.VISIBLE);
+                subtitleView.setText(subtitle);
+            }
         }
 
-        final CharSequence description = mViewModel.getDescription();
-        if (TextUtils.isEmpty(description)) {
-            descriptionView.setVisibility(View.GONE);
-        } else {
-            descriptionView.setVisibility(View.VISIBLE);
-            descriptionView.setText(description);
+        final TextView descriptionView = layout.findViewById(R.id.fingerprint_description);
+        if (descriptionView != null) {
+            final CharSequence description = mViewModel.getDescription();
+            if (TextUtils.isEmpty(description)) {
+                descriptionView.setVisibility(View.GONE);
+            } else {
+                descriptionView.setVisibility(View.VISIBLE);
+                descriptionView.setText(description);
+            }
         }
 
         mFingerprintIcon = layout.findViewById(R.id.fingerprint_icon);
diff --git a/biometric/biometric/src/main/java/androidx/biometric/PackageUtils.java b/biometric/biometric/src/main/java/androidx/biometric/PackageUtils.java
new file mode 100644
index 0000000..9dc2f51
--- /dev/null
+++ b/biometric/biometric/src/main/java/androidx/biometric/PackageUtils.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020 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.biometric;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+
+/**
+ * Utilities related to the system {@link PackageManager}.
+ */
+class PackageUtils {
+    // Prevent instantiation.
+    private PackageUtils() {}
+
+    /**
+     * Checks if the current device supports fingerprint authentication.
+     *
+     * @param context The application or activity context.
+     * @return Whether fingerprint is supported.
+     */
+    static boolean hasSystemFeatureFingerprint(@Nullable Context context) {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+                && context != null
+                && context.getPackageManager() != null
+                && Api23Impl.hasSystemFeatureFingerprint(context.getPackageManager());
+    }
+
+    /**
+     * Nested class to avoid verification errors for methods introduced in Android 6.0 (API 23).
+     */
+    @RequiresApi(Build.VERSION_CODES.M)
+    private static class Api23Impl {
+        // Prevent instantiation.
+        private Api23Impl() {}
+
+        /**
+         * Checks if the given package manager has support for the fingerprint system feature.
+         *
+         * @param packageManager The system package manager.
+         * @return Whether fingerprint is supported.
+         */
+        static boolean hasSystemFeatureFingerprint(@NonNull PackageManager packageManager) {
+            return packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
+        }
+    }
+}
diff --git a/biometric/biometric/src/test/java/androidx/biometric/BiometricManagerTest.java b/biometric/biometric/src/test/java/androidx/biometric/BiometricManagerTest.java
index 00e61d7..04e665d 100644
--- a/biometric/biometric/src/test/java/androidx/biometric/BiometricManagerTest.java
+++ b/biometric/biometric/src/test/java/androidx/biometric/BiometricManagerTest.java
@@ -55,6 +55,7 @@
                 frameworkBiometricManager,
                 true /* isDeviceSecurable */,
                 true /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */,
                 false /* isStrongBiometricGuaranteed */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
@@ -73,6 +74,7 @@
                 frameworkBiometricManager,
                 true /* isDeviceSecurable */,
                 true /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */,
                 false /* isStrongBiometricGuaranteed */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
@@ -92,6 +94,7 @@
                 frameworkBiometricManager,
                 true /* isDeviceSecurable */,
                 true /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */,
                 false /* isStrongBiometricGuaranteed */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
@@ -111,6 +114,7 @@
                 frameworkBiometricManager,
                 true /* isDeviceSecurable */,
                 true /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */,
                 false /* isStrongBiometricGuaranteed */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
@@ -130,7 +134,8 @@
         final BiometricManager.Injector injector = createInjector(
                 fingerprintManager,
                 true /* isDeviceSecurable */,
-                true /* isDeviceSecuredWithCredential */);
+                true /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
         final int authenticators = Authenticators.DEVICE_CREDENTIAL;
@@ -149,6 +154,7 @@
                 frameworkBiometricManager,
                 true /* isDeviceSecurable */,
                 true /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */,
                 false /* isStrongBiometricGuaranteed */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
@@ -166,7 +172,8 @@
         final BiometricManager.Injector injector = createInjector(
                 fingerprintManager,
                 true /* isDeviceSecurable */,
-                true /* isDeviceSecuredWithCredential */);
+                true /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
         assertThat(biometricManager.canAuthenticate(0)).isEqualTo(BIOMETRIC_ERROR_NO_HARDWARE);
@@ -183,6 +190,7 @@
                 frameworkBiometricManager,
                 false /* isDeviceSecurable */,
                 false /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */,
                 false /* isStrongBiometricGuaranteed */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
@@ -202,7 +210,8 @@
         final BiometricManager.Injector injector = createInjector(
                 fingerprintManager,
                 false /* isDeviceSecurable */,
-                false /* isDeviceSecuredWithCredential */);
+                false /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
         final int authenticators = Authenticators.BIOMETRIC_WEAK;
@@ -221,6 +230,7 @@
                 frameworkBiometricManager,
                 true /* isDeviceSecurable */,
                 false /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */,
                 false /* isStrongBiometricGuaranteed */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
@@ -240,7 +250,8 @@
         final BiometricManager.Injector injector = createInjector(
                 fingerprintManager,
                 true /* isDeviceSecurable */,
-                false /* isDeviceSecuredWithCredential */);
+                false /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
         final int authenticators = Authenticators.BIOMETRIC_WEAK;
@@ -259,6 +270,7 @@
                 frameworkBiometricManager,
                 true /* isDeviceSecurable */,
                 true /* isDeviceSecuredWithCredential */,
+                false /* isFingerprintHardwarePresent */,
                 false /* isStrongBiometricGuaranteed */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
@@ -277,7 +289,8 @@
         final BiometricManager.Injector injector = createInjector(
                 fingerprintManager,
                 true /* isDeviceSecurable */,
-                true /* isDeviceSecuredWithCredential */);
+                true /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
         final int authenticators = Authenticators.BIOMETRIC_WEAK | Authenticators.DEVICE_CREDENTIAL;
@@ -295,6 +308,7 @@
                 frameworkBiometricManager,
                 true /* isDeviceSecurable */,
                 true /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */,
                 true /* isStrongBiometricGuaranteed */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
@@ -313,6 +327,7 @@
                 frameworkBiometricManager,
                 true /* isDeviceSecurable */,
                 true /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */,
                 false /* isStrongBiometricGuaranteed */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
@@ -332,7 +347,8 @@
         final BiometricManager.Injector injector = createInjector(
                 fingerprintManager,
                 true /* isDeviceSecurable */,
-                true /* isDeviceSecuredWithCredential */);
+                true /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
         final int authenticators = Authenticators.BIOMETRIC_STRONG;
@@ -350,7 +366,8 @@
         final BiometricManager.Injector injector = createInjector(
                 fingerprintManager,
                 true /* isDeviceSecurable */,
-                true /* isDeviceSecuredWithCredential */);
+                true /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
         final int authenticators = Authenticators.BIOMETRIC_STRONG;
@@ -359,6 +376,26 @@
     }
 
     @Test
+    @Config(minSdk = Build.VERSION_CODES.P, maxSdk = Build.VERSION_CODES.P)
+    public void testCanAuthenticate_ReturnsError_WhenNoFingerprintHardware_OnApi28() {
+        final androidx.core.hardware.fingerprint.FingerprintManagerCompat fingerprintManager =
+                mock(androidx.core.hardware.fingerprint.FingerprintManagerCompat.class);
+        when(fingerprintManager.isHardwareDetected()).thenReturn(false);
+        when(fingerprintManager.hasEnrolledFingerprints()).thenReturn(false);
+
+        final BiometricManager.Injector injector = createInjector(
+                fingerprintManager,
+                true /* isDeviceSecurable */,
+                true /* isDeviceSecuredWithCredential */,
+                false /* isFingerprintHardwarePresent */);
+
+        final BiometricManager biometricManager = new BiometricManager(injector);
+        final int authenticators = Authenticators.BIOMETRIC_STRONG;
+        assertThat(biometricManager.canAuthenticate(authenticators))
+                .isEqualTo(BIOMETRIC_ERROR_NO_HARDWARE);
+    }
+
+    @Test
     @Config(maxSdk = Build.VERSION_CODES.O_MR1)
     public void testCanAuthenticate_ReturnsError_WhenFingerprintUnavailable_OnApi27AndBelow() {
         final androidx.core.hardware.fingerprint.FingerprintManagerCompat fingerprintManager =
@@ -369,7 +406,8 @@
         final BiometricManager.Injector injector = createInjector(
                 fingerprintManager,
                 true /* isDeviceSecurable */,
-                true /* isDeviceSecuredWithCredential */);
+                true /* isDeviceSecuredWithCredential */,
+                true /* isFingerprintHardwarePresent */);
 
         final BiometricManager biometricManager = new BiometricManager(injector);
         final int authenticators = Authenticators.BIOMETRIC_STRONG;
@@ -381,6 +419,7 @@
             @Nullable final android.hardware.biometrics.BiometricManager biometricManager,
             final boolean isDeviceSecurable,
             final boolean isDeviceSecuredWithCredential,
+            final boolean isFingerprintHardwarePresent,
             final boolean isStrongBiometricGuaranteed) {
 
         return new BiometricManager.Injector() {
@@ -408,6 +447,11 @@
             }
 
             @Override
+            public boolean isFingerprintHardwarePresent() {
+                return isFingerprintHardwarePresent;
+            }
+
+            @Override
             public boolean isStrongBiometricGuaranteed() {
                 return isStrongBiometricGuaranteed;
             }
@@ -418,7 +462,8 @@
             @Nullable final androidx.core.hardware.fingerprint.FingerprintManagerCompat
                     fingerprintManager,
             final boolean isDeviceSecurable,
-            final boolean isDeviceSecuredWithCredential) {
+            final boolean isDeviceSecuredWithCredential,
+            final boolean isFingerprintHardwarePresent) {
 
         return new BiometricManager.Injector() {
             @Override
@@ -445,6 +490,11 @@
             }
 
             @Override
+            public boolean isFingerprintHardwarePresent() {
+                return isFingerprintHardwarePresent;
+            }
+
+            @Override
             public boolean isStrongBiometricGuaranteed() {
                 return false;
             }
diff --git a/biometric/biometric/src/test/java/androidx/biometric/PackageUtilsTest.java b/biometric/biometric/src/test/java/androidx/biometric/PackageUtilsTest.java
new file mode 100644
index 0000000..b597082
--- /dev/null
+++ b/biometric/biometric/src/test/java/androidx/biometric/PackageUtilsTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2020 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.biometric;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+
+import androidx.test.filters.LargeTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+@LargeTest
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+public class PackageUtilsTest {
+    @Mock private Context mContext;
+    @Mock private PackageManager mPackageManager;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    @Config(maxSdk = Build.VERSION_CODES.LOLLIPOP_MR1)
+    public void testHasSystemFeatureFingerprint_ReturnsFalse_OnApi22AndBelow() {
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.hasSystemFeature(anyString())).thenReturn(true);
+        assertThat(PackageUtils.hasSystemFeatureFingerprint(mContext)).isFalse();
+    }
+
+    @Test
+    @Config(minSdk = Build.VERSION_CODES.M)
+    public void testHasSystemFeatureFingerprint_ReturnsFalse_WhenContextIsNull() {
+        assertThat(PackageUtils.hasSystemFeatureFingerprint(null)).isFalse();
+    }
+
+    @Test
+    @Config(minSdk = Build.VERSION_CODES.M)
+    public void testHasSystemFeatureFingerprint_ReturnsFalse_WhenPackageManagerIsNull() {
+        when(mContext.getPackageManager()).thenReturn(null);
+        assertThat(PackageUtils.hasSystemFeatureFingerprint(mContext)).isFalse();
+    }
+
+    @Test
+    @Config(minSdk = Build.VERSION_CODES.M)
+    public void testHasSystemFeatureFingerprint_ReturnsFalse_WhenPackageManagerReturnsFalse() {
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT))
+                .thenReturn(false);
+        assertThat(PackageUtils.hasSystemFeatureFingerprint(mContext)).isFalse();
+    }
+
+    @Test
+    @Config(minSdk = Build.VERSION_CODES.M)
+    public void testHasSystemFeatureFingerprint_ReturnsTrue_WhenPackageManagerReturnsTrue() {
+        when(mContext.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
+        assertThat(PackageUtils.hasSystemFeatureFingerprint(mContext)).isTrue();
+    }
+}
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXExtension.kt b/buildSrc/src/main/kotlin/androidx/build/AndroidXExtension.kt
index 56e533a..d19314f 100644
--- a/buildSrc/src/main/kotlin/androidx/build/AndroidXExtension.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/AndroidXExtension.kt
@@ -36,6 +36,7 @@
             field = value
             chooseProjectVersion()
         }
+    private val ALLOWED_EXTRA_PREFIXES = listOf("-alpha", "-beta", "-rc", "-dev", "-SNAPSHOT")
 
     private fun chooseProjectVersion() {
         val version: Version
@@ -49,10 +50,12 @@
                     ") whose mavenGroup already specifies forcedVersion (" + groupVersion +
                 ")")
             } else {
+                verifyVersionExtraFormat(mavenVersion)
                 version = mavenVersion
             }
         } else {
             if (groupVersion != null) {
+                verifyVersionExtraFormat(groupVersion)
                 version = groupVersion
             } else {
                 return
@@ -65,6 +68,31 @@
         versionIsSet = true
     }
 
+    private fun verifyVersionExtraFormat(version: Version) {
+        val extra = version.extra
+        if (extra != null) {
+            if (!version.isSnapshot()) {
+                if (ALLOWED_EXTRA_PREFIXES.any { extra.startsWith(it) }) {
+                    for (potentialPrefix in ALLOWED_EXTRA_PREFIXES) {
+                        if (extra.startsWith(potentialPrefix)) {
+                            val secondExtraPart = extra.removePrefix(
+                                potentialPrefix)
+                            if (secondExtraPart.toIntOrNull() == null) {
+                                throw IllegalArgumentException("Version $version is not" +
+                                        " a properly formatted version, please ensure that " +
+                                        "$potentialPrefix is followed by a number only")
+                            }
+                        }
+                    }
+                } else {
+                    throw IllegalArgumentException("Version $version is not a proper " +
+                            "version, version suffixes following major.minor.patch should " +
+                            "be one of ${ALLOWED_EXTRA_PREFIXES.joinToString(", ")}")
+                }
+            }
+        }
+    }
+
     private fun isGroupVersionOverrideAllowed(): Boolean {
         // Grant an exception to the same-version-group policy for artifacts that haven't shipped a
         // stable API surface, e.g. 1.0.0-alphaXX, to allow for rapid early-stage development.
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt b/buildSrc/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
index ba65de1..9a201a2 100644
--- a/buildSrc/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/AndroidXGradleProperties.kt
@@ -81,7 +81,7 @@
  * Specifies to validate that the build doesn't generate any unrecognized messages
  * This prevents developers from inadvertently adding new warnings to the build output
  */
-const val VALIDATE_NO_EXTRA_MESSAGES = "androidx.validateNoExtraMessages"
+const val VALIDATE_NO_UNRECOGNIZED_MESSAGES = "androidx.validateNoUnrecognizedMessages"
 
 val ALL_ANDROIDX_PROPERTIES = setOf(
     ALL_WARNINGS_AS_ERRORS,
@@ -91,7 +91,7 @@
     STUDIO_TYPE,
     SUMMARIZE_STANDARD_ERROR,
     TEST_FAILURES_DO_NOT_FAIL_TEST_TASK,
-    VALIDATE_NO_EXTRA_MESSAGES,
+    VALIDATE_NO_UNRECOGNIZED_MESSAGES,
     WRITE_VERSIONED_API_FILES,
     AffectedModuleDetector.CHANGED_PROJECTS_ARG,
     AffectedModuleDetector.ENABLE_ARG,
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt
index d7c006d..d6881ff 100644
--- a/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt
@@ -285,6 +285,7 @@
 
             check(!excludes.contains("/META-INF/*.kotlin_module"))
         }
+        project.verifyLintProjectSettings(androidXExtension)
 
         project.configureSourceJarForAndroid(libraryExtension)
         project.configureVersionFileWriter(libraryExtension, androidXExtension)
@@ -335,6 +336,7 @@
     private fun configureWithJavaPlugin(project: Project, extension: AndroidXExtension) {
         project.configureErrorProneForJava()
         project.configureSourceJarForJava()
+        project.verifyLintProjectSettings(extension)
 
         // Force Java 1.8 source- and target-compatibilty for all Java libraries.
         val convention = project.convention.getPlugin<JavaPluginConvention>()
@@ -702,6 +704,29 @@
         }
     }
 
+    private fun Project.verifyLintProjectSettings(extension: AndroidXExtension) {
+        if (isLint()) {
+            project.afterEvaluate {
+                if (extension.publish != Publish.NONE) {
+                    throw IllegalArgumentException("Invalid Publish `${extension.publish}` for " +
+                            "lint project, should be `NONE` instead. Lint projects are meant to " +
+                            "be published through lintPublish as part of an aar, as such, lint " +
+                            "projects should always set their publish to <Publish.NONE>")
+                }
+                if (extension.toolingProject != true) {
+                    throw IllegalArgumentException("Invalid toolingProject settings: `${extension
+                        .toolingProject}` for lint project, should be `true` instead. Lint " +
+                            "projects are considered tooling projects.")
+                }
+                if (extension.compilationTarget != CompilationTarget.HOST) {
+                    throw IllegalArgumentException("Invalid compilation target: " +
+                            "`${extension.compilationTarget}` for lint project, should be " +
+                            "`CompilationTarget.HOST` instead.")
+                }
+            }
+        }
+    }
+
     private fun Project.configureJacoco() {
         apply(plugin = "jacoco")
         configure<JacocoPluginExtension> {
@@ -849,3 +874,12 @@
         it.dependsOn(task)
     }
 }
+
+/**
+ * This isn't ideal for figuring out if a project is a lint project that's meant to be published
+ * using lintPublish, however it's a reasonable estimate for now until we have a better way.
+ * @owengray plans to refine this function.
+ */
+fun Project.isLint(): Boolean {
+    return project.name.endsWith("-lint")
+}
diff --git a/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
index d17cf46..66e9a20 100644
--- a/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
@@ -459,7 +459,7 @@
         description = "Zips $ruleName Java documentation (generated via Doclava in the " +
             "style of d.android.com) into $destinationFile"
         doLast {
-            logger.quiet("'Wrote API reference to $destinationFile")
+            logger.info("'Wrote API reference to $destinationFile")
         }
     }
 }
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
index 7a2427f..43b5e21 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
@@ -41,7 +41,6 @@
     val CONTENTPAGER = LibraryGroup("androidx.contentpager", LibraryVersions.CONTENTPAGER)
     val COORDINATORLAYOUT = LibraryGroup("androidx.coordinatorlayout",
         LibraryVersions.COORDINATORLAYOUT)
-    val COMPOSE = LibraryGroup("androidx.compose", null)
     val CORE = LibraryGroup("androidx.core", null)
     val CURSORADAPTER = LibraryGroup("androidx.cursoradapter", LibraryVersions.CURSORADAPTER)
     val CUSTOMVIEW = LibraryGroup("androidx.customview", LibraryVersions.CUSTOMVIEW)
@@ -109,6 +108,7 @@
 
     object Compose {
         val ANIMATION = LibraryGroup("androidx.compose.animation", null)
+        val COMPILER = LibraryGroup("androidx.compose.compiler", null)
         val FOUNDATION = LibraryGroup("androidx.compose.foundation", null)
         val MATERIAL = LibraryGroup("androidx.compose.material", null)
         val NAVIGATION = LibraryGroup("androidx.compose.navigation", null)
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
index 66afc79..f6d4ffa 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
@@ -20,7 +20,7 @@
  * The list of versions codes of all the libraries in this project.
  */
 object LibraryVersions {
-    val ACTIVITY = Version("1.2.0-alpha09")
+    val ACTIVITY = Version("1.2.0-beta01")
     val ADS_IDENTIFIER = Version("1.0.0-alpha04")
     val ANNOTATION = Version("1.2.0-alpha02")
     val ANNOTATION_EXPERIMENTAL = Version("1.1.0-alpha01")
@@ -30,16 +30,16 @@
     val ARCH_CORE_TESTING = ARCH_CORE
     val ARCH_RUNTIME = Version("2.2.0-alpha01")
     val ASYNCLAYOUTINFLATER = Version("1.1.0-alpha01")
-    val AUTOFILL = Version("1.1.0-alpha02")
+    val AUTOFILL = Version("1.1.0-beta01")
     val BENCHMARK = Version("1.1.0-alpha02")
     val BIOMETRIC = Version("1.1.0-alpha03")
     val BROWSER = Version("1.3.0-alpha06")
     val BUILDSRC_TESTS = Version("1.0.0-alpha01")
-    val CAMERA = Version("1.0.0-beta09")
-    val CAMERA_EXTENSIONS = Version("1.0.0-alpha16")
+    val CAMERA = Version("1.0.0-beta10")
+    val CAMERA_EXTENSIONS = Version("1.0.0-alpha17")
     val CAMERA_PIPE = Version("1.0.0-alpha01")
     val CAMERA_VIDEO = Version("1.0.0-alpha01")
-    val CAMERA_VIEW = Version("1.0.0-alpha16")
+    val CAMERA_VIEW = Version("1.0.0-alpha17")
     val CARDVIEW = Version("1.1.0-alpha01")
     val COLLECTION = Version("1.2.0-alpha01")
     val CONTENTPAGER = Version("1.1.0-alpha01")
@@ -47,7 +47,7 @@
     val COMPOSE_NAVIGATION = Version("0.1.0-dev01")
     val CONTENTACCESS = Version("1.0.0-alpha01")
     val COORDINATORLAYOUT = Version("1.2.0-alpha01")
-    val CORE = Version("1.5.0-alpha03")
+    val CORE = Version("1.5.0-alpha04")
     val CORE_ANIMATION = Version("1.0.0-alpha03")
     val CORE_ANIMATION_TESTING = Version("1.0.0-alpha03")
     val CORE_APPDIGEST = Version("1.0.0-alpha01")
@@ -62,7 +62,7 @@
     val EMOJI = Version("1.2.0-alpha02")
     val ENTERPRISE = Version("1.1.0-alpha02")
     val EXIFINTERFACE = Version("1.4.0-alpha01")
-    val FRAGMENT = Version("1.3.0-alpha09")
+    val FRAGMENT = Version("1.3.0-beta01")
     val FUTURES = Version("1.2.0-alpha01")
     val GRIDLAYOUT = Version("1.1.0-alpha01")
     val HEIFWRITER = Version("1.1.0-alpha01")
diff --git a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
index e61f8fd..3d69a0d 100644
--- a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
@@ -40,6 +40,7 @@
     prebuilts(LibraryGroups.ASYNCLAYOUTINFLATER, "1.0.0")
     prebuilts(LibraryGroups.AUTOFILL, "1.1.0-alpha02")
     ignore(LibraryGroups.BENCHMARK.group, "benchmark-gradle-plugin")
+    ignore(LibraryGroups.BENCHMARK.group, "benchmark-macro")
     prebuilts(LibraryGroups.BENCHMARK, "1.1.0-alpha01")
     prebuilts(LibraryGroups.BIOMETRIC, "biometric", "1.1.0-alpha02")
     prebuilts(LibraryGroups.BROWSER, "1.3.0-alpha05")
@@ -172,7 +173,9 @@
  * Rule set used to generate tip-of-tree documentation, typically for local and pre-submit use.
  */
 val TIP_OF_TREE = docsRules("tipOfTree", true) {
-    ignore(LibraryGroups.COMPOSE.group)
+    // Doclava breaks when generating docs for the Compiler due to some missing (?) Kotlin
+    // classes - this can probably be removed after we remove Doclava support.
+    ignore(LibraryGroups.Compose.COMPILER.group)
     default(TipOfTree)
 }
 
diff --git a/buildSrc/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt b/buildSrc/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt
index 03eec98..e8fc778 100644
--- a/buildSrc/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/VerifyDependencyVersionsTask.kt
@@ -99,7 +99,7 @@
     // Only verify configurations that are exported to POM. In an ideal world, this would be an
     // inclusion derived from the mappings used by the Maven Publish Plugin; however, since we
     // don't have direct access to those, this should remain an exclusion list.
-    var name = configuration.name
+    val name = configuration.name
 
     // Don't check any Android-specific variants of Java plugin configurations -- releaseApi for
     // api, debugImplementation for implementation, etc. -- or test configurations.
@@ -108,10 +108,11 @@
     if (name.startsWith("release")) return false
     if (name.startsWith("test")) return false
 
-    // Don't check any tooling configurations (except lint!).
+    // Don't check any tooling configurations.
     if (name == "annotationProcessor") return false
     if (name == "errorprone") return false
     if (name.startsWith("jacoco")) return false
+    if (name.startsWith("lint")) return false
     if (name == "metalava") return false
 
     return true
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
index a123998..ccec494 100644
--- a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
@@ -72,7 +72,7 @@
     "com.squareup:kotlinpoet-classinspector-elements:1.4.0"
 const val KOTLIN_COMPILE_TESTING = "com.github.tschuchortdev:kotlin-compile-testing:1.2.10"
 const val KOTLIN_COMPILE_TESTING_KSP = "com.github.tschuchortdev:kotlin-compile-testing-ksp:1.2.10"
-const val KSP_VERSION = "1.4.0-dev-experimental-20200828"
+const val KSP_VERSION = "1.4.0-dev-experimental-20200914"
 const val KOTLIN_KSP_API = "org.jetbrains.kotlin:kotlin-symbol-processing-api:$KSP_VERSION"
 const val KOTLIN_KSP = "org.jetbrains.kotlin:kotlin-ksp:$KSP_VERSION"
 const val KOTLIN_GRADLE_PLUGIN = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.0-rc"
diff --git a/busytown/androidx.sh b/busytown/androidx.sh
index eedda4e..05e7732 100755
--- a/busytown/androidx.sh
+++ b/busytown/androidx.sh
@@ -6,9 +6,9 @@
 cd "$(dirname $0)"
 
 # Run Gradle
-impl/build.sh --no-daemon listTaskOutputs "$@"
+impl/build.sh --no-daemon listTaskOutputs -Pandroidx.validateNoUnrecognizedMessages "$@"
 impl/build.sh allProperties "$@" >/dev/null
-impl/build.sh --no-daemon buildOnServer checkExternalLicenses \
+impl/build.sh --no-daemon buildOnServer -Pandroidx.validateNoUnrecognizedMessages checkExternalLicenses \
     -PverifyUpToDate \
     -Pandroidx.coverageEnabled=true \
     -Pandroidx.allWarningsAsErrors --profile "$@"
diff --git a/busytown/impl/build.sh b/busytown/impl/build.sh
index 5ea576e..aee363c 100755
--- a/busytown/impl/build.sh
+++ b/busytown/impl/build.sh
@@ -15,6 +15,5 @@
 # cd to checkout root
 cd "$SCRIPT_DIR/../../../.."
 
-
 OUT_DIR=out/ui DIST_DIR=$DIST_DIR/ui ANDROID_HOME=./prebuilts/fullsdk-linux frameworks/support/ui/gradlew -p frameworks/support/ui --stacktrace -Pandroidx.summarizeStderr "$@"
 OUT_DIR=out    DIST_DIR=$DIST_DIR    ANDROID_HOME=./prebuilts/fullsdk-linux frameworks/support/gradlew    -p frameworks/support    --stacktrace -Pandroidx.summarizeStderr "$@"
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraPipeCameraFactory.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraPipeCameraFactory.kt
index ce33ae9..adcd429 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraPipeCameraFactory.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/impl/CameraPipeCameraFactory.kt
@@ -38,8 +38,9 @@
     init {
         if (DEBUG) {
             Log.d(
-                TAG, "Initialized CameraFactory [Context: $context, " +
-                        "ThreadConfig: $threadConfig, CameraPipe: $cameraPipe]"
+                TAG,
+                "Initialized CameraFactory [Context: $context, " +
+                    "ThreadConfig: $threadConfig, CameraPipe: $cameraPipe]"
             )
         }
     }
diff --git a/camera/camera-camera2-pipe/build.gradle b/camera/camera-camera2-pipe/build.gradle
index 4a76775..f61ac0a 100644
--- a/camera/camera-camera2-pipe/build.gradle
+++ b/camera/camera-camera2-pipe/build.gradle
@@ -70,6 +70,13 @@
     testOptions.unitTests.includeAndroidResources = true
 }
 
+kapt {
+    javacOptions {
+        option("-Adagger.fastInit=enabled")
+        option("-Adagger.fullBindingGraphValidation=ERROR")
+    }
+}
+
 // Create jarjar artifact for all variants (debug/release)
 android.libraryVariants.all { variant ->
     def variantName = variant.name
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraGraphComponent.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraGraphComponent.kt
index a1c4460..c95132b 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraGraphComponent.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraGraphComponent.kt
@@ -38,7 +38,8 @@
 @Subcomponent(
     modules = [
         CameraGraphModules::class,
-        CameraGraphConfigModule::class]
+        CameraGraphConfigModule::class
+    ]
 )
 interface CameraGraphComponent {
     fun cameraGraph(): CameraGraph
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraPipeComponent.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraPipeComponent.kt
index 1849443..f8ee3cc 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraPipeComponent.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/CameraPipeComponent.kt
@@ -119,7 +119,7 @@
             val globalScope = CoroutineScope(
                 cameraDispatcher.plus(
                     CoroutineName
-                        ("CXCP-Pipe")
+                    ("CXCP-Pipe")
                 )
             )
 
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/Debug.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/Debug.kt
index cf44015..277b27e 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/Debug.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/Debug.kt
@@ -97,8 +97,8 @@
             val capabilities = metadata[REQUEST_AVAILABLE_CAPABILITIES]
             val cameraType = if (capabilities != null &&
                 capabilities.contains(
-                    REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
-                )
+                        REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
+                    )
             ) {
                 "Logical"
             } else {
@@ -123,9 +123,11 @@
                     append("Default Parameters: (None)")
                 } else {
                     append("Default Parameters:\n")
-                    for (parameter in graphConfig.defaultParameters.filter {
-                        it is CaptureRequest.Key<*>
-                    }) {
+                    for (
+                        parameter in graphConfig.defaultParameters.filter {
+                            it is CaptureRequest.Key<*>
+                        }
+                    ) {
                         append("  ")
                         append((parameter.key as CaptureRequest.Key<*>).name.padEnd(50, ' '))
                         append(parameter.value)
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/GraphProcessor.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/GraphProcessor.kt
index 19e67ff..21fe62d 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/GraphProcessor.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/GraphProcessor.kt
@@ -123,7 +123,7 @@
             } else {
                 warn {
                     "Refusing to detach $requestProcessor. " +
-                            "It is different from $_requestProcessor"
+                        "It is different from $_requestProcessor"
                 }
             }
         }
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/SessionFactory.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/SessionFactory.kt
index 09459db..dec2ca9 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/SessionFactory.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/SessionFactory.kt
@@ -138,7 +138,7 @@
             } catch (e: Throwable) {
                 Log.warn {
                     "Failed to create reprocessable captures session from $cameraDevice for" +
-                            " $virtualSessionState!"
+                        " $virtualSessionState!"
                 }
                 virtualSessionState.disconnect()
             }
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/StreamMap.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/StreamMap.kt
index 94e67db..a7f435a 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/StreamMap.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/StreamMap.kt
@@ -58,11 +58,13 @@
 
         val hardwareLevel = cameraMetadata[INFO_SUPPORTED_HARDWARE_LEVEL]
         val deferredStreamsSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
-                graphConfig.operatingMode == CameraGraph.OperatingMode.NORMAL &&
-                hardwareLevel != INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY &&
-                hardwareLevel != INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED &&
-                (Build.VERSION.SDK_INT < Build.VERSION_CODES.P ||
-                        hardwareLevel != INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL)
+            graphConfig.operatingMode == CameraGraph.OperatingMode.NORMAL &&
+            hardwareLevel != INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY &&
+            hardwareLevel != INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED &&
+            (
+                Build.VERSION.SDK_INT < Build.VERSION_CODES.P ||
+                    hardwareLevel != INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL
+                )
 
         for (streamConfig in graphConfig.streams) {
             // Using an inline class generates a synthetic constructor
@@ -79,8 +81,10 @@
 
             if (deferredStreamsSupported &&
                 streamConfig.deferrable &&
-                (streamConfig.type == StreamType.SURFACE_TEXTURE ||
-                        streamConfig.type == StreamType.SURFACE_VIEW)
+                (
+                    streamConfig.type == StreamType.SURFACE_TEXTURE ||
+                        streamConfig.type == StreamType.SURFACE_VIEW
+                    )
             ) {
                 deferrableStreamBuilder.add(stream.id)
             }
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCamera.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCamera.kt
index baa41dd..30822fb 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCamera.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCamera.kt
@@ -220,7 +220,7 @@
                 "Opened $cameraId in ${attemptDuration.formatNanoTime()}"
             } else {
                 "Opened $cameraId in ${attemptDuration.formatNanoTime()} " +
-                        "(${totalDuration.formatNanoTime()} total) after $attemptNumber attempts."
+                    "(${totalDuration.formatNanoTime()} total) after $attemptNumber attempts."
             }
         }
 
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCameraManager.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCameraManager.kt
index c69a306..f865202 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCameraManager.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualCameraManager.kt
@@ -349,7 +349,8 @@
             timeout = 1000,
             callback = {
                 channel.offer(RequestClose(this))
-            })
+            }
+        )
 
         init {
             listenerJob = scope.launch {
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualSessionState.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualSessionState.kt
index e9ab5aa..ba041d5 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualSessionState.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/impl/VirtualSessionState.kt
@@ -280,7 +280,7 @@
                     Log.info {
                         val finalizationTime = Metrics.monotonicNanos() - finalizedStartTime
                         "Finalized ${pendingOutputs.map { it.key }} for $this in " +
-                                finalizationTime.formatNanoTime()
+                            finalizationTime.formatNanoTime()
                     }
                     tryResubmit = true
                 }
@@ -329,7 +329,7 @@
             if (deferred.isNotEmpty()) {
                 Log.info {
                     "Created $this with ${surfaces.keys.toList()}. " +
-                            "Waiting to finalize ${deferred.keys.toList()}"
+                        "Waiting to finalize ${deferred.keys.toList()}"
                 }
                 pendingOutputMap = deferred
 
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/CaptureSession.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/CaptureSession.kt
index b5a9a42..50cecfa 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/CaptureSession.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/CaptureSession.kt
@@ -313,8 +313,8 @@
     override fun finalizeOutputConfigurations(outputConfigs: List<OutputConfigurationWrapper>) {
         check(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
             "Attempting to call finalizeOutputConfigurations before O is not supported and may " +
-                    "lead to to unexpected behavior if an application is expects this call to " +
-                    "succeed."
+                "lead to to unexpected behavior if an application is expects this call to " +
+                "succeed."
         }
 
         rethrowCamera2Exceptions {
@@ -362,7 +362,7 @@
             // exception that can be ignored.
             Log.warn {
                 "Failed to createHighSpeedRequestList from $device because the output surface" +
-                        " was destroyed before calling createHighSpeedRequestList."
+                    " was destroyed before calling createHighSpeedRequestList."
             }
             throw ObjectUnavailableException(e)
         }
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/Configuration.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/Configuration.kt
index 0761aeb..2324ff4 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/Configuration.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/wrapper/Configuration.kt
@@ -149,7 +149,7 @@
                 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
                     throw IllegalStateException(
                         "Deferred OutputConfigurations are not supported on API " +
-                                "${Build.VERSION.SDK_INT} (requires API ${Build.VERSION_CODES.O})"
+                            "${Build.VERSION.SDK_INT} (requires API ${Build.VERSION_CODES.O})"
                     )
                 }
 
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/SessionFactoryTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/SessionFactoryTest.kt
index 6eb59f3..a6a33e50 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/SessionFactoryTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/SessionFactoryTest.kt
@@ -43,7 +43,8 @@
 @CameraGraphScope
 @Component(
     modules = [
-        FakeCameras.FakeCameraGraphModule::class
+        FakeCameras.FakeCameraGraphModule::class,
+        FakeCameras.FakeCameraPipeModule::class
     ]
 )
 interface CameraSessionTestComponent {
@@ -71,8 +72,8 @@
     @Test
     fun canCreateSessionFactoryTestComponent() = runBlockingTest {
         val component: CameraSessionTestComponent = DaggerCameraSessionTestComponent.builder()
-            .fakeCameraGraphModule(
-                FakeCameras.FakeCameraGraphModule(context, testCamera)
+            .fakeCameraPipeModule(
+                FakeCameras.FakeCameraPipeModule(context, testCamera)
             )
             .build()
 
@@ -83,8 +84,8 @@
     @Test
     fun createCameraCaptureSession() = runBlockingTest {
         val component: CameraSessionTestComponent = DaggerCameraSessionTestComponent.builder()
-            .fakeCameraGraphModule(
-                FakeCameras.FakeCameraGraphModule(context, testCamera)
+            .fakeCameraPipeModule(
+                FakeCameras.FakeCameraPipeModule(context, testCamera)
             )
             .build()
 
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/VirtualCameraTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/VirtualCameraTest.kt
index edc640a..7164298 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/VirtualCameraTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/impl/VirtualCameraTest.kt
@@ -83,11 +83,14 @@
         // additional events from being passed to the virtual camera instance.
         val virtualCamera = VirtualCameraState(cameraId)
         val cameraState = flowOf(CameraStateOpen(testCamera.cameraDeviceWrapper))
-        virtualCamera.connect(cameraState, object : Token {
-            override fun release(): Boolean {
-                return true
+        virtualCamera.connect(
+            cameraState,
+            object : Token {
+                override fun release(): Boolean {
+                    return true
+                }
             }
-        })
+        )
 
         virtualCamera.state.first { it !is CameraStateUnopened }
 
@@ -122,11 +125,14 @@
             }
         }
 
-        virtualCamera.connect(states.asFlow(), object : Token {
-            override fun release(): Boolean {
-                return true
+        virtualCamera.connect(
+            states.asFlow(),
+            object : Token {
+                override fun release(): Boolean {
+                    return true
+                }
             }
-        })
+        )
 
         // Suspend until the state is closed
         virtualCamera.state.first { it is CameraStateClosed }
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameras.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameras.kt
index 029766f0..774a8ce 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameras.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/testing/FakeCameras.kt
@@ -184,13 +184,8 @@
     /**
      * Utility module for testing the Dagger generated graph with a a reasonable default config.
      */
-    @Module(
-        includes = [
-            CameraPipeModules::class,
-            CameraGraphModules::class
-        ]
-    )
-    class FakeCameraGraphModule(
+    @Module(includes = [CameraPipeModules::class])
+    class FakeCameraPipeModule(
         private val context: Context,
         private val fakeCamera: FakeCamera
     ) {
@@ -213,4 +208,7 @@
             template = RequestTemplate(0)
         )
     }
+
+    @Module(includes = [CameraGraphModules::class])
+    class FakeCameraGraphModule
 }
diff --git a/camera/camera-camera2/api/1.0.0-beta10.txt b/camera/camera-camera2/api/1.0.0-beta10.txt
new file mode 100644
index 0000000..c4e0698
--- /dev/null
+++ b/camera/camera-camera2/api/1.0.0-beta10.txt
@@ -0,0 +1,9 @@
+// Signature format: 3.0
+package androidx.camera.camera2 {
+
+  public final class Camera2Config {
+    method public static androidx.camera.core.CameraXConfig defaultConfig();
+  }
+
+}
+
diff --git a/camera/camera-camera2/api/public_plus_experimental_1.0.0-beta10.txt b/camera/camera-camera2/api/public_plus_experimental_1.0.0-beta10.txt
new file mode 100644
index 0000000..d706ed6
--- /dev/null
+++ b/camera/camera-camera2/api/public_plus_experimental_1.0.0-beta10.txt
@@ -0,0 +1,41 @@
+// Signature format: 3.0
+package androidx.camera.camera2 {
+
+  public final class Camera2Config {
+    method public static androidx.camera.core.CameraXConfig defaultConfig();
+  }
+
+}
+
+package androidx.camera.camera2.interop {
+
+  @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2CameraFilter {
+    method public static androidx.camera.core.CameraFilter createCameraFilter(androidx.camera.camera2.interop.Camera2CameraFilter.Camera2Filter);
+  }
+
+  public static interface Camera2CameraFilter.Camera2Filter {
+    method public java.util.LinkedHashMap<java.lang.String!,android.hardware.camera2.CameraCharacteristics!> filter(java.util.LinkedHashMap<java.lang.String!,android.hardware.camera2.CameraCharacteristics!>);
+  }
+
+  @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2CameraInfo {
+    method public static androidx.camera.camera2.interop.Camera2CameraInfo fromCameraInfo(androidx.camera.core.CameraInfo);
+    method public <T> T? getCameraCharacteristic(android.hardware.camera2.CameraCharacteristics.Key<T!>);
+    method public String getCameraId();
+  }
+
+  @androidx.camera.camera2.interop.ExperimentalCamera2Interop public final class Camera2Interop {
+  }
+
+  public static final class Camera2Interop.Extender<T> {
+    ctor public Camera2Interop.Extender(androidx.camera.core.ExtendableBuilder<T!>);
+    method public <ValueT> androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setCaptureRequestOption(android.hardware.camera2.CaptureRequest.Key<ValueT!>, ValueT);
+    method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setDeviceStateCallback(android.hardware.camera2.CameraDevice.StateCallback);
+    method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setSessionCaptureCallback(android.hardware.camera2.CameraCaptureSession.CaptureCallback);
+    method public androidx.camera.camera2.interop.Camera2Interop.Extender<T!> setSessionStateCallback(android.hardware.camera2.CameraCaptureSession.StateCallback);
+  }
+
+  @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalCamera2Interop {
+  }
+
+}
+
diff --git a/camera/camera-camera2/api/res-1.0.0-beta10.txt b/camera/camera-camera2/api/res-1.0.0-beta10.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-camera2/api/res-1.0.0-beta10.txt
diff --git a/camera/camera-camera2/api/restricted_1.0.0-beta10.txt b/camera/camera-camera2/api/restricted_1.0.0-beta10.txt
new file mode 100644
index 0000000..c4e0698
--- /dev/null
+++ b/camera/camera-camera2/api/restricted_1.0.0-beta10.txt
@@ -0,0 +1,9 @@
+// Signature format: 3.0
+package androidx.camera.camera2 {
+
+  public final class Camera2Config {
+    method public static androidx.camera.core.CameraXConfig defaultConfig();
+  }
+
+}
+
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java
index fed9c13..5a3d6d4 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/CameraControlDeviceTest.java
@@ -19,7 +19,6 @@
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
-import android.Manifest;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.hardware.camera2.CameraCharacteristics;
@@ -41,7 +40,6 @@
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.filters.LargeTest;
 import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.GrantPermissionRule;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -49,6 +47,7 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
@@ -80,8 +79,7 @@
     }
 
     @Rule
-    public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(
-            Manifest.permission.CAMERA);
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
     private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
     private CameraUseCaseAdapter mCamera;
     private UseCase mBoundUseCase;
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java
index 9c5c2f8..629c6f6 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java
@@ -254,7 +254,7 @@
     public void defaultAspectRatioWillBeSet_whenTargetResolutionIsNotSet() {
         ImageAnalysis useCase = new ImageAnalysis.Builder().build();
         mCamera = CameraUtil.createCameraAndAttachUseCase(mContext, mCameraSelector, useCase);
-        ImageOutputConfig config = (ImageOutputConfig) useCase.getUseCaseConfig();
+        ImageOutputConfig config = (ImageOutputConfig) useCase.getCurrentConfig();
         assertThat(config.getTargetAspectRatio()).isEqualTo(AspectRatio.RATIO_4_3);
     }
 
@@ -264,13 +264,13 @@
         ImageAnalysis useCase = new ImageAnalysis.Builder().setTargetResolution(
                 GUARANTEED_RESOLUTION).build();
 
-        assertThat(useCase.getUseCaseConfig().containsOption(
+        assertThat(useCase.getCurrentConfig().containsOption(
                 ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)).isFalse();
 
         mCamera = CameraUtil.createCameraAndAttachUseCase(mContext,
                 CameraSelector.DEFAULT_BACK_CAMERA, useCase);
 
-        assertThat(useCase.getUseCaseConfig().containsOption(
+        assertThat(useCase.getCurrentConfig().containsOption(
                 ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)).isFalse();
     }
 
@@ -292,7 +292,7 @@
         // Updates target rotation from ROTATION_0 to ROTATION_90.
         imageAnalysis.setTargetRotation(Surface.ROTATION_90);
 
-        ImageOutputConfig newConfig = (ImageOutputConfig) imageAnalysis.getUseCaseConfig();
+        ImageOutputConfig newConfig = (ImageOutputConfig) imageAnalysis.getCurrentConfig();
         Size expectedTargetResolution = new Size(GUARANTEED_RESOLUTION.getHeight(),
                 GUARANTEED_RESOLUTION.getWidth());
 
@@ -337,7 +337,7 @@
     @Test
     public void useCaseConfigCanBeReset_afterUnbind() {
         final ImageAnalysis useCase = new ImageAnalysis.Builder().build();
-        UseCaseConfig<?> initialConfig = useCase.getUseCaseConfig();
+        UseCaseConfig<?> initialConfig = useCase.getCurrentConfig();
 
         mCamera = CameraUtil.createCameraAndAttachUseCase(mContext, mCameraSelector, useCase);
 
@@ -345,7 +345,7 @@
             mCamera.removeUseCases(Collections.singleton(useCase));
         });
 
-        UseCaseConfig<?> configAfterUnbinding = useCase.getUseCaseConfig();
+        UseCaseConfig<?> configAfterUnbinding = useCase.getCurrentConfig();
         assertThat(initialConfig.equals(configAfterUnbinding)).isTrue();
     }
 
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
index 7fc0216..34dd3e5 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
@@ -778,7 +778,7 @@
     public void defaultAspectRatioWillBeSet_whenTargetResolutionIsNotSet() {
         ImageCapture useCase = new ImageCapture.Builder().build();
         mCamera = CameraUtil.createCameraAndAttachUseCase(mContext, BACK_SELECTOR, useCase);
-        ImageOutputConfig config = (ImageOutputConfig) useCase.getUseCaseConfig();
+        ImageOutputConfig config = (ImageOutputConfig) useCase.getCurrentConfig();
         assertThat(config.getTargetAspectRatio()).isEqualTo(AspectRatio.RATIO_4_3);
     }
 
@@ -788,12 +788,12 @@
         ImageCapture useCase = new ImageCapture.Builder().setTargetResolution(
                 DEFAULT_RESOLUTION).build();
 
-        assertThat(useCase.getUseCaseConfig().containsOption(
+        assertThat(useCase.getCurrentConfig().containsOption(
                 ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)).isFalse();
 
         mCamera = CameraUtil.createCameraAndAttachUseCase(mContext, BACK_SELECTOR, useCase);
 
-        assertThat(useCase.getUseCaseConfig().containsOption(
+        assertThat(useCase.getCurrentConfig().containsOption(
                 ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)).isFalse();
     }
 
@@ -815,7 +815,7 @@
         // Updates target rotation from ROTATION_0 to ROTATION_90.
         imageCapture.setTargetRotation(Surface.ROTATION_90);
 
-        ImageOutputConfig newConfig = (ImageOutputConfig) imageCapture.getUseCaseConfig();
+        ImageOutputConfig newConfig = (ImageOutputConfig) imageCapture.getCurrentConfig();
         Size expectedTargetResolution = new Size(DEFAULT_RESOLUTION.getHeight(),
                 DEFAULT_RESOLUTION.getWidth());
 
@@ -1003,7 +1003,7 @@
     @Test
     public void useCaseConfigCanBeReset_afterUnbind() {
         final ImageCapture useCase = mDefaultBuilder.build();
-        UseCaseConfig<?> initialConfig = useCase.getUseCaseConfig();
+        UseCaseConfig<?> initialConfig = useCase.getCurrentConfig();
 
         mCamera = CameraUtil.createCameraAndAttachUseCase(mContext, BACK_SELECTOR, useCase);
 
@@ -1011,7 +1011,7 @@
             mCamera.removeUseCases(Collections.singleton(useCase));
         });
 
-        UseCaseConfig<?> configAfterUnbinding = useCase.getUseCaseConfig();
+        UseCaseConfig<?> configAfterUnbinding = useCase.getCurrentConfig();
         assertThat(initialConfig.equals(configAfterUnbinding)).isTrue();
     }
 
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java
index e0c776a..5d75838 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java
@@ -357,7 +357,7 @@
     public void defaultAspectRatioWillBeSet_whenTargetResolutionIsNotSet() {
         Preview useCase = new Preview.Builder().build();
         mCamera = CameraUtil.createCameraAndAttachUseCase(mContext, mCameraSelector, useCase);
-        ImageOutputConfig config = (ImageOutputConfig) useCase.getUseCaseConfig();
+        ImageOutputConfig config = (ImageOutputConfig) useCase.getCurrentConfig();
         assertThat(config.getTargetAspectRatio()).isEqualTo(AspectRatio.RATIO_4_3);
     }
 
@@ -366,20 +366,20 @@
         assumeTrue(CameraUtil.hasCameraWithLensFacing(CameraSelector.LENS_FACING_BACK));
         Preview useCase = new Preview.Builder().setTargetResolution(GUARANTEED_RESOLUTION).build();
 
-        assertThat(useCase.getUseCaseConfig().containsOption(
+        assertThat(useCase.getCurrentConfig().containsOption(
                 ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)).isFalse();
 
         mCamera = CameraUtil.createCameraAndAttachUseCase(mContext,
                 CameraSelector.DEFAULT_BACK_CAMERA, useCase);
 
-        assertThat(useCase.getUseCaseConfig().containsOption(
+        assertThat(useCase.getCurrentConfig().containsOption(
                 ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)).isFalse();
     }
 
     @Test
     public void useCaseConfigCanBeReset_afterUnbind() {
         final Preview preview = mDefaultBuilder.build();
-        UseCaseConfig<?> initialConfig = preview.getUseCaseConfig();
+        UseCaseConfig<?> initialConfig = preview.getCurrentConfig();
 
         mCamera = CameraUtil.createCameraAndAttachUseCase(mContext, mCameraSelector, preview);
 
@@ -387,7 +387,7 @@
             mCamera.removeUseCases(Collections.singleton(preview));
         });
 
-        UseCaseConfig<?> configAfterUnbinding = preview.getUseCaseConfig();
+        UseCaseConfig<?> configAfterUnbinding = preview.getCurrentConfig();
         assertThat(initialConfig.equals(configAfterUnbinding)).isTrue();
     }
 
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplTest.java
index 749e9ed..b7b4f65 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraControlImplTest.java
@@ -41,7 +41,6 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.Manifest;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.graphics.Rect;
@@ -79,7 +78,6 @@
 import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.GrantPermissionRule;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -88,6 +86,7 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
@@ -104,8 +103,7 @@
 @RunWith(AndroidJUnit4.class)
 public final class Camera2CameraControlImplTest {
     @Rule
-    public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(
-            Manifest.permission.CAMERA);
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
 
     private Camera2CameraControlImpl mCamera2CameraControlImpl;
     private CameraControlInternal.ControlUpdateCallback mControlUpdateCallback;
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java
index 13e82f2..39717f0 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CameraImplTest.java
@@ -59,6 +59,8 @@
 import androidx.camera.core.impl.ImmediateSurface;
 import androidx.camera.core.impl.Observable;
 import androidx.camera.core.impl.SessionConfig;
+import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
 import androidx.camera.testing.CameraUtil;
 import androidx.camera.testing.HandlerUtil;
@@ -766,7 +768,7 @@
                 @NonNull ImageReader.OnImageAvailableListener listener) {
             super(config);
             // Ensure we're using the combined configuration (user config + defaults)
-            mConfig = (FakeUseCaseConfig) getUseCaseConfig();
+            mConfig = (FakeUseCaseConfig) getCurrentConfig();
 
             mImageAvailableListener = listener;
             mHandlerThread.start();
@@ -776,7 +778,15 @@
                             cameraSelector.getLensFacing();
             mCameraId = CameraUtil.getCameraIdWithLensFacing(lensFacing);
             onAttach(new FakeCamera(mCameraId, null,
-                    new FakeCameraInfoInternal(mCameraId, 0, lensFacing)));
+                            new FakeCameraInfoInternal(mCameraId, 0, lensFacing)),
+                    new UseCaseConfigFactory() {
+                        @Nullable
+                        @Override
+                        public <C extends UseCaseConfig<?>> C getConfig(
+                                @NonNull Class<C> configType) {
+                            return null;
+                        }
+                    });
             updateSuggestedResolution(new Size(640, 480));
         }
 
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ExposureDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ExposureDeviceTest.java
index 32ee4fd..3fc83e4 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ExposureDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/ExposureDeviceTest.java
@@ -61,6 +61,7 @@
 import androidx.camera.testing.fakes.FakeCameraDeviceSurfaceManager;
 import androidx.camera.testing.fakes.FakeUseCase;
 import androidx.camera.testing.fakes.FakeUseCaseConfig;
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory;
 import androidx.core.os.HandlerCompat;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -103,7 +104,7 @@
     @Rule
     public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
 
-    private ArrayList<FakeTestUseCase> mFakeTestUseCases = new ArrayList<>();
+    private final ArrayList<FakeTestUseCase> mFakeTestUseCases = new ArrayList<>();
     private Camera2CameraImpl mCamera2CameraImpl;
     private static ExecutorService sCameraExecutor;
     private static HandlerThread sCameraHandlerThread;
@@ -158,7 +159,7 @@
 
         mCameraUseCaseAdapter = new CameraUseCaseAdapter(mCamera2CameraImpl,
                 new LinkedHashSet<>(Collections.singleton(mCamera2CameraImpl)),
-                fakeCameraDeviceSurfaceManager);
+                fakeCameraDeviceSurfaceManager, new FakeUseCaseConfigFactory());
     }
 
     @After
@@ -459,7 +460,7 @@
 
     public static class FakeTestUseCase extends FakeUseCase {
         private DeferrableSurface mDeferrableSurface;
-        private CameraCaptureSession.StateCallback mSessionStateCallback;
+        private final CameraCaptureSession.StateCallback mSessionStateCallback;
         CameraCaptureSession.CaptureCallback mCameraCaptureCallback;
 
         FakeTestUseCase(
@@ -493,7 +494,7 @@
         }
 
         private void createPipeline(Size resolution) {
-            SessionConfig.Builder builder = SessionConfig.Builder.createFrom(getUseCaseConfig());
+            SessionConfig.Builder builder = SessionConfig.Builder.createFrom(getCurrentConfig());
 
             builder.setTemplateType(CameraDevice.TEMPLATE_PREVIEW);
             if (mDeferrableSurface != null) {
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/TorchControlDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/TorchControlDeviceTest.java
index fe8afe9..eeac253 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/TorchControlDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/TorchControlDeviceTest.java
@@ -33,7 +33,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
 import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.GrantPermissionRule;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -41,6 +40,7 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 
 import java.util.concurrent.ExecutionException;
@@ -54,8 +54,7 @@
     private static final int LENS_FACING = CameraSelector.LENS_FACING_BACK;
 
     @Rule
-    public GrantPermissionRule mCameraPermissionRule =
-            GrantPermissionRule.grant(android.Manifest.permission.CAMERA);
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
 
     private TorchControl mTorchControl;
     private CameraUseCaseAdapter mCamera;
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatDeviceTest.java
index bc553f9..4bdb7d5 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/compat/CameraDeviceCompatDeviceTest.java
@@ -21,7 +21,6 @@
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 
-import android.Manifest;
 import android.content.Context;
 import android.graphics.SurfaceTexture;
 import android.hardware.camera2.CameraAccessException;
@@ -38,17 +37,18 @@
 import androidx.annotation.NonNull;
 import androidx.camera.camera2.internal.compat.params.OutputConfigurationCompat;
 import androidx.camera.camera2.internal.compat.params.SessionConfigurationCompat;
+import androidx.camera.testing.CameraUtil;
 import androidx.core.os.HandlerCompat;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
-import androidx.test.rule.GrantPermissionRule;
 
 import org.junit.After;
 import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 
 import java.util.Collections;
@@ -67,8 +67,7 @@
 
     private final Semaphore mOpenCloseSemaphore = new Semaphore(0);
     @Rule
-    public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(
-            Manifest.permission.CAMERA);
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
     private CameraDevice mCameraDevice;
     private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
         @Override
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/util/FakeRepeatingUseCase.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/util/FakeRepeatingUseCase.java
deleted file mode 100644
index b91a252..0000000
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/util/FakeRepeatingUseCase.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2019 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.camera.camera2.internal.util;
-
-import android.graphics.ImageFormat;
-import android.hardware.camera2.CameraDevice;
-import android.media.Image;
-import android.media.ImageReader;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Size;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-import androidx.annotation.RestrictTo.Scope;
-import androidx.camera.core.impl.DeferrableSurface;
-import androidx.camera.core.impl.ImmediateSurface;
-import androidx.camera.core.impl.SessionConfig;
-import androidx.camera.core.impl.UseCaseConfig;
-import androidx.camera.core.impl.utils.executor.CameraXExecutors;
-import androidx.camera.testing.fakes.FakeUseCase;
-import androidx.camera.testing.fakes.FakeUseCaseConfig;
-
-/**
- * A fake {@link FakeUseCase} which contain a repeating surface.
- *
- * @hide
- */
-@RestrictTo(Scope.LIBRARY)
-public class FakeRepeatingUseCase extends FakeUseCase {
-
-    private DeferrableSurface mDeferrableSurface;
-
-    public FakeRepeatingUseCase(@NonNull FakeUseCaseConfig configuration) {
-        super(configuration);
-    }
-
-    @Override
-    public UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder() {
-        return new FakeUseCaseConfig.Builder()
-                .setSessionOptionUnpacker(
-                        (useCaseConfig, sessionConfigBuilder) -> {
-                            // Set the template since it is currently required by implementation
-                            sessionConfigBuilder.setTemplateType(CameraDevice.TEMPLATE_PREVIEW);
-                        });
-    }
-
-    @Override
-    public void onDetached() {
-        super.onDetached();
-        if (mDeferrableSurface != null) {
-            mDeferrableSurface.close();
-        }
-        mDeferrableSurface = null;
-    }
-
-    @Override
-    @NonNull
-    protected Size onSuggestedResolutionUpdated(@NonNull Size suggestedResolution) {
-        FakeUseCaseConfig configWithDefaults = (FakeUseCaseConfig) getUseCaseConfig();
-
-        ImageReader imageReader = ImageReader.newInstance(640, 480, ImageFormat.YUV_420_888, 2);
-
-        imageReader.setOnImageAvailableListener(
-                reader -> {
-                    Image image = reader.acquireLatestImage();
-                    if (image != null) {
-                        image.close();
-                    }
-                },
-                new Handler(Looper.getMainLooper()));
-
-        SessionConfig.Builder builder = SessionConfig.Builder.createFrom(configWithDefaults);
-        if (mDeferrableSurface != null) {
-            mDeferrableSurface.close();
-        }
-        mDeferrableSurface = new ImmediateSurface(imageReader.getSurface());
-        mDeferrableSurface.getTerminationFuture().addListener(imageReader::close,
-                CameraXExecutors.mainThreadExecutor());
-        builder.addSurface(mDeferrableSurface);
-
-        updateSessionConfig(builder.build());
-        notifyActive();
-
-        return new Size(640, 480);
-    }
-}
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2InteropDeviceTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2InteropDeviceTest.java
index c34f231..58eb8d2 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2InteropDeviceTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/interop/Camera2InteropDeviceTest.java
@@ -24,7 +24,6 @@
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 
-import android.Manifest;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.graphics.Rect;
@@ -49,12 +48,12 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.LargeTest;
 import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.GrantPermissionRule;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 
@@ -76,8 +75,7 @@
     private CameraUseCaseAdapter mCamera;
 
     @Rule
-    public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(
-            Manifest.permission.CAMERA);
+    public TestRule mUseCamera = CameraUtil.grantCameraPermissionAndPreTest();
 
     @Before
     public void setUp() {
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/PreviewConfigProvider.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/PreviewConfigProvider.java
index e7146ef..4025db2 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/PreviewConfigProvider.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/PreviewConfigProvider.java
@@ -59,6 +59,8 @@
         captureBuilder.setTemplateType(CameraDevice.TEMPLATE_PREVIEW);
         builder.setDefaultCaptureConfig(captureBuilder.build());
         builder.setCaptureOptionUnpacker(Camera2CaptureOptionUnpacker.INSTANCE);
+
+        builder.setMaxResolution(SupportedSurfaceCombination.getPreviewSize(mWindowManager));
         builder.setTargetAspectRatio(AspectRatio.RATIO_4_3);
 
         // TODO(b/160477756): Make UseCase default config providers only provider static configs
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
index 47ebf56..b16f526 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/SupportedSurfaceCombination.java
@@ -1148,7 +1148,8 @@
      * (1920x1080), whichever is smaller.
      */
     @SuppressWarnings("deprecation") /* defaultDisplay */
-    private Size getPreviewSize(WindowManager windowManager) {
+    @NonNull
+    public static Size getPreviewSize(@NonNull WindowManager windowManager) {
         Point displaySize = new Point();
         windowManager.getDefaultDisplay().getRealSize(displaySize);
 
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManagerTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManagerTest.java
index 08a4c7b..5c6d82e 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManagerTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/Camera2DeviceSurfaceManagerTest.java
@@ -134,6 +134,7 @@
 
     private final Context mContext = ApplicationProvider.getApplicationContext();
     private CameraDeviceSurfaceManager mSurfaceManager;
+    private UseCaseConfigFactory mUseCaseConfigFactory;
     private FakeCameraFactory mCameraFactory;
 
     @Before
@@ -352,7 +353,8 @@
         useCases.add(preview);
 
         Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
-                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+                        mUseCaseConfigFactory);
         // A legacy level camera device can't support JPEG (ImageCapture) + PRIV (VideoCapture) +
         // PRIV (Preview) combination. An IllegalArgumentException will be thrown when trying to
         // bind these use cases at the same time.
@@ -378,7 +380,8 @@
         useCases.add(preview);
 
         Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
-                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+                        mUseCaseConfigFactory);
         Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
                 mSurfaceManager.getSuggestedResolutions(LIMITED_CAMERA_ID, Collections.emptyList(),
                         new ArrayList<>(useCaseToConfigMap.values()));
@@ -573,7 +576,14 @@
     private void initCameraX() {
         CameraXConfig cameraXConfig = createFakeAppConfig();
         CameraX.initialize(mContext, cameraXConfig);
-        mSurfaceManager = CameraX.getSurfaceManager();
+        CameraX cameraX;
+        try {
+            cameraX = CameraX.getOrCreateInstance(mContext).get();
+        } catch (ExecutionException | InterruptedException e) {
+            throw new IllegalStateException("Unable to initialize CameraX for test.");
+        }
+        mSurfaceManager = cameraX.getCameraDeviceSurfaceManager();
+        mUseCaseConfigFactory = cameraX.getDefaultConfigFactory();
     }
 
     private CameraXConfig createFakeAppConfig() {
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSizeConstraintsTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSizeConstraintsTest.java
index 8cd2ef8..e7a338b 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSizeConstraintsTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSizeConstraintsTest.java
@@ -147,7 +147,7 @@
         FakeUseCase useCase = new FakeUseCaseConfig.Builder().setBufferFormat(
                 ImageFormat.JPEG).build();
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
 
         for (Size size : excludedSizes) {
             assertThat(resultList.contains(size)).isFalse();
@@ -178,7 +178,7 @@
         FakeUseCase useCase = new FakeUseCaseConfig.Builder().setBufferFormat(
                 ImageFormat.JPEG).build();
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
 
         for (Size size : excludedSizes) {
             assertThat(resultList.contains(size)).isFalse();
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.java
index a71184d..7896141 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/SupportedSurfaceCombinationTest.java
@@ -54,6 +54,7 @@
 import androidx.camera.core.impl.SurfaceConfig.ConfigSize;
 import androidx.camera.core.impl.SurfaceConfig.ConfigType;
 import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
 import androidx.camera.core.internal.CameraUseCaseAdapter;
 import androidx.camera.testing.CameraUtil;
@@ -154,6 +155,7 @@
 
     private final Context mContext = RuntimeEnvironment.application.getApplicationContext();
     private FakeCameraFactory mCameraFactory;
+    private UseCaseConfigFactory mUseCaseConfigFactory;
 
     @Before
     @SuppressWarnings("deprecation") /* defaultDisplay */
@@ -491,7 +493,8 @@
         List<UseCase> useCases = new ArrayList<>();
         useCases.add(fakeUseCase);
         Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
-                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+                        mUseCaseConfigFactory);
         Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
                 supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
                         new ArrayList<>(useCaseToConfigMap.values()));
@@ -600,7 +603,8 @@
         useCases.add(imageCapture);
         useCases.add(imageAnalysis);
         Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
-                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+                        mUseCaseConfigFactory);
         Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
                 supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
                         new ArrayList<>(useCaseToConfigMap.values()));
@@ -647,7 +651,8 @@
         List<UseCase> useCases = new ArrayList<>();
         useCases.add(preview);
         Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
-                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+                        mUseCaseConfigFactory);
         Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
                 supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
                         new ArrayList<>(useCaseToConfigMap.values()));
@@ -683,10 +688,10 @@
 
             Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
                     supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
-                            Collections.singletonList(imageCapture.getUseCaseConfig()));
+                            Collections.singletonList(imageCapture.getCurrentConfig()));
 
             assertThat(targetResolution).isEqualTo(
-                    suggestedResolutionMap.get(imageCapture.getUseCaseConfig()));
+                    suggestedResolutionMap.get(imageCapture.getCurrentConfig()));
         }
     }
 
@@ -707,10 +712,10 @@
 
         Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
                 supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
-                        Arrays.asList(imageCapture.getUseCaseConfig()));
+                        Arrays.asList(imageCapture.getCurrentConfig()));
 
         assertThat(new Size(1280, 720)).isEqualTo(
-                suggestedResolutionMap.get(imageCapture.getUseCaseConfig()));
+                suggestedResolutionMap.get(imageCapture.getCurrentConfig()));
     }
 
 
@@ -736,7 +741,8 @@
         useCases.add(videoCapture);
         useCases.add(preview);
         Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
-                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+                        mUseCaseConfigFactory);
         Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
                 supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
                         new ArrayList<>(useCaseToConfigMap.values()));
@@ -767,7 +773,8 @@
         useCases.add(preview);
 
         Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
-                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+                        mUseCaseConfigFactory);
         Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
                 supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
                         new ArrayList<>(useCaseToConfigMap.values()));
@@ -809,7 +816,8 @@
         useCases.add(preview);
         useCases.add(imageAnalysis);
         Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
-                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+                        mUseCaseConfigFactory);
         Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
                 supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
                         new ArrayList<>(useCaseToConfigMap.values()));
@@ -843,7 +851,8 @@
         useCases.add(preview);
         useCases.add(imageAnalysis);
         Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
-                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+                        mUseCaseConfigFactory);
         Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
                 supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
                         new ArrayList<>(useCaseToConfigMap.values()));
@@ -924,7 +933,8 @@
         useCases.add(videoCapture);
         useCases.add(preview);
         Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
-                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+                        mUseCaseConfigFactory);
         Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
                 supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
                         new ArrayList<>(useCaseToConfigMap.values()));
@@ -1104,7 +1114,8 @@
         useCases.add(imageCapture);
 
         Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
-                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases);
+                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(useCases,
+                        mUseCaseConfigFactory);
         Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
                 supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
                         new ArrayList<>(useCaseToConfigMap.values()));
@@ -1147,7 +1158,7 @@
         // removed. No any aspect ratio related setting. The returned sizes list will be sorted in
         // descending order.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 new Size(4032, 3024),
                 new Size(3840, 2160),
@@ -1176,7 +1187,7 @@
         // list is sorted in descending order. Other items will be put in the following that are
         // sorted by aspect ratio delta and then area size.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 // Matched AspectRatio items, sorted by area size.
                 new Size(4032, 3024),
@@ -1209,7 +1220,7 @@
         // list is sorted in descending order. Other items will be put in the following that are
         // sorted by aspect ratio delta and then area size.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 // Matched AspectRatio items, sorted by area size.
                 new Size(3840, 2160),
@@ -1239,7 +1250,7 @@
                         AspectRatio.RATIO_16_9).build();
 
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList;
         // There is default minimum size 640x480 setting. Sizes smaller than 640x480 will be
         // removed.
@@ -1304,7 +1315,7 @@
         // order. Other items will be put in the following that are sorted by aspect ratio delta
         // and then area size.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 // Matched AspectRatio items, sorted by area size.
                 new Size(1920, 1080),
@@ -1333,7 +1344,7 @@
         // Unnecessary big enough sizes will be removed from the result list. There is default
         // minimum size 640x480 setting. Sizes smaller than 640x480 will also be removed.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList;
         if (Build.VERSION.SDK_INT == 21) {
             // Sizes with the same aspect ratio as maximum JPEG resolution will be in front of
@@ -1395,7 +1406,7 @@
         // items will be put in the following that are sorted by aspect ratio delta and then area
         // size.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 // Matched AspectRatio items, sorted by area size.
                 new Size(1280, 960),
@@ -1428,7 +1439,7 @@
         // order. Other items will be put in the following that are sorted by aspect ratio delta
         // and then area size.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 // Matched AspectRatio items, sorted by area size.
                 new Size(320, 240),
@@ -1456,7 +1467,7 @@
         // therefore, sizes of aspect ratio 4/3 will be in front of the returned sizes list and
         // the list is sorted in descending order.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 // Sizes of 4/3 are near to aspect ratio of 1800/1440
                 new Size(1920, 1440),
@@ -1490,7 +1501,7 @@
         // therefore, sizes of aspect ratio 16/9 will be in front of the returned sizes list and
         // the list is sorted in descending order.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 // Sizes of 16/9 are near to aspect ratio of 1280/600
                 new Size(1280, 720),
@@ -1517,7 +1528,7 @@
         // larger than 1280x720 will be removed. The returned sizes list will be sorted in
         // descending order.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 new Size(1280, 720),
                 new Size(960, 544),
@@ -1542,7 +1553,7 @@
         // resolution as 1280x720. Unnecessary big enough sizes will also be removed. The
         // returned sizes list will be sorted in descending order.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 new Size(1280, 720),
                 new Size(960, 544),
@@ -1570,7 +1581,7 @@
         // in descending order.  Other items will be put in the following that are sorted by
         // aspect ratio delta and then area size.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 // Matched AspectRatio items, sorted by area size.
                 new Size(1920, 1080),
@@ -1605,7 +1616,7 @@
         // removed. There is target resolution 1920x1080 (16:9). Even 640x480 does not match 16:9
         // requirement, it will still be returned to use.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 new Size(640, 480)
         });
@@ -1632,7 +1643,7 @@
         // bound and it is also smaller than 640x480, the default minimum size bound will be
         // ignored. Then, sizes equal to or smaller than 320x240 will be kept in the result list.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 new Size(320, 240),
                 new Size(320, 180),
@@ -1663,7 +1674,7 @@
         // size bound will be ignored. Then, sizes equal to or smaller than 320x180 will be kept
         // in the result list.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 new Size(320, 180),
                 new Size(256, 144)
@@ -1693,7 +1704,7 @@
         // size bound will be ignored. Then, all sizes equal to or smaller than 320x320 will be
         // kept in the result list.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 new Size(320, 180),
                 new Size(256, 144),
@@ -1721,7 +1732,7 @@
         // order. Other items will be put in the following that are sorted by aspect ratio delta
         // and then area size.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 // Matched AspectRatio items, sorted by area size.
                 new Size(1920, 1080),
@@ -1758,7 +1769,7 @@
         // smaller than 640x480, the default minimum size bound will be ignored. Then, sizes
         // equal to or smaller than 320x200 will be kept in the result list.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 new Size(320, 180),
                 new Size(256, 144)
@@ -1786,7 +1797,7 @@
         // filtered out by it. The result list will only keep one big enough size of aspect ratio
         // 4:3 and 16:9.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 new Size(320, 240),
                 new Size(256, 144)
@@ -1811,7 +1822,7 @@
 
         // All sizes will be filtered out by the max resolution 192x144 setting and an
         // IllegalArgumentException will be thrown.
-        supportedSurfaceCombination.getSupportedOutputSizes(useCase.getUseCaseConfig());
+        supportedSurfaceCombination.getSupportedOutputSizes(useCase.getCurrentConfig());
     }
 
     @Test
@@ -1836,7 +1847,7 @@
         // result list. After ignoring mod 16 calculation for small sizes, 256x144 will still be
         // kept as a 16:9 resolution as the result.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 new Size(296, 144),
                 new Size(256, 144),
@@ -1866,14 +1877,8 @@
         FakeUseCase useCase = new FakeUseCaseConfig.Builder().setTargetResolution(
                 new Size(1080, 2016)).build();
 
-        Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap =
-                Configs.useCaseConfigMapWithDefaultSettingsFromUseCaseList(Arrays.asList(useCase));
-        Map<UseCaseConfig<?>, Size> suggestedResolutionMap =
-                supportedSurfaceCombination.getSuggestedResolutions(Collections.emptyList(),
-                        new ArrayList<>(useCaseToConfigMap.values()));
-
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 new Size(1920, 1080),
                 new Size(1280, 720),
@@ -1916,7 +1921,7 @@
         // items will be put in the following that are sorted by aspect ratio delta and then area
         // size.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 // Matched AspectRatio items, sorted by area size.
                 new Size(1080, 1920),
@@ -1962,7 +1967,7 @@
         // items will be put in the following that are sorted by aspect ratio delta and then area
         // size.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 // Matched AspectRatio items, sorted by area size.
                 new Size(1080, 1920),
@@ -1994,7 +1999,7 @@
         // list is sorted in descending order. Other items will be put in the following that are
         // sorted by aspect ratio delta and then area size.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 // Matched AspectRatio items, sorted by area size.
                 new Size(3840, 2160),
@@ -2038,7 +2043,7 @@
         // list is sorted in descending order. Other items will be put in the following that are
         // sorted by aspect ratio delta and then area size.
         List<Size> resultList = supportedSurfaceCombination.getSupportedOutputSizes(
-                useCase.getUseCaseConfig());
+                useCase.getCurrentConfig());
         List<Size> expectedList = Arrays.asList(new Size[]{
                 // Matched AspectRatio items, sorted by area size.
                 new Size(1920, 1080),
@@ -2132,6 +2137,13 @@
                 .setCameraFactoryProvider((ignored0, ignored1) -> mCameraFactory)
                 .build();
         CameraX.initialize(mContext, cameraXConfig);
+        CameraX cameraX;
+        try {
+            cameraX = CameraX.getOrCreateInstance(mContext).get();
+        } catch (ExecutionException | InterruptedException e) {
+            throw new IllegalStateException("Unable to initialize CameraX for test.");
+        }
+        mUseCaseConfigFactory = cameraX.getDefaultConfigFactory();
     }
 
     private boolean isRawSupported(int[] capabilities) {
diff --git a/camera/camera-core/api/1.0.0-beta10.txt b/camera/camera-core/api/1.0.0-beta10.txt
new file mode 100644
index 0000000..0a36e63
--- /dev/null
+++ b/camera/camera-core/api/1.0.0-beta10.txt
@@ -0,0 +1,306 @@
+// Signature format: 3.0
+package androidx.camera.core {
+
+  public class AspectRatio {
+    field public static final int RATIO_16_9 = 1; // 0x1
+    field public static final int RATIO_4_3 = 0; // 0x0
+  }
+
+  public interface Camera {
+    method public androidx.camera.core.CameraControl getCameraControl();
+    method public androidx.camera.core.CameraInfo getCameraInfo();
+  }
+
+  public interface CameraControl {
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelFocusAndMetering();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
+  }
+
+  public static final class CameraControl.OperationCanceledException extends java.lang.Exception {
+  }
+
+  public interface CameraInfo {
+    method public int getSensorRotationDegrees();
+    method public int getSensorRotationDegrees(int);
+    method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+    method public androidx.lifecycle.LiveData<androidx.camera.core.ZoomState!> getZoomState();
+    method public boolean hasFlashUnit();
+  }
+
+  public final class CameraInfoUnavailableException extends java.lang.Exception {
+  }
+
+  public final class CameraSelector {
+    field public static final androidx.camera.core.CameraSelector DEFAULT_BACK_CAMERA;
+    field public static final androidx.camera.core.CameraSelector DEFAULT_FRONT_CAMERA;
+    field public static final int LENS_FACING_BACK = 1; // 0x1
+    field public static final int LENS_FACING_FRONT = 0; // 0x0
+  }
+
+  public static final class CameraSelector.Builder {
+    ctor public CameraSelector.Builder();
+    method public androidx.camera.core.CameraSelector build();
+    method public androidx.camera.core.CameraSelector.Builder requireLensFacing(int);
+  }
+
+  public class CameraUnavailableException extends java.lang.Exception {
+    ctor public CameraUnavailableException(int);
+    ctor public CameraUnavailableException(int, String?);
+    ctor public CameraUnavailableException(int, String?, Throwable?);
+    ctor public CameraUnavailableException(int, Throwable?);
+    method public int getReason();
+    field public static final int CAMERA_DISABLED = 1; // 0x1
+    field public static final int CAMERA_DISCONNECTED = 2; // 0x2
+    field public static final int CAMERA_ERROR = 3; // 0x3
+    field public static final int CAMERA_IN_USE = 4; // 0x4
+    field public static final int CAMERA_MAX_IN_USE = 5; // 0x5
+    field public static final int CAMERA_UNAVAILABLE_DO_NOT_DISTURB = 6; // 0x6
+    field public static final int CAMERA_UNKNOWN_ERROR = 0; // 0x0
+  }
+
+  public final class CameraXConfig {
+  }
+
+  public static final class CameraXConfig.Builder {
+    method public androidx.camera.core.CameraXConfig build();
+    method public static androidx.camera.core.CameraXConfig.Builder fromConfig(androidx.camera.core.CameraXConfig);
+    method public androidx.camera.core.CameraXConfig.Builder setCameraExecutor(java.util.concurrent.Executor);
+  }
+
+  public static interface CameraXConfig.Provider {
+    method public androidx.camera.core.CameraXConfig getCameraXConfig();
+  }
+
+  public final class DisplayOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+    ctor public DisplayOrientedMeteringPointFactory(android.view.Display, androidx.camera.core.CameraInfo, float, float);
+  }
+
+  public interface ExtendableBuilder<T> {
+    method public T build();
+  }
+
+  public final class FocusMeteringAction {
+    method public long getAutoCancelDurationInMillis();
+    method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAe();
+    method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAf();
+    method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAwb();
+    method public boolean isAutoCancelEnabled();
+    field public static final int FLAG_AE = 2; // 0x2
+    field public static final int FLAG_AF = 1; // 0x1
+    field public static final int FLAG_AWB = 4; // 0x4
+  }
+
+  public static class FocusMeteringAction.Builder {
+    ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint);
+    ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint, int);
+    method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint);
+    method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint, int);
+    method public androidx.camera.core.FocusMeteringAction build();
+    method public androidx.camera.core.FocusMeteringAction.Builder disableAutoCancel();
+    method public androidx.camera.core.FocusMeteringAction.Builder setAutoCancelDuration(@IntRange(from=1) long, java.util.concurrent.TimeUnit);
+  }
+
+  public final class FocusMeteringResult {
+    method public boolean isFocusSuccessful();
+  }
+
+  public final class ImageAnalysis extends androidx.camera.core.UseCase {
+    method public void clearAnalyzer();
+    method public int getBackpressureStrategy();
+    method public int getImageQueueDepth();
+    method public int getTargetRotation();
+    method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+    method public void setTargetRotation(int);
+    field public static final int STRATEGY_BLOCK_PRODUCER = 1; // 0x1
+    field public static final int STRATEGY_KEEP_ONLY_LATEST = 0; // 0x0
+  }
+
+  public static interface ImageAnalysis.Analyzer {
+    method public void analyze(androidx.camera.core.ImageProxy);
+  }
+
+  public static final class ImageAnalysis.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageAnalysis> {
+    ctor public ImageAnalysis.Builder();
+    method public androidx.camera.core.ImageAnalysis build();
+    method public androidx.camera.core.ImageAnalysis.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+    method public androidx.camera.core.ImageAnalysis.Builder setBackpressureStrategy(int);
+    method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
+    method public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
+    method public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+    method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
+  }
+
+  public final class ImageCapture extends androidx.camera.core.UseCase {
+    method public int getCaptureMode();
+    method public int getFlashMode();
+    method public int getTargetRotation();
+    method public void setCropAspectRatio(android.util.Rational);
+    method public void setFlashMode(int);
+    method public void setTargetRotation(int);
+    method public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+    method public void takePicture(androidx.camera.core.ImageCapture.OutputFileOptions, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+    field public static final int CAPTURE_MODE_MAXIMIZE_QUALITY = 0; // 0x0
+    field public static final int CAPTURE_MODE_MINIMIZE_LATENCY = 1; // 0x1
+    field public static final int ERROR_CAMERA_CLOSED = 3; // 0x3
+    field public static final int ERROR_CAPTURE_FAILED = 2; // 0x2
+    field public static final int ERROR_FILE_IO = 1; // 0x1
+    field public static final int ERROR_INVALID_CAMERA = 4; // 0x4
+    field public static final int ERROR_UNKNOWN = 0; // 0x0
+    field public static final int FLASH_MODE_AUTO = 0; // 0x0
+    field public static final int FLASH_MODE_OFF = 2; // 0x2
+    field public static final int FLASH_MODE_ON = 1; // 0x1
+  }
+
+  public static final class ImageCapture.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageCapture> {
+    ctor public ImageCapture.Builder();
+    method public androidx.camera.core.ImageCapture build();
+    method public androidx.camera.core.ImageCapture.Builder setCaptureMode(int);
+    method public androidx.camera.core.ImageCapture.Builder setFlashMode(int);
+    method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
+    method public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
+    method public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+    method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
+  }
+
+  public static final class ImageCapture.Metadata {
+    ctor public ImageCapture.Metadata();
+    method public android.location.Location? getLocation();
+    method public boolean isReversedHorizontal();
+    method public boolean isReversedVertical();
+    method public void setLocation(android.location.Location?);
+    method public void setReversedHorizontal(boolean);
+    method public void setReversedVertical(boolean);
+  }
+
+  public abstract static class ImageCapture.OnImageCapturedCallback {
+    ctor public ImageCapture.OnImageCapturedCallback();
+    method public void onCaptureSuccess(androidx.camera.core.ImageProxy);
+    method public void onError(androidx.camera.core.ImageCaptureException);
+  }
+
+  public static interface ImageCapture.OnImageSavedCallback {
+    method public void onError(androidx.camera.core.ImageCaptureException);
+    method public void onImageSaved(androidx.camera.core.ImageCapture.OutputFileResults);
+  }
+
+  public static final class ImageCapture.OutputFileOptions {
+  }
+
+  public static final class ImageCapture.OutputFileOptions.Builder {
+    ctor public ImageCapture.OutputFileOptions.Builder(java.io.File);
+    ctor public ImageCapture.OutputFileOptions.Builder(android.content.ContentResolver, android.net.Uri, android.content.ContentValues);
+    ctor public ImageCapture.OutputFileOptions.Builder(java.io.OutputStream);
+    method public androidx.camera.core.ImageCapture.OutputFileOptions build();
+    method public androidx.camera.core.ImageCapture.OutputFileOptions.Builder setMetadata(androidx.camera.core.ImageCapture.Metadata);
+  }
+
+  public static class ImageCapture.OutputFileResults {
+    method public android.net.Uri? getSavedUri();
+  }
+
+  public class ImageCaptureException extends java.lang.Exception {
+    ctor public ImageCaptureException(int, String, Throwable?);
+    method public int getImageCaptureError();
+  }
+
+  public interface ImageInfo {
+    method public int getRotationDegrees();
+    method public long getTimestamp();
+  }
+
+  public interface ImageProxy extends java.lang.AutoCloseable {
+    method public void close();
+    method public android.graphics.Rect getCropRect();
+    method public int getFormat();
+    method public int getHeight();
+    method public androidx.camera.core.ImageInfo getImageInfo();
+    method public androidx.camera.core.ImageProxy.PlaneProxy![] getPlanes();
+    method public int getWidth();
+    method public void setCropRect(android.graphics.Rect?);
+  }
+
+  public static interface ImageProxy.PlaneProxy {
+    method public java.nio.ByteBuffer getBuffer();
+    method public int getPixelStride();
+    method public int getRowStride();
+  }
+
+  public class InitializationException extends java.lang.Exception {
+    ctor public InitializationException(String?);
+    ctor public InitializationException(String?, Throwable?);
+    ctor public InitializationException(Throwable?);
+  }
+
+  public class MeteringPoint {
+    method public float getSize();
+  }
+
+  public abstract class MeteringPointFactory {
+    method public final androidx.camera.core.MeteringPoint createPoint(float, float);
+    method public final androidx.camera.core.MeteringPoint createPoint(float, float, float);
+    method public static float getDefaultPointSize();
+  }
+
+  public final class Preview extends androidx.camera.core.UseCase {
+    method public int getTargetRotation();
+    method @UiThread public void setSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.SurfaceProvider?);
+    method @UiThread public void setSurfaceProvider(androidx.camera.core.Preview.SurfaceProvider?);
+  }
+
+  public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
+    ctor public Preview.Builder();
+    method public androidx.camera.core.Preview build();
+    method public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.Preview.Builder setTargetName(String);
+    method public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+    method public androidx.camera.core.Preview.Builder setTargetRotation(int);
+  }
+
+  public static interface Preview.SurfaceProvider {
+    method public void onSurfaceRequested(androidx.camera.core.SurfaceRequest);
+  }
+
+  public class SurfaceOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+    ctor public SurfaceOrientedMeteringPointFactory(float, float);
+    ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
+  }
+
+  public final class SurfaceRequest {
+    method public void addRequestCancellationListener(java.util.concurrent.Executor, Runnable);
+    method public android.util.Size getResolution();
+    method public void provideSurface(android.view.Surface, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceRequest.Result!>);
+    method public boolean willNotProvideSurface();
+  }
+
+  @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.Result {
+    method public abstract int getResultCode();
+    method public abstract android.view.Surface getSurface();
+    field public static final int RESULT_INVALID_SURFACE = 2; // 0x2
+    field public static final int RESULT_REQUEST_CANCELLED = 1; // 0x1
+    field public static final int RESULT_SURFACE_ALREADY_PROVIDED = 3; // 0x3
+    field public static final int RESULT_SURFACE_USED_SUCCESSFULLY = 0; // 0x0
+    field public static final int RESULT_WILL_NOT_PROVIDE_SURFACE = 4; // 0x4
+  }
+
+  public class TorchState {
+    field public static final int OFF = 0; // 0x0
+    field public static final int ON = 1; // 0x1
+  }
+
+  public abstract class UseCase {
+  }
+
+  public interface ZoomState {
+    method public float getLinearZoom();
+    method public float getMaxZoomRatio();
+    method public float getMinZoomRatio();
+    method public float getZoomRatio();
+  }
+
+}
+
diff --git a/camera/camera-core/api/public_plus_experimental_1.0.0-beta10.txt b/camera/camera-core/api/public_plus_experimental_1.0.0-beta10.txt
new file mode 100644
index 0000000..7da2353
--- /dev/null
+++ b/camera/camera-core/api/public_plus_experimental_1.0.0-beta10.txt
@@ -0,0 +1,376 @@
+// Signature format: 3.0
+package androidx.camera.core {
+
+  public class AspectRatio {
+    field public static final int RATIO_16_9 = 1; // 0x1
+    field public static final int RATIO_4_3 = 0; // 0x0
+  }
+
+  public interface Camera {
+    method public androidx.camera.core.CameraControl getCameraControl();
+    method public androidx.camera.core.CameraInfo getCameraInfo();
+  }
+
+  public interface CameraControl {
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelFocusAndMetering();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+    method @androidx.camera.core.ExperimentalExposureCompensation public com.google.common.util.concurrent.ListenableFuture<java.lang.Integer!> setExposureCompensationIndex(int);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
+  }
+
+  public static final class CameraControl.OperationCanceledException extends java.lang.Exception {
+  }
+
+  @androidx.camera.core.ExperimentalCameraFilter public interface CameraFilter {
+    method public java.util.LinkedHashSet<androidx.camera.core.Camera!> filter(java.util.LinkedHashSet<androidx.camera.core.Camera!>);
+  }
+
+  public interface CameraInfo {
+    method @androidx.camera.core.ExperimentalExposureCompensation public androidx.camera.core.ExposureState getExposureState();
+    method public int getSensorRotationDegrees();
+    method public int getSensorRotationDegrees(int);
+    method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+    method public androidx.lifecycle.LiveData<androidx.camera.core.ZoomState!> getZoomState();
+    method public boolean hasFlashUnit();
+  }
+
+  public final class CameraInfoUnavailableException extends java.lang.Exception {
+  }
+
+  public final class CameraSelector {
+    field public static final androidx.camera.core.CameraSelector DEFAULT_BACK_CAMERA;
+    field public static final androidx.camera.core.CameraSelector DEFAULT_FRONT_CAMERA;
+    field public static final int LENS_FACING_BACK = 1; // 0x1
+    field public static final int LENS_FACING_FRONT = 0; // 0x0
+  }
+
+  public static final class CameraSelector.Builder {
+    ctor public CameraSelector.Builder();
+    method @androidx.camera.core.ExperimentalCameraFilter public androidx.camera.core.CameraSelector.Builder addCameraFilter(androidx.camera.core.CameraFilter);
+    method public androidx.camera.core.CameraSelector build();
+    method public androidx.camera.core.CameraSelector.Builder requireLensFacing(int);
+  }
+
+  public class CameraUnavailableException extends java.lang.Exception {
+    ctor public CameraUnavailableException(int);
+    ctor public CameraUnavailableException(int, String?);
+    ctor public CameraUnavailableException(int, String?, Throwable?);
+    ctor public CameraUnavailableException(int, Throwable?);
+    method public int getReason();
+    field public static final int CAMERA_DISABLED = 1; // 0x1
+    field public static final int CAMERA_DISCONNECTED = 2; // 0x2
+    field public static final int CAMERA_ERROR = 3; // 0x3
+    field public static final int CAMERA_IN_USE = 4; // 0x4
+    field public static final int CAMERA_MAX_IN_USE = 5; // 0x5
+    field public static final int CAMERA_UNAVAILABLE_DO_NOT_DISTURB = 6; // 0x6
+    field public static final int CAMERA_UNKNOWN_ERROR = 0; // 0x0
+  }
+
+  public final class CameraXConfig {
+  }
+
+  public static final class CameraXConfig.Builder {
+    method public androidx.camera.core.CameraXConfig build();
+    method public static androidx.camera.core.CameraXConfig.Builder fromConfig(androidx.camera.core.CameraXConfig);
+    method public androidx.camera.core.CameraXConfig.Builder setCameraExecutor(java.util.concurrent.Executor);
+    method @androidx.camera.core.ExperimentalCustomizableThreads public androidx.camera.core.CameraXConfig.Builder setSchedulerHandler(android.os.Handler);
+  }
+
+  public static interface CameraXConfig.Provider {
+    method public androidx.camera.core.CameraXConfig getCameraXConfig();
+  }
+
+  public final class DisplayOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+    ctor public DisplayOrientedMeteringPointFactory(android.view.Display, androidx.camera.core.CameraInfo, float, float);
+  }
+
+  @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalCameraFilter {
+  }
+
+  @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalCustomizableThreads {
+  }
+
+  @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalExposureCompensation {
+  }
+
+  @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalGetImage {
+  }
+
+  @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalUseCaseGroup {
+  }
+
+  @androidx.camera.core.ExperimentalExposureCompensation public interface ExposureState {
+    method public int getExposureCompensationIndex();
+    method public android.util.Range<java.lang.Integer!> getExposureCompensationRange();
+    method public android.util.Rational getExposureCompensationStep();
+    method public boolean isExposureCompensationSupported();
+  }
+
+  public interface ExtendableBuilder<T> {
+    method public T build();
+  }
+
+  public final class FocusMeteringAction {
+    method public long getAutoCancelDurationInMillis();
+    method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAe();
+    method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAf();
+    method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAwb();
+    method public boolean isAutoCancelEnabled();
+    field public static final int FLAG_AE = 2; // 0x2
+    field public static final int FLAG_AF = 1; // 0x1
+    field public static final int FLAG_AWB = 4; // 0x4
+  }
+
+  public static class FocusMeteringAction.Builder {
+    ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint);
+    ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint, int);
+    method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint);
+    method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint, int);
+    method public androidx.camera.core.FocusMeteringAction build();
+    method public androidx.camera.core.FocusMeteringAction.Builder disableAutoCancel();
+    method public androidx.camera.core.FocusMeteringAction.Builder setAutoCancelDuration(@IntRange(from=1) long, java.util.concurrent.TimeUnit);
+  }
+
+  public final class FocusMeteringResult {
+    method public boolean isFocusSuccessful();
+  }
+
+  public final class ImageAnalysis extends androidx.camera.core.UseCase {
+    method public void clearAnalyzer();
+    method public int getBackpressureStrategy();
+    method public int getImageQueueDepth();
+    method public int getTargetRotation();
+    method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+    method public void setTargetRotation(int);
+    field public static final int STRATEGY_BLOCK_PRODUCER = 1; // 0x1
+    field public static final int STRATEGY_KEEP_ONLY_LATEST = 0; // 0x0
+  }
+
+  public static interface ImageAnalysis.Analyzer {
+    method public void analyze(androidx.camera.core.ImageProxy);
+  }
+
+  public static final class ImageAnalysis.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageAnalysis> {
+    ctor public ImageAnalysis.Builder();
+    method public androidx.camera.core.ImageAnalysis build();
+    method public androidx.camera.core.ImageAnalysis.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+    method public androidx.camera.core.ImageAnalysis.Builder setBackpressureStrategy(int);
+    method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
+    method public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
+    method public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+    method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
+  }
+
+  public final class ImageCapture extends androidx.camera.core.UseCase {
+    method public int getCaptureMode();
+    method public int getFlashMode();
+    method public int getTargetRotation();
+    method public void setCropAspectRatio(android.util.Rational);
+    method public void setFlashMode(int);
+    method public void setTargetRotation(int);
+    method public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+    method public void takePicture(androidx.camera.core.ImageCapture.OutputFileOptions, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+    field public static final int CAPTURE_MODE_MAXIMIZE_QUALITY = 0; // 0x0
+    field public static final int CAPTURE_MODE_MINIMIZE_LATENCY = 1; // 0x1
+    field public static final int ERROR_CAMERA_CLOSED = 3; // 0x3
+    field public static final int ERROR_CAPTURE_FAILED = 2; // 0x2
+    field public static final int ERROR_FILE_IO = 1; // 0x1
+    field public static final int ERROR_INVALID_CAMERA = 4; // 0x4
+    field public static final int ERROR_UNKNOWN = 0; // 0x0
+    field public static final int FLASH_MODE_AUTO = 0; // 0x0
+    field public static final int FLASH_MODE_OFF = 2; // 0x2
+    field public static final int FLASH_MODE_ON = 1; // 0x1
+  }
+
+  public static final class ImageCapture.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageCapture> {
+    ctor public ImageCapture.Builder();
+    method public androidx.camera.core.ImageCapture build();
+    method public androidx.camera.core.ImageCapture.Builder setCaptureMode(int);
+    method public androidx.camera.core.ImageCapture.Builder setFlashMode(int);
+    method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
+    method public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
+    method public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+    method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
+  }
+
+  public static final class ImageCapture.Metadata {
+    ctor public ImageCapture.Metadata();
+    method public android.location.Location? getLocation();
+    method public boolean isReversedHorizontal();
+    method public boolean isReversedVertical();
+    method public void setLocation(android.location.Location?);
+    method public void setReversedHorizontal(boolean);
+    method public void setReversedVertical(boolean);
+  }
+
+  public abstract static class ImageCapture.OnImageCapturedCallback {
+    ctor public ImageCapture.OnImageCapturedCallback();
+    method public void onCaptureSuccess(androidx.camera.core.ImageProxy);
+    method public void onError(androidx.camera.core.ImageCaptureException);
+  }
+
+  public static interface ImageCapture.OnImageSavedCallback {
+    method public void onError(androidx.camera.core.ImageCaptureException);
+    method public void onImageSaved(androidx.camera.core.ImageCapture.OutputFileResults);
+  }
+
+  public static final class ImageCapture.OutputFileOptions {
+  }
+
+  public static final class ImageCapture.OutputFileOptions.Builder {
+    ctor public ImageCapture.OutputFileOptions.Builder(java.io.File);
+    ctor public ImageCapture.OutputFileOptions.Builder(android.content.ContentResolver, android.net.Uri, android.content.ContentValues);
+    ctor public ImageCapture.OutputFileOptions.Builder(java.io.OutputStream);
+    method public androidx.camera.core.ImageCapture.OutputFileOptions build();
+    method public androidx.camera.core.ImageCapture.OutputFileOptions.Builder setMetadata(androidx.camera.core.ImageCapture.Metadata);
+  }
+
+  public static class ImageCapture.OutputFileResults {
+    method public android.net.Uri? getSavedUri();
+  }
+
+  public class ImageCaptureException extends java.lang.Exception {
+    ctor public ImageCaptureException(int, String, Throwable?);
+    method public int getImageCaptureError();
+  }
+
+  public interface ImageInfo {
+    method public int getRotationDegrees();
+    method public long getTimestamp();
+  }
+
+  public interface ImageProxy extends java.lang.AutoCloseable {
+    method public void close();
+    method public android.graphics.Rect getCropRect();
+    method public int getFormat();
+    method public int getHeight();
+    method @androidx.camera.core.ExperimentalGetImage public android.media.Image? getImage();
+    method public androidx.camera.core.ImageInfo getImageInfo();
+    method public androidx.camera.core.ImageProxy.PlaneProxy![] getPlanes();
+    method public int getWidth();
+    method public void setCropRect(android.graphics.Rect?);
+  }
+
+  public static interface ImageProxy.PlaneProxy {
+    method public java.nio.ByteBuffer getBuffer();
+    method public int getPixelStride();
+    method public int getRowStride();
+  }
+
+  public class InitializationException extends java.lang.Exception {
+    ctor public InitializationException(String?);
+    ctor public InitializationException(String?, Throwable?);
+    ctor public InitializationException(Throwable?);
+  }
+
+  public class MeteringPoint {
+    method public float getSize();
+  }
+
+  public abstract class MeteringPointFactory {
+    method public final androidx.camera.core.MeteringPoint createPoint(float, float);
+    method public final androidx.camera.core.MeteringPoint createPoint(float, float, float);
+    method public static float getDefaultPointSize();
+  }
+
+  public final class Preview extends androidx.camera.core.UseCase {
+    method public int getTargetRotation();
+    method @UiThread public void setSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.SurfaceProvider?);
+    method @UiThread public void setSurfaceProvider(androidx.camera.core.Preview.SurfaceProvider?);
+    method @androidx.camera.core.ExperimentalUseCaseGroup public void setTargetRotation(int);
+  }
+
+  public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
+    ctor public Preview.Builder();
+    method public androidx.camera.core.Preview build();
+    method public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.Preview.Builder setTargetName(String);
+    method public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+    method public androidx.camera.core.Preview.Builder setTargetRotation(int);
+  }
+
+  public static interface Preview.SurfaceProvider {
+    method public void onSurfaceRequested(androidx.camera.core.SurfaceRequest);
+  }
+
+  public class SurfaceOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+    ctor public SurfaceOrientedMeteringPointFactory(float, float);
+    ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
+  }
+
+  public final class SurfaceRequest {
+    method public void addRequestCancellationListener(java.util.concurrent.Executor, Runnable);
+    method @androidx.camera.core.ExperimentalUseCaseGroup public void clearTransformationInfoListener();
+    method public android.util.Size getResolution();
+    method public void provideSurface(android.view.Surface, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceRequest.Result!>);
+    method @androidx.camera.core.ExperimentalUseCaseGroup public void setTransformationInfoListener(java.util.concurrent.Executor, androidx.camera.core.SurfaceRequest.TransformationInfoListener);
+    method public boolean willNotProvideSurface();
+  }
+
+  @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.Result {
+    method public abstract int getResultCode();
+    method public abstract android.view.Surface getSurface();
+    field public static final int RESULT_INVALID_SURFACE = 2; // 0x2
+    field public static final int RESULT_REQUEST_CANCELLED = 1; // 0x1
+    field public static final int RESULT_SURFACE_ALREADY_PROVIDED = 3; // 0x3
+    field public static final int RESULT_SURFACE_USED_SUCCESSFULLY = 0; // 0x0
+    field public static final int RESULT_WILL_NOT_PROVIDE_SURFACE = 4; // 0x4
+  }
+
+  @androidx.camera.core.ExperimentalUseCaseGroup @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.TransformationInfo {
+    method public abstract android.graphics.Rect getCropRect();
+    method public abstract int getRotationDegrees();
+  }
+
+  @androidx.camera.core.ExperimentalUseCaseGroup public static interface SurfaceRequest.TransformationInfoListener {
+    method public void onTransformationInfoUpdate(androidx.camera.core.SurfaceRequest.TransformationInfo);
+  }
+
+  public class TorchState {
+    field public static final int OFF = 0; // 0x0
+    field public static final int ON = 1; // 0x1
+  }
+
+  public abstract class UseCase {
+  }
+
+  @androidx.camera.core.ExperimentalUseCaseGroup public final class UseCaseGroup {
+    method public java.util.List<androidx.camera.core.UseCase!> getUseCases();
+    method public androidx.camera.core.ViewPort? getViewPort();
+  }
+
+  @androidx.camera.core.ExperimentalUseCaseGroup public static final class UseCaseGroup.Builder {
+    ctor public UseCaseGroup.Builder();
+    method public androidx.camera.core.UseCaseGroup.Builder addUseCase(androidx.camera.core.UseCase);
+    method public androidx.camera.core.UseCaseGroup build();
+    method public androidx.camera.core.UseCaseGroup.Builder setViewPort(androidx.camera.core.ViewPort);
+  }
+
+  @androidx.camera.core.ExperimentalUseCaseGroup public final class ViewPort {
+    method public android.util.Rational getAspectRatio();
+    method public int getRotation();
+    method public int getScaleType();
+    field public static final int FILL_CENTER = 1; // 0x1
+    field public static final int FILL_END = 2; // 0x2
+    field public static final int FILL_START = 0; // 0x0
+    field public static final int FIT = 3; // 0x3
+  }
+
+  @androidx.camera.core.ExperimentalUseCaseGroup public static final class ViewPort.Builder {
+    ctor public ViewPort.Builder(android.util.Rational, int);
+    method public androidx.camera.core.ViewPort build();
+  }
+
+  public interface ZoomState {
+    method public float getLinearZoom();
+    method public float getMaxZoomRatio();
+    method public float getMinZoomRatio();
+    method public float getZoomRatio();
+  }
+
+}
+
diff --git a/camera/camera-core/api/res-1.0.0-beta10.txt b/camera/camera-core/api/res-1.0.0-beta10.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-core/api/res-1.0.0-beta10.txt
diff --git a/camera/camera-core/api/restricted_1.0.0-beta10.txt b/camera/camera-core/api/restricted_1.0.0-beta10.txt
new file mode 100644
index 0000000..0a36e63
--- /dev/null
+++ b/camera/camera-core/api/restricted_1.0.0-beta10.txt
@@ -0,0 +1,306 @@
+// Signature format: 3.0
+package androidx.camera.core {
+
+  public class AspectRatio {
+    field public static final int RATIO_16_9 = 1; // 0x1
+    field public static final int RATIO_4_3 = 0; // 0x0
+  }
+
+  public interface Camera {
+    method public androidx.camera.core.CameraControl getCameraControl();
+    method public androidx.camera.core.CameraInfo getCameraInfo();
+  }
+
+  public interface CameraControl {
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> cancelFocusAndMetering();
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> enableTorch(boolean);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setLinearZoom(@FloatRange(from=0.0f, to=1.0f) float);
+    method public com.google.common.util.concurrent.ListenableFuture<java.lang.Void!> setZoomRatio(float);
+    method public com.google.common.util.concurrent.ListenableFuture<androidx.camera.core.FocusMeteringResult!> startFocusAndMetering(androidx.camera.core.FocusMeteringAction);
+  }
+
+  public static final class CameraControl.OperationCanceledException extends java.lang.Exception {
+  }
+
+  public interface CameraInfo {
+    method public int getSensorRotationDegrees();
+    method public int getSensorRotationDegrees(int);
+    method public androidx.lifecycle.LiveData<java.lang.Integer!> getTorchState();
+    method public androidx.lifecycle.LiveData<androidx.camera.core.ZoomState!> getZoomState();
+    method public boolean hasFlashUnit();
+  }
+
+  public final class CameraInfoUnavailableException extends java.lang.Exception {
+  }
+
+  public final class CameraSelector {
+    field public static final androidx.camera.core.CameraSelector DEFAULT_BACK_CAMERA;
+    field public static final androidx.camera.core.CameraSelector DEFAULT_FRONT_CAMERA;
+    field public static final int LENS_FACING_BACK = 1; // 0x1
+    field public static final int LENS_FACING_FRONT = 0; // 0x0
+  }
+
+  public static final class CameraSelector.Builder {
+    ctor public CameraSelector.Builder();
+    method public androidx.camera.core.CameraSelector build();
+    method public androidx.camera.core.CameraSelector.Builder requireLensFacing(int);
+  }
+
+  public class CameraUnavailableException extends java.lang.Exception {
+    ctor public CameraUnavailableException(int);
+    ctor public CameraUnavailableException(int, String?);
+    ctor public CameraUnavailableException(int, String?, Throwable?);
+    ctor public CameraUnavailableException(int, Throwable?);
+    method public int getReason();
+    field public static final int CAMERA_DISABLED = 1; // 0x1
+    field public static final int CAMERA_DISCONNECTED = 2; // 0x2
+    field public static final int CAMERA_ERROR = 3; // 0x3
+    field public static final int CAMERA_IN_USE = 4; // 0x4
+    field public static final int CAMERA_MAX_IN_USE = 5; // 0x5
+    field public static final int CAMERA_UNAVAILABLE_DO_NOT_DISTURB = 6; // 0x6
+    field public static final int CAMERA_UNKNOWN_ERROR = 0; // 0x0
+  }
+
+  public final class CameraXConfig {
+  }
+
+  public static final class CameraXConfig.Builder {
+    method public androidx.camera.core.CameraXConfig build();
+    method public static androidx.camera.core.CameraXConfig.Builder fromConfig(androidx.camera.core.CameraXConfig);
+    method public androidx.camera.core.CameraXConfig.Builder setCameraExecutor(java.util.concurrent.Executor);
+  }
+
+  public static interface CameraXConfig.Provider {
+    method public androidx.camera.core.CameraXConfig getCameraXConfig();
+  }
+
+  public final class DisplayOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+    ctor public DisplayOrientedMeteringPointFactory(android.view.Display, androidx.camera.core.CameraInfo, float, float);
+  }
+
+  public interface ExtendableBuilder<T> {
+    method public T build();
+  }
+
+  public final class FocusMeteringAction {
+    method public long getAutoCancelDurationInMillis();
+    method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAe();
+    method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAf();
+    method public java.util.List<androidx.camera.core.MeteringPoint!> getMeteringPointsAwb();
+    method public boolean isAutoCancelEnabled();
+    field public static final int FLAG_AE = 2; // 0x2
+    field public static final int FLAG_AF = 1; // 0x1
+    field public static final int FLAG_AWB = 4; // 0x4
+  }
+
+  public static class FocusMeteringAction.Builder {
+    ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint);
+    ctor public FocusMeteringAction.Builder(androidx.camera.core.MeteringPoint, int);
+    method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint);
+    method public androidx.camera.core.FocusMeteringAction.Builder addPoint(androidx.camera.core.MeteringPoint, int);
+    method public androidx.camera.core.FocusMeteringAction build();
+    method public androidx.camera.core.FocusMeteringAction.Builder disableAutoCancel();
+    method public androidx.camera.core.FocusMeteringAction.Builder setAutoCancelDuration(@IntRange(from=1) long, java.util.concurrent.TimeUnit);
+  }
+
+  public final class FocusMeteringResult {
+    method public boolean isFocusSuccessful();
+  }
+
+  public final class ImageAnalysis extends androidx.camera.core.UseCase {
+    method public void clearAnalyzer();
+    method public int getBackpressureStrategy();
+    method public int getImageQueueDepth();
+    method public int getTargetRotation();
+    method public void setAnalyzer(java.util.concurrent.Executor, androidx.camera.core.ImageAnalysis.Analyzer);
+    method public void setTargetRotation(int);
+    field public static final int STRATEGY_BLOCK_PRODUCER = 1; // 0x1
+    field public static final int STRATEGY_KEEP_ONLY_LATEST = 0; // 0x0
+  }
+
+  public static interface ImageAnalysis.Analyzer {
+    method public void analyze(androidx.camera.core.ImageProxy);
+  }
+
+  public static final class ImageAnalysis.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageAnalysis> {
+    ctor public ImageAnalysis.Builder();
+    method public androidx.camera.core.ImageAnalysis build();
+    method public androidx.camera.core.ImageAnalysis.Builder setBackgroundExecutor(java.util.concurrent.Executor);
+    method public androidx.camera.core.ImageAnalysis.Builder setBackpressureStrategy(int);
+    method public androidx.camera.core.ImageAnalysis.Builder setImageQueueDepth(int);
+    method public androidx.camera.core.ImageAnalysis.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.ImageAnalysis.Builder setTargetName(String);
+    method public androidx.camera.core.ImageAnalysis.Builder setTargetResolution(android.util.Size);
+    method public androidx.camera.core.ImageAnalysis.Builder setTargetRotation(int);
+  }
+
+  public final class ImageCapture extends androidx.camera.core.UseCase {
+    method public int getCaptureMode();
+    method public int getFlashMode();
+    method public int getTargetRotation();
+    method public void setCropAspectRatio(android.util.Rational);
+    method public void setFlashMode(int);
+    method public void setTargetRotation(int);
+    method public void takePicture(java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageCapturedCallback);
+    method public void takePicture(androidx.camera.core.ImageCapture.OutputFileOptions, java.util.concurrent.Executor, androidx.camera.core.ImageCapture.OnImageSavedCallback);
+    field public static final int CAPTURE_MODE_MAXIMIZE_QUALITY = 0; // 0x0
+    field public static final int CAPTURE_MODE_MINIMIZE_LATENCY = 1; // 0x1
+    field public static final int ERROR_CAMERA_CLOSED = 3; // 0x3
+    field public static final int ERROR_CAPTURE_FAILED = 2; // 0x2
+    field public static final int ERROR_FILE_IO = 1; // 0x1
+    field public static final int ERROR_INVALID_CAMERA = 4; // 0x4
+    field public static final int ERROR_UNKNOWN = 0; // 0x0
+    field public static final int FLASH_MODE_AUTO = 0; // 0x0
+    field public static final int FLASH_MODE_OFF = 2; // 0x2
+    field public static final int FLASH_MODE_ON = 1; // 0x1
+  }
+
+  public static final class ImageCapture.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.ImageCapture> {
+    ctor public ImageCapture.Builder();
+    method public androidx.camera.core.ImageCapture build();
+    method public androidx.camera.core.ImageCapture.Builder setCaptureMode(int);
+    method public androidx.camera.core.ImageCapture.Builder setFlashMode(int);
+    method public androidx.camera.core.ImageCapture.Builder setIoExecutor(java.util.concurrent.Executor);
+    method public androidx.camera.core.ImageCapture.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.ImageCapture.Builder setTargetName(String);
+    method public androidx.camera.core.ImageCapture.Builder setTargetResolution(android.util.Size);
+    method public androidx.camera.core.ImageCapture.Builder setTargetRotation(int);
+  }
+
+  public static final class ImageCapture.Metadata {
+    ctor public ImageCapture.Metadata();
+    method public android.location.Location? getLocation();
+    method public boolean isReversedHorizontal();
+    method public boolean isReversedVertical();
+    method public void setLocation(android.location.Location?);
+    method public void setReversedHorizontal(boolean);
+    method public void setReversedVertical(boolean);
+  }
+
+  public abstract static class ImageCapture.OnImageCapturedCallback {
+    ctor public ImageCapture.OnImageCapturedCallback();
+    method public void onCaptureSuccess(androidx.camera.core.ImageProxy);
+    method public void onError(androidx.camera.core.ImageCaptureException);
+  }
+
+  public static interface ImageCapture.OnImageSavedCallback {
+    method public void onError(androidx.camera.core.ImageCaptureException);
+    method public void onImageSaved(androidx.camera.core.ImageCapture.OutputFileResults);
+  }
+
+  public static final class ImageCapture.OutputFileOptions {
+  }
+
+  public static final class ImageCapture.OutputFileOptions.Builder {
+    ctor public ImageCapture.OutputFileOptions.Builder(java.io.File);
+    ctor public ImageCapture.OutputFileOptions.Builder(android.content.ContentResolver, android.net.Uri, android.content.ContentValues);
+    ctor public ImageCapture.OutputFileOptions.Builder(java.io.OutputStream);
+    method public androidx.camera.core.ImageCapture.OutputFileOptions build();
+    method public androidx.camera.core.ImageCapture.OutputFileOptions.Builder setMetadata(androidx.camera.core.ImageCapture.Metadata);
+  }
+
+  public static class ImageCapture.OutputFileResults {
+    method public android.net.Uri? getSavedUri();
+  }
+
+  public class ImageCaptureException extends java.lang.Exception {
+    ctor public ImageCaptureException(int, String, Throwable?);
+    method public int getImageCaptureError();
+  }
+
+  public interface ImageInfo {
+    method public int getRotationDegrees();
+    method public long getTimestamp();
+  }
+
+  public interface ImageProxy extends java.lang.AutoCloseable {
+    method public void close();
+    method public android.graphics.Rect getCropRect();
+    method public int getFormat();
+    method public int getHeight();
+    method public androidx.camera.core.ImageInfo getImageInfo();
+    method public androidx.camera.core.ImageProxy.PlaneProxy![] getPlanes();
+    method public int getWidth();
+    method public void setCropRect(android.graphics.Rect?);
+  }
+
+  public static interface ImageProxy.PlaneProxy {
+    method public java.nio.ByteBuffer getBuffer();
+    method public int getPixelStride();
+    method public int getRowStride();
+  }
+
+  public class InitializationException extends java.lang.Exception {
+    ctor public InitializationException(String?);
+    ctor public InitializationException(String?, Throwable?);
+    ctor public InitializationException(Throwable?);
+  }
+
+  public class MeteringPoint {
+    method public float getSize();
+  }
+
+  public abstract class MeteringPointFactory {
+    method public final androidx.camera.core.MeteringPoint createPoint(float, float);
+    method public final androidx.camera.core.MeteringPoint createPoint(float, float, float);
+    method public static float getDefaultPointSize();
+  }
+
+  public final class Preview extends androidx.camera.core.UseCase {
+    method public int getTargetRotation();
+    method @UiThread public void setSurfaceProvider(java.util.concurrent.Executor, androidx.camera.core.Preview.SurfaceProvider?);
+    method @UiThread public void setSurfaceProvider(androidx.camera.core.Preview.SurfaceProvider?);
+  }
+
+  public static final class Preview.Builder implements androidx.camera.core.ExtendableBuilder<androidx.camera.core.Preview> {
+    ctor public Preview.Builder();
+    method public androidx.camera.core.Preview build();
+    method public androidx.camera.core.Preview.Builder setTargetAspectRatio(int);
+    method public androidx.camera.core.Preview.Builder setTargetName(String);
+    method public androidx.camera.core.Preview.Builder setTargetResolution(android.util.Size);
+    method public androidx.camera.core.Preview.Builder setTargetRotation(int);
+  }
+
+  public static interface Preview.SurfaceProvider {
+    method public void onSurfaceRequested(androidx.camera.core.SurfaceRequest);
+  }
+
+  public class SurfaceOrientedMeteringPointFactory extends androidx.camera.core.MeteringPointFactory {
+    ctor public SurfaceOrientedMeteringPointFactory(float, float);
+    ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
+  }
+
+  public final class SurfaceRequest {
+    method public void addRequestCancellationListener(java.util.concurrent.Executor, Runnable);
+    method public android.util.Size getResolution();
+    method public void provideSurface(android.view.Surface, java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceRequest.Result!>);
+    method public boolean willNotProvideSurface();
+  }
+
+  @com.google.auto.value.AutoValue public abstract static class SurfaceRequest.Result {
+    method public abstract int getResultCode();
+    method public abstract android.view.Surface getSurface();
+    field public static final int RESULT_INVALID_SURFACE = 2; // 0x2
+    field public static final int RESULT_REQUEST_CANCELLED = 1; // 0x1
+    field public static final int RESULT_SURFACE_ALREADY_PROVIDED = 3; // 0x3
+    field public static final int RESULT_SURFACE_USED_SUCCESSFULLY = 0; // 0x0
+    field public static final int RESULT_WILL_NOT_PROVIDE_SURFACE = 4; // 0x4
+  }
+
+  public class TorchState {
+    field public static final int OFF = 0; // 0x0
+    field public static final int ON = 1; // 0x1
+  }
+
+  public abstract class UseCase {
+  }
+
+  public interface ZoomState {
+    method public float getLinearZoom();
+    method public float getMaxZoomRatio();
+    method public float getMinZoomRatio();
+    method public float getZoomRatio();
+  }
+
+}
+
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java
index a4bdecf..30aa230 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java
@@ -33,7 +33,6 @@
 import androidx.camera.testing.fakes.FakeCameraFactory;
 import androidx.camera.testing.fakes.FakeCameraInfoInternal;
 import androidx.camera.testing.fakes.FakeLifecycleOwner;
-import androidx.camera.testing.fakes.FakeUseCase;
 import androidx.camera.testing.fakes.FakeUseCaseConfig;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -220,15 +219,6 @@
     }
 
     @Test
-    public void requestingDefaultConfiguration_returnsDefaultConfiguration() {
-        initCameraX();
-        // Requesting a default configuration will throw if CameraX is not initialized.
-        FakeUseCaseConfig config = CameraX.getDefaultUseCaseConfig(FakeUseCaseConfig.class);
-        assertThat(config).isNotNull();
-        assertThat(config.getTargetClass(null)).isEqualTo(FakeUseCase.class);
-    }
-
-    @Test
     public void canGetCameraXContext() {
         initCameraX();
         Context context = CameraX.getContext();
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java
index 8b90e05..4dccf39 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java
@@ -19,7 +19,11 @@
 import android.util.Size;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.camera.core.impl.Config;
 import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
 import androidx.camera.testing.fakes.FakeUseCase;
 
 /**
@@ -28,7 +32,6 @@
  * <p>This is used to complement the {@link FakeUseCase} for testing instances where a use case of
  * different type is created.
  */
-
 public class FakeOtherUseCase extends UseCase {
     private volatile boolean mIsDetached = false;
 
@@ -48,10 +51,34 @@
         mIsDetached = true;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @Nullable
+    @Override
+    public UseCaseConfig<?> getDefaultConfig(@NonNull UseCaseConfigFactory factory) {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @NonNull
+    @Override
+    public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config) {
+        throw new RuntimeException("Not implemented");
+    }
+
     @NonNull
     @Override
     public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder() {
-        return null;
+        throw new RuntimeException("Not implemented");
     }
 
     @Override
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageAnalysisDeviceTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageAnalysisDeviceTest.java
index 9d236f6..1fd8418 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageAnalysisDeviceTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageAnalysisDeviceTest.java
@@ -22,44 +22,29 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
-import android.content.Context;
-
 import androidx.camera.core.impl.CameraInternal;
+import androidx.camera.core.impl.UseCaseConfigFactory;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
-import androidx.camera.testing.fakes.FakeAppConfig;
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory;
 import androidx.test.annotation.UiThreadTest;
-import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ImageAnalysisDeviceTest {
 
     private final CameraInternal mMockCameraInternal = mock(CameraInternal.class);
     private final ImageAnalysis.Analyzer mMockAnalyzer = mock(ImageAnalysis.Analyzer.class);
+    private UseCaseConfigFactory mUseCaseConfigFactory;
 
     @Before
-    public void setup() throws ExecutionException, InterruptedException {
-        CameraXConfig cameraXConfig = CameraXConfig.Builder.fromConfig(
-                FakeAppConfig.create()).build();
-
-        Context context = ApplicationProvider.getApplicationContext();
-        CameraX.initialize(context, cameraXConfig).get();
-    }
-
-    @After
-    public void tearDown() throws ExecutionException, InterruptedException, TimeoutException {
-        CameraX.shutdown().get(10000, TimeUnit.MILLISECONDS);
+    public void setup() {
+        mUseCaseConfigFactory = new FakeUseCaseConfigFactory();
     }
 
     @Test
@@ -68,7 +53,7 @@
         ImageAnalysis useCase = new ImageAnalysis.Builder().setBackpressureStrategy(
                 STRATEGY_KEEP_ONLY_LATEST).build();
 
-        useCase.onAttach(mMockCameraInternal);
+        useCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
 
         useCase.setAnalyzer(CameraXExecutors.mainThreadExecutor(), mMockAnalyzer);
 
@@ -81,7 +66,7 @@
         ImageAnalysis useCase = new ImageAnalysis.Builder().setBackpressureStrategy(
                 STRATEGY_KEEP_ONLY_LATEST).build();
 
-        useCase.onAttach(mMockCameraInternal);
+        useCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
         useCase.setAnalyzer(CameraXExecutors.mainThreadExecutor(), mMockAnalyzer);
         useCase.clearAnalyzer();
 
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageCaptureTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageCaptureTest.java
index e9d4858..b45ac106 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageCaptureTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageCaptureTest.java
@@ -24,35 +24,46 @@
 import static org.mockito.Mockito.verify;
 
 import android.app.Instrumentation;
-import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.ImageFormat;
+import android.graphics.Rect;
 import android.util.Size;
 
+import androidx.annotation.NonNull;
 import androidx.camera.core.impl.CaptureConfig;
 import androidx.camera.core.impl.ImageCaptureConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
 import androidx.camera.core.internal.CameraUseCaseAdapter;
-import androidx.camera.testing.fakes.FakeAppConfig;
 import androidx.camera.testing.fakes.FakeCamera;
 import androidx.camera.testing.fakes.FakeCameraControl;
 import androidx.camera.testing.fakes.FakeCameraDeviceSurfaceManager;
-import androidx.test.core.app.ApplicationProvider;
+import androidx.camera.testing.fakes.FakeImageInfo;
+import androidx.camera.testing.fakes.FakeImageProxy;
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory;
+import androidx.exifinterface.media.ExifInterface;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Instrument tests for {@link ImageCapture}.
@@ -64,13 +75,7 @@
     private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
 
     @Before
-    public void setup() throws ExecutionException, InterruptedException {
-        CameraXConfig cameraXConfig = CameraXConfig.Builder.fromConfig(
-                FakeAppConfig.create()).build();
-
-        Context context = ApplicationProvider.getApplicationContext();
-        CameraX.initialize(context, cameraXConfig).get();
-
+    public void setup() {
         FakeCamera fakeCamera = new FakeCamera("fakeCameraId");
 
         FakeCameraDeviceSurfaceManager fakeCameraDeviceSurfaceManager =
@@ -79,14 +84,48 @@
                 ImageCaptureConfig.class,
                 new Size(640, 480));
 
+        UseCaseConfigFactory useCaseConfigFactory = new FakeUseCaseConfigFactory();
+
         mCameraUseCaseAdapter = new CameraUseCaseAdapter(fakeCamera,
                 new LinkedHashSet<>(Collections.singleton(fakeCamera)),
-                fakeCameraDeviceSurfaceManager);
+                fakeCameraDeviceSurfaceManager,
+                useCaseConfigFactory);
     }
 
-    @After
-    public void tearDown() throws ExecutionException, InterruptedException, TimeoutException {
-        CameraX.shutdown().get(10000, TimeUnit.MILLISECONDS);
+    @Test
+    public void getDispatchCropRect_dispatchBufferRotated90() {
+        assertGetDispatchCropRect(90, new Size(4, 6), new Rect(3, 0, 4, 1));
+    }
+
+    @Test
+    public void getDispatchCropRect_dispatchBufferRotated180() {
+        assertGetDispatchCropRect(180, new Size(6, 4), new Rect(5, 3, 6, 4));
+    }
+
+    @Test
+    public void getDispatchCropRect_dispatchBufferRotated270() {
+        assertGetDispatchCropRect(270, new Size(4, 6), new Rect(0, 5, 1, 6));
+    }
+
+    @Test
+    public void getDispatchCropRect_dispatchBufferRotated0() {
+        assertGetDispatchCropRect(0, new Size(6, 4), new Rect(0, 0, 1, 1));
+    }
+
+    private void assertGetDispatchCropRect(int outputDegrees, Size dispatchResolution,
+            Rect dispatchRect) {
+        // Arrange:
+        // Surface crop rect stays the same regardless of HAL rotations.
+        Rect surfaceCropRect = new Rect(0, 0, 1, 1);
+        // Exif degrees being 0 means HAL consumed the target rotation.
+        int exifRotationDegrees = 0;
+
+        // Act.
+        Rect dispatchCropRect = ImageCapture.ImageCaptureRequest.getDispatchCropRect(
+                surfaceCropRect, outputDegrees, dispatchResolution, exifRotationDegrees);
+
+        // Assert.
+        assertThat(dispatchCropRect).isEqualTo(dispatchRect);
     }
 
     @Test
@@ -183,6 +222,101 @@
     }
 
     @Test
+    public void dispatchImage_cropRectIsUpdatedBasedOnExifOrientation()
+            throws InterruptedException, IOException {
+        // Arrange: assume the sensor buffer is 6x4, the crop rect is (0, 0) - (2, 1) and the
+        // rotation degrees is 90°.
+        Semaphore semaphore = new Semaphore(0);
+        AtomicReference<ImageProxy> imageProxyReference = new AtomicReference<>();
+        ImageCapture.ImageCaptureRequest request = new ImageCapture.ImageCaptureRequest(
+                /*rotationDegrees*/90,
+                /*jpegQuality*/100,
+                /*targetRatio*/ null,
+                /*viewPortCropRect*/ new Rect(0, 0, 2, 1),
+                CameraXExecutors.mainThreadExecutor(),
+                new ImageCapture.OnImageCapturedCallback() {
+                    @Override
+                    public void onCaptureSuccess(@NonNull ImageProxy image) {
+                        super.onCaptureSuccess(image);
+                        imageProxyReference.set(image);
+                        semaphore.release();
+                    }
+                });
+
+        // Act: dispatch a image that has been rotated in the HAL. After 90° rotation the buffer
+        // becomes 4x6 and orientation is normal.
+        request.dispatchImage(createJpegImageProxy(4, 6, ExifInterface.ORIENTATION_NORMAL));
+        semaphore.tryAcquire(3, TimeUnit.SECONDS);
+
+        // Assert: that the rotation is 0 and the crop rect has been updated.
+        assertThat(imageProxyReference.get().getImageInfo().getRotationDegrees()).isEqualTo(0);
+        assertThat(imageProxyReference.get().getCropRect()).isEqualTo(new Rect(3, 0, 4, 2));
+    }
+
+    /**
+     * Creates a {@link ImageProxy} with given width, height and exif orientation.
+     *
+     * @param exifOrientation orientation integers defined in {@link ExifInterface}.
+     */
+    private ImageProxy createJpegImageProxy(int width, int height,
+            int exifOrientation) throws IOException {
+        // Create a temporary jpeg file with given width/height.
+        File jpegFile = File.createTempFile("fake_jpeg_with_exif", "jpeg",
+                mInstrumentation.getContext().getCacheDir());
+        jpegFile.deleteOnExit();
+        try (FileOutputStream out = new FileOutputStream(jpegFile)) {
+            Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).compress(
+                    Bitmap.CompressFormat.JPEG, 100, out);
+        }
+
+        // Save the exif orientation to the jpeg file.
+        ExifInterface exifInterface = new ExifInterface(jpegFile.getAbsolutePath());
+        exifInterface.setAttribute(androidx.exifinterface.media.ExifInterface.TAG_ORIENTATION,
+                String.valueOf(exifOrientation));
+        exifInterface.saveAttributes();
+
+        // Load the jpeg file into a ByteBuffer.
+        ByteBuffer byteData;
+        try (FileInputStream inputStream = new FileInputStream(jpegFile)) {
+            byte[] buffer = new byte[1024];
+            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+            int read;
+            while (true) {
+                read = inputStream.read(buffer);
+                if (read == -1) {
+                    break;
+                }
+                outStream.write(buffer, 0, read);
+            }
+            byteData = ByteBuffer.wrap(outStream.toByteArray());
+        }
+
+        // Create a FakeImageProxy from the ByteBuffer.
+        FakeImageProxy fakeImageProxy = new FakeImageProxy(new FakeImageInfo());
+        fakeImageProxy.setFormat(ImageFormat.JPEG);
+        ImageProxy.PlaneProxy planeProxy = new ImageProxy.PlaneProxy() {
+
+            @Override
+            public int getRowStride() {
+                return 0;
+            }
+
+            @Override
+            public int getPixelStride() {
+                return 0;
+            }
+
+            @NonNull
+            @Override
+            public ByteBuffer getBuffer() {
+                return byteData;
+            }
+        };
+        fakeImageProxy.setPlanes(new ImageProxy.PlaneProxy[]{planeProxy});
+        return fakeImageProxy;
+    }
+
+    @Test
     public void setFlashModeDuringPictureTaken() throws InterruptedException {
         // Arrange.
         ImageCapture imageCapture = createImageCapture();
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/ProcessingImageReaderDeviceTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/ProcessingImageReaderDeviceTest.kt
index 81b3932..e915887d 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/ProcessingImageReaderDeviceTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/ProcessingImageReaderDeviceTest.kt
@@ -127,8 +127,12 @@
         imageWriter.queueInputImage(image)
         val fakeCameraCaptureResult = FakeCameraCaptureResult()
         fakeCameraCaptureResult.timestamp = timestamp
-        val tagBundle = TagBundle.create(Pair(mCaptureBundle.hashCode().toString(),
-            captureId))
+        val tagBundle = TagBundle.create(
+            Pair(
+                mCaptureBundle.hashCode().toString(),
+                captureId
+            )
+        )
         fakeCameraCaptureResult.setTag(tagBundle)
         callback.onCaptureCompleted(fakeCameraCaptureResult)
     }
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java
index 0b3c829..fc61519 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.graphics.ImageFormat;
 import android.graphics.Rect;
 import android.util.Size;
 
@@ -34,8 +35,10 @@
 import androidx.camera.core.impl.Config;
 import androidx.camera.core.impl.SessionConfig;
 import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
 import androidx.camera.testing.fakes.FakeUseCase;
 import androidx.camera.testing.fakes.FakeUseCaseConfig;
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
@@ -47,10 +50,12 @@
 @RunWith(AndroidJUnit4.class)
 public class UseCaseTest {
     private CameraInternal mMockCameraInternal;
+    private UseCaseConfigFactory mUseCaseConfigFactory;
 
     @Before
     public void setup() {
         mMockCameraInternal = mock(CameraInternal.class);
+        mUseCaseConfigFactory = new FakeUseCaseConfigFactory();
     }
 
     @Test
@@ -72,7 +77,7 @@
                 "UseCase").getUseCaseConfig();
         TestUseCase testUseCase = new TestUseCase(config);
 
-        testUseCase.onAttach(mMockCameraInternal);
+        testUseCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
         testUseCase.onDetach(mMockCameraInternal);
 
         testUseCase.activate();
@@ -85,7 +90,7 @@
         FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
                 "UseCase").getUseCaseConfig();
         TestUseCase testUseCase = new TestUseCase(config);
-        testUseCase.onAttach(mMockCameraInternal);
+        testUseCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
 
         testUseCase.activate();
         verify(mMockCameraInternal, times(1)).onUseCaseActive(testUseCase);
@@ -96,7 +101,7 @@
         FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
                 "UseCase").getUseCaseConfig();
         TestUseCase testUseCase = new TestUseCase(config);
-        testUseCase.onAttach(mMockCameraInternal);
+        testUseCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
 
         testUseCase.deactivate();
         verify(mMockCameraInternal, times(1)).onUseCaseInactive(testUseCase);
@@ -107,7 +112,7 @@
         FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
                 "UseCase").getUseCaseConfig();
         TestUseCase testUseCase = new TestUseCase(config);
-        testUseCase.onAttach(mMockCameraInternal);
+        testUseCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
 
         testUseCase.update();
         verify(mMockCameraInternal, times(1)).onUseCaseUpdated(testUseCase);
@@ -118,40 +123,12 @@
         FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
                 "UseCase").getUseCaseConfig();
         TestUseCase testUseCase = new TestUseCase(config);
-        testUseCase.onAttach(mMockCameraInternal);
+        testUseCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
 
         testUseCase.notifyReset();
         verify(mMockCameraInternal, times(1)).onUseCaseReset(testUseCase);
     }
 
-    @Test(expected = IllegalStateException.class)
-    public void updateUseCaseConfig_beforeUseCaseIsAttached_throwException() {
-        FakeUseCaseConfig.Builder configBuilder = new FakeUseCaseConfig.Builder();
-        TestUseCase testUseCase = new TestUseCase(configBuilder.getUseCaseConfig());
-        testUseCase.updateUseCaseConfig(configBuilder.getUseCaseConfig());
-    }
-
-    @Test
-    public void updateUseCaseConfig_afterUseCaseIsAttached() {
-        String originalName = "UseCase";
-        FakeUseCaseConfig.Builder configBuilder =
-                new FakeUseCaseConfig.Builder().setTargetName(originalName);
-
-        TestUseCase testUseCase = new TestUseCase(configBuilder.getUseCaseConfig());
-        String originalRetrievedName = testUseCase.getUseCaseConfig().getTargetName();
-
-        // NOTE: Updating the use case name is probably a very bad idea in most cases. However,
-        // we'll do it here for the sake of this test.
-        String newName = "UseCase-New";
-        configBuilder.setTargetName(newName);
-        testUseCase.onAttach(mMockCameraInternal);
-        testUseCase.updateUseCaseConfig(configBuilder.getUseCaseConfig());
-        String newRetrievedName = testUseCase.getUseCaseConfig().getTargetName();
-
-        assertThat(originalRetrievedName).isEqualTo(originalName);
-        assertThat(newRetrievedName).isEqualTo(newName);
-    }
-
     @Test
     public void useCaseConfig_keepOptionPriority() {
         FakeUseCaseConfig.Builder builder =  new FakeUseCaseConfig.Builder();
@@ -159,7 +136,7 @@
         builder.getMutableConfig().insertOption(opt, ALWAYS_OVERRIDE, 1);
 
         FakeUseCase fakeUseCase = builder.build();
-        UseCaseConfig<?> useCaseConfig = fakeUseCase.getUseCaseConfig();
+        UseCaseConfig<?> useCaseConfig = fakeUseCase.getCurrentConfig();
 
         assertThat(useCaseConfig.getOptionPriority(opt)).isEqualTo(ALWAYS_OVERRIDE);
     }
@@ -173,7 +150,7 @@
         testUseCase.updateSuggestedResolution(new Size(640, 480));
         assertThat(testUseCase.getAttachedSurfaceResolution()).isNotNull();
 
-        testUseCase.onAttach(mMockCameraInternal);
+        testUseCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
         testUseCase.onDetach(mMockCameraInternal);
 
         assertThat(testUseCase.getAttachedSurfaceResolution()).isNull();
@@ -188,12 +165,38 @@
         testUseCase.setViewPortCropRect(new Rect());
         assertThat(testUseCase.getViewPortCropRect()).isNotNull();
 
-        testUseCase.onAttach(mMockCameraInternal);
+        testUseCase.onAttach(mMockCameraInternal, mUseCaseConfigFactory);
         testUseCase.onDetach(mMockCameraInternal);
 
         assertThat(testUseCase.getViewPortCropRect()).isNull();
     }
 
+    @Test
+    public void mergeConfigs() {
+        int cameraDefaultPriority = 4;
+        FakeUseCaseConfig defaultConfig = new FakeUseCaseConfig.Builder()
+                .setTargetName("UseCase-camera")
+                .setBufferFormat(ImageFormat.RAW10)
+                .setSurfaceOccupancyPriority(cameraDefaultPriority).getUseCaseConfig();
+
+        int useCaseImageFormat = ImageFormat.YUV_420_888;
+        FakeUseCaseConfig useCaseConfig = new FakeUseCaseConfig.Builder()
+                .setTargetName("UseCase-useCase")
+                .setBufferFormat(useCaseImageFormat).getUseCaseConfig();
+
+        String extendedTargetName = "UseCase-extended";
+        FakeUseCaseConfig extendedConfig = new FakeUseCaseConfig.Builder()
+                .setTargetName(extendedTargetName).getUseCaseConfig();
+
+        TestUseCase testUseCase = new TestUseCase(useCaseConfig);
+
+        UseCaseConfig<?> mergedConfig = testUseCase.mergeConfigs(extendedConfig, defaultConfig);
+
+        assertThat(mergedConfig.getSurfaceOccupancyPriority()).isEqualTo(cameraDefaultPriority);
+        assertThat(mergedConfig.getInputFormat()).isEqualTo(useCaseImageFormat);
+        assertThat(mergedConfig.getTargetName()).isEqualTo(extendedTargetName);
+    }
+
     static class TestUseCase extends FakeUseCase {
         TestUseCase(FakeUseCaseConfig config) {
             super(config);
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.java
index 6e955dc..3476d6f 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/CameraUseCaseAdapterTest.java
@@ -28,10 +28,12 @@
 import androidx.camera.core.UseCase;
 import androidx.camera.core.ViewPort;
 import androidx.camera.core.impl.CameraInternal;
+import androidx.camera.core.impl.UseCaseConfigFactory;
 import androidx.camera.testing.fakes.FakeCamera;
 import androidx.camera.testing.fakes.FakeCameraDeviceSurfaceManager;
 import androidx.camera.testing.fakes.FakeUseCase;
 import androidx.camera.testing.fakes.FakeUseCaseConfig;
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
 import androidx.test.filters.SmallTest;
@@ -49,12 +51,14 @@
 public class CameraUseCaseAdapterTest {
     FakeCameraDeviceSurfaceManager mFakeCameraDeviceSurfaceManager;
     FakeCamera mFakeCamera;
+    UseCaseConfigFactory mUseCaseConfigFactory;
     LinkedHashSet<CameraInternal> mFakeCameraSet = new LinkedHashSet<>();
 
     @Before
     public void setUp() {
         mFakeCameraDeviceSurfaceManager = new FakeCameraDeviceSurfaceManager();
         mFakeCamera = new FakeCamera();
+        mUseCaseConfigFactory = new FakeUseCaseConfigFactory();
         mFakeCameraSet.add(mFakeCamera);
     }
 
@@ -62,7 +66,8 @@
     public void attachUseCases() throws CameraUseCaseAdapter.CameraException {
         CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
                 mFakeCameraSet,
-                mFakeCameraDeviceSurfaceManager);
+                mFakeCameraDeviceSurfaceManager,
+                mUseCaseConfigFactory);
         FakeUseCase fakeUseCase = new FakeUseCase();
         cameraUseCaseAdapter.addUseCases(Collections.singleton(fakeUseCase));
 
@@ -74,7 +79,8 @@
     public void detachUseCases() throws CameraUseCaseAdapter.CameraException {
         CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
                 mFakeCameraSet,
-                mFakeCameraDeviceSurfaceManager);
+                mFakeCameraDeviceSurfaceManager,
+                mUseCaseConfigFactory);
         FakeUseCase fakeUseCase = new FakeUseCase();
         cameraUseCaseAdapter.addUseCases(Collections.singleton(fakeUseCase));
         cameraUseCaseAdapter.removeUseCases(Collections.singleton(fakeUseCase));
@@ -86,7 +92,8 @@
     public void closeCameraUseCaseAdapter() throws CameraUseCaseAdapter.CameraException {
         CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
                 mFakeCameraSet,
-                mFakeCameraDeviceSurfaceManager);
+                mFakeCameraDeviceSurfaceManager,
+                mUseCaseConfigFactory);
         FakeUseCase fakeUseCase = new FakeUseCase();
         cameraUseCaseAdapter.addUseCases(Collections.singleton(fakeUseCase));
         cameraUseCaseAdapter.detachUseCases();
@@ -99,7 +106,8 @@
     public void cameraIdEquals() {
         CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
                 mFakeCameraSet,
-                mFakeCameraDeviceSurfaceManager);
+                mFakeCameraDeviceSurfaceManager,
+                mUseCaseConfigFactory);
 
         CameraUseCaseAdapter.CameraId otherCameraId =
                 CameraUseCaseAdapter.generateCameraId(mFakeCameraSet);
@@ -111,11 +119,13 @@
     public void cameraEquivalent() {
         CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
                 mFakeCameraSet,
-                mFakeCameraDeviceSurfaceManager);
+                mFakeCameraDeviceSurfaceManager,
+                mUseCaseConfigFactory);
 
         CameraUseCaseAdapter otherCameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
                 mFakeCameraSet,
-                mFakeCameraDeviceSurfaceManager);
+                mFakeCameraDeviceSurfaceManager,
+                mUseCaseConfigFactory);
         assertThat(cameraUseCaseAdapter.isEquivalent(otherCameraUseCaseAdapter)).isTrue();
     }
 
@@ -124,12 +134,13 @@
     public void useCase_onAttach() throws CameraUseCaseAdapter.CameraException {
         CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
                 mFakeCameraSet,
-                mFakeCameraDeviceSurfaceManager);
+                mFakeCameraDeviceSurfaceManager,
+                mUseCaseConfigFactory);
 
         FakeUseCase fakeUseCase = spy(new FakeUseCase());
         cameraUseCaseAdapter.addUseCases(Collections.singleton(fakeUseCase));
 
-        verify(fakeUseCase).onAttach(mFakeCamera);
+        verify(fakeUseCase).onAttach(mFakeCamera, mUseCaseConfigFactory);
     }
 
     @Test
@@ -137,7 +148,8 @@
     public void useCase_onDetach() throws CameraUseCaseAdapter.CameraException {
         CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
                 mFakeCameraSet,
-                mFakeCameraDeviceSurfaceManager);
+                mFakeCameraDeviceSurfaceManager,
+                mUseCaseConfigFactory);
 
         FakeUseCase fakeUseCase = spy(new FakeUseCase());
         cameraUseCaseAdapter.addUseCases(Collections.singleton(fakeUseCase));
@@ -151,7 +163,8 @@
     public void eventCallbackOnBind() throws CameraUseCaseAdapter.CameraException {
         CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
                 mFakeCameraSet,
-                mFakeCameraDeviceSurfaceManager);
+                mFakeCameraDeviceSurfaceManager,
+                mUseCaseConfigFactory);
 
         UseCase.EventCallback callback = mock(UseCase.EventCallback.class);
         FakeUseCase fakeUseCase =
@@ -166,7 +179,8 @@
     public void eventCallbackOnUnbind() throws CameraUseCaseAdapter.CameraException {
         CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
                 mFakeCameraSet,
-                mFakeCameraDeviceSurfaceManager);
+                mFakeCameraDeviceSurfaceManager,
+                mUseCaseConfigFactory);
 
         UseCase.EventCallback callback = mock(UseCase.EventCallback.class);
         FakeUseCase fakeUseCase =
@@ -189,7 +203,8 @@
         // Arrange: set up adapter with aspect ratio 1.
         CameraUseCaseAdapter cameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
                 mFakeCameraSet,
-                mFakeCameraDeviceSurfaceManager);
+                mFakeCameraDeviceSurfaceManager,
+                mUseCaseConfigFactory);
         cameraUseCaseAdapter.setViewPort(
                 new ViewPort.Builder(aspectRatio1, Surface.ROTATION_0).build());
         FakeUseCase fakeUseCase = spy(new FakeUseCase());
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/UseCaseOccupancyTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/UseCaseOccupancyTest.java
deleted file mode 100644
index 1079d6e..0000000
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/internal/UseCaseOccupancyTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2020 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.camera.core.internal;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-
-import androidx.camera.core.CameraX;
-import androidx.camera.core.CameraXConfig;
-import androidx.camera.core.ImageCapture;
-import androidx.camera.core.VideoCapture;
-import androidx.camera.testing.fakes.FakeAppConfig;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-/** JUnit test cases for {@link UseCaseOccupancy} class. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class UseCaseOccupancyTest {
-
-    @Before
-    public void setUp() throws ExecutionException, InterruptedException {
-        Context context = ApplicationProvider.getApplicationContext();
-        CameraXConfig cameraXConfig = CameraXConfig.Builder.fromConfig(
-                FakeAppConfig.create()).build();
-        CameraX.initialize(context, cameraXConfig).get();
-    }
-
-    @After
-    public void tearDown() throws ExecutionException, InterruptedException, TimeoutException {
-        CameraX.shutdown().get(10000, TimeUnit.MILLISECONDS);
-    }
-
-    @Test
-    public void failedWhenBindTooManyImageCapture() {
-        ImageCapture useCase1 = createImageCapture();
-        ImageCapture useCase2 = createImageCapture();
-
-        assertThat(UseCaseOccupancy.checkUseCaseLimitNotExceeded(
-                Arrays.asList(useCase1, useCase2))).isFalse();
-    }
-
-    @Test
-    public void failedWhenBindTooManyVideoCapture() {
-        VideoCapture useCase1 = new VideoCapture.Builder().build();
-        VideoCapture useCase2 = new VideoCapture.Builder().build();
-
-        assertThat(UseCaseOccupancy.checkUseCaseLimitNotExceeded(
-                Arrays.asList(useCase1, useCase2))).isFalse();
-    }
-
-    @Test
-    public void passWhenNotBindTooManyImageVideoCapture() {
-        ImageCapture imageCapture = createImageCapture();
-        VideoCapture videoCapture = new VideoCapture.Builder().build();
-
-        assertThat(UseCaseOccupancy.checkUseCaseLimitNotExceeded(
-                Arrays.asList(imageCapture, videoCapture))).isTrue();
-    }
-
-    // TODO remove when UseCase does not require
-    private ImageCapture createImageCapture() {
-        return new ImageCapture.Builder()
-                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
-                .setFlashMode(ImageCapture.FLASH_MODE_OFF)
-                .setCaptureOptionUnpacker((config, builder) -> { })
-                .setSessionOptionUnpacker((config, builder) -> { })
-                .build();
-    }
-}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/CameraX.java b/camera/camera-core/src/main/java/androidx/camera/core/CameraX.java
index 8753394..75eedea 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/CameraX.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/CameraX.java
@@ -36,7 +36,6 @@
 import androidx.camera.core.impl.CameraInternal;
 import androidx.camera.core.impl.CameraRepository;
 import androidx.camera.core.impl.CameraThreadConfig;
-import androidx.camera.core.impl.UseCaseConfig;
 import androidx.camera.core.impl.UseCaseConfigFactory;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
 import androidx.camera.core.impl.utils.futures.FutureCallback;
@@ -141,40 +140,6 @@
     }
 
     /**
-     * Returns the {@link CameraDeviceSurfaceManager} which can be used to query for valid surface
-     * configurations.
-     *
-     * @hide
-     */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @NonNull
-    public static CameraDeviceSurfaceManager getSurfaceManager() {
-        CameraX cameraX = checkInitialized();
-
-        return cameraX.getCameraDeviceSurfaceManager();
-    }
-
-    /**
-     * Returns the default configuration for the given use case configuration type.
-     *
-     * <p>The options contained in this configuration serve as fallbacks if they are not included in
-     * the user-provided configuration used to create a use case.
-     *
-     * @param configType the configuration type
-     * @return the default configuration for the given configuration type
-     * @throws IllegalStateException if CameraX has not yet been initialized.
-     * @hide
-     */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    @Nullable
-    public static <C extends UseCaseConfig<?>> C getDefaultUseCaseConfig(
-            @NonNull Class<C> configType) {
-        CameraX cameraX = checkInitialized();
-
-        return cameraX.getDefaultConfigFactory().getConfig(configType);
-    }
-
-    /**
      * Initializes CameraX with the given context and application configuration.
      *
      * <p>The context enables CameraX to obtain access to necessary services, including the camera
@@ -530,7 +495,14 @@
         return mCameraRepository;
     }
 
-    private UseCaseConfigFactory getDefaultConfigFactory() {
+    /**
+     * Returns the {@link UseCaseConfigFactory} instance.
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @NonNull
+    public UseCaseConfigFactory getDefaultConfigFactory() {
         if (mDefaultConfigFactory == null) {
             throw new IllegalStateException("CameraX not initialized yet.");
         }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
index 5813f51..adb7ceb 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
@@ -49,6 +49,7 @@
 import androidx.annotation.RestrictTo.Scope;
 import androidx.camera.core.impl.CameraInternal;
 import androidx.camera.core.impl.CaptureConfig;
+import androidx.camera.core.impl.Config;
 import androidx.camera.core.impl.ConfigProvider;
 import androidx.camera.core.impl.DeferrableSurface;
 import androidx.camera.core.impl.ImageAnalysisConfig;
@@ -60,6 +61,7 @@
 import androidx.camera.core.impl.OptionsBundle;
 import androidx.camera.core.impl.SessionConfig;
 import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
 import androidx.camera.core.impl.utils.Threads;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
 import androidx.camera.core.internal.TargetConfig;
@@ -174,7 +176,7 @@
         super(config);
 
         // Get the combined configuration with defaults
-        ImageAnalysisConfig combinedConfig = (ImageAnalysisConfig) getUseCaseConfig();
+        ImageAnalysisConfig combinedConfig = (ImageAnalysisConfig) getCurrentConfig();
 
         if (combinedConfig.getBackpressureStrategy(DEFAULT_BACKPRESSURE_STRATEGY)
                 == STRATEGY_BLOCK_PRODUCER) {
@@ -390,7 +392,7 @@
      */
     @BackpressureStrategy
     public int getBackpressureStrategy() {
-        return ((ImageAnalysisConfig) getUseCaseConfig()).getBackpressureStrategy(
+        return ((ImageAnalysisConfig) getCurrentConfig()).getBackpressureStrategy(
                 DEFAULT_BACKPRESSURE_STRATEGY);
     }
 
@@ -409,7 +411,7 @@
      * @see ImageAnalysis.Builder#setBackpressureStrategy(int)
      */
     public int getImageQueueDepth() {
-        return ((ImageAnalysisConfig) getUseCaseConfig()).getImageQueueDepth(
+        return ((ImageAnalysisConfig) getCurrentConfig()).getImageQueueDepth(
                 DEFAULT_IMAGE_QUEUE_DEPTH);
     }
 
@@ -435,16 +437,11 @@
      *
      * @hide
      */
+    @RestrictTo(Scope.LIBRARY_GROUP)
     @Override
     @Nullable
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    public UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder() {
-        ImageAnalysisConfig defaults = CameraX.getDefaultUseCaseConfig(ImageAnalysisConfig.class);
-        if (defaults != null) {
-            return Builder.fromConfig(defaults);
-        }
-
-        return null;
+    public UseCaseConfig<?> getDefaultConfig(@NonNull UseCaseConfigFactory factory) {
+        return factory.getConfig(ImageAnalysisConfig.class);
     }
 
     /**
@@ -473,8 +470,20 @@
     @NonNull
     @RestrictTo(Scope.LIBRARY_GROUP)
     @Override
+    public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config) {
+        return ImageAnalysis.Builder.fromConfig(config);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @hide
+     */
+    @NonNull
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @Override
     public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder() {
-        return Builder.fromConfig((ImageAnalysisConfig) getUseCaseConfig());
+        return Builder.fromConfig((ImageAnalysisConfig) getCurrentConfig());
     }
 
     /**
@@ -486,7 +495,7 @@
     @RestrictTo(Scope.LIBRARY_GROUP)
     @NonNull
     protected Size onSuggestedResolutionUpdated(@NonNull Size suggestedResolution) {
-        final ImageAnalysisConfig config = (ImageAnalysisConfig) getUseCaseConfig();
+        final ImageAnalysisConfig config = (ImageAnalysisConfig) getCurrentConfig();
 
         SessionConfig.Builder sessionConfigBuilder = createPipeline(getCameraId(), config,
                 suggestedResolution);
@@ -641,6 +650,19 @@
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
+        static Builder fromConfig(@NonNull Config configuration) {
+            return new Builder(MutableOptionsBundle.from(configuration));
+        }
+
+        /**
+         * Generates a Builder from another Config object.
+         *
+         * @param configuration An immutable configuration to pre-populate this builder.
+         * @return The new Builder.
+         * @hide
+         */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
         public static Builder fromConfig(@NonNull ImageAnalysisConfig configuration) {
             return new Builder(MutableOptionsBundle.from(configuration));
         }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
index 40cccc2..d192fb7 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
@@ -39,11 +39,15 @@
 import static androidx.camera.core.impl.ImageCaptureConfig.OPTION_USE_CASE_EVENT_CALLBACK;
 import static androidx.camera.core.impl.ImageInputConfig.OPTION_INPUT_FORMAT;
 import static androidx.camera.core.impl.UseCaseConfig.OPTION_CAMERA_SELECTOR;
+import static androidx.camera.core.internal.utils.ImageUtil.min;
+import static androidx.camera.core.internal.utils.ImageUtil.sizeToVertexes;
 
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.graphics.ImageFormat;
+import android.graphics.Matrix;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.location.Location;
 import android.media.Image;
 import android.media.ImageReader;
@@ -81,6 +85,7 @@
 import androidx.camera.core.impl.CaptureConfig;
 import androidx.camera.core.impl.CaptureProcessor;
 import androidx.camera.core.impl.CaptureStage;
+import androidx.camera.core.impl.Config;
 import androidx.camera.core.impl.ConfigProvider;
 import androidx.camera.core.impl.DeferrableSurface;
 import androidx.camera.core.impl.ImageCaptureConfig;
@@ -93,6 +98,7 @@
 import androidx.camera.core.impl.OptionsBundle;
 import androidx.camera.core.impl.SessionConfig;
 import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
 import androidx.camera.core.impl.utils.CameraOrientationUtil;
 import androidx.camera.core.impl.utils.Exif;
 import androidx.camera.core.impl.utils.Threads;
@@ -311,7 +317,7 @@
     ImageCapture(@NonNull ImageCaptureConfig userConfig) {
         super(userConfig);
 
-        ImageCaptureConfig useCaseConfig = (ImageCaptureConfig) getUseCaseConfig();
+        ImageCaptureConfig useCaseConfig = (ImageCaptureConfig) getCurrentConfig();
 
         if (useCaseConfig.containsOption(OPTION_IMAGE_CAPTURE_MODE)) {
             mCaptureMode = useCaseConfig.getCaptureMode();
@@ -417,16 +423,23 @@
      *
      * @hide
      */
+    @RestrictTo(Scope.LIBRARY_GROUP)
     @Override
     @Nullable
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    public UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder() {
-        ImageCaptureConfig defaults = CameraX.getDefaultUseCaseConfig(ImageCaptureConfig.class);
-        if (defaults != null) {
-            return Builder.fromConfig(defaults);
-        }
+    public UseCaseConfig<?> getDefaultConfig(@NonNull UseCaseConfigFactory factory) {
+        return factory.getConfig(ImageCaptureConfig.class);
+    }
 
-        return null;
+    /**
+     * {@inheritDoc}
+     *
+     * @hide
+     */
+    @NonNull
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @Override
+    public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config) {
+        return Builder.fromConfig(config);
     }
 
     /**
@@ -438,7 +451,7 @@
     @RestrictTo(Scope.LIBRARY_GROUP)
     @Override
     public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder() {
-        return Builder.fromConfig((ImageCaptureConfig) getUseCaseConfig());
+        return Builder.fromConfig((ImageCaptureConfig) getCurrentConfig());
     }
 
     /**
@@ -462,7 +475,7 @@
     public int getFlashMode() {
         synchronized (mLockedFlashMode) {
             return mFlashMode != FLASH_MODE_UNKNOWN ? mFlashMode
-                    : ((ImageCaptureConfig) getUseCaseConfig()).getFlashMode(DEFAULT_FLASH_MODE);
+                    : ((ImageCaptureConfig) getCurrentConfig()).getFlashMode(DEFAULT_FLASH_MODE);
         }
     }
 
@@ -1095,7 +1108,7 @@
     @Override
     @RestrictTo(Scope.LIBRARY_GROUP)
     public void onAttached() {
-        ImageCaptureConfig useCaseConfig = (ImageCaptureConfig) getUseCaseConfig();
+        ImageCaptureConfig useCaseConfig = (ImageCaptureConfig) getCurrentConfig();
 
         CaptureConfig.Builder captureBuilder = CaptureConfig.Builder.createFrom(useCaseConfig);
         mCaptureConfig = captureBuilder.build();
@@ -1132,7 +1145,7 @@
     @RestrictTo(Scope.LIBRARY_GROUP)
     protected Size onSuggestedResolutionUpdated(@NonNull Size suggestedResolution) {
         mSessionConfigBuilder = createPipeline(getCameraId(),
-                (ImageCaptureConfig) getUseCaseConfig(), suggestedResolution);
+                (ImageCaptureConfig) getCurrentConfig(), suggestedResolution);
 
         updateSessionConfig(mSessionConfigBuilder.build());
 
@@ -2056,8 +2069,8 @@
                 return;
             }
 
-            Size dispatchResolution = null;
-            int dispatchRotation = 0;
+            Size dispatchResolution;
+            int dispatchRotationDegrees = 0;
 
             if (image.getFormat() == ImageFormat.JPEG) {
                 // JPEG needs to have rotation/crop based on the EXIF
@@ -2074,7 +2087,7 @@
                     buffer.rewind();
 
                     dispatchResolution = new Size(exif.getWidth(), exif.getHeight());
-                    dispatchRotation = exif.getRotation();
+                    dispatchRotationDegrees = exif.getRotation();
                 } catch (IOException e) {
                     notifyCallbackError(ERROR_FILE_IO, "Unable to parse JPEG exif", e);
                     image.close();
@@ -2082,13 +2095,14 @@
                 }
             } else {
                 // All other formats take the rotation based simply on the target rotation
-                dispatchRotation = mRotationDegrees;
+                dispatchResolution = new Size(image.getWidth(), image.getHeight());
+                dispatchRotationDegrees = mRotationDegrees;
             }
 
             // Construct the ImageProxy with the updated rotation & crop for the output
             ImageInfo imageInfo = ImmutableImageInfo.create(
                     image.getImageInfo().getTagBundle(),
-                    image.getImageInfo().getTimestamp(), dispatchRotation);
+                    image.getImageInfo().getTimestamp(), dispatchRotationDegrees);
 
             final ImageProxy dispatchedImageProxy = new SettableImageProxy(image,
                     dispatchResolution,
@@ -2097,12 +2111,13 @@
             // Update the crop rect aspect ratio after it has been rotated into the buffer
             // orientation
             if (mViewPortCropRect != null) {
-                // If Viewport is present, use the crop rect based on Viewport.
-                dispatchedImageProxy.setCropRect(mViewPortCropRect);
+                // If Viewport is present, use the Viewport-based crop rect.
+                dispatchedImageProxy.setCropRect(getDispatchCropRect(mViewPortCropRect,
+                        mRotationDegrees, dispatchResolution, dispatchRotationDegrees));
             } else if (mTargetRatio != null) {
                 // Fall back to crop aspect ratio if view port is not available.
                 Rational dispatchRatio = mTargetRatio;
-                if ((dispatchRotation % 180) != 0) {
+                if ((dispatchRotationDegrees % 180) != 0) {
                     dispatchRatio = new Rational(
                             /* invert the ratio numerator=*/ mTargetRatio.getDenominator(),
                             /* invert the ratio denominator=*/ mTargetRatio.getNumerator());
@@ -2128,6 +2143,50 @@
             }
         }
 
+        /**
+         * Corrects crop rect based on JPEG exif rotation.
+         *
+         * <p> The original crop rect is calculated based on camera sensor buffer. On some devices,
+         * the buffer is rotated before being passed to users, in which case the crop rect also
+         * needs additional transformations.
+         *
+         * <p> There are two most common scenarios: 1) exif rotation is 0, or 2) exif rotation
+         * equals output rotation. 1) means the HAL rotated the buffer based on target
+         * rotation. 2) means HAL no-oped on the rotation. Theoretically only 1) needs
+         * additional transformations, but this method is also generic enough to handle all possible
+         * HAL rotations.
+         */
+        @NonNull
+        static Rect getDispatchCropRect(@NonNull Rect surfaceCropRect, int surfaceToOutputDegrees,
+                @NonNull Size dispatchResolution, int dispatchToOutputDegrees) {
+            // There are 3 coordinate systems: surface, dispatch and output. Surface is where
+            // the original crop rect is defined. We need to figure out what HAL
+            // has done to the buffer (the surface->dispatch mapping) and apply the same
+            // transformation to the crop rect.
+            // The surface->dispatch mapping is calculated by inverting a dispatch->surface mapping.
+
+            Matrix matrix = new Matrix();
+            // Apply the dispatch->surface rotation.
+            matrix.setRotate(dispatchToOutputDegrees - surfaceToOutputDegrees);
+            // Apply the dispatch->surface translation. The translation is calculated by
+            // compensating for the offset caused by the dispatch->surface rotation.
+            float[] vertexes = sizeToVertexes(dispatchResolution);
+            matrix.mapPoints(vertexes);
+            float left = min(vertexes[0], vertexes[2], vertexes[4], vertexes[6]);
+            float top = min(vertexes[1], vertexes[3], vertexes[5], vertexes[7]);
+            matrix.postTranslate(-left, -top);
+            // Inverting the dispatch->surface mapping to get the surface->dispatch mapping.
+            matrix.invert(matrix);
+
+            // Apply the surface->dispatch mapping to surface crop rect.
+            RectF dispatchCropRectF = new RectF();
+            matrix.mapRect(dispatchCropRectF, new RectF(surfaceCropRect));
+            dispatchCropRectF.sort();
+            Rect dispatchCropRect = new Rect();
+            dispatchCropRectF.round(dispatchCropRect);
+            return dispatchCropRect;
+        }
+
         void notifyCallbackError(final @ImageCaptureError int imageCaptureError,
                 final String message, final Throwable cause) {
             // Check to make sure image hasn't been already dispatched or error has been notified
@@ -2182,7 +2241,20 @@
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
-        public static Builder fromConfig(@NonNull ImageCaptureConfig configuration) {
+        public static Builder fromConfig(@NonNull Config configuration) {
+            return new Builder(MutableOptionsBundle.from(configuration));
+        }
+
+        /**
+         * Generates a Builder from another Config object
+         *
+         * @param configuration An immutable configuration to pre-populate this builder.
+         * @return The new Builder.
+         * @hide
+         */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        static Builder fromConfig(@NonNull ImageCaptureConfig configuration) {
             return new Builder(MutableOptionsBundle.from(configuration));
         }
 
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
index 8a3b70b..8f92ad8 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
@@ -64,6 +64,7 @@
 import androidx.camera.core.impl.CaptureConfig;
 import androidx.camera.core.impl.CaptureProcessor;
 import androidx.camera.core.impl.CaptureStage;
+import androidx.camera.core.impl.Config;
 import androidx.camera.core.impl.ConfigProvider;
 import androidx.camera.core.impl.DeferrableSurface;
 import androidx.camera.core.impl.ImageFormatConstants;
@@ -75,6 +76,7 @@
 import androidx.camera.core.impl.PreviewConfig;
 import androidx.camera.core.impl.SessionConfig;
 import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
 import androidx.camera.core.impl.utils.Threads;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
 import androidx.camera.core.internal.CameraCaptureResultImageInfo;
@@ -377,7 +379,7 @@
                 // Either way, try updating session config and let createPipeline() sends a
                 // new SurfaceRequest.
                 if (getAttachedSurfaceResolution() != null) {
-                    updateConfigAndOutput(getCameraId(), (PreviewConfig) getUseCaseConfig(),
+                    updateConfigAndOutput(getCameraId(), (PreviewConfig) getCurrentConfig(),
                             getAttachedSurfaceResolution());
                     notifyReset();
                 }
@@ -446,16 +448,23 @@
      *
      * @hide
      */
+    @RestrictTo(Scope.LIBRARY_GROUP)
     @Override
     @Nullable
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    public UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder() {
-        PreviewConfig defaults = CameraX.getDefaultUseCaseConfig(PreviewConfig.class);
-        if (defaults != null) {
-            return Builder.fromConfig(defaults);
-        }
+    public UseCaseConfig<?> getDefaultConfig(@NonNull UseCaseConfigFactory factory) {
+        return factory.getConfig(PreviewConfig.class);
+    }
 
-        return null;
+    /**
+     * {@inheritDoc}
+     *
+     * @hide
+     */
+    @NonNull
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @Override
+    public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config) {
+        return Preview.Builder.fromConfig(config);
     }
 
     /**
@@ -467,7 +476,7 @@
     @RestrictTo(Scope.LIBRARY_GROUP)
     @Override
     public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder() {
-        return Preview.Builder.fromConfig((PreviewConfig) getUseCaseConfig());
+        return Preview.Builder.fromConfig((PreviewConfig) getCurrentConfig());
     }
 
     /**
@@ -501,7 +510,7 @@
     @NonNull
     protected Size onSuggestedResolutionUpdated(@NonNull Size suggestedResolution) {
         mSurfaceSize = suggestedResolution;
-        updateConfigAndOutput(getCameraId(), (PreviewConfig) getUseCaseConfig(),
+        updateConfigAndOutput(getCameraId(), (PreviewConfig) getCurrentConfig(),
                 suggestedResolution);
         return suggestedResolution;
     }
@@ -597,8 +606,6 @@
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     public static final class Defaults implements ConfigProvider<PreviewConfig> {
-        private static final Size DEFAULT_MAX_RESOLUTION =
-                CameraX.getSurfaceManager().getPreviewSize();
         private static final int DEFAULT_SURFACE_OCCUPANCY_PRIORITY = 2;
 
         private static final PreviewConfig DEFAULT_CONFIG;
@@ -606,7 +613,6 @@
         static {
             Builder builder =
                     new Builder()
-                            .setMaxResolution(DEFAULT_MAX_RESOLUTION)
                             .setSurfaceOccupancyPriority(DEFAULT_SURFACE_OCCUPANCY_PRIORITY);
             DEFAULT_CONFIG = builder.getUseCaseConfig();
         }
@@ -649,6 +655,18 @@
 
         /**
          * Generates a Builder from another Config object
+         * @return
+         *
+         * @hide
+         */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        static Builder fromConfig(@NonNull Config configuration) {
+            return new Builder(MutableOptionsBundle.from(configuration));
+        }
+
+        /**
+         * Generates a Builder from another Config object
          *
          * @param configuration An immutable configuration to pre-populate this builder.
          * @return The new Builder.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java b/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
index 8c50439..88ecd8b 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
@@ -16,8 +16,6 @@
 
 package androidx.camera.core;
 
-import static androidx.camera.core.impl.ImageOutputConfig.OPTION_TARGET_ROTATION;
-
 import android.annotation.SuppressLint;
 import android.graphics.Rect;
 import android.media.ImageReader;
@@ -33,11 +31,13 @@
 import androidx.annotation.RestrictTo.Scope;
 import androidx.camera.core.impl.CameraControlInternal;
 import androidx.camera.core.impl.CameraInternal;
+import androidx.camera.core.impl.Config;
 import androidx.camera.core.impl.Config.Option;
 import androidx.camera.core.impl.ImageOutputConfig;
-import androidx.camera.core.impl.MutableConfig;
+import androidx.camera.core.impl.MutableOptionsBundle;
 import androidx.camera.core.impl.SessionConfig;
 import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
 import androidx.camera.core.internal.utils.UseCaseConfigUtil;
 import androidx.core.util.Preconditions;
 
@@ -65,19 +65,8 @@
      */
     private final Set<StateChangeCallback> mStateChangeCallbacks = new HashSet<>();
 
-    /**
-     * Store the initial {@link UseCaseConfig} used to create the use case.
-     */
-    private final UseCaseConfig<?> mInitialUseCaseConfig;
     private final Object mCameraLock = new Object();
 
-    /**
-     * The default target rotation value is determined when the use case is created. Detaching
-     * and attaching the use case won't change the use case's default target rotation value.
-     */
-    @ImageOutputConfig.RotationValue
-    private final int mDefaultTargetRotation;
-
     ////////////////////////////////////////////////////////////////////////////////////////////
     // [UseCase lifetime dynamic] - Dynamic variables which could change during anytime during
     // the UseCase lifetime.
@@ -85,12 +74,25 @@
 
     private State mState = State.INACTIVE;
 
-    /** The target rotation setting set via {@link #setTargetRotationInternal(int)}. */
-    @ImageOutputConfig.RotationValue
-    private int mTargetRotation;
+    /** Extended config, applied on top of the app defined Config (mUseCaseConfig). */
+    @Nullable
+    private UseCaseConfig<?> mExtendedConfig;
 
+    /**
+     * Store the app defined {@link UseCaseConfig} used to create the use case.
+     */
+    @NonNull
     private UseCaseConfig<?> mUseCaseConfig;
 
+    /**
+     * The currently used Config.
+     *
+     * <p> This is the combination of the extended Config, app provided Config, and camera
+     * implementation Config (with decreasing priority).
+     */
+    @NonNull
+    private UseCaseConfig<?> mCurrentConfig;
+
     ////////////////////////////////////////////////////////////////////////////////////////////
     // [UseCase attached constant] - Is only valid when the UseCase is attached to a camera.
     ////////////////////////////////////////////////////////////////////////////////////////////
@@ -101,6 +103,13 @@
     private Size mAttachedResolution;
 
     /**
+     * The camera implementation provided Config. Its options has lowest priority and will be
+     * overwritten by any app defined or extended configs.
+     */
+    @Nullable
+    private UseCaseConfig<?> mCameraConfig;
+
+    /**
      * The crop rect calculated at the time of binding based on {@link ViewPort}.
      */
     @Nullable
@@ -119,131 +128,97 @@
     /**
      * Creates a named instance of the use case.
      *
-     * @param useCaseConfig the configuration object used for this use case
+     * @param currentConfig the configuration object used for this use case
      * @hide
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
-    protected UseCase(@NonNull UseCaseConfig<?> useCaseConfig) {
-        mInitialUseCaseConfig = useCaseConfig;
-        mUseCaseConfig = useCaseConfig;
-
-        // Determine the use case's target rotation value. If it has been provided in the
-        // useCaseConfig, extract it. Otherwise, obtain it from the default config provider.
-        if (useCaseConfig.containsOption(OPTION_TARGET_ROTATION)) {
-            mDefaultTargetRotation = useCaseConfig.retrieveOption(OPTION_TARGET_ROTATION);
-        } else {
-            UseCaseConfig.Builder<?, ?, ?> defaultBuilder = getDefaultBuilder();
-            mDefaultTargetRotation =
-                    defaultBuilder != null ? defaultBuilder.getUseCaseConfig().retrieveOption(
-                            OPTION_TARGET_ROTATION, Surface.ROTATION_0) : Surface.ROTATION_0;
-        }
-
-        mTargetRotation = mDefaultTargetRotation;
+    protected UseCase(@NonNull UseCaseConfig<?> currentConfig) {
+        mUseCaseConfig = currentConfig;
+        mCurrentConfig = currentConfig;
     }
 
     /**
-     * Returns a use case configuration pre-populated with default configuration
-     * options.
+     * Retrieve the default {@link UseCaseConfig} for the UseCase.
      *
-     * <p>This is used to generate a final configuration by combining the user-supplied
-     * configuration with the default configuration. Subclasses can override this method to provide
-     * the pre-populated builder. If <code>null</code> is returned, then the user-supplied
-     * configuration will be used directly.
-     *
-     * @return A builder pre-populated with use case default options.
+     * @param factory the factory that contains the default UseCases.
+     * @return The UseCaseConfig or null if there is no default Config.
      * @hide
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @Nullable
-    public UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder() {
-        return null;
-    }
+    public abstract UseCaseConfig<?> getDefaultConfig(@NonNull UseCaseConfigFactory factory);
 
     /**
-     * Updates the stored use case configuration.
+     * Create a {@link UseCaseConfig.Builder} for the UseCase.
      *
-     * <p>This configuration will be combined with the default configuration that is contained in
-     * the pre-populated builder supplied by {@link #getDefaultBuilder}, if it exists and the
-     * behavior of {@link #applyDefaults(UseCaseConfig, UseCaseConfig.Builder)} is not overridden.
-     * Once this method returns, the combined use case configuration can be retrieved with
-     * {@link #getUseCaseConfig()}.
-     *
-     * <p>This method alone will not make any changes to the {@link SessionConfig}, it is up to
-     * the use case to decide when to modify the session configuration.
-     *
-     * @param useCaseConfig Configuration which will be applied on top of use case defaults, if a
-     *                      default builder is provided by {@link #getDefaultBuilder}.
-     * @throws IllegalStateException if this function is called when the UseCase is not attached
-     * to a camera.
-     * @hide
-     */
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    protected final void updateUseCaseConfig(@NonNull UseCaseConfig<?> useCaseConfig) {
-        // updateUseCaseConfig() can only be called after the use case is attached to a camera
-        // and then the settings will only be applied to the use case config. This is to make the
-        // use case config static.
-        CameraInternal camera = getCamera();
-
-        if (camera == null) {
-            throw new IllegalStateException("Disallow to call updateUseCaseConfig() before the "
-                    + "use case is attached to a camera.");
-        }
-
-        // Attempt to retrieve builder containing defaults for this use case's config
-        UseCaseConfig.Builder<?, ?, ?> defaultBuilder = getDefaultBuilder();
-
-        // Combine with default configuration.
-        mUseCaseConfig = applyDefaults(useCaseConfig, defaultBuilder);
-    }
-
-    /**
-     * Combines user-supplied configuration with use case default configuration.
-     *
-     * <p>Subclasses can override this method to
-     * modify the behavior of combining user-supplied values and default values.
-     *
-     * @param userConfig           The user-supplied configuration.
-     * @param defaultConfigBuilder A builder containing use-case default values, or {@code null}
-     *                             if no default values exist.
-     * @return The configuration that will be used by this use case.
+     * @param config the Config to initialize the builder
      * @hide
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @NonNull
-    public UseCaseConfig<?> applyDefaults(
-            @NonNull UseCaseConfig<?> userConfig,
-            @Nullable UseCaseConfig.Builder<?, ?, ?> defaultConfigBuilder) {
-        if (defaultConfigBuilder == null) {
+    public abstract UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config);
+
+    /**
+     * Create a merged {@link UseCaseConfig} from the UseCase, camera, and an extended config.
+     *
+     * @param extendedConfig      configs that take priority over the UseCase's default config
+     * @param cameraDefaultConfig configs that have lower priority than the UseCase's default.
+     *                            This Config comes from the camera implementation.
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @NonNull
+    public UseCaseConfig<?> mergeConfigs(
+            @Nullable UseCaseConfig<?> extendedConfig,
+            @Nullable UseCaseConfig<?> cameraDefaultConfig) {
+        if (extendedConfig == null && cameraDefaultConfig == null) {
             // No default builder was retrieved, return config directly
-            return userConfig;
+            return mUseCaseConfig;
         }
 
-        MutableConfig defaultMutableConfig = defaultConfigBuilder.getMutableConfig();
+        MutableOptionsBundle mergedConfig;
+
+        if (cameraDefaultConfig != null) {
+            mergedConfig = MutableOptionsBundle.from(cameraDefaultConfig);
+        } else {
+            mergedConfig = MutableOptionsBundle.create();
+        }
+
+        // If any options need special handling, this is the place to do it. For now we'll just copy
+        // over all options.
+        for (Option<?> opt : mUseCaseConfig.listOptions()) {
+            @SuppressWarnings("unchecked") // Options/values are being copied directly
+                    Option<Object> objectOpt = (Option<Object>) opt;
+
+            mergedConfig.insertOption(objectOpt,
+                    mUseCaseConfig.getOptionPriority(opt),
+                    mUseCaseConfig.retrieveOption(objectOpt));
+        }
+
+        if (extendedConfig != null) {
+            // If any options need special handling, this is the place to do it. For now we'll
+            // just copy
+            // over all options.
+            for (Option<?> opt : extendedConfig.listOptions()) {
+                @SuppressWarnings("unchecked") // Options/values are being copied directly
+                        Option<Object> objectOpt = (Option<Object>) opt;
+
+                mergedConfig.insertOption(objectOpt,
+                        extendedConfig.getOptionPriority(opt),
+                        extendedConfig.retrieveOption(objectOpt));
+            }
+        }
 
         // If OPTION_TARGET_RESOLUTION has been set by the user, remove
         // OPTION_TARGET_ASPECT_RATIO from defaultConfigBuilder because these two settings can be
         // set at the same time.
-        if (userConfig.containsOption(ImageOutputConfig.OPTION_TARGET_RESOLUTION)
-                && defaultMutableConfig.containsOption(
+        if (mergedConfig.containsOption(ImageOutputConfig.OPTION_TARGET_RESOLUTION)
+                && mergedConfig.containsOption(
                 ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO)) {
-            defaultMutableConfig.removeOption(ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO);
+            mergedConfig.removeOption(ImageOutputConfig.OPTION_TARGET_ASPECT_RATIO);
         }
 
-        // Overwrite the default config builder's target rotation value by the determined default
-        // target rotation value of the use case.
-        defaultMutableConfig.insertOption(OPTION_TARGET_ROTATION, mDefaultTargetRotation);
-
-        // If any options need special handling, this is the place to do it. For now we'll just copy
-        // over all options.
-        for (Option<?> opt : userConfig.listOptions()) {
-            @SuppressWarnings("unchecked") // Options/values are being copied directly
-                    Option<Object> objectOpt = (Option<Object>) opt;
-
-            defaultMutableConfig.insertOption(objectOpt,
-                    userConfig.getOptionPriority(opt), userConfig.retrieveOption(objectOpt));
-        }
-
-        return defaultConfigBuilder.getUseCaseConfig();
+        return getUseCaseConfigBuilder(mergedConfig).getUseCaseConfig();
     }
 
     /**
@@ -258,19 +233,15 @@
     @RestrictTo(Scope.LIBRARY_GROUP)
     protected boolean setTargetRotationInternal(
             @ImageOutputConfig.RotationValue int targetRotation) {
-        ImageOutputConfig oldConfig = (ImageOutputConfig) getUseCaseConfig();
+        ImageOutputConfig oldConfig = (ImageOutputConfig) getCurrentConfig();
         int oldRotation = oldConfig.getTargetRotation(ImageOutputConfig.INVALID_ROTATION);
         if (oldRotation == ImageOutputConfig.INVALID_ROTATION || oldRotation != targetRotation) {
-            // Camera is not null if the use case has been attached to a camera. Only calling
-            // updateUseCaseConfig() when the use case has been attached to a camera. So that
-            // some default config will be applied to the use case config.
-            if (getCamera() != null) {
-                UseCaseConfig.Builder<?, ?, ?> builder = getUseCaseConfigBuilder();
-                UseCaseConfigUtil.updateTargetRotationAndRelatedConfigs(builder, targetRotation);
-                updateUseCaseConfig(builder.getUseCaseConfig());
-            }
+            UseCaseConfig.Builder<?, ?, ?> builder = getUseCaseConfigBuilder(mUseCaseConfig);
+            UseCaseConfigUtil.updateTargetRotationAndRelatedConfigs(builder, targetRotation);
+            mUseCaseConfig = builder.getUseCaseConfig();
 
-            mTargetRotation = targetRotation;
+            mCurrentConfig = mergeConfigs(mExtendedConfig, mCameraConfig);
+
             return true;
         }
         return false;
@@ -280,14 +251,13 @@
      * Returns the rotation that the intended target resolution is expressed in.
      *
      * @return The rotation of the intended target.
-     *
      * @hide
      */
     @SuppressLint("WrongConstant")
     @RestrictTo(Scope.LIBRARY_GROUP)
     @ImageOutputConfig.RotationValue
     protected int getTargetRotationInternal() {
-        return mTargetRotation;
+        return ((ImageOutputConfig) mCurrentConfig).getTargetRotation(Surface.ROTATION_0);
     }
 
     /**
@@ -298,7 +268,8 @@
     @RestrictTo(Scope.LIBRARY_GROUP)
     @IntRange(from = 0, to = 359)
     protected int getRelativeRotation(@NonNull CameraInternal cameraInternal) {
-        return cameraInternal.getCameraInfoInternal().getSensorRotationDegrees(mTargetRotation);
+        return cameraInternal.getCameraInfoInternal().getSensorRotationDegrees(
+                getTargetRotationInternal());
     }
 
     /**
@@ -442,7 +413,7 @@
     @RestrictTo(Scope.LIBRARY_GROUP)
     @NonNull
     public String getName() {
-        return mUseCaseConfig.getTargetName("<UnknownUseCase-" + this.hashCode() + ">");
+        return mCurrentConfig.getTargetName("<UnknownUseCase-" + this.hashCode() + ">");
     }
 
     /**
@@ -452,8 +423,9 @@
      * @hide
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
-    public UseCaseConfig<?> getUseCaseConfig() {
-        return mUseCaseConfig;
+    @NonNull
+    public UseCaseConfig<?> getCurrentConfig() {
+        return mCurrentConfig;
     }
 
     /**
@@ -535,18 +507,16 @@
      */
     @SuppressLint("WrongConstant")
     @RestrictTo(Scope.LIBRARY_GROUP)
-    public void onAttach(@NonNull CameraInternal camera) {
+    public void onAttach(@NonNull CameraInternal camera, @NonNull UseCaseConfigFactory factory) {
         synchronized (mCameraLock) {
             mCamera = camera;
             addStateChangeCallback(camera);
         }
 
-        updateUseCaseConfig(mUseCaseConfig);
+        mCameraConfig = getDefaultConfig(factory);
+        mCurrentConfig = mergeConfigs(mExtendedConfig, mCameraConfig);
 
-        // Updates the user persistent target rotation setting to the use case config.
-        setTargetRotationInternal(mTargetRotation);
-
-        EventCallback eventCallback = mUseCaseConfig.getUseCaseEventCallback(null);
+        EventCallback eventCallback = mCurrentConfig.getUseCaseEventCallback(null);
         if (eventCallback != null) {
             eventCallback.onBind(camera.getCameraInfoInternal().getCameraId());
         }
@@ -580,7 +550,7 @@
         onDetached();
 
         // Cleanup required for any type of UseCase
-        EventCallback eventCallback = mUseCaseConfig.getUseCaseEventCallback(null);
+        EventCallback eventCallback = mCurrentConfig.getUseCaseEventCallback(null);
         if (eventCallback != null) {
             eventCallback.onUnbind();
         }
@@ -596,7 +566,8 @@
 
         // Resets the mUseCaseConfig to the initial status when the use case was created to make
         // the use case reusable.
-        mUseCaseConfig = mInitialUseCaseConfig;
+        mCurrentConfig = mUseCaseConfig;
+        mCameraConfig = null;
     }
 
     /**
@@ -673,7 +644,7 @@
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     public int getImageFormat() {
-        return mUseCaseConfig.getInputFormat();
+        return mCurrentConfig.getInputFormat();
     }
 
     enum State {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
index cdf1c21..eee4f7f 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
@@ -76,6 +76,7 @@
 import androidx.annotation.UiThread;
 import androidx.camera.core.impl.CameraInternal;
 import androidx.camera.core.impl.CaptureConfig;
+import androidx.camera.core.impl.Config;
 import androidx.camera.core.impl.ConfigProvider;
 import androidx.camera.core.impl.DeferrableSurface;
 import androidx.camera.core.impl.ImageOutputConfig;
@@ -86,6 +87,7 @@
 import androidx.camera.core.impl.OptionsBundle;
 import androidx.camera.core.impl.SessionConfig;
 import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
 import androidx.camera.core.impl.VideoCaptureConfig;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
 import androidx.camera.core.internal.ThreadConfig;
@@ -260,22 +262,16 @@
         return format;
     }
 
-
     /**
      * {@inheritDoc}
      *
      * @hide
      */
+    @RestrictTo(Scope.LIBRARY_GROUP)
     @Override
     @Nullable
-    @RestrictTo(Scope.LIBRARY_GROUP)
-    public UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder() {
-        VideoCaptureConfig defaults = CameraX.getDefaultUseCaseConfig(VideoCaptureConfig.class);
-        if (defaults != null) {
-            return Builder.fromConfig(defaults);
-        }
-
-        return null;
+    public UseCaseConfig<?> getDefaultConfig(@NonNull UseCaseConfigFactory factory) {
+        return factory.getConfig(VideoCaptureConfig.class);
     }
 
     /**
@@ -520,8 +516,20 @@
     @NonNull
     @RestrictTo(Scope.LIBRARY_GROUP)
     @Override
+    public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config) {
+        return Builder.fromConfig(config);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @hide
+     */
+    @NonNull
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @Override
     public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder() {
-        return Builder.fromConfig((VideoCaptureConfig) getUseCaseConfig());
+        return Builder.fromConfig(getCurrentConfig());
     }
 
     /**
@@ -581,7 +589,7 @@
     @UiThread
     @SuppressWarnings("WeakerAccess") /* synthetic accessor */
     void setupEncoder(@NonNull String cameraId, @NonNull Size resolution) {
-        VideoCaptureConfig config = (VideoCaptureConfig) getUseCaseConfig();
+        VideoCaptureConfig config = (VideoCaptureConfig) getCurrentConfig();
 
         // video encoder setup
         mVideoEncoder.reset();
@@ -976,7 +984,7 @@
         // In case no corresponding camcorder profile can be founded, * get default value from
         // VideoCaptureConfig.
         if (!isCamcorderProfileFound) {
-            VideoCaptureConfig config = (VideoCaptureConfig) getUseCaseConfig();
+            VideoCaptureConfig config = (VideoCaptureConfig) getCurrentConfig();
             mAudioChannelCount = config.getAudioChannelCount();
             mAudioSampleRate = config.getAudioSampleRate();
             mAudioBitRate = config.getAudioBitRate();
@@ -1199,6 +1207,20 @@
         }
 
         /**
+         * Generates a Builder from another Config object.
+         *
+         * @param configuration An immutable configuration to pre-populate this builder.
+         * @return The new Builder.
+         * @hide
+         */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        static Builder fromConfig(@NonNull Config configuration) {
+            return new Builder(MutableOptionsBundle.from(configuration));
+        }
+
+
+        /**
          * Generates a Builder from another Config object
          *
          * @param configuration An immutable configuration to pre-populate this builder.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
index fd60409..3f39bf9 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/CameraUseCaseAdapter.java
@@ -33,6 +33,7 @@
 import androidx.camera.core.impl.CameraInternal;
 import androidx.camera.core.impl.SurfaceConfig;
 import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
 import androidx.core.util.Preconditions;
 
 import java.util.ArrayList;
@@ -56,6 +57,7 @@
     private final CameraInternal mCameraInternal;
     private final LinkedHashSet<CameraInternal> mCameraInternals;
     private final CameraDeviceSurfaceManager mCameraDeviceSurfaceManager;
+    private final UseCaseConfigFactory mUseCaseConfigFactory;
 
     private static final String TAG = "CameraUseCaseAdapter";
 
@@ -85,11 +87,13 @@
      */
     public CameraUseCaseAdapter(@NonNull CameraInternal cameraInternal,
             @NonNull LinkedHashSet<CameraInternal> cameras,
-            @NonNull CameraDeviceSurfaceManager cameraDeviceSurfaceManager) {
+            @NonNull CameraDeviceSurfaceManager cameraDeviceSurfaceManager,
+            @NonNull UseCaseConfigFactory useCaseConfigFactory) {
         mCameraInternal = cameraInternal;
         mCameraInternals = new LinkedHashSet<>(cameras);
         mId = new CameraId(mCameraInternals);
         mCameraDeviceSurfaceManager = cameraDeviceSurfaceManager;
+        mUseCaseConfigFactory = useCaseConfigFactory;
     }
 
     /**
@@ -130,12 +134,6 @@
      * <p> This does not take into account UseCases which are already attached to the camera.
      */
     public void checkAttachUseCases(@NonNull List<UseCase> useCases) throws CameraException {
-        // Only do resolution calculation if UseCases were bound
-        if (!UseCaseOccupancy.checkUseCaseLimitNotExceeded(useCases)) {
-            throw new CameraException("Attempting to bind too many ImageCapture or "
-                    + "VideoCapture instances");
-        }
-
         // If the UseCases exceed the resolutions then it will throw an exception
         try {
             calculateSuggestedResolutions(useCases, Collections.emptyList());
@@ -153,24 +151,16 @@
     @UseExperimental(markerClass = androidx.camera.core.ExperimentalUseCaseGroup.class)
     public void addUseCases(@NonNull Collection<UseCase> useCases) throws CameraException {
         synchronized (mLock) {
-            List<UseCase> useCaseListAfterUpdate = new ArrayList<>(mUseCases);
             List<UseCase> newUseCases = new ArrayList<>();
 
             for (UseCase useCase : useCases) {
                 if (mUseCases.contains(useCase)) {
                     Logger.d(TAG, "Attempting to attach already attached UseCase");
                 } else {
-                    useCaseListAfterUpdate.add(useCase);
                     newUseCases.add(useCase);
                 }
             }
 
-            // Only do resolution calculation if UseCases were bound
-            if (!UseCaseOccupancy.checkUseCaseLimitNotExceeded(useCaseListAfterUpdate)) {
-                throw new CameraException("Attempting to bind too many ImageCapture or "
-                        + "VideoCapture instances");
-            }
-
             Map<UseCase, Size> suggestedResolutionsMap;
             try {
                 suggestedResolutionsMap =
@@ -198,7 +188,7 @@
             // At this point the binding will succeed since all the calculations are done
             // Do all attaching related work
             for (UseCase useCase : newUseCases) {
-                useCase.onAttach(mCameraInternal);
+                useCase.onAttach(mCameraInternal, mUseCaseConfigFactory);
                 useCase.updateSuggestedResolution(
                         Preconditions.checkNotNull(suggestedResolutionsMap.get(useCase)));
             }
@@ -303,12 +293,11 @@
         if (!newUseCases.isEmpty()) {
             Map<UseCaseConfig<?>, UseCase> configToUseCaseMap = new HashMap<>();
             for (UseCase useCase : newUseCases) {
-                UseCaseConfig.Builder<?, ?, ?> defaultBuilder = useCase.getDefaultBuilder();
+                UseCaseConfig<?> defaultConfig =
+                        useCase.getDefaultConfig(mUseCaseConfigFactory);
 
                 // Combine with default configuration.
-                UseCaseConfig<?> combinedUseCaseConfig =
-                        useCase.applyDefaults(useCase.getUseCaseConfig(),
-                                defaultBuilder);
+                UseCaseConfig<?> combinedUseCaseConfig = useCase.mergeConfigs(null, defaultConfig);
                 configToUseCaseMap.put(combinedUseCaseConfig, useCase);
             }
 
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/UseCaseOccupancy.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/UseCaseOccupancy.java
deleted file mode 100644
index 1790cd9..0000000
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/UseCaseOccupancy.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2020 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.camera.core.internal;
-
-import androidx.annotation.NonNull;
-import androidx.camera.core.ImageCapture;
-import androidx.camera.core.Logger;
-import androidx.camera.core.UseCase;
-import androidx.camera.core.VideoCapture;
-
-import java.util.List;
-
-/**
- * Checks to see if the number of specific {@link UseCase} exceeds the supported number.
- */
-public final class UseCaseOccupancy {
-    private static final String TAG = "UseCaseOccupancy";
-    private UseCaseOccupancy() {
-    }
-
-    /**
-     * Check to see if CameraX supports running the set of use cases.
-     *
-     * @return true if the set of use cases is supported, otherwise false
-     */
-    public static boolean checkUseCaseLimitNotExceeded(
-            @NonNull List<UseCase> useCases) {
-        int imageCaptureCount = 0;
-        int videoCaptureCount = 0;
-
-        for (UseCase useCase : useCases) {
-            if (useCase instanceof ImageCapture) {
-                imageCaptureCount++;
-            } else if (useCase instanceof VideoCapture) {
-                videoCaptureCount++;
-            }
-        }
-
-        if (imageCaptureCount > 1) {
-            Logger.e(TAG, "Exceeded max simultaneously bound image capture use cases.");
-            return false;
-        }
-
-        if (videoCaptureCount > 1) {
-            Logger.e(TAG, "Exceeded max simultaneously bound video capture use cases.");
-            return false;
-        }
-
-        return true;
-    }
-}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java b/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java
index c63c9df..c7d011a 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/internal/utils/ImageUtil.java
@@ -45,6 +45,22 @@
     }
 
     /**
+     * Converts a {@link Size} to an float array of vertexes.
+     */
+    @NonNull
+    public static float[] sizeToVertexes(@NonNull Size size) {
+        return new float[]{0, 0, size.getWidth(), 0, size.getWidth(), size.getHeight(), 0,
+                size.getHeight()};
+    }
+
+    /**
+     * Returns the min value.
+     */
+    public static float min(float value1, float value2, float value3, float value4) {
+        return Math.min(Math.min(value1, value2), Math.min(value3, value4));
+    }
+
+    /**
      * Rotates aspect ratio based on rotation degrees.
      */
     @NonNull
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java b/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
index 31d8cee..ff41aef 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
@@ -30,6 +30,7 @@
 import android.view.Surface;
 
 import androidx.camera.core.impl.CameraFactory;
+import androidx.camera.core.impl.CameraInternal;
 import androidx.camera.core.impl.TagBundle;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
 import androidx.camera.core.internal.CameraUseCaseAdapter;
@@ -65,7 +66,7 @@
 @MediumTest
 @RunWith(RobolectricTestRunner.class)
 @DoNotInstrument
-@Config(minSdk = Build.VERSION_CODES.LOLLIPOP, shadows = {ShadowCameraX.class})
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
 public class ImageAnalysisTest {
 
     private static final int QUEUE_DEPTH = 8;
@@ -103,10 +104,12 @@
 
         mTagBundle = TagBundle.create(new Pair<>("FakeCaptureStageId", IMAGE_TAG));
 
+        CameraInternal camera = new FakeCamera();
+
         CameraFactory.Provider cameraFactoryProvider = (ignored1, ignored2) -> {
             FakeCameraFactory cameraFactory = new FakeCameraFactory();
-            cameraFactory.insertDefaultBackCamera(ShadowCameraX.DEFAULT_CAMERA_ID,
-                    () -> new FakeCamera(ShadowCameraX.DEFAULT_CAMERA_ID));
+            cameraFactory.insertDefaultBackCamera(camera.getCameraInfoInternal().getCameraId(),
+                    () -> camera);
             return cameraFactory;
         };
         CameraXConfig cameraXConfig = CameraXConfig.Builder.fromConfig(
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureTest.kt
index b38856c..d00ee97 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/ImageCaptureTest.kt
@@ -81,7 +81,7 @@
 @MediumTest
 @RunWith(RobolectricTestRunner::class)
 @DoNotInstrument
-@Config(minSdk = Build.VERSION_CODES.LOLLIPOP, shadows = [ShadowCameraX::class])
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
 class ImageCaptureTest {
 
     private lateinit var callbackHandler: Handler
@@ -102,11 +102,13 @@
     @Before
     @Throws(ExecutionException::class, InterruptedException::class)
     fun setUp() {
+        val camera = FakeCamera()
+
         val cameraFactoryProvider =
             CameraFactory.Provider { _: Context?, _: CameraThreadConfig? ->
                 val cameraFactory = FakeCameraFactory()
-                cameraFactory.insertDefaultBackCamera(ShadowCameraX.DEFAULT_CAMERA_ID) {
-                    FakeCamera(ShadowCameraX.DEFAULT_CAMERA_ID)
+                cameraFactory.insertDefaultBackCamera(camera.cameraInfoInternal.cameraId) {
+                    camera
                 }
                 cameraFactory
             }
@@ -171,7 +173,8 @@
         fakeImageReaderProxy?.triggerImageAvailable(TagBundle.create(Pair("TagBundleKey", 0)), 0)
         flushHandler(callbackHandler)
         cameraUseCaseAdapter.removeUseCases(
-            Collections.singleton(imageCapture) as Collection<UseCase>)
+            Collections.singleton(imageCapture) as Collection<UseCase>
+        )
 
         // Assert.
         // The captured image should still be valid even if the ImageCapture has been unbound. It
@@ -361,8 +364,11 @@
             .setSessionOptionUnpacker(sessionOptionUnpacker)
             .build()
 
-        cameraUseCaseAdapter = CameraUtil.createCameraUseCaseAdapter(ApplicationProvider
-            .getApplicationContext<Context>(), CameraSelector.DEFAULT_BACK_CAMERA)
+        cameraUseCaseAdapter = CameraUtil.createCameraUseCaseAdapter(
+            ApplicationProvider
+                .getApplicationContext<Context>(),
+            CameraSelector.DEFAULT_BACK_CAMERA
+        )
 
         cameraUseCaseAdapter.setViewPort(viewPort)
         cameraUseCaseAdapter.addUseCases(Collections.singleton<UseCase>(imageCapture))
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
index 5483966..5471a14 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/PreviewTest.kt
@@ -59,21 +59,22 @@
 @RunWith(RobolectricTestRunner::class)
 @DoNotInstrument
 @Config(
-    minSdk = Build.VERSION_CODES.LOLLIPOP, shadows = [ShadowCameraX::class]
+    minSdk = Build.VERSION_CODES.LOLLIPOP
 )
 class PreviewTest {
-
     var cameraUseCaseAdapter: CameraUseCaseAdapter? = null
 
     @Before
     @Throws(ExecutionException::class, InterruptedException::class)
     fun setUp() {
+        val camera = FakeCamera()
+
         val cameraFactoryProvider =
             CameraFactory.Provider { _: Context?, _: CameraThreadConfig? ->
                 val cameraFactory = FakeCameraFactory()
                 cameraFactory.insertDefaultBackCamera(
-                    ShadowCameraX.DEFAULT_CAMERA_ID
-                ) { FakeCamera(ShadowCameraX.DEFAULT_CAMERA_ID) }
+                    camera.cameraInfoInternal.cameraId
+                ) { camera }
                 cameraFactory
             }
         val cameraXConfig = CameraXConfig.Builder.fromConfig(
@@ -100,8 +101,10 @@
         )
         // The expected value is based on fitting the 1:1 view port into a rect with the size of
         // FakeCameraDeviceSurfaceManager.MAX_OUTPUT_SIZE.
-        val expectedPadding = (FakeCameraDeviceSurfaceManager.MAX_OUTPUT_SIZE.width -
-                FakeCameraDeviceSurfaceManager.MAX_OUTPUT_SIZE.height) / 2
+        val expectedPadding = (
+            FakeCameraDeviceSurfaceManager.MAX_OUTPUT_SIZE.width -
+                FakeCameraDeviceSurfaceManager.MAX_OUTPUT_SIZE.height
+            ) / 2
         assertThat(transformationInfo.cropRect).isEqualTo(
             Rect(
                 expectedPadding,
@@ -174,7 +177,8 @@
                 CameraXExecutors.directExecutor(),
                 SurfaceRequest.TransformationInfoListener {
                     receivedTransformationInfo = it
-                })
+                }
+            )
         }
         shadowOf(getMainLooper()).idle()
         assertThat(receivedTransformationInfo!!.cropRect.getAspectRatio()).isEqualTo(rational1)
@@ -213,7 +217,8 @@
                 CameraXExecutors.directExecutor(),
                 SurfaceRequest.TransformationInfoListener {
                     receivedTransformationInfo = it
-                })
+                }
+            )
         }
         shadowOf(getMainLooper()).idle()
         assertThat(receivedTransformationInfo!!.targetRotation).isEqualTo(Surface.ROTATION_0)
@@ -237,7 +242,8 @@
             .build()
         val cameraUseCaseAdapter = CameraUtil.createCameraUseCaseAdapter(
             ApplicationProvider
-                .getApplicationContext(), TEST_CAMERA_SELECTOR
+                .getApplicationContext(),
+            TEST_CAMERA_SELECTOR
         )
         cameraUseCaseAdapter.addUseCases(Collections.singleton<UseCase>(preview))
 
@@ -252,7 +258,8 @@
                 CameraXExecutors.directExecutor(),
                 SurfaceRequest.TransformationInfoListener {
                     receivedTransformationInfo = it
-                })
+                }
+            )
             receivedSurfaceRequest = request
         }
         shadowOf(getMainLooper()).idle()
@@ -267,7 +274,8 @@
                 CameraXExecutors.directExecutor(),
                 SurfaceRequest.TransformationInfoListener {
                     receivedTransformationInfo = it
-                })
+                }
+            )
             receivedSurfaceRequest = request
         }
         shadowOf(getMainLooper()).idle()
@@ -287,7 +295,8 @@
             .build()
         cameraUseCaseAdapter = CameraUtil.createCameraUseCaseAdapter(
             ApplicationProvider
-                .getApplicationContext(), TEST_CAMERA_SELECTOR
+                .getApplicationContext(),
+            TEST_CAMERA_SELECTOR
         )
         // Attach
         cameraUseCaseAdapter!!.addUseCases(Collections.singleton<UseCase>(preview))
@@ -317,12 +326,12 @@
     }
 
     private fun bindToLifecycleAndGetTransformationInfo(viewPort: ViewPort?):
-            SurfaceRequest.TransformationInfo {
-        return bindToLifecycleAndGetResult(viewPort).second
-    }
+        SurfaceRequest.TransformationInfo {
+            return bindToLifecycleAndGetResult(viewPort).second
+        }
 
     private fun bindToLifecycleAndGetResult(viewPort: ViewPort?): Pair<SurfaceRequest,
-            SurfaceRequest.TransformationInfo> {
+        SurfaceRequest.TransformationInfo> {
         // Arrange.
         val sessionOptionUnpacker =
             { _: UseCaseConfig<*>?, _: SessionConfig.Builder? -> }
@@ -337,7 +346,8 @@
                 CameraXExecutors.directExecutor(),
                 SurfaceRequest.TransformationInfoListener {
                     transformationInfo = it
-                })
+                }
+            )
             surfaceRequest = request
         }
 
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ShadowCameraX.java b/camera/camera-core/src/test/java/androidx/camera/core/ShadowCameraX.java
deleted file mode 100644
index 50189ad6..0000000
--- a/camera/camera-core/src/test/java/androidx/camera/core/ShadowCameraX.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2019 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.camera.core;
-
-import androidx.annotation.Nullable;
-import androidx.camera.core.impl.CameraDeviceSurfaceManager;
-import androidx.camera.core.impl.ImageAnalysisConfig;
-import androidx.camera.core.impl.ImageCaptureConfig;
-import androidx.camera.core.impl.PreviewConfig;
-import androidx.camera.core.impl.UseCaseConfig;
-import androidx.camera.testing.fakes.FakeCameraDeviceSurfaceManager;
-import androidx.camera.testing.fakes.FakeCameraInfoInternal;
-
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-
-/**
- * A Robolectric shadow of {@link CameraX}.
- */
-@Implements(CameraX.class)
-public class ShadowCameraX {
-    public static final String DEFAULT_CAMERA_ID = "0";
-
-    private static final UseCaseConfig<ImageAnalysis> DEFAULT_IMAGE_ANALYSIS_CONFIG =
-            new ImageAnalysis.Builder().setSessionOptionUnpacker(
-                    (config, builder) -> {
-                    }).getUseCaseConfig();
-
-    private static final UseCaseConfig<Preview> DEFAULT_PREVIEW_CONFIG =
-            new Preview.Builder().setSessionOptionUnpacker(
-                    (config, builder) -> {
-                    }).getUseCaseConfig();
-
-    private static final UseCaseConfig<ImageCapture> DEFAULT_IMAGE_CAPTURE_CONFIG =
-            new ImageCapture.Builder().setSessionOptionUnpacker(
-                    (config, builder) -> {
-                    }).getUseCaseConfig();
-
-    private static final CameraInfo DEFAULT_CAMERA_INFO = new FakeCameraInfoInternal();
-
-    private static final CameraDeviceSurfaceManager DEFAULT_DEVICE_SURFACE_MANAGER =
-            new FakeCameraDeviceSurfaceManager();
-
-    /**
-     * Shadow of {@link CameraX#getCameraInfo(String)}.
-     */
-    @Implementation
-    public static CameraInfo getCameraInfo(String cameraId) {
-        return DEFAULT_CAMERA_INFO;
-    }
-
-    /**
-     * Shadow of {@link CameraX#getDefaultUseCaseConfig(Class, CameraInfo)}.
-     */
-    @SuppressWarnings("unchecked")
-    @Implementation
-    public static <C extends UseCaseConfig<?>> C getDefaultUseCaseConfig(Class<C> configType,
-            @Nullable CameraInfo cameraInfo) {
-        if (configType.equals(PreviewConfig.class)) {
-            return (C) DEFAULT_PREVIEW_CONFIG;
-        } else if (configType.equals(ImageAnalysisConfig.class)) {
-            return (C) DEFAULT_IMAGE_ANALYSIS_CONFIG;
-        } else if (configType.equals(ImageCaptureConfig.class)) {
-            return (C) DEFAULT_IMAGE_CAPTURE_CONFIG;
-        }
-        throw new UnsupportedOperationException(
-                "Shadow UseCase config not implemented: " + configType);
-    }
-
-    /**
-     * Shadow of {@link CameraX#getSurfaceManager()}.
-     */
-    @Implementation
-    public static CameraDeviceSurfaceManager getSurfaceManager() {
-        return DEFAULT_DEVICE_SURFACE_MANAGER;
-    }
-}
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/VideoCaptureTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/VideoCaptureTest.kt
index 2f4340f..e2ce334 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/VideoCaptureTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/VideoCaptureTest.kt
@@ -46,18 +46,18 @@
 @RunWith(RobolectricTestRunner::class)
 @DoNotInstrument
 @Config(
-    minSdk = Build.VERSION_CODES.LOLLIPOP, shadows = [ShadowCameraX::class]
+    minSdk = Build.VERSION_CODES.LOLLIPOP
 )
 class VideoCaptureTest {
     @Before
     fun setUp() {
+        val camera = FakeCamera()
+
         val cameraFactoryProvider =
             CameraFactory.Provider { _: Context?, _: CameraThreadConfig? ->
                 val cameraFactory = FakeCameraFactory()
-                cameraFactory.insertDefaultBackCamera(ShadowCameraX.DEFAULT_CAMERA_ID) {
-                    FakeCamera(
-                        ShadowCameraX.DEFAULT_CAMERA_ID
-                    )
+                cameraFactory.insertDefaultBackCamera(camera.cameraInfoInternal.cameraId) {
+                    camera
                 }
                 cameraFactory
             }
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsTest.kt b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsTest.kt
index b5557095..32a6dc8 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsTest.kt
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionsTest.kt
@@ -96,7 +96,7 @@
 
         assertThat(
             ExtensionsManager.isExtensionAvailable(mEffectMode, mLensFacing) ==
-                    mExtensions.isExtensionAvailable(camera, mExtensionMode)
+                mExtensions.isExtensionAvailable(camera, mExtensionMode)
         ).isTrue()
     }
 }
\ No newline at end of file
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java
index 7c87555..62b0651 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java
@@ -179,7 +179,7 @@
         }
 
         for (UseCase useCase : activeUseCases) {
-            EffectMode previewExtenderMode = useCase.getUseCaseConfig().retrieveOption(
+            EffectMode previewExtenderMode = useCase.getCurrentConfig().retrieveOption(
                     PreviewExtender.OPTION_PREVIEW_EXTENDER_MODE, null);
 
             if (effectMode == previewExtenderMode) {
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java
index 8ba37ca..5c493f8b 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java
@@ -185,7 +185,7 @@
         }
 
         for (UseCase useCase : activeUseCases) {
-            EffectMode imageCaptureExtenderMode = useCase.getUseCaseConfig().retrieveOption(
+            EffectMode imageCaptureExtenderMode = useCase.getCurrentConfig().retrieveOption(
                     ImageCaptureExtender.OPTION_IMAGE_CAPTURE_EXTENDER_MODE, null);
 
             if (effectMode == imageCaptureExtenderMode) {
diff --git a/camera/camera-lifecycle/api/1.0.0-beta10.txt b/camera/camera-lifecycle/api/1.0.0-beta10.txt
new file mode 100644
index 0000000..88187bc6
--- /dev/null
+++ b/camera/camera-lifecycle/api/1.0.0-beta10.txt
@@ -0,0 +1,14 @@
+// Signature format: 3.0
+package androidx.camera.lifecycle {
+
+  public final class ProcessCameraProvider {
+    method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+    method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
+    method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+    method public boolean isBound(androidx.camera.core.UseCase);
+    method @MainThread public void unbind(androidx.camera.core.UseCase!...);
+    method @MainThread public void unbindAll();
+  }
+
+}
+
diff --git a/camera/camera-lifecycle/api/public_plus_experimental_1.0.0-beta10.txt b/camera/camera-lifecycle/api/public_plus_experimental_1.0.0-beta10.txt
new file mode 100644
index 0000000..d317ea5
--- /dev/null
+++ b/camera/camera-lifecycle/api/public_plus_experimental_1.0.0-beta10.txt
@@ -0,0 +1,22 @@
+// Signature format: 3.0
+package androidx.camera.lifecycle {
+
+  @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalCameraProviderConfiguration {
+  }
+
+  @experimental.Experimental @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ExperimentalUseCaseGroupLifecycle {
+  }
+
+  public final class ProcessCameraProvider {
+    method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+    method @MainThread @androidx.camera.lifecycle.ExperimentalUseCaseGroupLifecycle public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCaseGroup);
+    method @androidx.camera.lifecycle.ExperimentalCameraProviderConfiguration public static void configureInstance(androidx.camera.core.CameraXConfig);
+    method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
+    method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+    method public boolean isBound(androidx.camera.core.UseCase);
+    method @MainThread public void unbind(androidx.camera.core.UseCase!...);
+    method @MainThread public void unbindAll();
+  }
+
+}
+
diff --git a/camera/camera-lifecycle/api/res-1.0.0-beta10.txt b/camera/camera-lifecycle/api/res-1.0.0-beta10.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/camera/camera-lifecycle/api/res-1.0.0-beta10.txt
diff --git a/camera/camera-lifecycle/api/restricted_1.0.0-beta10.txt b/camera/camera-lifecycle/api/restricted_1.0.0-beta10.txt
new file mode 100644
index 0000000..88187bc6
--- /dev/null
+++ b/camera/camera-lifecycle/api/restricted_1.0.0-beta10.txt
@@ -0,0 +1,14 @@
+// Signature format: 3.0
+package androidx.camera.lifecycle {
+
+  public final class ProcessCameraProvider {
+    method @MainThread public androidx.camera.core.Camera bindToLifecycle(androidx.lifecycle.LifecycleOwner, androidx.camera.core.CameraSelector, androidx.camera.core.UseCase!...);
+    method public static com.google.common.util.concurrent.ListenableFuture<androidx.camera.lifecycle.ProcessCameraProvider!> getInstance(android.content.Context);
+    method public boolean hasCamera(androidx.camera.core.CameraSelector) throws androidx.camera.core.CameraInfoUnavailableException;
+    method public boolean isBound(androidx.camera.core.UseCase);
+    method @MainThread public void unbind(androidx.camera.core.UseCase!...);
+    method @MainThread public void unbindAll();
+  }
+
+}
+
diff --git a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraRepositoryTest.java b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraRepositoryTest.java
index e2b5492..cb7e298 100644
--- a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraRepositoryTest.java
+++ b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraRepositoryTest.java
@@ -24,6 +24,7 @@
 import androidx.camera.testing.fakes.FakeCameraDeviceSurfaceManager;
 import androidx.camera.testing.fakes.FakeLifecycleOwner;
 import androidx.camera.testing.fakes.FakeUseCase;
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory;
 import androidx.lifecycle.LifecycleOwner;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
@@ -56,7 +57,8 @@
         mCameraSet = new LinkedHashSet<>(Collections.singleton(camera));
         mCameraUseCaseAdapter = new CameraUseCaseAdapter(camera,
                 mCameraSet,
-                new FakeCameraDeviceSurfaceManager());
+                new FakeCameraDeviceSurfaceManager(),
+                new FakeUseCaseConfigFactory());
     }
 
     @Test(expected = IllegalArgumentException.class)
@@ -442,6 +444,7 @@
         CameraInternal fakeCamera = new FakeCamera(cameraId);
         return new CameraUseCaseAdapter(fakeCamera,
                 new LinkedHashSet<>(Collections.singleton(fakeCamera)),
-                new FakeCameraDeviceSurfaceManager());
+                new FakeCameraDeviceSurfaceManager(),
+                new FakeUseCaseConfigFactory());
     }
 }
diff --git a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraTest.java b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraTest.java
index d5b46dd..db47919 100644
--- a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraTest.java
+++ b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/LifecycleCameraTest.java
@@ -23,6 +23,7 @@
 import androidx.camera.testing.fakes.FakeCameraDeviceSurfaceManager;
 import androidx.camera.testing.fakes.FakeLifecycleOwner;
 import androidx.camera.testing.fakes.FakeUseCase;
+import androidx.camera.testing.fakes.FakeUseCaseConfigFactory;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
@@ -48,7 +49,8 @@
         mFakeCamera = new FakeCamera();
         mCameraUseCaseAdapter = new CameraUseCaseAdapter(mFakeCamera,
                 new LinkedHashSet<>(Collections.singleton(mFakeCamera)),
-                new FakeCameraDeviceSurfaceManager());
+                new FakeCameraDeviceSurfaceManager(),
+                new FakeUseCaseConfigFactory());
         mFakeUseCase = new FakeUseCase();
     }
 
diff --git a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/ProcessCameraProviderTest.kt b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/ProcessCameraProviderTest.kt
index 6c5cc189..00497d0 100644
--- a/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/ProcessCameraProviderTest.kt
+++ b/camera/camera-lifecycle/src/androidTest/java/androidx/camera/lifecycle/ProcessCameraProviderTest.kt
@@ -312,12 +312,16 @@
             provider = ProcessCameraProvider.getInstance(context).await()
 
             val useCase0 = Preview.Builder().setSessionOptionUnpacker { _, _ -> }.build()
-            val camera0 = provider.bindToLifecycle(lifecycleOwner0,
-                CameraSelector.DEFAULT_BACK_CAMERA, useCase0)
+            val camera0 = provider.bindToLifecycle(
+                lifecycleOwner0,
+                CameraSelector.DEFAULT_BACK_CAMERA, useCase0
+            )
 
             val useCase1 = Preview.Builder().setSessionOptionUnpacker { _, _ -> }.build()
-            val camera1 = provider.bindToLifecycle(lifecycleOwner1,
-                CameraSelector.DEFAULT_BACK_CAMERA, useCase1)
+            val camera1 = provider.bindToLifecycle(
+                lifecycleOwner1,
+                CameraSelector.DEFAULT_BACK_CAMERA, useCase1
+            )
 
             assertThat(camera0).isNotEqualTo(camera1)
         }
@@ -347,11 +351,18 @@
             val useCase0 = Preview.Builder().setSessionOptionUnpacker { _, _ -> }.build()
             val useCase1 = Preview.Builder().setSessionOptionUnpacker { _, _ -> }.build()
 
-            val camera0 = provider.bindToLifecycle(lifecycleOwner0, CameraSelector
-            .DEFAULT_BACK_CAMERA, useCase0)
-            val camera1 = provider.bindToLifecycle(lifecycleOwner0, CameraSelector
-            .DEFAULT_BACK_CAMERA,
-                useCase1)
+            val camera0 = provider.bindToLifecycle(
+                lifecycleOwner0,
+                CameraSelector
+                    .DEFAULT_BACK_CAMERA,
+                useCase0
+            )
+            val camera1 = provider.bindToLifecycle(
+                lifecycleOwner0,
+                CameraSelector
+                    .DEFAULT_BACK_CAMERA,
+                useCase1
+            )
 
             assertThat(camera0).isSameInstanceAs(camera1)
         }
@@ -389,11 +400,19 @@
             val useCase0 = Preview.Builder().setSessionOptionUnpacker { _, _ -> }.build()
             val useCase1 = Preview.Builder().setSessionOptionUnpacker { _, _ -> }.build()
 
-            val camera0 = provider.bindToLifecycle(lifecycleOwner0, CameraSelector
-                .DEFAULT_BACK_CAMERA, useCase0)
+            val camera0 = provider.bindToLifecycle(
+                lifecycleOwner0,
+                CameraSelector
+                    .DEFAULT_BACK_CAMERA,
+                useCase0
+            )
 
-            val camera1 = provider.bindToLifecycle(lifecycleOwner1, CameraSelector
-                .DEFAULT_FRONT_CAMERA, useCase1)
+            val camera1 = provider.bindToLifecycle(
+                lifecycleOwner1,
+                CameraSelector
+                    .DEFAULT_FRONT_CAMERA,
+                useCase1
+            )
 
             assertThat(camera0).isNotEqualTo(camera1)
         }
@@ -450,7 +469,7 @@
             provider = ProcessCameraProvider.getInstance(context).await()
             val camera: LifecycleCamera =
                 provider.bindToLifecycle(lifecycleOwner0, CameraSelector.DEFAULT_BACK_CAMERA) as
-                        LifecycleCamera
+                    LifecycleCamera
             lifecycleOwner0.startAndResume()
             assertThat(camera.isActive).isFalse()
         }
@@ -464,7 +483,7 @@
             lifecycleOwner0.startAndResume()
             val camera: LifecycleCamera =
                 provider.bindToLifecycle(lifecycleOwner0, CameraSelector.DEFAULT_BACK_CAMERA) as
-                        LifecycleCamera
+                    LifecycleCamera
             assertThat(camera.isActive).isFalse()
         }
     }
@@ -539,7 +558,7 @@
 }
 
 private class TestAppContextWrapper(base: Context, val app: Application? = null) : ContextWrapper
-    (base) {
+(base) {
 
     val testResources = TestResources(base.resources)
 
@@ -565,7 +584,8 @@
 
 @Suppress("DEPRECATION")
 private class TestResources(base: Resources) : Resources(
-    base.assets, base.displayMetrics, base
+    base.assets, base.displayMetrics,
+    base
         .configuration
 ) {
 
diff --git a/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java b/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
index 8312f2c..79ff401 100644
--- a/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
+++ b/camera/camera-lifecycle/src/main/java/androidx/camera/lifecycle/ProcessCameraProvider.java
@@ -375,7 +375,7 @@
                 CameraSelector.Builder.fromSelector(cameraSelector);
         // Append the camera filter required internally if there's any.
         for (UseCase useCase : useCases) {
-            CameraSelector selector = useCase.getUseCaseConfig().getCameraSelector(null);
+            CameraSelector selector = useCase.getCurrentConfig().getCameraSelector(null);
             if (selector != null) {
                 for (CameraFilter filter : selector.getCameraFilterSet()) {
                     selectorBuilder.addCameraFilter(filter);
@@ -414,7 +414,8 @@
                     mLifecycleCameraRepository.createLifecycleCamera(lifecycleOwner,
                             new CameraUseCaseAdapter(cameraInternals.iterator().next(),
                                     cameraInternals,
-                                    mCameraX.getCameraDeviceSurfaceManager()));
+                                    mCameraX.getCameraDeviceSurfaceManager(),
+                                    mCameraX.getDefaultConfigFactory()));
         }
 
         if (useCases.length == 0) {
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java b/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java
index 116a462..0c2b9e4 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/CameraUtil.java
@@ -283,7 +283,7 @@
             LinkedHashSet<CameraInternal> cameras =
                     cameraSelector.filter(cameraX.getCameraRepository().getCameras());
             return new CameraUseCaseAdapter(cameras.iterator().next(), cameras,
-                    cameraX.getCameraDeviceSurfaceManager());
+                    cameraX.getCameraDeviceSurfaceManager(), cameraX.getDefaultConfigFactory());
         } catch (ExecutionException | InterruptedException | TimeoutException e) {
             throw new RuntimeException("Unable to retrieve CameraX instance");
         }
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/Configs.java b/camera/camera-testing/src/main/java/androidx/camera/testing/Configs.java
index 4800728..b6d69bb 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/Configs.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/Configs.java
@@ -19,6 +19,7 @@
 import androidx.annotation.NonNull;
 import androidx.camera.core.UseCase;
 import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
 
 import java.util.HashMap;
 import java.util.List;
@@ -31,15 +32,13 @@
     /** Return a map that associates UseCases to UseCaseConfigs with default settings. */
     @NonNull
     public static Map<UseCase, UseCaseConfig<?>> useCaseConfigMapWithDefaultSettingsFromUseCaseList(
-            @NonNull List<UseCase> useCases) {
+            @NonNull List<UseCase> useCases, @NonNull UseCaseConfigFactory useCaseConfigFactory) {
         Map<UseCase, UseCaseConfig<?>> useCaseToConfigMap = new HashMap<>();
 
         for (UseCase useCase : useCases) {
-            UseCaseConfig.Builder<?, ?, ?> defaultBuilder = useCase.getDefaultBuilder();
-
             // Combine with default configuration.
-            UseCaseConfig<?> combinedUseCaseConfig = useCase.applyDefaults(
-                    useCase.getUseCaseConfig(), defaultBuilder);
+            UseCaseConfig<?> combinedUseCaseConfig = useCase.mergeConfigs(null,
+                    useCase.getDefaultConfig(useCaseConfigFactory));
             useCaseToConfigMap.put(useCase, combinedUseCaseConfig);
         }
 
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java b/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java
index 9a23aed..e2f4693 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java
@@ -133,7 +133,7 @@
             LinkedHashSet<CameraInternal> cameras =
                     cameraSelector.filter(cameraX.getCameraRepository().getCameras());
             mCameraUseCaseAdapter = new CameraUseCaseAdapter(cameras.iterator().next(), cameras,
-                    cameraX.getCameraDeviceSurfaceManager());
+                    cameraX.getCameraDeviceSurfaceManager(), cameraX.getDefaultConfigFactory());
             mCameraUseCaseAdapter.addUseCases(Collections.singleton(mPreview));
         } catch (InterruptedException | ExecutionException e) {
             e.printStackTrace();
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java
index a797434..b697234 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java
@@ -20,9 +20,11 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
 import androidx.camera.core.UseCase;
-import androidx.camera.core.impl.SessionConfig;
+import androidx.camera.core.impl.Config;
 import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
 
 /**
  * A fake {@link UseCase}.
@@ -44,16 +46,31 @@
         this(new FakeUseCaseConfig.Builder().getUseCaseConfig());
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * @hide
+     */
+    @NonNull
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @Override
+    public UseCaseConfig.Builder<?, ?, ?> getUseCaseConfigBuilder(@NonNull Config config) {
+        return new FakeUseCaseConfig.Builder(config)
+                .setSessionOptionUnpacker((useCaseConfig, sessionConfigBuilder) -> { });
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @hide
+     */
     @Nullable
-    public UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder() {
-        return new FakeUseCaseConfig.Builder()
-                .setSessionOptionUnpacker(new SessionConfig.OptionUnpacker() {
-                    @Override
-                    public void unpack(@NonNull UseCaseConfig<?> useCaseConfig,
-                            @NonNull SessionConfig.Builder sessionConfigBuilder) {
-                    }
-                });
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @Override
+    public UseCaseConfig<?> getDefaultConfig(@NonNull UseCaseConfigFactory factory) {
+        return new FakeUseCaseConfig.Builder(getCurrentConfig())
+                .setSessionOptionUnpacker((useCaseConfig, sessionConfigBuilder) -> {
+                }).getUseCaseConfig();
     }
 
     @Override
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java
index 3d2db75..7759f10 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java
@@ -68,6 +68,11 @@
             setTargetClass(FakeUseCase.class);
         }
 
+        public Builder(@NonNull Config config) {
+            mOptionsBundle = MutableOptionsBundle.from(config);
+            setTargetClass(FakeUseCase.class);
+        }
+
         @Override
         @NonNull
         public MutableConfig getMutableConfig() {
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfigFactory.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfigFactory.java
new file mode 100644
index 0000000..1cfb60a
--- /dev/null
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfigFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2020 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.camera.testing.fakes;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.camera.core.impl.UseCaseConfig;
+import androidx.camera.core.impl.UseCaseConfigFactory;
+
+/**
+ * A fake implementation of {@link UseCaseConfigFactory}.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public final class FakeUseCaseConfigFactory implements UseCaseConfigFactory {
+    @Nullable
+    @Override
+    public <C extends UseCaseConfig<?>> C getConfig(@NonNull Class<C> configType) {
+        return null;
+    }
+}
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewTransformationDeviceTest.kt b/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewTransformationDeviceTest.kt
index 7605453..e32f258 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewTransformationDeviceTest.kt
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/PreviewTransformationDeviceTest.kt
@@ -187,7 +187,8 @@
             SurfaceRequest.TransformationInfo.of(
                 CROP_RECT,
                 90, Surface.ROTATION_90
-            ), SURFACE_SIZE
+            ),
+            SURFACE_SIZE
         )
 
         // Act.
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/AccelerometerRotationListener.java b/camera/camera-view/src/main/java/androidx/camera/view/AccelerometerRotationListener.java
new file mode 100644
index 0000000..b5cf3b5
--- /dev/null
+++ b/camera/camera-view/src/main/java/androidx/camera/view/AccelerometerRotationListener.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 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.camera.view;
+
+import android.content.Context;
+import android.view.OrientationEventListener;
+import android.view.Surface;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+
+/**
+ * Listens to accelerometer reading and converts the orientation degrees to {@link Surface}
+ * rotation.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public abstract class AccelerometerRotationListener extends OrientationEventListener {
+
+    public static final int INVALID_SURFACE_ROTATION = -1;
+
+    private int mRotation = INVALID_SURFACE_ROTATION;
+
+    public AccelerometerRotationListener(@NonNull Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onOrientationChanged(int orientation) {
+        if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
+            // Short-circuit if orientation is unknown. Unknown rotation can't be handled so it
+            // shouldn't be sent.
+            return;
+        }
+
+        int newRotation;
+        if (orientation >= 315 || orientation < 45) {
+            newRotation = Surface.ROTATION_0;
+        } else if (orientation >= 225) {
+            newRotation = Surface.ROTATION_90;
+        } else if (orientation >= 135) {
+            newRotation = Surface.ROTATION_180;
+        } else {
+            newRotation = Surface.ROTATION_270;
+        }
+        if (mRotation != newRotation) {
+            mRotation = newRotation;
+            onRotationChanged(newRotation);
+        }
+    }
+
+    /**
+     * Invoked when rotation changes.
+     *
+     * <p> The output rotation is defined as the UI Surface rotation, or what the Surface rotation
+     * should be if the app's orientation is not locked.
+     */
+    public abstract void onRotationChanged(int rotation);
+}
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
index 1d97dfb..4067a55 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/CameraController.java
@@ -16,8 +16,14 @@
 
 package androidx.camera.view;
 
+import static androidx.camera.view.AccelerometerRotationListener.INVALID_SURFACE_ROTATION;
+
 import android.annotation.SuppressLint;
 import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.Display;
 
 import androidx.annotation.MainThread;
 import androidx.annotation.NonNull;
@@ -39,6 +45,7 @@
 import androidx.camera.core.UseCase;
 import androidx.camera.core.UseCaseGroup;
 import androidx.camera.core.VideoCapture;
+import androidx.camera.core.ViewPort;
 import androidx.camera.core.ZoomState;
 import androidx.camera.core.impl.utils.Threads;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
@@ -78,11 +85,6 @@
     @Nullable
     Preview mPreview;
 
-    // SurfaceProvider form the latest attachPreviewSurface() call.
-    // Synthetic access
-    @SuppressWarnings("WeakerAccess")
-    Preview.SurfaceProvider mSurfaceProvider;
-
     // Synthetic access
     @SuppressWarnings("WeakerAccess")
     @Nullable
@@ -120,16 +122,46 @@
     @Nullable
     ProcessCameraProvider mCameraProvider;
 
+
+    // Synthetic access
+    @SuppressWarnings("WeakerAccess")
+    @Nullable
+    ViewPort mViewPort;
+
+    // Synthetic access
+    @SuppressWarnings("WeakerAccess")
+    @Nullable
+    Preview.SurfaceProvider mSurfaceProvider;
+
+    // Synthetic access
+    @SuppressWarnings("WeakerAccess")
+    @Nullable
+    Display mPreviewDisplay;
+
+    @NonNull
+    private final AccelerometerRotationListener mAccelerometerRotationListener;
+
+    @Nullable
+    private final DisplayChangeListener mDisplayChangeListener;
+
+    // Synthetic access
+    @SuppressWarnings("WeakerAccess")
+    int mAccelerometerRotation = INVALID_SURFACE_ROTATION;
+    int mDisplayRotation = INVALID_SURFACE_ROTATION;
+
     private boolean mPinchToZoomEnabled = true;
     private boolean mTapToFocusEnabled = true;
 
     private final ForwardingLiveData<ZoomState> mZoomState = new ForwardingLiveData<>();
     private final ForwardingLiveData<Integer> mTorchState = new ForwardingLiveData<>();
 
+    private final Context mAppContext;
+
     CameraController(@NonNull Context context) {
+        mAppContext = context.getApplicationContext();
         // Wait for camera to be initialized before binding use cases.
         Futures.addCallback(
-                ProcessCameraProvider.getInstance(context),
+                ProcessCameraProvider.getInstance(mAppContext),
                 new FutureCallback<ProcessCameraProvider>() {
 
                     @SuppressLint("MissingPermission")
@@ -141,6 +173,8 @@
                                 mFlashMode).build();
                         mVideoCapture = new VideoCapture.Builder().build();
                         mCameraProvider = provider;
+                        updateImageAndVideoRotationIfCameraIsReady();
+                        updatePreviewRotationIfCameraIsReady();
                         startCameraAndTrackStates();
                     }
 
@@ -151,6 +185,19 @@
                     }
 
                 }, CameraXExecutors.mainThreadExecutor());
+
+        // Listen to display rotation and set target rotation for Preview.
+        mDisplayChangeListener = new DisplayChangeListener();
+
+        // Listen to accelerometer reading and set target rotation for ImageCapture and
+        // VideoCapture.
+        mAccelerometerRotationListener = new AccelerometerRotationListener(mAppContext) {
+            @Override
+            public void onRotationChanged(int rotation) {
+                mAccelerometerRotation = rotation;
+                updateImageAndVideoRotationIfCameraIsReady();
+            }
+        };
     }
 
     /**
@@ -165,21 +212,32 @@
 
     /**
      * Internal API used by {@link PreviewView} to notify changes.
-     *
-     * TODO(b/148791439): replace width/height with a Viewport.
      */
-    @SuppressLint("MissingPermission")
+    @SuppressLint({"MissingPermission", "WrongConstant"})
     @MainThread
-    void attachPreviewSurface(@NonNull Preview.SurfaceProvider surfaceProvider, int width,
-            int height) {
+    @UseExperimental(markerClass = ExperimentalUseCaseGroup.class)
+    void attachPreviewSurface(@NonNull Preview.SurfaceProvider surfaceProvider,
+            @NonNull ViewPort viewPort, @NonNull Display display) {
         Threads.checkMainThread();
         if (mSurfaceProvider != surfaceProvider) {
-            mSurfaceProvider = surfaceProvider;
             // Avoid setting provider unnecessarily which restarts Preview pipeline.
+            mSurfaceProvider = surfaceProvider;
             if (mPreview != null) {
                 mPreview.setSurfaceProvider(surfaceProvider);
             }
         }
+        mViewPort = viewPort;
+        mPreviewDisplay = display;
+        // Update default rotation value with display rotation.
+        if (mAccelerometerRotation == INVALID_SURFACE_ROTATION) {
+            mAccelerometerRotation = display.getRotation();
+            updateImageAndVideoRotationIfCameraIsReady();
+        }
+        if (mDisplayRotation == INVALID_SURFACE_ROTATION) {
+            mDisplayRotation = display.getRotation();
+            updatePreviewRotationIfCameraIsReady();
+        }
+        startListeningToRotationEvents();
         startCameraAndTrackStates();
     }
 
@@ -198,6 +256,26 @@
         }
         mCamera = null;
         mSurfaceProvider = null;
+        mViewPort = null;
+        mPreviewDisplay = null;
+        stopListeningToRotationEvents();
+    }
+
+    private void startListeningToRotationEvents() {
+        getDisplayManager().registerDisplayListener(mDisplayChangeListener,
+                new Handler(Looper.getMainLooper()));
+        if (mAccelerometerRotationListener.canDetectOrientation()) {
+            mAccelerometerRotationListener.enable();
+        }
+    }
+
+    private void stopListeningToRotationEvents() {
+        getDisplayManager().unregisterDisplayListener(mDisplayChangeListener);
+        mAccelerometerRotationListener.disable();
+    }
+
+    private DisplayManager getDisplayManager() {
+        return (DisplayManager) mAppContext.getSystemService(Context.DISPLAY_SERVICE);
     }
 
     // ----------------------
@@ -645,7 +723,6 @@
         return mCamera.getCameraControl().enableTorch(torchEnabled);
     }
 
-    // TODO(b/148791439): Handle rotation so the output is always in gravity orientation.
     // TODO(b/148791439): Give user a way to tell if the camera provider is ready.
 
     /**
@@ -668,11 +745,11 @@
      */
     @UseExperimental(markerClass = ExperimentalUseCaseGroup.class)
     protected UseCaseGroup createUseCaseGroup() {
-        if (mCameraProvider == null) {
+        if (mCameraProvider == null || mPreview == null) {
             Logger.d(TAG, CAMERA_NOT_READY);
             return null;
         }
-        if (mSurfaceProvider == null || mPreview == null) {
+        if (mSurfaceProvider == null || mViewPort == null) {
             // Preview is required. Return early if preview Surface is not ready.
             Logger.d(TAG, "Preview is not ready.");
             return null;
@@ -687,7 +764,58 @@
             builder.addUseCase(mVideoCapture);
         }
 
-        // TODO(b/148791439): set ViewPort if mPreviewSize/ LayoutDirection is not null.
+        builder.setViewPort(mViewPort);
         return builder.build();
     }
+
+    // Synthetic access
+    @SuppressWarnings("WeakerAccess")
+    @SuppressLint("WrongConstant")
+    void updateImageAndVideoRotationIfCameraIsReady() {
+        if (mAccelerometerRotation != INVALID_SURFACE_ROTATION && mImageCapture != null
+                && mVideoCapture != null) {
+            mImageCapture.setTargetRotation(mAccelerometerRotation);
+            mVideoCapture.setTargetRotation(mAccelerometerRotation);
+        }
+
+    }
+
+    @SuppressLint("WrongConstant")
+    @UseExperimental(markerClass = ExperimentalUseCaseGroup.class)
+    void updatePreviewRotationIfCameraIsReady() {
+        if (mDisplayRotation != INVALID_SURFACE_ROTATION && mPreview != null) {
+            mPreview.setTargetRotation(mDisplayRotation);
+        }
+    }
+
+    /**
+     * Listener for display changes.
+     *
+     * <p>When the device is rotated 180° from side to side, the activity is not
+     * destroyed and recreated, thus {@link #attachPreviewSurface} will not be invoked. This
+     * class is necessary to make sure preview's target rotation is the display rotation when
+     * that happens.
+     */
+    // Synthetic access
+    @SuppressWarnings("WeakerAccess")
+    class DisplayChangeListener implements DisplayManager.DisplayListener {
+
+        @Override
+        public void onDisplayAdded(int displayId) {
+        }
+
+        @Override
+        public void onDisplayRemoved(int displayId) {
+        }
+
+        @SuppressLint("WrongConstant")
+        @Override
+        public void onDisplayChanged(int displayId) {
+            if (mPreviewDisplay != null && mPreview != null
+                    && mPreviewDisplay.getDisplayId() == displayId) {
+                mDisplayRotation = mPreviewDisplay.getRotation();
+                updatePreviewRotationIfCameraIsReady();
+            }
+        }
+    }
 }
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java b/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
index b66bed6..4b58b90 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
@@ -67,16 +67,17 @@
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
- * Custom View that displays the camera feed for CameraX's Preview use case.
+ * Custom View that displays the camera feed for CameraX's {@link Preview} use case.
  *
- * <p> This class manages the Surface lifecycle, as well as the preview aspect ratio and
- * orientation. Internally, it uses either a {@link TextureView} or {@link SurfaceView} to
- * display the camera feed.
+ * <p> This class manages the preview {@link Surface}'s lifecycle. It internally uses either a
+ * {@link TextureView} or {@link SurfaceView} to display the camera feed, and applies required
+ * transformations on them to correctly display the preview, this involves correcting their
+ * aspect ratio, scale and rotation.
  *
  * <p> If {@link PreviewView} uses a {@link SurfaceView} to display the preview
  * stream, be careful when overlapping a {@link View} that's initially not visible (either
- * {@link View#INVISIBLE} or {@link View#GONE}) on top of it. When the
- * {@link SurfaceView} is attached to the display window, it calls
+ * {@link View#INVISIBLE} or {@link View#GONE}) on top of it. When the {@link SurfaceView} is
+ * attached to the display window, it calls
  * {@link android.view.ViewParent#requestTransparentRegion(View)} which requests a computation of
  * the transparent regions on the display. At this point, the {@link View} isn't visible, causing
  * the overlapped region between the {@link SurfaceView} and the {@link View} to be
@@ -133,23 +134,17 @@
     private float mDownX = 0F;
     private float mDownY = 0F;
 
-    private final OnLayoutChangeListener mOnLayoutChangeListener = new OnLayoutChangeListener() {
-        @Override
-        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
-                int oldTop, int oldRight, int oldBottom) {
+    private final OnLayoutChangeListener mOnLayoutChangeListener =
+            (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
 
-            mPreviewViewMeteringPointFactory.setViewSize(getWidth(), getHeight());
-            boolean isSizeChanged =
-                    right - left != oldRight - oldLeft || bottom - top != oldBottom - oldTop;
-            if (isSizeChanged) {
-                redrawPreview();
-            }
-            if (mCameraController != null && isSizeChanged) {
-                mCameraController.attachPreviewSurface(getSurfaceProvider(), getWidth(),
-                        getHeight());
-            }
-        }
-    };
+                mPreviewViewMeteringPointFactory.setViewSize(getWidth(), getHeight());
+                boolean isSizeChanged =
+                        right - left != oldRight - oldLeft || bottom - top != oldBottom - oldTop;
+                if (isSizeChanged) {
+                    redrawPreview();
+                    attachToControllerIfReady();
+                }
+            };
 
     private final Preview.SurfaceProvider mSurfaceProvider = new Preview.SurfaceProvider() {
 
@@ -248,10 +243,7 @@
             mImplementation.onAttachedToWindow();
         }
         mPreviewViewMeteringPointFactory.setDisplay(getDisplay());
-        if (mCameraController != null) {
-            mCameraController.attachPreviewSurface(getSurfaceProvider(), getWidth(),
-                    getHeight());
-        }
+        attachToControllerIfReady();
     }
 
     @Override
@@ -309,12 +301,13 @@
     /**
      * Sets the {@link ImplementationMode} for the {@link PreviewView}.
      *
-     * <p> {@link PreviewView} displays the preview with either a {@link SurfaceView} or a
-     * {@link TextureView} depending on the mode. If not set, the default value is
-     * {@link ImplementationMode#PERFORMANCE}.
-     *
-     * @see ImplementationMode
+     * <p> {@link PreviewView} displays the preview with a {@link TextureView} when the
+     * mode is {@link ImplementationMode#COMPATIBLE}, and tries to use a {@link SurfaceView} if
+     * it is {@link ImplementationMode#PERFORMANCE} when possible, which depends on the device's
+     * attributes (e.g. API level, camera hardware support level). If not set, the default mode
+     * is {@link ImplementationMode#PERFORMANCE}.
      */
+    @UiThread
     public void setImplementationMode(@NonNull final ImplementationMode implementationMode) {
         mImplementationMode = implementationMode;
     }
@@ -327,24 +320,27 @@
      *
      * @return The {@link ImplementationMode} for {@link PreviewView}.
      */
+    @UiThread
     @NonNull
     public ImplementationMode getImplementationMode() {
         return mImplementationMode;
     }
 
     /**
-     * Gets the {@link Preview.SurfaceProvider} to be used with
-     * {@link Preview#setSurfaceProvider(Executor, Preview.SurfaceProvider)}.
+     * Gets a {@link Preview.SurfaceProvider} to be used with
+     * {@link Preview#setSurfaceProvider(Executor, Preview.SurfaceProvider)}. This allows the
+     * camera feed to start when the {@link Preview} use case is bound to a lifecycle.
      *
      * <p> The returned {@link Preview.SurfaceProvider} will provide a preview {@link Surface} to
      * the camera that's either managed by a {@link TextureView} or {@link SurfaceView} depending
-     * on the {@link ImplementationMode}.
+     * on the {@link ImplementationMode} and the device's attributes (e.g. API level, camera
+     * hardware support level).
      *
-     * @return A {@link Preview.SurfaceProvider} used to start the camera preview.
+     * @return A {@link Preview.SurfaceProvider} to attach to a {@link Preview} use case.
      * @see ImplementationMode
      */
-    @NonNull
     @UiThread
+    @NonNull
     @UseExperimental(markerClass = ExperimentalUseCaseGroup.class)
     public Preview.SurfaceProvider getSurfaceProvider() {
         Threads.checkMainThread();
@@ -358,6 +354,7 @@
      *
      * @param scaleType A {@link ScaleType} to apply to the preview.
      */
+    @UiThread
     public void setScaleType(@NonNull final ScaleType scaleType) {
         mPreviewTransform.setScaleType(scaleType);
         mPreviewViewMeteringPointFactory.setScaleType(scaleType);
@@ -371,49 +368,54 @@
      *
      * @return The {@link ScaleType} currently applied to the preview.
      */
+    @UiThread
     @NonNull
     public ScaleType getScaleType() {
         return mPreviewTransform.getScaleType();
     }
 
     /**
-     * Gets the {@link MeteringPointFactory} for the Camera currently connected to the PreviewView.
+     * Gets the {@link MeteringPointFactory} for the camera currently connected to the
+     * {@link PreviewView}, if any.
      *
      * <p>The returned {@link MeteringPointFactory} is capable of creating {@link MeteringPoint}s
      * from (x, y) coordinates in the {@link PreviewView}. This conversion takes into account its
      * {@link ScaleType}.
      *
      * <p>When the PreviewView has a width and/or height equal to zero, or when a preview
-     * {@link Surface} is not yet requested, the returned factory will always create invalid
-     * {@link MeteringPoint}s which could lead to the failure of
-     * {@link androidx.camera.core.CameraControl#startFocusAndMetering(FocusMeteringAction)} but it
-     * won't cause any crash.
+     * {@link Surface} is not yet requested by the camera, the returned factory will always create
+     * invalid {@link MeteringPoint}s which could lead to the failure of
+     * {@link androidx.camera.core.CameraControl#startFocusAndMetering(FocusMeteringAction)}, but it
+     * won't cause the application to crash.
      *
      * @return a {@link MeteringPointFactory}
      */
+    @UiThread
     @NonNull
     public MeteringPointFactory getMeteringPointFactory() {
         return mPreviewViewMeteringPointFactory;
     }
 
     /**
-     * Gets the {@link LiveData} of current preview {@link StreamState}.
+     * Gets a {@link LiveData} for the preview {@link StreamState}.
      *
-     * <p>There are two states, {@link StreamState#IDLE} and {@link StreamState#STREAMING}.
-     * {@link StreamState#IDLE} represents the preview is currently not visible and streaming is
-     * stopped. {@link StreamState#STREAMING} means the preview is streaming.
+     * <p>There are two preview stream states, {@link StreamState#IDLE} and
+     * {@link StreamState#STREAMING}. {@link StreamState#IDLE} indicates the preview is currently
+     * not visible and streaming is stopped. {@link StreamState#STREAMING} means the preview is
+     * streaming or is about to start streaming. This state guarantees the preview is visible
+     * only when the {@link ImplementationMode} is {@link ImplementationMode#COMPATIBLE}. When in
+     * {@link ImplementationMode#PERFORMANCE} mode, it is possible the preview becomes
+     * visible slightly after the state changes to {@link StreamState#STREAMING}.
      *
-     * <p>When {@link PreviewView} is in a {@link StreamState#STREAMING} state, it guarantees
-     * preview is visible only when implementationMode is {@link ImplementationMode#COMPATIBLE}.
-     * When in {@link ImplementationMode#PERFORMANCE} mode, it is possible that preview becomes
-     * visible slightly after state changes to {@link StreamState#STREAMING}. For apps
-     * relying on the preview visible signal to be working correctly, please set
-     * {@link ImplementationMode#COMPATIBLE} mode in
-     * {@link #setImplementationMode}.
+     * <p>Apps that require a precise signal for when the preview starts should
+     * {@linkplain #setImplementationMode(ImplementationMode) set} the implementation mode to
+     * {@link ImplementationMode#COMPATIBLE}.
      *
-     * @return A {@link LiveData} containing the {@link StreamState}. Apps can either get current
-     * value by {@link LiveData#getValue()} or register a observer by {@link LiveData#observe} .
+     * @return A {@link LiveData} of the preview's {@link StreamState}. Apps can get the current
+     * state with {@link LiveData#getValue()}, or register an observer with
+     * {@link LiveData#observe} .
      */
+    @UiThread
     @NonNull
     public LiveData<StreamState> getPreviewStreamState() {
         return mPreviewStreamStateLiveData;
@@ -439,6 +441,7 @@
      * @return A {@link Bitmap.Config#ARGB_8888} {@link Bitmap} representing the content
      * displayed on the preview {@link Surface}, or null if the camera preview hasn't started yet.
      */
+    @UiThread
     @Nullable
     public Bitmap getBitmap() {
         return mImplementation == null ? null : mImplementation.getBitmap();
@@ -455,6 +458,7 @@
      * @see ViewPort
      * @see UseCaseGroup
      */
+    @UiThread
     @Nullable
     @ExperimentalUseCaseGroup
     public ViewPort getViewPort() {
@@ -490,7 +494,7 @@
      * ViewPort viewPort = previewView.getViewPort(targetRotation);
      * UseCaseGroup useCaseGroup =
      *     new UseCaseGroup.Builder().setViewPort(viewPort).addUseCase(preview).build();
-     * cameraProvider.bindToLifecycle(this, cameraSelector, useCaseGroup);
+     * cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCaseGroup);
      * </code></pre>
      *
      * <p> Note that for non-display rotation to work, the mode must be set to
@@ -502,6 +506,7 @@
      *                       {@link Surface#ROTATION_270}.
      * @see ImplementationMode
      */
+    @UiThread
     @SuppressLint("WrongConstant")
     @Nullable
     @ExperimentalUseCaseGroup
@@ -587,17 +592,18 @@
          * {@link TextureView} instead.
          *
          * <p>{@link PreviewView} falls back to {@link TextureView} when the API level is 24 or
-         * lower, the camera hardware is
+         * lower, the camera hardware support level is
          * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY}, or
          * {@link Preview#getTargetRotation()} is different from {@link PreviewView}'s display
          * rotation.
          *
          * <p>Do not use this mode if {@link Preview.Builder#setTargetRotation(int)} is set
          * to a value different than the display's rotation, because {@link SurfaceView} does not
-         * support arbitrary transformation. Do not use this mode if the {@link PreviewView}
+         * support arbitrary rotations. Do not use this mode if the {@link PreviewView}
          * needs to be animated. {@link SurfaceView} animation is not supported on API level 24
-         * or lower. Also, for streaming state provided in {@link #getPreviewStreamState}, the
-         * {@link StreamState#STREAMING} state might happen prematurely if this mode is used.
+         * or lower. Also, for the preview's streaming state provided in
+         * {@link #getPreviewStreamState}, the {@link StreamState#STREAMING} state might happen
+         * prematurely if this mode is used.
          *
          * @see Preview.Builder#setTargetRotation(int)
          * @see Preview.Builder#getTargetRotation()
@@ -693,7 +699,7 @@
     }
 
     /**
-     * Definitions for current preview stream state.
+     * Definitions for the preview stream state.
      */
     public enum StreamState {
         /** Preview is not visible yet. */
@@ -701,10 +707,10 @@
         /**
          * Preview is streaming.
          *
-         * It only guarantees preview streaming when implementation mode is
-         * {@link ImplementationMode#COMPATIBLE}. When in {@link ImplementationMode#PERFORMANCE},
-         * it is possible that preview becomes visible slightly after state is changed. For apps
-         * relying on the preview visible signal to work correctly, please set
+         * <p>This state only guarantees the preview is streaming when the implementation mode is
+         * {@link ImplementationMode#COMPATIBLE}. When in {@link ImplementationMode#PERFORMANCE}
+         * mode, it is possible that the preview becomes visible slightly after the state has
+         * changed. For apps requiring a precise signal for when the preview starts, please set
          * {@link ImplementationMode#PERFORMANCE} mode via {@link #setImplementationMode}.
          */
         STREAMING
@@ -743,10 +749,7 @@
             mCameraController.clearPreviewSurface();
         }
         mCameraController = cameraController;
-        if (mCameraController != null) {
-            mCameraController.attachPreviewSurface(getSurfaceProvider(), getWidth(),
-                    getHeight());
-        }
+        attachToControllerIfReady();
     }
 
     /**
@@ -761,4 +764,14 @@
         Threads.checkMainThread();
         return mCameraController;
     }
+
+    @UseExperimental(markerClass = ExperimentalUseCaseGroup.class)
+    private void attachToControllerIfReady() {
+        Display display = getDisplay();
+        ViewPort viewPort = getViewPort();
+        if (mCameraController != null && viewPort != null && isAttachedToWindow()
+                && display != null) {
+            mCameraController.attachPreviewSurface(getSurfaceProvider(), viewPort, display);
+        }
+    }
 }
diff --git a/camera/integration-tests/camerapipetestapp/build.gradle b/camera/integration-tests/camerapipetestapp/build.gradle
index 13156be..af70051 100644
--- a/camera/integration-tests/camerapipetestapp/build.gradle
+++ b/camera/integration-tests/camerapipetestapp/build.gradle
@@ -56,6 +56,7 @@
 
     // Android Support Library
     implementation("androidx.appcompat:appcompat:1.1.0")
+    implementation(CONSTRAINT_LAYOUT, { transitive = true })
 
     // Camera Pipe
     implementation(project(":camera:camera-camera2-pipe"))
diff --git a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt
index e87a73d..4e29e3e 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt
+++ b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeActivity.kt
@@ -17,120 +17,58 @@
 package androidx.camera.integration.camera2.pipe
 
 import android.app.Activity
+import android.hardware.camera2.CameraCharacteristics
 import android.os.Build
 import android.os.Bundle
 import android.util.Log
 import android.view.View
-import android.view.ViewGroup
 import android.view.WindowManager
-import android.widget.RelativeLayout
+import androidx.camera.camera2.pipe.CameraId
 import androidx.camera.camera2.pipe.CameraPipe
-import androidx.camera.camera2.pipe.CameraTimestamp
-import androidx.camera.camera2.pipe.FrameInfo
-import androidx.camera.camera2.pipe.FrameNumber
-import androidx.camera.camera2.pipe.Request
-import androidx.camera.camera2.pipe.RequestMetadata
-import androidx.camera.integration.camera2.pipe.dataholders.GraphDataHolder
-import androidx.camera.integration.camera2.pipe.dataholders.GraphDataHolderStateImpl
-import androidx.camera.integration.camera2.pipe.dataholders.GraphDataHolderValueImpl
-import androidx.camera.integration.camera2.pipe.dataholders.KeyValueDataHolder
-import androidx.camera.integration.camera2.pipe.transformations.DataTransformations1D
-import androidx.camera.integration.camera2.pipe.transformations.DataTransformationsKeyValue
-import androidx.camera.integration.camera2.pipe.visualizations.KeyValueView
-import androidx.camera.integration.camera2.pipe.visualizations.Paints
-import androidx.camera.integration.camera2.pipe.visualizations.StateGraphView
-import androidx.camera.integration.camera2.pipe.visualizations.ValueGraphView
-import kotlinx.android.synthetic.main.activity_main.graphs
-import kotlinx.android.synthetic.main.activity_main.key_values
-import kotlinx.android.synthetic.main.graph_layout.view.graph_layout
-import kotlinx.android.synthetic.main.graph_layout.view.graph_view_layout
-import kotlinx.android.synthetic.main.graph_layout.view.top_row_layout
-import kotlinx.android.synthetic.main.key_value_layout.view.key_name
-import kotlinx.android.synthetic.main.key_value_layout.view.key_value_layout
-import kotlinx.android.synthetic.main.key_value_layout.view.value_layout
 
+/**
+ * This is the main activity for the CameraPipe test application.
+ */
 class CameraPipeActivity : Activity() {
-    private lateinit var dataManager: DataManager
-    private lateinit var dataListener: DataListener
-    private lateinit var dataGenerator: DataGenerator
-    private lateinit var paints: Paints
-    private lateinit var viewfinder: Viewfinder
-
     private lateinit var cameraPipe: CameraPipe
+    private lateinit var dataVisualizations: DataVisualizations
+    private lateinit var ui: CameraPipeUi
+
+    private var lastCameraId: CameraId? = null
     private var currentCamera: SimpleCamera? = null
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         Log.i("CXCP-App", "Activity onCreate")
 
+        // This adjusts the UI to make the activity run a a full screen application.
         configureFullScreenCameraWindow()
         cameraPipe = (applicationContext as CameraPipeApplication).cameraPipe
 
-        setContentView(R.layout.activity_main)
-        viewfinder = findViewById(R.id.viewfinder)
-        paints = Paints(this)
+        // Inflate the main ui for the camera activity.
+        ui = CameraPipeUi.inflate(this)
 
-        val beginTimeNanos = System.nanoTime()
+        // Configure and wire up basic UI behaviors.
+        ui.disableButton(ui.captureButton)
+        ui.disableButton(ui.infoButton)
+        ui.viewfinderText.visibility = View.VISIBLE
+        ui.switchButton.setOnClickListener { startNextCamera() }
 
-        // Initialize manager of data holders for visualizations, and data holders themselves
-        dataManager = DataManager(VisualizationDefaults)
-        dataManager.initializeDataHolders()
-
-        // Initialize the listener of new data
-        dataListener = DataListener(
-            dataManager,
-            DataTransformationsKeyValue,
-            DataTransformations1D,
-            beginTimeNanos
-        )
-
-        // Initialize the data generator and start generating data, noting the begin timestamp
-        dataGenerator = DataGenerator(
-            dataListener,
-            VisualizationDefaults
-        )
-        dataGenerator.beginTimeNanos = beginTimeNanos
-
-        // Set up the views powered by data holders, and plug in the data holders
-        setUpVisualizations()
+        // TODO: Update this to work with newer versions of the visualizations and to accept
+        //   the CameraPipeUi object as a parameter.
+        dataVisualizations = DataVisualizations(this)
     }
 
     override fun onStart() {
         super.onStart()
         Log.i("CXCP-App", "Activity onStart")
 
-        if (currentCamera == null) {
-            dataGenerator.runDataGenerators()
-            currentCamera = SimpleCamera.create(cameraPipe, viewfinder, listOf(object : Request
-            .Listener {
-                override fun onStarted(
-                    requestMetadata: RequestMetadata,
-                    frameNumber: FrameNumber,
-                    timestamp: CameraTimestamp
-                ) {
-//                    Log.i("PJR", "OnStart:   $frameNumber")
-                    // TODO: Implement the onStarted event to get frameNumber(s) and timestamps
-                }
-
-                override fun onTotalCaptureResult(
-                    requestMetadata: RequestMetadata,
-                    frameNumber: FrameNumber,
-                    totalCaptureResult: FrameInfo
-                ) {
-//                    Log.i("PJR", "onTotalCaptureResult: $frameNumber")
-                }
-
-                override fun onComplete(
-                    requestMetadata: RequestMetadata,
-                    frameNumber: FrameNumber,
-                    result: FrameInfo
-                ) {
-                    Log.i("PJR", "onComplete: $frameNumber")
-                    // TODO: Implement the onComplete event to write out Metadata
-                }
-            }))
+        val camera = currentCamera
+        if (camera == null) {
+            startNextCamera()
+        } else {
+            camera.start()
         }
-        currentCamera!!.start()
     }
 
     override fun onResume() {
@@ -147,16 +85,49 @@
         super.onStop()
         Log.i("CXCP-App", "Activity onStop")
         currentCamera?.stop()
-
-        // TODO: Stop data generation threads here, but do not stall the app waiting for the threads
-        //   to quit.
     }
 
     override fun onDestroy() {
         super.onDestroy()
         Log.i("CXCP-App", "Activity onDestroy")
         currentCamera?.close()
-        dataGenerator.quitDataGenerators()
+        dataVisualizations.close()
+    }
+
+    private fun startNextCamera() {
+        var camera = currentCamera
+        camera?.stop()
+
+        val cameraId = findNextCamera(lastCameraId)
+        camera = SimpleCamera.create(cameraPipe, cameraId, ui.viewfinder, listOf())
+        currentCamera = camera
+        lastCameraId = cameraId
+        ui.viewfinderText.text = camera.cameraInfoString()
+
+        camera.start()
+    }
+
+    private fun findNextCamera(lastCameraId: CameraId?): CameraId {
+        // By default, open the first back facing camera if no camera was previously configured.
+        if (lastCameraId == null) {
+            return cameraPipe.cameras().findAll().firstOrNull {
+                cameraPipe.cameras().awaitMetadata(it)[CameraCharacteristics.LENS_FACING] ==
+                        CameraCharacteristics.LENS_FACING_BACK
+            } ?: cameraPipe.cameras().findAll().first()
+        }
+
+        // If a camera was previously open, select the next camera in the list of all cameras. It is
+        // possible that the list of cameras contains only one camera, in which case this will return
+        // the same camera as "currentCameraId"
+        val cameras: List<CameraId> = cameraPipe.cameras().findAll()
+        val lastCameraIndex = cameras.indexOf(lastCameraId)
+        if (cameras.isEmpty() || lastCameraIndex == -1) {
+            Log.e("CXCP-App", "Failed to find matching camera!")
+            return cameraPipe.cameras().findAll().first()
+        }
+
+        // When we reach the end of the list of cameras, loop.
+        return cameras[(lastCameraIndex + 1) % cameras.size]
     }
 
     @Suppress("DEPRECATION")
@@ -191,105 +162,4 @@
         }
         window.attributes = windowParams
     }
-
-    /** Sets up all the different types of visualizations */
-    private fun setUpVisualizations() {
-        setUpKeyValueVisualizations(dataManager.keyValueDataHolders, dataManager.graphDataHolders)
-        setUpGraphVisualizations(dataManager.keyValueDataHolders, dataManager.graphDataHolders)
-    }
-
-    private fun setUpKeyValueVisualizations(
-        keyValeDataHolders: Map<CameraMetadataKey, KeyValueDataHolder>,
-        graphDataHolders: Map<CameraMetadataKey, GraphDataHolder>
-    ) {
-        val heightPixels = 30
-
-        keyValeDataHolders.forEach loop@{
-            if (graphDataHolders.containsKey(it.key)) return@loop
-            val dataHolder = it.value
-            val keyValueView =
-                KeyValueView(
-                    this,
-                    dataHolder,
-                    paints
-                )
-
-            val keyValueLayout = View.inflate(this, R.layout.key_value_layout, null)
-            keyValueLayout.key_name.text = "${it.key.name}    "
-
-            val keyValueViewParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams
-                .MATCH_PARENT, heightPixels)
-            keyValueView.layoutParams = keyValueViewParams
-
-            keyValueLayout.key_value_layout.value_layout.addView(keyValueView)
-            key_values.addView(keyValueLayout)
-        }
-    }
-
-    /** Sets up the graph visualizations specifically */
-    private fun setUpGraphVisualizations(
-        keyValeDataHolders: Map<CameraMetadataKey, KeyValueDataHolder>,
-        graphDataHolders: Map<CameraMetadataKey, GraphDataHolder>
-    ) {
-        val heightPixels = 110
-
-        graphDataHolders.forEach {
-            val key = it.key
-            val dataHolder = it.value
-            val graphView = when (dataHolder) {
-                is GraphDataHolderValueImpl -> ValueGraphView(
-                    this,
-                    dataGenerator.beginTimeNanos,
-                    dataHolder,
-                    paints
-                )
-                is GraphDataHolderStateImpl -> StateGraphView(
-                    this,
-                    dataGenerator.beginTimeNanos,
-                    dataHolder,
-                    paints = paints
-                )
-                else -> throw Exception("Visualization is not supported for this graphDataHolder " +
-                        "implementation")
-            }
-
-            val graphLayout = View.inflate(this, R.layout.graph_layout, null)
-
-            val graphViewParams = RelativeLayout.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                heightPixels
-            )
-            graphViewParams.addRule(RelativeLayout.BELOW, graphLayout.top_row_layout.id)
-            graphView.layoutParams = graphViewParams
-
-            graphLayout.graph_view_layout.addView(graphView)
-            graphLayout.graph_layout.setBackgroundResource(R.drawable.graph_background)
-
-            val graphLayoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams
-                .WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
-            graphLayoutParams.setMargins(0, 0, 0, 20)
-            graphLayout.layoutParams = graphLayoutParams
-
-            val keyValueDataHolder = keyValeDataHolders[key]
-            if (keyValueDataHolder != null) {
-                val keyValueView =
-                    KeyValueView(
-                        this,
-                        keyValueDataHolder,
-                        paints
-                    )
-                val keyValueLayout = View.inflate(this, R.layout.key_value_layout, null)
-                keyValueLayout.key_name.text = "${it.key.name} "
-
-                val keyValueViewParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams
-                    .MATCH_PARENT, 30)
-                keyValueView.layoutParams = keyValueViewParams
-
-                keyValueLayout.key_value_layout.value_layout.addView(keyValueView)
-                graphLayout.top_row_layout.addView(keyValueLayout)
-            }
-
-            graphs.addView(graphLayout)
-        }
-    }
 }
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeUi.kt b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeUi.kt
new file mode 100644
index 0000000..feb1ac4
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/CameraPipeUi.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2020 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.camera.integration.camera2.pipe
+
+import android.app.Activity
+import android.graphics.drawable.Drawable
+import android.view.View
+import android.widget.ImageButton
+import android.widget.LinearLayout
+import android.widget.ScrollView
+import android.widget.TextView
+
+class CameraPipeUi private constructor(activity: Activity) {
+    companion object {
+        /**
+         * Set the content view for the activity and then bind basic interactions together.
+         */
+        fun inflate(activity: Activity): CameraPipeUi {
+            activity.setContentView(R.layout.activity_main)
+            return CameraPipeUi(activity)
+        }
+    }
+
+    val viewfinder: Viewfinder = activity.findViewById(R.id.viewfinder)
+    val viewfinderText: TextView = activity.findViewById(R.id.viewfinder_text)
+    val switchButton: ImageButton = activity.findViewById(R.id.switch_button)
+    val captureButton: ImageButton = activity.findViewById(R.id.capture_button)
+    val infoButton: ImageButton = activity.findViewById(R.id.info_button)
+    val infoView: LinearLayout = activity.findViewById(R.id.info_content)
+    val infoText: TextView = activity.findViewById(R.id.info_text)
+
+    @Suppress("DEPRECATION")
+    private val recordBackground: Drawable = activity.resources.getDrawable(
+        R.drawable.theme_round_button_record
+    )
+
+    @Suppress("DEPRECATION")
+    private val defaultBackground: Drawable = activity.resources.getDrawable(
+        R.drawable.theme_round_button_default
+    )
+
+    init {
+        val infoViewContainer: ScrollView = activity.findViewById(R.id.info_view)
+        infoButton.setOnClickListener {
+            if (infoViewContainer.visibility == View.VISIBLE) {
+                infoViewContainer.visibility = View.INVISIBLE
+            } else {
+                infoViewContainer.visibility = View.VISIBLE
+                infoViewContainer.isClickable = true
+            }
+        }
+        infoView.setOnClickListener { infoViewContainer.visibility = View.INVISIBLE }
+    }
+
+    fun disableButton(button: ImageButton) {
+        button.background = defaultBackground
+        button.isEnabled = false
+        button.alpha = 0.25f
+    }
+
+    fun enableButton(button: ImageButton) {
+        button.background = defaultBackground
+        button.isEnabled = true
+        button.alpha = 1.0f
+    }
+
+    fun enableRecordingButton(button: ImageButton) {
+        button.background = recordBackground
+        button.isEnabled = true
+        button.alpha = 1.0f
+    }
+}
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/DataVisualizations.kt b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/DataVisualizations.kt
new file mode 100644
index 0000000..2278003
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/DataVisualizations.kt
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2020 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.camera.integration.camera2.pipe
+
+import android.app.Activity
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup
+import android.widget.RelativeLayout
+import androidx.camera.integration.camera2.pipe.dataholders.GraphDataHolder
+import androidx.camera.integration.camera2.pipe.dataholders.GraphDataHolderStateImpl
+import androidx.camera.integration.camera2.pipe.dataholders.GraphDataHolderValueImpl
+import androidx.camera.integration.camera2.pipe.dataholders.KeyValueDataHolder
+import androidx.camera.integration.camera2.pipe.transformations.DataTransformations1D
+import androidx.camera.integration.camera2.pipe.transformations.DataTransformationsKeyValue
+import androidx.camera.integration.camera2.pipe.visualizations.KeyValueView
+import androidx.camera.integration.camera2.pipe.visualizations.Paints
+import androidx.camera.integration.camera2.pipe.visualizations.StateGraphView
+import androidx.camera.integration.camera2.pipe.visualizations.ValueGraphView
+import kotlinx.android.synthetic.main.graph_layout.view.graph_layout
+import kotlinx.android.synthetic.main.graph_layout.view.graph_view_layout
+import kotlinx.android.synthetic.main.graph_layout.view.top_row_layout
+import kotlinx.android.synthetic.main.key_value_layout.view.key_name
+import kotlinx.android.synthetic.main.key_value_layout.view.key_value_layout
+import kotlinx.android.synthetic.main.key_value_layout.view.value_layout
+
+class DataVisualizations(activity: Activity) {
+    private var dataManager: DataManager
+    private var dataListener: DataListener
+    private var dataGenerator: DataGenerator
+    private var paints: Paints
+
+    private val context: Context
+
+    init {
+        context = activity
+        paints = Paints(activity)
+
+        val beginTimeNanos = System.nanoTime()
+
+        // Initialize manager of data holders for visualizations, and data holders themselves
+        dataManager = DataManager(VisualizationDefaults)
+        dataManager.initializeDataHolders()
+
+        // Initialize the listener of new data
+        dataListener = DataListener(
+            dataManager,
+            DataTransformationsKeyValue,
+            DataTransformations1D,
+            beginTimeNanos
+        )
+
+        // Initialize the data generator and start generating data, noting the begin timestamp
+        dataGenerator = DataGenerator(
+            dataListener,
+            VisualizationDefaults
+        )
+        dataGenerator.beginTimeNanos = beginTimeNanos
+
+        // Set up the views powered by data holders, and plug in the data holders
+        setUpVisualizations()
+    }
+
+    fun start() {
+        // TODO(codelogic): Attach and start the data visualizer.
+//        dataGenerator.runDataGenerators()
+    }
+
+    fun stop() {
+        // TODO(codelogic): Unregister and clear visualizations
+    }
+
+    fun close() {
+    }
+
+    /** Sets up all the different types of visualizations */
+    private fun setUpVisualizations() {
+        setUpKeyValueVisualizations(dataManager.keyValueDataHolders, dataManager.graphDataHolders)
+        setUpGraphVisualizations(dataManager.keyValueDataHolders, dataManager.graphDataHolders)
+    }
+
+    private fun setUpKeyValueVisualizations(
+        keyValeDataHolders: Map<CameraMetadataKey, KeyValueDataHolder>,
+        graphDataHolders: Map<CameraMetadataKey, GraphDataHolder>
+    ) {
+        val heightPixels = 30
+
+        keyValeDataHolders.forEach loop@{
+            if (graphDataHolders.containsKey(it.key)) return@loop
+            val dataHolder = it.value
+            val keyValueView =
+                KeyValueView(
+                    context,
+                    dataHolder,
+                    paints
+                )
+
+            val keyValueLayout = View.inflate(context, R.layout.key_value_layout, null)
+            keyValueLayout.key_name.text = "${it.key.name}    "
+
+            val keyValueViewParams = RelativeLayout.LayoutParams(
+                ViewGroup.LayoutParams
+                .MATCH_PARENT, heightPixels)
+            keyValueView.layoutParams = keyValueViewParams
+
+            keyValueLayout.key_value_layout.value_layout.addView(keyValueView)
+//            kotlinx.android.synthetic.main.activity_main. .addView(keyValueLayout)
+        }
+    }
+
+    /** Sets up the graph visualizations specifically */
+    private fun setUpGraphVisualizations(
+        keyValeDataHolders: Map<CameraMetadataKey, KeyValueDataHolder>,
+        graphDataHolders: Map<CameraMetadataKey, GraphDataHolder>
+    ) {
+        val heightPixels = 110
+
+        graphDataHolders.forEach {
+            val key = it.key
+            val dataHolder = it.value
+            val graphView = when (dataHolder) {
+                is GraphDataHolderValueImpl -> ValueGraphView(
+                    context,
+                    dataGenerator.beginTimeNanos,
+                    dataHolder,
+                    paints
+                )
+                is GraphDataHolderStateImpl -> StateGraphView(
+                    context,
+                    dataGenerator.beginTimeNanos,
+                    dataHolder,
+                    paints = paints
+                )
+                else -> throw Exception("Visualization is not supported for this graphDataHolder " +
+                        "implementation")
+            }
+
+            val graphLayout = View.inflate(context, R.layout.graph_layout, null)
+
+            val graphViewParams = RelativeLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                heightPixels
+            )
+            graphViewParams.addRule(RelativeLayout.BELOW, graphLayout.top_row_layout.id)
+            graphView.layoutParams = graphViewParams
+
+            graphLayout.graph_view_layout.addView(graphView)
+            graphLayout.graph_layout.setBackgroundResource(R.drawable.graph_background)
+
+            val graphLayoutParams = RelativeLayout.LayoutParams(
+                ViewGroup.LayoutParams
+                .WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+            graphLayoutParams.setMargins(0, 0, 0, 20)
+            graphLayout.layoutParams = graphLayoutParams
+
+            val keyValueDataHolder = keyValeDataHolders[key]
+            if (keyValueDataHolder != null) {
+                val keyValueView =
+                    KeyValueView(
+                        context,
+                        keyValueDataHolder,
+                        paints
+                    )
+                val keyValueLayout = View.inflate(context, R.layout.key_value_layout, null)
+                keyValueLayout.key_name.text = "${it.key.name} "
+
+                val keyValueViewParams = RelativeLayout.LayoutParams(
+                    ViewGroup.LayoutParams
+                    .MATCH_PARENT, 30)
+                keyValueView.layoutParams = keyValueViewParams
+
+                keyValueLayout.key_value_layout.value_layout.addView(keyValueView)
+                graphLayout.top_row_layout.addView(keyValueLayout)
+            }
+
+//            graphs.addView(graphLayout)
+        }
+    }
+}
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/SimpleCamera.kt b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/SimpleCamera.kt
index f404acb..d86f84e 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/SimpleCamera.kt
+++ b/camera/integration-tests/camerapipetestapp/src/main/java/androidx/camera/integration/camera2/pipe/SimpleCamera.kt
@@ -19,12 +19,15 @@
 import android.graphics.ImageFormat
 import android.hardware.camera2.CameraCharacteristics
 import android.hardware.camera2.CameraDevice
+import android.hardware.camera2.CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
 import android.media.ImageReader
 import android.os.Handler
 import android.util.Log
 import android.util.Size
 import android.view.Surface
 import androidx.camera.camera2.pipe.CameraGraph
+import androidx.camera.camera2.pipe.CameraId
+import androidx.camera.camera2.pipe.CameraMetadata
 import androidx.camera.camera2.pipe.CameraPipe
 import androidx.camera.camera2.pipe.Request
 import androidx.camera.camera2.pipe.RequestTemplate
@@ -33,33 +36,30 @@
 import androidx.camera.camera2.pipe.StreamType
 import kotlin.math.absoluteValue
 
+private const val defaultWidth = 1280
+private const val defaultHeight = 720
+private const val defaultAspectRatio = defaultWidth.toDouble() / defaultHeight.toDouble()
+
 class SimpleCamera(
+    private val cameraId: CameraId,
+    private val cameraMetadata: CameraMetadata,
     private val cameraGraph: CameraGraph,
     private val imageReader: ImageReader
 ) {
     companion object {
-        private val defaultResolution = Size(1280, 720)
-        private const val defaultAspectRatio = 4.0 / 3.0
-
         fun create(
             cameraPipe: CameraPipe,
+            cameraId: CameraId,
             viewfinder: Viewfinder,
             listeners: List<Request.Listener> = emptyList()
         ): SimpleCamera {
             // TODO: It may be worthwhile to turn this into a suspending function to avoid running
             //   camera-finding and metadata querying on the main thread.
 
-            // Find first back facing camera, or any camera id at all if the back facing camera is
-            // not available.
-            val cameraId = cameraPipe.cameras().findAll().firstOrNull() {
-                cameraPipe.cameras().awaitMetadata(it)[CameraCharacteristics.LENS_FACING] ==
-                        CameraCharacteristics.LENS_FACING_BACK
-            } ?: cameraPipe.cameras().findAll().first()
-
             Log.i("CXCP-App", "Selected $cameraId to open.")
 
-            val metadata = cameraPipe.cameras().awaitMetadata(cameraId)
-            val yuvSizes = metadata.streamMap.getOutputSizes(ImageFormat.YUV_420_888)
+            val cameraMetadata = cameraPipe.cameras().awaitMetadata(cameraId)
+            val yuvSizes = cameraMetadata.streamMap.getOutputSizes(ImageFormat.YUV_420_888)
             val yuv43Sizes = yuvSizes.filter {
                 (((it.width.toDouble() / it.height.toDouble()) - defaultAspectRatio).absoluteValue
                         < 0.001)
@@ -67,8 +67,8 @@
 
             // Find the size that is the least different
             val yuvSize = yuv43Sizes.minByOrNull {
-                ((it.width * it.height) - (defaultResolution.width *
-                        defaultResolution.height)).absoluteValue
+                ((it.width * it.height) - (defaultWidth *
+                        defaultHeight)).absoluteValue
             }!!
 
             Log.i("CXCP-App", "Selected $yuvSize as the YUV output size")
@@ -122,7 +122,7 @@
                 10
             )
             cameraGraph.setSurface(yuvStream.id, imageReader.surface)
-            return SimpleCamera(cameraGraph, imageReader)
+            return SimpleCamera(cameraId, cameraMetadata, cameraGraph, imageReader)
         }
     }
 
@@ -153,4 +153,37 @@
         cameraGraph.close()
         imageReader.close()
     }
+
+    fun cameraInfoString(): String {
+        val lensFacing = when (cameraMetadata[CameraCharacteristics.LENS_FACING]) {
+            CameraCharacteristics.LENS_FACING_FRONT -> "Front"
+            CameraCharacteristics.LENS_FACING_BACK -> "Back"
+            CameraCharacteristics.LENS_FACING_EXTERNAL -> "External"
+            else -> "Unknown"
+        }
+
+        val capabilities = cameraMetadata[CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES]
+        val cameraType = if (capabilities != null &&
+            capabilities.contains(REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA)
+        ) {
+            "Logical"
+        } else {
+            "Physical"
+        }
+
+        return StringBuilder().apply {
+            append("$cameraGraph (Camera ${cameraId.value})\n")
+            append("  Facing:    $lensFacing ($cameraType)\n")
+            append("Streams:")
+            for (stream in cameraGraph.streams) {
+                append("\n  ")
+                append(stream.value.id.toString().padEnd(12, ' '))
+                append(stream.value.size.toString().padEnd(12, ' '))
+                append(stream.value.format.name.padEnd(16, ' '))
+                append(stream.value.type.toString().padEnd(16, ' '))
+            }
+
+            // TODO: Add static configuration info.
+        }.toString()
+    }
 }
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable-v24/ic_launcher_foreground.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable-v24/ic_launcher_foreground.xml
deleted file mode 100644
index c162111..0000000
--- a/camera/integration-tests/camerapipetestapp/src/main/res/drawable-v24/ic_launcher_foreground.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<!-- Copyright (C) 2020 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:aapt="http://schemas.android.com/aapt"
-    android:width="108dp"
-    android:height="108dp"
-    android:viewportHeight="108"
-    android:viewportWidth="108">
-    <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
-        <aapt:attr name="android:fillColor">
-            <gradient
-                android:endX="85.84757"
-                android:endY="92.4963"
-                android:startX="42.9492"
-                android:startY="49.59793"
-                android:type="linear">
-                <item
-                    android:color="#44000000"
-                    android:offset="0.0" />
-                <item
-                    android:color="#00000000"
-                    android:offset="1.0" />
-            </gradient>
-        </aapt:attr>
-    </path>
-    <path
-        android:fillColor="#FFFFFF"
-        android:fillType="nonZero"
-        android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
-        android:strokeColor="#00000000"
-        android:strokeWidth="1" />
-</vector>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_baseline_flip_camera_android_24.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_baseline_flip_camera_android_24.xml
new file mode 100644
index 0000000..85e5bca
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_baseline_flip_camera_android_24.xml
@@ -0,0 +1,23 @@
+<!--
+  Copyright 2020 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.
+  -->
+
+<vector android:height="24dp" android:tint="#FFFFFF"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M9,12c0,1.66 1.34,3 3,3s3,-1.34 3,-3s-1.34,-3 -3,-3S9,10.34 9,12z"/>
+    <path android:fillColor="@android:color/white" android:pathData="M8,10V8H5.09C6.47,5.61 9.05,4 12,4c3.72,0 6.85,2.56 7.74,6h2.06c-0.93,-4.56 -4.96,-8 -9.8,-8C8.73,2 5.82,3.58 4,6.01V4H2v6H8z"/>
+    <path android:fillColor="@android:color/white" android:pathData="M16,14v2h2.91c-1.38,2.39 -3.96,4 -6.91,4c-3.72,0 -6.85,-2.56 -7.74,-6H2.2c0.93,4.56 4.96,8 9.8,8c3.27,0 6.18,-1.58 8,-4.01V20h2v-6H16z"/>
+</vector>
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_baseline_photo_camera_24.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_baseline_photo_camera_24.xml
new file mode 100644
index 0000000..c6f0df49
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_baseline_photo_camera_24.xml
@@ -0,0 +1,22 @@
+<!--
+  Copyright 2020 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.
+  -->
+
+<vector android:height="24dp" android:tint="#FFFFFF"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
+    <path android:fillColor="@android:color/white" android:pathData="M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
+</vector>
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_launcher_background.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_launcher_background.xml
index 47d3f33..ca3826a 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_launcher_background.xml
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_launcher_background.xml
@@ -1,184 +1,74 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="108dp"
+<vector
     android:height="108dp"
+    android:width="108dp"
     android:viewportHeight="108"
-    android:viewportWidth="108">
-    <path
-        android:fillColor="#3DDC84"
-        android:pathData="M0,0h108v108h-108z" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M9,0L9,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,0L19,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M29,0L29,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M39,0L39,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M49,0L49,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M59,0L59,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M69,0L69,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M79,0L79,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M89,0L89,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M99,0L99,108"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,9L108,9"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,19L108,19"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,29L108,29"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,39L108,39"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,49L108,49"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,59L108,59"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,69L108,69"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,79L108,79"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,89L108,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M0,99L108,99"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,29L89,29"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,39L89,39"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,49L89,49"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,59L89,59"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,69L89,69"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M19,79L89,79"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M29,19L29,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M39,19L39,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M49,19L49,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M59,19L59,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M69,19L69,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
-    <path
-        android:fillColor="#00000000"
-        android:pathData="M79,19L79,89"
-        android:strokeColor="#33FFFFFF"
-        android:strokeWidth="0.8" />
+    android:viewportWidth="108"
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#3DDC84"
+          android:pathData="M0,0h108v108h-108z"/>
+    <path android:fillColor="#00000000" android:pathData="M9,0L9,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,0L19,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M29,0L29,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M39,0L39,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M49,0L49,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M59,0L59,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M69,0L69,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M79,0L79,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M89,0L89,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M99,0L99,108"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,9L108,9"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,19L108,19"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,29L108,29"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,39L108,39"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,49L108,49"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,59L108,59"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,69L108,69"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,79L108,79"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,89L108,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M0,99L108,99"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,29L89,29"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,39L89,39"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,49L89,49"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,59L89,59"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,69L89,69"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M19,79L89,79"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M29,19L29,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M39,19L39,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M49,19L49,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M59,19L59,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M69,19L69,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+    <path android:fillColor="#00000000" android:pathData="M79,19L79,89"
+          android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
 </vector>
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_launcher_foreground.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..e773727
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+<!--
+  Copyright 2020 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108"
+    android:tint="#FFFFFF">
+  <group android:scaleX="1.9575"
+      android:scaleY="1.9575"
+      android:translateX="30.51"
+      android:translateY="30.51">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M9,2L7.17,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2L9,2zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z"/>
+  </group>
+</vector>
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_outline_info_24.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_outline_info_24.xml
new file mode 100644
index 0000000..0510f56
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/ic_outline_info_24.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright 2020 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.
+  -->
+
+<vector android:height="24dp" android:tint="#FFFFFF"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
+</vector>
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_info_panel.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_info_panel.xml
new file mode 100644
index 0000000..af0aa020
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_info_panel.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  Copyright 2020 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+    android:opacity="translucent">
+    <item xmlns:android="http://schemas.android.com/apk/res/android">
+        <shape
+            android:shape="rectangle">
+            <solid
+                android:width="3dp"
+                android:color="@color/cameraPipeThemeBgOverlayDark100"/>
+            <corners
+                android:bottomLeftRadius="12dp"
+                android:bottomRightRadius="12dp"
+                android:topLeftRadius="12dp"
+                android:topRightRadius="12dp"/>
+        </shape>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_launch_screen.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_launch_screen.xml
index cc087fe..902e878 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_launch_screen.xml
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_launch_screen.xml
@@ -1,4 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?><!--
+<?xml version="1.0" encoding="utf-8"?>
+<!--
   Copyright 2020 The Android Open Source Project
 
   Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button.xml
new file mode 100644
index 0000000..a23f88b
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2020 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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="true"
+        android:drawable="@drawable/theme_round_button_default" />
+    <item android:state_enabled="false"
+        android:drawable="@drawable/theme_round_button_disabled" />
+</selector>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_default.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_default.xml
new file mode 100644
index 0000000..d7dcfb7
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_default.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2020 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.
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="@color/cameraPipeThemeBtnOverlay200">
+    <item>
+        <shape
+            android:padding="8dp"
+            android:shape="rectangle">
+            <corners
+                android:bottomLeftRadius="25dp"
+                android:bottomRightRadius="25dp"
+                android:topLeftRadius="25dp"
+                android:topRightRadius="25dp" />
+            <padding
+                android:bottom="6dp"
+                android:left="20dp"
+                android:right="20dp"
+                android:top="6dp" />
+            <solid
+                android:width="3dp"
+                android:color="@color/cameraPipeThemeBtnOverlay100" />
+        </shape>
+    </item>
+</ripple>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_disabled.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_disabled.xml
new file mode 100644
index 0000000..56994f4
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_disabled.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2020 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:padding="8dp"
+    android:shape="rectangle"
+    android:color="@color/cameraPipeThemeBtnOverlay100">
+    <solid
+        android:width="3dp"
+        android:color="@color/cameraPipeThemeBtnOverlay100" />
+    <padding
+        android:bottom="6dp"
+        android:left="20dp"
+        android:right="20dp"
+        android:top="6dp" />
+    <corners
+        android:bottomLeftRadius="25dp"
+        android:bottomRightRadius="25dp"
+        android:topLeftRadius="25dp"
+        android:topRightRadius="25dp" />
+</shape>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_record.xml b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_record.xml
new file mode 100644
index 0000000..f7a80b1
--- /dev/null
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/drawable/theme_round_button_record.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2020 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.
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="@color/cameraPipeThemeBgRecord">
+    <item>
+        <shape
+            android:padding="8dp"
+            android:shape="rectangle">
+            <solid
+                android:width="3dp"
+                android:color="@color/cameraPipeThemeBgRecordRipple"/>
+            <padding
+                android:bottom="6dp"
+                android:left="20dp"
+                android:right="20dp"
+                android:top="6dp"/>
+            <corners
+                android:bottomLeftRadius="25dp"
+                android:bottomRightRadius="25dp"
+                android:topLeftRadius="25dp"
+                android:topRightRadius="25dp"/>
+        </shape>
+    </item>
+</ripple>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/layout/activity_main.xml b/camera/integration-tests/camerapipetestapp/src/main/res/layout/activity_main.xml
index 8767f7d..bcfe4ef 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/layout/activity_main.xml
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/layout/activity_main.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2020 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.
@@ -13,49 +12,153 @@
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/content"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:background="@color/cameraPipeThemeBgDark100"
-    android:keepScreenOn="true"
-    tools:context=".CameraPipeActivity">
-
-    <androidx.camera.integration.camera2.pipe.Viewfinder
-        android:id="@+id/viewfinder"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:background="#FFFFFF" />
+    android:keepScreenOn="true">
 
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:weightSum="2">
+        android:baselineAligned="false"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent">
 
         <LinearLayout
             android:id="@+id/key_values"
+            android:layout_width="0dp"
             android:layout_height="wrap_content"
-            android:orientation="vertical"
-            android:gravity="center"
+            android:layout_marginStart="20dp"
             android:layout_marginTop="20dp"
-            android:layout_marginLeft="20dp"
-            android:background="@drawable/graph_background"
             android:layout_weight="1"
-            android:layout_width="0dp" />
-
+            android:background="@drawable/graph_background"
+            android:gravity="center"
+            android:orientation="vertical" />
 
         <LinearLayout
             android:id="@+id/graphs"
             android:layout_width="0dp"
             android:layout_height="wrap_content"
-            android:orientation="vertical"
-            android:gravity="center"
-            android:layout_marginTop="20dp"
             android:layout_marginHorizontal="20dp"
-            android:layout_weight="1"/>
-
+            android:layout_marginTop="20dp"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:orientation="vertical" />
     </LinearLayout>
-</FrameLayout>
+
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:fitsSystemWindows="true"
+        app:layout_constraintBottom_toTopOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent">
+
+        <androidx.camera.integration.camera2.pipe.Viewfinder
+            android:id="@+id/viewfinder"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:background="#FFFFFF"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_bias="0.5"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <ImageButton
+            android:id="@+id/capture_button"
+            android:layout_width="150dp"
+            android:layout_height="48dp"
+            android:layout_marginBottom="16dp"
+            android:layout_marginEnd="8dp"
+            android:layout_marginStart="8dp"
+            android:layout_marginTop="16dp"
+            android:adjustViewBounds="false"
+            android:background="@drawable/theme_round_button"
+            android:src="@drawable/ic_baseline_photo_camera_24"
+            android:visibility="visible"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent" />
+
+        <ImageButton
+            android:id="@+id/switch_button"
+            android:layout_width="72dp"
+            android:layout_height="48dp"
+            android:layout_marginEnd="8dp"
+            android:background="@drawable/theme_round_button"
+            android:src="@drawable/ic_baseline_flip_camera_android_24"
+            app:layout_constraintEnd_toStartOf="@+id/capture_button"
+            app:layout_constraintTop_toTopOf="@+id/capture_button" />
+
+        <ImageButton
+            android:id="@+id/info_button"
+            android:layout_width="72dp"
+            android:layout_height="48dp"
+            android:layout_marginStart="8dp"
+            android:background="@drawable/theme_round_button"
+            android:src="@drawable/ic_outline_info_24"
+            app:layout_constraintStart_toEndOf="@+id/capture_button"
+            app:layout_constraintTop_toTopOf="@+id/capture_button" />
+
+        <ScrollView
+            android:id="@+id/info_view"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginBottom="8dp"
+            android:layout_marginEnd="8dp"
+            android:layout_marginStart="8dp"
+            android:layout_marginTop="8dp"
+            android:background="@drawable/theme_info_panel"
+            android:clipToPadding="true"
+            android:fillViewport="true"
+            android:scrollbarStyle="insideOverlay"
+            android:visibility="invisible"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent">
+
+            <LinearLayout
+                android:id="@+id/info_content"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical">
+
+                <TextView
+                    android:id="@+id/info_text"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginBottom="8dp"
+                    android:layout_marginEnd="8dp"
+                    android:layout_marginStart="8dp"
+                    android:layout_marginTop="8dp"
+                    android:textColor="@color/cameraPipeThemeFgLight800"
+                    android:textSize="10sp"
+                    android:typeface="monospace" />
+            </LinearLayout>
+        </ScrollView>
+
+        <TextView
+            android:id="@+id/viewfinder_text"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:background="@color/cameraPipeThemeFgOverlay"
+            android:fontFamily="sans-serif-condensed"
+            android:padding="8dp"
+            android:textColor="@color/cameraPipeThemeFgLight800"
+            android:typeface="monospace"
+            android:visibility="invisible"
+            app:layout_constraintEnd_toEndOf="@id/viewfinder"
+            app:layout_constraintStart_toStartOf="@id/viewfinder"
+            app:layout_constraintTop_toTopOf="@id/viewfinder" />
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</androidx.constraintlayout.widget.ConstraintLayout>
+
 
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index f763f8a..bbd3e02 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,19 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 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.
--->
 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
-    <background android:drawable="@drawable/ic_launcher_background" />
-    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+    <background android:drawable="@drawable/ic_launcher_background"/>
+    <foreground android:drawable="@drawable/ic_launcher_foreground"/>
 </adaptive-icon>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
index f763f8a..bbd3e02 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -1,19 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 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.
--->
 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
-    <background android:drawable="@drawable/ic_launcher_background" />
-    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+    <background android:drawable="@drawable/ic_launcher_background"/>
+    <foreground android:drawable="@drawable/ic_launcher_foreground"/>
 </adaptive-icon>
\ No newline at end of file
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher.png
index a571e60..349ab41 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher_round.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher_round.png
index 61da551..7614eb4 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher_round.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher.png
index c41dd28..a57c7a8 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher_round.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher_round.png
index db5080a..df0dbb0 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher_round.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher.png
index 6dba46d..ce806bd 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher_round.png
index da31a87..5a7d770 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher_round.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher.png
index 15ac681..cf7ce7d 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
index b216f2d..4cc2f02 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index f25a419..f37f717 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
index e96783c..e4175ef 100644
--- a/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
+++ b/camera/integration-tests/camerapipetestapp/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisBaseTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisBaseTest.kt
index 575b05f..580f20a 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisBaseTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisBaseTest.kt
@@ -17,14 +17,16 @@
 package androidx.camera.integration.uiwidgets.rotations
 
 import android.content.Intent
+import androidx.camera.core.CameraX
 import androidx.camera.testing.CameraUtil
 import androidx.camera.testing.CoreAppTestUtil
 import androidx.test.core.app.ActivityScenario
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.rule.GrantPermissionRule
 import androidx.test.uiautomator.UiDevice
 import androidx.testutils.withActivity
-import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Assume
 import org.junit.Rule
 import org.junit.rules.TestRule
@@ -43,7 +45,11 @@
 abstract class ImageAnalysisBaseTest<A : CameraActivity> {
 
     @get:Rule
-    val mUseCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val mUseCameraRule: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+
+    @get:Rule
+    val mCameraActivityRules: GrantPermissionRule =
+        GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
 
     protected val mDevice: UiDevice =
         UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@@ -58,6 +64,7 @@
     }
 
     protected fun tearDown() {
+        CameraX.shutdown().get()
         mDevice.unfreezeRotation()
     }
 
@@ -84,7 +91,12 @@
             val (sensorToTargetRotation, imageRotationDegrees) = scenario.withActivity {
                 Pair(getSensorRotationRelativeToAnalysisTargetRotation(), mAnalysisImageRotation)
             }
-            assertThat(sensorToTargetRotation).isEqualTo(imageRotationDegrees)
+            assertWithMessage(
+                "The image rotation degrees [$imageRotationDegrees] was expected to" +
+                        " be equal to [$sensorToTargetRotation]"
+            )
+                .that(imageRotationDegrees)
+                .isEqualTo(sensorToTargetRotation)
         }
     }
 
@@ -101,7 +113,9 @@
 
     protected inline fun <reified A : CameraActivity> ActivityScenario<A>.waitOnCameraFrames() {
         val analysisRunning = withActivity { mAnalysisRunning }
-        assertThat(analysisRunning.tryAcquire(IMAGES_COUNT, TIMEOUT, TimeUnit.SECONDS)).isTrue()
+        assertWithMessage("Timed out waiting on image analysis frames")
+            .that(analysisRunning.tryAcquire(IMAGES_COUNT, TIMEOUT, TimeUnit.SECONDS))
+            .isTrue()
     }
 
     protected inline fun <reified A : CameraActivity> ActivityScenario<A>.resetFramesCount() {
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisLockedOrientationTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisLockedOrientationTest.kt
index c81032c..4f4899a 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisLockedOrientationTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisLockedOrientationTest.kt
@@ -19,10 +19,8 @@
 import androidx.camera.core.CameraSelector
 import androidx.test.core.app.ActivityScenario
 import androidx.test.filters.LargeTest
-import androidx.test.rule.GrantPermissionRule
 import org.junit.After
 import org.junit.Before
-import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -49,10 +47,6 @@
         }
     }
 
-    @get:Rule
-    val mCameraPermissionRule: GrantPermissionRule =
-        GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
-
     @Before
     fun before() {
         setUp(lensFacing)
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisOrientationConfigChangesTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisOrientationConfigChangesTest.kt
index 97e96d6..085988b 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisOrientationConfigChangesTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisOrientationConfigChangesTest.kt
@@ -22,12 +22,10 @@
 import androidx.test.core.app.ActivityScenario
 import androidx.test.filters.LargeTest
 import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.GrantPermissionRule
 import androidx.testutils.withActivity
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
-import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -55,10 +53,6 @@
         }
     }
 
-    @get:Rule
-    val mCameraPermissionRule: GrantPermissionRule =
-        GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
-
     @Before
     fun before() {
         setUp(lensFacing)
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisUnlockedOrientationTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisUnlockedOrientationTest.kt
index 2883dda..82aa20f 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisUnlockedOrientationTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageAnalysisUnlockedOrientationTest.kt
@@ -21,10 +21,8 @@
 import androidx.camera.core.CameraSelector.LENS_FACING_FRONT
 import androidx.test.filters.LargeTest
 import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.GrantPermissionRule
 import org.junit.After
 import org.junit.Before
-import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -50,10 +48,6 @@
         }
     }
 
-    @get:Rule
-    val mCameraPermissionRule: GrantPermissionRule =
-        GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
-
     @Before
     fun before() {
         setUp(lensFacing)
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureBaseTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureBaseTest.kt
index 824109f..fb98edb 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureBaseTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureBaseTest.kt
@@ -21,15 +21,18 @@
 import android.os.Environment
 import android.view.View
 import androidx.camera.core.CameraSelector
+import androidx.camera.core.CameraX
 import androidx.camera.integration.uiwidgets.R
 import androidx.camera.testing.CameraUtil
 import androidx.camera.testing.CoreAppTestUtil
 import androidx.test.core.app.ActivityScenario
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.rule.GrantPermissionRule
 import androidx.test.uiautomator.UiDevice
 import androidx.testutils.withActivity
 import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Assume.assumeFalse
 import org.junit.Assume.assumeTrue
 import org.junit.Rule
@@ -51,7 +54,11 @@
 abstract class ImageCaptureBaseTest<A : CameraActivity> {
 
     @get:Rule
-    val mUseCamera: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+    val mUseCameraRule: TestRule = CameraUtil.grantCameraPermissionAndPreTest()
+
+    @get:Rule
+    val mCameraActivityRules: GrantPermissionRule =
+        GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
 
     protected val mDevice: UiDevice =
         UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@@ -76,6 +83,7 @@
     }
 
     protected fun tearDown() {
+        CameraX.shutdown().get()
         mDevice.unfreezeRotation()
     }
 
@@ -135,7 +143,13 @@
             }
             val areResolutionsEqual = expectedResolution == imageSize
 
-            assertThat(areRotationsEqual || areResolutionsEqual).isTrue()
+            assertWithMessage(
+                "The captured image rotation degrees [$imageRotationDegrees] was expected to be " +
+                        "equal to [$sensorToTargetRotation], or the captured image's resolution " +
+                        "[$imageSize] was expected to be equal to [$expectedResolution]"
+            )
+                .that(areRotationsEqual || areResolutionsEqual)
+                .isTrue()
 
             // Delete captured image
             scenario.withActivity { mCaptureResult?.delete() ?: Unit }
@@ -158,7 +172,9 @@
 
     protected inline fun <reified A : CameraActivity> ActivityScenario<A>.waitOnCameraFrames() {
         val analysisRunning = withActivity { mAnalysisRunning }
-        assertThat(analysisRunning.tryAcquire(IMAGES_COUNT, TIMEOUT, TimeUnit.SECONDS)).isTrue()
+        assertWithMessage("Timed out waiting on image analysis frames")
+            .that(analysisRunning.tryAcquire(IMAGES_COUNT, TIMEOUT, TimeUnit.SECONDS))
+            .isTrue()
     }
 
     protected inline fun <reified A : CameraActivity> ActivityScenario<A>.resetFramesCount() {
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureLockedOrientationTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureLockedOrientationTest.kt
index da68c27..696972a 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureLockedOrientationTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureLockedOrientationTest.kt
@@ -18,10 +18,8 @@
 
 import androidx.test.core.app.ActivityScenario
 import androidx.test.filters.LargeTest
-import androidx.test.rule.GrantPermissionRule
 import org.junit.After
 import org.junit.Before
-import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -49,10 +47,6 @@
         }
     }
 
-    @get:Rule
-    val mCameraPermissionRule: GrantPermissionRule =
-        GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
-
     @Before
     fun before() {
         setUp(lensFacing)
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureOrientationConfigChangesTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureOrientationConfigChangesTest.kt
index 3c3b3a3..abc055c 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureOrientationConfigChangesTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureOrientationConfigChangesTest.kt
@@ -21,12 +21,10 @@
 import androidx.test.core.app.ActivityScenario
 import androidx.test.filters.LargeTest
 import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.GrantPermissionRule
 import androidx.testutils.withActivity
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
-import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -61,10 +59,6 @@
         }
     }
 
-    @get:Rule
-    val mCameraPermissionRule: GrantPermissionRule =
-        GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
-
     @Before
     fun before() {
         setUp(lensFacing)
diff --git a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureUnlockedOrientationTest.kt b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureUnlockedOrientationTest.kt
index 95bcbf0..0248f11 100644
--- a/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureUnlockedOrientationTest.kt
+++ b/camera/integration-tests/uiwidgetstestapp/src/androidTest/java/androidx/camera/integration/uiwidgets/rotations/ImageCaptureUnlockedOrientationTest.kt
@@ -24,10 +24,8 @@
 import androidx.camera.integration.uiwidgets.rotations.CameraActivity.Companion.IMAGE_CAPTURE_MODE_OUTPUT_STREAM
 import androidx.test.filters.LargeTest
 import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.rule.GrantPermissionRule
 import org.junit.After
 import org.junit.Before
-import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -84,10 +82,6 @@
         }
     }
 
-    @get:Rule
-    val mCameraPermissionRule: GrantPermissionRule =
-        GrantPermissionRule.grant(*CameraActivity.PERMISSIONS)
-
     @Before
     fun before() {
         setUp(lensFacing)
diff --git a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
index 8b16ab1..114f84c 100644
--- a/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
+++ b/camera/integration-tests/viewtestapp/src/androidTest/java/androidx/camera/integration/view/CameraControllerFragmentTest.kt
@@ -16,9 +16,16 @@
 
 package androidx.camera.integration.view
 
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Matrix
+import android.graphics.PointF
 import android.net.Uri
+import android.os.Build
+import android.view.Surface
 import androidx.camera.core.ImageCapture
 import androidx.camera.core.ImageCaptureException
+import androidx.camera.core.impl.utils.Exif
 import androidx.camera.testing.CameraUtil
 import androidx.camera.view.PreviewView
 import androidx.fragment.app.testing.FragmentScenario
@@ -31,7 +38,10 @@
 import androidx.test.filters.LargeTest
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.rule.GrantPermissionRule
+import com.google.common.collect.ImmutableList
 import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Assume
 import org.junit.Rule
 import org.junit.Test
 import org.junit.rules.ExpectedException
@@ -49,6 +59,13 @@
 @RunWith(AndroidJUnit4::class)
 class CameraControllerFragmentTest {
 
+    companion object {
+        // The right shift needed to get color component from a Int color, in the order of R, G
+        // and B.
+        private val RGB_SHIFTS = ImmutableList.of(/*R*/16, /*G*/ 8, /*B*/0)
+        private const val COLOR_MASK = 0xFF
+    }
+
     @get:Rule
     val thrown: ExpectedException = ExpectedException.none()
 
@@ -64,6 +81,61 @@
     private val instrumentation = InstrumentationRegistry.getInstrumentation()
 
     @Test
+    fun capturedImage_sameAsPreviewSnapshot() {
+        // TODO(b/147448711) Add back in once cuttlefish has correct user cropping functionality.
+        Assume.assumeFalse(
+            "Cuttlefish does not correctly handle crops. Unable to test.",
+            Build.MODEL.contains("Cuttlefish")
+        )
+
+        // Arrange.
+        val fragment = createFragmentScenario().getFragment()
+        fragment.assertPreviewIsStreaming()
+        // Scaled down images to 10x10 bitmap to normalize and reduce computation.
+        val width = 10
+        val height = 10
+
+        // Act.
+        // Get the capture bitmap and the preview bitmap.
+        val captureTargetDegrees = rotationValueToRotationDegrees(fragment.accelerometerRotation)
+        val captureResult = fragment.assertCanTakePicture()
+        var captureBitmap = Bitmap.createScaledBitmap(captureResult.first, width, height, true)
+        val captureDegrees = captureResult.second
+
+        val previewTargetDegrees =
+            rotationValueToRotationDegrees(fragment.previewView.display.rotation)
+        var previewBitmap = fragment.previewView.bitmap!!
+        previewBitmap = Bitmap.createScaledBitmap(previewBitmap, width, height, true)
+
+        // Rotate capture bitmap to match preview orientation
+        val captureToPreviewDegrees = captureTargetDegrees - previewTargetDegrees + captureDegrees
+        val rotateCapture = Matrix()
+        rotateCapture.postRotate(
+            captureToPreviewDegrees.toFloat(),
+            width.toFloat() / 2,
+            height.toFloat() / 2
+        )
+        captureBitmap = Bitmap.createBitmap(captureBitmap, 0, 0, width, height, rotateCapture, true)
+
+        // Assert.
+        val captureMoment = getRgbMoments(captureBitmap)
+        val previewMoment = getRgbMoments(previewBitmap)
+        // For a 10x10 image, we allow an 1px error. The 2 bitmaps are different due to
+        // dynamic range processing, especially in a high contrast environment. The error
+        // tolerance is purposely high to avoid false positive.
+        val errorTolerance = 1F
+        for ((i, colorShift) in RGB_SHIFTS.withIndex()) {
+            val errorMsg = "Color $i Capture\n" +
+                    colorComponentToReadableString(captureBitmap, colorShift) + "Preview\n" +
+                    colorComponentToReadableString(previewBitmap, colorShift)
+            assertWithMessage(errorMsg).that(captureMoment[i].x).isWithin(errorTolerance)
+                .of(previewMoment[i].x)
+            assertWithMessage(errorMsg).that(captureMoment[i].y).isWithin(errorTolerance)
+                .of(previewMoment[i].y)
+        }
+    }
+
+    @Test
     fun fragmentLaunched_canTakePicture() {
         val fragment = createFragmentScenario().getFragment()
         fragment.assertPreviewIsStreaming()
@@ -132,11 +204,71 @@
     }
 
     /**
+     * Calculates the 1st order moment (center of mass) of the R, G and B of the bitmap.
+     */
+    private fun getRgbMoments(bitmap: Bitmap): Array<PointF> {
+        val rgbMoments = arrayOf(PointF(0F, 0F), PointF(0F, 0F), PointF(0F, 0F))
+        val totals = arrayOf(0F, 0F, 0F)
+        for ((i, colorShift) in RGB_SHIFTS.withIndex()) {
+            for (x in 0 until bitmap.width) {
+                for (y in 0 until bitmap.height) {
+                    val color = bitmap.getPixel(x, y)
+                    val colorComponent = color shr colorShift and COLOR_MASK
+                    rgbMoments[i].x += colorComponent * x
+                    rgbMoments[i].y += colorComponent * y
+                    totals[i] += colorComponent.toFloat()
+                }
+            }
+            rgbMoments[i].x /= totals[i]
+            rgbMoments[i].y /= totals[i]
+        }
+        return rgbMoments
+    }
+
+    /**
+     * Converts the R, G or B component of the bitmap to a readable string table with fixed
+     * column width.
+     *
+     * <p> Example:
+     * <pre>
+     * 255 255 200
+     * 200 10  100
+     * 0   1   10
+     * </pre>
+     *
+     * @param colorShift: color component in the format of right shift on Int color.
+     */
+    private fun colorComponentToReadableString(bitmap1: Bitmap, colorShift: Int):
+            String {
+        var result = ""
+        for (x in 0 until bitmap1.width) {
+            for (y in 0 until bitmap1.height) {
+                var color = (bitmap1.getPixel(x, y) shr colorShift and 0xFF).toString()
+                // 10x10 table Each column is a fixed size of 4.
+                color += " ".repeat((3 - color.length))
+                result += "$color "
+            }
+            result += "\n"
+        }
+        return result
+    }
+
+    private fun rotationValueToRotationDegrees(rotationValue: Int): Int {
+        return when (rotationValue) {
+            Surface.ROTATION_0 -> 0
+            Surface.ROTATION_90 -> 90
+            Surface.ROTATION_180 -> 180
+            Surface.ROTATION_270 -> 270
+            else -> throw IllegalStateException("Unexpected rotation value $rotationValue")
+        }
+    }
+
+    /**
      * Takes a picture and assert the URI exists.
      *
      * <p> Also cleans up the saved picture afterwards.
      */
-    private fun CameraControllerFragment.assertCanTakePicture() {
+    private fun CameraControllerFragment.assertCanTakePicture(): Pair<Bitmap, Int> {
         val imageCallbackSemaphore = Semaphore(0)
         var uri: Uri? = null
         instrumentation.runOnMainSync {
@@ -152,9 +284,19 @@
             })
         }
         assertThat(imageCallbackSemaphore.tryAcquire(TIMEOUT_SECONDS, TimeUnit.SECONDS)).isTrue()
-        assertThat(uri).isNotNull()
+
+        // Read bitmap and exif rotation to return.
+        val bitmap = this.activity!!.contentResolver.openInputStream(uri!!)!!.use {
+            BitmapFactory.decodeStream(it)
+        }
+        val rotationDegrees = this.activity!!.contentResolver.openInputStream(uri!!)!!.use {
+            val exif = Exif.createFromInputStream(it)
+            exif.rotation
+        }
+
         // Delete the saved picture. Assert 1 row was deleted.
         assertThat(this.activity!!.contentResolver.delete(uri!!, null, null)).isEqualTo(1)
+        return Pair(bitmap, rotationDegrees)
     }
 
     private fun createFragmentScenario(): FragmentScenario<CameraControllerFragment?> {
@@ -185,7 +327,7 @@
     private fun CameraControllerFragment.assertPreviewState(state: PreviewView.StreamState) {
         val previewStreaming = Semaphore(0)
         instrumentation.runOnMainSync {
-            this.observePreviewStreamState(Observer {
+            previewView.previewStreamState.observe(this, Observer {
                 if (it == state) {
                     previewStreaming.release()
                 }
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
index 668aedb..778612f9 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/CameraControllerFragment.java
@@ -46,10 +46,10 @@
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
 import androidx.camera.core.impl.utils.futures.FutureCallback;
 import androidx.camera.core.impl.utils.futures.Futures;
+import androidx.camera.view.AccelerometerRotationListener;
 import androidx.camera.view.LifecycleCameraController;
 import androidx.camera.view.PreviewView;
 import androidx.fragment.app.Fragment;
-import androidx.lifecycle.Observer;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
@@ -69,7 +69,8 @@
     @SuppressWarnings("WeakerAccess")
     LifecycleCameraController mCameraController;
 
-    private PreviewView mPreviewView;
+    @VisibleForTesting
+    PreviewView mPreviewView;
     private FrameLayout mContainer;
     private Button mFlashMode;
     private ToggleButton mCameraToggle;
@@ -79,6 +80,7 @@
     private ToggleButton mTapToFocusToggle;
     private TextView mZoomStateText;
     private TextView mTorchStateText;
+    private RotationListener mAccelerometerRotationListener;
 
     @Override
     public void onAttach(@NonNull Context context) {
@@ -92,7 +94,9 @@
             @Nullable ViewGroup container,
             @Nullable Bundle savedInstanceState) {
         mExecutorService = Executors.newSingleThreadExecutor();
-        mCameraController = new LifecycleCameraController(getContext());
+        mAccelerometerRotationListener = new RotationListener(requireContext());
+        mAccelerometerRotationListener.enable();
+        mCameraController = new LifecycleCameraController(requireContext());
         mCameraController.bindToLifecycle(getViewLifecycleOwner());
 
         View view = inflater.inflate(R.layout.camera_controller_view, container, false);
@@ -270,6 +274,7 @@
         if (mExecutorService != null) {
             mExecutorService.shutdown();
         }
+        mAccelerometerRotationListener.disable();
     }
 
     void logFailedFuture(ListenableFuture<Void> voidFuture) {
@@ -351,6 +356,27 @@
     // -----------------
 
     /**
+     * Listens to accelerometer rotation change and pass it to tests.
+     */
+    static class RotationListener extends AccelerometerRotationListener {
+
+        private int mRotation;
+
+        RotationListener(@NonNull Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onRotationChanged(int rotation) {
+            mRotation = rotation;
+        }
+
+        int getRotation() {
+            return mRotation;
+        }
+    }
+
+    /**
      * @hide
      */
     @RestrictTo(RestrictTo.Scope.TESTS)
@@ -362,9 +388,16 @@
      * @hide
      */
     @RestrictTo(RestrictTo.Scope.TESTS)
-    void observePreviewStreamState(Observer<PreviewView.StreamState> observer) {
-        mPreviewView.getPreviewStreamState().observe(CameraControllerFragment.this,
-                observer);
+    PreviewView getPreviewView() {
+        return mPreviewView;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.TESTS)
+    int getAccelerometerRotation() {
+        return mAccelerometerRotationListener.getRotation();
     }
 
     @VisibleForTesting
diff --git a/camera/integration-tests/viewtestapp/src/main/res/layout-land/camera_controller_view.xml b/camera/integration-tests/viewtestapp/src/main/res/layout-land/camera_controller_view.xml
new file mode 100644
index 0000000..1d646ac
--- /dev/null
+++ b/camera/integration-tests/viewtestapp/src/main/res/layout-land/camera_controller_view.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  Copyright 2020 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.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <FrameLayout
+        android:id="@+id/container"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1">
+        <androidx.camera.view.PreviewView
+            android:id="@+id/preview_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent" />
+    </FrameLayout>
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content">
+            <Button
+                android:id="@+id/remove_or_add"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/btn_remove_or_add" />
+            <Button
+                android:id="@+id/shrink"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/btn_shrink" />
+            <ToggleButton
+                android:id="@+id/camera_toggle"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textOff="@string/toggle_camera_front"
+                android:textOn="@string/toggle_camera_back" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content">
+            <ToggleButton
+                android:id="@+id/capture_enabled"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textOff="@string/toggle_capture_disabled"
+                android:textOn="@string/toggle_capture_enabled" />
+            <Button
+                android:id="@+id/flash_mode"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
+            <Button
+                android:id="@+id/capture"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/btn_capture" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content">
+            <ToggleButton
+                android:id="@+id/video_enabled"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textOff="@string/toggle_video_disabled"
+                android:textOn="@string/toggle_video_enabled" />
+            <Button
+                android:id="@+id/video_record"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/btn_video_record" />
+            <Button
+                android:id="@+id/video_stop_recording"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/btn_video_stop_recording"/>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="40dp"
+            android:gravity="center_vertical">
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/linear_zoom"/>
+            <SeekBar
+                android:id="@+id/linear_zoom_slider"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:max="100"/>
+        </LinearLayout>
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content">
+            <ToggleButton
+                android:id="@+id/pinch_to_zoom_toggle"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textOff="@string/pinch_to_zoom"
+                android:textOn="@string/pinch_to_zoom"/>
+            <ToggleButton
+                android:id="@+id/tap_to_focus_toggle"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textOff="@string/tap_to_focus"
+                android:textOn="@string/tap_to_focus"/>
+            <ToggleButton
+                android:id="@+id/torch_toggle"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textOff="@string/torch"
+                android:textOn="@string/torch"/>
+        </LinearLayout>
+        <TextView
+            android:id="@+id/zoom_state_text"
+            android:layout_width="300dp"
+            android:layout_height="wrap_content"
+            android:lines="2"/>
+        <TextView
+            android:id="@+id/torch_state_text"
+            android:layout_width="300dp"
+            android:layout_height="wrap_content"/>
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/compose/androidview/androidview/build.gradle b/compose/androidview/androidview/build.gradle
index 5eb8028..db6fb8f 100644
--- a/compose/androidview/androidview/build.gradle
+++ b/compose/androidview/androidview/build.gradle
@@ -27,7 +27,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     // TODO: remove / refactor out reflection dependencies, this is a large dependency to bundle
     // with a library.
diff --git a/compose/androidview/androidview/integration-tests/androidview-demos/build.gradle b/compose/androidview/androidview/integration-tests/androidview-demos/build.gradle
index 4348e4d..6523313 100644
--- a/compose/androidview/androidview/integration-tests/androidview-demos/build.gradle
+++ b/compose/androidview/androidview/integration-tests/androidview-demos/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/animation/animation-core/build.gradle b/compose/animation/animation-core/build.gradle
index 83e859d..a6edcb2 100644
--- a/compose/animation/animation-core/build.gradle
+++ b/compose/animation/animation-core/build.gradle
@@ -29,7 +29,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 }
 
 kotlin {
diff --git a/compose/animation/animation-core/samples/build.gradle b/compose/animation/animation-core/samples/build.gradle
index 0217f4e..49c9294 100644
--- a/compose/animation/animation-core/samples/build.gradle
+++ b/compose/animation/animation-core/samples/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/animation/animation/build.gradle b/compose/animation/animation/build.gradle
index bcea23f..580b930 100644
--- a/compose/animation/animation/build.gradle
+++ b/compose/animation/animation/build.gradle
@@ -29,7 +29,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 }
 
 kotlin {
diff --git a/compose/animation/animation/integration-tests/animation-demos/build.gradle b/compose/animation/animation/integration-tests/animation-demos/build.gradle
index 2b167ff..5892c7e 100644
--- a/compose/animation/animation/integration-tests/animation-demos/build.gradle
+++ b/compose/animation/animation/integration-tests/animation-demos/build.gradle
@@ -10,7 +10,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt
index 2e16ef8..b71c71b 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimateContentSizeDemo.kt
@@ -65,14 +65,16 @@
     val shortText = "Click me"
     val longText = "Very long text\nthat spans across\nmultiple lines"
     var short by remember { mutableStateOf(true) }
-    Box(modifier = Modifier
-        .background(Color.Blue,
-            RoundedCornerShape(15.dp)
-        )
-        .clickable { short = !short }
-        .padding(20.dp)
-        .wrapContentSize()
-        .animateContentSize { startSize, endSize -> println("$startSize -> $endSize") }
+    Box(
+        modifier = Modifier
+            .background(
+                Color.Blue,
+                RoundedCornerShape(15.dp)
+            )
+            .clickable { short = !short }
+            .padding(20.dp)
+            .wrapContentSize()
+            .animateContentSize { startSize, endSize -> println("$startSize -> $endSize") }
     ) {
         Text(
             if (short) {
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt
index 7b46d6f..5a3254f 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt
@@ -72,10 +72,12 @@
     Stack(
         Modifier.padding(bottom = 20.dp)
     ) {
-        Button(modifier = Modifier.align(Alignment.TopEnd).padding(10.dp),
+        Button(
+            modifier = Modifier.align(Alignment.TopEnd).padding(10.dp),
             onClick = {
                 counter = (counter + 1) % 12
-            }) {
+            }
+        ) {
             Text("Click Me")
         }
 
@@ -89,7 +91,7 @@
                 Item(
                     pastelColors[0],
                     "Expand Vertically + Fade In\nShrink " +
-                            "Vertically + Fade Out\n(Column Default)"
+                        "Vertically + Fade Out\n(Column Default)"
                 )
             }
             HorizontalTransition(visible = itemNum > 1) {
@@ -97,8 +99,9 @@
             }
             SlideTransition(visible = itemNum > 2) {
                 Item(
-                    pastelColors[2], "Slide In Horizontally + Fade In\nSlide Out Horizontally + " +
-                            "Fade Out"
+                    pastelColors[2],
+                    "Slide In Horizontally + Fade In\nSlide Out Horizontally + " +
+                        "Fade Out"
                 )
             }
             AnimatedVisibility(
@@ -113,8 +116,9 @@
             }
             FullyLoadedTransition(visible = itemNum > 5) {
                 Item(
-                    pastelColors[0], "Expand Vertically + Fade In + Slide In Vertically\n" +
-                            "Shrink Vertically + Fade Out + Slide Out Vertically"
+                    pastelColors[0],
+                    "Expand Vertically + Fade In + Slide In Vertically\n" +
+                        "Shrink Vertically + Fade Out + Slide Out Vertically"
                 )
             }
         }
@@ -210,7 +214,8 @@
 @OptIn(ExperimentalAnimationApi::class)
 @Composable
 fun FullyLoadedTransition(visible: Boolean, children: @Composable () -> Unit) {
-    AnimatedVisibility(visible = visible,
+    AnimatedVisibility(
+        visible = visible,
         enter = slideInVertically(
             // Start the slide from 40 (pixels) above where the content is supposed to go, to
             // produce a parallax effect
@@ -218,7 +223,8 @@
         ) + expandVertically(
             expandFrom = Alignment.Top
         ) + fadeIn(initialAlpha = 0.3f),
-        exit = slideOutVertically() + shrinkVertically() + fadeOut()) {
+        exit = slideOutVertically() + shrinkVertically() + fadeOut()
+    ) {
         children()
     }
 }
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt
index 84e84fc..6b825a9 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisiblilityLazyColumnDemo.kt
@@ -72,9 +72,10 @@
             }
         }
 
-        Button({
-            itemNum = 0
-        }, modifier = Modifier.align(End).padding(15.dp)) {
+        Button(
+            { itemNum = 0 },
+            modifier = Modifier.align(End).padding(15.dp)
+        ) {
             Text("Clear All")
         }
     }
@@ -87,4 +88,4 @@
     Color(0xffBCF8FF),
     Color(0xff8AEAE9),
     Color(0xff46CECA)
-)
\ No newline at end of file
+)
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
index 77e570c..8d93ddd 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
@@ -19,20 +19,27 @@
 import androidx.compose.integration.demos.common.ComposableDemo
 import androidx.compose.integration.demos.common.DemoCategory
 
-val AnimationDemos = DemoCategory("Animation", listOf(
-    ComposableDemo("Animate multi-dimensional prop") { MultiDimensionalAnimationDemo() },
-    ComposableDemo("Animate") { SingleValueAnimationDemo() },
-    ComposableDemo("Animated scrolling") { FancyScrollingDemo() },
-    ComposableDemo("Animate Content Size") { AnimateContentSizeDemo() },
-    ComposableDemo("Animate Visibility Demo") { AnimatedVisibilityDemo() },
-    ComposableDemo("Animate Visibility Lazy Column Demo") { AnimatedVisibilityLazyColumnDemo() },
-    ComposableDemo("Cross Fade") { CrossfadeDemo() },
-    ComposableDemo("Enter/Exit Transition Demo") { EnterExitTransitionDemo() },
-    ComposableDemo("Gesture based animation") { GestureBasedAnimationDemo() },
-    ComposableDemo("Manual animation clock") { AnimatableSeekBarDemo() },
-    ComposableDemo("Repeating rotation") { RepeatedRotationDemo() },
-    ComposableDemo("Spring back scrolling") { SpringBackScrollingDemo() },
-    ComposableDemo("State animation with interruptions") { StateAnimationWithInterruptionsDemo() },
-    ComposableDemo("State based ripple") { StateBasedRippleDemo() },
-    ComposableDemo("Swipe to dismiss") { SwipeToDismissDemo() }
-))
+val AnimationDemos = DemoCategory(
+    "Animation",
+    listOf(
+        ComposableDemo("Animate multi-dimensional prop") { MultiDimensionalAnimationDemo() },
+        ComposableDemo("Animate") { SingleValueAnimationDemo() },
+        ComposableDemo("Animated scrolling") { FancyScrollingDemo() },
+        ComposableDemo("Animate Content Size") { AnimateContentSizeDemo() },
+        ComposableDemo("Animate Visibility Demo") { AnimatedVisibilityDemo() },
+        ComposableDemo("Animate Visibility Lazy Column Demo") {
+            AnimatedVisibilityLazyColumnDemo()
+        },
+        ComposableDemo("Cross Fade") { CrossfadeDemo() },
+        ComposableDemo("Enter/Exit Transition Demo") { EnterExitTransitionDemo() },
+        ComposableDemo("Gesture based animation") { GestureBasedAnimationDemo() },
+        ComposableDemo("Manual animation clock") { AnimatableSeekBarDemo() },
+        ComposableDemo("Repeating rotation") { RepeatedRotationDemo() },
+        ComposableDemo("Spring back scrolling") { SpringBackScrollingDemo() },
+        ComposableDemo("State animation with interruptions") {
+            StateAnimationWithInterruptionsDemo()
+        },
+        ComposableDemo("State based ripple") { StateBasedRippleDemo() },
+        ComposableDemo("Swipe to dismiss") { SwipeToDismissDemo() }
+    )
+)
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/CrossfadeDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/CrossfadeDemo.kt
index fd214c8..dc6b702 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/CrossfadeDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/CrossfadeDemo.kt
@@ -41,10 +41,12 @@
         Row {
             tabs.forEach { tab ->
                 Box(
-                    Modifier.tapGestureFilter(onTap = {
-                        Log.e("Crossfade", "Switch to $tab")
-                        current = tab
-                    })
+                    Modifier.tapGestureFilter(
+                        onTap = {
+                            Log.e("Crossfade", "Switch to $tab")
+                            current = tab
+                        }
+                    )
                         .weight(1f, true)
                         .preferredHeight(48.dp),
                     backgroundColor = tab.color
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitTransitionDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitTransitionDemo.kt
index 1a62aa5..b9bbd03 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitTransitionDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/EnterExitTransitionDemo.kt
@@ -76,59 +76,83 @@
         var visible by remember { mutableStateOf(true) }
         val (selectedOption, onOptionSelected) = remember { mutableStateOf(0) }
         Column(Modifier.fillMaxSize()) {
-            Button(modifier = Modifier.align(CenterHorizontally), onClick = {
-                alignment = TopCenter
-                visible = !visible
-            }) {
+            Button(
+                modifier = Modifier.align(CenterHorizontally),
+                onClick = {
+                    alignment = TopCenter
+                    visible = !visible
+                }
+            ) {
                 Text("Top")
             }
             Row(Modifier.fillMaxWidth().weight(1f)) {
                 Stack(Modifier.fillMaxHeight().wrapContentWidth()) {
-                    Button(modifier = Modifier.align(TopEnd), onClick = {
-                        alignment = TopStart
-                        visible = !visible
-                    }) {
+                    Button(
+                        modifier = Modifier.align(TopEnd),
+                        onClick = {
+                            alignment = TopStart
+                            visible = !visible
+                        }
+                    ) {
                         Text("Top\nStart")
                     }
-                    Button(modifier = Modifier.align(CenterEnd), onClick = {
-                        alignment = CenterStart
-                        visible = !visible
-                    }) {
+                    Button(
+                        modifier = Modifier.align(CenterEnd),
+                        onClick = {
+                            alignment = CenterStart
+                            visible = !visible
+                        }
+                    ) {
                         Text("Start")
                     }
-                    Button(modifier = Modifier.align(BottomEnd), onClick = {
-                        alignment = BottomStart
-                        visible = !visible
-                    }) {
+                    Button(
+                        modifier = Modifier.align(BottomEnd),
+                        onClick = {
+                            alignment = BottomStart
+                            visible = !visible
+                        }
+                    ) {
                         Text("Bottom\nStart")
                     }
                 }
                 CenterMenu(selectedOption, oppositeAlignment.value, alignment, visible)
                 Stack(Modifier.fillMaxHeight().wrapContentWidth()) {
-                    Button(modifier = Modifier.align(TopStart), onClick = {
-                        alignment = TopEnd
-                        visible = !visible
-                    }) {
+                    Button(
+                        modifier = Modifier.align(TopStart),
+                        onClick = {
+                            alignment = TopEnd
+                            visible = !visible
+                        }
+                    ) {
                         Text("Top\nEnd")
                     }
-                    Button(modifier = Modifier.align(CenterStart), onClick = {
-                        alignment = CenterEnd
-                        visible = !visible
-                    }) {
+                    Button(
+                        modifier = Modifier.align(CenterStart),
+                        onClick = {
+                            alignment = CenterEnd
+                            visible = !visible
+                        }
+                    ) {
                         Text("End")
                     }
-                    Button(modifier = Modifier.align(BottomEnd), onClick = {
-                        alignment = BottomEnd
-                        visible = !visible
-                    }) {
+                    Button(
+                        modifier = Modifier.align(BottomEnd),
+                        onClick = {
+                            alignment = BottomEnd
+                            visible = !visible
+                        }
+                    ) {
                         Text("Bottom\nEnd")
                     }
                 }
             }
-            Button(modifier = Modifier.align(CenterHorizontally), onClick = {
-                alignment = BottomCenter
-                visible = !visible
-            }) {
+            Button(
+                modifier = Modifier.align(CenterHorizontally),
+                onClick = {
+                    alignment = BottomCenter
+                    visible = !visible
+                }
+            ) {
                 Text("Bottom")
             }
 
@@ -220,14 +244,15 @@
         val radioOptions =
             listOf("No Fade", "Fade In", "Fade Out", "Fade In & Fade out")
         radioOptions.forEachIndexed { i, text ->
-            Row(Modifier
-                .fillMaxWidth()
-                .preferredHeight(30.dp)
-                .selectable(
-                    selected = (i == selectedOption),
-                    onClick = { onOptionSelected(i) }
-                )
-                .padding(horizontal = 16.dp),
+            Row(
+                Modifier
+                    .fillMaxWidth()
+                    .preferredHeight(30.dp)
+                    .selectable(
+                        selected = (i == selectedOption),
+                        onClick = { onOptionSelected(i) }
+                    )
+                    .padding(horizontal = 16.dp),
                 verticalAlignment = Alignment.CenterVertically
             ) {
                 RadioButton(
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/FancyScrollingDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/FancyScrollingDemo.kt
index e15fd885..fae08f1 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/FancyScrollingDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/FancyScrollingDemo.kt
@@ -53,29 +53,36 @@
         )
         val animScroll = animatedFloat(0f)
         val itemWidth = remember { mutableStateOf(0f) }
-        val gesture = Modifier.rawDragGestureFilter(dragObserver = object : DragObserver {
-            override fun onDrag(dragDistance: Offset): Offset {
-                // Snap to new drag position
-                animScroll.snapTo(animScroll.value + dragDistance.x)
-                return dragDistance
-            }
+        val gesture = Modifier.rawDragGestureFilter(
+            dragObserver = object : DragObserver {
+                override fun onDrag(dragDistance: Offset): Offset {
+                    // Snap to new drag position
+                    animScroll.snapTo(animScroll.value + dragDistance.x)
+                    return dragDistance
+                }
 
-            override fun onStop(velocity: Offset) {
+                override fun onStop(velocity: Offset) {
 
-                // Uses default decay animation to calculate where the fling will settle,
-                // and adjust that position as needed. The target animation will be used for
-                // animating to the adjusted target.
-                animScroll.fling(velocity.x, adjustTarget = { target ->
-                    // Adjust the target position to center align the item
-                    var rem = target % itemWidth.value
-                    if (rem < 0) {
-                        rem += itemWidth.value
-                    }
-                    TargetAnimation((target - rem),
-                        SpringSpec(dampingRatio = 2.0f, stiffness = 100f))
-                })
+                    // Uses default decay animation to calculate where the fling will settle,
+                    // and adjust that position as needed. The target animation will be used for
+                    // animating to the adjusted target.
+                    animScroll.fling(
+                        velocity.x,
+                        adjustTarget = { target ->
+                            // Adjust the target position to center align the item
+                            var rem = target % itemWidth.value
+                            if (rem < 0) {
+                                rem += itemWidth.value
+                            }
+                            TargetAnimation(
+                                (target - rem),
+                                SpringSpec(dampingRatio = 2.0f, stiffness = 100f)
+                            )
+                        }
+                    )
+                }
             }
-        })
+        )
 
         Canvas(gesture.fillMaxWidth().preferredHeight(400.dp)) {
             val width = size.width / 2f
@@ -83,8 +90,9 @@
             itemWidth.value = width
             if (DEBUG) {
                 Log.w(
-                    "Anim", "Drawing items with updated" +
-                            " AnimatedFloat: ${animScroll.value}"
+                    "Anim",
+                    "Drawing items with updated" +
+                        " AnimatedFloat: ${animScroll.value}"
                 )
             }
             drawItems(scroll, width, size.height)
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/GestureBasedAnimationDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/GestureBasedAnimationDemo.kt
index 0d63697..734e749 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/GestureBasedAnimationDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/GestureBasedAnimationDemo.kt
@@ -65,7 +65,8 @@
         Modifier.pressIndicatorGestureFilter(
             onStart = { toState.value = ComponentState.Pressed },
             onStop = { toState.value = ComponentState.Released },
-            onCancel = { toState.value = ComponentState.Released })
+            onCancel = { toState.value = ComponentState.Released }
+        )
 
     val state = transition(definition = definition, toState = toState.value)
     ScaledColorRect(pressIndicator, scale = state[scale], color = state[color])
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SpringBackScrollingDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SpringBackScrollingDemo.kt
index 9a28732..acc2ae5 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SpringBackScrollingDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SpringBackScrollingDemo.kt
@@ -52,19 +52,24 @@
         val animScroll = animatedFloat(0f)
         val itemWidth = remember { mutableStateOf(0f) }
         val isFlinging = remember { mutableStateOf(false) }
-        val gesture = Modifier.rawDragGestureFilter(dragObserver = object : DragObserver {
-            override fun onDrag(dragDistance: Offset): Offset {
-                animScroll.snapTo(animScroll.targetValue + dragDistance.x)
-                return dragDistance
-            }
+        val gesture = Modifier.rawDragGestureFilter(
+            dragObserver = object : DragObserver {
+                override fun onDrag(dragDistance: Offset): Offset {
+                    animScroll.snapTo(animScroll.targetValue + dragDistance.x)
+                    return dragDistance
+                }
 
-            override fun onStop(velocity: Offset) {
-                isFlinging.value = true
-                animScroll.fling(velocity.x, onEnd = { _, _, _ ->
-                    isFlinging.value = false
-                })
+                override fun onStop(velocity: Offset) {
+                    isFlinging.value = true
+                    animScroll.fling(
+                        velocity.x,
+                        onEnd = { _, _, _ ->
+                            isFlinging.value = false
+                        }
+                    )
+                }
             }
-        })
+        )
         Canvas(gesture.fillMaxWidth().preferredHeight(400.dp)) {
             itemWidth.value = size.width / 2f
             if (isFlinging.value) {
@@ -94,8 +99,9 @@
             }
             if (DEBUG) {
                 Log.w(
-                    "Anim", "Spring back scrolling, redrawing with new" +
-                            " scroll value: ${animScroll.value}"
+                    "Anim",
+                    "Spring back scrolling, redrawing with new" +
+                        " scroll value: ${animScroll.value}"
                 )
             }
             drawRects(animScroll.value)
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateAnimationWithInterruptionsDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateAnimationWithInterruptionsDemo.kt
index d1af27e..cd03e18 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateAnimationWithInterruptionsDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateAnimationWithInterruptionsDemo.kt
@@ -79,15 +79,18 @@
 @Composable
 private fun ColorRect() {
     var toState by mutableStateOf(OverlayState.Closed)
-    handler.postDelayed(object : Runnable {
-        override fun run() {
-            if ((0..1).random() == 0) {
-                toState = OverlayState.Open
-            } else {
-                toState = OverlayState.Closed
+    handler.postDelayed(
+        object : Runnable {
+            override fun run() {
+                if ((0..1).random() == 0) {
+                    toState = OverlayState.Open
+                } else {
+                    toState = OverlayState.Closed
+                }
             }
-        }
-    }, (200..800).random().toLong())
+        },
+        (200..800).random().toLong()
+    )
     val state = transition(definition = definition, toState = toState)
     ColorRectState(state = state)
 }
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateBasedRippleDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateBasedRippleDemo.kt
index 3b0531e..5158e54 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateBasedRippleDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/StateBasedRippleDemo.kt
@@ -61,7 +61,8 @@
     }
     val state = transition(definition = rippleTransDef, toState = toState.value)
     RippleRectFromState(
-        Modifier.pressIndicatorGestureFilter(onStart = onPress, onStop = onRelease), state = state)
+        Modifier.pressIndicatorGestureFilter(onStart = onPress, onStop = onRelease), state = state
+    )
 }
 
 @Composable
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SwipeToDismissDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SwipeToDismissDemo.kt
index c98ae3a..8d7e2e7 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SwipeToDismissDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/SwipeToDismissDemo.kt
@@ -67,59 +67,63 @@
     val index = remember { mutableStateOf(0) }
     val itemWidth = remember { mutableStateOf(0f) }
     val isFlinging = remember { mutableStateOf(false) }
-    val modifier = Modifier.rawDragGestureFilter(dragObserver = object : DragObserver {
-        override fun onStart(downPosition: Offset) {
-            itemBottom.setBounds(0f, height)
-            if (isFlinging.value && itemBottom.targetValue < 100f) {
-                reset()
+    val modifier = Modifier.rawDragGestureFilter(
+        dragObserver = object : DragObserver {
+            override fun onStart(downPosition: Offset) {
+                itemBottom.setBounds(0f, height)
+                if (isFlinging.value && itemBottom.targetValue < 100f) {
+                    reset()
+                }
             }
-        }
 
-        private fun reset() {
-            itemBottom.snapTo(height)
-            index.value--
-            if (index.value < 0) {
-                index.value += pastelColors.size
+            private fun reset() {
+                itemBottom.snapTo(height)
+                index.value--
+                if (index.value < 0) {
+                    index.value += pastelColors.size
+                }
             }
-        }
 
-        override fun onDrag(dragDistance: Offset): Offset {
-            itemBottom.snapTo(itemBottom.targetValue + dragDistance.y)
-            return dragDistance
-        }
+            override fun onDrag(dragDistance: Offset): Offset {
+                itemBottom.snapTo(itemBottom.targetValue + dragDistance.y)
+                return dragDistance
+            }
 
-        fun adjustTarget(velocity: Float): (Float) -> TargetAnimation? {
-            return { target: Float ->
-                // The velocity is fast enough to fly off screen
-                if (target <= 0) {
-                    null
-                } else {
-                    val animation = SpringSpec<Float>(
-                        dampingRatio = 0.8f, stiffness = 300f
-                    )
-                    val projectedTarget = target + sign(velocity) * 0.2f * height
-                    if (projectedTarget < 0.6 * height) {
-                        TargetAnimation(0f, animation)
+            fun adjustTarget(velocity: Float): (Float) -> TargetAnimation? {
+                return { target: Float ->
+                    // The velocity is fast enough to fly off screen
+                    if (target <= 0) {
+                        null
                     } else {
-                        TargetAnimation(height, animation)
+                        val animation = SpringSpec<Float>(
+                            dampingRatio = 0.8f, stiffness = 300f
+                        )
+                        val projectedTarget = target + sign(velocity) * 0.2f * height
+                        if (projectedTarget < 0.6 * height) {
+                            TargetAnimation(0f, animation)
+                        } else {
+                            TargetAnimation(height, animation)
+                        }
                     }
                 }
             }
-        }
 
-        override fun onStop(velocity: Offset) {
-            isFlinging.value = true
-            itemBottom.fling(velocity.y,
-                ExponentialDecay(3.0f),
-                adjustTarget(velocity.y),
-                onEnd = { endReason, final, _ ->
-                    isFlinging.value = false
-                    if (endReason != AnimationEndReason.Interrupted && final == 0f) {
-                        reset()
+            override fun onStop(velocity: Offset) {
+                isFlinging.value = true
+                itemBottom.fling(
+                    velocity.y,
+                    ExponentialDecay(3.0f),
+                    adjustTarget(velocity.y),
+                    onEnd = { endReason, final, _ ->
+                        isFlinging.value = false
+                        if (endReason != AnimationEndReason.Interrupted && final == 0f) {
+                            reset()
+                        }
                     }
-                })
+                )
+            }
         }
-    })
+    )
 
     val heightDp = with(DensityAmbient.current) { height.toDp() }
 
diff --git a/compose/animation/animation/samples/build.gradle b/compose/animation/animation/samples/build.gradle
index d9238e5..ba7416f 100644
--- a/compose/animation/animation/samples/build.gradle
+++ b/compose/animation/animation/samples/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedValueSamples.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedValueSamples.kt
index 208d1fc..20862c0 100644
--- a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedValueSamples.kt
+++ b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedValueSamples.kt
@@ -70,10 +70,13 @@
                 MySize(100.dp, 100.dp)
             }
         }
-        val animSize = animate<MySize, AnimationVector2D>(mySize, TwoWayConverter(
-            convertToVector = { AnimationVector2D(it.width.value, it.height.value) },
-            convertFromVector = { MySize(it.v1.dp, it.v2.dp) }
-        ))
+        val animSize = animate<MySize, AnimationVector2D>(
+            mySize,
+            TwoWayConverter(
+                convertToVector = { AnimationVector2D(it.width.value, it.height.value) },
+                convertFromVector = { MySize(it.v1.dp, it.v2.dp) }
+            )
+        )
         Box(Modifier.preferredSize(animSize.width, animSize.height).background(color = Color.Red))
     }
 }
diff --git a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt
index a4027e7..46c7c31 100644
--- a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt
+++ b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimatedVisibilitySamples.kt
@@ -145,7 +145,8 @@
 @Composable
 fun FullyLoadedTransition() {
     var visible by remember { mutableStateOf(true) }
-    AnimatedVisibility(visible = visible,
+    AnimatedVisibility(
+        visible = visible,
         enter = slideInVertically(
             // Start the slide from 40 (pixels) above where the content is supposed to go, to
             // produce a parallax effect
@@ -153,7 +154,8 @@
         ) + expandVertically(
             expandFrom = Alignment.Top
         ) + fadeIn(initialAlpha = 0.3f),
-        exit = slideOutVertically() + shrinkVertically() + fadeOut()) {
+        exit = slideOutVertically() + shrinkVertically() + fadeOut()
+    ) {
         // Content that needs to appear/disappear goes here:
         Text("Content to appear/disappear", Modifier.fillMaxWidth().height(200.dp))
     }
@@ -214,7 +216,8 @@
 fun ExpandShrinkVerticallySample() {
     var visible by remember { mutableStateOf(true) }
 
-    AnimatedVisibility(visible,
+    AnimatedVisibility(
+        visible,
         // Sets the initial height of the content to 20, revealing only the top of the content at
         // the beginning of the expanding animation.
         enter = expandVertically(
@@ -270,9 +273,11 @@
 fun ColumnAnimatedVisibilitySample() {
     var itemIndex by remember { mutableStateOf(0) }
     val colors = listOf(Color.Red, Color.Green, Color.Blue)
-    Column(Modifier.fillMaxWidth().clickable {
-        itemIndex = (itemIndex + 1) % colors.size
-    }) {
+    Column(
+        Modifier.fillMaxWidth().clickable {
+            itemIndex = (itemIndex + 1) % colors.size
+        }
+    ) {
         colors.forEachIndexed { i, color ->
             // By default ColumnScope.AnimatedVisibility expands and shrinks new content while
             // fading.
diff --git a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimationModifierSample.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimationModifierSample.kt
index 17c1672..87b80fc 100644
--- a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimationModifierSample.kt
+++ b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/AnimationModifierSample.kt
@@ -41,14 +41,16 @@
     val shortText = "Hi"
     val longText = "Very long text\nthat spans across\nmultiple lines"
     var short by remember { mutableStateOf(true) }
-    Box(modifier = Modifier
-        .background(Color.Blue,
-            RoundedCornerShape(15.dp)
-        )
-        .clickable { short = !short }
-        .padding(20.dp)
-        .wrapContentSize()
-        .animateContentSize()
+    Box(
+        modifier = Modifier
+            .background(
+                Color.Blue,
+                RoundedCornerShape(15.dp)
+            )
+            .clickable { short = !short }
+            .padding(20.dp)
+            .wrapContentSize()
+            .animateContentSize()
     ) {
         Text(
             if (short) {
diff --git a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/TransitionSamples.kt b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/TransitionSamples.kt
index 0dc02f8..e30277a 100644
--- a/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/TransitionSamples.kt
+++ b/compose/animation/animation/samples/src/main/java/androidx/compose/animation/samples/TransitionSamples.kt
@@ -70,7 +70,8 @@
         // This starts the transition going from State.First to State.Second when this composable
         // gets composed for the first time.
         val state = transition(
-            definition = definition, initState = State.First, toState = State.Second)
+            definition = definition, initState = State.First, toState = State.Second
+        )
         Box(
             Modifier
                 .preferredSize(state[widthKey], state[heightKey])
diff --git a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
index 410a039..97906e1 100644
--- a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
+++ b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
@@ -74,9 +74,11 @@
                     tween(100, easing = FastOutSlowInEasing)
                 )
             ) {
-                Stack(Modifier.onPositioned {
-                    offset = it.localToRoot(Offset.Zero)
-                }.size(100.dp, 100.dp)) {
+                Stack(
+                    Modifier.onPositioned {
+                        offset = it.localToRoot(Offset.Zero)
+                    }.size(100.dp, 100.dp)
+                ) {
                     onDispose {
                         disposed = true
                     }
@@ -176,9 +178,11 @@
                     tween(100, easing = FastOutSlowInEasing)
                 )
             ) {
-                Stack(Modifier.onPositioned {
-                    offset = it.localToRoot(Offset.Zero)
-                }.size(100.dp, 100.dp)) {
+                Stack(
+                    Modifier.onPositioned {
+                        offset = it.localToRoot(Offset.Zero)
+                    }.size(100.dp, 100.dp)
+                ) {
                     onDispose {
                         disposed = true
                     }
diff --git a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/SingleValueAnimationTest.kt b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/SingleValueAnimationTest.kt
index 2eba353..b41f4d5 100644
--- a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/SingleValueAnimationTest.kt
+++ b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/SingleValueAnimationTest.kt
@@ -293,7 +293,8 @@
         var value = Color.Black
         val children: @Composable() (Boolean) -> Unit = { enabled ->
             value = animate(
-                if (enabled) Color.Cyan else Color.Black, TweenSpec(
+                if (enabled) Color.Cyan else Color.Black,
+                TweenSpec(
                     durationMillis = 100,
                     easing = FastOutLinearInEasing
                 )
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt
index e5ec767..932202d 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/AnimationModifier.kt
@@ -118,7 +118,8 @@
         } ?: AnimData(
             AnimatedValueModel(
                 targetSize, IntSize.VectorConverter, clock, IntSize(1, 1)
-            ), targetSize
+            ),
+            targetSize
         )
 
         animData = data
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/Crossfade.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/Crossfade.kt
index 21df8cf..38adbe5 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/Crossfade.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/Crossfade.kt
@@ -116,7 +116,8 @@
                 if (reason == AnimationEndReason.TargetReached) {
                     onAnimationFinish()
                 }
-            })
+            }
+        )
     }
     return animatedFloat
 }
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
index 262d6fe..73c11e1 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
@@ -969,7 +969,8 @@
                         IntSize.VectorConverter,
                         clock,
                         visibilityThreshold = IntSize(1, 1)
-                    ), enter.alignment, enter.clip, listener
+                    ),
+                    enter.alignment, enter.clip, listener
                 )
                 // Animate to full size
                 sizeAnim = anim.animateTo(
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/LegacyTransition.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/LegacyTransition.kt
index 0360f16..1e6e430 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/LegacyTransition.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/LegacyTransition.kt
@@ -59,11 +59,14 @@
  *
  * @see [TransitionDefinition]
  */
-@Deprecated("Transition has been renamed to transition, which returns a TransitionState instead " +
+@Deprecated(
+    "Transition has been renamed to transition, which returns a TransitionState instead " +
         "of passing it to children",
     replaceWith = ReplaceWith(
         "transition(definition, toState, clock, initState, null, onStateChangeFinished)",
-        "androidx.compose.animation.transition"))
+        "androidx.compose.animation.transition"
+    )
+)
 @Composable
 fun <T> Transition(
     definition: TransitionDefinition<T>,
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/PropertyKeys.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/PropertyKeys.kt
index ea49d3f..e9a2745 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/PropertyKeys.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/PropertyKeys.kt
@@ -210,8 +210,8 @@
  * [ColorSpace].
  */
 val Color.Companion.VectorConverter:
-            (colorSpace: ColorSpace) -> TwoWayConverter<Color, AnimationVector4D>
-    get() = ColorToVector
+    (colorSpace: ColorSpace) -> TwoWayConverter<Color, AnimationVector4D>
+        get() = ColorToVector
 
 /**
  * A lambda that takes a [ColorSpace] and returns a converter that can both convert a [Color] to
@@ -308,8 +308,10 @@
  * A type converter that converts a [PxBounds] to a [AnimationVector4D], and vice versa.
  * @see Rect.Companion.VectorConverter
  */
-@Deprecated("Use Rect and RectToVectorConverter instead",
-    ReplaceWith("Rect.VectorConverter"))
+@Deprecated(
+    "Use Rect and RectToVectorConverter instead",
+    ReplaceWith("Rect.VectorConverter")
+)
 @Suppress("DEPRECATION")
 val PxBounds.Companion.VectorConverter: TwoWayConverter<PxBounds, AnimationVector4D>
     get() = PxBoundsToVector
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation.kt
index f0aaef8..bb63f17 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation.kt
@@ -241,7 +241,7 @@
     animSpec: AnimationSpec<Bounds> = remember {
         SpringSpec(
             visibilityThreshold = Bounds.VectorConverter.convertFromVector
-                (DpVisibilityThreshold4D)
+            (DpVisibilityThreshold4D)
         )
     },
     endListener: ((Bounds) -> Unit)? = null
@@ -304,7 +304,7 @@
     animSpec: AnimationSpec<Rect> = remember {
         SpringSpec(
             visibilityThreshold =
-            Rect.VectorConverter.convertFromVector(PxVisibilityThreshold4D)
+                Rect.VectorConverter.convertFromVector(PxVisibilityThreshold4D)
         )
     },
     endListener: ((Rect) -> Unit)? = null
@@ -330,10 +330,15 @@
  *                    animation will be used by default.
  * @param endListener An optional end listener to get notified when the animation is finished.
  */
-@Deprecated("Consider usage of Rect instead",
-    ReplaceWith("animate(target: Rect, animSpec: AnimationSpec<Rect>, " +
+@Deprecated(
+    "Consider usage of Rect instead",
+    ReplaceWith(
+        "animate(target: Rect, animSpec: AnimationSpec<Rect>, " +
             "endListener: ((Rect) -> " +
-            "Unit)?", "androidx.compose.animation.animation"))
+            "Unit)?",
+        "androidx.compose.animation.animation"
+    )
+)
 @Suppress("DEPRECATION")
 @Composable
 fun animate(
@@ -341,7 +346,7 @@
     animSpec: AnimationSpec<PxBounds> = remember {
         SpringSpec(
             visibilityThreshold =
-            PxBounds.VectorConverter.convertFromVector(PxVisibilityThreshold4D)
+                PxBounds.VectorConverter.convertFromVector(PxVisibilityThreshold4D)
         )
     },
     endListener: ((PxBounds) -> Unit)? = null
diff --git a/compose/animation/animation/src/test/kotlin/androidx/compose/animation/ConverterTest.kt b/compose/animation/animation/src/test/kotlin/androidx/compose/animation/ConverterTest.kt
index 7bdf8c34..cbe47ba 100644
--- a/compose/animation/animation/src/test/kotlin/androidx/compose/animation/ConverterTest.kt
+++ b/compose/animation/animation/src/test/kotlin/androidx/compose/animation/ConverterTest.kt
@@ -38,19 +38,24 @@
         val converter = (Color.VectorConverter)(ColorSpaces.Srgb)
         assertEquals(converter.convertFromVector(AnimationVector4D(1f, 1f, 0f, 0f)), Color.Red)
         assertEquals(converter.convertToVector(Color.Green), AnimationVector4D(1f, 0f, 1f, 0f))
-        assertEquals(converter.convertFromVector(AnimationVector4D(0f, 0f, 0f, 1f)),
-            Color(alpha = 0f, red = 0f, green = 0f, blue = 1f))
+        assertEquals(
+            converter.convertFromVector(AnimationVector4D(0f, 0f, 0f, 1f)),
+            Color(alpha = 0f, red = 0f, green = 0f, blue = 1f)
+        )
     }
 
     @Test
     fun testRectConverter() {
         assertEquals(
             Rect.VectorConverter.convertToVector(Rect(1f, 2f, 3f, 4f)),
-            AnimationVector4D(1f, 2f, 3f, 4f))
+            AnimationVector4D(1f, 2f, 3f, 4f)
+        )
         assertEquals(
             Rect.VectorConverter.convertFromVector(
-            AnimationVector4D(-400f, -300f, -200f, -100f)),
-            Rect(-400f, -300f, -200f, -100f))
+                AnimationVector4D(-400f, -300f, -200f, -100f)
+            ),
+            Rect(-400f, -300f, -200f, -100f)
+        )
     }
 
     @Test
@@ -66,9 +71,13 @@
     fun testOffsetConverter() {
         val x = Random.nextFloat()
         val y = Random.nextFloat()
-        assertEquals(Offset(x, y),
-            Offset.VectorConverter.convertFromVector(AnimationVector2D(x, y)))
-        assertEquals(AnimationVector2D(x, y),
-            Offset.VectorConverter.convertToVector(Offset(x, y)))
+        assertEquals(
+            Offset(x, y),
+            Offset.VectorConverter.convertFromVector(AnimationVector2D(x, y))
+        )
+        assertEquals(
+            AnimationVector2D(x, y),
+            Offset.VectorConverter.convertToVector(Offset(x, y))
+        )
     }
 }
\ No newline at end of file
diff --git a/compose/compose-compiler-hosted/build.gradle b/compose/compiler/compiler-hosted/build.gradle
similarity index 96%
rename from compose/compose-compiler-hosted/build.gradle
rename to compose/compiler/compiler-hosted/build.gradle
index dd10fd1..63b0577 100644
--- a/compose/compose-compiler-hosted/build.gradle
+++ b/compose/compiler/compiler-hosted/build.gradle
@@ -46,7 +46,7 @@
     publish = Publish.SNAPSHOT_AND_RELEASE
     toolingProject = true
     mavenVersion = LibraryVersions.COMPOSE
-    mavenGroup = LibraryGroups.COMPOSE
+    mavenGroup = LibraryGroups.Compose.COMPILER
     inceptionYear = "2019"
     description = "Contains the Kotlin compiler plugin for Compose used in Android Studio and IDEA"
     compilationTarget = CompilationTarget.HOST
diff --git a/compose/compose-compiler-hosted/integration-tests/build.gradle b/compose/compiler/compiler-hosted/integration-tests/build.gradle
similarity index 95%
rename from compose/compose-compiler-hosted/integration-tests/build.gradle
rename to compose/compiler/compiler-hosted/integration-tests/build.gradle
index 326ec15..c8f3d09 100644
--- a/compose/compose-compiler-hosted/integration-tests/build.gradle
+++ b/compose/compiler/compiler-hosted/integration-tests/build.gradle
@@ -37,7 +37,7 @@
 
     testImplementation(KOTLIN_STDLIB)
     testImplementation(project(":compose:androidview:androidview"))
-    testImplementation(project(":compose:compose-compiler-hosted"))
+    testImplementation(project(":compose:compiler:compiler-hosted"))
     testImplementation(project(":compose:runtime:runtime"))
     testImplementation(project(":compose:ui:ui"))
     testImplementation("androidx.core:core-ktx:1.1.0")
@@ -74,7 +74,6 @@
     name = "AndroidX Compiler CLI Tests"
     publish = Publish.NONE
     toolingProject = true
-    mavenGroup = LibraryGroups.COMPOSE
     inceptionYear = "2019"
     description = "Contains test for the compose compiler plugin"
 }
diff --git a/compose/compose-compiler-hosted/integration-tests/src/main/AndroidManifest.xml b/compose/compiler/compiler-hosted/integration-tests/src/main/AndroidManifest.xml
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/main/AndroidManifest.xml
rename to compose/compiler/compiler-hosted/integration-tests/src/main/AndroidManifest.xml
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenSignatureTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenSignatureTest.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenSignatureTest.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenSignatureTest.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenTest.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenTest.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCodegenTest.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt
similarity index 98%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt
index e8837758..2b7c8f5 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractCompilerTest.kt
@@ -221,7 +221,7 @@
 
     companion object {
         val homeDir by lazy { File(computeHomeDirectory()).absolutePath }
-        val projectRoot by lazy { File(homeDir, "../../../../..").absolutePath }
+        val projectRoot by lazy { File(homeDir, "../../../../../..").absolutePath }
         val kotlinHome by lazy {
             File(projectRoot, "prebuilts/androidx/external/org/jetbrains/kotlin/")
         }
@@ -229,8 +229,7 @@
             File(System.getenv("OUT_DIR") ?: File(projectRoot, "out").absolutePath)
         }
         val composePluginJar by lazy {
-
-            File(outDir, "ui/compose/compose-compiler/build/jarjar/compose-compiler.jar")
+            File(outDir, "ui/compose/compiler/compiler/build/jarjar/compiler.jar")
         }
 
         fun kotlinRuntimeJar(module: String) = File(
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractComposeDiagnosticsTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractComposeDiagnosticsTest.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractComposeDiagnosticsTest.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractComposeDiagnosticsTest.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractControlFlowTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractControlFlowTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractControlFlowTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractControlFlowTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractIrTransformTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractIrTransformTest.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractIrTransformTest.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractIrTransformTest.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractLoweringTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractLoweringTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractLoweringTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractLoweringTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractMultiPlatformIntegrationTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractMultiPlatformIntegrationTest.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractMultiPlatformIntegrationTest.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/AbstractMultiPlatformIntegrationTest.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/CodegenTestFiles.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/CodegenTestFiles.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/CodegenTestFiles.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/CodegenTestFiles.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallLoweringTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallLoweringTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallLoweringTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallLoweringTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallResolverTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallResolverTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallResolverTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCallResolverTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCodegenTestUtils.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCodegenTestUtils.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCodegenTestUtils.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeCodegenTestUtils.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeMultiPlatformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeMultiPlatformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeMultiPlatformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeMultiPlatformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeRobolectricTestRunner.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeRobolectricTestRunner.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeRobolectricTestRunner.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposeRobolectricTestRunner.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamSignatureTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamSignatureTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamSignatureTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamSignatureTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ComposerParamTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTestsNoSource.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTestsNoSource.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTestsNoSource.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTestsNoSource.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DefaultParamTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DefaultParamTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DefaultParamTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DefaultParamTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DurableKeyTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DurableKeyTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DurableKeyTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/DurableKeyTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FcsTypeResolutionTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FcsTypeResolutionTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FcsTypeResolutionTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FcsTypeResolutionTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/FunctionBodySkippingTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/GenerationUtils.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/GenerationUtils.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/GenerationUtils.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/GenerationUtils.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/JvmResolveUtil.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/JvmResolveUtil.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/JvmResolveUtil.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/JvmResolveUtil.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxCrossModuleTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxCrossModuleTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxCrossModuleTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxCrossModuleTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxTransformationTest.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxTransformationTest.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxTransformationTest.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/KtxTransformationTest.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralCodegenTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralCodegenTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralCodegenTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralCodegenTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LiveLiteralTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RememberIntrinsicTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RememberIntrinsicTransformTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RememberIntrinsicTransformTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RememberIntrinsicTransformTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RobolectricComposeTester.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RobolectricComposeTester.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RobolectricComposeTester.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RobolectricComposeTester.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ScopeComposabilityTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ScopeComposabilityTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ScopeComposabilityTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ScopeComposabilityTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TestsCompilerError.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TestsCompilerError.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TestsCompilerError.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/TestsCompilerError.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableCheckerTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableCheckerTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableCheckerTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableCheckerTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableDeclarationCheckerTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableDeclarationCheckerTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableDeclarationCheckerTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposableDeclarationCheckerTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/TryCatchComposableCheckerTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/TryCatchComposableCheckerTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/TryCatchComposableCheckerTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/TryCatchComposableCheckerTests.kt
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/UnionCheckerTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/UnionCheckerTests.kt
similarity index 100%
rename from compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/UnionCheckerTests.kt
rename to compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/analysis/UnionCheckerTests.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableCallChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableCallChecker.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableCallChecker.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableCallChecker.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposableDeclarationChecker.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeDiagnosticSuppressor.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeDiagnosticSuppressor.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeDiagnosticSuppressor.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeDiagnosticSuppressor.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrorMessages.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrorMessages.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrorMessages.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrorMessages.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrors.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrors.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrors.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeErrors.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFlags.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFlags.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFlags.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFlags.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFqNames.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFqNames.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFqNames.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFqNames.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeTypeResolutionInterceptorExtension.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeTypeResolutionInterceptorExtension.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeTypeResolutionInterceptorExtension.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeTypeResolutionInterceptorExtension.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/KtxNameConventions.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/KtxNameConventions.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/KtxNameConventions.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/KtxNameConventions.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/TryCatchComposableChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/TryCatchComposableChecker.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/TryCatchComposableChecker.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/TryCatchComposableChecker.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/UnionAnnotationChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/UnionAnnotationChecker.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/UnionAnnotationChecker.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/UnionAnnotationChecker.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ValidatedAssignment.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ValidatedAssignment.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ValidatedAssignment.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ValidatedAssignment.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/VersionChecker.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/WeakBindingTrace.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/WeakBindingTrace.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/WeakBindingTrace.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/WeakBindingTrace.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposeWritableSlices.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposeWritableSlices.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposeWritableSlices.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/analysis/ComposeWritableSlices.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerIntrinsicTransformer.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerParamTransformer.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/DurableKeyVisitor.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/DurableKeyVisitor.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/DurableKeyVisitor.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/DurableKeyVisitor.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/FakeJvmSymbols.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/FakeJvmSymbols.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/FakeJvmSymbols.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/FakeJvmSymbols.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/IrSourcePrinter.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/LiveLiteralTransformer.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ModuleLoweringPass.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ModuleLoweringPass.kt
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ModuleLoweringPass.kt
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ModuleLoweringPass.kt
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/package-info.java b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/package-info.java
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/package-info.java
rename to compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/package-info.java
diff --git a/compose/compose-compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor b/compose/compiler/compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
rename to compose/compiler/compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
diff --git a/compose/compose-compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar b/compose/compiler/compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
rename to compose/compiler/compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
diff --git a/compose/compose-compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages$Extension b/compose/compiler/compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages$Extension
similarity index 100%
rename from compose/compose-compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages$Extension
rename to compose/compiler/compiler-hosted/src/main/resources/META-INF/services/org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages$Extension
diff --git a/compose/compose-compiler/build.gradle b/compose/compiler/compiler/build.gradle
similarity index 92%
rename from compose/compose-compiler/build.gradle
rename to compose/compiler/compiler/build.gradle
index 2d52b62..5adff18 100644
--- a/compose/compose-compiler/build.gradle
+++ b/compose/compiler/compiler/build.gradle
@@ -34,11 +34,11 @@
 apply plugin: 'org.anarres.jarjar'
 
 dependencies {
-    compileOnly(project(":compose:compose-compiler-hosted"))
+    compileOnly(project(":compose:compiler:compiler-hosted"))
 }
 
 jarjar.repackage('embeddedPlugin') {
-    destinationName "compose-compiler.jar"
+    destinationName "compiler.jar"
     from configurations.compileClasspath
     classRename 'com.intellij.**', 'org.jetbrains.kotlin.com.intellij.@1'
 }
@@ -60,7 +60,7 @@
     publish = Publish.SNAPSHOT_AND_RELEASE
     toolingProject = true
     mavenVersion = LibraryVersions.COMPOSE
-    mavenGroup = LibraryGroups.COMPOSE
+    mavenGroup = LibraryGroups.Compose.COMPILER
     inceptionYear = "2019"
     description = "Compiler plugin that enables Compose"
     compilationTarget = CompilationTarget.HOST
diff --git a/compose/desktop/desktop/build.gradle b/compose/desktop/desktop/build.gradle
index dfb6564..7c93116 100644
--- a/compose/desktop/desktop/build.gradle
+++ b/compose/desktop/desktop/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 }
 
 kotlin {
diff --git a/compose/desktop/desktop/samples/build.gradle b/compose/desktop/desktop/samples/build.gradle
index c8c5629..74ba22e 100644
--- a/compose/desktop/desktop/samples/build.gradle
+++ b/compose/desktop/desktop/samples/build.gradle
@@ -27,7 +27,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 }
 
 kotlin {
diff --git a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.kt b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.kt
index a34fb25..797a79b 100644
--- a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.kt
+++ b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.kt
@@ -122,10 +122,12 @@
                 if (animation.value) {
                     appendInlineContent(inlineIndicatorId)
                 }
-                pushStyle(SpanStyle(
-                    color = Color(0xff964B00),
-                    shadow = Shadow(Color.Green, offset = Offset(1f, 1f))
-                ))
+                pushStyle(
+                    SpanStyle(
+                        color = Color(0xff964B00),
+                        shadow = Shadow(Color.Green, offset = Offset(1f, 1f))
+                    )
+                )
                 append("brown fox")
                 pop()
                 pushStyle(SpanStyle(background = Color.Yellow))
@@ -165,13 +167,13 @@
             TextDecoration.LineThrough
         )
         val lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do" +
-                " eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" +
-                " minim veniam, quis nostrud exercitation ullamco laboris nisi ut" +
-                " aliquipex ea commodo consequat. Duis aute irure dolor in reprehenderit" +
-                " in voluptate velit esse cillum dolore eu fugiat nulla pariatur." +
-                " Excepteur" +
-                " sint occaecat cupidatat non proident, sunt in culpa qui officia" +
-                " deserunt mollit anim id est laborum."
+            " eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" +
+            " minim veniam, quis nostrud exercitation ullamco laboris nisi ut" +
+            " aliquipex ea commodo consequat. Duis aute irure dolor in reprehenderit" +
+            " in voluptate velit esse cillum dolore eu fugiat nulla pariatur." +
+            " Excepteur" +
+            " sint occaecat cupidatat non proident, sunt in culpa qui officia" +
+            " deserunt mollit anim id est laborum."
         var loremDecoration by remember { mutableStateOf(0) }
         Text(
             text = lorem,
@@ -200,13 +202,13 @@
 
         Text(
             text = "fun <T : Comparable<T>> List<T>.quickSort(): List<T> = when {\n" +
-                    "  size < 2 -> this\n" +
-                    "  else -> {\n" +
-                    "    val pivot = first()\n" +
-                    "    val (smaller, greater) = drop(1).partition { it <= pivot }\n" +
-                    "    smaller.quickSort() + pivot + greater.quickSort()\n" +
-                    "   }\n" +
-                    "}",
+                "  size < 2 -> this\n" +
+                "  else -> {\n" +
+                "    val pivot = first()\n" +
+                "    val (smaller, greater) = drop(1).partition { it <= pivot }\n" +
+                "    smaller.quickSort() + pivot + greater.quickSort()\n" +
+                "   }\n" +
+                "}",
             modifier = Modifier.padding(10.dp).pointerMoveFilter(
                 onMove = { position ->
                     println("MOVE: $position")
@@ -221,12 +223,16 @@
                     println("UNHOVER!")
                     text.value = "UNHOVER ${amount.value}"
                     false
-                })
+                }
+            )
         )
 
-        Button(modifier = Modifier.padding(4.dp), onClick = {
-            amount.value++
-        }) {
+        Button(
+            modifier = Modifier.padding(4.dp),
+            onClick = {
+                amount.value++
+            }
+        ) {
             Text("Base")
         }
 
@@ -239,7 +245,8 @@
                     modifier = Modifier.padding(4.dp),
                     onClick = {
                         animation.value = !animation.value
-                    }) {
+                    }
+                ) {
                     Text("Toggle")
                 }
 
@@ -249,7 +256,8 @@
                         Window(size = IntSize(400, 200)) {
                             Animations(isCircularEnabled = animation.value)
                         }
-                    }) {
+                    }
+                ) {
                     Text("Window")
                 }
             }
@@ -257,8 +265,10 @@
             Animations(isCircularEnabled = animation.value)
         }
 
-        Slider(value = amount.value.toFloat() / 100f,
-            onValueChange = { amount.value = (it * 100).toInt() })
+        Slider(
+            value = amount.value.toFloat() / 100f,
+            onValueChange = { amount.value = (it * 100).toInt() }
+        )
         TextField(
             value = amount.value.toString(),
             onValueChange = { amount.value = it.toIntOrNull() ?: 42 },
diff --git a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppContent.kt b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppContent.kt
index e887578..42db6ac 100644
--- a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppContent.kt
+++ b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/popupexample/AppContent.kt
@@ -73,9 +73,12 @@
                                 println("Second window is dismissed.")
                             }
                         ).show {
-                            WindowContent(amount, onClose = {
-                                AppManager.getCurrentFocusedWindow()?.close()
-                            })
+                            WindowContent(
+                                amount,
+                                onClose = {
+                                    AppManager.getCurrentFocusedWindow()?.close()
+                                }
+                            )
                         }
                     }
                 )
diff --git a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/desktop/ParagraphTest.kt b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/desktop/ParagraphTest.kt
index 7277c2f..347723a 100644
--- a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/desktop/ParagraphTest.kt
+++ b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/desktop/ParagraphTest.kt
@@ -51,22 +51,22 @@
 
     private val text1 =
         "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do" +
-                " eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" +
-                " minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip" +
-                " ex ea commodo consequat. Duis aute irure dolor in reprehenderit in" +
-                " voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur" +
-                " sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt" +
-                " mollit anim id est laborum."
+            " eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad" +
+            " minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip" +
+            " ex ea commodo consequat. Duis aute irure dolor in reprehenderit in" +
+            " voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur" +
+            " sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt" +
+            " mollit anim id est laborum."
 
     private val text2 =
         "fun <T : Comparable<T>> List<T>.quickSort(): List<T> = when {\n" +
-                "  size < 2 -> this\n" +
-                "  else -> {\n" +
-                "    val pivot = first()\n" +
-                "    val (smaller, greater) = drop(1).partition { it <= pivot }\n" +
-                "    smaller.quickSort() + pivot + greater.quickSort()\n" +
-                "   }\n" +
-                "}"
+            "  size < 2 -> this\n" +
+            "  else -> {\n" +
+            "    val pivot = first()\n" +
+            "    val (smaller, greater) = drop(1).partition { it <= pivot }\n" +
+            "    smaller.quickSort() + pivot + greater.quickSort()\n" +
+            "   }\n" +
+            "}"
 
     val fontFamily = fontFamily(
         font("Noto", "NotoSans-Regular.ttf"),
diff --git a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPaintTest.kt b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPaintTest.kt
index fff340a..5154080 100644
--- a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPaintTest.kt
+++ b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPaintTest.kt
@@ -46,10 +46,13 @@
     @Test
     fun blendModePlus() {
         canvas.drawRect(left = 0f, top = 0f, right = 16f, bottom = 16f, paint = redPaint)
-        canvas.drawRect(left = 4f, top = 4f, right = 12f, bottom = 12f, paint = Paint().apply {
-            color = Color.Blue
-            blendMode = BlendMode.Plus
-        })
+        canvas.drawRect(
+            left = 4f, top = 4f, right = 12f, bottom = 12f,
+            paint = Paint().apply {
+                color = Color.Blue
+                blendMode = BlendMode.Plus
+            }
+        )
 
         screenshotRule.snap(surface)
     }
@@ -57,10 +60,13 @@
     @Test
     fun blendModeMultiply() {
         canvas.drawRect(left = 0f, top = 0f, right = 16f, bottom = 16f, paint = redPaint)
-        canvas.drawRect(left = 4f, top = 4f, right = 12f, bottom = 12f, paint = Paint().apply {
-            color = Color.Gray
-            blendMode = BlendMode.Multiply
-        })
+        canvas.drawRect(
+            left = 4f, top = 4f, right = 12f, bottom = 12f,
+            paint = Paint().apply {
+                color = Color.Gray
+                blendMode = BlendMode.Multiply
+            }
+        )
 
         screenshotRule.snap(surface)
     }
@@ -118,14 +124,17 @@
     fun linearGradientShader() {
         canvas.drawRect(left = 0f, top = 0f, right = 16f, bottom = 16f, paint = redPaint)
 
-        canvas.drawRect(left = 2f, top = 2f, right = 14f, bottom = 14f, paint = Paint().apply {
-            shader = LinearGradientShader(
-                from = Offset(0f, 0f),
-                to = Offset(6f, 6f),
-                colors = listOf(Color.Blue, Color.Green),
-                tileMode = TileMode.Mirror
-            )
-        })
+        canvas.drawRect(
+            left = 2f, top = 2f, right = 14f, bottom = 14f,
+            paint = Paint().apply {
+                shader = LinearGradientShader(
+                    from = Offset(0f, 0f),
+                    to = Offset(6f, 6f),
+                    colors = listOf(Color.Blue, Color.Green),
+                    tileMode = TileMode.Mirror
+                )
+            }
+        )
 
         screenshotRule.snap(surface)
     }
@@ -134,15 +143,18 @@
     fun linearGradientShaderWithStops() {
         canvas.drawRect(left = 0f, top = 0f, right = 16f, bottom = 16f, paint = redPaint)
 
-        canvas.drawRect(left = 1f, top = 2f, right = 14f, bottom = 15f, paint = Paint().apply {
-            shader = LinearGradientShader(
-                from = Offset(0f, 0f),
-                to = Offset(12f, 0f),
-                colorStops = listOf(0f, 0.25f, 1f),
-                colors = listOf(Color.Blue, Color.Green, Color.Yellow),
-                tileMode = TileMode.Mirror
-            )
-        })
+        canvas.drawRect(
+            left = 1f, top = 2f, right = 14f, bottom = 15f,
+            paint = Paint().apply {
+                shader = LinearGradientShader(
+                    from = Offset(0f, 0f),
+                    to = Offset(12f, 0f),
+                    colorStops = listOf(0f, 0.25f, 1f),
+                    colors = listOf(Color.Blue, Color.Green, Color.Yellow),
+                    tileMode = TileMode.Mirror
+                )
+            }
+        )
 
         screenshotRule.snap(surface)
     }
@@ -151,14 +163,17 @@
     fun radialGradientShader() {
         canvas.drawRect(left = 0f, top = 0f, right = 16f, bottom = 16f, paint = redPaint)
 
-        canvas.drawRect(left = 2f, top = 2f, right = 14f, bottom = 14f, paint = Paint().apply {
-            shader = RadialGradientShader(
-                center = Offset(4f, 8f),
-                radius = 8f,
-                colors = listOf(Color.Blue, Color.Green),
-                tileMode = TileMode.Clamp
-            )
-        })
+        canvas.drawRect(
+            left = 2f, top = 2f, right = 14f, bottom = 14f,
+            paint = Paint().apply {
+                shader = RadialGradientShader(
+                    center = Offset(4f, 8f),
+                    radius = 8f,
+                    colors = listOf(Color.Blue, Color.Green),
+                    tileMode = TileMode.Clamp
+                )
+            }
+        )
 
         screenshotRule.snap(surface)
     }
diff --git a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPathTest.kt b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPathTest.kt
index 9ce4554..85a721a 100644
--- a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPathTest.kt
+++ b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/DesktopPathTest.kt
@@ -149,10 +149,13 @@
             relativeLineTo(0f, -8f)
         }
 
-        canvas.drawPath(path, redPaint.apply {
-            style = PaintingStyle.Stroke
-            strokeWidth = 2f
-        })
+        canvas.drawPath(
+            path,
+            redPaint.apply {
+                style = PaintingStyle.Stroke
+                strokeWidth = 2f
+            }
+        )
 
         screenshotRule.snap(surface)
     }
diff --git a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/canvas/DesktopCanvasTest.kt b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/canvas/DesktopCanvasTest.kt
index 789ee32..f196391 100644
--- a/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/canvas/DesktopCanvasTest.kt
+++ b/compose/desktop/desktop/src/jvmTest/kotlin/androidx/compose/ui/graphics/canvas/DesktopCanvasTest.kt
@@ -121,49 +121,70 @@
 
     @Test
     fun drawLine() {
-        canvas.drawLine(Offset(-4f, -4f), Offset(4f, 4f), Paint().apply {
-            color = Color.Red
-            strokeWidth = 1f
-            strokeCap = StrokeCap.Butt
-        })
-        canvas.drawLine(Offset(8f, 4f), Offset(8f, 12f), Paint().apply {
-            color = Color.Blue
-            strokeWidth = 4f
-            strokeCap = StrokeCap.Butt
-        })
-        canvas.drawLine(Offset(12f, 4f), Offset(12f, 12f), Paint().apply {
-            color = Color.Green
-            strokeWidth = 4f
-            strokeCap = StrokeCap.Round
-        })
-        canvas.drawLine(Offset(4f, 4f), Offset(4f, 12f), Paint().apply {
-            color = Color.Black.copy(alpha = 0.5f)
-            strokeWidth = 4f
-            strokeCap = StrokeCap.Square
-        })
+        canvas.drawLine(
+            Offset(-4f, -4f), Offset(4f, 4f),
+            Paint().apply {
+                color = Color.Red
+                strokeWidth = 1f
+                strokeCap = StrokeCap.Butt
+            }
+        )
+        canvas.drawLine(
+            Offset(8f, 4f), Offset(8f, 12f),
+            Paint().apply {
+                color = Color.Blue
+                strokeWidth = 4f
+                strokeCap = StrokeCap.Butt
+            }
+        )
+        canvas.drawLine(
+            Offset(12f, 4f), Offset(12f, 12f),
+            Paint().apply {
+                color = Color.Green
+                strokeWidth = 4f
+                strokeCap = StrokeCap.Round
+            }
+        )
+        canvas.drawLine(
+            Offset(4f, 4f), Offset(4f, 12f),
+            Paint().apply {
+                color = Color.Black.copy(alpha = 0.5f)
+                strokeWidth = 4f
+                strokeCap = StrokeCap.Square
+            }
+        )
 
         // should draw antialiased two-pixel line
-        canvas.drawLine(Offset(4f, 4f), Offset(4f, 12f), Paint().apply {
-            color = Color.Yellow
-            strokeWidth = 1f
-            strokeCap = StrokeCap.Butt
-        })
+        canvas.drawLine(
+            Offset(4f, 4f), Offset(4f, 12f),
+            Paint().apply {
+                color = Color.Yellow
+                strokeWidth = 1f
+                strokeCap = StrokeCap.Butt
+            }
+        )
 
         // should draw aliased one-pixel line
-        canvas.drawLine(Offset(4f, 4f), Offset(4f, 12f), Paint().apply {
-            color = Color.Yellow
-            strokeWidth = 1f
-            strokeCap = StrokeCap.Butt
-            isAntiAlias = false
-        })
+        canvas.drawLine(
+            Offset(4f, 4f), Offset(4f, 12f),
+            Paint().apply {
+                color = Color.Yellow
+                strokeWidth = 1f
+                strokeCap = StrokeCap.Butt
+                isAntiAlias = false
+            }
+        )
 
         // shouldn't draw any line
-        canvas.drawLine(Offset(4f, 4f), Offset(4f, 12f), Paint().apply {
-            color = Color.Yellow
-            strokeWidth = 0f
-            strokeCap = StrokeCap.Butt
-            isAntiAlias = false
-        })
+        canvas.drawLine(
+            Offset(4f, 4f), Offset(4f, 12f),
+            Paint().apply {
+                color = Color.Yellow
+                strokeWidth = 0f
+                strokeCap = StrokeCap.Butt
+                isAntiAlias = false
+            }
+        )
 
         screenshotRule.snap(surface)
     }
@@ -204,7 +225,8 @@
         canvas.drawRect(0f, 0f, 16f, 16f, redPaint)
 
         canvas.withSaveLayer(
-            Rect(left = 4f, top = 8f, right = 12f, bottom = 16f), redPaint.apply {
+            Rect(left = 4f, top = 8f, right = 12f, bottom = 16f),
+            redPaint.apply {
                 blendMode = BlendMode.Plus
             }
         ) {
diff --git a/compose/foundation/foundation-layout/api/current.txt b/compose/foundation/foundation-layout/api/current.txt
index aacbcc9..6740f1d 100644
--- a/compose/foundation/foundation-layout/api/current.txt
+++ b/compose/foundation/foundation-layout/api/current.txt
@@ -51,8 +51,7 @@
   }
 
   @androidx.compose.foundation.layout.InternalLayoutApi public static interface Arrangement.Horizontal {
-    method public void arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.unit.Density density, java.util.List<java.lang.Integer> outPosition);
-    method @Deprecated public default java.util.List<java.lang.Integer> arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.LayoutDirection layoutDirection);
+    method public void arrange(int totalSize, int[] size, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.unit.Density density, int[] outPosition);
     method public default float getSpacing();
     property public default float spacing;
   }
@@ -62,8 +61,7 @@
   }
 
   @androidx.compose.foundation.layout.InternalLayoutApi public static interface Arrangement.Vertical {
-    method public void arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.Density density, java.util.List<java.lang.Integer> outPosition);
-    method @Deprecated public default java.util.List<java.lang.Integer> arrange(int totalSize, java.util.List<java.lang.Integer> size);
+    method public void arrange(int totalSize, int[] size, androidx.compose.ui.unit.Density density, int[] outPosition);
     method public default float getSpacing();
     property public default float spacing;
   }
diff --git a/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt b/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt
index aacbcc9..6740f1d 100644
--- a/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt
+++ b/compose/foundation/foundation-layout/api/public_plus_experimental_current.txt
@@ -51,8 +51,7 @@
   }
 
   @androidx.compose.foundation.layout.InternalLayoutApi public static interface Arrangement.Horizontal {
-    method public void arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.unit.Density density, java.util.List<java.lang.Integer> outPosition);
-    method @Deprecated public default java.util.List<java.lang.Integer> arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.LayoutDirection layoutDirection);
+    method public void arrange(int totalSize, int[] size, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.unit.Density density, int[] outPosition);
     method public default float getSpacing();
     property public default float spacing;
   }
@@ -62,8 +61,7 @@
   }
 
   @androidx.compose.foundation.layout.InternalLayoutApi public static interface Arrangement.Vertical {
-    method public void arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.Density density, java.util.List<java.lang.Integer> outPosition);
-    method @Deprecated public default java.util.List<java.lang.Integer> arrange(int totalSize, java.util.List<java.lang.Integer> size);
+    method public void arrange(int totalSize, int[] size, androidx.compose.ui.unit.Density density, int[] outPosition);
     method public default float getSpacing();
     property public default float spacing;
   }
diff --git a/compose/foundation/foundation-layout/api/restricted_current.txt b/compose/foundation/foundation-layout/api/restricted_current.txt
index 2806d37..7b36eca9 100644
--- a/compose/foundation/foundation-layout/api/restricted_current.txt
+++ b/compose/foundation/foundation-layout/api/restricted_current.txt
@@ -51,8 +51,7 @@
   }
 
   @androidx.compose.foundation.layout.InternalLayoutApi public static interface Arrangement.Horizontal {
-    method public void arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.unit.Density density, java.util.List<java.lang.Integer> outPosition);
-    method @Deprecated public default java.util.List<java.lang.Integer> arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.LayoutDirection layoutDirection);
+    method public void arrange(int totalSize, int[] size, androidx.compose.ui.unit.LayoutDirection layoutDirection, androidx.compose.ui.unit.Density density, int[] outPosition);
     method public default float getSpacing();
     property public default float spacing;
   }
@@ -62,8 +61,7 @@
   }
 
   @androidx.compose.foundation.layout.InternalLayoutApi public static interface Arrangement.Vertical {
-    method public void arrange(int totalSize, java.util.List<java.lang.Integer> size, androidx.compose.ui.unit.Density density, java.util.List<java.lang.Integer> outPosition);
-    method @Deprecated public default java.util.List<java.lang.Integer> arrange(int totalSize, java.util.List<java.lang.Integer> size);
+    method public void arrange(int totalSize, int[] size, androidx.compose.ui.unit.Density density, int[] outPosition);
     method public default float getSpacing();
     property public default float spacing;
   }
@@ -416,7 +414,7 @@
   }
 
   public final class RowColumnImplKt {
-    method @kotlin.PublishedApi internal static androidx.compose.ui.node.LayoutNode.MeasureBlocks rowColumnMeasureBlocks-GZ6WFlY(androidx.compose.foundation.layout.LayoutOrientation orientation, kotlin.jvm.functions.Function5<? super java.lang.Integer,? super java.util.List<java.lang.Integer>,? super androidx.compose.ui.unit.LayoutDirection,? super androidx.compose.ui.unit.Density,? super java.util.List<java.lang.Integer>,kotlin.Unit> arrangement, float arrangementSpacing, androidx.compose.foundation.layout.SizeMode crossAxisSize, androidx.compose.foundation.layout.CrossAxisAlignment crossAxisAlignment);
+    method @kotlin.PublishedApi internal static androidx.compose.ui.node.LayoutNode.MeasureBlocks rowColumnMeasureBlocks-GZ6WFlY(androidx.compose.foundation.layout.LayoutOrientation orientation, kotlin.jvm.functions.Function5<? super java.lang.Integer,? super int[],? super androidx.compose.ui.unit.LayoutDirection,? super androidx.compose.ui.unit.Density,? super int[],kotlin.Unit> arrangement, float arrangementSpacing, androidx.compose.foundation.layout.SizeMode crossAxisSize, androidx.compose.foundation.layout.CrossAxisAlignment crossAxisAlignment);
   }
 
   public final class RowKt {
diff --git a/compose/foundation/foundation-layout/build.gradle b/compose/foundation/foundation-layout/build.gradle
index 93e2980..fa91824 100644
--- a/compose/foundation/foundation-layout/build.gradle
+++ b/compose/foundation/foundation-layout/build.gradle
@@ -29,7 +29,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 }
 
 kotlin {
diff --git a/compose/foundation/foundation-layout/integration-tests/layout-demos/build.gradle b/compose/foundation/foundation-layout/integration-tests/layout-demos/build.gradle
index 6517c25..876d95b 100644
--- a/compose/foundation/foundation-layout/integration-tests/layout-demos/build.gradle
+++ b/compose/foundation/foundation-layout/integration-tests/layout-demos/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/foundation/foundation-layout/samples/build.gradle b/compose/foundation/foundation-layout/samples/build.gradle
index 164e5ef..a09a4a1 100644
--- a/compose/foundation/foundation-layout/samples/build.gradle
+++ b/compose/foundation/foundation-layout/samples/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Arrangement.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Arrangement.kt
index e5b433c..9268c68 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Arrangement.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Arrangement.kt
@@ -22,7 +22,6 @@
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
-import androidx.compose.ui.util.fastForEachIndexed
 import kotlin.math.min
 import kotlin.math.roundToInt
 
@@ -47,31 +46,19 @@
          * Horizontally places the layout children inside the [Row].
          *
          * @param totalSize Available space that can be occupied by the children.
-         * @param size A list of sizes of all children.
+         * @param size An array of sizes of all children.
          * @param layoutDirection A layout direction, left-to-right or right-to-left, of the parent
          * layout that should be taken into account when determining positions of the children.
          * @param density The current density.
-         * @param outPosition A preallocated list that should return the calculated positions.
+         * @param outPosition An array of the size of [size] that returns the calculated positions.
          */
         fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             layoutDirection: LayoutDirection,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         )
-
-        @Deprecated("Custom arrangements will not be supported anymore. Please use a provided " +
-                "one instead, or Spacers.")
-        fun arrange(
-            totalSize: Int,
-            size: List<Int>,
-            layoutDirection: LayoutDirection
-        ): List<Int> {
-            val result = MutableList(size.size) { 0 }
-            arrange(totalSize, size, layoutDirection, Density(1f), result)
-            return result
-        }
     }
 
     /**
@@ -88,27 +75,16 @@
          * Vertically places the layout children inside the [Column].
          *
          * @param totalSize Available space that can be occupied by the children.
-         * @param size A list of sizes of all children.
+         * @param size An array of sizes of all children.
          * @param density The current density.
-         * @param outPosition A preallocated list that should return the calculated positions.
+         * @param outPosition An array of the size of [size] that returns the calculated positions.
          */
         fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         )
-
-        @Deprecated("Custom arrangements will not be supported anymore. Please use a provided " +
-                "one instead, or Spacers.")
-        fun arrange(
-            totalSize: Int,
-            size: List<Int>
-        ): List<Int> {
-            val result = MutableList(size.size) { 0 }
-            arrange(totalSize, size, Density(1f), result)
-            return result
-        }
     }
 
     /**
@@ -130,14 +106,15 @@
     val Start = object : Horizontal {
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             layoutDirection: LayoutDirection,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = if (layoutDirection == LayoutDirection.Ltr) {
             placeLeftOrTop(size, outPosition)
         } else {
-            placeRightOrBottom(totalSize, size.asReversed(), outPosition)
+            size.reverse()
+            placeRightOrBottom(totalSize, size, outPosition)
             outPosition.reverse()
         }
     }
@@ -149,14 +126,15 @@
     val End = object : Horizontal {
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             layoutDirection: LayoutDirection,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = if (layoutDirection == LayoutDirection.Ltr) {
             placeRightOrBottom(totalSize, size, outPosition)
         } else {
-            placeLeftOrTop(size.asReversed(), outPosition)
+            size.reverse()
+            placeLeftOrTop(size, outPosition)
             outPosition.reverse()
         }
     }
@@ -168,9 +146,9 @@
     val Top = object : Vertical {
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = placeLeftOrTop(size, outPosition)
     }
 
@@ -181,9 +159,9 @@
     val Bottom = object : Vertical {
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = placeRightOrBottom(totalSize, size, outPosition)
     }
 
@@ -195,22 +173,23 @@
 
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             layoutDirection: LayoutDirection,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = if (layoutDirection == LayoutDirection.Ltr) {
             placeCenter(totalSize, size, outPosition)
         } else {
-            placeCenter(totalSize, size.asReversed(), outPosition)
+            size.reverse()
+            placeCenter(totalSize, size, outPosition)
             outPosition.reverse()
         }
 
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = placeCenter(totalSize, size, outPosition)
     }
 
@@ -223,22 +202,23 @@
 
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             layoutDirection: LayoutDirection,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = if (layoutDirection == LayoutDirection.Ltr) {
             placeSpaceEvenly(totalSize, size, outPosition)
         } else {
-            placeSpaceEvenly(totalSize, size.asReversed(), outPosition)
+            size.reverse()
+            placeSpaceEvenly(totalSize, size, outPosition)
             outPosition.reverse()
         }
 
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = placeSpaceEvenly(totalSize, size, outPosition)
     }
 
@@ -251,22 +231,23 @@
 
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             layoutDirection: LayoutDirection,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = if (layoutDirection == LayoutDirection.Ltr) {
             placeSpaceBetween(totalSize, size, outPosition)
         } else {
-            placeSpaceBetween(totalSize, size.asReversed(), outPosition)
+            size.reverse()
+            placeSpaceBetween(totalSize, size, outPosition)
             outPosition.reverse()
         }
 
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = placeSpaceBetween(totalSize, size, outPosition)
     }
 
@@ -280,22 +261,23 @@
 
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             layoutDirection: LayoutDirection,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = if (layoutDirection == LayoutDirection.Ltr) {
             placeSpaceAround(totalSize, size, outPosition)
         } else {
-            placeSpaceAround(totalSize, size.asReversed(), outPosition)
+            size.reverse()
+            placeSpaceAround(totalSize, size, outPosition)
             outPosition.reverse()
         }
 
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = placeSpaceAround(totalSize, size, outPosition)
     }
 
@@ -368,22 +350,22 @@
 
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             layoutDirection: LayoutDirection,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) {
             if (size.isEmpty()) return
             val spacePx = with(density) { space.toIntPx() }
 
             var occupied = 0
             var lastSpace = 0
-            (if (layoutDirection == LayoutDirection.Ltr || !rtlMirror) size else size.asReversed())
-                .fastForEachIndexed { index, it ->
-                    outPosition[index] = min(occupied, totalSize - it)
-                    lastSpace = min(spacePx, totalSize - outPosition[index] - it)
-                    occupied = outPosition[index] + it + lastSpace
-                }
+            if (layoutDirection == LayoutDirection.Rtl && rtlMirror) size.reverse()
+            size.forEachIndexed { index, it ->
+                outPosition[index] = min(occupied, totalSize - it)
+                lastSpace = min(spacePx, totalSize - outPosition[index] - it)
+                occupied = outPosition[index] + it + lastSpace
+            }
             occupied -= lastSpace
 
             if (alignment != null && occupied < totalSize) {
@@ -398,53 +380,53 @@
 
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = arrange(totalSize, size, LayoutDirection.Ltr, density, outPosition)
     }
 
     internal fun placeRightOrBottom(
         totalSize: Int,
-        size: List<Int>,
-        outPosition: MutableList<Int>
+        size: IntArray,
+        outPosition: IntArray
     ) {
         val consumedSize = size.fold(0) { a, b -> a + b }
         var current = totalSize - consumedSize
-        size.fastForEachIndexed { index, it ->
+        size.forEachIndexed { index, it ->
             outPosition[index] = current
             current += it
         }
     }
 
-    internal fun placeLeftOrTop(size: List<Int>, outPosition: MutableList<Int>) {
+    internal fun placeLeftOrTop(size: IntArray, outPosition: IntArray) {
         var current = 0
-        size.fastForEachIndexed { index, it ->
+        size.forEachIndexed { index, it ->
             outPosition[index] = current
             current += it
         }
     }
 
-    internal fun placeCenter(totalSize: Int, size: List<Int>, outPosition: MutableList<Int>) {
+    internal fun placeCenter(totalSize: Int, size: IntArray, outPosition: IntArray) {
         val consumedSize = size.fold(0) { a, b -> a + b }
         var current = (totalSize - consumedSize).toFloat() / 2
-        size.fastForEachIndexed { index, it ->
+        size.forEachIndexed { index, it ->
             outPosition[index] = current.roundToInt()
             current += it.toFloat()
         }
     }
 
-    internal fun placeSpaceEvenly(totalSize: Int, size: List<Int>, outPosition: MutableList<Int>) {
+    internal fun placeSpaceEvenly(totalSize: Int, size: IntArray, outPosition: IntArray) {
         val consumedSize = size.fold(0) { a, b -> a + b }
         val gapSize = (totalSize - consumedSize).toFloat() / (size.size + 1)
         var current = gapSize
-        size.fastForEachIndexed { index, it ->
+        size.forEachIndexed { index, it ->
             outPosition[index] = current.roundToInt()
             current += it.toFloat() + gapSize
         }
     }
 
-    internal fun placeSpaceBetween(totalSize: Int, size: List<Int>, outPosition: MutableList<Int>) {
+    internal fun placeSpaceBetween(totalSize: Int, size: IntArray, outPosition: IntArray) {
         val consumedSize = size.fold(0) { a, b -> a + b }
         val gapSize = if (size.size > 1) {
             (totalSize - consumedSize).toFloat() / (size.size - 1)
@@ -452,13 +434,13 @@
             0f
         }
         var current = 0f
-        size.fastForEachIndexed { index, it ->
+        size.forEachIndexed { index, it ->
             outPosition[index] = current.roundToInt()
             current += it.toFloat() + gapSize
         }
     }
 
-    internal fun placeSpaceAround(totalSize: Int, size: List<Int>, outPosition: MutableList<Int>) {
+    internal fun placeSpaceAround(totalSize: Int, size: IntArray, outPosition: IntArray) {
         val consumedSize = size.fold(0) { a, b -> a + b }
         val gapSize = if (size.isNotEmpty()) {
             (totalSize - consumedSize).toFloat() / size.size
@@ -466,7 +448,7 @@
             0f
         }
         var current = gapSize / 2
-        size.fastForEachIndexed { index, it ->
+        size.forEachIndexed { index, it ->
             outPosition[index] = current.roundToInt()
             current += it.toFloat() + gapSize
         }
@@ -486,10 +468,10 @@
     val Left = object : Arrangement.Horizontal {
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             layoutDirection: LayoutDirection,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = Arrangement.placeLeftOrTop(size, outPosition)
     }
 
@@ -502,10 +484,10 @@
     val Center = object : Arrangement.Horizontal {
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             layoutDirection: LayoutDirection,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = Arrangement.placeCenter(totalSize, size, outPosition)
     }
 
@@ -519,10 +501,10 @@
     val Right = object : Arrangement.Horizontal {
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             layoutDirection: LayoutDirection,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = Arrangement.placeRightOrBottom(totalSize, size, outPosition)
     }
 
@@ -536,10 +518,10 @@
     val SpaceBetween = object : Arrangement.Horizontal {
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             layoutDirection: LayoutDirection,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = Arrangement.placeSpaceBetween(totalSize, size, outPosition)
     }
 
@@ -553,10 +535,10 @@
     val SpaceEvenly = object : Arrangement.Horizontal {
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             layoutDirection: LayoutDirection,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = Arrangement.placeSpaceEvenly(totalSize, size, outPosition)
     }
 
@@ -571,10 +553,10 @@
     val SpaceAround = object : Arrangement.Horizontal {
         override fun arrange(
             totalSize: Int,
-            size: List<Int>,
+            size: IntArray,
             layoutDirection: LayoutDirection,
             density: Density,
-            outPosition: MutableList<Int>
+            outPosition: IntArray
         ) = Arrangement.placeSpaceAround(totalSize, size, outPosition)
     }
 
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Flow.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Flow.kt
index 9b854c8..34f2ed9 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Flow.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Flow.kt
@@ -229,8 +229,8 @@
 
         layout(layoutWidth, layoutHeight) {
             sequences.fastForEachIndexed { i, placeables ->
-                val childrenMainAxisSizes = placeables.mapIndexed { j, placeable ->
-                    placeable.mainAxisSize() +
+                val childrenMainAxisSizes = IntArray(placeables.size) { j ->
+                    placeables[j].mainAxisSize() +
                         if (j < placeables.lastIndex) mainAxisSpacing.toIntPx() else 0
                 }
                 val arrangement = if (i < sequences.lastIndex) {
@@ -240,7 +240,7 @@
                 }
                 // TODO(soboleva): rtl support
                 // Handle vertical direction
-                val mainAxisPositions = MutableList(childrenMainAxisSizes.size) { 0 }
+                val mainAxisPositions = IntArray(childrenMainAxisSizes.size) { 0 }
                 arrangement.arrange(
                     mainAxisLayoutSize,
                     childrenMainAxisSizes,
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt
index 85a1b54..d915287 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl.kt
@@ -44,7 +44,7 @@
 @OptIn(ExperimentalLayoutNodeApi::class)
 internal fun rowColumnMeasureBlocks(
     orientation: LayoutOrientation,
-    arrangement: (Int, List<Int>, LayoutDirection, Density, MutableList<Int>) -> Unit,
+    arrangement: (Int, IntArray, LayoutDirection, Density, IntArray) -> Unit,
     arrangementSpacing: Dp,
     crossAxisSize: SizeMode,
     crossAxisAlignment: CrossAxisAlignment
@@ -222,9 +222,11 @@
             mainAxisLayoutSize
         }
 
-        val mainAxisPositions = MutableList(measurables.size) { 0 }
+        val mainAxisPositions = IntArray(measurables.size) { 0 }
         layout(layoutWidth, layoutHeight) {
-            val childrenMainAxisSize = placeables.map { it!!.mainAxisSize() }
+            val childrenMainAxisSize = IntArray(measurables.size) { index ->
+                placeables[index]!!.mainAxisSize()
+            }
             arrangement(
                 mainAxisLayoutSize,
                 childrenMainAxisSize,
diff --git a/compose/foundation/foundation-text/build.gradle b/compose/foundation/foundation-text/build.gradle
index a88b8d4..07b7156 100644
--- a/compose/foundation/foundation-text/build.gradle
+++ b/compose/foundation/foundation-text/build.gradle
@@ -29,7 +29,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 }
 
 kotlin {
diff --git a/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/build.gradle b/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/build.gradle
index d35f2a8..72dd6fb 100644
--- a/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/build.gradle
+++ b/compose/foundation/foundation-text/integration-tests/ui-text-compose-demos/build.gradle
@@ -10,7 +10,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/foundation/foundation-text/samples/build.gradle b/compose/foundation/foundation-text/samples/build.gradle
index c345b51..5647372 100644
--- a/compose/foundation/foundation-text/samples/build.gradle
+++ b/compose/foundation/foundation-text/samples/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt
index a3554eb..a0025c7 100644
--- a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt
+++ b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreText.kt
@@ -32,7 +32,7 @@
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Paint
-import androidx.compose.ui.graphics.drawscope.drawCanvas
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
 import androidx.compose.ui.layout.LayoutCoordinates
 import androidx.compose.ui.layout.globalPosition
 import androidx.compose.ui.onPositioned
@@ -138,7 +138,7 @@
         children = { InlineChildren(text, inlineComposables) },
         modifier = modifier.drawLayer().drawBehind {
             state.layoutResult?.let { layoutResult ->
-                drawCanvas { canvas, _ ->
+                drawIntoCanvas { canvas ->
                     state.selectionRange?.let {
                         TextDelegate.paintBackground(
                             it.min,
diff --git a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
index 5548cda..4c51453 100644
--- a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
+++ b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
@@ -43,7 +43,7 @@
 import androidx.compose.ui.gesture.dragGestureFilter
 import androidx.compose.ui.gesture.longPressDragGestureFilter
 import androidx.compose.ui.gesture.pressIndicatorGestureFilter
-import androidx.compose.ui.graphics.drawscope.drawCanvas
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
 import androidx.compose.ui.layout.LayoutCoordinates
 import androidx.compose.ui.onPositioned
 import androidx.compose.ui.platform.ClipboardManagerAmbient
@@ -274,7 +274,7 @@
 
         val drawModifier = Modifier.drawBehind {
             state.layoutResult?.let { layoutResult ->
-                drawCanvas { canvas, _ ->
+                drawIntoCanvas { canvas ->
                     TextFieldDelegate.draw(
                         canvas,
                         value,
diff --git a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt
index 4331f9e..b038486 100644
--- a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt
+++ b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldDelegate.kt
@@ -26,7 +26,6 @@
 import androidx.compose.ui.text.AnnotatedString
 import androidx.compose.ui.text.InternalTextApi
 import androidx.compose.ui.text.Paragraph
-import androidx.compose.ui.text.ParagraphConstraints
 import androidx.compose.ui.text.SpanStyle
 import androidx.compose.ui.text.TextDelegate
 import androidx.compose.ui.text.TextLayoutResult
@@ -79,7 +78,7 @@
         ellipsis = false,
         density = density,
         resourceLoader = resourceLoader,
-        constraints = ParagraphConstraints(width = Float.POSITIVE_INFINITY)
+        width = Float.POSITIVE_INFINITY
     ).height.toIntPx()
 }
 
diff --git a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
index 7658b5e..9441450 100644
--- a/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
+++ b/compose/foundation/foundation-text/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
@@ -255,7 +255,7 @@
 
         clipboardManager?.setText(AnnotatedString(value.getSelectedText()))
 
-        val newCursorOffset = value.selection.end
+        val newCursorOffset = value.selection.max
         val newValue = TextFieldValue(
             text = value.text,
             selection = TextRange(newCursorOffset, newCursorOffset)
@@ -279,7 +279,7 @@
         val newText = value.getTextBeforeSelection(value.text.length) +
                 text +
                 value.getTextAfterSelection(value.text.length)
-        val newCursorOffset = value.selection.start + text.length
+        val newCursorOffset = value.selection.min + text.length
 
         val newValue = TextFieldValue(
             text = newText,
@@ -305,7 +305,7 @@
 
         val newText = value.getTextBeforeSelection(value.text.length) +
                 value.getTextAfterSelection(value.text.length)
-        val newCursorOffset = value.selection.start
+        val newCursorOffset = value.selection.min
 
         val newValue = TextFieldValue(
             text = newText,
diff --git a/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt b/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt
index 2b4d599..fbaf29f 100644
--- a/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt
+++ b/compose/foundation/foundation-text/src/test/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManagerTest.kt
@@ -49,6 +49,8 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
+import org.mockito.invocation.InvocationOnMock
+import org.mockito.stubbing.Answer
 
 @SmallTest
 @RunWith(JUnit4::class)
@@ -106,8 +108,10 @@
             beginOffset
         )
         whenever(state.layoutResult!!.getOffsetForPosition(dragDistance)).thenReturn(dragOffset)
-        whenever(state.layoutResult!!.getWordBoundary(beginOffset)).thenReturn(fakeTextRange)
-        whenever(state.layoutResult!!.getWordBoundary(dragOffset)).thenReturn(dragTextRange)
+        whenever(state.layoutResult!!.getWordBoundary(beginOffset))
+            .thenAnswer(TextRangeAnswer(fakeTextRange))
+        whenever(state.layoutResult!!.getWordBoundary(dragOffset))
+            .thenAnswer(TextRangeAnswer(dragTextRange))
         whenever(state.layoutResult!!.getBidiRunDirection(any()))
             .thenReturn(ResolvedTextDirection.Ltr)
         whenever(state.layoutResult!!.getBoundingBox(any())).thenReturn(Rect.Zero)
@@ -285,6 +289,20 @@
     }
 
     @Test
+    fun copy_selection_reversed() {
+        manager.value = TextFieldValue(
+            text = text,
+            selection = TextRange("Hello".length, "He".length)
+        )
+
+        manager.copy()
+
+        verify(clipboardManager, times(1)).setText(AnnotatedString("llo"))
+        assertThat(value.selection).isEqualTo(TextRange("Hello".length, "Hello".length))
+        assertThat(state.selectionIsOn).isFalse()
+    }
+
+    @Test
     fun paste_clipBoardManager_null() {
         manager.clipboardManager = null
 
@@ -318,6 +336,21 @@
     }
 
     @Test
+    fun paste_selection_reversed() {
+        whenever(clipboardManager.getText()).thenReturn(AnnotatedString("i"))
+        manager.value = TextFieldValue(
+            text = text,
+            selection = TextRange("Hello".length, "H".length)
+        )
+
+        manager.paste()
+
+        assertThat(value.text).isEqualTo("Hi World")
+        assertThat(value.selection).isEqualTo(TextRange("Hi".length, "Hi".length))
+        assertThat(state.selectionIsOn).isFalse()
+    }
+
+    @Test
     fun cut_selection_collapse() {
         manager.value = TextFieldValue(text = text, selection = TextRange(4, 4))
 
@@ -342,6 +375,21 @@
     }
 
     @Test
+    fun cut_selection_reversed() {
+        manager.value = TextFieldValue(
+            text = text,
+            selection = TextRange("Hello".length, "He".length)
+        )
+
+        manager.cut()
+
+        verify(clipboardManager, times(1)).setText(AnnotatedString("llo"))
+        assertThat(value.text).isEqualTo("He World")
+        assertThat(value.selection).isEqualTo(TextRange("He".length, "He".length))
+        assertThat(state.selectionIsOn).isFalse()
+    }
+
+    @Test
     fun showSelectionToolbar_trigger_textToolbar_showMenu_Clipboard_empty_not_show_paste() {
         manager.value = TextFieldValue(
             text = text + text,
@@ -381,3 +429,9 @@
         assertThat(manager.isTextChanged()).isFalse()
     }
 }
+
+// This class is a workaround for the bug that mockito can't stub a method returning inline class.
+// (https://github.com/nhaarman/mockito-kotlin/issues/309).
+internal class TextRangeAnswer(private val textRange: TextRange) : Answer<Any> {
+    override fun answer(invocation: InvocationOnMock?): Any = textRange.packedValue
+}
diff --git a/compose/foundation/foundation/api/current.txt b/compose/foundation/foundation/api/current.txt
index 419cd2e7..f5c2286 100644
--- a/compose/foundation/foundation/api/current.txt
+++ b/compose/foundation/foundation/api/current.txt
@@ -68,7 +68,7 @@
   }
 
   public final class DarkThemeKt {
-    method @androidx.compose.runtime.Composable public static boolean isSystemInDarkTheme();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ComposableContract(readonly=true) public static boolean isSystemInDarkTheme();
   }
 
   @kotlin.RequiresOptIn(message="This foundation API is experimental and is likely to change or be removed in the " + "future.") public @interface ExperimentalFoundationApi {
@@ -297,6 +297,9 @@
   public final class LazyForStateKt {
   }
 
+  public final class LazyGridKt {
+  }
+
   @androidx.compose.runtime.Stable public interface LazyItemScope {
     method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier);
     method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier);
diff --git a/compose/foundation/foundation/api/public_plus_experimental_current.txt b/compose/foundation/foundation/api/public_plus_experimental_current.txt
index 419cd2e7..f5c2286 100644
--- a/compose/foundation/foundation/api/public_plus_experimental_current.txt
+++ b/compose/foundation/foundation/api/public_plus_experimental_current.txt
@@ -68,7 +68,7 @@
   }
 
   public final class DarkThemeKt {
-    method @androidx.compose.runtime.Composable public static boolean isSystemInDarkTheme();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ComposableContract(readonly=true) public static boolean isSystemInDarkTheme();
   }
 
   @kotlin.RequiresOptIn(message="This foundation API is experimental and is likely to change or be removed in the " + "future.") public @interface ExperimentalFoundationApi {
@@ -297,6 +297,9 @@
   public final class LazyForStateKt {
   }
 
+  public final class LazyGridKt {
+  }
+
   @androidx.compose.runtime.Stable public interface LazyItemScope {
     method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier);
     method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier);
diff --git a/compose/foundation/foundation/api/restricted_current.txt b/compose/foundation/foundation/api/restricted_current.txt
index 419cd2e7..f5c2286 100644
--- a/compose/foundation/foundation/api/restricted_current.txt
+++ b/compose/foundation/foundation/api/restricted_current.txt
@@ -68,7 +68,7 @@
   }
 
   public final class DarkThemeKt {
-    method @androidx.compose.runtime.Composable public static boolean isSystemInDarkTheme();
+    method @androidx.compose.runtime.Composable @androidx.compose.runtime.ComposableContract(readonly=true) public static boolean isSystemInDarkTheme();
   }
 
   @kotlin.RequiresOptIn(message="This foundation API is experimental and is likely to change or be removed in the " + "future.") public @interface ExperimentalFoundationApi {
@@ -297,6 +297,9 @@
   public final class LazyForStateKt {
   }
 
+  public final class LazyGridKt {
+  }
+
   @androidx.compose.runtime.Stable public interface LazyItemScope {
     method public androidx.compose.ui.Modifier fillParentMaxHeight(androidx.compose.ui.Modifier);
     method public androidx.compose.ui.Modifier fillParentMaxSize(androidx.compose.ui.Modifier);
diff --git a/compose/foundation/foundation/build.gradle b/compose/foundation/foundation/build.gradle
index da3d897..51cea41 100644
--- a/compose/foundation/foundation/build.gradle
+++ b/compose/foundation/foundation/build.gradle
@@ -29,7 +29,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 }
 
 kotlin {
diff --git a/compose/foundation/foundation/integration-tests/foundation-demos/build.gradle b/compose/foundation/foundation/integration-tests/foundation-demos/build.gradle
index d24890c..2575b16 100644
--- a/compose/foundation/foundation/integration-tests/foundation-demos/build.gradle
+++ b/compose/foundation/foundation/integration-tests/foundation-demos/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/foundation/foundation/samples/build.gradle b/compose/foundation/foundation/samples/build.gradle
index 46852b9..564f3f3 100644
--- a/compose/foundation/foundation/samples/build.gradle
+++ b/compose/foundation/foundation/samples/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyGridTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyGridTest.kt
new file mode 100644
index 0000000..f3f349a
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/lazy/LazyGridTest.kt
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2020 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.foundation.lazy
+
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.preferredHeight
+import androidx.compose.foundation.layout.preferredSize
+import androidx.compose.foundation.layout.preferredWidth
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.unit.dp
+import androidx.test.filters.MediumTest
+import androidx.ui.test.assertIsDisplayed
+import androidx.ui.test.createComposeRule
+import androidx.ui.test.onNodeWithTag
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@MediumTest
+@RunWith(JUnit4::class)
+class LazyGridTest {
+    private val LazyGridTag = "LazyGridTag"
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    @Test
+    fun lazyGridShowsOneItem() {
+        val itemTestTag = "itemTestTag"
+
+        rule.setContent {
+            LazyGrid(
+                columns = 3
+            ) {
+                item {
+                    Spacer(
+                        Modifier.preferredSize(10.dp).testTag(itemTestTag)
+                    )
+                }
+            }
+        }
+
+        rule.onNodeWithTag(itemTestTag)
+            .assertIsDisplayed()
+    }
+
+    @Test
+    fun lazyGridShowsOneRow() {
+        val items = (1..5).map { it.toString() }
+
+        rule.setContent {
+            LazyGrid(
+                columns = 3,
+                modifier = Modifier.preferredHeight(100.dp).preferredWidth(300.dp)
+            ) {
+                items(items) {
+                    Spacer(Modifier.preferredHeight(101.dp).testTag(it))
+                }
+            }
+        }
+
+        rule.onNodeWithTag("1")
+            .assertIsDisplayed()
+
+        rule.onNodeWithTag("2")
+            .assertIsDisplayed()
+
+        rule.onNodeWithTag("3")
+            .assertIsDisplayed()
+
+        rule.onNodeWithTag("4")
+            .assertDoesNotExist()
+
+        rule.onNodeWithTag("5")
+            .assertDoesNotExist()
+    }
+
+    @Test
+    fun lazyGridShowsSecondRowOnScroll() {
+        val items = (1..9).map { it.toString() }
+
+        rule.setContent {
+            LazyGrid(
+                columns = 3,
+                modifier = Modifier.preferredHeight(100.dp).testTag(LazyGridTag)
+            ) {
+                items(items) {
+                    Spacer(Modifier.preferredHeight(101.dp).testTag(it))
+                }
+            }
+        }
+
+        rule.onNodeWithTag(LazyGridTag)
+            .scrollBy(y = 50.dp, density = rule.density)
+
+        rule.onNodeWithTag("4")
+            .assertIsDisplayed()
+
+        rule.onNodeWithTag("5")
+            .assertIsDisplayed()
+
+        rule.onNodeWithTag("6")
+            .assertIsDisplayed()
+
+        rule.onNodeWithTag("7")
+            .assertDoesNotExist()
+
+        rule.onNodeWithTag("8")
+            .assertDoesNotExist()
+
+        rule.onNodeWithTag("9")
+            .assertDoesNotExist()
+    }
+
+    @Test
+    fun lazyGridScrollHidesFirstRow() {
+        val items = (1..9).map { it.toString() }
+
+        rule.setContent {
+            LazyGrid(
+                columns = 3,
+                modifier = Modifier.preferredHeight(200.dp).testTag(LazyGridTag)
+            ) {
+                items(items) {
+                    Spacer(Modifier.preferredHeight(101.dp).testTag(it))
+                }
+            }
+        }
+
+        rule.onNodeWithTag(LazyGridTag)
+            .scrollBy(y = 102.dp, density = rule.density)
+
+        rule.onNodeWithTag("1")
+            .assertDoesNotExist()
+
+        rule.onNodeWithTag("2")
+            .assertDoesNotExist()
+
+        rule.onNodeWithTag("3")
+            .assertDoesNotExist()
+
+        rule.onNodeWithTag("4")
+            .assertIsDisplayed()
+
+        rule.onNodeWithTag("5")
+            .assertIsDisplayed()
+
+        rule.onNodeWithTag("6")
+            .assertIsDisplayed()
+
+        rule.onNodeWithTag("7")
+            .assertIsDisplayed()
+
+        rule.onNodeWithTag("8")
+            .assertIsDisplayed()
+
+        rule.onNodeWithTag("9")
+            .assertIsDisplayed()
+    }
+}
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/DarkTheme.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/DarkTheme.kt
index e35ee4c..785c201 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/DarkTheme.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/DarkTheme.kt
@@ -18,6 +18,7 @@
 
 import android.content.res.Configuration
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.ComposableContract
 import androidx.compose.ui.platform.ConfigurationAmbient
 
 /**
@@ -42,8 +43,8 @@
  * @return `true` if the system is considered to be in 'dark theme'.
  */
 @Composable
+@ComposableContract(readonly = true)
 fun isSystemInDarkTheme(): Boolean {
-    val configuration = ConfigurationAmbient.current
-    return (configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration
-        .UI_MODE_NIGHT_YES
+    val uiMode = ConfigurationAmbient.current.uiMode
+    return (uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
 }
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Border.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Border.kt
index 4d135f5..d7bb036 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Border.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Border.kt
@@ -300,7 +300,7 @@
                         size.height - borderPixelSize * 2
                     )
                 innerPath.addOutline(lastShape!!.createOutline(sizeMinusBorder, density))
-                innerPath.shift(Offset(borderPixelSize, borderPixelSize))
+                innerPath.translate(Offset(borderPixelSize, borderPixelSize))
 
                 // now we calculate the diff between the inner and the outer paths
                 diffPath.op(outerPath, innerPath, PathOperation.difference)
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
index 7d2b287..c259476 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/Scroll.kt
@@ -53,8 +53,11 @@
 import androidx.compose.ui.gesture.scrollorientationlocking.Orientation
 import androidx.compose.ui.platform.AnimationClockAmbient
 import androidx.compose.ui.platform.LayoutDirectionAmbient
+import androidx.compose.ui.semantics.AccessibilityScrollState
 import androidx.compose.ui.semantics.scrollBy
 import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.horizontalAccessibilityScrollState
+import androidx.compose.ui.semantics.verticalAccessibilityScrollState
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
@@ -364,6 +367,16 @@
 ) = composed {
     val semantics = Modifier.semantics {
         if (isScrollable) {
+            val accessibilityScrollState = AccessibilityScrollState(
+                value = state.value,
+                maxValue = state.maxValue,
+                reverseScrolling = reverseScrolling
+            )
+            if (isVertical) {
+                this.verticalAccessibilityScrollState = accessibilityScrollState
+            } else {
+                this.horizontalAccessibilityScrollState = accessibilityScrollState
+            }
             // when b/156389287 is fixed, this should be proper scrollTo with reverse handling
             scrollBy(action = { x: Float, y: Float ->
                 if (isVertical) {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyDsl.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyDsl.kt
index 881a67c..e963bcd 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyDsl.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyDsl.kt
@@ -63,13 +63,13 @@
     )
 }
 
-private class IntervalHolder(
+internal class IntervalHolder(
     val startIndex: Int,
     val content: LazyItemScope.(Int) -> (@Composable () -> Unit)
 )
 
-private class LazyListScopeImpl : LazyListScope {
-    val intervals = mutableListOf<IntervalHolder>()
+internal class LazyListScopeImpl : LazyListScope {
+    private val intervals = mutableListOf<IntervalHolder>()
     var totalSize = 0
 
     fun contentFor(index: Int, scope: LazyItemScope): @Composable () -> Unit {
@@ -220,4 +220,4 @@
     ) {
         index -> scope.contentFor(index, this)
     }
-}
\ No newline at end of file
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyGrid.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyGrid.kt
new file mode 100644
index 0000000..0b92f54
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyGrid.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2020 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.foundation.lazy
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Layout
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.dp
+
+/**
+ * The DSL implementation of a lazy grid layout. It composes only visible rows of the grid.
+ * This API is not stable, please consider using stable components like [LazyColumnFor] and [Row]
+ * to achieve the same result.
+ *
+ * @param columns a fixed number of columns of the grid
+ * @param modifier the modifier to apply to this layout
+ * @param contentPadding specify a padding around the whole content
+ * @param content the [LazyListScope] which describes the content
+ */
+@Composable
+internal fun LazyGrid(
+    columns: Int,
+    modifier: Modifier = Modifier,
+    contentPadding: PaddingValues = PaddingValues(0.dp),
+    content: LazyListScope.() -> Unit
+) {
+    val scope = LazyListScopeImpl()
+    scope.apply(content)
+
+    val rows = (scope.totalSize + columns - 1) / columns
+    LazyFor(
+        itemsCount = rows,
+        modifier = modifier,
+        contentPadding = contentPadding,
+        isVertical = true
+    ) { rowIndex ->
+        {
+            GridRow {
+                for (columnIndex in 0 until columns) {
+                    val itemIndex = rowIndex * columns + columnIndex
+                    if (itemIndex < scope.totalSize) {
+                        scope.contentFor(itemIndex, this).invoke()
+                    } else {
+                        Spacer(Modifier)
+                    }
+                }
+            }
+        }
+    }
+}
+
+@Composable
+private fun GridRow(
+    children: @Composable () -> Unit
+) {
+    // TODO: Implement customisable column widths.
+    Layout(
+        children = children
+    ) { measurables, constraints ->
+
+        // TODO: Avoid int rounding to fill all the width pixels.
+        val itemConstraint = Constraints.fixedWidth(constraints.maxWidth / measurables.size)
+        var maxItemHeight = 0
+        val placeables = measurables.map { measurable ->
+            measurable.measure(itemConstraint)
+                .also {
+                    if (it.height > maxItemHeight) {
+                        maxItemHeight = it.height
+                    }
+                }
+        }
+
+        layout(constraints.maxWidth, maxItemHeight) {
+            var currentXPosition = 0
+            placeables.forEach { placeable ->
+                placeable.placeRelative(x = currentXPosition, y = 0)
+                currentXPosition += placeable.width
+            }
+        }
+    }
+}
diff --git a/compose/integration-tests/benchmark/build.gradle b/compose/integration-tests/benchmark/build.gradle
index 31a7a56..a6dfa41 100644
--- a/compose/integration-tests/benchmark/build.gradle
+++ b/compose/integration-tests/benchmark/build.gradle
@@ -30,7 +30,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation project(":benchmark:benchmark-junit4")
     implementation project(":compose:foundation:foundation-layout")
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphBenchmark.kt b/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphBenchmark.kt
index e338cf5..bd15771 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphBenchmark.kt
+++ b/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphBenchmark.kt
@@ -97,11 +97,11 @@
     private fun paragraph(
         text: String,
         spanStyles: List<AnnotatedString.Range<SpanStyle>>,
-        constraints: ParagraphConstraints
+        width: Float
     ): Paragraph {
         return Paragraph(
             paragraphIntrinsics = paragraphIntrinsics(text, spanStyles),
-            constraints = constraints
+            width = width
         )
     }
 
@@ -167,7 +167,7 @@
                 paragraph(
                     text = annotatedString.text,
                     spanStyles = annotatedString.spanStyles,
-                    constraints = ParagraphConstraints(width)
+                    width = width
                 )
             }
         }
@@ -182,7 +182,7 @@
             benchmarkRule.measureRepeated {
                 val (paragraph, canvas) = runWithTimingDisabled {
                     val (text, style) = text(textGenerator)
-                    val paragraph = paragraph(text, style, ParagraphConstraints(width))
+                    val paragraph = paragraph(text, style, width)
                     val canvas = Canvas(
                         ImageAsset(paragraph.width.roundToInt(), paragraph.height.roundToInt())
                     )
@@ -202,7 +202,7 @@
             val (text, style) = text(textGenerator)
             // create a new paragraph and use a smaller width to get
             // some line breaking in the result
-            val paragraph = paragraph(text, style, ParagraphConstraints(width))
+            val paragraph = paragraph(text, style, width)
             val canvas = Canvas(
                 ImageAsset(paragraph.width.roundToInt(), paragraph.height.roundToInt())
             )
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphMethodBenchmark.kt b/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphMethodBenchmark.kt
index 2b0f875..6077d8e 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphMethodBenchmark.kt
+++ b/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/ParagraphMethodBenchmark.kt
@@ -87,9 +87,7 @@
         val paragraphIntrinsics = paragraphIntrinsics(textGenerator, textLength)
         return Paragraph(
             paragraphIntrinsics = paragraphIntrinsics,
-            constraints = ParagraphConstraints(
-                width = paragraphIntrinsics.maxIntrinsicWidth / preferredLineCount
-            )
+            width = paragraphIntrinsics.maxIntrinsicWidth / preferredLineCount
         )
     }
 
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/input/EditProcessorBenchmark.kt b/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/input/EditProcessorBenchmark.kt
index f30d311..04cc171 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/input/EditProcessorBenchmark.kt
+++ b/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/text/input/EditProcessorBenchmark.kt
@@ -63,8 +63,10 @@
                 TestScenario(listOf(SetComposingTextEditOp("Android", 1)), "Insert composition"),
                 TestScenario(listOf(SetComposingRegionEditOp(0, 1)), "Set composition"),
                 TestScenario(listOf(DeleteSurroundingTextEditOp(0, 1)), "Delete text"),
-                TestScenario(listOf(DeleteSurroundingTextInCodePointsEditOp(0, 1)),
-                    "Delete text in code points"),
+                TestScenario(
+                    listOf(DeleteSurroundingTextInCodePointsEditOp(0, 1)),
+                    "Delete text in code points"
+                ),
                 TestScenario(listOf(SetSelectionEditOp(0, 1)), "Set selection"),
                 TestScenario(listOf(BackspaceKeyEditOp()), "Backspace"),
                 TestScenario(listOf(MoveCursorEditOp(1)), "Cursor movement")
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/LayoutNodeModifierBenchmark.kt b/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/LayoutNodeModifierBenchmark.kt
index ec1599150..4619d28 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/LayoutNodeModifierBenchmark.kt
+++ b/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/LayoutNodeModifierBenchmark.kt
@@ -96,9 +96,8 @@
         rule.activityTestRule.runOnUiThread {
             val composeView = rule.findAndroidOwner()
             val root = composeView.root
-            val selection = root.children[0]
-            check(selection.children.size == 1) { "Expecting only a Box" }
-            layoutNode = selection.children[0]
+            check(root.children.size == 1) { "Expecting only a Box" }
+            layoutNode = root.children[0]
             check(layoutNode.children.isEmpty()) { "Box should be empty" }
         }
     }
@@ -137,7 +136,8 @@
 
         override fun apply(base: Statement, description: Description?): Statement {
             val statement = benchmarkRule.apply(
-                activityTestRule.apply(base, description), description!!)
+                activityTestRule.apply(base, description), description!!
+            )
             return disableTransitionsRule.apply(statement, description)
         }
 
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/NestedScrollerBenchmark.kt b/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/NestedScrollerBenchmark.kt
index a5e8a97..855abaa 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/NestedScrollerBenchmark.kt
+++ b/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/NestedScrollerBenchmark.kt
@@ -63,20 +63,17 @@
 
     @Test
     fun changeScroll_measure() {
-        benchmarkRule.toggleStateBenchmarkMeasure(nestedScrollerCaseFactory,
-            toggleCausesRecompose = false)
+        benchmarkRule.toggleStateBenchmarkMeasure(nestedScrollerCaseFactory)
     }
 
     @Test
     fun changeScroll_layout() {
-        benchmarkRule.toggleStateBenchmarkLayout(nestedScrollerCaseFactory,
-            toggleCausesRecompose = false)
+        benchmarkRule.toggleStateBenchmarkLayout(nestedScrollerCaseFactory)
     }
 
     @Test
     fun changeScroll_draw() {
-        benchmarkRule.toggleStateBenchmarkDraw(nestedScrollerCaseFactory,
-            toggleCausesRecompose = false)
+        benchmarkRule.toggleStateBenchmarkDraw(nestedScrollerCaseFactory)
     }
 
     @Test
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/ScrollerBenchmark.kt b/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/ScrollerBenchmark.kt
index 03aca7e..910e55b 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/ScrollerBenchmark.kt
+++ b/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/ScrollerBenchmark.kt
@@ -63,18 +63,17 @@
 
     @Test
     fun changeScroll_measure() {
-        benchmarkRule.toggleStateBenchmarkMeasure(scrollerCaseFactory,
-            toggleCausesRecompose = false)
+        benchmarkRule.toggleStateBenchmarkMeasure(scrollerCaseFactory)
     }
 
     @Test
     fun changeScroll_layout() {
-        benchmarkRule.toggleStateBenchmarkLayout(scrollerCaseFactory, toggleCausesRecompose = false)
+        benchmarkRule.toggleStateBenchmarkLayout(scrollerCaseFactory)
     }
 
     @Test
     fun changeScroll_draw() {
-        benchmarkRule.toggleStateBenchmarkDraw(scrollerCaseFactory, toggleCausesRecompose = false)
+        benchmarkRule.toggleStateBenchmarkDraw(scrollerCaseFactory)
     }
 
     @Test
diff --git a/compose/integration-tests/build.gradle b/compose/integration-tests/build.gradle
index ed23152..a99f159 100644
--- a/compose/integration-tests/build.gradle
+++ b/compose/integration-tests/build.gradle
@@ -30,7 +30,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/integration-tests/demos/build.gradle b/compose/integration-tests/demos/build.gradle
index 7772833..432bfc2 100644
--- a/compose/integration-tests/demos/build.gradle
+++ b/compose/integration-tests/demos/build.gradle
@@ -10,7 +10,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation project(":compose:androidview:androidview:integration-tests:androidview-demos")
     implementation project(":compose:animation:animation:integration-tests:animation-demos")
diff --git a/compose/integration-tests/demos/common/build.gradle b/compose/integration-tests/demos/common/build.gradle
index 1024dd3..46b1585 100644
--- a/compose/integration-tests/demos/common/build.gradle
+++ b/compose/integration-tests/demos/common/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
     implementation(KOTLIN_STDLIB)
 
     api "androidx.activity:activity:1.2.0-alpha02"
diff --git a/compose/integration-tests/src/androidTest/java/androidx/ui/integration/test/VectorAssetTest.kt b/compose/integration-tests/src/androidTest/java/androidx/ui/integration/test/VectorAssetTest.kt
index 7438ae2..09b34ae 100644
--- a/compose/integration-tests/src/androidTest/java/androidx/ui/integration/test/VectorAssetTest.kt
+++ b/compose/integration-tests/src/androidTest/java/androidx/ui/integration/test/VectorAssetTest.kt
@@ -106,12 +106,28 @@
             assertEquals(Color.Blue.toArgb(), getPixel(width / 2, height / 2))
 
             assertEquals(Color.Red.toArgb(), getPixel(insetRectSize + 2, insetRectSize + 2))
-            assertEquals(Color.Red.toArgb(), getPixel(width - insetRectSize - 2,
-                insetRectSize + 2))
-            assertEquals(Color.Red.toArgb(), getPixel(insetRectSize + 2,
-                height - insetRectSize - 2))
-            assertEquals(Color.Red.toArgb(), getPixel(width - insetRectSize - 2, height -
-                    insetRectSize - 2))
+            assertEquals(
+                Color.Red.toArgb(),
+                getPixel(
+                    width - insetRectSize - 2,
+                    insetRectSize + 2
+                )
+            )
+            assertEquals(
+                Color.Red.toArgb(),
+                getPixel(
+                    insetRectSize + 2,
+                    height - insetRectSize - 2
+                )
+            )
+            assertEquals(
+                Color.Red.toArgb(),
+                getPixel(
+                    width - insetRectSize - 2,
+                    height -
+                        insetRectSize - 2
+                )
+            )
         }
     }
 }
diff --git a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/SimpleRadioButton2TestCase.kt b/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/SimpleRadioButton2TestCase.kt
index 651acc6..20fcfae 100644
--- a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/SimpleRadioButton2TestCase.kt
+++ b/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/SimpleRadioButton2TestCase.kt
@@ -26,7 +26,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.geometry.shift
+import androidx.compose.ui.geometry.translate
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Outline
 import androidx.compose.ui.graphics.Path
@@ -62,11 +62,13 @@
 private fun Outline.offset(size: Float): Outline {
     val offset = Offset(size, size)
     return when (this) {
-        is Outline.Rectangle -> Outline.Rectangle(rect.shift(offset))
-        is Outline.Rounded -> Outline.Rounded(roundRect.shift(offset))
-        is Outline.Generic -> Outline.Generic(Path().apply {
-            addPath(path)
-            shift(offset)
-        })
+        is Outline.Rectangle -> Outline.Rectangle(rect.translate(offset))
+        is Outline.Rounded -> Outline.Rounded(roundRect.translate(offset))
+        is Outline.Generic -> Outline.Generic(
+            Path().apply {
+                addPath(path)
+                translate(offset)
+            }
+        )
     }
 }
diff --git a/compose/integration-tests/src/main/java/androidx/ui/integration/test/framework/VectorAssetTestCase.kt b/compose/integration-tests/src/main/java/androidx/ui/integration/test/framework/VectorAssetTestCase.kt
index 8f1e01e..3b55f60 100644
--- a/compose/integration-tests/src/main/java/androidx/ui/integration/test/framework/VectorAssetTestCase.kt
+++ b/compose/integration-tests/src/main/java/androidx/ui/integration/test/framework/VectorAssetTestCase.kt
@@ -45,9 +45,11 @@
     @Composable
     override fun emitContent() {
         Box {
-            Box(Modifier.testTag(testTag)
-                .preferredSize(24.dp)
-                .paint(VectorPainter(getVectorAsset())))
+            Box(
+                Modifier.testTag(testTag)
+                    .preferredSize(24.dp)
+                    .paint(VectorPainter(getVectorAsset()))
+            )
         }
     }
 
diff --git a/compose/material/material-icons-core/samples/build.gradle b/compose/material/material-icons-core/samples/build.gradle
index 138b96b..4d6d462 100644
--- a/compose/material/material-icons-core/samples/build.gradle
+++ b/compose/material/material-icons-core/samples/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/material/material-icons-extended/build.gradle b/compose/material/material-icons-extended/build.gradle
index 2ac2813..6cd7c12 100644
--- a/compose/material/material-icons-extended/build.gradle
+++ b/compose/material/material-icons-extended/build.gradle
@@ -30,7 +30,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 }
 
 kotlin {
diff --git a/compose/material/material/api/current.txt b/compose/material/material/api/current.txt
index d99fdf3..bb85bfc 100644
--- a/compose/material/material/api/current.txt
+++ b/compose/material/material/api/current.txt
@@ -189,8 +189,12 @@
   }
 
   public final class CheckboxKt {
-    method @androidx.compose.runtime.Composable public static void Checkbox-D3vZVBM(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long checkedColor = MaterialTheme.colors.secondary, long uncheckedColor = CheckboxConstants.defaultUncheckedColor);
-    method @androidx.compose.runtime.Composable public static void TriStateCheckbox-w6h9dZI(androidx.compose.foundation.selection.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long checkMarkColor = CheckboxConstants.animateDefaultCheckmarkColor(state), long boxColor = CheckboxConstants.animateDefaultBoxColor(state, enabled), long borderColor = CheckboxConstants.animateDefaultBorderColor(state, enabled));
+    method @androidx.compose.runtime.Composable public static void Checkbox-JW8VE8g(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long checkedColor = MaterialTheme.colors.secondary, long uncheckedColor = CheckboxConstants.defaultUncheckedColor);
+    method @androidx.compose.runtime.Composable public static void TriStateCheckbox-yIvEug4(androidx.compose.foundation.selection.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long checkMarkColor = CheckboxConstants.animateDefaultCheckmarkColor(state), long boxColor = CheckboxConstants.animateDefaultBoxColor(state, enabled), long borderColor = CheckboxConstants.animateDefaultBorderColor(state, enabled));
   }
 
   @androidx.compose.runtime.Stable public final class Colors {
@@ -365,8 +369,12 @@
   }
 
   public final class IconButtonKt {
-    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
-    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
+    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> icon);
+    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> icon);
   }
 
   public final class ListItemKt {
@@ -389,7 +397,9 @@
 
   public final class MenuKt {
     method @androidx.compose.runtime.Composable public static void DropdownMenu-iBtHMRc(kotlin.jvm.functions.Function0<kotlin.Unit> toggle, boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, androidx.compose.ui.Modifier toggleModifier = Modifier, long dropdownOffset = Position(0.dp, 0.dp), androidx.compose.ui.Modifier dropdownModifier = Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> dropdownContent);
-    method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   public final class ModalBottomSheetConstants {
@@ -427,8 +437,12 @@
   }
 
   public final class OutlinedTextFieldKt {
-    method @androidx.compose.runtime.Composable public static void OutlinedTextField--KhY4tc(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
-    method @androidx.compose.runtime.Composable public static void OutlinedTextField-YV8zA4E(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
+    method @androidx.compose.runtime.Composable public static void OutlinedTextField-NT1NBPE(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
+    method @androidx.compose.runtime.Composable public static void OutlinedTextField-OHK2xX0(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
   }
 
   public final class ProgressIndicatorConstants {
@@ -457,7 +471,9 @@
   }
 
   public final class RadioButtonKt {
-    method @androidx.compose.runtime.Composable public static void RadioButton-5r5xgFI(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long color = RadioButtonConstants.animateDefaultColor(selected, enabled));
+    method @androidx.compose.runtime.Composable public static void RadioButton-BNs5H-w(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long color = RadioButtonConstants.animateDefaultColor(selected, enabled));
   }
 
   @androidx.compose.runtime.Immutable public final class ResistanceConfig {
@@ -508,7 +524,9 @@
   }
 
   public final class SliderKt {
-    method @androidx.compose.runtime.Composable public static void Slider-OaNVCSA(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange = 0.0 .. 1.0, @IntRange(from=0) int steps = 0, kotlin.jvm.functions.Function0<kotlin.Unit> onValueChangeEnd = {}, long thumbColor = MaterialTheme.colors.primary, long activeTrackColor = MaterialTheme.colors.primary, long inactiveTrackColor = activeTrackColor.copy(InactiveTrackColorAlpha), long activeTickColor = MaterialTheme.colors.onPrimary.copy(TickColorAlpha), long inactiveTickColor = activeTrackColor.copy(TickColorAlpha));
+    method @androidx.compose.runtime.Composable public static void Slider-B7rb6FQ(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange = 0.0 .. 1.0, @IntRange(from=0) int steps = 0, kotlin.jvm.functions.Function0<kotlin.Unit> onValueChangeEnd = {}, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long thumbColor = MaterialTheme.colors.primary, long activeTrackColor = MaterialTheme.colors.primary, long inactiveTrackColor = activeTrackColor.copy(InactiveTrackColorAlpha), long activeTickColor = MaterialTheme.colors.onPrimary.copy(TickColorAlpha), long inactiveTickColor = activeTrackColor.copy(TickColorAlpha));
   }
 
   public final class SnackbarConstants {
@@ -624,7 +642,9 @@
   }
 
   public final class SwitchKt {
-    method @androidx.compose.runtime.Composable public static void Switch-y3bT5vQ(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long color = MaterialTheme.colors.secondaryVariant);
+    method @androidx.compose.runtime.Composable public static void Switch-vndggBo(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long color = MaterialTheme.colors.secondaryVariant);
   }
 
   public final class TabConstants {
@@ -669,8 +689,12 @@
   }
 
   public final class TextFieldKt {
-    method @androidx.compose.runtime.Composable public static void TextField-enE39lU(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
-    method @androidx.compose.runtime.Composable public static void TextField-tHV9mug(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
+    method @androidx.compose.runtime.Composable public static void TextField-LTmrouY(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
+    method @androidx.compose.runtime.Composable public static void TextField-WI3iwFk(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
     field public static final float ContainerAlpha = 0.12f;
   }
 
diff --git a/compose/material/material/api/public_plus_experimental_current.txt b/compose/material/material/api/public_plus_experimental_current.txt
index d99fdf3..bb85bfc 100644
--- a/compose/material/material/api/public_plus_experimental_current.txt
+++ b/compose/material/material/api/public_plus_experimental_current.txt
@@ -189,8 +189,12 @@
   }
 
   public final class CheckboxKt {
-    method @androidx.compose.runtime.Composable public static void Checkbox-D3vZVBM(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long checkedColor = MaterialTheme.colors.secondary, long uncheckedColor = CheckboxConstants.defaultUncheckedColor);
-    method @androidx.compose.runtime.Composable public static void TriStateCheckbox-w6h9dZI(androidx.compose.foundation.selection.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long checkMarkColor = CheckboxConstants.animateDefaultCheckmarkColor(state), long boxColor = CheckboxConstants.animateDefaultBoxColor(state, enabled), long borderColor = CheckboxConstants.animateDefaultBorderColor(state, enabled));
+    method @androidx.compose.runtime.Composable public static void Checkbox-JW8VE8g(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long checkedColor = MaterialTheme.colors.secondary, long uncheckedColor = CheckboxConstants.defaultUncheckedColor);
+    method @androidx.compose.runtime.Composable public static void TriStateCheckbox-yIvEug4(androidx.compose.foundation.selection.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long checkMarkColor = CheckboxConstants.animateDefaultCheckmarkColor(state), long boxColor = CheckboxConstants.animateDefaultBoxColor(state, enabled), long borderColor = CheckboxConstants.animateDefaultBorderColor(state, enabled));
   }
 
   @androidx.compose.runtime.Stable public final class Colors {
@@ -365,8 +369,12 @@
   }
 
   public final class IconButtonKt {
-    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
-    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
+    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> icon);
+    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> icon);
   }
 
   public final class ListItemKt {
@@ -389,7 +397,9 @@
 
   public final class MenuKt {
     method @androidx.compose.runtime.Composable public static void DropdownMenu-iBtHMRc(kotlin.jvm.functions.Function0<kotlin.Unit> toggle, boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, androidx.compose.ui.Modifier toggleModifier = Modifier, long dropdownOffset = Position(0.dp, 0.dp), androidx.compose.ui.Modifier dropdownModifier = Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> dropdownContent);
-    method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   public final class ModalBottomSheetConstants {
@@ -427,8 +437,12 @@
   }
 
   public final class OutlinedTextFieldKt {
-    method @androidx.compose.runtime.Composable public static void OutlinedTextField--KhY4tc(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
-    method @androidx.compose.runtime.Composable public static void OutlinedTextField-YV8zA4E(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
+    method @androidx.compose.runtime.Composable public static void OutlinedTextField-NT1NBPE(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
+    method @androidx.compose.runtime.Composable public static void OutlinedTextField-OHK2xX0(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
   }
 
   public final class ProgressIndicatorConstants {
@@ -457,7 +471,9 @@
   }
 
   public final class RadioButtonKt {
-    method @androidx.compose.runtime.Composable public static void RadioButton-5r5xgFI(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long color = RadioButtonConstants.animateDefaultColor(selected, enabled));
+    method @androidx.compose.runtime.Composable public static void RadioButton-BNs5H-w(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long color = RadioButtonConstants.animateDefaultColor(selected, enabled));
   }
 
   @androidx.compose.runtime.Immutable public final class ResistanceConfig {
@@ -508,7 +524,9 @@
   }
 
   public final class SliderKt {
-    method @androidx.compose.runtime.Composable public static void Slider-OaNVCSA(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange = 0.0 .. 1.0, @IntRange(from=0) int steps = 0, kotlin.jvm.functions.Function0<kotlin.Unit> onValueChangeEnd = {}, long thumbColor = MaterialTheme.colors.primary, long activeTrackColor = MaterialTheme.colors.primary, long inactiveTrackColor = activeTrackColor.copy(InactiveTrackColorAlpha), long activeTickColor = MaterialTheme.colors.onPrimary.copy(TickColorAlpha), long inactiveTickColor = activeTrackColor.copy(TickColorAlpha));
+    method @androidx.compose.runtime.Composable public static void Slider-B7rb6FQ(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange = 0.0 .. 1.0, @IntRange(from=0) int steps = 0, kotlin.jvm.functions.Function0<kotlin.Unit> onValueChangeEnd = {}, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long thumbColor = MaterialTheme.colors.primary, long activeTrackColor = MaterialTheme.colors.primary, long inactiveTrackColor = activeTrackColor.copy(InactiveTrackColorAlpha), long activeTickColor = MaterialTheme.colors.onPrimary.copy(TickColorAlpha), long inactiveTickColor = activeTrackColor.copy(TickColorAlpha));
   }
 
   public final class SnackbarConstants {
@@ -624,7 +642,9 @@
   }
 
   public final class SwitchKt {
-    method @androidx.compose.runtime.Composable public static void Switch-y3bT5vQ(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long color = MaterialTheme.colors.secondaryVariant);
+    method @androidx.compose.runtime.Composable public static void Switch-vndggBo(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long color = MaterialTheme.colors.secondaryVariant);
   }
 
   public final class TabConstants {
@@ -669,8 +689,12 @@
   }
 
   public final class TextFieldKt {
-    method @androidx.compose.runtime.Composable public static void TextField-enE39lU(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
-    method @androidx.compose.runtime.Composable public static void TextField-tHV9mug(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
+    method @androidx.compose.runtime.Composable public static void TextField-LTmrouY(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
+    method @androidx.compose.runtime.Composable public static void TextField-WI3iwFk(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
     field public static final float ContainerAlpha = 0.12f;
   }
 
diff --git a/compose/material/material/api/restricted_current.txt b/compose/material/material/api/restricted_current.txt
index d99fdf3..bb85bfc 100644
--- a/compose/material/material/api/restricted_current.txt
+++ b/compose/material/material/api/restricted_current.txt
@@ -189,8 +189,12 @@
   }
 
   public final class CheckboxKt {
-    method @androidx.compose.runtime.Composable public static void Checkbox-D3vZVBM(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long checkedColor = MaterialTheme.colors.secondary, long uncheckedColor = CheckboxConstants.defaultUncheckedColor);
-    method @androidx.compose.runtime.Composable public static void TriStateCheckbox-w6h9dZI(androidx.compose.foundation.selection.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long checkMarkColor = CheckboxConstants.animateDefaultCheckmarkColor(state), long boxColor = CheckboxConstants.animateDefaultBoxColor(state, enabled), long borderColor = CheckboxConstants.animateDefaultBorderColor(state, enabled));
+    method @androidx.compose.runtime.Composable public static void Checkbox-JW8VE8g(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long checkedColor = MaterialTheme.colors.secondary, long uncheckedColor = CheckboxConstants.defaultUncheckedColor);
+    method @androidx.compose.runtime.Composable public static void TriStateCheckbox-yIvEug4(androidx.compose.foundation.selection.ToggleableState state, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long checkMarkColor = CheckboxConstants.animateDefaultCheckmarkColor(state), long boxColor = CheckboxConstants.animateDefaultBoxColor(state, enabled), long borderColor = CheckboxConstants.animateDefaultBorderColor(state, enabled));
   }
 
   @androidx.compose.runtime.Stable public final class Colors {
@@ -365,8 +369,12 @@
   }
 
   public final class IconButtonKt {
-    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
-    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> icon);
+    method @androidx.compose.runtime.Composable public static void IconButton(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> icon);
+    method @androidx.compose.runtime.Composable public static void IconToggleButton(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> icon);
   }
 
   public final class ListItemKt {
@@ -389,7 +397,9 @@
 
   public final class MenuKt {
     method @androidx.compose.runtime.Composable public static void DropdownMenu-iBtHMRc(kotlin.jvm.functions.Function0<kotlin.Unit> toggle, boolean expanded, kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, androidx.compose.ui.Modifier toggleModifier = Modifier, long dropdownOffset = Position(0.dp, 0.dp), androidx.compose.ui.Modifier dropdownModifier = Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit> dropdownContent);
-    method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void DropdownMenuItem(kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   public final class ModalBottomSheetConstants {
@@ -427,8 +437,12 @@
   }
 
   public final class OutlinedTextFieldKt {
-    method @androidx.compose.runtime.Composable public static void OutlinedTextField--KhY4tc(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
-    method @androidx.compose.runtime.Composable public static void OutlinedTextField-YV8zA4E(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
+    method @androidx.compose.runtime.Composable public static void OutlinedTextField-NT1NBPE(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
+    method @androidx.compose.runtime.Composable public static void OutlinedTextField-OHK2xX0(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error);
   }
 
   public final class ProgressIndicatorConstants {
@@ -457,7 +471,9 @@
   }
 
   public final class RadioButtonKt {
-    method @androidx.compose.runtime.Composable public static void RadioButton-5r5xgFI(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long color = RadioButtonConstants.animateDefaultColor(selected, enabled));
+    method @androidx.compose.runtime.Composable public static void RadioButton-BNs5H-w(boolean selected, kotlin.jvm.functions.Function0<kotlin.Unit> onClick, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long color = RadioButtonConstants.animateDefaultColor(selected, enabled));
   }
 
   @androidx.compose.runtime.Immutable public final class ResistanceConfig {
@@ -508,7 +524,9 @@
   }
 
   public final class SliderKt {
-    method @androidx.compose.runtime.Composable public static void Slider-OaNVCSA(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange = 0.0 .. 1.0, @IntRange(from=0) int steps = 0, kotlin.jvm.functions.Function0<kotlin.Unit> onValueChangeEnd = {}, long thumbColor = MaterialTheme.colors.primary, long activeTrackColor = MaterialTheme.colors.primary, long inactiveTrackColor = activeTrackColor.copy(InactiveTrackColorAlpha), long activeTickColor = MaterialTheme.colors.onPrimary.copy(TickColorAlpha), long inactiveTickColor = activeTrackColor.copy(TickColorAlpha));
+    method @androidx.compose.runtime.Composable public static void Slider-B7rb6FQ(float value, kotlin.jvm.functions.Function1<? super java.lang.Float,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, kotlin.ranges.ClosedFloatingPointRange<java.lang.Float> valueRange = 0.0 .. 1.0, @IntRange(from=0) int steps = 0, kotlin.jvm.functions.Function0<kotlin.Unit> onValueChangeEnd = {}, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long thumbColor = MaterialTheme.colors.primary, long activeTrackColor = MaterialTheme.colors.primary, long inactiveTrackColor = activeTrackColor.copy(InactiveTrackColorAlpha), long activeTickColor = MaterialTheme.colors.onPrimary.copy(TickColorAlpha), long inactiveTickColor = activeTrackColor.copy(TickColorAlpha));
   }
 
   public final class SnackbarConstants {
@@ -624,7 +642,9 @@
   }
 
   public final class SwitchKt {
-    method @androidx.compose.runtime.Composable public static void Switch-y3bT5vQ(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, long color = MaterialTheme.colors.secondaryVariant);
+    method @androidx.compose.runtime.Composable public static void Switch-vndggBo(boolean checked, kotlin.jvm.functions.Function1<? super java.lang.Boolean,kotlin.Unit> onCheckedChange, androidx.compose.ui.Modifier modifier = Modifier, boolean enabled = true, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long color = MaterialTheme.colors.secondaryVariant);
   }
 
   public final class TabConstants {
@@ -669,8 +689,12 @@
   }
 
   public final class TextFieldKt {
-    method @androidx.compose.runtime.Composable public static void TextField-enE39lU(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
-    method @androidx.compose.runtime.Composable public static void TextField-tHV9mug(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
+    method @androidx.compose.runtime.Composable public static void TextField-LTmrouY(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
+    method @androidx.compose.runtime.Composable public static void TextField-WI3iwFk(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, androidx.compose.ui.Modifier modifier = Modifier, androidx.compose.ui.text.TextStyle textStyle = currentTextStyle(), kotlin.jvm.functions.Function0<kotlin.Unit>? label = null, kotlin.jvm.functions.Function0<kotlin.Unit>? placeholder = null, kotlin.jvm.functions.Function0<kotlin.Unit>? leadingIcon = null, kotlin.jvm.functions.Function0<kotlin.Unit>? trailingIcon = null, boolean isErrorValue = false, androidx.compose.ui.text.input.VisualTransformation visualTransformation = VisualTransformation.None, androidx.compose.ui.text.input.KeyboardType keyboardType = KeyboardType.Text, androidx.compose.ui.text.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function2<? super androidx.compose.ui.text.input.ImeAction,? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onImeActionPerformed = { _, _ ->  }, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.SoftwareKeyboardController,kotlin.Unit> onTextInputStarted = {}, androidx.compose.foundation.InteractionState interactionState = remember({ 
+    return <init>()
+}), long activeColor = MaterialTheme.colors.primary, long inactiveColor = MaterialTheme.colors.onSurface, long errorColor = MaterialTheme.colors.error, long backgroundColor = MaterialTheme.colors.onSurface.copy(ContainerAlpha), androidx.compose.ui.graphics.Shape shape = MaterialTheme.shapes.small.copy(ZeroCornerSize, ZeroCornerSize));
     field public static final float ContainerAlpha = 0.12f;
   }
 
diff --git a/compose/material/material/build.gradle b/compose/material/material/build.gradle
index ef5e787..fdcbca3 100644
--- a/compose/material/material/build.gradle
+++ b/compose/material/material/build.gradle
@@ -29,7 +29,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 }
 
 kotlin {
diff --git a/compose/material/material/integration-tests/material-demos/build.gradle b/compose/material/material/integration-tests/material-demos/build.gradle
index 73503977..52ad8421 100644
--- a/compose/material/material/integration-tests/material-demos/build.gradle
+++ b/compose/material/material/integration-tests/material-demos/build.gradle
@@ -11,7 +11,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
     implementation(KOTLIN_STDLIB)
 
     implementation project(":compose:androidview:androidview")
diff --git a/compose/material/material/integration-tests/material-studies/build.gradle b/compose/material/material/integration-tests/material-studies/build.gradle
index 65d7eea..d1b3805 100644
--- a/compose/material/material/integration-tests/material-studies/build.gradle
+++ b/compose/material/material/integration-tests/material-studies/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/material/material/samples/build.gradle b/compose/material/material/samples/build.gradle
index 07e7f20..e0c3d61 100644
--- a/compose/material/material/samples/build.gradle
+++ b/compose/material/material/samples/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
index b10ec7e..44b6e81 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/textfield/TextFieldTest.kt
@@ -16,7 +16,10 @@
 
 package androidx.compose.material.textfield
 
+import android.content.Context
 import android.os.Build
+import android.view.View
+import android.view.inputmethod.InputMethodManager
 import androidx.compose.foundation.Box
 import androidx.compose.foundation.Text
 import androidx.compose.foundation.background
@@ -37,9 +40,12 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus
 import androidx.compose.ui.focus.ExperimentalFocus
+import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.isFocused
 import androidx.compose.ui.focusObserver
+import androidx.compose.ui.focusRequester
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.RectangleShape
@@ -47,6 +53,7 @@
 import androidx.compose.ui.node.Ref
 import androidx.compose.ui.onPositioned
 import androidx.compose.ui.platform.TextInputServiceAmbient
+import androidx.compose.ui.platform.ViewAmbient
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.text.SoftwareKeyboardController
 import androidx.compose.ui.text.input.ImeAction
@@ -182,6 +189,71 @@
     }
 
     @Test
+    fun testTextField_showHideKeyboardBasedOnFocus() {
+        val parentFocusRequester = FocusRequester()
+        val focusRequester = FocusRequester()
+        lateinit var hostView: View
+        rule.setMaterialContent {
+            hostView = ViewAmbient.current
+            Box {
+                TextField(
+                    modifier = Modifier
+                        .focusRequester(parentFocusRequester)
+                        .focus()
+                        .focusRequester(focusRequester)
+                        .testTag(TextfieldTag),
+                    value = "input",
+                    onValueChange = {},
+                    label = {}
+                )
+            }
+        }
+
+        // Shows keyboard when the text field is focused.
+        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle { assertThat(hostView.isSoftwareKeyboardShown).isTrue() }
+
+        // Hides keyboard when the text field is not focused.
+        rule.runOnIdle { parentFocusRequester.requestFocus() }
+        rule.runOnIdle { assertThat(hostView.isSoftwareKeyboardShown).isFalse() }
+    }
+
+    @Test
+    fun testTextField_clickingOnTextAfterDismissingKeyboard_showsKeyboard() {
+        val parentFocusRequester = FocusRequester()
+        val focusRequester = FocusRequester()
+        lateinit var softwareKeyboardController: SoftwareKeyboardController
+        lateinit var hostView: View
+        rule.setMaterialContent {
+            hostView = ViewAmbient.current
+            Box {
+                TextField(
+                    modifier = Modifier
+                        .focusRequester(parentFocusRequester)
+                        .focus()
+                        .focusRequester(focusRequester)
+                        .testTag(TextfieldTag),
+                    value = "input",
+                    onValueChange = {},
+                    onTextInputStarted = { softwareKeyboardController = it },
+                    label = {}
+                )
+            }
+        }
+
+        // Shows keyboard when the text field is focused.
+        rule.runOnIdle { focusRequester.requestFocus() }
+        rule.runOnIdle { assertThat(hostView.isSoftwareKeyboardShown).isTrue() }
+
+        // Hide keyboard.
+        rule.runOnIdle { softwareKeyboardController.hideSoftwareKeyboard() }
+
+        // Clicking on the text field shows the keyboard.
+        rule.onNodeWithTag(TextfieldTag).performClick()
+        rule.runOnIdle { assertThat(hostView.isSoftwareKeyboardShown).isTrue() }
+    }
+
+    @Test
     fun testTextField_labelPosition_initial_withDefaultHeight() {
         val labelSize = Ref<IntSize>()
         val labelPosition = Ref<Offset>()
@@ -797,4 +869,12 @@
         rule.onNodeWithTag(TextfieldTag).performClick()
         rule.clockTestRule.advanceClock(200L)
     }
+
+    private val View.isSoftwareKeyboardShown: Boolean get() {
+        val inputMethodManager =
+            context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
+        // TODO(b/163742556): This is just a proxy for software keyboard visibility. Find a better
+        //  way to check if the software keyboard is shown.
+        return inputMethodManager.isAcceptingText()
+    }
 }
\ No newline at end of file
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AppBar.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AppBar.kt
index 5f97c4f8..86282a4 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AppBar.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/AppBar.kt
@@ -236,7 +236,7 @@
         val cutoutStartY = -cutoutRadius
 
         addOutline(cutoutShape.createOutline(cutoutSize, density))
-        shift(Offset(cutoutStartX, cutoutStartY))
+        translate(Offset(cutoutStartX, cutoutStartY))
 
         // TODO: consider exposing the custom cutout shape instead of just replacing circle shapes?
         if (cutoutShape == CircleShape) {
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Checkbox.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Checkbox.kt
index a362e7e..b7d9f70 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Checkbox.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Checkbox.kt
@@ -25,6 +25,8 @@
 import androidx.compose.animation.core.tween
 import androidx.compose.animation.transition
 import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.InteractionState
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.wrapContentSize
@@ -63,6 +65,10 @@
  * @param modifier Modifier to be applied to the layout of the checkbox
  * @param enabled enabled whether or not this [Checkbox] will handle input events and appear
  * enabled for semantics purposes
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this Checkbox. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this Checkbox in different [Interaction]s.
  * @param checkedColor color of the box of the Checkbox when [checked]. See
  * [TriStateCheckbox] to fully customize the color of the checkmark / box / border in different
  * states.
@@ -76,12 +82,14 @@
     onCheckedChange: (Boolean) -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
+    interactionState: InteractionState = remember { InteractionState() },
     checkedColor: Color = MaterialTheme.colors.secondary,
     uncheckedColor: Color = CheckboxConstants.defaultUncheckedColor
 ) {
     TriStateCheckbox(
         state = ToggleableState(checked),
         onClick = { onCheckedChange(!checked) },
+        interactionState = interactionState,
         enabled = enabled,
         boxColor = CheckboxConstants.animateDefaultBoxColor(
             state = ToggleableState(checked),
@@ -115,6 +123,10 @@
  * @param modifier Modifier to be applied to the layout of the checkbox
  * @param enabled whether or not this [TriStateCheckbox] will handle input events and
  * appear enabled for semantics purposes
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this TriStateCheckbox. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this TriStateCheckbox in different [Interaction]s.
  * @param checkMarkColor color of the check mark of the [TriStateCheckbox]. See
  * [CheckboxConstants.animateDefaultCheckmarkColor] for customizing the check mark color in
  * different [state]s.
@@ -131,6 +143,7 @@
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
+    interactionState: InteractionState = remember { InteractionState() },
     checkMarkColor: Color = CheckboxConstants.animateDefaultCheckmarkColor(state),
     boxColor: Color = CheckboxConstants.animateDefaultBoxColor(state, enabled),
     borderColor: Color = CheckboxConstants.animateDefaultBorderColor(state, enabled)
@@ -142,6 +155,7 @@
                 state = state,
                 onClick = onClick,
                 enabled = enabled,
+                interactionState = interactionState,
                 indication = RippleIndication(bounded = false, radius = CheckboxRippleRadius)
             )
             .padding(CheckboxDefaultPadding),
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/IconButton.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/IconButton.kt
index 83ab797..1a2f903f 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/IconButton.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/IconButton.kt
@@ -18,11 +18,14 @@
 
 import androidx.compose.foundation.Box
 import androidx.compose.foundation.ContentGravity
+import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.InteractionState
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.layout.preferredSize
 import androidx.compose.foundation.selection.toggleable
 import androidx.compose.material.ripple.RippleIndication
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 
@@ -44,6 +47,10 @@
  * @param modifier optional [Modifier] for this IconButton
  * @param enabled whether or not this IconButton will handle input events and appear enabled for
  * semantics purposes
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this IconButton. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this IconButton in different [Interaction]s.
  * @param icon the content (icon) to be drawn inside the IconButton. This is typically an
  * [androidx.compose.foundation.Icon].
  */
@@ -52,6 +59,7 @@
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
+    interactionState: InteractionState = remember { InteractionState() },
     icon: @Composable () -> Unit
 ) {
     Box(
@@ -59,6 +67,7 @@
             .clickable(
                 onClick = onClick,
                 enabled = enabled,
+                interactionState = interactionState,
                 indication = RippleIndication(bounded = false, radius = RippleRadius)
             )
             .then(IconButtonSizeModifier),
@@ -78,6 +87,10 @@
  * @param modifier optional [Modifier] for this IconToggleButton
  * @param enabled enabled whether or not this [IconToggleButton] will handle input events and appear
  * enabled for semantics purposes
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this IconToggleButton. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this IconToggleButton in different [Interaction]s.
  * @param icon the content (icon) to be drawn inside the IconToggleButton. This is typically an
  * [androidx.compose.foundation.Icon].
  */
@@ -87,6 +100,7 @@
     onCheckedChange: (Boolean) -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
+    interactionState: InteractionState = remember { InteractionState() },
     icon: @Composable () -> Unit
 ) {
     Box(
@@ -94,6 +108,7 @@
             value = checked,
             onValueChange = onCheckedChange,
             enabled = enabled,
+            interactionState = interactionState,
             indication = RippleIndication(bounded = false, radius = RippleRadius)
         ).then(IconButtonSizeModifier),
         gravity = ContentGravity.Center,
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Menu.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Menu.kt
index 5aa22fe..92deb97 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Menu.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Menu.kt
@@ -23,6 +23,8 @@
 import androidx.compose.animation.transition
 import androidx.compose.foundation.Box
 import androidx.compose.foundation.ContentGravity
+import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.InteractionState
 import androidx.compose.foundation.ProvideTextStyle
 import androidx.compose.foundation.ScrollableColumn
 import androidx.compose.foundation.clickable
@@ -162,18 +164,28 @@
  * @param modifier The modifier to be applied to the menu item
  * @param enabled Controls the enabled state of the menu item - when `false`, the menu item
  * will not be clickable and [onClick] will not be invoked
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this DropdownMenuItem. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this DropdownMenuItem in different [Interaction]s.
  */
 @Composable
 fun DropdownMenuItem(
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
+    interactionState: InteractionState = remember { InteractionState() },
     content: @Composable () -> Unit
 ) {
     // TODO(popam, b/156911853): investigate replacing this Box with ListItem
     Box(
         modifier = modifier
-            .clickable(enabled = enabled, onClick = onClick, indication = RippleIndication(true))
+            .clickable(
+                enabled = enabled,
+                onClick = onClick,
+                interactionState = interactionState,
+                indication = RippleIndication(true)
+            )
             .fillMaxWidth()
             // Preferred min and max width used during the intrinsic measurement.
             .preferredSizeIn(
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
index e609011..4f0728a 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/OutlinedTextField.kt
@@ -17,6 +17,8 @@
 package androidx.compose.material
 
 import androidx.compose.foundation.Box
+import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.InteractionState
 import androidx.compose.foundation.Text
 import androidx.compose.foundation.currentTextStyle
 import androidx.compose.foundation.layout.padding
@@ -101,6 +103,10 @@
  * input service (e.g. software keyboard on Android) has been established. Called with the
  * [SoftwareKeyboardController] instance that can be used to request to show or hide the software
  * keyboard
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this OutlinedTextField. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this OutlinedTextField in different [Interaction]s.
  * @param activeColor the color of the label, bottom indicator and the cursor when the text field is
  * in focus
  * @param inactiveColor the color of either the input text or placeholder when the text field is in
@@ -124,6 +130,7 @@
     imeAction: ImeAction = ImeAction.Unspecified,
     onImeActionPerformed: (ImeAction, SoftwareKeyboardController?) -> Unit = { _, _ -> },
     onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
+    interactionState: InteractionState = remember { InteractionState() },
     activeColor: Color = MaterialTheme.colors.primary,
     inactiveColor: Color = MaterialTheme.colors.onSurface,
     errorColor: Color = MaterialTheme.colors.error
@@ -160,6 +167,7 @@
         imeAction = imeAction,
         onImeActionPerformed = onImeActionPerformed,
         onTextInputStarted = onTextInputStarted,
+        interactionState = interactionState,
         activeColor = activeColor,
         inactiveColor = inactiveColor,
         errorColor = errorColor,
@@ -214,6 +222,10 @@
  * input service (e.g. software keyboard on Android) has been established. Called with the
  * [SoftwareKeyboardController] instance that can be used to request to show or hide the software
  * keyboard
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this OutlinedTextField. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this OutlinedTextField in different [Interaction]s.
  * @param activeColor the color of the label, bottom indicator and the cursor when the text field is
  * in focus
  * @param inactiveColor the color of either the input text or placeholder when the text field is in
@@ -237,6 +249,7 @@
     imeAction: ImeAction = ImeAction.Unspecified,
     onImeActionPerformed: (ImeAction, SoftwareKeyboardController?) -> Unit = { _, _ -> },
     onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
+    interactionState: InteractionState = remember { InteractionState() },
     activeColor: Color = MaterialTheme.colors.primary,
     inactiveColor: Color = MaterialTheme.colors.onSurface,
     errorColor: Color = MaterialTheme.colors.error
@@ -257,6 +270,7 @@
         imeAction = imeAction,
         onImeActionPerformed = onImeActionPerformed,
         onTextInputStarted = onTextInputStarted,
+        interactionState = interactionState,
         activeColor = activeColor,
         inactiveColor = inactiveColor,
         errorColor = errorColor,
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ProgressIndicator.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ProgressIndicator.kt
index 8ad5a57..0be2779 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ProgressIndicator.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/ProgressIndicator.kt
@@ -101,15 +101,15 @@
         initState = 0,
         toState = 1
     )
-    val firstLineHead = state[FirstLineHeadProp]
-    val firstLineTail = state[FirstLineTailProp]
-    val secondLineHead = state[SecondLineHeadProp]
-    val secondLineTail = state[SecondLineTailProp]
     Canvas(
         modifier
             .progressSemantics()
             .preferredSize(LinearIndicatorWidth, LinearIndicatorHeight)
     ) {
+        val firstLineHead = state[FirstLineHeadProp]
+        val firstLineTail = state[FirstLineTailProp]
+        val secondLineHead = state[SecondLineHeadProp]
+        val secondLineTail = state[SecondLineTailProp]
         val strokeWidth = ProgressIndicatorConstants.DefaultStrokeWidth.toPx()
         drawLinearIndicatorBackground(backgroundColor, strokeWidth)
         if (firstLineHead - firstLineTail > 0) {
@@ -213,25 +213,24 @@
         initState = 0,
         toState = 1
     )
-    val currentRotation = state[IterationProp]
-    val baseRotation = state[BaseRotationProp]
-
-    val currentRotationAngleOffset = (currentRotation * RotationAngleOffset) % 360f
-
-    var startAngle = state[TailRotationProp]
-    val endAngle = state[HeadRotationProp]
-    // How long a line to draw using the start angle as a reference point
-    val sweep = abs(endAngle - startAngle)
-
-    // Offset by the constant offset and the per rotation offset
-    startAngle += StartAngleOffset + currentRotationAngleOffset
-    startAngle += baseRotation
-
     Canvas(
         modifier
             .progressSemantics()
             .preferredSize(CircularIndicatorDiameter)
     ) {
+        val currentRotation = state[IterationProp]
+        val baseRotation = state[BaseRotationProp]
+
+        val currentRotationAngleOffset = (currentRotation * RotationAngleOffset) % 360f
+
+        var startAngle = state[TailRotationProp]
+        val endAngle = state[HeadRotationProp]
+        // How long a line to draw using the start angle as a reference point
+        val sweep = abs(endAngle - startAngle)
+
+        // Offset by the constant offset and the per rotation offset
+        startAngle += StartAngleOffset + currentRotationAngleOffset
+        startAngle += baseRotation
         drawIndeterminateCircularIndicator(startAngle, strokeWidth, sweep, color, stroke)
     }
 }
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/RadioButton.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/RadioButton.kt
index ebfef1b..d4c0983 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/RadioButton.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/RadioButton.kt
@@ -19,6 +19,8 @@
 import androidx.compose.animation.animate
 import androidx.compose.animation.core.tween
 import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.InteractionState
 import androidx.compose.foundation.Text
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
@@ -28,6 +30,7 @@
 import androidx.compose.foundation.selection.selectable
 import androidx.compose.material.ripple.RippleIndication
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
@@ -52,6 +55,10 @@
  * @param modifier Modifier to be applied to the radio button
  * @param enabled Controls the enabled state of the [RadioButton]. When `false`, this button will
  * not be selectable and appears in the disabled ui state
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this RadioButton. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this RadioButton in different [Interaction]s.
  * @param color color of the RadioButton. See [RadioButtonConstants.animateDefaultColor] for
  * customizing the color of the RadioButton in one / multiple states, such as when [selected] or
  * not [enabled].
@@ -62,6 +69,7 @@
     onClick: () -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
+    interactionState: InteractionState = remember { InteractionState() },
     color: Color = RadioButtonConstants.animateDefaultColor(selected, enabled)
 ) {
     val dotRadius = animate(
@@ -74,6 +82,7 @@
                 selected = selected,
                 onClick = onClick,
                 enabled = enabled,
+                interactionState = interactionState,
                 indication = RippleIndication(bounded = false, radius = RadioButtonRippleRadius)
             )
             .wrapContentSize(Alignment.Center)
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
index 5a1ea8d..2bfa513 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Slider.kt
@@ -99,6 +99,10 @@
  * @param onValueChangeEnd lambda to be invoked when value change has ended. This callback
  * shouldn't be used to update the slider value (use [onValueChange] for that), but rather to
  * know when the user has completed selecting a new value by ending a drag or a click.
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this Slider. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this Slider in different [Interaction]s.
  * @param thumbColor color of thumb of the slider
  * @param activeTrackColor color of the track in the part that is "active", meaning that the
  * thumb is ahead of it
@@ -117,6 +121,7 @@
     valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
     @IntRange(from = 0) steps: Int = 0,
     onValueChangeEnd: () -> Unit = {},
+    interactionState: InteractionState = remember { InteractionState() },
     thumbColor: Color = MaterialTheme.colors.primary,
     activeTrackColor: Color = MaterialTheme.colors.primary,
     inactiveTrackColor: Color = activeTrackColor.copy(alpha = InactiveTrackColorAlpha),
@@ -149,8 +154,6 @@
             }
         }
 
-        val interactionState = remember { InteractionState() }
-
         val press = Modifier.pressIndicatorGestureFilter(
             onStart = { pos ->
                 position.holder.snapTo(if (isRtl) maxPx - pos.x else pos.x)
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
index df18725..793f052 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Switch.kt
@@ -57,7 +57,11 @@
  * therefore the change of checked state is requested.
  * @param modifier Modifier to be applied to the switch layout
  * @param enabled whether or not components is enabled and can be clicked to request state change
- * @param color main color of the track and trumb when the Switch is checked
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this Switch. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this Switch in different [Interaction]s.
+ * @param color main color of the track and thumb when the Switch is checked
  */
 @Composable
 @OptIn(ExperimentalMaterialApi::class)
@@ -66,12 +70,12 @@
     onCheckedChange: (Boolean) -> Unit,
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
+    interactionState: InteractionState = remember { InteractionState() },
     color: Color = MaterialTheme.colors.secondaryVariant
 ) {
     val minBound = 0f
     val maxBound = with(DensityAmbient.current) { ThumbPathLength.toPx() }
     val swipeableState = rememberSwipeableStateFor(checked, onCheckedChange, AnimationSpec)
-    val interactionState = remember { InteractionState() }
     val isRtl = LayoutDirectionAmbient.current == LayoutDirection.Rtl
     Stack(
         modifier
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
index 42c6169..5459021 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt
@@ -17,6 +17,8 @@
 package androidx.compose.material
 
 import androidx.compose.foundation.Box
+import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.InteractionState
 import androidx.compose.foundation.Text
 import androidx.compose.foundation.background
 import androidx.compose.foundation.currentTextStyle
@@ -128,6 +130,10 @@
  * input service (e.g. software keyboard on Android) has been established. Called with the
  * [SoftwareKeyboardController] instance that can be used to request to show or hide the software
  * keyboard
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this TextField. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this TextField in different [Interaction]s.
  * @param activeColor the color of the label, bottom indicator and the cursor when the text field is
  * in focus
  * @param inactiveColor the color of either the input text or placeholder when the text field is in
@@ -153,6 +159,7 @@
     imeAction: ImeAction = ImeAction.Unspecified,
     onImeActionPerformed: (ImeAction, SoftwareKeyboardController?) -> Unit = { _, _ -> },
     onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
+    interactionState: InteractionState = remember { InteractionState() },
     activeColor: Color = MaterialTheme.colors.primary,
     inactiveColor: Color = MaterialTheme.colors.onSurface,
     errorColor: Color = MaterialTheme.colors.error,
@@ -191,6 +198,7 @@
         imeAction = imeAction,
         onImeActionPerformed = onImeActionPerformed,
         onTextInputStarted = onTextInputStarted,
+        interactionState = interactionState,
         activeColor = activeColor,
         inactiveColor = inactiveColor,
         errorColor = errorColor,
@@ -247,6 +255,10 @@
  * input service (e.g. software keyboard on Android) has been established. Called with the
  * [SoftwareKeyboardController] instance that can be used to request to show or hide the software
  * keyboard
+ * @param interactionState the [InteractionState] representing the different [Interaction]s
+ * present on this TextField. You can create and pass in your own remembered
+ * [InteractionState] if you want to read the [InteractionState] and customize the appearance /
+ * behavior of this TextField in different [Interaction]s.
  * @param activeColor the color of the label, bottom indicator and the cursor when the text field is
  * in focus
  * @param inactiveColor the color of either the input text or placeholder when the text field is in
@@ -272,6 +284,7 @@
     imeAction: ImeAction = ImeAction.Unspecified,
     onImeActionPerformed: (ImeAction, SoftwareKeyboardController?) -> Unit = { _, _ -> },
     onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
+    interactionState: InteractionState = remember { InteractionState() },
     activeColor: Color = MaterialTheme.colors.primary,
     inactiveColor: Color = MaterialTheme.colors.onSurface,
     errorColor: Color = MaterialTheme.colors.error,
@@ -295,6 +308,7 @@
         imeAction = imeAction,
         onImeActionPerformed = onImeActionPerformed,
         onTextInputStarted = onTextInputStarted,
+        interactionState = interactionState,
         activeColor = activeColor,
         inactiveColor = inactiveColor,
         errorColor = errorColor,
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt
index 5cb38ca..da9243e 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextFieldImpl.kt
@@ -31,8 +31,9 @@
 import androidx.compose.foundation.Box
 import androidx.compose.foundation.ContentColorAmbient
 import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.Interaction
+import androidx.compose.foundation.InteractionState
 import androidx.compose.foundation.ProvideTextStyle
-import androidx.compose.foundation.clickable
 import androidx.compose.foundation.gestures.rememberScrollableController
 import androidx.compose.foundation.gestures.scrollable
 import androidx.compose.foundation.layout.padding
@@ -42,6 +43,7 @@
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.onCommit
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.savedinstancestate.Saver
 import androidx.compose.runtime.savedinstancestate.rememberSavedInstanceState
@@ -61,9 +63,11 @@
 import androidx.compose.ui.focusObserver
 import androidx.compose.ui.focusRequester
 import androidx.compose.ui.gesture.scrollorientationlocking.Orientation
+import androidx.compose.ui.gesture.tapGestureFilter
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.node.Ref
+import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.text.SoftwareKeyboardController
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.input.ImeAction
@@ -108,6 +112,7 @@
     imeAction: ImeAction,
     onImeActionPerformed: (ImeAction, SoftwareKeyboardController?) -> Unit,
     onTextInputStarted: (SoftwareKeyboardController) -> Unit,
+    interactionState: InteractionState,
     activeColor: Color,
     inactiveColor: Color,
     errorColor: Color,
@@ -158,10 +163,11 @@
     }
 
     val focusRequester = FocusRequester()
+    // TODO(b/168908942): Populate interactionState values.
     val textFieldModifier = modifier
         .focusRequester(focusRequester)
         .focusObserver { isFocused = it.isFocused }
-        .clickable(indication = null) {
+        .tapGestureFilter {
             focusRequester.requestFocus()
             // TODO(b/163109449): Showing and hiding keyboard should be handled by BaseTextField.
             //  The requestFocus() call here should be enough to trigger the software keyboard.
@@ -170,9 +176,16 @@
             //  so that it can show or hide the keyboard based on the focus state.
             keyboardController.value?.showSoftwareKeyboard()
         }
+        .semantics(mergeAllDescendants = true) {}
 
     val emphasisLevels = EmphasisAmbient.current
 
+    onCommit(interactionState) {
+        onDispose {
+            interactionState.removeInteraction(Interaction.Pressed)
+        }
+    }
+
     TextFieldTransitionScope.transition(
         inputState = inputState,
         showLabel = label != null,
diff --git a/compose/navigation/navigation/build.gradle b/compose/navigation/navigation/build.gradle
index c5d3f94..63b6598 100644
--- a/compose/navigation/navigation/build.gradle
+++ b/compose/navigation/navigation/build.gradle
@@ -30,7 +30,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
     api project(":compose:runtime:runtime")
diff --git a/compose/navigation/navigation/integration-tests/navigation-demos/build.gradle b/compose/navigation/navigation/integration-tests/navigation-demos/build.gradle
index af097f4..7464171 100644
--- a/compose/navigation/navigation/integration-tests/navigation-demos/build.gradle
+++ b/compose/navigation/navigation/integration-tests/navigation-demos/build.gradle
@@ -28,7 +28,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
     implementation(KOTLIN_STDLIB)
 
     implementation project(":compose:integration-tests:demos:common")
diff --git a/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/BottomBarNavDemo.kt b/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/BottomBarNavDemo.kt
index 1e6e313..fc26e7f 100644
--- a/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/BottomBarNavDemo.kt
+++ b/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/BottomBarNavDemo.kt
@@ -43,19 +43,23 @@
     var selectedItem by remember { mutableStateOf(0) }
     val items = listOf("Profile", "Dashboard", "Scrollable")
 
-    Scaffold(bottomBar = { BottomNavigation {
-        items.forEachIndexed { index, item ->
-            BottomNavigationItem(
-                icon = { Icon(Icons.Filled.Favorite) },
-                label = { Text(item) },
-                selected = selectedItem == index,
-                onClick = {
-                    navController.navigate(item)
-                    selectedItem = index
+    Scaffold(
+        bottomBar = {
+            BottomNavigation {
+                items.forEachIndexed { index, item ->
+                    BottomNavigationItem(
+                        icon = { Icon(Icons.Filled.Favorite) },
+                        label = { Text(item) },
+                        selected = selectedItem == index,
+                        onClick = {
+                            navController.navigate(item)
+                            selectedItem = index
+                        }
+                    )
                 }
-            )
+            }
         }
-    } }) {
+    ) {
         NavHost(navController, startDestination = "Profile") {
             composable("Profile") { Profile() }
             composable("Dashboard") { Dashboard() }
diff --git a/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/NavigationDemos.kt b/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/NavigationDemos.kt
index d636f6ff..d840f47 100644
--- a/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/NavigationDemos.kt
+++ b/compose/navigation/navigation/integration-tests/navigation-demos/src/main/java/androidx/compose/navigation/demos/NavigationDemos.kt
@@ -19,7 +19,10 @@
 import androidx.compose.integration.demos.common.ComposableDemo
 import androidx.compose.integration.demos.common.DemoCategory
 
-val NavigationDemos = DemoCategory("Navigation", listOf(
-    ComposableDemo("Basic Nav Demo") { BasicNavDemo() },
-    ComposableDemo("Bottom Bar Nav Demo") { BottomBarNavDemo() }
-))
+val NavigationDemos = DemoCategory(
+    "Navigation",
+    listOf(
+        ComposableDemo("Basic Nav Demo") { BasicNavDemo() },
+        ComposableDemo("Bottom Bar Nav Demo") { BottomBarNavDemo() }
+    )
+)
diff --git a/compose/navigation/navigation/samples/build.gradle b/compose/navigation/navigation/samples/build.gradle
index d55fe2e..1025034 100644
--- a/compose/navigation/navigation/samples/build.gradle
+++ b/compose/navigation/navigation/samples/build.gradle
@@ -28,7 +28,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
     implementation(KOTLIN_STDLIB)
 
     implementation project(":annotation:annotation-sampled")
diff --git a/compose/navigation/navigation/samples/src/main/java/androidx/compose/navigation/samples/NavigationSamples.kt b/compose/navigation/navigation/samples/src/main/java/androidx/compose/navigation/samples/NavigationSamples.kt
index 601cf1b..f2b51ab 100644
--- a/compose/navigation/navigation/samples/src/main/java/androidx/compose/navigation/samples/NavigationSamples.kt
+++ b/compose/navigation/navigation/samples/src/main/java/androidx/compose/navigation/samples/NavigationSamples.kt
@@ -91,9 +91,11 @@
 @Composable
 fun NavigateButton(screen: Screen) {
     val navController = AmbientNavController.current
-    Button(onClick = { navController.navigate(screen.title) },
+    Button(
+        onClick = { navController.navigate(screen.title) },
         backgroundColor = LightGray,
-        modifier = Modifier.fillMaxWidth()) {
+        modifier = Modifier.fillMaxWidth()
+    ) {
         Text(text = "Navigate to " + screen.title)
     }
 }
diff --git a/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavGraphBuilder.kt b/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavGraphBuilder.kt
index 69ed290..3c8308d 100644
--- a/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavGraphBuilder.kt
+++ b/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavGraphBuilder.kt
@@ -27,7 +27,9 @@
  * @param content composable for the destination
  */
 fun NavGraphBuilder.composable(id: Any, content: @Composable () -> Unit) {
-    addDestination(ComposeNavigator.Destination(provider[ComposeNavigator::class], content).apply {
-        setId(generateId(id))
-    })
+    addDestination(
+        ComposeNavigator.Destination(provider[ComposeNavigator::class], content).apply {
+            setId(generateId(id))
+        }
+    )
 }
diff --git a/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavHost.kt b/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavHost.kt
index b8e25a3..d31cd18 100644
--- a/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavHost.kt
+++ b/compose/navigation/navigation/src/main/java/androidx/compose/navigation/NavHost.kt
@@ -49,9 +49,12 @@
     startDestination: Any,
     builder: NavGraphBuilder.() -> Unit
 ) {
-    NavHost(navController, remember (id, startDestination, builder) {
-        navController.createGraph(id, startDestination, builder)
-    })
+    NavHost(
+        navController,
+        remember (id, startDestination, builder) {
+            navController.createGraph(id, startDestination, builder)
+        }
+    )
 }
 
 /**
diff --git a/compose/runtime/runtime-livedata/build.gradle b/compose/runtime/runtime-livedata/build.gradle
index 825bf92..142fe35 100644
--- a/compose/runtime/runtime-livedata/build.gradle
+++ b/compose/runtime/runtime-livedata/build.gradle
@@ -29,7 +29,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/runtime/runtime-livedata/samples/build.gradle b/compose/runtime/runtime-livedata/samples/build.gradle
index 0c3adea..7ade3d3 100644
--- a/compose/runtime/runtime-livedata/samples/build.gradle
+++ b/compose/runtime/runtime-livedata/samples/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
     implementation project(":annotation:annotation-sampled")
diff --git a/compose/runtime/runtime-rxjava2/build.gradle b/compose/runtime/runtime-rxjava2/build.gradle
index 1afca61..fb12e6c 100644
--- a/compose/runtime/runtime-rxjava2/build.gradle
+++ b/compose/runtime/runtime-rxjava2/build.gradle
@@ -29,7 +29,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/runtime/runtime-rxjava2/samples/build.gradle b/compose/runtime/runtime-rxjava2/samples/build.gradle
index f2afd19..668ef47 100644
--- a/compose/runtime/runtime-rxjava2/samples/build.gradle
+++ b/compose/runtime/runtime-rxjava2/samples/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
     implementation project(":annotation:annotation-sampled")
diff --git a/compose/runtime/runtime-saved-instance-state/build.gradle b/compose/runtime/runtime-saved-instance-state/build.gradle
index 690ee6a..16c20f4 100644
--- a/compose/runtime/runtime-saved-instance-state/build.gradle
+++ b/compose/runtime/runtime-saved-instance-state/build.gradle
@@ -29,7 +29,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 }
 
 kotlin {
diff --git a/compose/runtime/runtime-saved-instance-state/samples/build.gradle b/compose/runtime/runtime-saved-instance-state/samples/build.gradle
index 4ead02e..96cd790 100644
--- a/compose/runtime/runtime-saved-instance-state/samples/build.gradle
+++ b/compose/runtime/runtime-saved-instance-state/samples/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/runtime/runtime/api/current.txt b/compose/runtime/runtime/api/current.txt
index 16dd20c..fc91886 100644
--- a/compose/runtime/runtime/api/current.txt
+++ b/compose/runtime/runtime/api/current.txt
@@ -976,6 +976,7 @@
     method public void clear(Object target);
     method public void dispose();
     method public void enableStateUpdatesObserving(boolean enabled);
+    method @org.jetbrains.annotations.TestOnly public void notifyChanges(java.util.Set<?> changes, androidx.compose.runtime.snapshots.Snapshot snapshot);
     method public <T> void observeReads(T target, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged, kotlin.jvm.functions.Function0<kotlin.Unit> block);
     method public void pauseObservingReads(kotlin.jvm.functions.Function0<kotlin.Unit> block);
   }
diff --git a/compose/runtime/runtime/api/public_plus_experimental_current.txt b/compose/runtime/runtime/api/public_plus_experimental_current.txt
index 16dd20c..fc91886 100644
--- a/compose/runtime/runtime/api/public_plus_experimental_current.txt
+++ b/compose/runtime/runtime/api/public_plus_experimental_current.txt
@@ -976,6 +976,7 @@
     method public void clear(Object target);
     method public void dispose();
     method public void enableStateUpdatesObserving(boolean enabled);
+    method @org.jetbrains.annotations.TestOnly public void notifyChanges(java.util.Set<?> changes, androidx.compose.runtime.snapshots.Snapshot snapshot);
     method public <T> void observeReads(T target, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged, kotlin.jvm.functions.Function0<kotlin.Unit> block);
     method public void pauseObservingReads(kotlin.jvm.functions.Function0<kotlin.Unit> block);
   }
diff --git a/compose/runtime/runtime/api/restricted_current.txt b/compose/runtime/runtime/api/restricted_current.txt
index 1a0ceb6..813ce4e 100644
--- a/compose/runtime/runtime/api/restricted_current.txt
+++ b/compose/runtime/runtime/api/restricted_current.txt
@@ -1016,6 +1016,7 @@
     method public void clear(Object target);
     method public void dispose();
     method public void enableStateUpdatesObserving(boolean enabled);
+    method @org.jetbrains.annotations.TestOnly public void notifyChanges(java.util.Set<?> changes, androidx.compose.runtime.snapshots.Snapshot snapshot);
     method public <T> void observeReads(T target, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged, kotlin.jvm.functions.Function0<kotlin.Unit> block);
     method public void pauseObservingReads(kotlin.jvm.functions.Function0<kotlin.Unit> block);
   }
diff --git a/compose/runtime/runtime/build.gradle b/compose/runtime/runtime/build.gradle
index 46b9aae..f60e242 100644
--- a/compose/runtime/runtime/build.gradle
+++ b/compose/runtime/runtime/build.gradle
@@ -29,7 +29,7 @@
     id("kotlin-multiplatform")
 }
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 }
 kotlin {
     android()
diff --git a/compose/runtime/runtime/compose-runtime-benchmark/build.gradle b/compose/runtime/runtime/compose-runtime-benchmark/build.gradle
index c595169..c3c8206 100644
--- a/compose/runtime/runtime/compose-runtime-benchmark/build.gradle
+++ b/compose/runtime/runtime/compose-runtime-benchmark/build.gradle
@@ -45,7 +45,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     androidTestImplementation(project("::compose:ui:ui"))
     androidTestImplementation(project(":compose:foundation:foundation"))
diff --git a/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt
index d5add45..d0ad476 100644
--- a/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt
+++ b/compose/runtime/runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/runtime/benchmark/SnapshotStateObserverBenchmark.kt
@@ -28,34 +28,26 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
+import org.junit.runners.JUnit4
+import kotlin.math.pow
+import kotlin.math.roundToInt
 import kotlin.random.Random
 
 @LargeTest
-@RunWith(Parameterized::class)
+@RunWith(JUnit4::class)
 @OptIn(ExperimentalComposeApi::class)
-class SnapshotStateObserverBenchmark(
-    private val numberOfModels: Int,
-    private val numberOfNodes: Int
-) : ComposeBenchmarkBase() {
+class SnapshotStateObserverBenchmark : ComposeBenchmarkBase() {
     companion object {
-        @JvmStatic
-        @Parameterized.Parameters(name = "states = {0}, nodes = {1}")
-        fun initParameters(): Array<Any> = arrayOf(
-            arrayOf(1000, 1000),
-            arrayOf(10000, 100),
-            arrayOf(100000, 10),
-            arrayOf(100, 1000)
-        )
+        private const val ScopeCount = 1000
+        private const val StateCount = 1000
     }
 
     private val doNothing: (Int) -> Unit = { _ -> }
 
     private lateinit var stateObserver: SnapshotStateObserver
-    private val models = List(numberOfModels) { mutableStateOf(0) }
-    private val nodes = List(numberOfNodes) { it }
+    private val models = List(StateCount) { mutableStateOf(0) }
+    private val nodes = List(ScopeCount) { it }
     private lateinit var random: Random
-    private val numObservations = numberOfModels / 10
 
     @Before
     fun setup() {
@@ -86,9 +78,13 @@
     fun modelObservation() {
         runOnUiThread {
             benchmarkRule.measureRepeated {
-                random = Random(0)
-                val node = nodes[random.nextInt(numberOfNodes)]
-                observeForNode(node)
+                runWithTimingDisabled {
+                    nodes.forEach { node ->
+                        stateObserver.clear(node)
+                    }
+                    random = Random(0)
+                }
+                setupObservations()
             }
         }
     }
@@ -96,11 +92,21 @@
     @Test
     fun nestedModelObservation() {
         runOnUiThread {
-            stateObserver.observeReads(nodes[0], doNothing) {
-                benchmarkRule.measureRepeated {
+            val list = mutableListOf<Int>()
+            repeat(10) {
+                list += nodes[random.nextInt(ScopeCount)]
+            }
+            benchmarkRule.measureRepeated {
+                runWithTimingDisabled {
                     random = Random(0)
-                    val node = nodes[random.nextInt(numberOfNodes)]
-                    observeForNode(node)
+                    nodes.forEach { node ->
+                        stateObserver.clear(node)
+                    }
+                }
+                stateObserver.observeReads(nodes[0], doNothing) {
+                    list.forEach { node ->
+                        observeForNode(node)
+                    }
                 }
             }
         }
@@ -110,12 +116,28 @@
     fun modelClear() {
         runOnUiThread {
             benchmarkRule.measureRepeated {
-                random = Random(0)
-                val node = nodes[random.nextInt(numberOfNodes)]
-                stateObserver.clear(node)
-                runWithTimingDisabled {
-                    observeForNode(node)
+                nodes.forEach { node ->
+                    stateObserver.clear(node)
                 }
+                random = Random(0)
+                runWithTimingDisabled {
+                    setupObservations()
+                }
+            }
+        }
+    }
+
+    @Test
+    fun notifyChanges() {
+        runOnUiThread {
+            val states = mutableSetOf<Int>()
+            repeat(50) {
+                states += random.nextInt(StateCount)
+            }
+            val snapshot: Snapshot = Snapshot.current
+            benchmarkRule.measureRepeated {
+                random = Random(0)
+                stateObserver.notifyChanges(states, snapshot)
             }
         }
     }
@@ -125,9 +147,11 @@
 
     private fun observeForNode(node: Int) {
         stateObserver.observeReads(node, doNothing) {
+            // we want between 0-10, with the cluster near 0, but some outliers
+            val numObservations = (10.0.pow(random.nextDouble(2.0)) / 10).roundToInt()
             repeat(numObservations) {
                 // just access the value
-                models[random.nextInt(numberOfModels)].value
+                models[random.nextInt(StateCount)].value
             }
         }
     }
diff --git a/compose/runtime/runtime/samples/build.gradle b/compose/runtime/runtime/samples/build.gradle
index ba09b21..6340a27 100644
--- a/compose/runtime/runtime/samples/build.gradle
+++ b/compose/runtime/runtime/samples/build.gradle
@@ -27,7 +27,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
index 3f79db7..ffc46e6 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/SnapshotStateObserver.kt
@@ -18,6 +18,7 @@
 
 import androidx.compose.runtime.ExperimentalComposeApi
 import androidx.compose.runtime.ObserverMap
+import androidx.compose.runtime.TestOnly
 
 @ExperimentalComposeApi
 @Suppress("DEPRECATION_ERROR")
@@ -178,6 +179,15 @@
     }
 
     /**
+     * This method is only used for testing. It notifies that [changes] have been made on
+     * [snapshot].
+     */
+    @TestOnly
+    fun notifyChanges(changes: Set<Any>, snapshot: Snapshot) {
+        applyObserver(changes, snapshot)
+    }
+
+    /**
      * Calls the `onChanged` callback for the given targets.
      */
     private fun callOnChanged(targetsArray: Array<List<Any>>) {
diff --git a/compose/test-utils/build.gradle b/compose/test-utils/build.gradle
index e5ed981..7c10786 100644
--- a/compose/test-utils/build.gradle
+++ b/compose/test-utils/build.gradle
@@ -27,7 +27,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 }
 
 kotlin {
diff --git a/compose/ui/ui-geometry/api/current.txt b/compose/ui/ui-geometry/api/current.txt
index 196e434..c6faa6b 100644
--- a/compose/ui/ui-geometry/api/current.txt
+++ b/compose/ui/ui-geometry/api/current.txt
@@ -104,7 +104,6 @@
     method public boolean contains-k-4lQ0M(long offset);
     method @androidx.compose.runtime.Immutable public androidx.compose.ui.geometry.Rect copy(float left, float top, float right, float bottom);
     method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect deflate(float delta);
-    method public androidx.compose.ui.geometry.Rect expandToInclude(androidx.compose.ui.geometry.Rect other);
     method public float getBottom();
     method public long getBottomCenter();
     method public long getBottomLeft();
@@ -128,10 +127,10 @@
     method public boolean isEmpty();
     method public boolean isFinite();
     method public boolean isInfinite();
-    method public androidx.compose.ui.geometry.Rect join(androidx.compose.ui.geometry.Rect other);
     method public boolean overlaps(androidx.compose.ui.geometry.Rect other);
-    method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect shift-k-4lQ0M(long offset);
+    method @Deprecated @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect shift-k-4lQ0M(long offset);
     method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect translate(float translateX, float translateY);
+    method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect translate-k-4lQ0M(long offset);
     property public final long bottomCenter;
     property public final long bottomLeft;
     property public final long bottomRight;
@@ -236,11 +235,12 @@
     method public static androidx.compose.ui.geometry.Rect middleRect(androidx.compose.ui.geometry.RoundRect);
     method public static androidx.compose.ui.geometry.Rect outerRect(androidx.compose.ui.geometry.RoundRect);
     method public static androidx.compose.ui.geometry.Rect safeInnerRect(androidx.compose.ui.geometry.RoundRect);
-    method public static androidx.compose.ui.geometry.RoundRect shift-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
+    method @Deprecated public static androidx.compose.ui.geometry.RoundRect shift-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
     method public static androidx.compose.ui.geometry.RoundRect shrink(androidx.compose.ui.geometry.RoundRect, float delta);
     method public static androidx.compose.ui.geometry.Rect tallMiddleRect(androidx.compose.ui.geometry.RoundRect);
     method public static long topLeftRadius(androidx.compose.ui.geometry.RoundRect);
     method public static long topRightRadius(androidx.compose.ui.geometry.RoundRect);
+    method public static androidx.compose.ui.geometry.RoundRect translate-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
     method public static androidx.compose.ui.geometry.Rect wideMiddleRect(androidx.compose.ui.geometry.RoundRect);
     method public static androidx.compose.ui.geometry.RoundRect withRadius-Z0w6hBY(androidx.compose.ui.geometry.RoundRect, long radius);
   }
diff --git a/compose/ui/ui-geometry/api/public_plus_experimental_current.txt b/compose/ui/ui-geometry/api/public_plus_experimental_current.txt
index 196e434..c6faa6b 100644
--- a/compose/ui/ui-geometry/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-geometry/api/public_plus_experimental_current.txt
@@ -104,7 +104,6 @@
     method public boolean contains-k-4lQ0M(long offset);
     method @androidx.compose.runtime.Immutable public androidx.compose.ui.geometry.Rect copy(float left, float top, float right, float bottom);
     method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect deflate(float delta);
-    method public androidx.compose.ui.geometry.Rect expandToInclude(androidx.compose.ui.geometry.Rect other);
     method public float getBottom();
     method public long getBottomCenter();
     method public long getBottomLeft();
@@ -128,10 +127,10 @@
     method public boolean isEmpty();
     method public boolean isFinite();
     method public boolean isInfinite();
-    method public androidx.compose.ui.geometry.Rect join(androidx.compose.ui.geometry.Rect other);
     method public boolean overlaps(androidx.compose.ui.geometry.Rect other);
-    method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect shift-k-4lQ0M(long offset);
+    method @Deprecated @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect shift-k-4lQ0M(long offset);
     method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect translate(float translateX, float translateY);
+    method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect translate-k-4lQ0M(long offset);
     property public final long bottomCenter;
     property public final long bottomLeft;
     property public final long bottomRight;
@@ -236,11 +235,12 @@
     method public static androidx.compose.ui.geometry.Rect middleRect(androidx.compose.ui.geometry.RoundRect);
     method public static androidx.compose.ui.geometry.Rect outerRect(androidx.compose.ui.geometry.RoundRect);
     method public static androidx.compose.ui.geometry.Rect safeInnerRect(androidx.compose.ui.geometry.RoundRect);
-    method public static androidx.compose.ui.geometry.RoundRect shift-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
+    method @Deprecated public static androidx.compose.ui.geometry.RoundRect shift-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
     method public static androidx.compose.ui.geometry.RoundRect shrink(androidx.compose.ui.geometry.RoundRect, float delta);
     method public static androidx.compose.ui.geometry.Rect tallMiddleRect(androidx.compose.ui.geometry.RoundRect);
     method public static long topLeftRadius(androidx.compose.ui.geometry.RoundRect);
     method public static long topRightRadius(androidx.compose.ui.geometry.RoundRect);
+    method public static androidx.compose.ui.geometry.RoundRect translate-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
     method public static androidx.compose.ui.geometry.Rect wideMiddleRect(androidx.compose.ui.geometry.RoundRect);
     method public static androidx.compose.ui.geometry.RoundRect withRadius-Z0w6hBY(androidx.compose.ui.geometry.RoundRect, long radius);
   }
diff --git a/compose/ui/ui-geometry/api/restricted_current.txt b/compose/ui/ui-geometry/api/restricted_current.txt
index 196e434..c6faa6b 100644
--- a/compose/ui/ui-geometry/api/restricted_current.txt
+++ b/compose/ui/ui-geometry/api/restricted_current.txt
@@ -104,7 +104,6 @@
     method public boolean contains-k-4lQ0M(long offset);
     method @androidx.compose.runtime.Immutable public androidx.compose.ui.geometry.Rect copy(float left, float top, float right, float bottom);
     method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect deflate(float delta);
-    method public androidx.compose.ui.geometry.Rect expandToInclude(androidx.compose.ui.geometry.Rect other);
     method public float getBottom();
     method public long getBottomCenter();
     method public long getBottomLeft();
@@ -128,10 +127,10 @@
     method public boolean isEmpty();
     method public boolean isFinite();
     method public boolean isInfinite();
-    method public androidx.compose.ui.geometry.Rect join(androidx.compose.ui.geometry.Rect other);
     method public boolean overlaps(androidx.compose.ui.geometry.Rect other);
-    method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect shift-k-4lQ0M(long offset);
+    method @Deprecated @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect shift-k-4lQ0M(long offset);
     method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect translate(float translateX, float translateY);
+    method @androidx.compose.runtime.Stable public androidx.compose.ui.geometry.Rect translate-k-4lQ0M(long offset);
     property public final long bottomCenter;
     property public final long bottomLeft;
     property public final long bottomRight;
@@ -236,11 +235,12 @@
     method public static androidx.compose.ui.geometry.Rect middleRect(androidx.compose.ui.geometry.RoundRect);
     method public static androidx.compose.ui.geometry.Rect outerRect(androidx.compose.ui.geometry.RoundRect);
     method public static androidx.compose.ui.geometry.Rect safeInnerRect(androidx.compose.ui.geometry.RoundRect);
-    method public static androidx.compose.ui.geometry.RoundRect shift-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
+    method @Deprecated public static androidx.compose.ui.geometry.RoundRect shift-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
     method public static androidx.compose.ui.geometry.RoundRect shrink(androidx.compose.ui.geometry.RoundRect, float delta);
     method public static androidx.compose.ui.geometry.Rect tallMiddleRect(androidx.compose.ui.geometry.RoundRect);
     method public static long topLeftRadius(androidx.compose.ui.geometry.RoundRect);
     method public static long topRightRadius(androidx.compose.ui.geometry.RoundRect);
+    method public static androidx.compose.ui.geometry.RoundRect translate-cBI5anY(androidx.compose.ui.geometry.RoundRect, long offset);
     method public static androidx.compose.ui.geometry.Rect wideMiddleRect(androidx.compose.ui.geometry.RoundRect);
     method public static androidx.compose.ui.geometry.RoundRect withRadius-Z0w6hBY(androidx.compose.ui.geometry.RoundRect, long radius);
   }
diff --git a/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Rect.kt b/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Rect.kt
index 409b0e1..4eae95f 100644
--- a/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Rect.kt
+++ b/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Rect.kt
@@ -28,26 +28,30 @@
 /**
  * An immutable, 2D, axis-aligned, floating-point rectangle whose coordinates
  * are relative to a given origin.
- *
- * A Rect can be created with one its constructors or from an [Offset] and a
- * [Size] using the `&` operator:
- *
- * ```dart
- * Rect myRect = const Offset(1.0, 2.0) & const Size(3.0, 4.0);
- * ```
  */
 @Immutable
 data class Rect(
-        // The offset of the left edge of this rectangle from the x axis.
+    /**
+     * The offset of the left edge of this rectangle from the x axis.
+     */
     @Stable
     val left: Float,
-        // The offset of the top edge of this rectangle from the y axis.
+
+    /**
+     * The offset of the top edge of this rectangle from the y axis.
+     */
     @Stable
     val top: Float,
-        // The offset of the right edge of this rectangle from the x axis.
+
+    /**
+     * The offset of the right edge of this rectangle from the x axis.
+     */
     @Stable
     val right: Float,
-        // The offset of the bottom edge of this rectangle from the y axis.
+
+    /**
+     * The offset of the bottom edge of this rectangle from the y axis.
+     */
     @Stable
     val bottom: Float
 ) {
@@ -108,17 +112,29 @@
      * To translate a rectangle by separate x and y components rather than by an
      * [Offset], consider [translate].
      */
+    @Deprecated(
+        "Use translate(offset) instead",
+        ReplaceWith("translate(offset)", "androidx.compose.ui.geometry")
+    )
     @Stable
     fun shift(offset: Offset): Rect {
         return Rect(left + offset.x, top + offset.y, right + offset.x, bottom + offset.y)
     }
 
     /**
+     * Returns a new rectangle translated by the given offset.
+     *
+     * To translate a rectangle by separate x and y components rather than by an
+     * [Offset], consider [translate].
+     */
+    @Stable
+    fun translate(offset: Offset): Rect {
+        return Rect(left + offset.x, top + offset.y, right + offset.x, bottom + offset.y)
+    }
+
+    /**
      * Returns a new rectangle with translateX added to the x components and
      * translateY added to the y components.
-     *
-     * To translate a rectangle by an [Offset] rather than by separate x and y
-     * components, consider [shift].
      */
     @Stable
     fun translate(translateX: Float, translateY: Float): Rect {
@@ -156,31 +172,6 @@
         )
     }
 
-    /**
-     * Returns a new rectangle which is the bounding box containing this
-     * rectangle and the given rectangle.
-     */
-    fun expandToInclude(other: Rect): Rect {
-        return Rect(
-            min(left, other.left),
-            min(top, other.top),
-            max(right, other.right),
-            max(bottom, other.bottom)
-        )
-    }
-
-    fun join(other: Rect): Rect {
-        if (other.isEmpty) {
-            // return this if the other params are empty
-            return this
-        }
-        if (isEmpty) {
-            // if we are empty, just take other
-            return other
-        }
-        return expandToInclude(other)
-    }
-
     /** Whether `other` has a nonzero area of overlap with this rectangle. */
     fun overlaps(other: Rect): Boolean {
         if (right <= other.left || other.right <= left)
diff --git a/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/RoundRect.kt b/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/RoundRect.kt
index 8115573..252067f 100644
--- a/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/RoundRect.kt
+++ b/compose/ui/ui-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/RoundRect.kt
@@ -574,7 +574,13 @@
 fun RoundRect.bottomLeftRadius(): Radius = Radius(bottomLeftRadiusX, bottomLeftRadiusY)
 
 /** Returns a new [RoundRect] translated by the given offset. */
-fun RoundRect.shift(offset: Offset): RoundRect = RoundRect(
+@Deprecated("Use translate(offset) instead",
+    ReplaceWith("translate(offset)", "androidx.compose.ui.RoundRect")
+)
+fun RoundRect.shift(offset: Offset): RoundRect = translate(offset)
+
+/** Returns a new [RoundRect] translated by the given offset. */
+fun RoundRect.translate(offset: Offset): RoundRect = RoundRect(
     left = left + offset.x,
     top = top + offset.y,
     right = right + offset.x,
diff --git a/compose/ui/ui-geometry/src/test/kotlin/androidx/compose/ui/geometry/RectTest.kt b/compose/ui/ui-geometry/src/test/kotlin/androidx/compose/ui/geometry/RectTest.kt
index 5edcabaf..ba68d88 100644
--- a/compose/ui/ui-geometry/src/test/kotlin/androidx/compose/ui/geometry/RectTest.kt
+++ b/compose/ui/ui-geometry/src/test/kotlin/androidx/compose/ui/geometry/RectTest.kt
@@ -104,8 +104,8 @@
     }
 
     @Test
-    fun `rect shift`() {
-        val shifted = Rect(0f, 5f, 10f, 15f).shift(Offset(10f, 15f))
+    fun `rect translate offset`() {
+        val shifted = Rect(0f, 5f, 10f, 15f).translate(Offset(10f, 15f))
         assertEquals(Rect(10f, 20f, 20f, 30f), shifted)
     }
 
@@ -135,21 +135,6 @@
     }
 
     @Test
-    fun `rect expandToInclude`() {
-        val expanded = Rect(0f, 0f, 20f, 20f).expandToInclude(
-            Rect(10f, 10f, 30f, 30f))
-        assertEquals(Rect(0f, 0f, 30f, 30f), expanded)
-    }
-
-    @Test
-    fun `rect join`() {
-        val rect1 = Rect.Zero
-        val rect2 = Rect(12f, 24f, 64f, 128f)
-        assertEquals(rect2, rect2.join(rect1))
-        assertEquals(rect2, rect1.join(rect2))
-    }
-
-    @Test
     fun `rect overlap`() {
         val rect1 = Rect(0f, 5f, 10f, 15f)
         val rect2 = Rect(5f, 10f, 15f, 20f)
diff --git a/compose/ui/ui-graphics/api/current.txt b/compose/ui/ui-graphics/api/current.txt
index 37b8fbe..187547b 100644
--- a/compose/ui/ui-graphics/api/current.txt
+++ b/compose/ui/ui-graphics/api/current.txt
@@ -96,7 +96,7 @@
     method public void relativeQuadraticBezierTo(float dx1, float dy1, float dx2, float dy2);
     method public void reset();
     method public void setFillType(androidx.compose.ui.graphics.PathFillType value);
-    method public void shift-k-4lQ0M(long offset);
+    method public void translate-k-4lQ0M(long offset);
     property public androidx.compose.ui.graphics.PathFillType fillType;
     property public boolean isConvex;
     property public boolean isEmpty;
@@ -500,7 +500,8 @@
     method public void relativeQuadraticBezierTo(float dx1, float dy1, float dx2, float dy2);
     method public void reset();
     method public void setFillType(androidx.compose.ui.graphics.PathFillType p);
-    method public void shift-k-4lQ0M(long offset);
+    method @Deprecated public default void shift-k-4lQ0M(long offset);
+    method public void translate-k-4lQ0M(long offset);
     property public abstract androidx.compose.ui.graphics.PathFillType fillType;
     property public abstract boolean isConvex;
     property public abstract boolean isEmpty;
@@ -880,9 +881,11 @@
   public final class DrawScopeKt {
     method public static inline void clipPath(androidx.compose.ui.graphics.drawscope.DrawScope, androidx.compose.ui.graphics.Path path, androidx.compose.ui.graphics.ClipOp clipOp = androidx.compose.ui.graphics.ClipOp.Intersect, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public static inline void clipRect(androidx.compose.ui.graphics.drawscope.DrawScope, float left = 0.0f, float top = 0.0f, float right = size.width, float bottom = size.height, androidx.compose.ui.graphics.ClipOp clipOp = androidx.compose.ui.graphics.ClipOp.Intersect, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
-    method public static inline void drawCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.Canvas,? super androidx.compose.ui.geometry.Size,kotlin.Unit> block);
+    method @Deprecated public static inline void drawCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.Canvas,? super androidx.compose.ui.geometry.Size,kotlin.Unit> block);
+    method public static inline void drawIntoCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.Canvas,kotlin.Unit> block);
     method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
-    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float dx = 0.0f, float dy = 0.0f, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float inset, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float horizontal = 0.0f, float vertical = 0.0f, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public static inline void rotate(androidx.compose.ui.graphics.drawscope.DrawScope, float degrees, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public static inline void rotateRad(androidx.compose.ui.graphics.drawscope.DrawScope, float radians, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public static inline void scale(androidx.compose.ui.graphics.drawscope.DrawScope, float scaleX, float scaleY = scaleX, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
@@ -911,7 +914,8 @@
   }
 
   public final class DrawTransformKt {
-    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float dx = 0.0f, float dy = 0.0f);
+    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float horizontal = 0.0f, float vertical = 0.0f);
+    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float inset);
     method public static inline void rotateRad(androidx.compose.ui.graphics.drawscope.DrawTransform, float radians, float pivotX = center.x, float pivotY = center.y);
   }
 
diff --git a/compose/ui/ui-graphics/api/public_plus_experimental_current.txt b/compose/ui/ui-graphics/api/public_plus_experimental_current.txt
index 37b8fbe..187547b 100644
--- a/compose/ui/ui-graphics/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-graphics/api/public_plus_experimental_current.txt
@@ -96,7 +96,7 @@
     method public void relativeQuadraticBezierTo(float dx1, float dy1, float dx2, float dy2);
     method public void reset();
     method public void setFillType(androidx.compose.ui.graphics.PathFillType value);
-    method public void shift-k-4lQ0M(long offset);
+    method public void translate-k-4lQ0M(long offset);
     property public androidx.compose.ui.graphics.PathFillType fillType;
     property public boolean isConvex;
     property public boolean isEmpty;
@@ -500,7 +500,8 @@
     method public void relativeQuadraticBezierTo(float dx1, float dy1, float dx2, float dy2);
     method public void reset();
     method public void setFillType(androidx.compose.ui.graphics.PathFillType p);
-    method public void shift-k-4lQ0M(long offset);
+    method @Deprecated public default void shift-k-4lQ0M(long offset);
+    method public void translate-k-4lQ0M(long offset);
     property public abstract androidx.compose.ui.graphics.PathFillType fillType;
     property public abstract boolean isConvex;
     property public abstract boolean isEmpty;
@@ -880,9 +881,11 @@
   public final class DrawScopeKt {
     method public static inline void clipPath(androidx.compose.ui.graphics.drawscope.DrawScope, androidx.compose.ui.graphics.Path path, androidx.compose.ui.graphics.ClipOp clipOp = androidx.compose.ui.graphics.ClipOp.Intersect, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public static inline void clipRect(androidx.compose.ui.graphics.drawscope.DrawScope, float left = 0.0f, float top = 0.0f, float right = size.width, float bottom = size.height, androidx.compose.ui.graphics.ClipOp clipOp = androidx.compose.ui.graphics.ClipOp.Intersect, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
-    method public static inline void drawCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.Canvas,? super androidx.compose.ui.geometry.Size,kotlin.Unit> block);
+    method @Deprecated public static inline void drawCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.Canvas,? super androidx.compose.ui.geometry.Size,kotlin.Unit> block);
+    method public static inline void drawIntoCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.Canvas,kotlin.Unit> block);
     method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
-    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float dx = 0.0f, float dy = 0.0f, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float inset, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float horizontal = 0.0f, float vertical = 0.0f, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public static inline void rotate(androidx.compose.ui.graphics.drawscope.DrawScope, float degrees, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public static inline void rotateRad(androidx.compose.ui.graphics.drawscope.DrawScope, float radians, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public static inline void scale(androidx.compose.ui.graphics.drawscope.DrawScope, float scaleX, float scaleY = scaleX, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
@@ -911,7 +914,8 @@
   }
 
   public final class DrawTransformKt {
-    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float dx = 0.0f, float dy = 0.0f);
+    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float horizontal = 0.0f, float vertical = 0.0f);
+    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float inset);
     method public static inline void rotateRad(androidx.compose.ui.graphics.drawscope.DrawTransform, float radians, float pivotX = center.x, float pivotY = center.y);
   }
 
diff --git a/compose/ui/ui-graphics/api/restricted_current.txt b/compose/ui/ui-graphics/api/restricted_current.txt
index bf9f72d..4d309aa 100644
--- a/compose/ui/ui-graphics/api/restricted_current.txt
+++ b/compose/ui/ui-graphics/api/restricted_current.txt
@@ -126,7 +126,7 @@
     method public void relativeQuadraticBezierTo(float dx1, float dy1, float dx2, float dy2);
     method public void reset();
     method public void setFillType(androidx.compose.ui.graphics.PathFillType value);
-    method public void shift-k-4lQ0M(long offset);
+    method public void translate-k-4lQ0M(long offset);
     property public androidx.compose.ui.graphics.PathFillType fillType;
     property public boolean isConvex;
     property public boolean isEmpty;
@@ -532,7 +532,8 @@
     method public void relativeQuadraticBezierTo(float dx1, float dy1, float dx2, float dy2);
     method public void reset();
     method public void setFillType(androidx.compose.ui.graphics.PathFillType p);
-    method public void shift-k-4lQ0M(long offset);
+    method @Deprecated public default void shift-k-4lQ0M(long offset);
+    method public void translate-k-4lQ0M(long offset);
     property public abstract androidx.compose.ui.graphics.PathFillType fillType;
     property public abstract boolean isConvex;
     property public abstract boolean isEmpty;
@@ -915,9 +916,11 @@
   public final class DrawScopeKt {
     method public static inline void clipPath(androidx.compose.ui.graphics.drawscope.DrawScope, androidx.compose.ui.graphics.Path path, androidx.compose.ui.graphics.ClipOp clipOp = androidx.compose.ui.graphics.ClipOp.Intersect, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public static inline void clipRect(androidx.compose.ui.graphics.drawscope.DrawScope, float left = 0.0f, float top = 0.0f, float right = size.width, float bottom = size.height, androidx.compose.ui.graphics.ClipOp clipOp = androidx.compose.ui.graphics.ClipOp.Intersect, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
-    method public static inline void drawCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.Canvas,? super androidx.compose.ui.geometry.Size,kotlin.Unit> block);
+    method @Deprecated public static inline void drawCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function2<? super androidx.compose.ui.graphics.Canvas,? super androidx.compose.ui.geometry.Size,kotlin.Unit> block);
+    method public static inline void drawIntoCanvas(androidx.compose.ui.graphics.drawscope.DrawScope, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.Canvas,kotlin.Unit> block);
     method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
-    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float dx = 0.0f, float dy = 0.0f, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float inset, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawScope, float horizontal = 0.0f, float vertical = 0.0f, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public static inline void rotate(androidx.compose.ui.graphics.drawscope.DrawScope, float degrees, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public static inline void rotateRad(androidx.compose.ui.graphics.drawscope.DrawScope, float radians, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
     method public static inline void scale(androidx.compose.ui.graphics.drawscope.DrawScope, float scaleX, float scaleY = scaleX, float pivotX = center.x, float pivotY = center.y, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
@@ -946,7 +949,8 @@
   }
 
   public final class DrawTransformKt {
-    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float dx = 0.0f, float dy = 0.0f);
+    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float horizontal = 0.0f, float vertical = 0.0f);
+    method public static inline void inset(androidx.compose.ui.graphics.drawscope.DrawTransform, float inset);
     method public static inline void rotateRad(androidx.compose.ui.graphics.drawscope.DrawTransform, float radians, float pivotX = center.x, float pivotY = center.y);
   }
 
diff --git a/compose/ui/ui-graphics/samples/build.gradle b/compose/ui/ui-graphics/samples/build.gradle
index a3603ac..02ccd5b 100644
--- a/compose/ui/ui-graphics/samples/build.gradle
+++ b/compose/ui/ui-graphics/samples/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt b/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt
index 696fafb..fb4cb0e 100644
--- a/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt
+++ b/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt
@@ -271,6 +271,57 @@
     }
 
     @Test
+    fun testDrawInsetHorizontalVertical() {
+        val img = createTestDstImage()
+        val insetHorizontal = 10.0f
+        val insetVertical = 12.0f
+        TestDrawScope().drawInto(Canvas(img), dstSize) {
+            inset(insetHorizontal, insetVertical, insetHorizontal, insetVertical) {
+                drawRect(color = Color.Red)
+            }
+        }
+
+        val pixelMap = img.toPixelMap()
+        for (i in 0 until pixelMap.width) {
+            for (j in 0 until pixelMap.height) {
+                val expectedColor =
+                    if (i >= insetHorizontal && i < pixelMap.width - insetHorizontal &&
+                        j >= insetVertical && j < pixelMap.height - insetVertical) {
+                        Color.Red
+                    } else {
+                        Color.White
+                    }
+                assertEquals("Coordinate: " + i + ", " + j, expectedColor, pixelMap[i, j])
+            }
+        }
+    }
+
+    @Test
+    fun testDrawInsetAll() {
+        val img = createTestDstImage()
+        val insetAll = 10.0f
+        TestDrawScope().drawInto(Canvas(img), dstSize) {
+            inset(insetAll) {
+                drawRect(color = Color.Red)
+            }
+        }
+
+        val pixelMap = img.toPixelMap()
+        for (i in 0 until pixelMap.width) {
+            for (j in 0 until pixelMap.height) {
+                val expectedColor =
+                    if (i >= insetAll && i < pixelMap.width - insetAll &&
+                        j >= insetAll && j < pixelMap.height - insetAll) {
+                        Color.Red
+                    } else {
+                        Color.White
+                    }
+                assertEquals("Coordinate: " + i + ", " + j, expectedColor, pixelMap[i, j])
+            }
+        }
+    }
+
+    @Test
     fun testInsetRestoredAfterScopedInsetDraw() {
         val img = createTestDstImage()
         TestDrawScope().drawInto(Canvas(img), dstSize) {
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.kt
index b61bae3..037cdd2 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.kt
@@ -184,7 +184,7 @@
         internalPath.reset()
     }
 
-    override fun shift(offset: Offset) {
+    override fun translate(offset: Offset) {
         mMatrix.reset()
         mMatrix.setTranslate(offset.x, offset.y)
         internalPath.transform(mMatrix)
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Path.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Path.kt
index 65d1df4..33441dd 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Path.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Path.kt
@@ -231,7 +231,16 @@
     /**
      * Translates all the segments of every subpath by the given offset.
      */
-    fun shift(offset: Offset)
+    @Deprecated(
+        "Use translate(offset) instead",
+        ReplaceWith("translate(offset)", "androidx.compose.ui.graphics.Path")
+    )
+    fun shift(offset: Offset) = translate(offset)
+
+    /**
+     * Translates all the segments of every subpath by the given offset.
+     */
+    fun translate(offset: Offset)
 
     /**
      * Compute the bounds of the control points of the path, and write the
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt
index fa1465a..94e6658 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt
@@ -46,7 +46,8 @@
  * the dimensions of the current painting area. This provides a callback to issue more
  * drawing instructions within the modified coordinate space. This method
  * modifies the width of the [DrawScope] to be equivalent to width - (left + right) as well as
- * height to height - (top + bottom)
+ * height to height - (top + bottom). After this method is invoked, the coordinate space is
+ * returned to the state before the inset was applied.
  *
  * @param left number of pixels to inset the left drawing bound
  * @param top number of pixels to inset the top drawing bound
@@ -67,18 +68,39 @@
 }
 
 /**
- * Convenience method modifies the [DrawScope] bounds to inset both left and right bounds by
- * [dx] as well as the top and bottom by [dy]. If only [dx] is provided, the same inset is applied
- * to all 4 bounds
+ * Convenience method modifies the [DrawScope] bounds to inset both left, top, right and
+ * bottom bounds by [inset]. After this method is invoked,
+ * the coordinate space is returned to the state before this inset was applied.
  *
- * @param dx number of pixels to inset both left and right bounds
- * @param dy Optional number of pixels to inset both top and bottom bounds, by default this also
- * insets the top and bottom by [dx] pixels
+ * @param inset number of pixels to inset left, top, right, and bottom bounds.
  * @param block lambda that is called to issue additional drawing commands within the modified
  * coordinate space
  */
-inline fun DrawScope.inset(dx: Float = 0.0f, dy: Float = 0.0f, block: DrawScope.() -> Unit) =
-    inset(dx, dy, dx, dy, block)
+inline fun DrawScope.inset(
+    inset: Float,
+    block: DrawScope.() -> Unit
+) {
+    transform.inset(inset, inset, inset, inset)
+    block()
+    transform.inset(-inset, -inset, -inset, -inset)
+}
+
+/**
+ * Convenience method modifies the [DrawScope] bounds to inset both left and right bounds by
+ * [horizontal] as well as the top and bottom by [vertical]. After this method is invoked,
+ * the coordinate space is returned to the state before this inset was applied.
+ *
+ * @param horizontal number of pixels to inset both left and right bounds. Zero by default
+ * @param vertical Optional number of pixels to inset both top and bottom bounds. Zero by
+ * default
+ * @param block lambda that is called to issue additional drawing commands within the modified
+ * coordinate space
+ */
+inline fun DrawScope.inset(
+    horizontal: Float = 0.0f,
+    vertical: Float = 0.0f,
+    block: DrawScope.() -> Unit
+) = inset(horizontal, vertical, horizontal, vertical, block)
 
 /**
  * Translate the coordinate space by the given delta in pixels in both the x and y coordinates
@@ -167,14 +189,16 @@
 
 /**
  * Reduces the clip region to the intersection of the current clip and the
- * given rectangle indicated by the given left, top, right and bottom bounds.
+ * given rectangle indicated by the given left, top, right and bottom bounds. This provides
+ * a callback to issue drawing commands within the clipped region. After this method is invoked,
+ * this clip is no longer applied.
  *
  * Use [ClipOp.Difference] to subtract the provided rectangle from the
  * current clip.
  *
  * @param left Left bound of the rectangle to clip
  * @param top Top bound of the rectangle to clip
- * @param right Right bound ofthe rectangle to clip
+ * @param right Right bound of the rectangle to clip
  * @param bottom Bottom bound of the rectangle to clip
  * @param clipOp Clipping operation to conduct on the given bounds, defaults to [ClipOp.Intersect]
  * @param block Lambda callback with this CanvasScope as a receiver scope to issue drawing commands
@@ -191,7 +215,8 @@
 
 /**
  * Reduces the clip region to the intersection of the current clip and the
- * given rounded rectangle.
+ * given path. This method provides a callback to issue drawing commands within the region
+ * defined by the clipped path. After this method is invoked, this clip is no longer applied.
  *
  * @param path Shape to clip drawing content within
  * @param clipOp Clipping operation to conduct on the given bounds, defaults to [ClipOp.Intersect]
@@ -205,12 +230,27 @@
 ) = withTransform({ clipPath(path, clipOp) }, block)
 
 /**
+ * Provides access to draw directly with the underlying [Canvas]. This is helpful for situations
+ * to re-use alternative drawing logic in combination with [DrawScope]
+ *
+ * @param block Lambda callback to issue drawing commands on the provided [Canvas]
+ */
+inline fun DrawScope.drawIntoCanvas(block: (Canvas) -> Unit) = block(canvas)
+
+/**
  * Provides access to draw directly with the underlying [Canvas] along with the current
  * size of the [DrawScope]. This is helpful for situations
  * to re-use alternative drawing logic in combination with [DrawScope]
  *
  * @param block Lambda callback to issue drawing commands on the provided [Canvas] and given size
  */
+@Deprecated(
+    "Use drawIntoCanvas instead",
+    ReplaceWith(
+        "drawIntoCanvas { canvas -> }",
+        "androidx.compose.ui.graphics.drawscope.drawIntoCanvas"
+    )
+)
 inline fun DrawScope.drawCanvas(block: (Canvas, Size) -> Unit) = block(canvas, size)
 
 /**
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawTransform.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawTransform.kt
index fc52620..4583266 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawTransform.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawTransform.kt
@@ -25,15 +25,27 @@
 
 /**
  * Convenience method modifies the [DrawTransform] bounds to inset both left and right bounds by
- * [dx] as well as the top and bottom by [dy]. If only [dx] is provided, the same inset is applied
- * to all 4 bounds
+ * [horizontal] as well as the top and bottom by [vertical]. After this method is
+ * invoked, the coordinate space is returned to the state before the inset was applied
  *
- * @param dx number of pixels to inset both left and right bounds
- * @param dy Optional number of pixels to inset both top and bottom bounds, by default this also
- * insets the top and bottom by [dx] pixels
+ * @param horizontal number of pixels to inset both left and right bounds. Zero by default.
+ * @param vertical number of pixels to inset both top and bottom bounds. Zero by default.
  */
 @Suppress("NOTHING_TO_INLINE")
-inline fun DrawTransform.inset(dx: Float = 0.0f, dy: Float = 0.0f) = inset(dx, dy, dx, dy)
+inline fun DrawTransform.inset(horizontal: Float = 0.0f, vertical: Float = 0.0f) =
+    inset(horizontal, vertical, horizontal, vertical)
+
+/**
+ * Convenience method modifies the [DrawScope] bounds to inset both left, top, right and
+ * bottom bounds by [inset]. After this method is invoked,
+ * the coordinate space is returned to the state before this inset was applied.
+ *
+ * @param inset number of pixels to inset left, top, right, and bottom bounds.
+ */
+@Suppress("NOTHING_TO_INLINE")
+inline fun DrawTransform.inset(
+    inset: Float
+) = inset(inset, inset)
 
 /**
  * Add a rotation (in radians clockwise) to the current transform at the given pivot point.
@@ -85,7 +97,8 @@
 
     /**
      * Reduces the clip region to the intersection of the current clip and the
-     * given rectangle indicated by the given left, top, right and bottom bounds
+     * given rectangle indicated by the given left, top, right and bottom bounds.
+     * After this method is invoked, this clip is no longer applied.
      *
      * Use [ClipOp.Difference] to subtract the provided rectangle from the
      * current clip.
@@ -106,7 +119,7 @@
 
     /**
      * Reduces the clip region to the intersection of the current clip and the
-     * given rounded rectangle.
+     * given rounded rectangle. After this method is invoked, this clip is no longer applied
      *
      * @param path Shape to clip drawing content within
      * @param clipOp Clipping operation to conduct on the given bounds, defaults to [ClipOp.Intersect]
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/painter/Painter.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/painter/Painter.kt
index 4191254..aafa202 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/painter/Painter.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/painter/Painter.kt
@@ -22,7 +22,7 @@
 import androidx.compose.ui.graphics.DefaultAlpha
 import androidx.compose.ui.graphics.Paint
 import androidx.compose.ui.graphics.drawscope.DrawScope
-import androidx.compose.ui.graphics.drawscope.drawCanvas
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
 import androidx.compose.ui.graphics.drawscope.inset
 import androidx.compose.ui.graphics.withSaveLayer
 import androidx.compose.ui.unit.LayoutDirection
@@ -200,10 +200,9 @@
 
             if (alpha > 0.0f && size.width > 0 && size.height > 0) {
                 if (useLayer) {
-                    val layerRect =
-                        Rect(Offset.Zero, Size(size.width, size.height))
+                    val layerRect = Rect(Offset.Zero, Size(size.width, size.height))
                     // TODO (b/154550724) njawad replace with RenderNode/Layer API usage
-                    drawCanvas { canvas, _ ->
+                    drawIntoCanvas { canvas ->
                         canvas.withSaveLayer(layerRect, obtainPaint()) {
                             onDraw()
                         }
diff --git a/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopPath.kt b/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopPath.kt
index 9c168c8..48c75e7 100644
--- a/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopPath.kt
+++ b/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopPath.kt
@@ -153,7 +153,7 @@
         internalPath.reset()
     }
 
-    override fun shift(offset: Offset) {
+    override fun translate(offset: Offset) {
         internalPath.transform(Matrix33.makeTranslate(offset.x, offset.y))
     }
 
diff --git a/compose/ui/ui-text/api/current.txt b/compose/ui/ui-text/api/current.txt
index dd69004..6fa0ebf 100644
--- a/compose/ui/ui-text/api/current.txt
+++ b/compose/ui/ui-text/api/current.txt
@@ -72,8 +72,8 @@
   }
 
   public final class MultiParagraph {
-    ctor public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, int maxLines, boolean ellipsis, androidx.compose.ui.text.ParagraphConstraints constraints);
-    ctor public MultiParagraph(androidx.compose.ui.text.AnnotatedString annotatedString, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, int maxLines, boolean ellipsis, androidx.compose.ui.text.ParagraphConstraints constraints, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
+    ctor public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, int maxLines, boolean ellipsis, float width);
+    ctor public MultiParagraph(androidx.compose.ui.text.AnnotatedString annotatedString, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, int maxLines, boolean ellipsis, float width, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
     method public androidx.compose.ui.text.style.ResolvedTextDirection getBidiRunDirection(int offset);
     method public androidx.compose.ui.geometry.Rect getBoundingBox(int offset);
     method public androidx.compose.ui.geometry.Rect getCursorRect(int offset);
@@ -103,7 +103,7 @@
     method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
     method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
     method public float getWidth();
-    method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+    method public long getWordBoundary(int offset);
     method public boolean isLineEllipsized(int lineIndex);
     method public void paint-TAOIQ28(androidx.compose.ui.graphics.Canvas canvas, long color = Color.Unset, androidx.compose.ui.graphics.Shadow? shadow = null, androidx.compose.ui.text.style.TextDecoration? decoration = null);
     property public final boolean didExceedMaxLines;
@@ -161,7 +161,7 @@
     method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
     method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
     method public float getWidth();
-    method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+    method public long getWordBoundary(int offset);
     method public boolean isLineEllipsized(int lineIndex);
     method public void paint-TAOIQ28(androidx.compose.ui.graphics.Canvas canvas, long color = Color.Unset, androidx.compose.ui.graphics.Shadow? shadow = null, androidx.compose.ui.text.style.TextDecoration? textDecoration = null);
     property public abstract boolean didExceedMaxLines;
@@ -175,13 +175,6 @@
     property public abstract float width;
   }
 
-  public final class ParagraphConstraints {
-    ctor public ParagraphConstraints(float width);
-    method public float component1();
-    method public androidx.compose.ui.text.ParagraphConstraints copy(float width);
-    method public float getWidth();
-  }
-
   public interface ParagraphIntrinsics {
     method public float getMaxIntrinsicWidth();
     method public float getMinIntrinsicWidth();
@@ -194,8 +187,8 @@
   }
 
   public final class ParagraphKt {
-    method public static androidx.compose.ui.text.Paragraph Paragraph(String text, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.SpanStyle>> spanStyles = listOf(), java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders = listOf(), int maxLines = 2147483647, boolean ellipsis = false, androidx.compose.ui.text.ParagraphConstraints constraints, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
-    method public static androidx.compose.ui.text.Paragraph Paragraph(androidx.compose.ui.text.ParagraphIntrinsics paragraphIntrinsics, int maxLines = 2147483647, boolean ellipsis = false, androidx.compose.ui.text.ParagraphConstraints constraints);
+    method public static androidx.compose.ui.text.Paragraph Paragraph(String text, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.SpanStyle>> spanStyles = listOf(), java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders = listOf(), int maxLines = 2147483647, boolean ellipsis = false, float width, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
+    method public static androidx.compose.ui.text.Paragraph Paragraph(androidx.compose.ui.text.ParagraphIntrinsics paragraphIntrinsics, int maxLines = 2147483647, boolean ellipsis = false, float width);
   }
 
   @androidx.compose.runtime.Immutable public final class ParagraphStyle {
@@ -350,7 +343,7 @@
     method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
     method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
     method public long getSize();
-    method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+    method public long getWordBoundary(int offset);
     method public boolean isLineEllipsized(int lineIndex);
     property public final boolean didOverflowHeight;
     property public final boolean didOverflowWidth;
@@ -362,7 +355,7 @@
   }
 
   public final class TextLayoutResultKt {
-    method @VisibleForTesting public static androidx.compose.ui.text.TextLayoutResult createTextLayoutResult-2H_Vf2E(androidx.compose.ui.text.TextLayoutInput layoutInput = androidx.compose.ui.text.TextLayoutInput(androidx.compose.ui.text.AnnotatedString(""), androidx.compose.ui.text.TextStyle(), emptyList(), 1, false, androidx.compose.ui.text.style.TextOverflow.Clip, Density(1.0), LayoutDirection.Ltr, null(), Constraints()), androidx.compose.ui.text.MultiParagraph multiParagraph = androidx.compose.ui.text.MultiParagraph(text, style, androidx.compose.ui.text.ParagraphConstraints(0.0), density, resourceLoader), long size = IntSize.Zero);
+    method @VisibleForTesting public static androidx.compose.ui.text.TextLayoutResult createTextLayoutResult-2H_Vf2E(androidx.compose.ui.text.TextLayoutInput layoutInput = androidx.compose.ui.text.TextLayoutInput(androidx.compose.ui.text.AnnotatedString(""), androidx.compose.ui.text.TextStyle(), emptyList(), 1, false, androidx.compose.ui.text.style.TextOverflow.Clip, Density(1.0), LayoutDirection.Ltr, null(), Constraints()), androidx.compose.ui.text.MultiParagraph multiParagraph = androidx.compose.ui.text.MultiParagraph(text, style, 0.0, density, resourceLoader), long size = IntSize.Zero);
   }
 
   public final class TextPainter {
@@ -370,37 +363,36 @@
     field public static final androidx.compose.ui.text.TextPainter INSTANCE;
   }
 
-  @androidx.compose.runtime.Immutable public final class TextRange {
-    ctor public TextRange(@IntRange(from=0) int start, @IntRange(from=0) int end);
-    method public int component1();
-    method public int component2();
-    method public operator boolean contains(androidx.compose.ui.text.TextRange other);
-    method public operator boolean contains(int offset);
-    method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.TextRange copy(int start, int end);
-    method public boolean getCollapsed();
-    method public int getEnd();
-    method public int getLength();
-    method public int getMax();
-    method public int getMin();
-    method public boolean getReversed();
-    method public int getStart();
-    method public boolean intersects(androidx.compose.ui.text.TextRange other);
-    property public final boolean collapsed;
-    property public final int length;
-    property public final int max;
-    property public final int min;
-    property public final boolean reversed;
+  @androidx.compose.runtime.Immutable public final inline class TextRange {
+    ctor public TextRange();
+    method public static long constructor-impl(long packedValue);
+    method public static long constructor-impl(int start, int end);
+    method public static operator boolean contains-5zc-tL8(long $this, long other);
+    method public static operator boolean contains-impl(long $this, int offset);
+    method @androidx.compose.runtime.Immutable public static inline boolean equals-impl(long p, Object? p1);
+    method public static boolean equals-impl0(long p1, long p2);
+    method public static boolean getCollapsed-impl(long $this);
+    method public static int getEnd-impl(long $this);
+    method public static int getLength-impl(long $this);
+    method public static int getMax-impl(long $this);
+    method public static int getMin-impl(long $this);
+    method public long getPackedValue();
+    method public static boolean getReversed-impl(long $this);
+    method public static int getStart-impl(long $this);
+    method @androidx.compose.runtime.Immutable public static inline int hashCode-impl(long p);
+    method public static boolean intersects-5zc-tL8(long $this, long other);
+    method public static String toString-impl(long $this);
     field public static final androidx.compose.ui.text.TextRange.Companion Companion;
   }
 
   public static final class TextRange.Companion {
-    method public androidx.compose.ui.text.TextRange getZero();
-    property public final androidx.compose.ui.text.TextRange Zero;
+    method public long getZero();
+    property public final long Zero;
   }
 
   public final class TextRangeKt {
-    method public static androidx.compose.ui.text.TextRange TextRange(int index);
-    method public static String substring(CharSequence, androidx.compose.ui.text.TextRange range);
+    method public static long TextRange(int index);
+    method public static String substring-cWlJSyE(CharSequence, long range);
   }
 
   @androidx.compose.runtime.Immutable public final class TextStyle {
@@ -674,20 +666,17 @@
   }
 
   public final class EditingBuffer {
-    ctor public EditingBuffer(String initialText, androidx.compose.ui.text.TextRange initialSelection);
     field public static final int NOWHERE = -1; // 0xffffffff
   }
 
   @Deprecated @androidx.compose.runtime.Immutable public final class EditorValue {
-    ctor @Deprecated public EditorValue(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
-    ctor @Deprecated public EditorValue();
     method @Deprecated public String component1();
-    method @Deprecated public androidx.compose.ui.text.TextRange component2();
+    method @Deprecated public long component2();
     method @Deprecated public androidx.compose.ui.text.TextRange? component3();
-    method @Deprecated @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.EditorValue copy(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
+    method @Deprecated @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.EditorValue copy-Dr2r1M0(String text, long selection, androidx.compose.ui.text.TextRange? composition);
     method @Deprecated public androidx.compose.ui.text.TextRange? getComposition();
     method @Deprecated public String getSelectedText();
-    method @Deprecated public androidx.compose.ui.text.TextRange getSelection();
+    method @Deprecated public long getSelection();
     method @Deprecated public String getText();
     method @Deprecated public String getTextAfterSelection(int maxChars);
     method @Deprecated public String getTextBeforeSelection(int maxChars);
@@ -800,14 +789,12 @@
   }
 
   @androidx.compose.runtime.Immutable public final class TextFieldValue {
-    ctor public TextFieldValue(@androidx.compose.runtime.Stable String text, @androidx.compose.runtime.Stable androidx.compose.ui.text.TextRange selection, @androidx.compose.runtime.Stable androidx.compose.ui.text.TextRange? composition);
-    ctor public TextFieldValue();
     method public String component1();
-    method public androidx.compose.ui.text.TextRange component2();
+    method public long component2();
     method public androidx.compose.ui.text.TextRange? component3();
-    method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.TextFieldValue copy(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
+    method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.TextFieldValue copy-Dr2r1M0(String text, long selection, androidx.compose.ui.text.TextRange? composition);
     method public androidx.compose.ui.text.TextRange? getComposition();
-    method public androidx.compose.ui.text.TextRange getSelection();
+    method public long getSelection();
     method public String getText();
     field public static final androidx.compose.ui.text.input.TextFieldValue.Companion Companion;
   }
diff --git a/compose/ui/ui-text/api/public_plus_experimental_current.txt b/compose/ui/ui-text/api/public_plus_experimental_current.txt
index dd69004..6fa0ebf 100644
--- a/compose/ui/ui-text/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-text/api/public_plus_experimental_current.txt
@@ -72,8 +72,8 @@
   }
 
   public final class MultiParagraph {
-    ctor public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, int maxLines, boolean ellipsis, androidx.compose.ui.text.ParagraphConstraints constraints);
-    ctor public MultiParagraph(androidx.compose.ui.text.AnnotatedString annotatedString, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, int maxLines, boolean ellipsis, androidx.compose.ui.text.ParagraphConstraints constraints, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
+    ctor public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, int maxLines, boolean ellipsis, float width);
+    ctor public MultiParagraph(androidx.compose.ui.text.AnnotatedString annotatedString, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, int maxLines, boolean ellipsis, float width, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
     method public androidx.compose.ui.text.style.ResolvedTextDirection getBidiRunDirection(int offset);
     method public androidx.compose.ui.geometry.Rect getBoundingBox(int offset);
     method public androidx.compose.ui.geometry.Rect getCursorRect(int offset);
@@ -103,7 +103,7 @@
     method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
     method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
     method public float getWidth();
-    method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+    method public long getWordBoundary(int offset);
     method public boolean isLineEllipsized(int lineIndex);
     method public void paint-TAOIQ28(androidx.compose.ui.graphics.Canvas canvas, long color = Color.Unset, androidx.compose.ui.graphics.Shadow? shadow = null, androidx.compose.ui.text.style.TextDecoration? decoration = null);
     property public final boolean didExceedMaxLines;
@@ -161,7 +161,7 @@
     method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
     method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
     method public float getWidth();
-    method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+    method public long getWordBoundary(int offset);
     method public boolean isLineEllipsized(int lineIndex);
     method public void paint-TAOIQ28(androidx.compose.ui.graphics.Canvas canvas, long color = Color.Unset, androidx.compose.ui.graphics.Shadow? shadow = null, androidx.compose.ui.text.style.TextDecoration? textDecoration = null);
     property public abstract boolean didExceedMaxLines;
@@ -175,13 +175,6 @@
     property public abstract float width;
   }
 
-  public final class ParagraphConstraints {
-    ctor public ParagraphConstraints(float width);
-    method public float component1();
-    method public androidx.compose.ui.text.ParagraphConstraints copy(float width);
-    method public float getWidth();
-  }
-
   public interface ParagraphIntrinsics {
     method public float getMaxIntrinsicWidth();
     method public float getMinIntrinsicWidth();
@@ -194,8 +187,8 @@
   }
 
   public final class ParagraphKt {
-    method public static androidx.compose.ui.text.Paragraph Paragraph(String text, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.SpanStyle>> spanStyles = listOf(), java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders = listOf(), int maxLines = 2147483647, boolean ellipsis = false, androidx.compose.ui.text.ParagraphConstraints constraints, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
-    method public static androidx.compose.ui.text.Paragraph Paragraph(androidx.compose.ui.text.ParagraphIntrinsics paragraphIntrinsics, int maxLines = 2147483647, boolean ellipsis = false, androidx.compose.ui.text.ParagraphConstraints constraints);
+    method public static androidx.compose.ui.text.Paragraph Paragraph(String text, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.SpanStyle>> spanStyles = listOf(), java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders = listOf(), int maxLines = 2147483647, boolean ellipsis = false, float width, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
+    method public static androidx.compose.ui.text.Paragraph Paragraph(androidx.compose.ui.text.ParagraphIntrinsics paragraphIntrinsics, int maxLines = 2147483647, boolean ellipsis = false, float width);
   }
 
   @androidx.compose.runtime.Immutable public final class ParagraphStyle {
@@ -350,7 +343,7 @@
     method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
     method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
     method public long getSize();
-    method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+    method public long getWordBoundary(int offset);
     method public boolean isLineEllipsized(int lineIndex);
     property public final boolean didOverflowHeight;
     property public final boolean didOverflowWidth;
@@ -362,7 +355,7 @@
   }
 
   public final class TextLayoutResultKt {
-    method @VisibleForTesting public static androidx.compose.ui.text.TextLayoutResult createTextLayoutResult-2H_Vf2E(androidx.compose.ui.text.TextLayoutInput layoutInput = androidx.compose.ui.text.TextLayoutInput(androidx.compose.ui.text.AnnotatedString(""), androidx.compose.ui.text.TextStyle(), emptyList(), 1, false, androidx.compose.ui.text.style.TextOverflow.Clip, Density(1.0), LayoutDirection.Ltr, null(), Constraints()), androidx.compose.ui.text.MultiParagraph multiParagraph = androidx.compose.ui.text.MultiParagraph(text, style, androidx.compose.ui.text.ParagraphConstraints(0.0), density, resourceLoader), long size = IntSize.Zero);
+    method @VisibleForTesting public static androidx.compose.ui.text.TextLayoutResult createTextLayoutResult-2H_Vf2E(androidx.compose.ui.text.TextLayoutInput layoutInput = androidx.compose.ui.text.TextLayoutInput(androidx.compose.ui.text.AnnotatedString(""), androidx.compose.ui.text.TextStyle(), emptyList(), 1, false, androidx.compose.ui.text.style.TextOverflow.Clip, Density(1.0), LayoutDirection.Ltr, null(), Constraints()), androidx.compose.ui.text.MultiParagraph multiParagraph = androidx.compose.ui.text.MultiParagraph(text, style, 0.0, density, resourceLoader), long size = IntSize.Zero);
   }
 
   public final class TextPainter {
@@ -370,37 +363,36 @@
     field public static final androidx.compose.ui.text.TextPainter INSTANCE;
   }
 
-  @androidx.compose.runtime.Immutable public final class TextRange {
-    ctor public TextRange(@IntRange(from=0) int start, @IntRange(from=0) int end);
-    method public int component1();
-    method public int component2();
-    method public operator boolean contains(androidx.compose.ui.text.TextRange other);
-    method public operator boolean contains(int offset);
-    method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.TextRange copy(int start, int end);
-    method public boolean getCollapsed();
-    method public int getEnd();
-    method public int getLength();
-    method public int getMax();
-    method public int getMin();
-    method public boolean getReversed();
-    method public int getStart();
-    method public boolean intersects(androidx.compose.ui.text.TextRange other);
-    property public final boolean collapsed;
-    property public final int length;
-    property public final int max;
-    property public final int min;
-    property public final boolean reversed;
+  @androidx.compose.runtime.Immutable public final inline class TextRange {
+    ctor public TextRange();
+    method public static long constructor-impl(long packedValue);
+    method public static long constructor-impl(int start, int end);
+    method public static operator boolean contains-5zc-tL8(long $this, long other);
+    method public static operator boolean contains-impl(long $this, int offset);
+    method @androidx.compose.runtime.Immutable public static inline boolean equals-impl(long p, Object? p1);
+    method public static boolean equals-impl0(long p1, long p2);
+    method public static boolean getCollapsed-impl(long $this);
+    method public static int getEnd-impl(long $this);
+    method public static int getLength-impl(long $this);
+    method public static int getMax-impl(long $this);
+    method public static int getMin-impl(long $this);
+    method public long getPackedValue();
+    method public static boolean getReversed-impl(long $this);
+    method public static int getStart-impl(long $this);
+    method @androidx.compose.runtime.Immutable public static inline int hashCode-impl(long p);
+    method public static boolean intersects-5zc-tL8(long $this, long other);
+    method public static String toString-impl(long $this);
     field public static final androidx.compose.ui.text.TextRange.Companion Companion;
   }
 
   public static final class TextRange.Companion {
-    method public androidx.compose.ui.text.TextRange getZero();
-    property public final androidx.compose.ui.text.TextRange Zero;
+    method public long getZero();
+    property public final long Zero;
   }
 
   public final class TextRangeKt {
-    method public static androidx.compose.ui.text.TextRange TextRange(int index);
-    method public static String substring(CharSequence, androidx.compose.ui.text.TextRange range);
+    method public static long TextRange(int index);
+    method public static String substring-cWlJSyE(CharSequence, long range);
   }
 
   @androidx.compose.runtime.Immutable public final class TextStyle {
@@ -674,20 +666,17 @@
   }
 
   public final class EditingBuffer {
-    ctor public EditingBuffer(String initialText, androidx.compose.ui.text.TextRange initialSelection);
     field public static final int NOWHERE = -1; // 0xffffffff
   }
 
   @Deprecated @androidx.compose.runtime.Immutable public final class EditorValue {
-    ctor @Deprecated public EditorValue(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
-    ctor @Deprecated public EditorValue();
     method @Deprecated public String component1();
-    method @Deprecated public androidx.compose.ui.text.TextRange component2();
+    method @Deprecated public long component2();
     method @Deprecated public androidx.compose.ui.text.TextRange? component3();
-    method @Deprecated @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.EditorValue copy(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
+    method @Deprecated @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.EditorValue copy-Dr2r1M0(String text, long selection, androidx.compose.ui.text.TextRange? composition);
     method @Deprecated public androidx.compose.ui.text.TextRange? getComposition();
     method @Deprecated public String getSelectedText();
-    method @Deprecated public androidx.compose.ui.text.TextRange getSelection();
+    method @Deprecated public long getSelection();
     method @Deprecated public String getText();
     method @Deprecated public String getTextAfterSelection(int maxChars);
     method @Deprecated public String getTextBeforeSelection(int maxChars);
@@ -800,14 +789,12 @@
   }
 
   @androidx.compose.runtime.Immutable public final class TextFieldValue {
-    ctor public TextFieldValue(@androidx.compose.runtime.Stable String text, @androidx.compose.runtime.Stable androidx.compose.ui.text.TextRange selection, @androidx.compose.runtime.Stable androidx.compose.ui.text.TextRange? composition);
-    ctor public TextFieldValue();
     method public String component1();
-    method public androidx.compose.ui.text.TextRange component2();
+    method public long component2();
     method public androidx.compose.ui.text.TextRange? component3();
-    method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.TextFieldValue copy(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
+    method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.TextFieldValue copy-Dr2r1M0(String text, long selection, androidx.compose.ui.text.TextRange? composition);
     method public androidx.compose.ui.text.TextRange? getComposition();
-    method public androidx.compose.ui.text.TextRange getSelection();
+    method public long getSelection();
     method public String getText();
     field public static final androidx.compose.ui.text.input.TextFieldValue.Companion Companion;
   }
diff --git a/compose/ui/ui-text/api/restricted_current.txt b/compose/ui/ui-text/api/restricted_current.txt
index dd69004..6fa0ebf 100644
--- a/compose/ui/ui-text/api/restricted_current.txt
+++ b/compose/ui/ui-text/api/restricted_current.txt
@@ -72,8 +72,8 @@
   }
 
   public final class MultiParagraph {
-    ctor public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, int maxLines, boolean ellipsis, androidx.compose.ui.text.ParagraphConstraints constraints);
-    ctor public MultiParagraph(androidx.compose.ui.text.AnnotatedString annotatedString, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, int maxLines, boolean ellipsis, androidx.compose.ui.text.ParagraphConstraints constraints, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
+    ctor public MultiParagraph(androidx.compose.ui.text.MultiParagraphIntrinsics intrinsics, int maxLines, boolean ellipsis, float width);
+    ctor public MultiParagraph(androidx.compose.ui.text.AnnotatedString annotatedString, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders, int maxLines, boolean ellipsis, float width, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
     method public androidx.compose.ui.text.style.ResolvedTextDirection getBidiRunDirection(int offset);
     method public androidx.compose.ui.geometry.Rect getBoundingBox(int offset);
     method public androidx.compose.ui.geometry.Rect getCursorRect(int offset);
@@ -103,7 +103,7 @@
     method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
     method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
     method public float getWidth();
-    method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+    method public long getWordBoundary(int offset);
     method public boolean isLineEllipsized(int lineIndex);
     method public void paint-TAOIQ28(androidx.compose.ui.graphics.Canvas canvas, long color = Color.Unset, androidx.compose.ui.graphics.Shadow? shadow = null, androidx.compose.ui.text.style.TextDecoration? decoration = null);
     property public final boolean didExceedMaxLines;
@@ -161,7 +161,7 @@
     method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
     method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
     method public float getWidth();
-    method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+    method public long getWordBoundary(int offset);
     method public boolean isLineEllipsized(int lineIndex);
     method public void paint-TAOIQ28(androidx.compose.ui.graphics.Canvas canvas, long color = Color.Unset, androidx.compose.ui.graphics.Shadow? shadow = null, androidx.compose.ui.text.style.TextDecoration? textDecoration = null);
     property public abstract boolean didExceedMaxLines;
@@ -175,13 +175,6 @@
     property public abstract float width;
   }
 
-  public final class ParagraphConstraints {
-    ctor public ParagraphConstraints(float width);
-    method public float component1();
-    method public androidx.compose.ui.text.ParagraphConstraints copy(float width);
-    method public float getWidth();
-  }
-
   public interface ParagraphIntrinsics {
     method public float getMaxIntrinsicWidth();
     method public float getMinIntrinsicWidth();
@@ -194,8 +187,8 @@
   }
 
   public final class ParagraphKt {
-    method public static androidx.compose.ui.text.Paragraph Paragraph(String text, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.SpanStyle>> spanStyles = listOf(), java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders = listOf(), int maxLines = 2147483647, boolean ellipsis = false, androidx.compose.ui.text.ParagraphConstraints constraints, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
-    method public static androidx.compose.ui.text.Paragraph Paragraph(androidx.compose.ui.text.ParagraphIntrinsics paragraphIntrinsics, int maxLines = 2147483647, boolean ellipsis = false, androidx.compose.ui.text.ParagraphConstraints constraints);
+    method public static androidx.compose.ui.text.Paragraph Paragraph(String text, androidx.compose.ui.text.TextStyle style, java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.SpanStyle>> spanStyles = listOf(), java.util.List<androidx.compose.ui.text.AnnotatedString.Range<androidx.compose.ui.text.Placeholder>> placeholders = listOf(), int maxLines = 2147483647, boolean ellipsis = false, float width, androidx.compose.ui.unit.Density density, androidx.compose.ui.text.font.Font.ResourceLoader resourceLoader);
+    method public static androidx.compose.ui.text.Paragraph Paragraph(androidx.compose.ui.text.ParagraphIntrinsics paragraphIntrinsics, int maxLines = 2147483647, boolean ellipsis = false, float width);
   }
 
   @androidx.compose.runtime.Immutable public final class ParagraphStyle {
@@ -350,7 +343,7 @@
     method public androidx.compose.ui.graphics.Path getPathForRange(int start, int end);
     method public java.util.List<androidx.compose.ui.geometry.Rect> getPlaceholderRects();
     method public long getSize();
-    method public androidx.compose.ui.text.TextRange getWordBoundary(int offset);
+    method public long getWordBoundary(int offset);
     method public boolean isLineEllipsized(int lineIndex);
     property public final boolean didOverflowHeight;
     property public final boolean didOverflowWidth;
@@ -362,7 +355,7 @@
   }
 
   public final class TextLayoutResultKt {
-    method @VisibleForTesting public static androidx.compose.ui.text.TextLayoutResult createTextLayoutResult-2H_Vf2E(androidx.compose.ui.text.TextLayoutInput layoutInput = androidx.compose.ui.text.TextLayoutInput(androidx.compose.ui.text.AnnotatedString(""), androidx.compose.ui.text.TextStyle(), emptyList(), 1, false, androidx.compose.ui.text.style.TextOverflow.Clip, Density(1.0), LayoutDirection.Ltr, null(), Constraints()), androidx.compose.ui.text.MultiParagraph multiParagraph = androidx.compose.ui.text.MultiParagraph(text, style, androidx.compose.ui.text.ParagraphConstraints(0.0), density, resourceLoader), long size = IntSize.Zero);
+    method @VisibleForTesting public static androidx.compose.ui.text.TextLayoutResult createTextLayoutResult-2H_Vf2E(androidx.compose.ui.text.TextLayoutInput layoutInput = androidx.compose.ui.text.TextLayoutInput(androidx.compose.ui.text.AnnotatedString(""), androidx.compose.ui.text.TextStyle(), emptyList(), 1, false, androidx.compose.ui.text.style.TextOverflow.Clip, Density(1.0), LayoutDirection.Ltr, null(), Constraints()), androidx.compose.ui.text.MultiParagraph multiParagraph = androidx.compose.ui.text.MultiParagraph(text, style, 0.0, density, resourceLoader), long size = IntSize.Zero);
   }
 
   public final class TextPainter {
@@ -370,37 +363,36 @@
     field public static final androidx.compose.ui.text.TextPainter INSTANCE;
   }
 
-  @androidx.compose.runtime.Immutable public final class TextRange {
-    ctor public TextRange(@IntRange(from=0) int start, @IntRange(from=0) int end);
-    method public int component1();
-    method public int component2();
-    method public operator boolean contains(androidx.compose.ui.text.TextRange other);
-    method public operator boolean contains(int offset);
-    method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.TextRange copy(int start, int end);
-    method public boolean getCollapsed();
-    method public int getEnd();
-    method public int getLength();
-    method public int getMax();
-    method public int getMin();
-    method public boolean getReversed();
-    method public int getStart();
-    method public boolean intersects(androidx.compose.ui.text.TextRange other);
-    property public final boolean collapsed;
-    property public final int length;
-    property public final int max;
-    property public final int min;
-    property public final boolean reversed;
+  @androidx.compose.runtime.Immutable public final inline class TextRange {
+    ctor public TextRange();
+    method public static long constructor-impl(long packedValue);
+    method public static long constructor-impl(int start, int end);
+    method public static operator boolean contains-5zc-tL8(long $this, long other);
+    method public static operator boolean contains-impl(long $this, int offset);
+    method @androidx.compose.runtime.Immutable public static inline boolean equals-impl(long p, Object? p1);
+    method public static boolean equals-impl0(long p1, long p2);
+    method public static boolean getCollapsed-impl(long $this);
+    method public static int getEnd-impl(long $this);
+    method public static int getLength-impl(long $this);
+    method public static int getMax-impl(long $this);
+    method public static int getMin-impl(long $this);
+    method public long getPackedValue();
+    method public static boolean getReversed-impl(long $this);
+    method public static int getStart-impl(long $this);
+    method @androidx.compose.runtime.Immutable public static inline int hashCode-impl(long p);
+    method public static boolean intersects-5zc-tL8(long $this, long other);
+    method public static String toString-impl(long $this);
     field public static final androidx.compose.ui.text.TextRange.Companion Companion;
   }
 
   public static final class TextRange.Companion {
-    method public androidx.compose.ui.text.TextRange getZero();
-    property public final androidx.compose.ui.text.TextRange Zero;
+    method public long getZero();
+    property public final long Zero;
   }
 
   public final class TextRangeKt {
-    method public static androidx.compose.ui.text.TextRange TextRange(int index);
-    method public static String substring(CharSequence, androidx.compose.ui.text.TextRange range);
+    method public static long TextRange(int index);
+    method public static String substring-cWlJSyE(CharSequence, long range);
   }
 
   @androidx.compose.runtime.Immutable public final class TextStyle {
@@ -674,20 +666,17 @@
   }
 
   public final class EditingBuffer {
-    ctor public EditingBuffer(String initialText, androidx.compose.ui.text.TextRange initialSelection);
     field public static final int NOWHERE = -1; // 0xffffffff
   }
 
   @Deprecated @androidx.compose.runtime.Immutable public final class EditorValue {
-    ctor @Deprecated public EditorValue(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
-    ctor @Deprecated public EditorValue();
     method @Deprecated public String component1();
-    method @Deprecated public androidx.compose.ui.text.TextRange component2();
+    method @Deprecated public long component2();
     method @Deprecated public androidx.compose.ui.text.TextRange? component3();
-    method @Deprecated @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.EditorValue copy(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
+    method @Deprecated @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.EditorValue copy-Dr2r1M0(String text, long selection, androidx.compose.ui.text.TextRange? composition);
     method @Deprecated public androidx.compose.ui.text.TextRange? getComposition();
     method @Deprecated public String getSelectedText();
-    method @Deprecated public androidx.compose.ui.text.TextRange getSelection();
+    method @Deprecated public long getSelection();
     method @Deprecated public String getText();
     method @Deprecated public String getTextAfterSelection(int maxChars);
     method @Deprecated public String getTextBeforeSelection(int maxChars);
@@ -800,14 +789,12 @@
   }
 
   @androidx.compose.runtime.Immutable public final class TextFieldValue {
-    ctor public TextFieldValue(@androidx.compose.runtime.Stable String text, @androidx.compose.runtime.Stable androidx.compose.ui.text.TextRange selection, @androidx.compose.runtime.Stable androidx.compose.ui.text.TextRange? composition);
-    ctor public TextFieldValue();
     method public String component1();
-    method public androidx.compose.ui.text.TextRange component2();
+    method public long component2();
     method public androidx.compose.ui.text.TextRange? component3();
-    method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.TextFieldValue copy(String text, androidx.compose.ui.text.TextRange selection, androidx.compose.ui.text.TextRange? composition);
+    method @androidx.compose.runtime.Immutable public androidx.compose.ui.text.input.TextFieldValue copy-Dr2r1M0(String text, long selection, androidx.compose.ui.text.TextRange? composition);
     method public androidx.compose.ui.text.TextRange? getComposition();
-    method public androidx.compose.ui.text.TextRange getSelection();
+    method public long getSelection();
     method public String getText();
     field public static final androidx.compose.ui.text.input.TextFieldValue.Companion Companion;
   }
diff --git a/compose/ui/ui-text/samples/build.gradle b/compose/ui/ui-text/samples/build.gradle
index 913904e..e213e45 100644
--- a/compose/ui/ui-text/samples/build.gradle
+++ b/compose/ui/ui-text/samples/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt
index 1abd85c..87135d0 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTest.kt
@@ -1231,7 +1231,7 @@
         val paragraph = MultiParagraph(
             annotatedString = text,
             style = TextStyle(textDirection = TextDirection.Rtl),
-            constraints = ParagraphConstraints(Float.MAX_VALUE),
+            width = Float.MAX_VALUE,
             density = defaultDensity,
             resourceLoader = TestFontResourceLoader(context)
         )
@@ -1263,7 +1263,7 @@
                 fontFamily = fontFamilyMeasureFont
             ),
             placeholders = placeholders,
-            constraints = ParagraphConstraints(Float.MAX_VALUE),
+            width = Float.MAX_VALUE,
             density = defaultDensity,
             resourceLoader = TestFontResourceLoader(context)
         )
@@ -1294,7 +1294,7 @@
                 fontFamily = fontFamilyMeasureFont
             ),
             placeholders = placeholders,
-            constraints = ParagraphConstraints(Float.MAX_VALUE),
+            width = Float.MAX_VALUE,
             density = defaultDensity,
             resourceLoader = TestFontResourceLoader(context)
         )
@@ -1326,7 +1326,7 @@
                 fontFamily = fontFamilyMeasureFont
             ),
             placeholders = placeholders,
-            constraints = ParagraphConstraints(Float.MAX_VALUE),
+            width = Float.MAX_VALUE,
             density = defaultDensity,
             resourceLoader = TestFontResourceLoader(context)
         )
@@ -1368,7 +1368,7 @@
                 fontFamily = fontFamilyMeasureFont
             ),
             placeholders = placeholders,
-            constraints = ParagraphConstraints(Float.MAX_VALUE),
+            width = Float.MAX_VALUE,
             density = defaultDensity,
             resourceLoader = TestFontResourceLoader(context)
         )
@@ -1413,7 +1413,7 @@
                 fontFamily = fontFamilyMeasureFont
             ),
             placeholders = placeholders,
-            constraints = ParagraphConstraints(Float.MAX_VALUE),
+            width = Float.MAX_VALUE,
             density = defaultDensity,
             resourceLoader = TestFontResourceLoader(context)
         )
@@ -1469,7 +1469,7 @@
                 fontSize = fontSize
             ).merge(style),
             maxLines = maxLines,
-            constraints = ParagraphConstraints(width),
+            width = width,
             density = defaultDensity,
             resourceLoader = TestFontResourceLoader(context)
         )
@@ -1491,7 +1491,7 @@
                 localeList = localeList
             ).merge(style),
             maxLines = maxLines,
-            constraints = ParagraphConstraints(width),
+            width = width,
             density = defaultDensity,
             resourceLoader = TestFontResourceLoader(context)
         )
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTextDirectionTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTextDirectionTest.kt
index 74d0bc0..13fea3a 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTextDirectionTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/MultiParagraphIntegrationTextDirectionTest.kt
@@ -283,7 +283,7 @@
                 localeList = localeList,
                 textDirection = textDirection
             ),
-            constraints = ParagraphConstraints(width),
+            width = width,
             density = defaultDensity,
             resourceLoader = TestFontResourceLoader(context)
         )
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt
index 4d2484b..8ea1e59 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTest.kt
@@ -74,7 +74,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = 100.0f)
+                width = 100.0f
             )
 
             assertThat(paragraph.width).isEqualTo(100.0f)
@@ -99,7 +99,7 @@
                     text = text,
                     style = TextStyle(fontSize = fontSize),
                     // width greater than text width - 150
-                    constraints = ParagraphConstraints(width = 200.0f)
+                    width = 200.0f
                 )
 
                 assertWithMessage(text).that(paragraph.width).isEqualTo(200.0f)
@@ -126,7 +126,7 @@
                     text = text,
                     style = TextStyle(fontSize = fontSize),
                     // 3 chars width
-                    constraints = ParagraphConstraints(width = 3 * fontSizeInPx)
+                    width = 3 * fontSizeInPx
                 )
 
                 // 3 chars
@@ -159,7 +159,7 @@
                     text = text,
                     style = TextStyle(fontSize = fontSize),
                     // 3 chars width
-                    constraints = ParagraphConstraints(width = 3 * fontSizeInPx)
+                    width = 3 * fontSizeInPx
                 )
 
                 // 3 chars
@@ -190,7 +190,7 @@
                     text = text,
                     style = TextStyle(fontSize = fontSize),
                     // 2 chars width
-                    constraints = ParagraphConstraints(width = 2 * fontSizeInPx)
+                    width = 2 * fontSizeInPx
                 )
 
                 // 2 chars
@@ -220,7 +220,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+                width = text.length * fontSizeInPx
             )
 
             // test positions that are 1, fontSize+1, 2fontSize+1 which maps to chars 0, 1, 2 ...
@@ -242,7 +242,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+                width = text.length * fontSizeInPx
             )
 
             // test positions that are 1, fontSize+1, 2fontSize+1 which maps to chars .., 2, 1, 0
@@ -266,7 +266,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = firstLine.length * fontSizeInPx)
+                width = firstLine.length * fontSizeInPx
             )
 
             // test positions are 1, fontSize+1, 2fontSize+1 and always on the second line
@@ -292,7 +292,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = firstLine.length * fontSizeInPx)
+                width = firstLine.length * fontSizeInPx
             )
 
             // test positions are 1, fontSize+1, 2fontSize+1 and always on the second line
@@ -316,7 +316,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+                width = text.length * fontSizeInPx
             )
 
             // greater than width
@@ -340,7 +340,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+                width = text.length * fontSizeInPx
             )
 
             // greater than height
@@ -370,7 +370,7 @@
                     fontSize = fontSize.sp,
                     lineHeight = lineHeight.sp
                 ),
-                constraints = ParagraphConstraints(width = layoutWidth)
+                width = layoutWidth
             )
 
             assertThat(paragraph.lineCount).isEqualTo(4)
@@ -401,7 +401,7 @@
                     fontSize = fontSize.sp,
                     lineHeight = lineHeight.sp
                 ),
-                constraints = ParagraphConstraints(width = layoutWidth)
+                width = layoutWidth
             )
 
             assertThat(paragraph.lineCount).isEqualTo(4)
@@ -432,7 +432,7 @@
                     fontSize = fontSize.sp,
                     lineHeight = lineHeight.sp
                 ),
-                constraints = ParagraphConstraints(width = layoutWidth)
+                width = layoutWidth
             )
 
             assertThat(paragraph.lineCount).isEqualTo(4)
@@ -457,7 +457,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+                width = text.length * fontSizeInPx
             )
 
             // test positions that are 0, 1, 2 ... which maps to chars 0, 1, 2 ...
@@ -482,7 +482,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = firstLine.length * fontSizeInPx)
+                width = firstLine.length * fontSizeInPx
             )
 
             // test positions are 3, 4, 5 and always on the second line
@@ -507,7 +507,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+                width = text.length * fontSizeInPx
             )
 
             val textPosition = -1
@@ -529,7 +529,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+                width = text.length * fontSizeInPx
             )
 
             val textPosition = text.length + 1
@@ -546,7 +546,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+                width = text.length * fontSizeInPx
             )
 
             paragraph.getCursorRect(text.length + 1)
@@ -562,7 +562,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+                width = text.length * fontSizeInPx
             )
 
             paragraph.getCursorRect(-1)
@@ -578,7 +578,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+                width = text.length * fontSizeInPx
             )
 
             for (i in text.indices) {
@@ -606,7 +606,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = charsPerLine * fontSizeInPx)
+                width = charsPerLine * fontSizeInPx
             )
 
             for (i in 0 until charsPerLine) {
@@ -710,7 +710,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+                width = text.length * fontSizeInPx
             )
 
             for (i in text.indices) {
@@ -737,7 +737,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = charsPerLine * fontSizeInPx)
+                width = charsPerLine * fontSizeInPx
             )
 
             for (i in 0 until charsPerLine) {
@@ -775,7 +775,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = 3 * fontSizeInPx)
+                width = 3 * fontSizeInPx
             )
 
             // Cursor before '\n'
@@ -810,7 +810,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize, localeList = ltrLocaleList),
-                constraints = ParagraphConstraints(width = 3 * fontSizeInPx)
+                width = 3 * fontSizeInPx
             )
 
             // Cursor before '\n'
@@ -844,7 +844,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+                width = text.length * fontSizeInPx
             )
 
             for (i in 0..text.length) {
@@ -864,7 +864,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in 0..text.length) {
@@ -886,7 +886,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in 0..ltrText.length) {
@@ -917,7 +917,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Rtl
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             assertThat(paragraph.getHorizontalPosition(0, true)).isEqualTo(width)
@@ -944,7 +944,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Ltr
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             assertThat(paragraph.getHorizontalPosition(0, true)).isZero()
@@ -974,7 +974,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Ltr
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in 0..ltrText.length) {
@@ -1007,7 +1007,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Rtl
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             assertThat(paragraph.getHorizontalPosition(0, true)).isEqualTo(width)
@@ -1034,7 +1034,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize, localeList = ltrLocaleList),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             assertThat(paragraph.getHorizontalPosition(text.length, true)).isZero()
@@ -1053,7 +1053,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize, localeList = ltrLocaleList),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             assertThat(paragraph.getHorizontalPosition(text.length, true)).isZero()
@@ -1073,7 +1073,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Rtl
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             assertThat(paragraph.getHorizontalPosition(text.length, true))
@@ -1094,7 +1094,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Ltr
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             assertThat(paragraph.getHorizontalPosition(text.length, true)).isZero()
@@ -1110,7 +1110,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = text.length * fontSizeInPx)
+                width = text.length * fontSizeInPx
             )
 
             for (i in 0..text.length) {
@@ -1130,7 +1130,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in 0..text.length) {
@@ -1152,7 +1152,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in ltrText.indices) {
@@ -1180,7 +1180,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Rtl
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             assertThat(paragraph.getHorizontalPosition(0, false)).isZero()
@@ -1208,7 +1208,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Ltr
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             assertThat(paragraph.getHorizontalPosition(0, false)).isEqualTo(width)
@@ -1237,7 +1237,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Ltr
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in ltrText.indices) {
@@ -1270,7 +1270,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Rtl
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             assertThat(paragraph.getHorizontalPosition(0, false))
@@ -1298,7 +1298,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize, localeList = ltrLocaleList),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             assertThat(paragraph.getHorizontalPosition(text.length, false)).isZero()
@@ -1317,7 +1317,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize, localeList = ltrLocaleList),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             assertThat(paragraph.getHorizontalPosition(text.length, false)).isZero()
@@ -1337,7 +1337,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Rtl
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             assertThat(paragraph.getHorizontalPosition(text.length, false))
@@ -1358,7 +1358,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Ltr
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             assertThat(paragraph.getHorizontalPosition(text.length, false)).isZero()
@@ -1375,7 +1375,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in 0..text.length) {
@@ -1397,7 +1397,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Rtl
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in 0..text.length) {
@@ -1416,7 +1416,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in text.indices) {
@@ -1438,7 +1438,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Ltr
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in 0..text.length) {
@@ -1459,7 +1459,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in 0..text.length) {
@@ -1483,7 +1483,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Ltr
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in 0..text.length) {
@@ -1507,7 +1507,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Rtl
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in 0..text.length) {
@@ -1526,7 +1526,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in 0..text.length) {
@@ -1548,7 +1548,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Rtl
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in 0..text.length) {
@@ -1567,7 +1567,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in text.indices) {
@@ -1589,7 +1589,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Ltr
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in 0 until text.length - 1) {
@@ -1613,7 +1613,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in ltrText.indices) {
@@ -1641,7 +1641,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Ltr
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in ltrText.indices) {
@@ -1669,7 +1669,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Rtl
                 ),
-                constraints = ParagraphConstraints(width)
+                width = width
             )
 
             for (i in ltrText.indices) {
@@ -1707,7 +1707,7 @@
                     density = defaultDensity,
                     resourceLoader = resourceLoader,
                     // just have 10x font size to have a bitmap
-                    constraints = ParagraphConstraints(width = fontSizeInPx * 10)
+                    width = fontSizeInPx * 10
                 )
 
                 paragraph.bitmap()
@@ -1842,7 +1842,7 @@
                 text = text,
                 style = TextStyle(fontSize = fontSize),
                 maxLines = maxLines,
-                constraints = ParagraphConstraints(width = 200f)
+                width = 200f
             )
 
             val expectHeight = (lineCount + (lineCount - 1) * 0.2f) * fontSizeInPx
@@ -1862,13 +1862,13 @@
                 text = text,
                 style = TextStyle(fontSize = fontSize),
                 maxLines = maxLines,
-                constraints = ParagraphConstraints(width = fontSizeInPx)
+                width = fontSizeInPx
             )
 
             val paragraphNoMaxLine = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = fontSizeInPx)
+                width = fontSizeInPx
             )
 
             // Make sure the maxLine is applied correctly
@@ -1941,7 +1941,7 @@
                 style = TextStyle(fontSize = fontSize),
                 maxLines = maxLines,
                 // One line can only contain 1 character
-                constraints = ParagraphConstraints(width = fontSizeInPx)
+                width = fontSizeInPx
             )
 
             assertThat(paragraph.didExceedMaxLines).isTrue()
@@ -1972,7 +1972,7 @@
                 style = TextStyle(fontSize = fontSize),
                 maxLines = maxLines,
                 // One line can only contain 1 character
-                constraints = ParagraphConstraints(width = fontSizeInPx)
+                width = fontSizeInPx
             )
 
             assertThat(paragraph.didExceedMaxLines).isFalse()
@@ -2031,7 +2031,7 @@
                 maxLines = maxLines,
                 ellipsis = true,
                 // One line can only contain 1 character
-                constraints = ParagraphConstraints(width = fontSizeInPx)
+                width = fontSizeInPx
             )
 
             assertThat(paragraph.didExceedMaxLines).isTrue()
@@ -2064,7 +2064,7 @@
                 maxLines = maxLines,
                 ellipsis = true,
                         // One line can only contain 1 character
-                constraints = ParagraphConstraints(width = fontSizeInPx)
+                width = fontSizeInPx
             )
 
             assertThat(paragraph.didExceedMaxLines).isFalse()
@@ -2083,14 +2083,14 @@
             val paragraphLTR = simpleParagraph(
                 text = textLTR,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = layoutLTRWidth)
+                width = layoutLTRWidth
             )
 
             val layoutRTLWidth = (textRTL.length + 2) * fontSizeInPx
             val paragraphRTL = simpleParagraph(
                 text = textRTL,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = layoutRTLWidth)
+                width = layoutRTLWidth
             )
 
             // When textAlign is TextAlign.start, LTR aligns to left, RTL aligns to right.
@@ -2114,7 +2114,7 @@
                         fontSize = fontSize,
                         textAlign = TextAlign.Left
                     ),
-                    constraints = ParagraphConstraints(width = layoutWidth)
+                    width = layoutWidth
                 )
 
                 assertThat(paragraph.getLineLeft(0)).isZero()
@@ -2138,7 +2138,7 @@
                         textAlign = TextAlign.Right
                     ),
 
-                    constraints = ParagraphConstraints(width = layoutWidth)
+                    width = layoutWidth
                 )
 
                 assertThat(paragraph.getLineRight(0)).isEqualTo(layoutWidth)
@@ -2161,7 +2161,7 @@
                         fontSize = fontSize,
                         textAlign = TextAlign.Center
                     ),
-                    constraints = ParagraphConstraints(width = layoutWidth)
+                    width = layoutWidth
                 )
 
                 val textWidth = text.length * fontSizeInPx
@@ -2185,7 +2185,7 @@
                     fontSize = fontSize,
                     textAlign = TextAlign.Start
                 ),
-                constraints = ParagraphConstraints(width = layoutWidth)
+                width = layoutWidth
             )
 
             assertThat(paragraph.getLineLeft(0)).isZero()
@@ -2206,7 +2206,7 @@
                     fontSize = fontSize,
                     textAlign = TextAlign.End
                 ),
-                constraints = ParagraphConstraints(width = layoutWidth)
+                width = layoutWidth
             )
 
             assertThat(paragraph.getLineRight(0)).isEqualTo(layoutWidth)
@@ -2227,7 +2227,7 @@
                     fontSize = fontSize,
                     textAlign = TextAlign.Start
                 ),
-                constraints = ParagraphConstraints(width = layoutWidth)
+                width = layoutWidth
             )
 
             assertThat(paragraph.getLineRight(0)).isEqualTo(layoutWidth)
@@ -2249,7 +2249,7 @@
                     fontSize = fontSize,
                     textAlign = TextAlign.End
                 ),
-                constraints = ParagraphConstraints(width = layoutWidth)
+                width = layoutWidth
             )
 
             assertThat(paragraph.getLineLeft(0)).isZero()
@@ -2273,7 +2273,7 @@
                     fontSize = fontSize,
                     textAlign = TextAlign.Justify
                 ),
-                constraints = ParagraphConstraints(width = layoutWidth)
+                width = layoutWidth
             )
 
             assertThat(paragraph.getLineLeft(0)).isZero()
@@ -2297,7 +2297,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Ltr
                 ),
-                constraints = ParagraphConstraints(width = layoutWidth)
+                width = layoutWidth
             )
 
             // The position of the last character in display order.
@@ -2321,7 +2321,7 @@
                     fontSize = fontSize,
                     textDirection = TextDirection.Rtl
                 ),
-                constraints = ParagraphConstraints(width = layoutWidth)
+                width = layoutWidth
             )
 
             // The position of the first character in display order.
@@ -2342,7 +2342,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize, localeList = ltrLocaleList),
-                constraints = ParagraphConstraints(width = layoutWidth)
+                width = layoutWidth
             )
 
             for (i in 0..text.length) {
@@ -2365,7 +2365,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = layoutWidth)
+                width = layoutWidth
             )
 
             for (i in text.indices) {
@@ -2388,7 +2388,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = layoutWidth)
+                width = layoutWidth
             )
 
             // The first character in display order should be '.'
@@ -2438,7 +2438,7 @@
 
         val paragraph = simpleParagraph(
             text = text,
-            constraints = ParagraphConstraints(Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
         for (i in 0..2) {
             assertThat(paragraph.getLineForOffset(i)).isEqualTo(0)
@@ -2454,7 +2454,7 @@
 
         val paragraph = simpleParagraph(
             text = text,
-            constraints = ParagraphConstraints(Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
         assertThat(paragraph.getLineForOffset(3)).isEqualTo(0)
         assertThat(paragraph.getLineForOffset(7)).isEqualTo(1)
@@ -2466,7 +2466,7 @@
 
         val paragraph = simpleParagraph(
             text = text,
-            constraints = ParagraphConstraints(Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
         assertThat(paragraph.getLineForOffset(-1)).isEqualTo(0)
         assertThat(paragraph.getLineForOffset(-2)).isEqualTo(0)
@@ -2484,7 +2484,7 @@
             maxLines = 1,
             ellipsis = true,
             style = TextStyle(),
-            constraints = ParagraphConstraints(Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         for (i in 0..2) {
@@ -2514,7 +2514,7 @@
                     fontFamily = fontFamilyMeasureFont,
                     fontSize = fontSize.sp
                 ),
-                constraints = ParagraphConstraints(fontSize * 3)
+                width = fontSize * 3
             )
 
             // Prerequisite check for the this test.
@@ -2530,7 +2530,7 @@
 
         val paragraph = simpleParagraph(
             text = text,
-            constraints = ParagraphConstraints(Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         // Prerequisite check for the this test.
@@ -2547,7 +2547,7 @@
 
         val paragraph = simpleParagraph(
             text = text,
-            constraints = ParagraphConstraints(Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         // Prerequisite check for the this test.
@@ -2567,7 +2567,7 @@
                 fontFamily = fontFamilyMeasureFont,
                 fontSize = fontSize.sp
             ),
-            constraints = ParagraphConstraints(fontSize * 3),
+            width = fontSize * 3,
             density = defaultDensity
         )
 
@@ -2583,7 +2583,7 @@
 
         val paragraph = simpleParagraph(
             text = text,
-            constraints = ParagraphConstraints(Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         // Prerequisite check for the this test.
@@ -2598,7 +2598,7 @@
 
         val paragraph = simpleParagraph(
             text = text,
-            constraints = ParagraphConstraints(Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         // Prerequisite check for the this test.
@@ -2615,7 +2615,7 @@
             text = text,
             maxLines = 2,
             ellipsis = true,
-            constraints = ParagraphConstraints(Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         assertThat(paragraph.lineCount).isEqualTo(2)
@@ -2640,7 +2640,7 @@
                 ),
                 maxLines = 2,
                 ellipsis = true,
-                constraints = ParagraphConstraints(50f)
+                width = 50f
             )
 
             // Prerequisite check for the this test.
@@ -2675,7 +2675,7 @@
                     fontSize = fontSize.sp,
                     lineHeight = lineHeight.sp
                 ),
-                constraints = ParagraphConstraints(width = layoutWidth)
+                width = layoutWidth
             )
 
             assertThat(paragraph.lineCount).isEqualTo(4)
@@ -2701,7 +2701,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize.sp, lineHeight = lineHeight.em),
-                constraints = ParagraphConstraints(width = layoutWidth)
+                width = layoutWidth
             )
 
             assertThat(paragraph.lineCount).isEqualTo(4)
@@ -2728,7 +2728,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
-                constraints = ParagraphConstraints(width = paragraphWidth)
+                width = paragraphWidth
             )
 
             // Make sure there is only one line, so that we can use getLineRight to test fontSize.
@@ -2753,7 +2753,7 @@
                 text = text,
                 spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = paragraphWidth)
+                width = paragraphWidth
             )
 
             // Make sure there is only one line, so that we can use getLineRight to test fontSize.
@@ -2784,7 +2784,7 @@
                     AnnotatedString.Range(spanStyle, 0, text.length),
                     AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
                 ),
-                constraints = ParagraphConstraints(width = paragraphWidth)
+                width = paragraphWidth
             )
 
             // Make sure there is only one line, so that we can use getLineRight to test fontSize.
@@ -2938,7 +2938,7 @@
                 text = text,
                 style = TextStyle(fontSize = fontSize),
                 spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
-                constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+                width = Float.MAX_VALUE
             )
 
             assertThat(paragraph.lineCount).isEqualTo(1)
@@ -2961,7 +2961,7 @@
                 text = text,
                 style = TextStyle(fontSize = fontSize),
                 spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
-                constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+                width = Float.MAX_VALUE
             )
 
             assertThat(paragraph.lineCount).isEqualTo(1)
@@ -2984,7 +2984,7 @@
                 text = text,
                 style = TextStyle(fontSize = fontSize),
                 spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
-                constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+                width = Float.MAX_VALUE
             )
 
             assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3013,7 +3013,7 @@
                     AnnotatedString.Range(spanStyle, 0, text.length),
                     AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
                 ),
-                constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+                width = Float.MAX_VALUE
             )
 
             assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3045,7 +3045,7 @@
                     AnnotatedString.Range(letterSpacingStyle, 0, text.length),
                     AnnotatedString.Range(fontSizeStyle, 0, "abc".length)
                 ),
-                constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+                width = Float.MAX_VALUE
             )
 
             assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3076,7 +3076,7 @@
                     AnnotatedString.Range(letterSpacingStyle, 0, text.length),
                     AnnotatedString.Range(scaleXStyle, 0, "abc".length)
                 ),
-                constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+                width = Float.MAX_VALUE
             )
 
             assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3109,7 +3109,7 @@
                     AnnotatedString.Range(letterSpacingStyle, 0, text.length),
                     AnnotatedString.Range(fontSizeStyle, 0, "abc".length)
                 ),
-                constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+                width = Float.MAX_VALUE
             )
 
             assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3141,7 +3141,7 @@
                     AnnotatedString.Range(letterSpacingStyle, 0, text.length),
                     AnnotatedString.Range(scaleXStyle, 0, "abc".length)
                 ),
-                constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+                width = Float.MAX_VALUE
             )
 
             assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3171,7 +3171,7 @@
                     AnnotatedString.Range(letterSpacingEmStyle, 0, text.length),
                     AnnotatedString.Range(letterSpacingSpStyle, 0, "abc".length)
                 ),
-                constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+                width = Float.MAX_VALUE
             )
 
             assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3201,7 +3201,7 @@
                     AnnotatedString.Range(letterSpacingSpStyle, 0, "abc".length),
                     AnnotatedString.Range(letterSpacingEmStyle, 0, text.length)
                 ),
-                constraints = ParagraphConstraints(width = 500f)
+                width = 500f
             )
 
             assertThat(paragraph.lineCount).isEqualTo(1)
@@ -3252,7 +3252,7 @@
                     textIndent = TextIndent(firstLine = indent.sp),
                     fontFamily = fontFamilyMeasureFont
                 ),
-                constraints = ParagraphConstraints(width = paragraphWidth)
+                width = paragraphWidth
             )
 
             assertThat(paragraph.lineCount).isEqualTo(2)
@@ -3275,7 +3275,7 @@
                     fontSize = fontSize.sp,
                     fontFamily = fontFamilyMeasureFont
                 ),
-                constraints = ParagraphConstraints(width = paragraphWidth)
+                width = paragraphWidth
             )
 
             // check the position of the first character in second line: "d" should be indented
@@ -3319,7 +3319,7 @@
                     fontSize = fontSize.sp,
                     fontFamily = fontFamilyMeasureFont
                 ),
-                constraints = ParagraphConstraints(width = paragraphWidth)
+                width = paragraphWidth
             )
 
             assertThat(paragraph.lineCount).isEqualTo(2)
@@ -3343,7 +3343,7 @@
                     fontSize = fontSize.sp,
                     fontFamily = fontFamilyMeasureFont
                 ),
-                constraints = ParagraphConstraints(width = paragraphWidth)
+                width = paragraphWidth
             )
 
             assertThat(paragraph.lineCount).isEqualTo(2)
@@ -3428,12 +3428,12 @@
                 spanStyles = listOf(
                     AnnotatedString.Range(spanStyle, 0, text.length)
                 ),
-                constraints = ParagraphConstraints(width = paragraphWidth)
+                width = paragraphWidth
             )
 
             val paragraph = simpleParagraph(
                 text = text,
-                constraints = ParagraphConstraints(width = paragraphWidth)
+                width = paragraphWidth
             )
 
             assertThat(paragraphShadow.bitmap()).isNotEqualToBitmap(paragraph.bitmap())
@@ -3452,7 +3452,7 @@
             val paragraphWithoutColor = simpleParagraph(
                 text = text,
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(paragraphWidth)
+                width = paragraphWidth
             )
 
             val paragraphWithColor = simpleParagraph(
@@ -3461,7 +3461,7 @@
                     color = Color.Red,
                     fontSize = fontSize
                 ),
-                constraints = ParagraphConstraints(paragraphWidth)
+                width = paragraphWidth
             )
 
             assertThat(paragraphWithColor.bitmap())
@@ -3980,7 +3980,7 @@
 
             val paragraph = Paragraph(
                 paragraphIntrinsics = paragraphIntrinsics,
-                constraints = ParagraphConstraints(fontSizeInPx * text.length)
+                width = fontSizeInPx * text.length
             )
 
             assertThat(paragraph.maxIntrinsicWidth).isEqualTo(paragraphIntrinsics.maxIntrinsicWidth)
@@ -3993,7 +3993,15 @@
         simpleParagraph(
             text = "",
             maxLines = -1,
-            constraints = ParagraphConstraints(Float.MAX_VALUE)
+            width = Float.MAX_VALUE
+        )
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun negativeWidth_throwsException() {
+        simpleParagraph(
+            text = "",
+            width = -1f
         )
     }
 
@@ -4004,7 +4012,7 @@
         ellipsis: Boolean = false,
         spanStyles: List<AnnotatedString.Range<SpanStyle>> = listOf(),
         density: Density? = null,
-        constraints: ParagraphConstraints = ParagraphConstraints(Float.MAX_VALUE)
+        width: Float = Float.MAX_VALUE
     ): Paragraph {
         return Paragraph(
             text = text,
@@ -4014,7 +4022,7 @@
             ).merge(style),
             maxLines = maxLines,
             ellipsis = ellipsis,
-            constraints = constraints,
+            width = width,
             density = density ?: defaultDensity,
             resourceLoader = TestFontResourceLoader(context)
         )
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTextDirectionTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTextDirectionTest.kt
index 08ffa20..ba0be8f 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTextDirectionTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphIntegrationTextDirectionTest.kt
@@ -59,7 +59,7 @@
         val paragraph = Paragraph(
             text = "",
             style = TextStyle(textDirection = null),
-            constraints = ParagraphConstraints(Float.MAX_VALUE),
+            width = Float.MAX_VALUE,
             density = defaultDensity,
             resourceLoader = resourceLoader
         )
@@ -74,7 +74,7 @@
         val paragraph = Paragraph(
             text = "",
             style = TextStyle(textDirection = null),
-            constraints = ParagraphConstraints(Float.MAX_VALUE),
+            width = Float.MAX_VALUE,
             density = defaultDensity,
             resourceLoader = resourceLoader
         )
@@ -87,7 +87,7 @@
         val paragraph = Paragraph(
             text = "",
             style = TextStyle(textDirection = null, localeList = ltrLocaleList),
-            constraints = ParagraphConstraints(Float.MAX_VALUE),
+            width = Float.MAX_VALUE,
             density = defaultDensity,
             resourceLoader = resourceLoader
         )
@@ -100,7 +100,7 @@
         val paragraph = Paragraph(
             text = "",
             style = TextStyle(textDirection = null, localeList = rtlLocaleList),
-            constraints = ParagraphConstraints(Float.MAX_VALUE),
+            width = Float.MAX_VALUE,
             density = defaultDensity,
             resourceLoader = resourceLoader
         )
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphPlaceholderIntegrationTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphPlaceholderIntegrationTest.kt
index a4f55a4..a584a20 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphPlaceholderIntegrationTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/ParagraphPlaceholderIntegrationTest.kt
@@ -521,7 +521,7 @@
             placeholders = placeholders,
             maxLines = maxLines,
             ellipsis = ellipsis,
-            constraints = ParagraphConstraints(width = width),
+            width = width,
             density = defaultDensity,
             resourceLoader = TestFontResourceLoader(context)
         )
diff --git a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/platform/AndroidParagraphTest.kt b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/platform/AndroidParagraphTest.kt
index 3cf048d..1f6d7b6 100644
--- a/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/platform/AndroidParagraphTest.kt
+++ b/compose/ui/ui-text/src/androidAndroidTest/kotlin/androidx/compose/ui/text/platform/AndroidParagraphTest.kt
@@ -17,7 +17,6 @@
 import androidx.compose.ui.graphics.toArgb
 import androidx.compose.ui.text.AnnotatedString
 import androidx.compose.ui.text.FontTestData.Companion.BASIC_MEASURE_FONT
-import androidx.compose.ui.text.ParagraphConstraints
 import androidx.compose.ui.text.SpanStyle
 import androidx.compose.ui.text.TestFontResourceLoader
 import androidx.compose.ui.text.TextStyle
@@ -85,7 +84,7 @@
                         fontFamily = basicFontFamily
                     ),
                     // 2 chars width
-                    constraints = ParagraphConstraints(width = 2 * fontSize.toPx())
+                    width = 2 * fontSize.toPx()
                 )
 
                 val textPaint = TextPaint(Paint.ANTI_ALIAS_FLAG)
@@ -111,7 +110,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence).hasSpan(ForegroundColorSpan::class, 0, text.length)
@@ -125,7 +124,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence).hasSpan(ForegroundColorSpan::class, 0, "abc".length)
@@ -143,7 +142,7 @@
                 AnnotatedString.Range(spanStyle, 0, text.length),
                 AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
             ),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence).hasSpan(ForegroundColorSpan::class, 0, text.length)
@@ -159,7 +158,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -174,7 +173,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -189,7 +188,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -204,7 +203,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -221,7 +220,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -240,7 +239,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
-                constraints = ParagraphConstraints(width = paragraphWidth)
+                width = paragraphWidth
             )
 
             assertThat(paragraph.charSequence).hasSpan(AbsoluteSizeSpan::class, 0, text.length)
@@ -258,7 +257,7 @@
             val paragraph = simpleParagraph(
                 text = text,
                 spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
-                constraints = ParagraphConstraints(width = paragraphWidth)
+                width = paragraphWidth
             )
 
             assertThat(paragraph.charSequence).hasSpan(AbsoluteSizeSpan::class, 0, "abc".length)
@@ -281,7 +280,7 @@
                     AnnotatedString.Range(spanStyle, 0, text.length),
                     AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
                 ),
-                constraints = ParagraphConstraints(width = paragraphWidth)
+                width = paragraphWidth
             )
 
             assertThat(paragraph.charSequence).hasSpan(AbsoluteSizeSpan::class, 0, text.length)
@@ -300,7 +299,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence).hasSpan(RelativeSizeSpan::class, 0, text.length) {
@@ -317,7 +316,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence).hasSpan(RelativeSizeSpan::class, 0, "abc".length) {
@@ -334,7 +333,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -349,7 +348,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -368,7 +367,7 @@
                 AnnotatedString.Range(spanStyle, 0, text.length),
                 AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
             ),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -386,7 +385,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -405,7 +404,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -429,7 +428,7 @@
                 AnnotatedString.Range(spanStyle, 0, text.length),
                 AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
             ),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -456,7 +455,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence).hasSpan(LocaleSpan::class, 0, text.length)
@@ -471,7 +470,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence).hasSpan(LocaleSpan::class, 0, "abc".length)
@@ -489,7 +488,7 @@
                 AnnotatedString.Range(spanStyle, 0, text.length),
                 AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
             ),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence).hasSpan(LocaleSpan::class, 0, text.length)
@@ -505,7 +504,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
-            constraints = ParagraphConstraints(width = 100.0f) // width is not important
+            width = 100.0f // width is not important
         )
 
         assertThat(paragraph.charSequence).hasSpan(BaselineShiftSpan::class, 0, text.length)
@@ -519,7 +518,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
-            constraints = ParagraphConstraints(width = 100.0f) // width is not important
+            width = 100.0f // width is not important
         )
 
         assertThat(paragraph.charSequence).hasSpan(BaselineShiftSpan::class, 0, "abc".length)
@@ -538,7 +537,7 @@
                 AnnotatedString.Range(spanStyle, 0, text.length),
                 AnnotatedString.Range(spanStyleOverwrite, 0, "abc".length)
             ),
-            constraints = ParagraphConstraints(width = 100.0f) // width is not important
+            width = 100.0f // width is not important
         )
 
         assertThat(paragraph.charSequence).hasSpan(BaselineShiftSpan::class, 0, text.length)
@@ -554,7 +553,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
-            constraints = ParagraphConstraints(width = 100.0f) // width is not important
+            width = 100.0f // width is not important
         )
 
         assertThat(paragraph.charSequence).spans(ScaleXSpan::class).isEmpty()
@@ -574,7 +573,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
-            constraints = ParagraphConstraints(width = 100.0f) // width is not important
+            width = 100.0f // width is not important
         )
 
         assertThat(paragraph.charSequence).hasSpan(ScaleXSpan::class, 0, text.length) {
@@ -592,7 +591,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, text.length)),
-            constraints = ParagraphConstraints(width = 100.0f) // width is not important
+            width = 100.0f // width is not important
         )
 
         assertThat(paragraph.charSequence).hasSpan(SkewXSpan::class, 0, text.length) {
@@ -610,7 +609,7 @@
         val paragraph = simpleParagraph(
             text = text,
             textIndent = TextIndent(firstLine.sp, restLine.sp),
-            constraints = ParagraphConstraints(width = 100.0f) // width is not important
+            width = 100.0f // width is not important
         )
 
         assertThat(paragraph.charSequence)
@@ -632,7 +631,7 @@
             spanStyles = listOf(
                 AnnotatedString.Range(spanStyle, start = 0, end = text.length)
             ),
-            constraints = ParagraphConstraints(width = 100.0f) // width is not important
+            width = 100.0f // width is not important
         )
 
         assertThat(paragraph.charSequence)
@@ -665,7 +664,7 @@
                 AnnotatedString.Range(spanStyle, start = 0, end = text.length),
                 AnnotatedString.Range(spanStyleOverwrite, start = 0, end = "abc".length)
             ),
-            constraints = ParagraphConstraints(width = 100.0f) // width is not important
+            width = 100.0f // width is not important
         )
 
         assertThat(paragraph.charSequence)
@@ -709,7 +708,7 @@
                     expectedEnd
                 )
             ),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -746,7 +745,7 @@
                     expectedEnd
                 )
             ),
-            constraints = ParagraphConstraints(width = 100.0f)
+            width = 100.0f
         )
 
         assertThat(paragraph.charSequence.toString()).isEqualTo(text)
@@ -765,7 +764,7 @@
         val paragraph = simpleParagraph(
             text = text,
             spanStyles = listOf(AnnotatedString.Range(spanStyle, 0, "abc".length)),
-            constraints = ParagraphConstraints(width = 100.0f) // width is not important
+            width = 100.0f // width is not important
         )
 
         assertThat(paragraph.charSequence).hasSpan(FontFeatureSpan::class, 0, "abc".length) {
@@ -779,7 +778,7 @@
         val paragraph = simpleParagraph(
             text = "abc",
             typefaceAdapter = typefaceAdapter,
-            constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         verify(typefaceAdapter, never()).create(
@@ -802,7 +801,7 @@
                 fontWeight = FontWeight.Bold
             ),
             typefaceAdapter = typefaceAdapter,
-            constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         verify(typefaceAdapter, times(1)).create(
@@ -828,7 +827,7 @@
                 fontStyle = FontStyle.Italic
             ),
             typefaceAdapter = typefaceAdapter,
-            constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         verify(typefaceAdapter, times(1)).create(
@@ -855,7 +854,7 @@
                 fontFamily = fontFamily
             ),
             typefaceAdapter = typefaceAdapter,
-            constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         verify(typefaceAdapter, times(1)).create(
@@ -880,7 +879,7 @@
                 fontFamily = basicFontFamily
             ),
             typefaceAdapter = typefaceAdapter,
-            constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         verify(typefaceAdapter, atLeastOnce()).create(
@@ -904,7 +903,7 @@
                 fontFamily = basicFontFamily
             ),
             typefaceAdapter = typefaceAdapter,
-            constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         val charSequence = paragraph.charSequence
@@ -924,7 +923,7 @@
                     fontSize = fontSize
                 ),
                 ellipsis = true,
-                constraints = ParagraphConstraints(width = paragraphWidth)
+                width = paragraphWidth
             )
 
             for (i in 0 until paragraph.lineCount) {
@@ -948,7 +947,7 @@
                     fontFamily = basicFontFamily,
                     fontSize = fontSize
                 ),
-                constraints = ParagraphConstraints(width = paragraphWidth)
+                width = paragraphWidth
             )
 
             assertThat(paragraph.isEllipsisApplied(0)).isTrue()
@@ -970,7 +969,7 @@
                     fontFamily = basicFontFamily,
                     fontSize = fontSize
                 ),
-                constraints = ParagraphConstraints(width = paragraphWidth)
+                width = paragraphWidth
             )
 
             for (i in 0 until paragraph.lineCount) {
@@ -986,7 +985,7 @@
             val paragraph = simpleParagraph(
                 text = "",
                 style = TextStyle(fontSize = fontSize),
-                constraints = ParagraphConstraints(width = 0.0f)
+                width = 0.0f
             )
 
             assertThat(paragraph.textPaint.textSize).isEqualTo(fontSize.toPx())
@@ -1001,7 +1000,7 @@
         val paragraph = simpleParagraph(
             text = "",
             style = TextStyle(localeList = localeList),
-            constraints = ParagraphConstraints(width = 0.0f)
+            width = 0.0f
         )
 
         assertThat(paragraph.textPaint.textLocale.language).isEqualTo(platformLocale.language)
@@ -1014,7 +1013,7 @@
         val paragraph = simpleParagraph(
             text = "",
             style = TextStyle(color = color),
-            constraints = ParagraphConstraints(width = 0.0f)
+            width = 0.0f
         )
 
         assertThat(paragraph.textPaint.color).isEqualTo(color.toArgb())
@@ -1026,7 +1025,7 @@
         val paragraph = simpleParagraph(
             text = "",
             style = TextStyle(letterSpacing = letterSpacing.em),
-            constraints = ParagraphConstraints(width = 0.0f)
+            width = 0.0f
         )
 
         assertThat(paragraph.textPaint.letterSpacing).isEqualTo((letterSpacing))
@@ -1039,7 +1038,7 @@
         val paragraph = simpleParagraph(
             text = text,
             style = TextStyle(letterSpacing = letterSpacing.sp),
-            constraints = ParagraphConstraints(width = 0.0f)
+            width = 0.0f
         )
 
         assertThat(paragraph.charSequence)
@@ -1054,7 +1053,7 @@
         val paragraph = simpleParagraph(
             text = "",
             style = TextStyle(fontFeatureSettings = fontFeatureSettings),
-            constraints = ParagraphConstraints(width = 0.0f)
+            width = 0.0f
         )
 
         assertThat(paragraph.textPaint.fontFeatureSettings).isEqualTo(fontFeatureSettings)
@@ -1070,7 +1069,7 @@
                     scaleX = scaleX
                 )
             ),
-            constraints = ParagraphConstraints(width = 0.0f)
+            width = 0.0f
         )
 
         assertThat(paragraph.textPaint.textScaleX).isEqualTo(scaleX)
@@ -1086,7 +1085,7 @@
                     skewX = skewX
                 )
             ),
-            constraints = ParagraphConstraints(width = 0.0f)
+            width = 0.0f
         )
 
         assertThat(paragraph.textPaint.textSkewX).isEqualTo(skewX)
@@ -1097,7 +1096,7 @@
         val paragraph = simpleParagraph(
             text = "",
             style = TextStyle(textDecoration = TextDecoration.Underline),
-            constraints = ParagraphConstraints(width = 0.0f)
+            width = 0.0f
         )
 
         assertThat(paragraph.textPaint.isUnderlineText).isTrue()
@@ -1108,7 +1107,7 @@
         val paragraph = simpleParagraph(
             text = "",
             style = TextStyle(textDecoration = TextDecoration.LineThrough),
-            constraints = ParagraphConstraints(width = 0.0f)
+            width = 0.0f
         )
 
         assertThat(paragraph.textPaint.isStrikeThruText).isTrue()
@@ -1123,7 +1122,7 @@
         val paragraph = simpleParagraph(
             text = text,
             style = TextStyle(background = color),
-            constraints = ParagraphConstraints(width = 0.0f)
+            width = 0.0f
         )
 
         assertThat(paragraph.charSequence)
@@ -1141,7 +1140,7 @@
         val paragraph = simpleParagraph(
             text = text,
             style = TextStyle(baselineShift = baselineShift),
-            constraints = ParagraphConstraints(width = 0.0f)
+            width = 0.0f
         )
 
         assertThat(paragraph.charSequence)
@@ -1155,7 +1154,7 @@
         val text = "abc"
         val paragraph = simpleParagraph(
             text = text,
-            constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         assertThat(paragraph.textLocale.toLanguageTag())
@@ -1169,7 +1168,7 @@
         val paragraph = simpleParagraph(
             text = text,
             style = TextStyle(localeList = localeList),
-            constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         assertThat(paragraph.textLocale.toLanguageTag()).isEqualTo("en-US")
@@ -1182,7 +1181,7 @@
         val paragraph = simpleParagraph(
             text = text,
             style = TextStyle(localeList = localeList),
-            constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         assertThat(paragraph.textLocale.toLanguageTag()).isEqualTo("ja-JP")
@@ -1195,7 +1194,7 @@
         val paragraph = simpleParagraph(
             text = text,
             style = TextStyle(localeList = localeList),
-            constraints = ParagraphConstraints(width = Float.MAX_VALUE)
+            width = Float.MAX_VALUE
         )
 
         assertThat(paragraph.textLocale.toLanguageTag()).isEqualTo("ja")
@@ -1206,7 +1205,7 @@
         val floatWidth = 1.3f
         val paragraph = simpleParagraph(
             text = "Hello, World",
-            constraints = ParagraphConstraints(floatWidth)
+            width = floatWidth
         )
 
         assertThat(floatWidth).isEqualTo(paragraph.width)
@@ -1219,7 +1218,7 @@
         textAlign: TextAlign? = null,
         ellipsis: Boolean = false,
         maxLines: Int = Int.MAX_VALUE,
-        constraints: ParagraphConstraints,
+        width: Float,
         style: TextStyle? = null,
         typefaceAdapter: TypefaceAdapter = TypefaceAdapter()
     ): AndroidParagraph {
@@ -1234,7 +1233,7 @@
             ).merge(style),
             maxLines = maxLines,
             ellipsis = ellipsis,
-            constraints = constraints,
+            width = width,
             density = Density(density = 1f)
         )
     }
diff --git a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.kt b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.kt
index d9e82af..df3b7c3 100644
--- a/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.kt
+++ b/compose/ui/ui-text/src/androidMain/kotlin/androidx/compose/ui/text/platform/AndroidParagraph.kt
@@ -28,7 +28,6 @@
 import androidx.compose.ui.graphics.nativeCanvas
 import androidx.compose.ui.text.AnnotatedString
 import androidx.compose.ui.text.Paragraph
-import androidx.compose.ui.text.ParagraphConstraints
 import androidx.compose.ui.text.ParagraphIntrinsics
 import androidx.compose.ui.text.Placeholder
 import androidx.compose.ui.text.SpanStyle
@@ -64,7 +63,7 @@
     val paragraphIntrinsics: AndroidParagraphIntrinsics,
     val maxLines: Int,
     val ellipsis: Boolean,
-    val constraints: ParagraphConstraints
+    override val width: Float
 ) : Paragraph {
 
     constructor(
@@ -74,7 +73,7 @@
         placeholders: List<AnnotatedString.Range<Placeholder>>,
         maxLines: Int,
         ellipsis: Boolean,
-        constraints: ParagraphConstraints,
+        width: Float,
         typefaceAdapter: TypefaceAdapter,
         density: Density
     ) : this(
@@ -88,15 +87,14 @@
         ),
         maxLines = maxLines,
         ellipsis = ellipsis,
-        constraints = constraints
+        width = width
     )
 
     private val layout: TextLayout
 
-    override val width: Float
-
     init {
         require(maxLines >= 1) { "maxLines should be greater than 0" }
+        require(width >= 0f) { "width should not be negative" }
 
         val style = paragraphIntrinsics.style
 
@@ -113,11 +111,9 @@
             null
         }
 
-        this.width = constraints.width
-
         layout = TextLayout(
             charSequence = paragraphIntrinsics.charSequence,
-            width = constraints.width,
+            width = width,
             textPaint = textPaint,
             ellipsize = ellipsize,
             alignment = alignment,
@@ -375,7 +371,7 @@
     placeholders: List<AnnotatedString.Range<Placeholder>>,
     maxLines: Int,
     ellipsis: Boolean,
-    constraints: ParagraphConstraints,
+    width: Float,
     density: Density,
     resourceLoader: Font.ResourceLoader
 ): Paragraph = AndroidParagraph(
@@ -391,17 +387,17 @@
     ),
     maxLines,
     ellipsis,
-    constraints
+    width
 )
 
 internal actual fun ActualParagraph(
     paragraphIntrinsics: ParagraphIntrinsics,
     maxLines: Int,
     ellipsis: Boolean,
-    constraints: ParagraphConstraints
+    width: Float
 ): Paragraph = AndroidParagraph(
     paragraphIntrinsics as AndroidParagraphIntrinsics,
     maxLines,
     ellipsis,
-    constraints
+    width
 )
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt
index 9e4f8bc..4ce14e5 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/MultiParagraph.kt
@@ -36,12 +36,13 @@
  * @param intrinsics previously calculated text intrinsics
  * @param maxLines the maximum number of lines that the text can have
  * @param ellipsis whether to ellipsize text, applied only when [maxLines] is set
+ * @param width how wide the text is allowed to be
  */
 class MultiParagraph(
     val intrinsics: MultiParagraphIntrinsics,
     val maxLines: Int = DefaultMaxLines,
     ellipsis: Boolean = false,
-    constraints: ParagraphConstraints
+    width: Float
 ) {
 
     /**
@@ -56,7 +57,7 @@
      * thrown.
      * @param maxLines the maximum number of lines that the text can have
      * @param ellipsis whether to ellipsize text, applied only when [maxLines] is set
-     * @param constraints how wide the text is allowed to be
+     * @param width how wide the text is allowed to be
      * @param density density of the device
      * @param resourceLoader [Font.ResourceLoader] to be used to load the font given in [SpanStyle]s
      *
@@ -70,7 +71,7 @@
         placeholders: List<AnnotatedString.Range<Placeholder>> = listOf(),
         maxLines: Int = Int.MAX_VALUE,
         ellipsis: Boolean = false,
-        constraints: ParagraphConstraints,
+        width: Float,
         density: Density,
         resourceLoader: Font.ResourceLoader
     ) : this(
@@ -83,7 +84,7 @@
         ),
         maxLines = maxLines,
         ellipsis = ellipsis,
-        constraints = constraints
+        width = width
     )
 
     private val annotatedString get() = intrinsics.annotatedString
@@ -178,7 +179,7 @@
                 paragraphInfo.intrinsics,
                 maxLines - currentLineCount,
                 ellipsis,
-                constraints
+                width
             )
 
             val paragraphTop = currentHeight
@@ -212,7 +213,7 @@
         this.lineCount = currentLineCount
         this.didExceedMaxLines = didExceedMaxLines
         this.paragraphInfoList = paragraphInfoList
-        this.width = constraints.width
+        this.width = width
         this.placeholderRects = paragraphInfoList.flatMap { paragraphInfo ->
             with(paragraphInfo) {
                 paragraph.placeholderRects.map { it?.toGlobal() }
@@ -763,7 +764,7 @@
      * [MultiParagraph].
      */
     fun Rect.toGlobal(): Rect {
-        return shift(Offset(0f, this@ParagraphInfo.top))
+        return translate(Offset(0f, this@ParagraphInfo.top))
     }
 
     /**
@@ -773,7 +774,7 @@
      * Notice that this function changes the input value.
      */
     fun Path.toGlobal(): Path {
-        shift(Offset(0f, top))
+        translate(Offset(0f, top))
         return this
     }
 
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/Paragraph.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/Paragraph.kt
index 197cce4..2f53bcd 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/Paragraph.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/Paragraph.kt
@@ -263,7 +263,7 @@
  * be left blank to leave space for inline elements.
  * @param maxLines the maximum number of lines that the text can have
  * @param ellipsis whether to ellipsize text, applied only when [maxLines] is set
- * @param constraints how wide the text is allowed to be
+ * @param width how wide the text is allowed to be
  * @param density density of the device
  * @param resourceLoader [Font.ResourceLoader] to be used to load the font given in [SpanStyle]s
  *
@@ -276,7 +276,7 @@
     placeholders: List<AnnotatedString.Range<Placeholder>> = listOf(),
     maxLines: Int = DefaultMaxLines,
     ellipsis: Boolean = false,
-    constraints: ParagraphConstraints,
+    width: Float,
     density: Density,
     resourceLoader: Font.ResourceLoader
 ): Paragraph = ActualParagraph(
@@ -286,7 +286,7 @@
     placeholders,
     maxLines,
     ellipsis,
-    constraints,
+    width,
     density,
     resourceLoader
 )
@@ -298,16 +298,16 @@
  * @param paragraphIntrinsics [ParagraphIntrinsics] instance
  * @param maxLines the maximum number of lines that the text can have
  * @param ellipsis whether to ellipsize text, applied only when [maxLines] is set
- * @param constraints how wide the text is allowed to be
+ * @param width how wide the text is allowed to be
  */
 fun Paragraph(
     paragraphIntrinsics: ParagraphIntrinsics,
     maxLines: Int = DefaultMaxLines,
     ellipsis: Boolean = false,
-    constraints: ParagraphConstraints
+    width: Float
 ): Paragraph = ActualParagraph(
     paragraphIntrinsics,
     maxLines,
     ellipsis,
-    constraints
+    width
 )
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/ParagraphConstraints.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/ParagraphConstraints.kt
deleted file mode 100644
index dfbbf72..0000000
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/ParagraphConstraints.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * 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.ui.text
-
-/**
- * Layout constraints for [Paragraph] objects.
- *
- * Instances of this class are typically used with [Paragraph].
- *
- * The only constraint that can be specified is the [width]. See the discussion
- * at [width] for more details.
- *
- * Creates constraints for laying out a paragraph.
- *
- * The [width] argument must not be null.
- *
- * The width the paragraph should use whey computing the positions of glyphs.
- *
- * If possible, the paragraph will select a soft line break prior to reaching
- * this width. If no soft line break is available, the paragraph will select
- * a hard line break prior to reaching this width. If that would force a line
- * break without any characters having been placed (i.e. if the next
- * character to be laid out does not fit within the given width constraint)
- * then the next character is allowed to overflow the width constraint and a
- * forced line break is placed after it (even if an explicit line break
- * follows).
- *
- * The width influences how ellipses are applied.
- *
- * This width is also used to position glyphs according to the text alignment
- * described in the [ParagraphStyle.textAlign] to create [Paragraph].
- */
-data class ParagraphConstraints(val width: Float) {
-    override fun toString(): String {
-        return "ParagraphConstraints(width: $width)"
-    }
-}
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextDelegate.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextDelegate.kt
index cc64073..2d8e528 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextDelegate.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextDelegate.kt
@@ -156,7 +156,7 @@
             intrinsics = nonNullIntrinsics,
             maxLines = maxLines,
             ellipsis = overflow == TextOverflow.Ellipsis,
-            constraints = ParagraphConstraints(width = width)
+            width = width
         )
     }
 
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextLayoutResult.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextLayoutResult.kt
index 1ca036f..957741f 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextLayoutResult.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextLayoutResult.kt
@@ -359,7 +359,7 @@
     multiParagraph: MultiParagraph = MultiParagraph(
         annotatedString = layoutInput.text,
         style = layoutInput.style,
-        constraints = ParagraphConstraints(width = 0f),
+        width = 0f,
         density = layoutInput.density,
         resourceLoader = layoutInput.resourceLoader
     ),
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextRange.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextRange.kt
index d8f4c44..0c79edc 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextRange.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/TextRange.kt
@@ -18,6 +18,9 @@
 
 import androidx.compose.runtime.Immutable
 import androidx.compose.ui.util.annotation.IntRange
+import androidx.compose.ui.util.packInts
+import androidx.compose.ui.util.unpackInt1
+import androidx.compose.ui.util.unpackInt2
 
 fun CharSequence.substring(range: TextRange): String = this.substring(range.min, range.max)
 
@@ -25,14 +28,30 @@
  * An immutable text range class, represents a text range from [start] (inclusive) to [end]
  * (exclusive). [end] can be smaller than [start] and in those cases [min] and [max] can be
  * used in order to fetch the values.
- *
- * @param start the inclusive start offset of the range. Must be non-negative, otherwise an
- * exception will be thrown.
- * @param end the exclusive end offset of the range. Must be non-negative, otherwise an
- * exception will be thrown.
  */
+@Suppress("EXPERIMENTAL_FEATURE_WARNING")
 @Immutable
-data class TextRange(@IntRange(from = 0) val start: Int, @IntRange(from = 0) val end: Int) {
+inline class TextRange(val packedValue: Long) {
+
+    /**
+     * An immutable text range class, represents a text range from [start] (inclusive) to [end]
+     * (exclusive). [end] can be smaller than [start] and in those cases [min] and [max] can be
+     * used in order to fetch the values.
+     *
+     * @param start the inclusive start offset of the range. Must be non-negative, otherwise an
+     * exception will be thrown.
+     * @param end the exclusive end offset of the range. Must be non-negative, otherwise an
+     * exception will be thrown.
+     */
+    constructor(
+        @IntRange(from = 0) start: Int,
+        @IntRange(from = 0) end: Int
+    ) : this(packWithCheck(start, end))
+
+    val start: Int get() = unpackInt1(packedValue)
+
+    val end: Int get() = unpackInt2(packedValue)
+
     /** The minimum offset of the range. */
     val min: Int get() = if (start > end) end else start
 
@@ -54,15 +73,6 @@
      */
     val length: Int get() = max - min
 
-    init {
-        require(start >= 0) {
-            "start cannot be negative. [start: $start]"
-        }
-        require(end >= 0) {
-            "end cannot negative. [end: $end]"
-        }
-    }
-
     /**
      * Returns true if the given range has intersection with this range
      */
@@ -78,6 +88,10 @@
      */
     operator fun contains(offset: Int): Boolean = offset in min until max
 
+    override fun toString(): String {
+        return "TextRange($start, $end)"
+    }
+
     companion object {
         val Zero = TextRange(0)
     }
@@ -107,4 +121,14 @@
         return TextRange(newStart, newEnd)
     }
     return this
+}
+
+private fun packWithCheck(start: Int, end: Int): Long {
+    require(start >= 0) {
+        "start cannot be negative. [start: $start]"
+    }
+    require(end >= 0) {
+        "end cannot negative. [end: $end]"
+    }
+    return packInts(start, end)
 }
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/platform/PlatformParagraph.kt b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/platform/PlatformParagraph.kt
index 78f32e0..76d54e0 100644
--- a/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/platform/PlatformParagraph.kt
+++ b/compose/ui/ui-text/src/commonMain/kotlin/androidx/compose/ui/text/platform/PlatformParagraph.kt
@@ -17,7 +17,6 @@
 
 import androidx.compose.ui.text.AnnotatedString
 import androidx.compose.ui.text.Paragraph
-import androidx.compose.ui.text.ParagraphConstraints
 import androidx.compose.ui.text.ParagraphIntrinsics
 import androidx.compose.ui.text.Placeholder
 import androidx.compose.ui.text.SpanStyle
@@ -33,7 +32,7 @@
     placeholders: List<AnnotatedString.Range<Placeholder>>,
     maxLines: Int,
     ellipsis: Boolean,
-    constraints: ParagraphConstraints,
+    width: Float,
     density: Density,
     resourceLoader: Font.ResourceLoader
 ): Paragraph
@@ -43,7 +42,7 @@
     paragraphIntrinsics: ParagraphIntrinsics,
     maxLines: Int,
     ellipsis: Boolean,
-    constraints: ParagraphConstraints
+    width: Float
 ): Paragraph
 
 // TODO(b/157854677): remove after fixing.
diff --git a/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopParagraph.kt b/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopParagraph.kt
index c9ac5b6..ab132e3 100644
--- a/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopParagraph.kt
+++ b/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopParagraph.kt
@@ -28,7 +28,6 @@
 import androidx.compose.ui.graphics.toComposeRect
 import androidx.compose.ui.text.AnnotatedString
 import androidx.compose.ui.text.Paragraph
-import androidx.compose.ui.text.ParagraphConstraints
 import androidx.compose.ui.text.ParagraphIntrinsics
 import androidx.compose.ui.text.Placeholder
 import androidx.compose.ui.text.PlaceholderVerticalAlign
@@ -72,7 +71,7 @@
     placeholders: List<AnnotatedString.Range<Placeholder>>,
     maxLines: Int,
     ellipsis: Boolean,
-    constraints: ParagraphConstraints,
+    width: Float,
     density: Density,
     resourceLoader: Font.ResourceLoader
 ): Paragraph = DesktopParagraph(
@@ -86,7 +85,7 @@
     ),
     maxLines,
     ellipsis,
-    constraints
+    width
 )
 
 @Suppress("UNUSED_PARAMETER")
@@ -94,19 +93,19 @@
     paragraphIntrinsics: ParagraphIntrinsics,
     maxLines: Int,
     ellipsis: Boolean,
-    constraints: ParagraphConstraints
+    width: Float
 ): Paragraph = DesktopParagraph(
     paragraphIntrinsics as DesktopParagraphIntrinsics,
     maxLines,
     ellipsis,
-    constraints
+    width
 )
 
 internal class DesktopParagraph(
     intrinsics: ParagraphIntrinsics,
     val maxLines: Int,
     val ellipsis: Boolean,
-    val constraints: ParagraphConstraints
+    override val width: Float
 ) : Paragraph {
 
     val paragraphIntrinsics = intrinsics as DesktopParagraphIntrinsics
@@ -122,15 +121,12 @@
         if (resetMaxLinesIfNeeded()) {
             rebuildParagraph()
         }
-        para.layout(constraints.width)
+        para.layout(width)
     }
 
     private val text: String
         get() = paragraphIntrinsics.text
 
-    override val width: Float
-        get() = para.getMaxWidth()
-
     override val height: Float
         get() = para.getHeight()
 
@@ -339,7 +335,7 @@
                     textDecoration = currentTextDecoration
                 )
             rebuildParagraph()
-            para.layout(constraints.width)
+            para.layout(width)
         }
         para.paint(canvas.nativeCanvas, 0.0f, 0.0f)
     }
diff --git a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/ParagraphConstraintsTest.kt b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/ParagraphConstraintsTest.kt
deleted file mode 100644
index a1d78da..0000000
--- a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/ParagraphConstraintsTest.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2019 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.ui.text
-
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-
-@RunWith(JUnit4::class)
-class ParagraphConstraintsTest {
-
-    @Test
-    fun `toString with values`() {
-        val paragraphConstraints = ParagraphConstraints(width = 101.0f)
-        assertThat(paragraphConstraints.toString()).isEqualTo("ParagraphConstraints(width: 101.0)")
-    }
-}
\ No newline at end of file
diff --git a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextRangeTest.kt b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextRangeTest.kt
index 819402c..3af74a5 100644
--- a/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextRangeTest.kt
+++ b/compose/ui/ui-text/src/test/java/androidx/compose/ui/text/TextRangeTest.kt
@@ -139,23 +139,11 @@
     }
 
     @Test
-    fun constrain_returns_same_object_if_no_change_required() {
-        val textRange = TextRange(1, 2)
-        assertThat(textRange.constrain(0, 3)).isSameInstanceAs(textRange)
-    }
-
-    @Test
     fun constrain_updates_start_end_if_required() {
         assertThat(TextRange(0, 4).constrain(1, 3)).isEqualTo(TextRange(1, 3))
     }
 
     @Test
-    fun constrain_collapsed_TextRange_with_the_same_min_max_returns_the_same_instance() {
-        val textRange = TextRange(2, 2)
-        assertThat(textRange.constrain(2, 2)).isSameInstanceAs(textRange)
-    }
-
-    @Test
     fun constrain_with_collapsed_min_max_returns_collapsed_values() {
         assertThat(TextRange(1, 2).constrain(2, 2)).isEqualTo(TextRange(2, 2))
         assertThat(TextRange(2, 3).constrain(2, 2)).isEqualTo(TextRange(2, 2))
@@ -170,4 +158,10 @@
     fun constrain_min_smaller_than_TextRange_values() {
         assertThat(TextRange(5, 6).constrain(0, 4)).isEqualTo(TextRange(4, 4))
     }
+
+    @Test
+    fun to_string() {
+        assertThat(TextRange(0, 1).toString()).isEqualTo("TextRange(0, 1)")
+        assertThat(TextRange(1, 1).toString()).isEqualTo("TextRange(1, 1)")
+    }
 }
\ No newline at end of file
diff --git a/compose/ui/ui-unit/samples/build.gradle b/compose/ui/ui-unit/samples/build.gradle
index 500b2cc..1a87f7a 100644
--- a/compose/ui/ui-unit/samples/build.gradle
+++ b/compose/ui/ui-unit/samples/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/ui/ui-viewbinding/build.gradle b/compose/ui/ui-viewbinding/build.gradle
index 940c8fe..1a4e04be 100644
--- a/compose/ui/ui-viewbinding/build.gradle
+++ b/compose/ui/ui-viewbinding/build.gradle
@@ -29,7 +29,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
     implementation project(":compose:ui:ui")
diff --git a/compose/ui/ui-viewbinding/samples/build.gradle b/compose/ui/ui-viewbinding/samples/build.gradle
index e087672..ac7eed9 100644
--- a/compose/ui/ui-viewbinding/samples/build.gradle
+++ b/compose/ui/ui-viewbinding/samples/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
     implementation project(":annotation:annotation-sampled")
diff --git a/compose/ui/ui-viewbinding/src/androidTest/java/androidx/compose/ui/viewinterop/AndroidViewBindingTest.kt b/compose/ui/ui-viewbinding/src/androidTest/java/androidx/compose/ui/viewinterop/AndroidViewBindingTest.kt
index 53cc239..8446139 100644
--- a/compose/ui/ui-viewbinding/src/androidTest/java/androidx/compose/ui/viewinterop/AndroidViewBindingTest.kt
+++ b/compose/ui/ui-viewbinding/src/androidTest/java/androidx/compose/ui/viewinterop/AndroidViewBindingTest.kt
@@ -91,9 +91,12 @@
             val density = Density(3f)
             val sizeIpx = with(density) { size.toIntPx() }
             Providers(DensityAmbient provides density) {
-                AndroidViewBinding(TestLayoutBinding::inflate, Modifier.size(size).onPositioned {
-                    Truth.assertThat(it.size).isEqualTo(IntSize(sizeIpx, sizeIpx))
-                })
+                AndroidViewBinding(
+                    TestLayoutBinding::inflate,
+                    Modifier.size(size).onPositioned {
+                        Truth.assertThat(it.size).isEqualTo(IntSize(sizeIpx, sizeIpx))
+                    }
+                )
             }
         }
         rule.waitForIdle()
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index ed8a943..8a0333c 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -89,6 +89,16 @@
     method public static int merge(androidx.compose.ui.AlignmentLine, int position1, int position2);
   }
 
+  public final class CacheDrawScope implements androidx.compose.ui.unit.Density {
+    method public float getDensity();
+    method public float getFontScale();
+    method public long getSize();
+    method public androidx.compose.ui.DrawResult onDraw(kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+    property public float density;
+    property public float fontScale;
+    property public final long size;
+  }
+
   public final class CombinedModifier implements androidx.compose.ui.Modifier {
     ctor public CombinedModifier(androidx.compose.ui.Modifier outer, androidx.compose.ui.Modifier inner);
     method public boolean all(kotlin.jvm.functions.Function1<? super androidx.compose.ui.Modifier.Element,java.lang.Boolean> predicate);
@@ -107,6 +117,10 @@
     method public abstract void drawContent();
   }
 
+  public interface DrawCacheModifier extends androidx.compose.ui.DrawModifier {
+    method public void onBuildCache-lwCvPpU(long size, androidx.compose.ui.unit.Density density);
+  }
+
   public interface DrawLayerModifier extends androidx.compose.ui.Modifier.Element {
     method @FloatRange(from=0.0, to=1.0) public default float getAlpha();
     method public default boolean getClip();
@@ -145,9 +159,13 @@
 
   public final class DrawModifierKt {
     method public static androidx.compose.ui.Modifier drawBehind(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> onDraw);
+    method public static androidx.compose.ui.Modifier drawWithCache(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.CacheDrawScope,androidx.compose.ui.DrawResult> onBuildDrawCache);
     method public static androidx.compose.ui.Modifier drawWithContent(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.ContentDrawScope,kotlin.Unit> onDraw);
   }
 
+  public final class DrawResult {
+  }
+
   public final class FocusModifierKt {
     method @androidx.compose.runtime.Composable @androidx.compose.ui.focus.ExperimentalFocus public static androidx.compose.ui.Modifier focus(androidx.compose.ui.Modifier);
   }
@@ -277,16 +295,16 @@
 
   public abstract static class Placeable.PlacementScope {
     ctor public Placeable.PlacementScope();
-    method public abstract androidx.compose.ui.unit.LayoutDirection getParentLayoutDirection();
-    method public abstract int getParentWidth();
+    method protected abstract androidx.compose.ui.unit.LayoutDirection getParentLayoutDirection();
+    method protected abstract int getParentWidth();
     method public final void place(androidx.compose.ui.Placeable, int x, int y);
     method public final void place-LmmdDA8(androidx.compose.ui.Placeable, long position);
     method public final void place-gl1q84w(androidx.compose.ui.Placeable, long position);
     method public final void placeRelative(androidx.compose.ui.Placeable, int x, int y);
     method public final void placeRelative-LmmdDA8(androidx.compose.ui.Placeable, long position);
     method public final void placeRelative-gl1q84w(androidx.compose.ui.Placeable, long position);
-    property public abstract androidx.compose.ui.unit.LayoutDirection parentLayoutDirection;
-    property public abstract int parentWidth;
+    property protected abstract androidx.compose.ui.unit.LayoutDirection parentLayoutDirection;
+    property protected abstract int parentWidth;
   }
 
   public interface Remeasurement {
@@ -451,15 +469,6 @@
   @kotlin.RequiresOptIn(message="The Focus API is experimental and is likely to change in the future.") public @interface ExperimentalFocus {
   }
 
-  @androidx.compose.ui.focus.ExperimentalFocus public final class FocusManager {
-    ctor public FocusManager();
-    method public void clearFocus();
-    method public androidx.compose.ui.Modifier getModifier();
-    method public void releaseFocus();
-    method public void takeFocus();
-    property public final androidx.compose.ui.Modifier modifier;
-  }
-
   public final class FocusNodeUtilsKt {
   }
 
@@ -1861,6 +1870,7 @@
     method public void measureAndLayout();
     method public void observeLayoutModelReads(androidx.compose.ui.node.LayoutNode node, kotlin.jvm.functions.Function0<kotlin.Unit> block);
     method public void observeMeasureModelReads(androidx.compose.ui.node.LayoutNode node, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+    method public <T> void observeReads(T target, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged, kotlin.jvm.functions.Function0<kotlin.Unit> block);
     method public void onAttach(androidx.compose.ui.node.LayoutNode node);
     method public void onDetach(androidx.compose.ui.node.LayoutNode node);
     method public void onRequestMeasure(androidx.compose.ui.node.LayoutNode layoutNode);
@@ -1961,14 +1971,12 @@
   public interface AndroidOwner extends androidx.compose.ui.node.Owner {
     method @androidx.compose.ui.node.ExperimentalLayoutNodeApi public void addAndroidView(android.view.View view, androidx.compose.ui.node.LayoutNode layoutNode);
     method public kotlin.jvm.functions.Function1<android.content.res.Configuration,kotlin.Unit> getConfigurationChangeObserver();
-    method public androidx.compose.ui.focus.FocusManager getFocusManager();
     method public android.view.View getView();
     method public androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners? getViewTreeOwners();
     method public void removeAndroidView(android.view.View view);
     method public void setConfigurationChangeObserver(kotlin.jvm.functions.Function1<? super android.content.res.Configuration,kotlin.Unit> p);
     method public void setOnViewTreeOwnersAvailable(kotlin.jvm.functions.Function1<? super androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners,kotlin.Unit> callback);
     property public abstract kotlin.jvm.functions.Function1<android.content.res.Configuration,kotlin.Unit> configurationChangeObserver;
-    property public abstract androidx.compose.ui.focus.FocusManager focusManager;
     property public abstract android.view.View view;
     property public abstract androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners? viewTreeOwners;
   }
@@ -2158,7 +2166,7 @@
     method public boolean getHandlesCrossed();
     method public androidx.compose.ui.selection.Selection.AnchorInfo getStart();
     method public androidx.compose.ui.selection.Selection merge(androidx.compose.ui.selection.Selection? other);
-    method public androidx.compose.ui.text.TextRange toTextRange();
+    method public long toTextRange();
   }
 
   @androidx.compose.runtime.Immutable public static final class Selection.AnchorInfo {
@@ -2219,6 +2227,18 @@
     method public int getSteps();
   }
 
+  public final class AccessibilityScrollState {
+    ctor public AccessibilityScrollState(float value, float maxValue, boolean reverseScrolling);
+    ctor public AccessibilityScrollState();
+    method public float component1();
+    method public float component2();
+    method public boolean component3();
+    method public androidx.compose.ui.semantics.AccessibilityScrollState copy(float value, float maxValue, boolean reverseScrolling);
+    method public float getMaxValue();
+    method public boolean getReverseScrolling();
+    method public float getValue();
+  }
+
   public final class CustomAccessibilityAction {
     ctor public CustomAccessibilityAction(CharSequence label, kotlin.jvm.functions.Function0<java.lang.Boolean> action);
     method public CharSequence component1();
@@ -2327,22 +2347,26 @@
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getDisabled();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> getFocused();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getHidden();
+    method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> getHorizontalAccessibilityScrollState();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsDialog();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsPopup();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> getTestTag();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> getText();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.TextRange> getTextSelectionRange();
+    method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> getVerticalAccessibilityScrollState();
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> AccessibilityLabel;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityRangeInfo> AccessibilityRangeInfo;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> AccessibilityValue;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> Disabled;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> Focused;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> Hidden;
+    property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> HorizontalAccessibilityScrollState;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsDialog;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsPopup;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> TestTag;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> Text;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.TextRange> TextSelectionRange;
+    property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> VerticalAccessibilityScrollState;
     field public static final androidx.compose.ui.semantics.SemanticsProperties INSTANCE;
   }
 
@@ -2354,10 +2378,12 @@
     method public static androidx.compose.ui.semantics.AccessibilityRangeInfo getAccessibilityValueRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction> getCustomActions(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static boolean getFocused(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+    method public static androidx.compose.ui.semantics.AccessibilityScrollState getHorizontalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static String getTestTag(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static androidx.compose.ui.text.AnnotatedString getText(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static void getTextLayoutResult(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.ui.text.TextLayoutResult>,java.lang.Boolean> action);
-    method public static androidx.compose.ui.text.TextRange getTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+    method public static long getTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+    method public static androidx.compose.ui.semantics.AccessibilityScrollState getVerticalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static void hidden(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static void onClick(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function0<java.lang.Boolean> action);
     method public static void popup(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
@@ -2367,12 +2393,14 @@
     method public static void setAccessibilityValueRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityRangeInfo p);
     method public static void setCustomActions(androidx.compose.ui.semantics.SemanticsPropertyReceiver, java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction> p);
     method public static void setFocused(androidx.compose.ui.semantics.SemanticsPropertyReceiver, boolean p);
+    method public static void setHorizontalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityScrollState p);
     method public static void setProgress(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Boolean> action);
     method public static void setSelection(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Boolean,java.lang.Boolean> action);
     method public static void setTestTag(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String p);
     method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.AnnotatedString p);
     method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.AnnotatedString,java.lang.Boolean> action);
-    method public static void setTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.TextRange p);
+    method public static void setTextSelectionRange-Hy0MoUY(androidx.compose.ui.semantics.SemanticsPropertyReceiver, long p);
+    method public static void setVerticalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityScrollState p);
   }
 
   public final class SemanticsPropertyKey<T> {
diff --git a/compose/ui/ui/api/public_plus_experimental_current.txt b/compose/ui/ui/api/public_plus_experimental_current.txt
index ed8a943..8a0333c 100644
--- a/compose/ui/ui/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui/api/public_plus_experimental_current.txt
@@ -89,6 +89,16 @@
     method public static int merge(androidx.compose.ui.AlignmentLine, int position1, int position2);
   }
 
+  public final class CacheDrawScope implements androidx.compose.ui.unit.Density {
+    method public float getDensity();
+    method public float getFontScale();
+    method public long getSize();
+    method public androidx.compose.ui.DrawResult onDraw(kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+    property public float density;
+    property public float fontScale;
+    property public final long size;
+  }
+
   public final class CombinedModifier implements androidx.compose.ui.Modifier {
     ctor public CombinedModifier(androidx.compose.ui.Modifier outer, androidx.compose.ui.Modifier inner);
     method public boolean all(kotlin.jvm.functions.Function1<? super androidx.compose.ui.Modifier.Element,java.lang.Boolean> predicate);
@@ -107,6 +117,10 @@
     method public abstract void drawContent();
   }
 
+  public interface DrawCacheModifier extends androidx.compose.ui.DrawModifier {
+    method public void onBuildCache-lwCvPpU(long size, androidx.compose.ui.unit.Density density);
+  }
+
   public interface DrawLayerModifier extends androidx.compose.ui.Modifier.Element {
     method @FloatRange(from=0.0, to=1.0) public default float getAlpha();
     method public default boolean getClip();
@@ -145,9 +159,13 @@
 
   public final class DrawModifierKt {
     method public static androidx.compose.ui.Modifier drawBehind(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> onDraw);
+    method public static androidx.compose.ui.Modifier drawWithCache(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.CacheDrawScope,androidx.compose.ui.DrawResult> onBuildDrawCache);
     method public static androidx.compose.ui.Modifier drawWithContent(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.ContentDrawScope,kotlin.Unit> onDraw);
   }
 
+  public final class DrawResult {
+  }
+
   public final class FocusModifierKt {
     method @androidx.compose.runtime.Composable @androidx.compose.ui.focus.ExperimentalFocus public static androidx.compose.ui.Modifier focus(androidx.compose.ui.Modifier);
   }
@@ -277,16 +295,16 @@
 
   public abstract static class Placeable.PlacementScope {
     ctor public Placeable.PlacementScope();
-    method public abstract androidx.compose.ui.unit.LayoutDirection getParentLayoutDirection();
-    method public abstract int getParentWidth();
+    method protected abstract androidx.compose.ui.unit.LayoutDirection getParentLayoutDirection();
+    method protected abstract int getParentWidth();
     method public final void place(androidx.compose.ui.Placeable, int x, int y);
     method public final void place-LmmdDA8(androidx.compose.ui.Placeable, long position);
     method public final void place-gl1q84w(androidx.compose.ui.Placeable, long position);
     method public final void placeRelative(androidx.compose.ui.Placeable, int x, int y);
     method public final void placeRelative-LmmdDA8(androidx.compose.ui.Placeable, long position);
     method public final void placeRelative-gl1q84w(androidx.compose.ui.Placeable, long position);
-    property public abstract androidx.compose.ui.unit.LayoutDirection parentLayoutDirection;
-    property public abstract int parentWidth;
+    property protected abstract androidx.compose.ui.unit.LayoutDirection parentLayoutDirection;
+    property protected abstract int parentWidth;
   }
 
   public interface Remeasurement {
@@ -451,15 +469,6 @@
   @kotlin.RequiresOptIn(message="The Focus API is experimental and is likely to change in the future.") public @interface ExperimentalFocus {
   }
 
-  @androidx.compose.ui.focus.ExperimentalFocus public final class FocusManager {
-    ctor public FocusManager();
-    method public void clearFocus();
-    method public androidx.compose.ui.Modifier getModifier();
-    method public void releaseFocus();
-    method public void takeFocus();
-    property public final androidx.compose.ui.Modifier modifier;
-  }
-
   public final class FocusNodeUtilsKt {
   }
 
@@ -1861,6 +1870,7 @@
     method public void measureAndLayout();
     method public void observeLayoutModelReads(androidx.compose.ui.node.LayoutNode node, kotlin.jvm.functions.Function0<kotlin.Unit> block);
     method public void observeMeasureModelReads(androidx.compose.ui.node.LayoutNode node, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+    method public <T> void observeReads(T target, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged, kotlin.jvm.functions.Function0<kotlin.Unit> block);
     method public void onAttach(androidx.compose.ui.node.LayoutNode node);
     method public void onDetach(androidx.compose.ui.node.LayoutNode node);
     method public void onRequestMeasure(androidx.compose.ui.node.LayoutNode layoutNode);
@@ -1961,14 +1971,12 @@
   public interface AndroidOwner extends androidx.compose.ui.node.Owner {
     method @androidx.compose.ui.node.ExperimentalLayoutNodeApi public void addAndroidView(android.view.View view, androidx.compose.ui.node.LayoutNode layoutNode);
     method public kotlin.jvm.functions.Function1<android.content.res.Configuration,kotlin.Unit> getConfigurationChangeObserver();
-    method public androidx.compose.ui.focus.FocusManager getFocusManager();
     method public android.view.View getView();
     method public androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners? getViewTreeOwners();
     method public void removeAndroidView(android.view.View view);
     method public void setConfigurationChangeObserver(kotlin.jvm.functions.Function1<? super android.content.res.Configuration,kotlin.Unit> p);
     method public void setOnViewTreeOwnersAvailable(kotlin.jvm.functions.Function1<? super androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners,kotlin.Unit> callback);
     property public abstract kotlin.jvm.functions.Function1<android.content.res.Configuration,kotlin.Unit> configurationChangeObserver;
-    property public abstract androidx.compose.ui.focus.FocusManager focusManager;
     property public abstract android.view.View view;
     property public abstract androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners? viewTreeOwners;
   }
@@ -2158,7 +2166,7 @@
     method public boolean getHandlesCrossed();
     method public androidx.compose.ui.selection.Selection.AnchorInfo getStart();
     method public androidx.compose.ui.selection.Selection merge(androidx.compose.ui.selection.Selection? other);
-    method public androidx.compose.ui.text.TextRange toTextRange();
+    method public long toTextRange();
   }
 
   @androidx.compose.runtime.Immutable public static final class Selection.AnchorInfo {
@@ -2219,6 +2227,18 @@
     method public int getSteps();
   }
 
+  public final class AccessibilityScrollState {
+    ctor public AccessibilityScrollState(float value, float maxValue, boolean reverseScrolling);
+    ctor public AccessibilityScrollState();
+    method public float component1();
+    method public float component2();
+    method public boolean component3();
+    method public androidx.compose.ui.semantics.AccessibilityScrollState copy(float value, float maxValue, boolean reverseScrolling);
+    method public float getMaxValue();
+    method public boolean getReverseScrolling();
+    method public float getValue();
+  }
+
   public final class CustomAccessibilityAction {
     ctor public CustomAccessibilityAction(CharSequence label, kotlin.jvm.functions.Function0<java.lang.Boolean> action);
     method public CharSequence component1();
@@ -2327,22 +2347,26 @@
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getDisabled();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> getFocused();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getHidden();
+    method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> getHorizontalAccessibilityScrollState();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsDialog();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsPopup();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> getTestTag();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> getText();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.TextRange> getTextSelectionRange();
+    method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> getVerticalAccessibilityScrollState();
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> AccessibilityLabel;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityRangeInfo> AccessibilityRangeInfo;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> AccessibilityValue;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> Disabled;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> Focused;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> Hidden;
+    property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> HorizontalAccessibilityScrollState;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsDialog;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsPopup;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> TestTag;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> Text;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.TextRange> TextSelectionRange;
+    property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> VerticalAccessibilityScrollState;
     field public static final androidx.compose.ui.semantics.SemanticsProperties INSTANCE;
   }
 
@@ -2354,10 +2378,12 @@
     method public static androidx.compose.ui.semantics.AccessibilityRangeInfo getAccessibilityValueRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction> getCustomActions(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static boolean getFocused(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+    method public static androidx.compose.ui.semantics.AccessibilityScrollState getHorizontalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static String getTestTag(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static androidx.compose.ui.text.AnnotatedString getText(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static void getTextLayoutResult(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.ui.text.TextLayoutResult>,java.lang.Boolean> action);
-    method public static androidx.compose.ui.text.TextRange getTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+    method public static long getTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+    method public static androidx.compose.ui.semantics.AccessibilityScrollState getVerticalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static void hidden(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static void onClick(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function0<java.lang.Boolean> action);
     method public static void popup(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
@@ -2367,12 +2393,14 @@
     method public static void setAccessibilityValueRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityRangeInfo p);
     method public static void setCustomActions(androidx.compose.ui.semantics.SemanticsPropertyReceiver, java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction> p);
     method public static void setFocused(androidx.compose.ui.semantics.SemanticsPropertyReceiver, boolean p);
+    method public static void setHorizontalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityScrollState p);
     method public static void setProgress(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Boolean> action);
     method public static void setSelection(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Boolean,java.lang.Boolean> action);
     method public static void setTestTag(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String p);
     method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.AnnotatedString p);
     method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.AnnotatedString,java.lang.Boolean> action);
-    method public static void setTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.TextRange p);
+    method public static void setTextSelectionRange-Hy0MoUY(androidx.compose.ui.semantics.SemanticsPropertyReceiver, long p);
+    method public static void setVerticalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityScrollState p);
   }
 
   public final class SemanticsPropertyKey<T> {
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index 61a9cb3..965c52d 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -89,6 +89,16 @@
     method public static int merge(androidx.compose.ui.AlignmentLine, int position1, int position2);
   }
 
+  public final class CacheDrawScope implements androidx.compose.ui.unit.Density {
+    method public float getDensity();
+    method public float getFontScale();
+    method public long getSize();
+    method public androidx.compose.ui.DrawResult onDraw(kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> block);
+    property public float density;
+    property public float fontScale;
+    property public final long size;
+  }
+
   public final class CombinedModifier implements androidx.compose.ui.Modifier {
     ctor public CombinedModifier(androidx.compose.ui.Modifier outer, androidx.compose.ui.Modifier inner);
     method public boolean all(kotlin.jvm.functions.Function1<? super androidx.compose.ui.Modifier.Element,java.lang.Boolean> predicate);
@@ -121,6 +131,10 @@
     property public Object? parentData;
   }
 
+  public interface DrawCacheModifier extends androidx.compose.ui.DrawModifier {
+    method public void onBuildCache-lwCvPpU(long size, androidx.compose.ui.unit.Density density);
+  }
+
   public interface DrawLayerModifier extends androidx.compose.ui.Modifier.Element {
     method @FloatRange(from=0.0, to=1.0) public default float getAlpha();
     method public default boolean getClip();
@@ -159,9 +173,13 @@
 
   public final class DrawModifierKt {
     method public static androidx.compose.ui.Modifier drawBehind(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit> onDraw);
+    method public static androidx.compose.ui.Modifier drawWithCache(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.CacheDrawScope,androidx.compose.ui.DrawResult> onBuildDrawCache);
     method public static androidx.compose.ui.Modifier drawWithContent(androidx.compose.ui.Modifier, kotlin.jvm.functions.Function1<? super androidx.compose.ui.ContentDrawScope,kotlin.Unit> onDraw);
   }
 
+  public final class DrawResult {
+  }
+
   public final class FocusModifierKt {
     method @androidx.compose.runtime.Composable @androidx.compose.ui.focus.ExperimentalFocus public static androidx.compose.ui.Modifier focus(androidx.compose.ui.Modifier);
   }
@@ -324,16 +342,16 @@
 
   public abstract static class Placeable.PlacementScope {
     ctor public Placeable.PlacementScope();
-    method public abstract androidx.compose.ui.unit.LayoutDirection getParentLayoutDirection();
-    method public abstract int getParentWidth();
+    method protected abstract androidx.compose.ui.unit.LayoutDirection getParentLayoutDirection();
+    method protected abstract int getParentWidth();
     method public final void place(androidx.compose.ui.Placeable, int x, int y);
     method public final void place-LmmdDA8(androidx.compose.ui.Placeable, long position);
     method public final void place-gl1q84w(androidx.compose.ui.Placeable, long position);
     method public final void placeRelative(androidx.compose.ui.Placeable, int x, int y);
     method public final void placeRelative-LmmdDA8(androidx.compose.ui.Placeable, long position);
     method public final void placeRelative-gl1q84w(androidx.compose.ui.Placeable, long position);
-    property public abstract androidx.compose.ui.unit.LayoutDirection parentLayoutDirection;
-    property public abstract int parentWidth;
+    property protected abstract androidx.compose.ui.unit.LayoutDirection parentLayoutDirection;
+    property protected abstract int parentWidth;
   }
 
   public interface Remeasurement {
@@ -498,15 +516,6 @@
   @kotlin.RequiresOptIn(message="The Focus API is experimental and is likely to change in the future.") public @interface ExperimentalFocus {
   }
 
-  @androidx.compose.ui.focus.ExperimentalFocus public final class FocusManager {
-    ctor public FocusManager();
-    method public void clearFocus();
-    method public androidx.compose.ui.Modifier getModifier();
-    method public void releaseFocus();
-    method public void takeFocus();
-    property public final androidx.compose.ui.Modifier modifier;
-  }
-
   public final class FocusNodeUtilsKt {
   }
 
@@ -1923,6 +1932,7 @@
     method public void measureAndLayout();
     method public void observeLayoutModelReads(androidx.compose.ui.node.LayoutNode node, kotlin.jvm.functions.Function0<kotlin.Unit> block);
     method public void observeMeasureModelReads(androidx.compose.ui.node.LayoutNode node, kotlin.jvm.functions.Function0<kotlin.Unit> block);
+    method public <T> void observeReads(T target, kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onChanged, kotlin.jvm.functions.Function0<kotlin.Unit> block);
     method public void onAttach(androidx.compose.ui.node.LayoutNode node);
     method public void onDetach(androidx.compose.ui.node.LayoutNode node);
     method public void onRequestMeasure(androidx.compose.ui.node.LayoutNode layoutNode);
@@ -2032,14 +2042,12 @@
   public interface AndroidOwner extends androidx.compose.ui.node.Owner {
     method @androidx.compose.ui.node.ExperimentalLayoutNodeApi public void addAndroidView(android.view.View view, androidx.compose.ui.node.LayoutNode layoutNode);
     method public kotlin.jvm.functions.Function1<android.content.res.Configuration,kotlin.Unit> getConfigurationChangeObserver();
-    method public androidx.compose.ui.focus.FocusManager getFocusManager();
     method public android.view.View getView();
     method public androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners? getViewTreeOwners();
     method public void removeAndroidView(android.view.View view);
     method public void setConfigurationChangeObserver(kotlin.jvm.functions.Function1<? super android.content.res.Configuration,kotlin.Unit> p);
     method public void setOnViewTreeOwnersAvailable(kotlin.jvm.functions.Function1<? super androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners,kotlin.Unit> callback);
     property public abstract kotlin.jvm.functions.Function1<android.content.res.Configuration,kotlin.Unit> configurationChangeObserver;
-    property public abstract androidx.compose.ui.focus.FocusManager focusManager;
     property public abstract android.view.View view;
     property public abstract androidx.compose.ui.platform.AndroidOwner.ViewTreeOwners? viewTreeOwners;
   }
@@ -2235,7 +2243,7 @@
     method public boolean getHandlesCrossed();
     method public androidx.compose.ui.selection.Selection.AnchorInfo getStart();
     method public androidx.compose.ui.selection.Selection merge(androidx.compose.ui.selection.Selection? other);
-    method public androidx.compose.ui.text.TextRange toTextRange();
+    method public long toTextRange();
   }
 
   @androidx.compose.runtime.Immutable public static final class Selection.AnchorInfo {
@@ -2296,6 +2304,18 @@
     method public int getSteps();
   }
 
+  public final class AccessibilityScrollState {
+    ctor public AccessibilityScrollState(float value, float maxValue, boolean reverseScrolling);
+    ctor public AccessibilityScrollState();
+    method public float component1();
+    method public float component2();
+    method public boolean component3();
+    method public androidx.compose.ui.semantics.AccessibilityScrollState copy(float value, float maxValue, boolean reverseScrolling);
+    method public float getMaxValue();
+    method public boolean getReverseScrolling();
+    method public float getValue();
+  }
+
   public final class CustomAccessibilityAction {
     ctor public CustomAccessibilityAction(CharSequence label, kotlin.jvm.functions.Function0<java.lang.Boolean> action);
     method public CharSequence component1();
@@ -2404,22 +2424,26 @@
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getDisabled();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> getFocused();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getHidden();
+    method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> getHorizontalAccessibilityScrollState();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsDialog();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> getIsPopup();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> getTestTag();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> getText();
     method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.TextRange> getTextSelectionRange();
+    method public androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> getVerticalAccessibilityScrollState();
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> AccessibilityLabel;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityRangeInfo> AccessibilityRangeInfo;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> AccessibilityValue;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> Disabled;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.Boolean> Focused;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> Hidden;
+    property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> HorizontalAccessibilityScrollState;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsDialog;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<kotlin.Unit> IsPopup;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<java.lang.String> TestTag;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.AnnotatedString> Text;
     property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.text.TextRange> TextSelectionRange;
+    property public final androidx.compose.ui.semantics.SemanticsPropertyKey<androidx.compose.ui.semantics.AccessibilityScrollState> VerticalAccessibilityScrollState;
     field public static final androidx.compose.ui.semantics.SemanticsProperties INSTANCE;
   }
 
@@ -2431,10 +2455,12 @@
     method public static androidx.compose.ui.semantics.AccessibilityRangeInfo getAccessibilityValueRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction> getCustomActions(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static boolean getFocused(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+    method public static androidx.compose.ui.semantics.AccessibilityScrollState getHorizontalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static String getTestTag(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static androidx.compose.ui.text.AnnotatedString getText(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static void getTextLayoutResult(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super java.util.List<androidx.compose.ui.text.TextLayoutResult>,java.lang.Boolean> action);
-    method public static androidx.compose.ui.text.TextRange getTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+    method public static long getTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
+    method public static androidx.compose.ui.semantics.AccessibilityScrollState getVerticalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static void hidden(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
     method public static void onClick(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function0<java.lang.Boolean> action);
     method public static void popup(androidx.compose.ui.semantics.SemanticsPropertyReceiver);
@@ -2444,12 +2470,14 @@
     method public static void setAccessibilityValueRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityRangeInfo p);
     method public static void setCustomActions(androidx.compose.ui.semantics.SemanticsPropertyReceiver, java.util.List<androidx.compose.ui.semantics.CustomAccessibilityAction> p);
     method public static void setFocused(androidx.compose.ui.semantics.SemanticsPropertyReceiver, boolean p);
+    method public static void setHorizontalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityScrollState p);
     method public static void setProgress(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.Boolean> action);
     method public static void setSelection(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function3<? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Boolean,java.lang.Boolean> action);
     method public static void setTestTag(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String p);
     method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.AnnotatedString p);
     method public static void setText(androidx.compose.ui.semantics.SemanticsPropertyReceiver, String? label = null, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.AnnotatedString,java.lang.Boolean> action);
-    method public static void setTextSelectionRange(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.text.TextRange p);
+    method public static void setTextSelectionRange-Hy0MoUY(androidx.compose.ui.semantics.SemanticsPropertyReceiver, long p);
+    method public static void setVerticalAccessibilityScrollState(androidx.compose.ui.semantics.SemanticsPropertyReceiver, androidx.compose.ui.semantics.AccessibilityScrollState p);
   }
 
   public final class SemanticsPropertyKey<T> {
diff --git a/compose/ui/ui/build.gradle b/compose/ui/ui/build.gradle
index 232a3c7..9f3e123 100644
--- a/compose/ui/ui/build.gradle
+++ b/compose/ui/ui/build.gradle
@@ -29,7 +29,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 }
 
 kotlin {
diff --git a/compose/ui/ui/integration-tests/ui-demos/build.gradle b/compose/ui/ui/integration-tests/ui-demos/build.gradle
index 3fdea37..962cd5a 100644
--- a/compose/ui/ui/integration-tests/ui-demos/build.gradle
+++ b/compose/ui/ui/integration-tests/ui-demos/build.gradle
@@ -10,7 +10,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/ui/ui/samples/build.gradle b/compose/ui/ui/samples/build.gradle
index 143aac3..f524a13 100644
--- a/compose/ui/ui/samples/build.gradle
+++ b/compose/ui/ui/samples/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/DrawModifierSample.kt b/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/DrawModifierSample.kt
new file mode 100644
index 0000000..ba574c0
--- /dev/null
+++ b/compose/ui/ui/samples/src/main/java/androidx/compose/ui/samples/DrawModifierSample.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2020 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.ui.samples
+
+import androidx.annotation.Sampled
+import androidx.compose.foundation.Box
+import androidx.compose.foundation.clickable
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.setValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.drawWithCache
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.LinearGradient
+
+/**
+ * Sample showing how to leverage [Modifier.drawWithCache] in order
+ * to cache contents in between draw calls that depend on sizing information.
+ * In the example below, the LinearGradient is created once and re-used across
+ * calls to onDraw. If the size of the drawing area changes, then the
+ * LinearGradient is re-created with the updated width and height.
+ */
+@Sampled
+@Composable
+fun DrawWithCacheModifierSample() {
+    Box(
+        Modifier.drawWithCache {
+            val gradient = LinearGradient(
+                startX = 0.0f,
+                startY = 0.0f,
+                endX = size.width,
+                endY = size.height,
+                colors = listOf(Color.Red, Color.Blue)
+            )
+            onDraw {
+                drawRect(gradient)
+            }
+        }
+    )
+}
+
+/**
+ * Sample showing how to leverage [Modifier.drawWithCache] to persist data across
+ * draw calls. In the example below, the [LinearGradient] will be re-created if either
+ * the size of the drawing area changes, or the toggle flag represented by a mutable state
+ * object changes. Otherwise the same [LinearGradient] instance is re-used for each call
+ * to drawRect.
+ */
+@Sampled
+@Composable
+fun DrawWithCacheModifierStateParameterSample() {
+    val colors1 = listOf(Color.Red, Color.Blue)
+    val colors2 = listOf(Color.Yellow, Color.Green)
+    var toggle by remember { mutableStateOf(true) }
+    Box(
+        Modifier.clickable { toggle = !toggle }.drawWithCache {
+            val gradient = LinearGradient(
+                startX = 0.0f,
+                startY = 0.0f,
+                endX = size.width,
+                endY = size.height,
+                colors = if (toggle) colors1 else colors2
+            )
+            onDraw {
+                drawRect(gradient)
+            }
+        }
+    )
+}
\ No newline at end of file
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
index 3738bb5..dfd0dc9 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
@@ -283,7 +283,8 @@
             .getParcelableArray(AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY)
         assertEquals(1, data!!.size)
         val rectF = data[0] as RectF
-        val expectedRect = textLayoutResult.getBoundingBox(0).shift(textFieldNode.globalPosition)
+        val expectedRect = textLayoutResult.getBoundingBox(0).translate(textFieldNode
+            .globalPosition)
         assertEquals(expectedRect.left, rectF.left)
         assertEquals(expectedRect.top, rectF.top)
         assertEquals(expectedRect.right, rectF.right)
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt
new file mode 100644
index 0000000..857768b
--- /dev/null
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2020 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.ui.draw
+
+import android.os.Build
+import androidx.compose.foundation.clickable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.AtLeastSize
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.drawWithCache
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Path
+import androidx.compose.ui.graphics.toArgb
+import androidx.compose.ui.platform.testTag
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.ui.test.captureToBitmap
+import androidx.ui.test.createComposeRule
+import androidx.ui.test.onNodeWithTag
+import androidx.ui.test.performClick
+import org.junit.Assert.assertEquals
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@MediumTest
+@RunWith(JUnit4::class)
+class DrawModifierTest {
+
+    @get:Rule
+    val rule = createComposeRule()
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    fun testCacheHitWithStateChange() {
+        // Verify that a state change outside of the cache block does not
+        // require the cache block to be invalidated
+        val testTag = "testTag"
+        var cacheBuildCount = 0
+        val size = 200
+        rule.setContent {
+            var rectColor by remember { mutableStateOf(Color.Blue) }
+            AtLeastSize(size = size, modifier = Modifier.testTag(testTag).drawWithCache {
+                val drawSize = this.size
+                val path = Path().apply {
+                    lineTo(drawSize.width / 2f, 0f)
+                    lineTo(drawSize.width / 2f, drawSize.height)
+                    lineTo(0f, drawSize.height)
+                    close()
+                }
+                cacheBuildCount++
+                onDraw {
+                    drawRect(rectColor)
+                    drawPath(path, Color.Red)
+                }
+            }.clickable {
+                if (rectColor == Color.Blue) {
+                    rectColor = Color.Green
+                } else {
+                    rectColor = Color.Blue
+                }
+            }) { }
+        }
+
+        rule.onNodeWithTag(testTag).apply {
+            // Verify that the path was created only once
+            assertEquals(1, cacheBuildCount)
+            captureToBitmap().apply {
+                assertEquals(Color.Red.toArgb(), getPixel(1, 1))
+                assertEquals(Color.Red.toArgb(), getPixel(width / 2 - 2, 1))
+                assertEquals(Color.Red.toArgb(), getPixel(width / 2 - 2, height / 2 - 2))
+                assertEquals(Color.Red.toArgb(), getPixel(1, height / 2 - 2))
+
+                assertEquals(Color.Blue.toArgb(), getPixel(width / 2 + 1, 1))
+                assertEquals(Color.Blue.toArgb(), getPixel(width - 2, 1))
+                assertEquals(Color.Blue.toArgb(), getPixel(width / 2 + 1, height - 2))
+                assertEquals(Color.Blue.toArgb(), getPixel(width - 2, height - 2))
+            }
+            performClick()
+        }
+
+        rule.waitForIdle()
+
+        rule.onNodeWithTag(testTag).apply {
+            // Verify that the path was re-used and only built once
+            assertEquals(1, cacheBuildCount)
+            captureToBitmap().apply {
+                assertEquals(Color.Red.toArgb(), getPixel(1, 1))
+                assertEquals(Color.Red.toArgb(), getPixel(width / 2 - 2, 1))
+                assertEquals(Color.Red.toArgb(), getPixel(width / 2 - 2, height / 2 - 1))
+                assertEquals(Color.Red.toArgb(), getPixel(1, height / 2 - 2))
+
+                assertEquals(Color.Green.toArgb(), getPixel(width / 2 + 1, 1))
+                assertEquals(Color.Green.toArgb(), getPixel(width - 2, 1))
+                assertEquals(Color.Green.toArgb(), getPixel(width / 2 + 1, height - 2))
+                assertEquals(Color.Green.toArgb(), getPixel(width - 2, height - 2))
+            }
+        }
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    fun testCacheInvalidatedAfterStateChange() {
+        // Verify that a state change within the cache block does
+        // require the cache block to be invalidated
+        val testTag = "testTag"
+        var cacheBuildCount = 0
+        val size = 200
+
+        rule.setContent {
+            var pathFillBounds by remember { mutableStateOf(false) }
+            AtLeastSize(size = size, modifier = Modifier.testTag(testTag).drawWithCache {
+                val pathSize = if (pathFillBounds) this.size else this.size / 2f
+                val path = Path().apply {
+                    lineTo(pathSize.width, 0f)
+                    lineTo(pathSize.width, pathSize.height)
+                    lineTo(0f, pathSize.height)
+                    close()
+                }
+                cacheBuildCount++
+                onDraw {
+                    drawRect(Color.Red)
+                    drawPath(path, Color.Blue)
+                }
+            }.clickable {
+                pathFillBounds = !pathFillBounds
+            }) { }
+        }
+
+        rule.onNodeWithTag(testTag).apply {
+            // Verify that the path was created only once
+            assertEquals(1, cacheBuildCount)
+            captureToBitmap().apply {
+                assertEquals(Color.Blue.toArgb(), getPixel(1, 1))
+                assertEquals(Color.Blue.toArgb(), getPixel(width / 2 - 2, 1))
+                assertEquals(Color.Blue.toArgb(), getPixel(width / 2 - 2, height / 2 - 2))
+                assertEquals(Color.Blue.toArgb(), getPixel(1, height / 2 - 1))
+
+                assertEquals(Color.Red.toArgb(), getPixel(width / 2 + 1, 1))
+                assertEquals(Color.Red.toArgb(), getPixel(width / 2 + 1, height / 2 - 1))
+                assertEquals(Color.Red.toArgb(), getPixel(width / 2 + 1, height / 2 - 2))
+                assertEquals(Color.Red.toArgb(), getPixel(width / 2 - 2, height / 2 + 1))
+                assertEquals(Color.Red.toArgb(), getPixel(1, height / 2 + 1))
+
+                assertEquals(Color.Red.toArgb(), getPixel(1, height - 2))
+                assertEquals(Color.Red.toArgb(), getPixel(width - 2, 1))
+                assertEquals(Color.Red.toArgb(), getPixel(width - 2, height - 2))
+            }
+            performClick()
+        }
+
+        rule.waitForIdle()
+
+        rule.onNodeWithTag(testTag).apply {
+            assertEquals(2, cacheBuildCount)
+            captureToBitmap().apply {
+                assertEquals(Color.Blue.toArgb(), getPixel(1, 1))
+                assertEquals(Color.Blue.toArgb(), getPixel(size - 2, 1))
+                assertEquals(Color.Blue.toArgb(), getPixel(size - 2, size - 2))
+                assertEquals(Color.Blue.toArgb(), getPixel(1, size - 2))
+            }
+        }
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    fun testCacheInvalidatedAfterSizeChange() {
+        // Verify that a size change does cause the cache block to be invalidated
+        val testTag = "testTag"
+        var cacheBuildCount = 0
+        val startSize = 200
+        val endSize = 400
+        rule.setContent {
+            var size by remember { mutableStateOf(startSize) }
+            AtLeastSize(size = size, modifier = Modifier.testTag(testTag).drawWithCache {
+                val drawSize = this.size
+                val path = Path().apply {
+                    lineTo(drawSize.width, 0f)
+                    lineTo(drawSize.height, drawSize.height)
+                    lineTo(0f, drawSize.height)
+                    close()
+                }
+                cacheBuildCount++
+                onDraw {
+                    drawPath(path, Color.Red)
+                }
+            }.clickable {
+                if (size == startSize) {
+                    size = endSize
+                } else {
+                    size = startSize
+                }
+            }) { }
+        }
+
+        rule.onNodeWithTag(testTag).apply {
+            // Verify that the path was created only once
+            assertEquals(1, cacheBuildCount)
+            captureToBitmap().apply {
+                assertEquals(startSize, this.width)
+                assertEquals(startSize, this.height)
+                assertEquals(Color.Red.toArgb(), getPixel(1, 1))
+                assertEquals(Color.Red.toArgb(), getPixel(width - 2, height - 2))
+            }
+            performClick()
+        }
+
+        rule.waitForIdle()
+
+        rule.onNodeWithTag(testTag).apply {
+            // Verify that the path was re-used and only built once
+            assertEquals(2, cacheBuildCount)
+            captureToBitmap().apply {
+                assertEquals(endSize, this.width)
+                assertEquals(endSize, this.height)
+                assertEquals(Color.Red.toArgb(), getPixel(1, 1))
+                assertEquals(Color.Red.toArgb(), getPixel(width - 2, height - 2))
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/SetRootFocus.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/SetRootFocusTest.kt
similarity index 98%
rename from compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/SetRootFocus.kt
rename to compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/SetRootFocusTest.kt
index a575b6d..e6ef28a 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/SetRootFocus.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/SetRootFocusTest.kt
@@ -37,7 +37,7 @@
 @MediumTest
 @OptIn(ExperimentalFocus::class)
 @RunWith(JUnit4::class)
-class SetRootFocus {
+class SetRootFocusTest {
     @get:Rule
     val rule = createComposeRule()
 
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
index ce7dd7d..a273e56 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/input/pointer/PointerInputEventProcessorTest.kt
@@ -3026,6 +3026,10 @@
         block()
     }
 
+    override fun <T : Any> observeReads(target: T, onChanged: (T) -> Unit, block: () -> Unit) {
+        block()
+    }
+
     override fun measureAndLayout() {
     }
 
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/node/ViewInterop.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/node/ViewInterop.kt
index 8f45579..4514404 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/node/ViewInterop.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/node/ViewInterop.kt
@@ -23,7 +23,7 @@
 import androidx.compose.ui.MeasureScope
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.drawBehind
-import androidx.compose.ui.graphics.drawscope.drawCanvas
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
 import androidx.compose.ui.graphics.nativeCanvas
 import androidx.compose.ui.input.pointer.pointerInteropFilter
 import androidx.compose.ui.layout.positionInRoot
@@ -104,7 +104,7 @@
     val coreModifier = Modifier
         .pointerInteropFilter(this)
         .drawBehind {
-            drawCanvas { canvas, _ -> draw(canvas.nativeCanvas) }
+            drawIntoCanvas { canvas -> draw(canvas.nativeCanvas) }
         }.onPositioned {
             // The global position of this LayoutNode can change with it being replaced. For these
             // cases, we need to inform the View.
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.kt
index ad73d7d..e2c9d5b 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeView.kt
@@ -138,7 +138,7 @@
         properties = {}
     )
 
-    override val focusManager: FocusManager = FocusManager()
+    private val focusManager: FocusManager = FocusManager()
 
     private val keyInputModifier = KeyInputModifier(null, null)
 
@@ -417,6 +417,10 @@
         snapshotObserver.observeReads(node, onCommitAffectingMeasure, block)
     }
 
+    override fun <T : Any> observeReads(target: T, onChanged: (T) -> Unit, block: () -> Unit) {
+        snapshotObserver.observeReads(target, onChanged, block)
+    }
+
     fun observeLayerModelReads(layer: OwnedLayer, block: () -> Unit) {
         snapshotObserver.observeReads(layer, onCommitAffectingLayer, block)
     }
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.kt
index 14e0111..3d9e722 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.kt
@@ -34,6 +34,7 @@
 import android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY
 import android.view.accessibility.AccessibilityNodeProvider
 import androidx.annotation.IntRange
+import androidx.annotation.RequiresApi
 import androidx.collection.SparseArrayCompat
 import androidx.compose.ui.R
 import androidx.compose.ui.geometry.Rect
@@ -283,7 +284,9 @@
         if (rangeInfo != null) {
             info.rangeInfo = AccessibilityNodeInfoCompat.RangeInfoCompat.obtain(
                 AccessibilityNodeInfoCompat.RangeInfoCompat.RANGE_TYPE_FLOAT,
-                rangeInfo.range.start, rangeInfo.range.endInclusive, rangeInfo.current
+                rangeInfo.range.start,
+                rangeInfo.range.endInclusive,
+                rangeInfo.current
             )
             if (semanticsNode.config.contains(SemanticsActions.SetProgress)) {
                 if (rangeInfo.current <
@@ -299,6 +302,78 @@
             }
         }
 
+        val xScrollState =
+            semanticsNode.config.getOrNull(SemanticsProperties.HorizontalAccessibilityScrollState)
+        val scrollAction = semanticsNode.config.getOrNull(SemanticsActions.ScrollBy)
+        if (xScrollState != null && scrollAction != null) {
+            // Talkback defines SCROLLABLE_ROLE_FILTER_FOR_DIRECTION_NAVIGATION, so we need to
+            // assign a role for auto scroll to work.
+            info.className = "android.widget.HorizontalScrollView"
+            if (xScrollState.value < xScrollState.maxValue) {
+                info.addAction(
+                    AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_FORWARD
+                )
+                if (!xScrollState.reverseScrolling) {
+                    info.addAction(
+                        AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT
+                    )
+                } else {
+                    info.addAction(
+                        AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT
+                    )
+                }
+            }
+            if (xScrollState.value > 0f) {
+                info.addAction(
+                    AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_BACKWARD
+                )
+                if (!xScrollState.reverseScrolling) {
+                    info.addAction(
+                        AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT
+                    )
+                } else {
+                    info.addAction(
+                        AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT
+                    )
+                }
+            }
+        }
+        val yScrollState =
+            semanticsNode.config.getOrNull(SemanticsProperties.VerticalAccessibilityScrollState)
+        if (yScrollState != null && scrollAction != null) {
+            // Talkback defines SCROLLABLE_ROLE_FILTER_FOR_DIRECTION_NAVIGATION, so we need to
+            // assign a role for auto scroll to work.
+            info.className = "android.widget.ScrollView"
+            if (yScrollState.value < yScrollState.maxValue) {
+                info.addAction(
+                    AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_FORWARD
+                )
+                if (!yScrollState.reverseScrolling) {
+                    info.addAction(
+                        AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN
+                    )
+                } else {
+                    info.addAction(
+                        AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP
+                    )
+                }
+            }
+            if (yScrollState.value > 0f) {
+                info.addAction(
+                    AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_BACKWARD
+                )
+                if (!yScrollState.reverseScrolling) {
+                    info.addAction(
+                        AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP
+                    )
+                } else {
+                    info.addAction(
+                        AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN
+                    )
+                }
+            }
+        }
+
         if (semanticsNode.config.contains(CustomActions)) {
             val customActions = semanticsNode.config[CustomActions]
             if (customActions.size >= AccessibilityActionsResourceIds.size) {
@@ -540,21 +615,87 @@
                 }
             }
             AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD,
-            AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD -> {
-                val rangeInfo = node.config.getOrNull(SemanticsProperties.AccessibilityRangeInfo)
-                val setProgressAction = node.config.getOrNull(SemanticsActions.SetProgress)
-                if (rangeInfo != null && setProgressAction != null) {
-                    val max = rangeInfo.range.endInclusive.coerceAtLeast(rangeInfo.range.start)
-                    val min = rangeInfo.range.start.coerceAtMost(rangeInfo.range.endInclusive)
-                    var increment = if (rangeInfo.steps > 0) {
-                        (max - min) / (rangeInfo.steps + 1)
-                    } else {
-                        (max - min) / AccessibilitySliderStepsCount
+            AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD,
+            android.R.id.accessibilityActionScrollDown,
+            android.R.id.accessibilityActionScrollUp,
+            android.R.id.accessibilityActionScrollRight,
+            android.R.id.accessibilityActionScrollLeft -> {
+                if (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD ||
+                        action == AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD) {
+                    val rangeInfo =
+                        node.config.getOrNull(SemanticsProperties.AccessibilityRangeInfo)
+                    val setProgressAction = node.config.getOrNull(SemanticsActions.SetProgress)
+                    if (rangeInfo != null && setProgressAction != null) {
+                        val max = rangeInfo.range.endInclusive.coerceAtLeast(rangeInfo.range.start)
+                        val min = rangeInfo.range.start.coerceAtMost(rangeInfo.range.endInclusive)
+                        var increment = if (rangeInfo.steps > 0) {
+                            (max - min) / (rangeInfo.steps + 1)
+                        } else {
+                            (max - min) / AccessibilitySliderStepsCount
+                        }
+                        if (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD) {
+                            increment = -increment
+                        }
+                        return setProgressAction.action(rangeInfo.current + increment)
                     }
-                    if (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD) {
-                        increment = -increment
+                }
+
+                val scrollAction = node.config.getOrNull(SemanticsActions.ScrollBy) ?: return false
+                val xScrollState =
+                    node.config.getOrNull(SemanticsProperties.HorizontalAccessibilityScrollState)
+                if (xScrollState != null) {
+                    if (((!xScrollState.reverseScrolling &&
+                                action == android.R.id.accessibilityActionScrollRight) ||
+                                (xScrollState.reverseScrolling &&
+                                        action == android.R.id.accessibilityActionScrollLeft) ||
+                                (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD)) &&
+                        xScrollState.value < xScrollState.maxValue
+                    ) {
+                        return scrollAction.action(
+                            node.globalBounds.right - node.globalBounds.left,
+                            0f
+                        )
                     }
-                    return setProgressAction.action(rangeInfo.current + increment)
+                    if (((xScrollState.reverseScrolling &&
+                                action == android.R.id.accessibilityActionScrollRight) ||
+                                (!xScrollState.reverseScrolling &&
+                                        action == android.R.id.accessibilityActionScrollLeft) ||
+                                (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD)) &&
+                        xScrollState.value > 0
+                    ) {
+                        return scrollAction.action(
+                            -(node.globalBounds.right - node.globalBounds.left),
+                            0f
+                        )
+                    }
+                }
+                val yScrollState =
+                    node.config.getOrNull(SemanticsProperties.VerticalAccessibilityScrollState)
+                if (yScrollState != null) {
+                    if (((!yScrollState.reverseScrolling &&
+                                action == android.R.id.accessibilityActionScrollDown) ||
+                                (yScrollState.reverseScrolling &&
+                                        action == android.R.id.accessibilityActionScrollUp) ||
+                                (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD)) &&
+                        yScrollState.value < yScrollState.maxValue
+                    ) {
+                        return scrollAction.action(
+                            0f,
+                            node.globalBounds.bottom - node.globalBounds.top
+                        )
+                    }
+                    if (((yScrollState.reverseScrolling &&
+                                action == android.R.id.accessibilityActionScrollDown) ||
+                                (!yScrollState.reverseScrolling &&
+                                        action == android.R.id.accessibilityActionScrollUp) ||
+                                (action == AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD)) &&
+                        yScrollState.value > 0
+                    ) {
+                        return scrollAction.action(
+                            0f,
+                            -(node.globalBounds.bottom - node.globalBounds.top)
+                        )
+                    }
                 }
                 return false
             }
@@ -683,7 +824,7 @@
     }
 
     private fun toScreenCoords(textNode: SemanticsNode, bounds: Rect): Rect? {
-        val screenBounds = bounds.shift(textNode.globalPosition)
+        val screenBounds = bounds.translate(textNode.globalPosition)
         val globalBounds = textNode.globalBounds
         if (screenBounds.overlaps(globalBounds)) {
             return screenBounds.intersect(globalBounds)
@@ -945,7 +1086,8 @@
                             SemanticsProperties.Text) { AnnotatedString("") }).text
                         val event = createEvent(
                             semanticsNodeIdToAccessibilityVirtualNodeId(id),
-                            AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED)
+                            AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
+                        )
                         val textRange = newNode.config[SemanticsProperties.TextSelectionRange]
                         event.fromIndex = textRange.start
                         event.toIndex = textRange.end
@@ -953,6 +1095,56 @@
                         event.text.add(trimToSize(newText, ParcelSafeTextLength))
                         sendEvent(event)
                     }
+                    SemanticsProperties.HorizontalAccessibilityScrollState,
+                    SemanticsProperties.VerticalAccessibilityScrollState -> {
+                        // TODO(yingleiw): Add throttling for scroll/state events.
+                        val newXState = newNode.config.getOrNull(
+                            SemanticsProperties.HorizontalAccessibilityScrollState
+                        )
+                        val oldXState = oldNode.config.getOrNull(
+                            SemanticsProperties.HorizontalAccessibilityScrollState
+                        )
+                        val newYState = newNode.config.getOrNull(
+                            SemanticsProperties.VerticalAccessibilityScrollState
+                        )
+                        val oldYState = oldNode.config.getOrNull(
+                            SemanticsProperties.VerticalAccessibilityScrollState
+                        )
+                        sendEventForVirtualView(
+                            semanticsNodeIdToAccessibilityVirtualNodeId(newNode.id),
+                            AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED,
+                            AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE,
+                            null
+                        )
+                        val deltaX = if (newXState != null && oldXState != null) {
+                            newXState.value - oldXState.value
+                        } else {
+                            0
+                        }
+                        val deltaY = if (newYState != null && oldYState != null) {
+                            newYState.value - oldYState.value
+                        } else {
+                            0
+                        }
+                        if (deltaX != 0f || deltaY != 0f) {
+                            val event = createEvent(
+                                semanticsNodeIdToAccessibilityVirtualNodeId(id),
+                                AccessibilityEvent.TYPE_VIEW_SCROLLED
+                            )
+                            if (newXState != null) {
+                                event.scrollX = newXState.value.toInt()
+                                event.maxScrollX = newXState.maxValue.toInt()
+                            }
+                            if (newYState != null) {
+                                event.scrollY = newYState.value.toInt()
+                                event.maxScrollY = newYState.maxValue.toInt()
+                            }
+                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+                                Api28Impl.setScrollEventDelta(event, deltaX.toInt(), deltaY.toInt())
+                            }
+                            sendEvent(event)
+                        }
+                    }
                     else -> {
                         // TODO(b/151840490) send the correct events when property changes
                     }
@@ -1214,4 +1406,14 @@
             addExtraDataToAccessibilityNodeInfoHelper(virtualViewId, info, extraDataKey, arguments)
         }
     }
+
+    private class Api28Impl {
+        @RequiresApi(Build.VERSION_CODES.P)
+        companion object {
+            fun setScrollEventDelta(event: AccessibilityEvent, deltaX: Int, deltaY: Int) {
+                event.scrollDeltaX = deltaX
+                event.scrollDeltaY = deltaY
+            }
+        }
+    }
 }
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidOwner.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidOwner.kt
index 03f1663..d975333 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidOwner.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidOwner.kt
@@ -18,8 +18,6 @@
 import android.content.res.Configuration
 import android.view.View
 import androidx.annotation.RestrictTo
-import androidx.compose.ui.focus.ExperimentalFocus
-import androidx.compose.ui.focus.FocusManager
 import androidx.compose.ui.node.ExperimentalLayoutNodeApi
 import androidx.compose.ui.node.LayoutNode
 import androidx.compose.ui.node.Owner
@@ -39,12 +37,6 @@
     val view: View
 
     /**
-     * Provide a focus manager that controls focus within Compose.
-     */
-    @ExperimentalFocus
-    val focusManager: FocusManager
-
-    /**
      * Called to inform the owner that a new Android [View] was [attached][Owner.onAttach]
      * to the hierarchy.
      */
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt
index c8c34d2..f6d8294 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt
@@ -35,11 +35,7 @@
 import androidx.compose.runtime.currentComposer
 import androidx.compose.runtime.emptyContent
 import androidx.compose.runtime.tooling.InspectionTables
-import androidx.compose.ui.Layout
-import androidx.compose.ui.Modifier
 import androidx.compose.ui.R
-import androidx.compose.ui.focus.ExperimentalFocus
-import androidx.compose.ui.gesture.noConsumptionTapGestureFilter
 import androidx.compose.ui.node.ExperimentalLayoutNodeApi
 import androidx.compose.ui.node.LayoutNode
 import androidx.compose.ui.node.UiApplier
@@ -48,7 +44,6 @@
 import androidx.lifecycle.LifecycleOwner
 import java.util.Collections
 import java.util.WeakHashMap
-import kotlin.math.max
 
 /**
  * Composes the children of the view with the passed in [composable].
@@ -267,21 +262,9 @@
                         val inspectionTable =
                             owner.view.getTag(R.id.inspection_slot_table_set) as?
                                     MutableSet<SlotTable>
-                        if (inspectionTable != null) {
-                            inspectionTable.add(currentComposer.slotTable)
-                        }
+                        inspectionTable?.add(currentComposer.slotTable)
                         Providers(InspectionTables provides inspectionTable) {
-                            ProvideAndroidAmbients(owner) {
-                                // TODO(ralu): Please move the modifier to the root layout and
-                                //  remove the [simpleLayout].
-                                simpleLayout(
-                                    modifier = Modifier.noConsumptionTapGestureFilter {
-                                        @OptIn(ExperimentalFocus::class)
-                                        owner.focusManager.clearFocus()
-                                    },
-                                    children = content
-                                )
-                            }
+                            ProvideAndroidAmbients(owner, content)
                         }
                     }
                 } else {
@@ -312,29 +295,6 @@
     }
 }
 
-@Composable
-private fun simpleLayout(modifier: Modifier = Modifier, children: @Composable () -> Unit) {
-    Layout(modifier = modifier, children = children) { measurables, constraints ->
-        val placeables = measurables.map { measurable ->
-            measurable.measure(constraints)
-        }
-
-        val width = placeables.fold(0) { maxWidth, placeable ->
-            max(maxWidth, (placeable.width))
-        }
-
-        val height = placeables.fold(0) { minWidth, placeable ->
-            max(minWidth, (placeable.height))
-        }
-
-        layout(width, height) {
-            placeables.forEach { placeable ->
-                placeable.place(0, 0)
-            }
-        }
-    }
-}
-
 private val DefaultLayoutParams = ViewGroup.LayoutParams(
     ViewGroup.LayoutParams.WRAP_CONTENT,
     ViewGroup.LayoutParams.WRAP_CONTENT
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/DrawModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/DrawModifier.kt
index c643423..81f7ec1 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/DrawModifier.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/DrawModifier.kt
@@ -16,17 +16,41 @@
 
 package androidx.compose.ui
 
+import androidx.compose.runtime.remember
+import androidx.compose.ui.geometry.Size
 import androidx.compose.ui.graphics.Canvas
 import androidx.compose.ui.graphics.drawscope.DrawScope
+import androidx.compose.ui.unit.Density
 
 /**
  * A [Modifier.Element] that draws into the space of the layout.
  */
 interface DrawModifier : Modifier.Element {
+
     fun ContentDrawScope.draw()
 }
 
 /**
+ * [DrawModifier] implementation that supports building a cache of objects
+ * to be referenced across draw calls
+ */
+interface DrawCacheModifier : DrawModifier {
+
+    /**
+     * Callback invoked to re-build objects to be re-used across draw calls.
+     * This is useful to conditionally recreate objects only if the size of the
+     * drawing environment changes, or if state parameters that are inputs
+     * to objects change. This method is guaranteed to be called before
+     * [DrawModifier.draw].
+     *
+     * @param size The current size of the drawing environment
+     * @param density The current screen density to provide the ability to convert between
+     * density independent and raw pixel values
+     */
+    fun onBuildCache(size: Size, density: Density)
+}
+
+/**
  * Draw into a [Canvas] behind the modified content.
  */
 fun Modifier.drawBehind(
@@ -43,6 +67,86 @@
 }
 
 /**
+ * Draw into a [DrawScope] with content that is persisted across
+ * draw calls as long as the size of the drawing area is the same or
+ * any state objects that are read have not changed. In the event that
+ * the drawing area changes, or the underlying state values that are being read
+ * change, this method is invoked again to recreate objects to be used during drawing
+ *
+ * For example, a [androidx.compose.ui.graphics.LinearGradient] that is to occupy the full
+ * bounds of the drawing area can be created once the size has been defined and referenced
+ * for subsequent draw calls without having to re-allocate.
+ *
+ * @sample androidx.compose.ui.samples.DrawWithCacheModifierSample
+ * @sample androidx.compose.ui.samples.DrawWithCacheModifierStateParameterSample
+ */
+fun Modifier.drawWithCache(
+    onBuildDrawCache: CacheDrawScope.() -> DrawResult
+) = composed {
+    val cacheDrawScope = remember { CacheDrawScope() }
+    this.then(DrawBackgroundCacheModifier(cacheDrawScope, onBuildDrawCache))
+}
+
+/**
+ * Handle to a drawing environment that enables caching of content based on the resolved size.
+ * Consumers define parameters and refer to them in the captured draw callback provided in
+ * [onDraw]
+ */
+class CacheDrawScope internal constructor(
+    internal var cachedDrawDensity: Density? = null
+) : Density {
+    internal var drawResult: DrawResult? = null
+
+    /**
+     * Provides the dimensions of the current drawing environment
+     */
+    var size: Size = Size.Unspecified
+        internal set
+
+    /**
+     * Specify the callback to be invoked to issue drawing commands
+     */
+    fun onDraw(block: DrawScope.() -> Unit): DrawResult {
+        return DrawResult(block).also { drawResult = it }
+    }
+
+    override val density: Float
+        get() = cachedDrawDensity!!.density
+
+    override val fontScale: Float
+        get() = cachedDrawDensity!!.density
+}
+
+private data class DrawBackgroundCacheModifier(
+    val cacheDrawScope: CacheDrawScope,
+    val onBuildDrawCache: CacheDrawScope.() -> DrawResult
+) : DrawCacheModifier {
+
+    override fun onBuildCache(size: Size, density: Density) {
+        cacheDrawScope.apply {
+            cachedDrawDensity = density
+            this.size = size
+            drawResult = null
+            onBuildDrawCache()
+            checkNotNull(drawResult) {
+                "DrawResult not defined, did you forget to call onDraw?"
+            }
+        }
+    }
+
+    override fun ContentDrawScope.draw() {
+        cacheDrawScope.drawResult?.block?.invoke(this)
+        drawContent()
+    }
+}
+
+/**
+ * Holder to a callback to be invoked during draw operations. This lambda
+ * captures and reuses parameters defined within the CacheDrawScope receiver scope lambda.
+ */
+class DrawResult internal constructor(internal var block: DrawScope.() -> Unit)
+
+/**
  * Creates a [DrawModifier] that allows the developer to draw before or after the layout's
  * contents. It also allows the modifier to adjust the layout's canvas.
  */
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/MeasureScope.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/MeasureScope.kt
index 60dcc6b..e133d99 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/MeasureScope.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/MeasureScope.kt
@@ -19,7 +19,6 @@
 import androidx.compose.ui.MeasureScope.MeasureResult
 import androidx.compose.ui.layout.IntrinsicMeasureScope
 import androidx.compose.ui.unit.Constraints
-import androidx.compose.ui.unit.LayoutDirection
 
 /**
  * The receiver scope of a layout's measure lambda. The return value of the
@@ -67,30 +66,8 @@
         override val height = height
         override val alignmentLines = alignmentLines
         override fun placeChildren() {
-            with(InnerPlacementScope) {
-                val previousParentWidth = parentWidth
-                val previousLayoutDirection = parentLayoutDirection
-                updateValuesForRtlMirroring(layoutDirection, width)
-                placementBlock()
-                updateValuesForRtlMirroring(previousLayoutDirection, previousParentWidth)
-            }
-        }
-    }
-
-    internal companion object {
-        object InnerPlacementScope : Placeable.PlacementScope() {
-            override var parentLayoutDirection = LayoutDirection.Ltr
-                private set
-            override var parentWidth = 0
-                private set
-
-            fun updateValuesForRtlMirroring(
-                parentLayoutDirection: LayoutDirection,
-                parentWidth: Int
-            ) {
-                this.parentLayoutDirection = parentLayoutDirection
-                this.parentWidth = parentWidth
-            }
+            Placeable.PlacementScope
+                .executeWithRtlMirroringValues(width, layoutDirection, placementBlock)
         }
     }
 }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/Placeable.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/Placeable.kt
index 4695179..cd35ccd 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/Placeable.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/Placeable.kt
@@ -111,14 +111,14 @@
          * in RTL environment. If the value is zero, than the [Placeable] will be be placed to
          * the original position (position will not be mirrored).
          */
-        abstract val parentWidth: Int
+        protected abstract val parentWidth: Int
 
         /**
          * Keeps the layout direction of the parent of the placeable that is being places using
          * current [PlacementScope]. Used to support automatic position mirroring for convenient
          * RTL support in custom layouts.
          */
-        abstract val parentLayoutDirection: LayoutDirection
+        protected abstract val parentLayoutDirection: LayoutDirection
 
         /**
          * Place a [Placeable] at [position] in its parent's coordinate system.
@@ -182,5 +182,26 @@
                 place(IntOffset(parentWidth - measuredSize.width - position.x, position.y))
             }
         }
+
+        internal companion object : PlacementScope() {
+            override var parentLayoutDirection = LayoutDirection.Ltr
+                private set
+            override var parentWidth = 0
+                private set
+
+            inline fun executeWithRtlMirroringValues(
+                parentWidth: Int,
+                parentLayoutDirection: LayoutDirection,
+                crossinline block: PlacementScope.() -> Unit
+            ) {
+                val previousParentWidth = this.parentWidth
+                val previousParentLayoutDirection = this.parentLayoutDirection
+                this.parentWidth = parentWidth
+                this.parentLayoutDirection = parentLayoutDirection
+                this.block()
+                this.parentWidth = previousParentWidth
+                this.parentLayoutDirection = previousParentLayoutDirection
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusManager.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusManager.kt
index aad72bf..61ef131 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusManager.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusManager.kt
@@ -20,17 +20,33 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.focus.FocusState.Active
 import androidx.compose.ui.focus.FocusState.Inactive
+import androidx.compose.ui.gesture.PointerInputModifierImpl
+import androidx.compose.ui.gesture.TapGestureFilter
 
 /**
  * The focus manager is used by different [Owner][androidx.compose.ui.node.Owner] implementations
  * to control focus.
+ *
+ * @param focusModifier The modifier that will be used as the root focus modifier.
  */
 @ExperimentalFocus
-class FocusManager {
+internal class FocusManager(private val focusModifier: FocusModifier = FocusModifier(Inactive)) {
 
-    private val focusModifier = FocusModifier(Inactive)
+    private val passThroughClickModifier = PointerInputModifierImpl(
+            TapGestureFilter().apply {
+                onTap = { clearFocus() }
+                consumeChanges = false
+            }
+        )
+
+    /**
+     * A [Modifier] that can be added to the [Owners][androidx.compose.ui.node.Owner] modifier
+     * list that contains the modifiers required by the foucus system. (Eg, a root focus modifier).
+     */
     val modifier: Modifier
-        get() = focusModifier
+        // TODO(b/168831247): return an empty Modifier when there are no focusable children.
+        get() = passThroughClickModifier
+            .then(focusModifier)
 
     /**
      * The [Owner][androidx.compose.ui.node.Owner] calls this function when it gains focus. This
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatingLayoutNodeWrapper.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatingLayoutNodeWrapper.kt
index ab66c6b..bf25e02 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatingLayoutNodeWrapper.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DelegatingLayoutNodeWrapper.kt
@@ -27,7 +27,6 @@
 import androidx.compose.ui.input.pointer.PointerInputFilter
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.IntOffset
-import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.util.nativeClass
 
 /**
@@ -93,12 +92,11 @@
         // our position in order ot know how to offset the value we provided).
         if (wrappedBy?.isShallowPlacing == true) return
 
-        with(InnerPlacementScope) {
-            val previousParentWidth = this.parentWidth
-            val previousLayoutDirection = this.parentLayoutDirection
-            updateValuesForRtlMirroring(measureScope.layoutDirection, measuredSize.width)
+        PlacementScope.executeWithRtlMirroringValues(
+            measuredSize.width,
+            measureScope.layoutDirection
+        ) {
             measureResult.placeChildren()
-            updateValuesForRtlMirroring(previousLayoutDirection, previousParentWidth)
         }
     }
 
@@ -109,7 +107,7 @@
             override val height: Int = wrapped.measureResult.height
             override val alignmentLines: Map<AlignmentLine, Int> = emptyMap()
             override fun placeChildren() {
-                with(InnerPlacementScope) {
+                with(PlacementScope) {
                     placeable.place(-apparentToRealOffset)
                 }
             }
@@ -165,15 +163,3 @@
         _isAttached = false
     }
 }
-
-internal object InnerPlacementScope : Placeable.PlacementScope() {
-    override var parentLayoutDirection = LayoutDirection.Ltr
-        private set
-    override var parentWidth = 0
-        private set
-
-    fun updateValuesForRtlMirroring(parentLayoutDirection: LayoutDirection, parentWidth: Int) {
-        this.parentLayoutDirection = parentLayoutDirection
-        this.parentWidth = parentWidth
-    }
-}
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
index 00ea94b..4888b4f 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
@@ -32,6 +32,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.OnPositionedModifier
 import androidx.compose.ui.ParentDataModifier
+import androidx.compose.ui.Placeable
 import androidx.compose.ui.Remeasurement
 import androidx.compose.ui.RemeasurementModifier
 import androidx.compose.ui.ZIndexModifier
@@ -40,7 +41,7 @@
 import androidx.compose.ui.geometry.Size
 import androidx.compose.ui.graphics.Canvas
 import androidx.compose.ui.graphics.drawscope.DrawScope
-import androidx.compose.ui.graphics.drawscope.drawCanvas
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
 import androidx.compose.ui.input.key.KeyInputModifier
 import androidx.compose.ui.input.pointer.PointerInputFilter
 import androidx.compose.ui.input.pointer.PointerInputModifier
@@ -780,12 +781,11 @@
     internal var needsOnPositionedDispatch = false
 
     fun place(x: Int, y: Int) {
-        with(InnerPlacementScope) {
-            val previousParentWidth = parentWidth
-            val previousLayoutDirection = parentLayoutDirection
-            updateValuesForRtlMirroring(layoutDirection, outerMeasurablePlaceable.measuredWidth)
+        Placeable.PlacementScope.executeWithRtlMirroringValues(
+            outerMeasurablePlaceable.measuredWidth,
+            layoutDirection
+        ) {
             outerMeasurablePlaceable.placeRelative(x, y)
-            updateValuesForRtlMirroring(previousLayoutDirection, previousParentWidth)
         }
     }
 
@@ -1344,9 +1344,7 @@
     private var wrapped: LayoutNodeWrapper? = null
 
     override fun drawContent() {
-        drawCanvas { canvas, _ ->
-            wrapped?.draw(canvas)
-        }
+        drawIntoCanvas { canvas -> wrapped?.draw(canvas) }
     }
 
     internal fun draw(
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeWrapper.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeWrapper.kt
index 0e4761e..b69647e 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeWrapper.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNodeWrapper.kt
@@ -61,7 +61,7 @@
     open val invalidateLayerOnBoundsChange = true
 
     private var _measureResult: MeasureScope.MeasureResult? = null
-    var measureResult: MeasureScope.MeasureResult
+    open var measureResult: MeasureScope.MeasureResult
         get() = _measureResult ?: error(UnmeasuredError)
         internal set(value) {
             if (invalidateLayerOnBoundsChange &&
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ModifiedDrawNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ModifiedDrawNode.kt
index 7f4cd55..fdce7d6 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ModifiedDrawNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ModifiedDrawNode.kt
@@ -16,9 +16,12 @@
 
 package androidx.compose.ui.node
 
+import androidx.compose.ui.DrawCacheModifier
 import androidx.compose.ui.DrawModifier
+import androidx.compose.ui.MeasureScope
 import androidx.compose.ui.geometry.Size
 import androidx.compose.ui.graphics.Canvas
+import androidx.compose.ui.unit.toSize
 
 @OptIn(ExperimentalLayoutNodeApi::class)
 internal class ModifiedDrawNode(
@@ -26,14 +29,47 @@
     drawModifier: DrawModifier
 ) : DelegatingLayoutNodeWrapper<DrawModifier>(wrapped, drawModifier) {
 
+    private val cacheDrawModifier: DrawCacheModifier? =
+        if (drawModifier is DrawCacheModifier) {
+            drawModifier
+        } else {
+            null
+        }
+
+    // Flag to determine if the cache should be re-built
+    private var invalidateCache = true
+
+    // Callback used to build the drawing cache
+    private val updateCache = {
+        val size: Size = measuredSize.toSize()
+        cacheDrawModifier?.onBuildCache(size, layoutNode.mDrawScope)
+        invalidateCache = false
+    }
+
+    override var measureResult: MeasureScope.MeasureResult
+        get() = super.measureResult
+        set(value) {
+            if (super.measuredSize.width != value.width ||
+                super.measuredSize.height != value.height
+            ) {
+                invalidateCache = true
+            }
+            super.measureResult = value
+        }
+
     // This is not thread safe
     override fun draw(canvas: Canvas) {
+        val size = measuredSize.toSize()
+        if (cacheDrawModifier != null && invalidateCache) {
+            layoutNode.owner?.observeReads(
+                this,
+                onCommitAffectingModifiedDrawNode,
+                updateCache
+            )
+        }
+
         val drawScope = layoutNode.mDrawScope
         withPositionTranslation(canvas) {
-            val size = Size(
-                measuredSize.width.toFloat(),
-                measuredSize.height.toFloat()
-            )
             drawScope.draw(canvas, size, wrapped) {
                 with(drawScope) {
                     with(modifier) {
@@ -43,4 +79,17 @@
             }
         }
     }
+
+    companion object {
+        // Callback invoked whenever a state parameter that is read within the cache
+        // execution callback is updated. This marks the cache flag as dirty and
+        // invalidates the current layer.
+        private val onCommitAffectingModifiedDrawNode: (ModifiedDrawNode) -> Unit =
+            { modifiedDrawNode ->
+                // Note this intentionally does not invalidate the layer as Owner implementations
+                // already observe and invalidate the layer on state changes. Instead just
+                // mark the cache dirty so that it will be re-created on the next draw
+                modifiedDrawNode.invalidateCache = true
+            }
+    }
 }
\ No newline at end of file
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OuterMeasurablePlaceable.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OuterMeasurablePlaceable.kt
index aea1a44..3b00627 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OuterMeasurablePlaceable.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/OuterMeasurablePlaceable.kt
@@ -110,7 +110,7 @@
 
     override fun placeAt(position: IntOffset) {
         lastPosition = position
-        with(InnerPlacementScope) {
+        with(PlacementScope) {
             outerWrapper.place(position)
         }
     }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
index 7795ee3..5a0691c 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/Owner.kt
@@ -154,6 +154,12 @@
     fun observeMeasureModelReads(node: LayoutNode, block: () -> Unit)
 
     /**
+     * Observe model reads for any target, allowing consumers to determine how to respond
+     * to state changes
+     */
+    fun <T : Any> observeReads(target: T, onChanged: (T) -> Unit, block: () -> Unit)
+
+    /**
      * Iterates through all LayoutNodes that have requested layout and measures and lays them out
      */
     fun measureAndLayout()
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
index a44f0a9..69027ba 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsProperties.kt
@@ -90,6 +90,14 @@
     )
 
     /**
+     * The horizontal scroll state of this node if this node is scrollable.
+     *
+     * @see SemanticsPropertyReceiver.horizontalAccessibilityScrollState
+     */
+    val HorizontalAccessibilityScrollState =
+        SemanticsPropertyKey<AccessibilityScrollState>("HorizontalAccessibilityScrollState")
+
+    /**
      * Whether this semantics node represents a Popup. Not to be confused with if this node is
      * _part of_ a Popup.
      *
@@ -159,6 +167,14 @@
      * @see SemanticsPropertyReceiver.textSelectionRange
      */
     val TextSelectionRange = SemanticsPropertyKey<TextRange>("TextSelectionRange")
+
+    /**
+     * The vertical scroll state of this node if this node is scrollable.
+     *
+     * @see SemanticsPropertyReceiver.verticalAccessibilityScrollState
+     */
+    val VerticalAccessibilityScrollState =
+        SemanticsPropertyKey<AccessibilityScrollState>("VerticalAccessibilityScrollState")
 }
 
 /**
@@ -307,6 +323,21 @@
     @IntRange(from = 0) val steps: Int = 0
 )
 
+/**
+ * The scroll state of this node if this node is scrollable.
+ *
+ * @param value current scroll position value in pixels
+ * @param maxValue maximum bound for [value], or [Float.POSITIVE_INFINITY] if still unknown
+ * @param reverseScrolling for horizontal scroll, when this is `true`, 0 [value] will mean right,
+ * when`false`, 0 [value] will mean left. For vertical scroll, when this is `true`, 0 [value] will
+ * mean bottom, when `false`, 0 [value] will mean top
+ */
+data class AccessibilityScrollState(
+    val value: Float = 0f,
+    val maxValue: Float = 0f,
+    val reverseScrolling: Boolean = false
+)
+
 interface SemanticsPropertyReceiver {
     operator fun <T> set(key: SemanticsPropertyKey<T>, value: T)
 }
@@ -363,6 +394,22 @@
 }
 
 /**
+ * The horizontal scroll state of this node if this node is scrollable.
+ *
+ * @see SemanticsProperties.HorizontalAccessibilityScrollState
+ */
+var SemanticsPropertyReceiver.horizontalAccessibilityScrollState
+        by SemanticsProperties.HorizontalAccessibilityScrollState
+
+/**
+ * The vertical scroll state of this node if this node is scrollable.
+ *
+ * @see SemanticsProperties.VerticalAccessibilityScrollState
+ */
+var SemanticsPropertyReceiver.verticalAccessibilityScrollState
+        by SemanticsProperties.VerticalAccessibilityScrollState
+
+/**
  * Whether this semantics node represents a Popup. Not to be confused with if this node is
  * _part of_ a Popup.
  *
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.kt
index 2a86c3b..2f04988 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.kt
@@ -40,6 +40,7 @@
 import androidx.compose.ui.input.pointer.PointerInputEventProcessor
 import androidx.compose.ui.input.pointer.PointerInputFilter
 import androidx.compose.ui.input.pointer.PointerMoveEventFilter
+import androidx.compose.ui.layout.globalBounds
 import androidx.compose.ui.node.ExperimentalLayoutNodeApi
 import androidx.compose.ui.node.InternalCoreApi
 import androidx.compose.ui.node.LayoutNode
@@ -180,6 +181,10 @@
         snapshotObserver.observeReads(node, onCommitAffectingMeasure, block)
     }
 
+    override fun <T : Any> observeReads(target: T, onChanged: (T) -> Unit, block: () -> Unit) {
+        snapshotObserver.observeReads(target, onChanged, block)
+    }
+
     private fun observeDrawModelReads(layer: SkijaLayer, block: () -> Unit) {
         snapshotObserver.observeReads(layer, onCommitAffectingLayer, block)
     }
@@ -261,8 +266,10 @@
             .asSequence()
             .filterIsInstance<PointerMoveEventFilter>()
         ) {
-            if (!onMoveConsumed)
-                onMoveConsumed = filter.onMoveHandler(position)
+            if (!onMoveConsumed) {
+                val relative = position - filter.layoutCoordinates.globalBounds.topLeft
+                onMoveConsumed = filter.onMoveHandler(relative)
+            }
             if (!onEnterConsumed && !oldMoveFilters.contains(filter))
                 onEnterConsumed = filter.onEnterHandler()
         }
diff --git a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/focus/FocusManagerTest.kt b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/focus/FocusManagerTest.kt
index c29bc230..05caee2 100644
--- a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/focus/FocusManagerTest.kt
+++ b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/focus/FocusManagerTest.kt
@@ -40,15 +40,15 @@
     ExperimentalLayoutNodeApi::class
 )
 @RunWith(Parameterized::class)
-class FocusManagerTest(val initialFocusState: FocusState) {
+class FocusManagerTest(private val initialFocusState: FocusState) {
     companion object {
         @JvmStatic
         @Parameterized.Parameters(name = "rootInitialFocus = {0}")
         fun initParameters() = FocusState.values()
     }
 
-    private val focusManager = FocusManager()
-    private val focusModifier: FocusModifier = focusManager.modifier as FocusModifier
+    private val focusModifier = FocusModifier(Inactive)
+    private val focusManager = FocusManager(focusModifier)
 
     @Before
     fun setup() {
diff --git a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
index cb823e0..46385b9 100644
--- a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
+++ b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/node/LayoutNodeTest.kt
@@ -1720,6 +1720,10 @@
         block()
     }
 
+    override fun <T : Any> observeReads(target: T, onChanged: (T) -> Unit, block: () -> Unit) {
+        block()
+    }
+
     override fun measureAndLayout() {
     }
 
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ContentAccessProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ContentAccessProcessor.kt
index cde30d1..4cf63d3 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ContentAccessProcessor.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ContentAccessProcessor.kt
@@ -46,13 +46,13 @@
     class ContentAccessProcessStep(val processingEnv: ProcessingEnvironment) : ProcessingStep {
         @KotlinPoetMetadataPreview
         override fun process(elementsByAnnotation: SetMultimap<Class<out Annotation>, Element>?):
-                Set<Element> {
+            Set<Element> {
 
-            elementsByAnnotation?.get(ContentAccessObject::class.java)?.forEach {
-                ContentAccessObjectProcessor(MoreElements.asType(it), processingEnv).process()
+                elementsByAnnotation?.get(ContentAccessObject::class.java)?.forEach {
+                    ContentAccessObjectProcessor(MoreElements.asType(it), processingEnv).process()
+                }
+                return emptySet()
             }
-            return emptySet()
-        }
 
         override fun annotations(): MutableSet<out Class<out Annotation>> {
             return mutableSetOf(ContentAccessObject::class.java)
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/element_ext.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/element_ext.kt
index 69f100a..a5e990b 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/element_ext.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/element_ext.kt
@@ -64,36 +64,36 @@
 fun TypeElement.isFilledThroughConstructor() = this.getNonPrivateNonIgnoreConstructors().size == 1
 
 fun TypeElement.isNotInstantiable():
-        Boolean {
-    // No constructors means we can't instantiate it to fill its public fields, user might have
-    // made the default constructor private or simply ignored it.
-    return this.getNonPrivateNonIgnoreConstructors().isEmpty()
-}
+    Boolean {
+        // No constructors means we can't instantiate it to fill its public fields, user might have
+        // made the default constructor private or simply ignored it.
+        return this.getNonPrivateNonIgnoreConstructors().isEmpty()
+    }
 
 /**
  * Gets either all the parameters of the single public constructor if they exist, otherwise returns
  * a list of all public fields, even if empty.
  */
 fun TypeElement.getAllConstructorParamsOrPublicFields():
-        List<VariableElement> {
-    val constructors = this.getNonPrivateNonIgnoreConstructors()
+    List<VariableElement> {
+        val constructors = this.getNonPrivateNonIgnoreConstructors()
 
-    if (constructors.size == 1) {
-        val parameters = MoreElements.asExecutable(constructors.first()).parameters
-        if (parameters.isNotEmpty()) {
-            return parameters.map { it as VariableElement }
+        if (constructors.size == 1) {
+            val parameters = MoreElements.asExecutable(constructors.first()).parameters
+            if (parameters.isNotEmpty()) {
+                return parameters.map { it as VariableElement }
+            }
+        } else if (constructors.isEmpty()) {
+            error("${this.qualifiedName} has no non private and non ignored constructors!")
+        } else {
+            error("${this.qualifiedName} has more than non private non ignored constructor")
         }
-    } else if (constructors.isEmpty()) {
-        error("${this.qualifiedName} has no non private and non ignored constructors!")
-    } else {
-        error("${this.qualifiedName} has more than non private non ignored constructor")
+        // TODO(obenabde): explore ways to warn users if they're unknowingly doing something wrong
+        //  e.g if there is a possibility they think we are filling fields instead of constructors
+        //  or both etc...
+        // This is a class with an empty or no public constructor, check public fields.
+        return getAllNonPrivateFieldsIncludingSuperclassOnes()
     }
-    // TODO(obenabde): explore ways to warn users if they're unknowingly doing something wrong
-    //  e.g if there is a possibility they think we are filling fields instead of constructors
-    //  or both etc...
-    // This is a class with an empty or no public constructor, check public fields.
-    return getAllNonPrivateFieldsIncludingSuperclassOnes()
-}
 
 fun TypeElement.getAllNonPrivateFieldsIncludingSuperclassOnes(): List<VariableElement> {
     var nonPrivateFields = ElementFilter.fieldsIn(this.enclosedElements)
@@ -117,11 +117,14 @@
 }
 
 fun TypeMirror.extendsBound(): TypeMirror? {
-    return this.accept(object : SimpleTypeVisitor7<TypeMirror?, Void?>() {
-        override fun visitWildcard(type: WildcardType, ignored: Void?): TypeMirror? {
-            return type.extendsBound ?: type.superBound
-        }
-    }, null)
+    return this.accept(
+        object : SimpleTypeVisitor7<TypeMirror?, Void?>() {
+            override fun visitWildcard(type: WildcardType, ignored: Void?): TypeMirror? {
+                return type.extendsBound ?: type.superBound
+            }
+        },
+        null
+    )
 }
 
 @KotlinPoetMetadataPreview
@@ -130,25 +133,28 @@
 
 @KotlinPoetMetadataPreview
 fun ExecutableElement.getSuspendFunctionReturnType():
-        TypeMirror {
-    val typeParam = MoreTypes.asDeclared(parameters.last().asType()).typeArguments.first()
-    return typeParam.extendsBound() ?: typeParam
-}
+    TypeMirror {
+        val typeParam = MoreTypes.asDeclared(parameters.last().asType()).typeArguments.first()
+        return typeParam.extendsBound() ?: typeParam
+    }
 
 @KotlinPoetMetadataPreview
 fun ExecutableElement.getKotlinFunspec(processingEnv: ProcessingEnvironment):
-        FunSpec {
-    val classInspector = ElementsClassInspector.create(processingEnv.elementUtils, processingEnv
-        .typeUtils)
-    val enclosingClass = this.enclosingElement as TypeElement
+    FunSpec {
+        val classInspector = ElementsClassInspector.create(
+            processingEnv.elementUtils,
+            processingEnv
+                .typeUtils
+        )
+        val enclosingClass = this.enclosingElement as TypeElement
 
-    val kotlinApi = enclosingClass.toTypeSpec(classInspector)
-    val jvmSignature = JvmSignatureUtil.getMethodDescriptor(this)
-    val funSpec = kotlinApi.funSpecs.find {
-        it.tag<ImmutableKmFunction>()?.signature?.asString() == jvmSignature
-    } ?: error("No matching funSpec found for $jvmSignature.")
-    return funSpec
-}
+        val kotlinApi = enclosingClass.toTypeSpec(classInspector)
+        val jvmSignature = JvmSignatureUtil.getMethodDescriptor(this)
+        val funSpec = kotlinApi.funSpecs.find {
+            it.tag<ImmutableKmFunction>()?.signature?.asString() == jvmSignature
+        } ?: error("No matching funSpec found for $jvmSignature.")
+        return funSpec
+    }
 
 fun TypeElement.getAllMethodsIncludingSupers(): Set<ExecutableElement> {
     val myMethods = ElementFilter.methodsIn(this.enclosedElements).toSet()
@@ -217,20 +223,24 @@
         }
         method.name to result
     }
-    return AnnotationBox(Proxy.newProxyInstance(ClassGetter::class.java.classLoader,
-            arrayOf(cl, ClassGetter::class.java)) { _, method, args ->
-        when (method.name) {
-            ClassGetter::getAsTypeMirror.name -> map[args[0]]
-            ClassGetter::getAsTypeMirrorList.name -> map[args[0]]
-            "getAsAnnotationBox" -> map[args[0]]
-            "getAsAnnotationBoxArray" -> map[args[0]]
-            else -> map[method.name]
+    return AnnotationBox(
+        Proxy.newProxyInstance(
+            ClassGetter::class.java.classLoader,
+            arrayOf(cl, ClassGetter::class.java)
+        ) { _, method, args ->
+            when (method.name) {
+                ClassGetter::getAsTypeMirror.name -> map[args[0]]
+                ClassGetter::getAsTypeMirrorList.name -> map[args[0]]
+                "getAsAnnotationBox" -> map[args[0]]
+                "getAsAnnotationBoxArray" -> map[args[0]]
+                else -> map[method.name]
+            }
         }
-    })
+    )
 }
 
 fun <T : Annotation> Element.toAnnotationBox(cl: KClass<T>) =
-        MoreElements.getAnnotationMirror(this, cl.java).orNull()?.box(cl.java)
+    MoreElements.getAnnotationMirror(this, cl.java).orNull()?.box(cl.java)
 
 @Suppress("DEPRECATION")
 private class ListVisitor<T : Annotation>(private val annotationClass: Class<T>) :
@@ -355,7 +365,7 @@
     return object : SimpleAnnotationValueVisitor6<T, Void>() {
         override fun visitEnumConstant(value: VariableElement?, p: Void?): T {
             return enumClass.getDeclaredMethod("valueOf", String::class.java)
-                    .invoke(null, value!!.simpleName.toString()) as T
+                .invoke(null, value!!.simpleName.toString()) as T
         }
     }.visit(this)
 }
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/type_mirror_ext.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/type_mirror_ext.kt
index 53ea666..ffb4433 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/type_mirror_ext.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/ext/type_mirror_ext.kt
@@ -52,18 +52,21 @@
 }
 
 fun TypeMirror.extractImmediateTypeParameter():
-        TypeMirror {
-    val asDeclared = MoreTypes.asDeclared(this)
-    return asDeclared.typeArguments.first()
-}
+    TypeMirror {
+        val asDeclared = MoreTypes.asDeclared(this)
+        return asDeclared.typeArguments.first()
+    }
 
 fun TypeMirror.extractIntendedReturnType(): TypeMirror {
     if (!this.isSupportedGenericType()) {
         return this
     }
     val firstWrappedType = extractImmediateTypeParameter()
-    if (isFlowable() && (firstWrappedType.isSupportedCollection() ||
-                firstWrappedType.isOptional())) {
+    if (isFlowable() && (
+        firstWrappedType.isSupportedCollection() ||
+            firstWrappedType.isOptional()
+        )
+    ) {
         return firstWrappedType.extractImmediateTypeParameter()
     }
     return firstWrappedType
@@ -138,22 +141,31 @@
 
 fun TypeMirror.isDouble() = isPrimitiveDouble() || isBoxedDouble()
 
-fun TypeMirror.isString() = MoreTypes.isType(this) && MoreTypes.isTypeOf(String::class
-    .java, this)
+fun TypeMirror.isString() = MoreTypes.isType(this) && MoreTypes.isTypeOf(
+    String::class
+        .java,
+    this
+)
 
-fun TypeMirror.isPrimitiveBlob() = MoreTypes.isType(this) && MoreTypes.isTypeOf(ByteArray::class
-    .java, this)
+fun TypeMirror.isPrimitiveBlob() = MoreTypes.isType(this) && MoreTypes.isTypeOf(
+    ByteArray::class
+        .java,
+    this
+)
 
-fun TypeMirror.isBoxedBlob() = MoreTypes.isType(this) && MoreTypes.isTypeOf(Array<Byte>::class
-    .java, this)
+fun TypeMirror.isBoxedBlob() = MoreTypes.isType(this) && MoreTypes.isTypeOf(
+    Array<Byte>::class
+        .java,
+    this
+)
 
 fun TypeMirror.isBlob() = isPrimitiveBlob() || isBoxedBlob()
 
 fun TypeMirror.isSupportedColumnType() = isBlob() || isInt() || isString() || isFloat() ||
-        isDouble() || isShort() || isLong()
+    isDouble() || isShort() || isLong()
 
 fun TypeMirror.isPrimitive(): Boolean = isPrimitiveLong() || isPrimitiveShort() ||
-        isPrimitiveBlob() || isPrimitiveDouble() || isPrimitiveFloat() || isPrimitiveInt()
+    isPrimitiveBlob() || isPrimitiveDouble() || isPrimitiveFloat() || isPrimitiveInt()
 
 fun TypeMirror.getCursorMethod(): String {
     if (isShort()) {
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentAccessObjectProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentAccessObjectProcessor.kt
index af1eb98..9002873 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentAccessObjectProcessor.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentAccessObjectProcessor.kt
@@ -36,19 +36,25 @@
 class ContentAccessObjectProcessor(
     val element: TypeElement,
     private val processingEnv:
-            ProcessingEnvironment
+        ProcessingEnvironment
 ) {
     @KotlinPoetMetadataPreview
     fun process() {
         val errorReporter = ErrorReporter(processingEnv.messager)
         if (element.kind != ElementKind.INTERFACE) {
-            errorReporter.reportError("Only interfaces should be annotated with " +
-                    "@ContentAccessObject, '${element.qualifiedName}' is not interface.", element)
+            errorReporter.reportError(
+                "Only interfaces should be annotated with " +
+                    "@ContentAccessObject, '${element.qualifiedName}' is not interface.",
+                element
+            )
         } else {
             if (element.getAllMethodsIncludingSupers().isEmpty()) {
-                errorReporter.reportError("Interface '${element.qualifiedName}' annotated with " +
+                errorReporter.reportError(
+                    "Interface '${element.qualifiedName}' annotated with " +
                         "@ContentAccessObject doesn't delcare any functions. Interfaces annotated" +
-                        " with @ContentAccessObject should declare at least one function.", element)
+                        " with @ContentAccessObject should declare at least one function.",
+                    element
+                )
             }
         }
         val contentEntityType = element.toAnnotationBox(ContentAccessObject::class)!!
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessor.kt
index cfb0324..d317ce7 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessor.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessor.kt
@@ -45,8 +45,10 @@
     fun processEntity(): ContentEntityVO? {
         val entity = contentEntity.asTypeElement()
         if (entity.hasMoreThanOneNonPrivateNonIgnoredConstructor()) {
-            errorReporter.reportError(entityWithMultipleConstructors(contentEntity.toString()),
-                entity)
+            errorReporter.reportError(
+                entityWithMultipleConstructors(contentEntity.toString()),
+                entity
+            )
             return null
         } else if (entity.isNotInstantiable()) {
             errorReporter.reportError(nonInstantiableEntity(contentEntity.toString()), entity)
@@ -54,19 +56,34 @@
         }
         val columns = entity.getAllConstructorParamsOrPublicFields()
         columns.forEach {
-            if (fieldIsNullable(it) && (it.asType().isPrimitive() &&
-                        !it.asType().isPrimitiveBlob())) {
-                errorReporter.reportError(entityWithNullablePrimitiveType(it.simpleName.toString(),
-                    contentEntity.toString()), it)
+            if (fieldIsNullable(it) && (
+                it.asType().isPrimitive() &&
+                    !it.asType().isPrimitiveBlob()
+                )
+            ) {
+                errorReporter.reportError(
+                    entityWithNullablePrimitiveType(
+                        it.simpleName.toString(),
+                        contentEntity.toString()
+                    ),
+                    it
+                )
             }
         }
         val contentColumns = HashMap<String, ContentColumnVO>()
         val contentPrimaryKey = ArrayList<ContentColumnVO>()
         columns.forEach { column ->
             if (column.hasAnnotation(ContentColumn::class) &&
-                column.hasAnnotation(ContentPrimaryKey::class)) {
-                errorReporter.reportError(entityFieldWithBothAnnotations(column.simpleName
-                    .toString(), entity.qualifiedName.toString()), entity)
+                column.hasAnnotation(ContentPrimaryKey::class)
+            ) {
+                errorReporter.reportError(
+                    entityFieldWithBothAnnotations(
+                        column.simpleName
+                            .toString(),
+                        entity.qualifiedName.toString()
+                    ),
+                    entity
+                )
             } else if (column.hasAnnotation(ContentColumn::class)) {
                 if (validateColumnType(column, errorReporter)) {
                     val vo = ContentColumnVO(
@@ -79,8 +96,10 @@
                 }
             } else if (column.hasAnnotation(ContentPrimaryKey::class)) {
                 if (validateColumnType(column, errorReporter)) {
-                    val vo = ContentColumnVO(column.simpleName.toString(), column.asType(), column
-                        .getAnnotation(ContentPrimaryKey::class.java).columnName,
+                    val vo = ContentColumnVO(
+                        column.simpleName.toString(), column.asType(),
+                        column
+                            .getAnnotation(ContentPrimaryKey::class.java).columnName,
                         fieldIsNullable(column),
                         fieldRequiresApi(column)
                     )
@@ -99,11 +118,21 @@
         }
         if (contentPrimaryKey.isEmpty()) {
             if (columns.isEmpty()) {
-                errorReporter.reportError(missingFieldsInContentEntityErrorMessage(entity
-                    .qualifiedName.toString()), entity)
+                errorReporter.reportError(
+                    missingFieldsInContentEntityErrorMessage(
+                        entity
+                            .qualifiedName.toString()
+                    ),
+                    entity
+                )
             } else {
-                errorReporter.reportError(missingEntityPrimaryKeyErrorMessage(entity
-                    .qualifiedName.toString()), entity)
+                errorReporter.reportError(
+                    missingEntityPrimaryKeyErrorMessage(
+                        entity
+                            .qualifiedName.toString()
+                    ),
+                    entity
+                )
             }
         }
         if (contentPrimaryKey.size > 1) {
@@ -115,17 +144,24 @@
         if (errorReporter.errorReported) {
             return null
         }
-        return ContentEntityVO(entity.getAnnotation(ContentEntity::class.java).uri, MoreTypes
-            .asDeclared(entity.asType()), contentColumns, contentPrimaryKey.first())
+        return ContentEntityVO(
+            entity.getAnnotation(ContentEntity::class.java).uri,
+            MoreTypes
+                .asDeclared(entity.asType()),
+            contentColumns, contentPrimaryKey.first()
+        )
     }
 
     fun validateColumnType(column: VariableElement, errorReporter: ErrorReporter): Boolean {
         if (!column.asType().isSupportedColumnType()) {
             errorReporter.reportError(
-                unsupportedColumnType(column.simpleName.toString(),
+                unsupportedColumnType(
+                    column.simpleName.toString(),
                     contentEntity.toString(),
                     column.asType().toString()
-                ), column)
+                ),
+                column
+            )
             return false
         }
         return true
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessor.kt
index 0fc343b..955e06b 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessor.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessor.kt
@@ -56,7 +56,8 @@
             return null
         } else if (entitiesInParams.isEmpty()) {
             errorReporter.reportError(
-                insertMethodHasNoEntityInParameters(), method)
+                insertMethodHasNoEntityInParameters(), method
+            )
             return null
         }
 
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessor.kt
index 105b4d8..9c69ff6 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessor.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessor.kt
@@ -61,8 +61,10 @@
         val potentialContentEntity = method.toAnnotationBox(ContentQuery::class)!!
             .getAsTypeMirror("contentEntity")!!
         val resolvedContentEntity = if (!potentialContentEntity.isVoidObject()) {
-            ContentEntityProcessor(potentialContentEntity,
-                processingEnv, errorReporter).processEntity()
+            ContentEntityProcessor(
+                potentialContentEntity,
+                processingEnv, errorReporter
+            ).processEntity()
         } else {
             contentEntity
         }
@@ -70,8 +72,10 @@
             errorReporter.reportError(missingEntityOnMethod(method.simpleName.toString()), method)
             return null
         }
-        val toBeUsedUri = determineToBeUsedUri(resolvedContentEntity, contentQueryAnnotation.uri,
-            errorReporter, method)
+        val toBeUsedUri = determineToBeUsedUri(
+            resolvedContentEntity, contentQueryAnnotation.uri,
+            errorReporter, method
+        )
         if (toBeUsedUri.isEmpty()) {
             errorReporter.reportError(missingUriOnMethod(), method)
         }
@@ -82,8 +86,11 @@
                     // Maybe it was "column desc" or "column asc", check.
                     val splitOrderBy = trimmedOrderByMember.split(" ")
                     if (splitOrderBy.size == 2 && resolvedContentEntity.columns.containsKey
-                            (splitOrderBy.get(0)) && ORDER_BY_KEYWORDS.contains(splitOrderBy
-                            .get(1))) {
+                        (splitOrderBy.get(0)) && ORDER_BY_KEYWORDS.contains(
+                                splitOrderBy
+                                    .get(1)
+                            )
+                    ) {
                         continue
                     }
                     errorReporter.reportError(badlyFormulatedOrderBy(orderByMember), method)
@@ -100,27 +107,44 @@
         val selectionVO = if (contentQueryAnnotation.selection.isEmpty()) {
             null
         } else {
-            SelectionProcessor(method, contentQueryAnnotation.selection,
-                paramsNamesAndTypes, errorReporter, resolvedContentEntity).process()
+            SelectionProcessor(
+                method, contentQueryAnnotation.selection,
+                paramsNamesAndTypes, errorReporter, resolvedContentEntity
+            ).process()
         }
         if (contentQueryAnnotation.projection.size == 1 &&
-            returnType.extractIntendedReturnType().isSupportedColumnType()) {
+            returnType.extractIntendedReturnType().isSupportedColumnType()
+        ) {
             val queriedColumn = contentQueryAnnotation.projection[0]
             if (!resolvedContentEntity.columns.containsKey(queriedColumn)) {
-                errorReporter.reportError(queriedColumnInProjectionNotInEntity(queriedColumn,
-                    resolvedContentEntity.type.toString()), method)
+                errorReporter.reportError(
+                    queriedColumnInProjectionNotInEntity(
+                        queriedColumn,
+                        resolvedContentEntity.type.toString()
+                    ),
+                    method
+                )
                 return null
             }
             val queriedColumnType = resolvedContentEntity.columns.get(queriedColumn)!!.type
             if (queriedColumnType.boxIfPrimitive(processingEnv).toString()
                 != returnType.boxIfPrimitive(processingEnv).toString() &&
-                ((!returnType.isSupportedGenericType() ||
-                    !processingEnv.typeUtils
-                        .isSameType(returnType.extractIntendedReturnType(),
-                            queriedColumnType.boxIfPrimitive(processingEnv))))) {
+                (
+                    (
+                        !returnType.isSupportedGenericType() ||
+                            !processingEnv.typeUtils
+                                .isSameType(
+                                        returnType.extractIntendedReturnType(),
+                                        queriedColumnType.boxIfPrimitive(processingEnv)
+                                    )
+                        )
+                    )
+            ) {
                 errorReporter.reportError(
-                    queriedColumnInProjectionTypeDoesntMatchReturnType(returnType.toString(),
-                        queriedColumnType.toString(), queriedColumn),
+                    queriedColumnInProjectionTypeDoesntMatchReturnType(
+                        returnType.toString(),
+                        queriedColumnType.toString(), queriedColumn
+                    ),
                     method
                 )
             }
@@ -135,7 +159,8 @@
                 returnType = returnType,
                 method = method,
                 orderBy = orderBy,
-                isSuspend = isSuspendFunction)
+                isSuspend = isSuspendFunction
+            )
         } else {
             // Either empty projection or more than one field, either way infer the return columns
             // from the return type POJO/entity.
@@ -149,7 +174,8 @@
                     uri = toBeUsedUri,
                     returnType = returnType,
                     method = method,
-                    isSuspend = isSuspendFunction)
+                    isSuspend = isSuspendFunction
+                )
             }
 
             val intendedReturnType = if (returnType.isSupportedGenericType()) {
@@ -159,27 +185,42 @@
             }
 
             if (intendedReturnType.asTypeElement()
-                    .hasMoreThanOneNonPrivateNonIgnoredConstructor()) {
+                .hasMoreThanOneNonPrivateNonIgnoredConstructor()
+            ) {
                 errorReporter.reportError(
                     pojoHasMoreThanOneQualifyingConstructor(intendedReturnType.toString()),
-                    intendedReturnType.asTypeElement())
+                    intendedReturnType.asTypeElement()
+                )
                 return null
             } else if (intendedReturnType.asTypeElement().isNotInstantiable()) {
-                errorReporter.reportError(pojoIsNotInstantiable(intendedReturnType.asTypeElement()
-                    .qualifiedName.toString()), intendedReturnType.asTypeElement())
+                errorReporter.reportError(
+                    pojoIsNotInstantiable(
+                        intendedReturnType.asTypeElement()
+                            .qualifiedName.toString()
+                    ),
+                    intendedReturnType.asTypeElement()
+                )
                 return null
             }
             val pojo = PojoProcessor(intendedReturnType).process()
             // Apply the projection (if existing) to the POJO
-            val pojoWithProjection = validateAndApplyProjectionToPojo(contentQueryAnnotation
-                .projection, pojo, returnType, resolvedContentEntity)
+            val pojoWithProjection = validateAndApplyProjectionToPojo(
+                contentQueryAnnotation
+                    .projection,
+                pojo, returnType, resolvedContentEntity
+            )
             if (errorReporter.errorReported) {
                 return null
             }
             pojoWithProjection!!.pojoFields.forEach {
                 if (it.isNullable && it.type.isPrimitive()) {
-                    errorReporter.reportError(pojoWithNullablePrimitive(it.name,
-                        pojo.type.toString()), method)
+                    errorReporter.reportError(
+                        pojoWithNullablePrimitive(
+                            it.name,
+                            pojo.type.toString()
+                        ),
+                        method
+                    )
                 }
             }
             return ContentQueryVO(
@@ -204,24 +245,35 @@
     ) {
         pojo.pojoFields.forEach { field ->
             if (!resolvedContentEntity.columns.containsKey(field.columnName) || !processingEnv
-                .typeUtils.isSameType(resolvedContentEntity.columns.get(field.columnName)!!
-                    .type.boxIfPrimitive(processingEnv),
-                    field.type.boxIfPrimitive(processingEnv)
-                )) {
-                errorReporter.reportError(pojoFieldNotInEntity(field.name, field.type.toString(),
-                    field.columnName, pojo.type.toString(), resolvedContentEntity.type.toString()),
-                    method)
+                .typeUtils.isSameType(
+                        resolvedContentEntity.columns.get(field.columnName)!!
+                            .type.boxIfPrimitive(processingEnv),
+                        field.type.boxIfPrimitive(processingEnv)
+                    )
+            ) {
+                errorReporter.reportError(
+                    pojoFieldNotInEntity(
+                        field.name, field.type.toString(),
+                        field.columnName, pojo.type.toString(),
+                        resolvedContentEntity.type.toString()
+                    ),
+                    method
+                )
             } else {
                 if (resolvedContentEntity.columns.get(field.columnName)!!.isNullable &&
-                    !field.isNullable) {
+                    !field.isNullable
+                ) {
                     // TODO(obenabde): clarify how to mark as nullable, i.e "?" for Kotlin and
                     // @androidx.annotations.Nullable for Java.
-                    errorReporter.reportError(nullableEntityColumnNotNullableInPojo(
-                        field.name,
-                        field.type.toString(),
-                        field.columnName,
-                        resolvedContentEntity.type.toString()
-                    ), method)
+                    errorReporter.reportError(
+                        nullableEntityColumnNotNullableInPojo(
+                            field.name,
+                            field.type.toString(),
+                            field.columnName,
+                            resolvedContentEntity.type.toString()
+                        ),
+                        method
+                    )
                 }
             }
         }
@@ -243,17 +295,28 @@
         for (column in projection) {
             if (!extractedColumnNames.containsKey(column)) {
                 errorFound = true
-                errorReporter.reportError(columnInProjectionNotIncludedInReturnPojo(column,
-                    pojo.type.toString()), method)
+                errorReporter.reportError(
+                    columnInProjectionNotIncludedInReturnPojo(
+                        column,
+                        pojo.type.toString()
+                    ),
+                    method
+                )
             }
         }
         for (pojoField in pojo.pojoFields) {
             if (!projection.contains(pojoField.columnName) && !pojoField.isNullable &&
-                pojo.type.asTypeElement().isFilledThroughConstructor()) {
+                pojo.type.asTypeElement().isFilledThroughConstructor()
+            ) {
                 errorFound = true
                 errorReporter.reportError(
-                    constructorFieldNotIncludedInProjectionNotNullable(pojoField.name, returnType
-                        .extractIntendedReturnType().toString()), method)
+                    constructorFieldNotIncludedInProjectionNotNullable(
+                        pojoField.name,
+                        returnType
+                            .extractIntendedReturnType().toString()
+                    ),
+                    method
+                )
             }
         }
         if (errorFound) {
@@ -287,15 +350,18 @@
         errorReporter.reportError(columnOnlyAsUri(), method)
         return uriInAnnotation
     } else if (!method.parameters.map { it.simpleName.toString() }.contains
-            (specifiedParamName)) {
+        (specifiedParamName)
+    ) {
         errorReporter.reportError(missingUriParameter(specifiedParamName), method)
         return uriInAnnotation
     } else if (!method.parameters.filter {
-            it.simpleName.toString().equals(specifiedParamName) }[0].asType().isString()) {
+        it.simpleName.toString().equals(specifiedParamName)
+    }[0].asType().isString()
+    ) {
         errorReporter.reportError(uriParameterIsNotString(specifiedParamName), method)
         return uriInAnnotation
     }
     return uriInAnnotation
 }
 
-internal val ORDER_BY_KEYWORDS = listOf("asc", "desc")
\ No newline at end of file
+internal val ORDER_BY_KEYWORDS = listOf("asc", "desc")
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessor.kt
index 7172823..1a46f41 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessor.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessor.kt
@@ -53,8 +53,10 @@
         val potentialContentEntity = method.toAnnotationBox(ContentUpdate::class)!!
             .getAsTypeMirror("contentEntity")!!
         val resolvedContentEntity = if (!potentialContentEntity.isVoidObject()) {
-            ContentEntityProcessor(potentialContentEntity,
-                processingEnv, errorReporter).processEntity()
+            ContentEntityProcessor(
+                potentialContentEntity,
+                processingEnv, errorReporter
+            ).processEntity()
         } else {
             contentEntity
         }
@@ -62,8 +64,10 @@
             errorReporter.reportError(missingEntityOnMethod(method.simpleName.toString()), method)
             return null
         }
-        val toBeUsedUri = determineToBeUsedUri(resolvedContentEntity, contentUpdateAnnotation.uri,
-            errorReporter, method)
+        val toBeUsedUri = determineToBeUsedUri(
+            resolvedContentEntity, contentUpdateAnnotation.uri,
+            errorReporter, method
+        )
         if (toBeUsedUri.isEmpty()) {
             errorReporter.reportError(missingUriOnMethod(), method)
         }
@@ -82,22 +86,27 @@
             //  happen atomically. Anyhow it would be easier to do the other way through
             //  parameters annotated with @ContentColumn. Explore this further later on, although I
             //  doubt we need to worry about this so much for the updates
-            errorReporter.reportError(updatingMultipleEntitiesAtTheSameType
+            errorReporter.reportError(
+                updatingMultipleEntitiesAtTheSameType
                 (resolvedContentEntity.type.toString(), method.simpleName.toString()),
-                method)
+                method
+            )
             return null
         }
         if (entitiesInParams.size == 1) {
             // Assume the user wants to update a single entity
             if (contentUpdateAnnotation.where.isNotEmpty()) {
-                errorReporter.reportError(methodSpecifiesWhereClauseWhenUpdatingUsingEntity
-                    (entitiesInParams.first().toString()), method)
+                errorReporter.reportError(
+                    methodSpecifiesWhereClauseWhenUpdatingUsingEntity
+                    (entitiesInParams.first().toString()),
+                    method
+                )
                 return null
             }
             val primaryKeyColumnName = resolvedContentEntity.primaryKeyColumn.columnName
             val primaryKeyVariableName = resolvedContentEntity.primaryKeyColumn.name
             val whereClause = "$primaryKeyColumnName = \${${entitiesInParams.first()}" +
-                    ".$primaryKeyVariableName}"
+                ".$primaryKeyVariableName}"
             val updateList = mutableListOf<Pair<String, String>>()
             for (entityColumn in resolvedContentEntity.columns.values) {
                 if (entityColumn.columnName != primaryKeyColumnName) {
@@ -124,8 +133,10 @@
         val selectionVO = if (contentUpdateAnnotation.where.isEmpty()) {
             null
         } else {
-            SelectionProcessor(method, contentUpdateAnnotation.where,
-                paramsNamesAndTypes, errorReporter, resolvedContentEntity).process()
+            SelectionProcessor(
+                method, contentUpdateAnnotation.where,
+                paramsNamesAndTypes, errorReporter, resolvedContentEntity
+            ).process()
         }
         val contentValues = mutableListOf<Pair<String, String>>()
         var foundContentColumnAnnotatedParameters = false
@@ -134,22 +145,37 @@
                 foundContentColumnAnnotatedParameters = true
                 val columnName = param.getAnnotation(ContentColumn::class.java).columnName
                 if (!resolvedContentEntity.columns.containsKey(columnName)) {
-                    errorReporter.reportError(columnInContentUpdateParametersNotInEntity(
-                        param.simpleName.toString(), columnName,
-                            resolvedContentEntity.type.toString()), method)
-                } else if (param.asType().boxIfPrimitive(processingEnv) != resolvedContentEntity
-                        .columns.get(columnName)!!.type.boxIfPrimitive(processingEnv)) {
                     errorReporter.reportError(
-                        mismatchedColumnTypeForColumnToBeUpdated(param.simpleName.toString(),
-                            columnName, param.asType().toString(), resolvedContentEntity.type
-                                .toString(), resolvedContentEntity.columns.get(columnName)!!.type
-                                .toString()),
-                        method)
+                        columnInContentUpdateParametersNotInEntity(
+                            param.simpleName.toString(), columnName,
+                            resolvedContentEntity.type.toString()
+                        ),
+                        method
+                    )
+                } else if (param.asType().boxIfPrimitive(processingEnv) != resolvedContentEntity
+                    .columns.get(columnName)!!.type.boxIfPrimitive(processingEnv)
+                ) {
+                    errorReporter.reportError(
+                        mismatchedColumnTypeForColumnToBeUpdated(
+                            param.simpleName.toString(),
+                            columnName, param.asType().toString(),
+                            resolvedContentEntity.type
+                                .toString(),
+                            resolvedContentEntity.columns.get(columnName)!!.type
+                                .toString()
+                        ),
+                        method
+                    )
                 } else if (fieldIsNullable(param) && !resolvedContentEntity
-                        .columns.get(columnName)!!.isNullable) {
-                    errorReporter.reportError(nullableUpdateParamForNonNullableEntityColumn(
-                        param.simpleName.toString(), columnName,
-                        resolvedContentEntity.type.toString()), method)
+                    .columns.get(columnName)!!.isNullable
+                ) {
+                    errorReporter.reportError(
+                        nullableUpdateParamForNonNullableEntityColumn(
+                            param.simpleName.toString(), columnName,
+                            resolvedContentEntity.type.toString()
+                        ),
+                        method
+                    )
                 } else {
                     contentValues.add(Pair(columnName, param.simpleName.toString()))
                 }
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/Errors.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/Errors.kt
index 8b6d56e..72220ae 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/Errors.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/Errors.kt
@@ -22,78 +22,78 @@
 
 fun missingEntityPrimaryKeyErrorMessage(entityName: String): String {
     return "Content entity $entityName doesn't have a primary key, a content entity must have one" +
-            " field annotated with @ContentPrimaryKey."
+        " field annotated with @ContentPrimaryKey."
 }
 
 fun missingFieldsInContentEntityErrorMessage(entityName: String): String {
     return "Content entity $entityName has no fields, a content entity must have at least one " +
-            "field and exactly one primary key."
+        "field and exactly one primary key."
 }
 
 fun missingAnnotationOnEntityFieldErrorMessage(fieldName: String, entityName: String): String {
     return "Field $fieldName in $entityName is neither annotated with @ContentPrimaryKey nor " +
-            "with @ContentColumn, all fields in a content entity must be be annotated by one of " +
-            "the two"
+        "with @ContentColumn, all fields in a content entity must be be annotated by one of " +
+        "the two"
 }
 
 fun entityFieldWithBothAnnotations(columnName: String, entityName: String): String {
     return "Field $columnName in $entityName is annotated with both @ContentPrimaryKey and " +
-            "@ContentColumn, these annotations are mutually exclusive and  a field " +
-            "can only be annotated by one of the two."
+        "@ContentColumn, these annotations are mutually exclusive and  a field " +
+        "can only be annotated by one of the two."
 }
 
 fun entityWithMultiplePrimaryKeys(entityName: String): String {
     return "Content entity $entityName has two or more " +
-            "primary keys, a content entity must have exactly one field annotated with " +
-            "@ContentPrimaryKey."
+        "primary keys, a content entity must have exactly one field annotated with " +
+        "@ContentPrimaryKey."
 }
 
 fun unsupportedColumnType(columnName: String, entityName: String, type: String): String {
     return "Field $columnName in $entityName is of type " +
-            "$type which is not a supported column type."
+        "$type which is not a supported column type."
 }
 
 fun nonInstantiableEntity(entityName: String): String {
     return "Entity $entityName is not instantiable. It has no non private non ignored " +
-            "constructors, it must have one and only one such constructor, whether parametrized " +
-            "or not."
+        "constructors, it must have one and only one such constructor, whether parametrized " +
+        "or not."
 }
 
 fun entityWithMultipleConstructors(entityName: String): String {
     return "Entity $entityName has more than one non private non ignored constructor. Entities " +
-            "should have only one non private non ignored constructor."
+        "should have only one non private non ignored constructor."
 }
 
 fun entityWithNullablePrimitiveType(fieldName: String, entityName: String): String {
     return "Field $fieldName of entity $entityName is of a primitive type but is marked as " +
-            "nullable. Please use the boxed type instead of the primitive of type for nullable " +
-            "fields"
+        "nullable. Please use the boxed type instead of the primitive of type for nullable " +
+        "fields"
 }
 
 fun missingEntityOnMethod(methodName: String): String {
     return "Method $methodName has no associated entity, " +
-            "please ensure that either the content access object containing the method " +
-            "specifies an entity inside the @ContentAccessObject annotation or that the " +
-            "method specifies a content entity through the contentEntity parameter of " +
-            "the annotation."
+        "please ensure that either the content access object containing the method " +
+        "specifies an entity inside the @ContentAccessObject annotation or that the " +
+        "method specifies a content entity through the contentEntity parameter of " +
+        "the annotation."
 }
 
 fun missingUriOnMethod(): String {
     return "Failed to determine URI for query, the " +
-            "URI is neither specified in the associated ContentEntity, nor in the annotation " +
-            "parameters."
+        "URI is neither specified in the associated ContentEntity, nor in the annotation " +
+        "parameters."
 }
 
 fun badlyFormulatedOrderBy(orderByMember: String): String {
     return "orderBy member \"$orderByMember\" is either not " +
-            "properly formulated or references columns that are not in the " +
-            "associated entity. All members in the orderBy array should either be" +
-            " a column name or a column name following by \"asc\" or \"desc\""
+        "properly formulated or references columns that are not in the " +
+        "associated entity. All members in the orderBy array should either be" +
+        " a column name or a column name following by \"asc\" or \"desc\""
 }
 
 fun queriedColumnInProjectionNotInEntity(queriedColumn: String, entity: String): String {
     return "Column $queriedColumn being queried through the projection is not defined within the " +
-            "specified entity $entity."
+        "specified entity $entity."
 }
 
 fun queriedColumnInProjectionTypeDoesntMatchReturnType(
@@ -102,24 +102,24 @@
     queriedColumn: String
 ): String {
     return "Return type $returnType does not match type" +
-            " $queriedColumnType of column $queriedColumn being queried."
+        " $queriedColumnType of column $queriedColumn being queried."
 }
 
 fun pojoHasMoreThanOneQualifyingConstructor(pojo: String): String {
     return "Pojo $pojo has more than one non private" +
-            " constructor. Pojos should have only one non private constructor."
+        " constructor. Pojos should have only one non private constructor."
 }
 
 fun pojoIsNotInstantiable(pojo: String): String {
     return "Pojo $pojo is not instantiable! It has no non private non ignored " +
-            "constructors, it must have one and only one such constructor, whether " +
-            "parametrized or not."
+        "constructors, it must have one and only one such constructor, whether " +
+        "parametrized or not."
 }
 
 fun pojoWithNullablePrimitive(fieldName: String, pojo: String): String {
     return "Field $fieldName of pojo $pojo is of a primitive type but is marked as " +
-            "nullable. Please use the boxed type instead of the primitive of type for nullable " +
-            "fields"
+        "nullable. Please use the boxed type instead of the primitive of type for nullable " +
+        "fields"
 }
 
 fun pojoFieldNotInEntity(
@@ -130,21 +130,22 @@
     entity: String
 ): String {
     return "Field $fieldName of type $fieldType corresponding to content" +
-            " provider column $columnName in object $pojo doesn't match a field with same " +
-            "type and content column in content entity $entity"
+        " provider column $columnName in object $pojo doesn't match a field with same " +
+        "type and content column in content entity $entity"
 }
 
 fun constructorFieldNotIncludedInProjectionNotNullable(fieldName: String, returnType: String):
-        String {
-    return "Field $fieldName in return object constructor $returnType is not included in the" +
+    String {
+        return "Field $fieldName in return object constructor $returnType is not included in the" +
             " supplied projection and is not nullable. Constructor fields that are not" +
             " included in a query projection should all be nullable."
-}
+    }
 
 fun columnInProjectionNotIncludedInReturnPojo(columnName: String, returnType: String):
-        String {
-    return "Column $columnName in projection array isn't included in the return type $returnType"
-}
+    String {
+        return "Column $columnName in projection array isn't included in " +
+            "the return type $returnType"
+    }
 
 fun nullableEntityColumnNotNullableInPojo(
     fieldName: String,
@@ -153,15 +154,15 @@
     entity: String
 ): String {
     return "Field $fieldName of type $fieldType corresponding to content provider column " +
-    "$columnName is not nullable, however that column is declared as nullable in the " +
-            "associated entity $entity. Please mark the field as nullable."
+        "$columnName is not nullable, however that column is declared as nullable in the " +
+        "associated entity $entity. Please mark the field as nullable."
 }
 
 fun columnOnlyAsUri(): String = ": is an invalid uri, please follow it up with the parameter name"
 
 fun missingUriParameter(parameterName: String): String {
     return "Parameter $parameterName mentioned as the uri does not exist! Please add it to " +
-            "the method parameters"
+        "the method parameters"
 }
 
 fun uriParameterIsNotString(parameterName: String): String {
@@ -176,7 +177,7 @@
 
 fun columnInSelectionMissingFromEntity(columnName: String, entity: String): String {
     return "Column $columnName in selection/where parameter" +
-            " does not exist in content entity $entity"
+        " does not exist in content entity $entity"
 }
 
 fun columnInContentUpdateParametersNotInEntity(
@@ -185,33 +186,33 @@
     entity: String
 ): String {
     return "Parameter $paramName is annotated with @ContentColumn and specifies that it should " +
-            "update column $columnName, however that column was not found in content entity $entity"
+        "update column $columnName, however that column was not found in content entity $entity"
 }
 
 fun mismatchedColumnTypeForColumnToBeUpdated(
     paramName: String,
     columnName: String,
     paramType:
-    String,
+        String,
     entityType: String,
     columnType: String
 ): String {
     return "Parameter $paramName linked to column " +
-            "$columnName is of type $paramType however that column's type " +
-            "as specified by entity $entityType is $columnType"
+        "$columnName is of type $paramType however that column's type " +
+        "as specified by entity $entityType is $columnType"
 }
 
 fun methodSpecifiesWhereClauseWhenUpdatingUsingEntity(paramName: String): String {
     return "@ContentUpdate annotated method specifies an entity as" +
-            " parameter $paramName but also specifies a where clause. " +
-            "Updates using an entity happen by matching the primary key and do not " +
-            "take into consideration the where clause."
+        " parameter $paramName but also specifies a where clause. " +
+        "Updates using an entity happen by matching the primary key and do not " +
+        "take into consideration the where clause."
 }
 
 fun updatingMultipleEntitiesAtTheSameType(entityType: String, methodName: String): String {
     return "There is more than one parameter of the entity type " +
-            "$entityType to the @ContentUpdate annotated method" +
-            " $methodName. Only one entity can be update at a time."
+        "$entityType to the @ContentUpdate annotated method" +
+        " $methodName. Only one entity can be update at a time."
 }
 
 fun contentUpdateAnnotatedMethodNotReturningAnInteger(): String {
@@ -228,23 +229,23 @@
 
 fun insertMethodHasMoreThanOneEntity(): String {
     return "@ContentInsert annotated method has more than one content entity in its parameters." +
-            " @ContentInsert annotated methods parameters should include one and only one " +
-            "content entity parameter (@ContentEntity annotated object)."
+        " @ContentInsert annotated methods parameters should include one and only one " +
+        "content entity parameter (@ContentEntity annotated object)."
 }
 
 fun insertMethodHasNoEntityInParameters(): String {
     return "@ContentInsert annotated method has no entity parameters. @ContentInsert annotated " +
-            "methods parameters should include one and only one content entity parameter " +
-            "(@ContentEntity annotated object)."
+        "methods parameters should include one and only one content entity parameter " +
+        "(@ContentEntity annotated object)."
 }
 
 fun unsureWhatToUpdate(): String {
     return "Not sure what this @ContentUpdate annotated method is supposed" +
-            " to update, @ContentUpdate annotated methods should either specify a parameter " +
-            "of the entity's type which will update the existing row in the content provider " +
-            "using info from the entity object and will match on the primary key, or specify " +
-            "one or more parameters annotated with @ContentColumn which will result in updating" +
-            " rows matching any given criteria in the where clause to the specified values"
+        " to update, @ContentUpdate annotated methods should either specify a parameter " +
+        "of the entity's type which will update the existing row in the content provider " +
+        "using info from the entity object and will match on the primary key, or specify " +
+        "one or more parameters annotated with @ContentColumn which will result in updating" +
+        " rows matching any given criteria in the where clause to the specified values"
 }
 
 fun nullableUpdateParamForNonNullableEntityColumn(
@@ -253,10 +254,10 @@
     entity: String
 ): String {
     return "Parameter $paramName corresponding content column $columnName is nullable, however " +
-            "that column is specified as non nullable in entity $entity. Please ensure that " +
-            "parameter $paramName is non nullable too."
+        "that column is specified as non nullable in entity $entity. Please ensure that " +
+        "parameter $paramName is non nullable too."
 }
 
 fun ProcessingEnvironment.warn(warning: String, element: Element) {
     this.messager.printMessage(Diagnostic.Kind.WARNING, warning, element)
-}
\ No newline at end of file
+}
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessor.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessor.kt
index ef47c95..7e440f1 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessor.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessor.kt
@@ -43,18 +43,21 @@
         val selectionsArgs = ArrayList<String>()
         val wordsStartingWithColumn = findWordsStartingWithColumn(selection)
         for (wordStartingWithColumn in wordsStartingWithColumn) {
-                if (wordStartingWithColumn.length == 1) {
-                    errorReporter.reportError(strayColumnInSelectionErrorMessage(), method)
-                    return null
-                }
-                val strippedParamName = wordStartingWithColumn.substring(1)
-                if (!paramsNamesAndTypes.containsKey(strippedParamName)) {
-                    errorReporter.reportError(selectionParameterNotInMethodParameters
-                        (strippedParamName), method)
-                    return null
-                }
-                selectionsArgs.add(strippedParamName)
-                modifiedSelection = modifiedSelection.replaceFirst(wordStartingWithColumn, "?")
+            if (wordStartingWithColumn.length == 1) {
+                errorReporter.reportError(strayColumnInSelectionErrorMessage(), method)
+                return null
+            }
+            val strippedParamName = wordStartingWithColumn.substring(1)
+            if (!paramsNamesAndTypes.containsKey(strippedParamName)) {
+                errorReporter.reportError(
+                    selectionParameterNotInMethodParameters
+                    (strippedParamName),
+                    method
+                )
+                return null
+            }
+            selectionsArgs.add(strippedParamName)
+            modifiedSelection = modifiedSelection.replaceFirst(wordStartingWithColumn, "?")
         }
         val selectionExpression = CCJSqlParserUtil.parseCondExpression(modifiedSelection)
         var foundMissingColumn = false
@@ -66,8 +69,13 @@
                 // around this for now.
                 if (!columnString.startsWith('"') || !columnString.endsWith('"')) {
                     if (!resolvedContentEntity.columns.contains(columnString)) {
-                        errorReporter.reportError(columnInSelectionMissingFromEntity(columnString,
-                                resolvedContentEntity.type.toString()), method)
+                        errorReporter.reportError(
+                            columnInSelectionMissingFromEntity(
+                                columnString,
+                                resolvedContentEntity.type.toString()
+                            ),
+                            method
+                        )
                         foundMissingColumn = true
                     }
                 }
@@ -87,7 +95,8 @@
         if (expression[currIndex] == ':') {
             val startingIndex = currIndex
             while (currIndex + 1 < expression.length && expression[currIndex + 1]
-                    .isLetterOrDigit()) {
+                .isLetterOrDigit()
+            ) {
                 currIndex++
             }
             wordsStartingWithColumn.add(expression.substring(startingIndex, currIndex + 1))
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/ErrorReporter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/ErrorReporter.kt
index 2504f3c..96ece18 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/ErrorReporter.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/ErrorReporter.kt
@@ -27,6 +27,7 @@
     fun reportError(error: String, element: Element) {
         errorReported = true
         messager.printMessage(
-            Diagnostic.Kind.ERROR, error, element)
+            Diagnostic.Kind.ERROR, error, element
+        )
     }
 }
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/JvmSignatureUtil.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/JvmSignatureUtil.kt
index 182eb78..228e596 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/JvmSignatureUtil.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/utils/JvmSignatureUtil.kt
@@ -261,10 +261,13 @@
                         val typeElement =
                             MoreElements.asType(element)
                         return when (typeElement.getNestingKind()) {
-                            NestingKind.TOP_LEVEL -> typeElement.getQualifiedName()
-                                .toString().replace('.', '/')
-                            NestingKind.MEMBER -> getInternalName(typeElement.getEnclosingElement
-                                ()) + "$" + typeElement.getSimpleName()
+                            NestingKind.TOP_LEVEL ->
+                                typeElement.getQualifiedName()
+                                    .toString().replace('.', '/')
+                            NestingKind.MEMBER -> getInternalName(
+                                typeElement.getEnclosingElement
+                                ()
+                            ) + "$" + typeElement.getSimpleName()
                             else -> throw IllegalArgumentException("Unsupported nesting kind.")
                         }
                     } catch (e: IllegalArgumentException) {
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentAccessObjectWriter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentAccessObjectWriter.kt
index a6097e0..5f4b88d 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentAccessObjectWriter.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentAccessObjectWriter.kt
@@ -38,22 +38,36 @@
         val generatedClassName =
             "${contentAccessObject.interfaceName.removePrefix(contentAccessObject.packageName)
                 .replace(".", "_")}Impl"
-        val fileSpecBuilder = FileSpec.builder(contentAccessObject.packageName,
-            generatedClassName)
+        val fileSpecBuilder = FileSpec.builder(
+            contentAccessObject.packageName,
+            generatedClassName
+        )
         val contentResolverTypePlaceholder = ClassName("android.content", "ContentResolver")
-        val coroutineDispatcherTypePlaceholder = ClassName("kotlinx.coroutines",
-            "CoroutineDispatcher")
+        val coroutineDispatcherTypePlaceholder = ClassName(
+            "kotlinx.coroutines",
+            "CoroutineDispatcher"
+        )
         val generatedClassBuilder = TypeSpec.classBuilder(generatedClassName)
             .addSuperinterface(ClassName.bestGuess(contentAccessObject.interfaceName))
-            .primaryConstructor(FunSpec.constructorBuilder()
-                .addParameter("contentResolver", contentResolverTypePlaceholder)
-                .addParameter("coroutineDispatcher", coroutineDispatcherTypePlaceholder)
-                .build())
-            .addProperty(PropertySpec.builder("_contentResolver",
-                contentResolverTypePlaceholder).initializer("contentResolver").build())
-            .addProperty(PropertySpec.builder("_coroutineDispatcher",
-                coroutineDispatcherTypePlaceholder)
-                .initializer("coroutineDispatcher").build())
+            .primaryConstructor(
+                FunSpec.constructorBuilder()
+                    .addParameter("contentResolver", contentResolverTypePlaceholder)
+                    .addParameter("coroutineDispatcher", coroutineDispatcherTypePlaceholder)
+                    .build()
+            )
+            .addProperty(
+                PropertySpec.builder(
+                    "_contentResolver",
+                    contentResolverTypePlaceholder
+                ).initializer("contentResolver").build()
+            )
+            .addProperty(
+                PropertySpec.builder(
+                    "_coroutineDispatcher",
+                    coroutineDispatcherTypePlaceholder
+                )
+                    .initializer("coroutineDispatcher").build()
+            )
 
         for (contentQuery in contentAccessObject.queries) {
             generatedClassBuilder.addFunction(
@@ -82,18 +96,20 @@
             )
         }
 
-        val accessorFile = fileSpecBuilder.addType(generatedClassBuilder.addOriginatingElement
-            (contentAccessObject.interfaceElement).build()).build()
+        val accessorFile = fileSpecBuilder.addType(
+            generatedClassBuilder.addOriginatingElement
+            (contentAccessObject.interfaceElement).build()
+        ).build()
         accessorFile.writeTo(processingEnv.filer)
     }
 }
 
 @KotlinPoetMetadataPreview
 fun funSpecOverriding(element: ExecutableElement, processingEnv: ProcessingEnvironment):
-        FunSpec.Builder {
-    val builder = element.getKotlinFunspec(processingEnv).toBuilder()
-    builder.modifiers.remove(KModifier.ABSTRACT)
-    builder.annotations.removeAll { true }
-    builder.addModifiers(KModifier.OVERRIDE)
-    return builder
-}
\ No newline at end of file
+    FunSpec.Builder {
+        val builder = element.getKotlinFunspec(processingEnv).toBuilder()
+        builder.modifiers.remove(KModifier.ABSTRACT)
+        builder.annotations.removeAll { true }
+        builder.addModifiers(KModifier.OVERRIDE)
+        return builder
+    }
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentInsertMethodWriter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentInsertMethodWriter.kt
index 35b35ad..4ccdaa9 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentInsertMethodWriter.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentInsertMethodWriter.kt
@@ -36,7 +36,8 @@
     fun createContentDeleteMethod(): FunSpec {
         val methodBuilder = funSpecOverriding(contentInsert.method, processingEnv)
         methodBuilder.annotations.add(
-            AnnotationSpec.builder(Suppress::class).addMember("%S", "DEPRECATION").build())
+            AnnotationSpec.builder(Suppress::class).addMember("%S", "DEPRECATION").build()
+        )
         if (contentInsert.isSuspend) {
             val withContext = MemberName("kotlinx.coroutines", "withContext")
             methodBuilder.beginControlFlow("return %M(_coroutineDispatcher)", withContext)
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentQueryMethodWriter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentQueryMethodWriter.kt
index 6793175..031bb0d 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentQueryMethodWriter.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentQueryMethodWriter.kt
@@ -51,9 +51,13 @@
     fun createContentQueryMethod(): FunSpec? {
         val uriTypePlaceHolder = ClassName("android.net", "Uri")
         val methodBuilder = funSpecOverriding(contentQuery.method, processingEnv)
-        methodBuilder.annotations.add(AnnotationSpec.builder(Suppress::class).addMember
-            ("%S", "USELESS_CAST").addMember("%S", "UNCHECKED_CAST").addMember("%S",
-            "PLATFORM_CLASS_MAPPED_TO_KOTLIN").addMember("%S", "DEPRECATION").build())
+        methodBuilder.annotations.add(
+            AnnotationSpec.builder(Suppress::class).addMember
+            ("%S", "USELESS_CAST").addMember("%S", "UNCHECKED_CAST").addMember(
+                "%S",
+                "PLATFORM_CLASS_MAPPED_TO_KOTLIN"
+            ).addMember("%S", "DEPRECATION").build()
+        )
         if (contentQuery.isSuspend) {
             val withContext = MemberName("kotlinx.coroutines", "withContext")
             methodBuilder.beginControlFlow(
@@ -62,17 +66,23 @@
             )
         }
         if (contentQuery.uri.startsWith(":")) {
-            methodBuilder.addStatement("val _uri = %T.parse(%L)", uriTypePlaceHolder.copy(),
-                contentQuery.uri.removePrefix(":"))
+            methodBuilder.addStatement(
+                "val _uri = %T.parse(%L)", uriTypePlaceHolder.copy(),
+                contentQuery.uri.removePrefix(":")
+            )
         } else {
-            methodBuilder.addStatement("val _uri = %T.parse(%S)", uriTypePlaceHolder.copy(),
-                contentQuery.uri)
+            methodBuilder.addStatement(
+                "val _uri = %T.parse(%S)", uriTypePlaceHolder.copy(),
+                contentQuery.uri
+            )
         }
         methodBuilder.addStatement("val _projectionList = mutableListOf<String>()")
         for (column in contentQuery.toQueryFor) {
             if (column.requiresApi != null) {
-                methodBuilder.beginControlFlow("if (%T.VERSION.SDK_INT >= ${column.requiresApi})",
-                    buildClassPlaceHolder)
+                methodBuilder.beginControlFlow(
+                    "if (%T.VERSION.SDK_INT >= ${column.requiresApi})",
+                    buildClassPlaceHolder
+                )
                 methodBuilder.addStatement("_projectionList.add(%S)", column.columnName)
                 methodBuilder.endControlFlow()
             } else {
@@ -96,8 +106,10 @@
         } else {
             methodBuilder.addStatement("val _selection = \"\"")
         }
-        callResolverAndFormulateReturn(methodBuilder, contentQuery.returnType,
-            noSelectionArgs)
+        callResolverAndFormulateReturn(
+            methodBuilder, contentQuery.returnType,
+            noSelectionArgs
+        )
 
         if (contentQuery.isSuspend) {
             methodBuilder.endControlFlow()
@@ -110,25 +122,36 @@
         returnType: TypeMirror,
         noSelectionArgs: Boolean
     ) {
-        methodBuilder.addStatement("val _cursor = _contentResolver.query(_uri, _projection, " +
+        methodBuilder.addStatement(
+            "val _cursor = _contentResolver.query(_uri, _projection, " +
                 "_selection, ${if (noSelectionArgs) "null" else "_selectionArgs"}, %S)",
-            contentQuery.orderBy)
+            contentQuery.orderBy
+        )
         methodBuilder.beginControlFlow("if (_cursor == null)")
-        methodBuilder.addStatement("throw NullPointerException(%S)", "Cursor returned by the " +
-                "content provider was null!")
+        methodBuilder.addStatement(
+            "throw NullPointerException(%S)",
+            "Cursor returned by the " +
+                "content provider was null!"
+        )
         methodBuilder.endControlFlow()
         if (returnType.isSupportedGenericType()) {
             val realReturnType = returnType.extractIntendedReturnType()
             val returnTypeInKotlin = methodBuilder.build().returnType.toString()
             if (returnType.isOptional()) {
-                populateAndReturnOptionalFromCursor(methodBuilder, realReturnType,
-                    checkIfTypeArgumentIsNullable(returnTypeInKotlin))
+                populateAndReturnOptionalFromCursor(
+                    methodBuilder, realReturnType,
+                    checkIfTypeArgumentIsNullable(returnTypeInKotlin)
+                )
             } else if (returnType.isList()) {
-                populateAndReturnListFromCursor(methodBuilder, realReturnType,
-                    checkIfTypeArgumentIsNullable(returnTypeInKotlin))
+                populateAndReturnListFromCursor(
+                    methodBuilder, realReturnType,
+                    checkIfTypeArgumentIsNullable(returnTypeInKotlin)
+                )
             } else if (returnType.isSet()) {
-                populateAndReturnSetFromCursor(methodBuilder, realReturnType,
-                    checkIfTypeArgumentIsNullable(returnTypeInKotlin))
+                populateAndReturnSetFromCursor(
+                    methodBuilder, realReturnType,
+                    checkIfTypeArgumentIsNullable(returnTypeInKotlin)
+                )
             }
         } else {
             returnNonPojoTypeFromCursor(methodBuilder, returnType)
@@ -140,9 +163,13 @@
         realReturnType: TypeMirror,
         typeArgumentIsNullable: Boolean
     ) {
-        methodBuilder.addStatement("val _returnList = %T()",
-            ClassName("kotlin.collections", "ArrayList").parameterizedBy(realReturnType
-                .toKotlinClassName().copy(typeArgumentIsNullable)))
+        methodBuilder.addStatement(
+            "val _returnList = %T()",
+            ClassName("kotlin.collections", "ArrayList").parameterizedBy(
+                realReturnType
+                    .toKotlinClassName().copy(typeArgumentIsNullable)
+            )
+        )
         methodBuilder.beginControlFlow("while (_cursor.moveToNext())")
         createReturnTypeFromCursor(realReturnType, methodBuilder, contentQuery.toQueryFor)
         // Check !realReturnType.isSupportedColumnType() because POJOs cannot be null, their
@@ -150,19 +177,25 @@
         // type is a supported cursor type (long, int, String etc...) Same goes for other
         // collections.
         if (typeArgumentIsNullable || !realReturnType.isSupportedColumnType()) {
-            methodBuilder.addStatement("_returnList.add($RETURN_OBJECT_NAME as %T)",
+            methodBuilder.addStatement(
+                "_returnList.add($RETURN_OBJECT_NAME as %T)",
                 realReturnType
-                    .toKotlinClassName())
+                    .toKotlinClassName()
+            )
         } else {
             methodBuilder.beginControlFlow("if ($RETURN_OBJECT_NAME != null)")
-            methodBuilder.addStatement("_returnList.add($RETURN_OBJECT_NAME as %T)",
+            methodBuilder.addStatement(
+                "_returnList.add($RETURN_OBJECT_NAME as %T)",
                 realReturnType
-                    .toKotlinClassName())
+                    .toKotlinClassName()
+            )
             methodBuilder.endControlFlow()
         }
         methodBuilder.endControlFlow()
-        methodBuilder.addStatement("$returnOrSet _returnList.toList() as ${methodBuilder.build()
-            .returnType}")
+        methodBuilder.addStatement(
+            "$returnOrSet _returnList.toList() as ${methodBuilder.build()
+                .returnType}"
+        )
     }
 
     fun populateAndReturnSetFromCursor(
@@ -170,24 +203,34 @@
         realReturnType: TypeMirror,
         typeArgumentIsNullable: Boolean
     ) {
-        methodBuilder.addStatement("val _returnSet = %T()",
-            ClassName("kotlin.collections", "HashSet").parameterizedBy(realReturnType
-                .toKotlinClassName().copy(typeArgumentIsNullable)).copy())
+        methodBuilder.addStatement(
+            "val _returnSet = %T()",
+            ClassName("kotlin.collections", "HashSet").parameterizedBy(
+                realReturnType
+                    .toKotlinClassName().copy(typeArgumentIsNullable)
+            ).copy()
+        )
         methodBuilder.beginControlFlow("while (_cursor.moveToNext())")
         createReturnTypeFromCursor(realReturnType, methodBuilder, contentQuery.toQueryFor)
         if (typeArgumentIsNullable || !realReturnType.isSupportedColumnType()) {
-            methodBuilder.addStatement("_returnSet.add($RETURN_OBJECT_NAME as %T)",
-                realReturnType.toKotlinClassName())
+            methodBuilder.addStatement(
+                "_returnSet.add($RETURN_OBJECT_NAME as %T)",
+                realReturnType.toKotlinClassName()
+            )
         } else {
             methodBuilder.beginControlFlow("if ($RETURN_OBJECT_NAME != null)")
-            methodBuilder.addStatement("_returnSet.add($RETURN_OBJECT_NAME as %T)",
-                realReturnType.toKotlinClassName())
+            methodBuilder.addStatement(
+                "_returnSet.add($RETURN_OBJECT_NAME as %T)",
+                realReturnType.toKotlinClassName()
+            )
             methodBuilder.endControlFlow()
         }
 
         methodBuilder.endControlFlow()
-        methodBuilder.addStatement("$returnOrSet _returnSet.toSet() as ${methodBuilder.build()
-            .returnType}")
+        methodBuilder.addStatement(
+            "$returnOrSet _returnSet.toSet() as ${methodBuilder.build()
+                .returnType}"
+        )
     }
 
     fun populateAndReturnOptionalFromCursor(
@@ -196,19 +239,26 @@
         typeArgumentIsNullable: Boolean
     ) {
         if (typeArgumentIsNullable) {
-            processingEnv.warn("Type argument $realReturnType of java.util.Optional is marked as " +
+            processingEnv.warn(
+                "Type argument $realReturnType of java.util.Optional is marked as " +
                     "nullable, an Optional cannot contain a null reference, instead it will be " +
-                    "empty.", contentQuery.method)
+                    "empty.",
+                contentQuery.method
+            )
         }
         methodBuilder.beginControlFlow("if (_cursor.moveToNext())")
         createReturnTypeFromCursor(realReturnType, methodBuilder, contentQuery.toQueryFor)
-        methodBuilder.addStatement("$returnOrSet %T.ofNullable($RETURN_OBJECT_NAME as %T) as %L",
+        methodBuilder.addStatement(
+            "$returnOrSet %T.ofNullable($RETURN_OBJECT_NAME as %T) as %L",
             ClassName("java.util", "Optional").copy(), realReturnType.toKotlinClassName(),
-            methodBuilder.build().returnType.toString())
+            methodBuilder.build().returnType.toString()
+        )
         methodBuilder.nextControlFlow("else")
-            .addStatement("$returnOrSet Optional.empty<%T>() as %L",
+            .addStatement(
+                "$returnOrSet Optional.empty<%T>() as %L",
                 realReturnType.toKotlinClassName(),
-                methodBuilder.build().returnType.toString())
+                methodBuilder.build().returnType.toString()
+            )
             .endControlFlow()
     }
 
@@ -218,8 +268,10 @@
     ) {
         methodBuilder.beginControlFlow("if (_cursor.moveToNext())")
         createReturnTypeFromCursor(returnType, methodBuilder, contentQuery.toQueryFor)
-        methodBuilder.addStatement("$returnOrSet $RETURN_OBJECT_NAME as ${methodBuilder.build()
-            .returnType}")
+        methodBuilder.addStatement(
+            "$returnOrSet $RETURN_OBJECT_NAME as ${methodBuilder.build()
+                .returnType}"
+        )
         methodBuilder.nextControlFlow("else")
             .addStatement("$returnOrSet null")
             .endControlFlow()
@@ -250,29 +302,42 @@
             for (column in columns) {
                 if (column.isNullable) {
                     if (column.requiresApi != null) {
-                        methodBuilder.beginControlFlow("val _${pojoColumnsToFieldNames
-                            .get(column.columnName)}_value = if (%T.VERSION.SDK_INT >= ${column
-                            .requiresApi})", buildClassPlaceHolder)
-                        methodBuilder.beginControlFlow("if (_cursor.isNull(_cursor" +
-                                ".getColumnIndex(%S)))", column.columnName)
+                        methodBuilder.beginControlFlow(
+                            "val _${pojoColumnsToFieldNames
+                                .get(column.columnName)}_value = if (%T.VERSION.SDK_INT >= ${column
+                                .requiresApi})",
+                            buildClassPlaceHolder
+                        )
+                        methodBuilder.beginControlFlow(
+                            "if (_cursor.isNull(_cursor" +
+                                ".getColumnIndex(%S)))",
+                            column.columnName
+                        )
                         methodBuilder.addStatement("null")
                         methodBuilder.nextControlFlow("else")
-                        methodBuilder.addStatement("_cursor" +
+                        methodBuilder.addStatement(
+                            "_cursor" +
                                 ".${column.type.getCursorMethod()}(_cursor.getColumnIndex(%S))",
-                            column.columnName)
+                            column.columnName
+                        )
                         methodBuilder.endControlFlow()
                         methodBuilder.nextControlFlow("else")
                         methodBuilder.addStatement("null")
                         methodBuilder.endControlFlow()
                     } else {
-                        methodBuilder.beginControlFlow("val _${pojoColumnsToFieldNames
-                            .get(column.columnName)}_value = if (_cursor.isNull(_cursor" +
-                                ".getColumnIndex(%S)))", column.columnName)
+                        methodBuilder.beginControlFlow(
+                            "val _${pojoColumnsToFieldNames
+                                .get(column.columnName)}_value = if (_cursor.isNull(_cursor" +
+                                ".getColumnIndex(%S)))",
+                            column.columnName
+                        )
                         methodBuilder.addStatement("null")
                         methodBuilder.nextControlFlow("else")
-                        methodBuilder.addStatement("_cursor" +
+                        methodBuilder.addStatement(
+                            "_cursor" +
                                 ".${column.type.getCursorMethod()}(_cursor.getColumnIndex(%S))",
-                            column.columnName)
+                            column.columnName
+                        )
                         methodBuilder.endControlFlow()
                     }
                 } else {
@@ -280,21 +345,32 @@
                     // fields that were added in a later API to the provider. If that ever happens
                     // the bug ought to be with the entity or if it's legitimate then weird but
                     // okay, warrants a special exception.
-                    methodBuilder.beginControlFlow("val _${pojoColumnsToFieldNames.get(column
-                        .columnName)}_value" +
+                    methodBuilder.beginControlFlow(
+                        "val _${pojoColumnsToFieldNames.get(
+                            column
+                                .columnName
+                        )}_value" +
                             " = if (_cursor.isNull(_cursor.getColumnIndex(%S)))",
-                        column.columnName)
-                    methodBuilder.addStatement("throw NullPointerException(%S)", "Column ${column
-                        .columnName} associated with field ${column.name} in $realReturnType " +
-                            "return null, however field ${column.name} is not nullable")
+                        column.columnName
+                    )
+                    methodBuilder.addStatement(
+                        "throw NullPointerException(%S)",
+                        "Column ${column
+                            .columnName} associated with field ${column.name} in $realReturnType " +
+                            "return null, however field ${column.name} is not nullable"
+                    )
                     methodBuilder.nextControlFlow("else")
-                    methodBuilder.addStatement("_cursor" +
+                    methodBuilder.addStatement(
+                        "_cursor" +
                             ".${column.type.getCursorMethod()}(_cursor.getColumnIndex(%S))",
-                        column.columnName)
+                        column.columnName
+                    )
                     methodBuilder.endControlFlow()
                 }
-                fieldNameValueMap.put(pojoColumnsToFieldNames.get(column.columnName)!!,
-                    "_${pojoColumnsToFieldNames.get(column.columnName)!!}_value")
+                fieldNameValueMap.put(
+                    pojoColumnsToFieldNames.get(column.columnName)!!,
+                    "_${pojoColumnsToFieldNames.get(column.columnName)!!}_value"
+                )
             }
             for (field in constructorFieldNames) {
                 if (field in fieldNameValueMap) {
@@ -304,8 +380,10 @@
                 }
             }
 
-            methodBuilder.addStatement("val $RETURN_OBJECT_NAME = %T(%L)", realReturnType,
-                constructorParams.joinToString(","))
+            methodBuilder.addStatement(
+                "val $RETURN_OBJECT_NAME = %T(%L)", realReturnType,
+                constructorParams.joinToString(",")
+            )
         } else {
             // We should instead assign to public fields directly.
             methodBuilder.addStatement("val $RETURN_OBJECT_NAME = %T()", realReturnType)
@@ -316,34 +394,54 @@
                             "if (%T.VERSION.SDK_INT >= ${column.requiresApi})",
                             buildClassPlaceHolder
                         )
-                        methodBuilder.beginControlFlow("if (!_cursor.isNull(_cursor" +
-                                ".getColumnIndex(%S)))", column.columnName)
-                        methodBuilder.addStatement("$RETURN_OBJECT_NAME.${pojoColumnsToFieldNames
-                            .get(column.columnName)} =" +
+                        methodBuilder.beginControlFlow(
+                            "if (!_cursor.isNull(_cursor" +
+                                ".getColumnIndex(%S)))",
+                            column.columnName
+                        )
+                        methodBuilder.addStatement(
+                            "$RETURN_OBJECT_NAME.${pojoColumnsToFieldNames
+                                .get(column.columnName)} =" +
                                 " _cursor.${column.type.getCursorMethod()}" +
-                                "(_cursor.getColumnIndex(%S))", column.columnName)
+                                "(_cursor.getColumnIndex(%S))",
+                            column.columnName
+                        )
                         methodBuilder.endControlFlow()
                         methodBuilder.endControlFlow()
                     } else {
-                        methodBuilder.beginControlFlow("if (!_cursor.isNull(_cursor" +
-                                ".getColumnIndex(%S)))", column.columnName)
-                        methodBuilder.addStatement("$RETURN_OBJECT_NAME.${pojoColumnsToFieldNames
-                            .get(column.columnName)} =" +
+                        methodBuilder.beginControlFlow(
+                            "if (!_cursor.isNull(_cursor" +
+                                ".getColumnIndex(%S)))",
+                            column.columnName
+                        )
+                        methodBuilder.addStatement(
+                            "$RETURN_OBJECT_NAME.${pojoColumnsToFieldNames
+                                .get(column.columnName)} =" +
                                 " _cursor.${column.type.getCursorMethod()}" +
-                                "(_cursor.getColumnIndex(%S))", column.columnName)
+                                "(_cursor.getColumnIndex(%S))",
+                            column.columnName
+                        )
                         methodBuilder.endControlFlow()
                     }
                 } else {
-                    methodBuilder.beginControlFlow("if (_cursor.isNull(" +
-                            "_cursor.getColumnIndex(%S)))", column.columnName)
-                    methodBuilder.addStatement("throw NullPointerException(%S)", "Column ${column
-                        .columnName} associated with field ${column.name} in $realReturnType " +
-                            "return null, however field ${column.name} is not nullable")
+                    methodBuilder.beginControlFlow(
+                        "if (_cursor.isNull(" +
+                            "_cursor.getColumnIndex(%S)))",
+                        column.columnName
+                    )
+                    methodBuilder.addStatement(
+                        "throw NullPointerException(%S)",
+                        "Column ${column
+                            .columnName} associated with field ${column.name} in $realReturnType " +
+                            "return null, however field ${column.name} is not nullable"
+                    )
                     methodBuilder.nextControlFlow("else")
-                    methodBuilder.addStatement("$RETURN_OBJECT_NAME.${pojoColumnsToFieldNames
-                        .get(column.columnName)} = " +
+                    methodBuilder.addStatement(
+                        "$RETURN_OBJECT_NAME.${pojoColumnsToFieldNames
+                            .get(column.columnName)} = " +
                             "_cursor.${column.type.getCursorMethod()}(_cursor.getColumnIndex(%S))",
-                        column.columnName)
+                        column.columnName
+                    )
                     methodBuilder.endControlFlow()
                 }
             }
diff --git a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentUpdateMethodWriter.kt b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentUpdateMethodWriter.kt
index a21b067..fab312d 100644
--- a/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentUpdateMethodWriter.kt
+++ b/contentaccess/contentaccess-compiler/src/main/kotlin/androidx/contentaccess/compiler/writer/ContentUpdateMethodWriter.kt
@@ -37,8 +37,11 @@
         val methodBuilder = funSpecOverriding(contentUpdate.method, processingEnv)
         methodBuilder.annotations.add(
             AnnotationSpec.builder(Suppress::class).addMember
-                ("%S", "USELESS_CAST").addMember("%S", "UNCHECKED_CAST").addMember("%S",
-                "PLATFORM_CLASS_MAPPED_TO_KOTLIN").build())
+            ("%S", "USELESS_CAST").addMember("%S", "UNCHECKED_CAST").addMember(
+                "%S",
+                "PLATFORM_CLASS_MAPPED_TO_KOTLIN"
+            ).build()
+        )
         if (contentUpdate.isSuspend) {
             val withContext = MemberName("kotlinx.coroutines", "withContext")
             methodBuilder.beginControlFlow(
@@ -47,14 +50,21 @@
             )
         }
         if (contentUpdate.uri.startsWith(":")) {
-            methodBuilder.addStatement("val _uri = %T.parse(%L)", uriTypePlaceHolder.copy(),
-                contentUpdate.uri.removePrefix(":"))
+            methodBuilder.addStatement(
+                "val _uri = %T.parse(%L)", uriTypePlaceHolder.copy(),
+                contentUpdate.uri.removePrefix(":")
+            )
         } else {
-            methodBuilder.addStatement("val _uri = %T.parse(%S)", uriTypePlaceHolder.copy(),
-                contentUpdate.uri)
+            methodBuilder.addStatement(
+                "val _uri = %T.parse(%S)", uriTypePlaceHolder.copy(),
+                contentUpdate.uri
+            )
         }
-        methodBuilder.addStatement("val _contentValues = %T(${contentUpdate.toUpdate
-            .size})", contentValuesPlaceHolder)
+        methodBuilder.addStatement(
+            "val _contentValues = %T(${contentUpdate.toUpdate
+                .size})",
+            contentValuesPlaceHolder
+        )
         for (value in contentUpdate.toUpdate) {
             methodBuilder.addStatement("_contentValues.put(\"${value.first}\", ${value.second})")
         }
@@ -74,8 +84,10 @@
         } else {
             methodBuilder.addStatement("val _where = \"\"")
         }
-        methodBuilder.addStatement("${returnOrSet}_contentResolver.update(_uri, _contentValues, " +
-                "_where, ${if (noSelectionArgs) "null" else "_selectionArgs"})")
+        methodBuilder.addStatement(
+            "${returnOrSet}_contentResolver.update(_uri, _contentValues, " +
+                "_where, ${if (noSelectionArgs) "null" else "_selectionArgs"})"
+        )
 
         if (contentUpdate.isSuspend) {
             methodBuilder.endControlFlow()
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentDeleteProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentDeleteProcessorTest.kt
index d92a93a..18ea44b 100644
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentDeleteProcessorTest.kt
+++ b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentDeleteProcessorTest.kt
@@ -32,8 +32,10 @@
     val entityName = "androidx.contentaccess.compiler.processor.test.Entity"
 
     fun generateMainSourceFile(accessorBody: String, entityWithoutUri: Boolean = false):
-            SourceFile {
-        return SourceFile.kotlin("MyClass.kt", """
+        SourceFile {
+            return SourceFile.kotlin(
+                "MyClass.kt",
+                """
         package androidx.contentaccess.compiler.processor.test
 
         import androidx.contentaccess.ContentAccessObject
@@ -65,20 +67,22 @@
         )
 
         @ContentAccessObject(${if (entityWithoutUri) "EntityWithoutUri::class" else
-            "Entity::class"})
+                    "Entity::class"})
         interface ContentAccessor {
             $accessorBody
         }
         """
-        )
-    }
+            )
+        }
 
     @Test
     fun validDelete() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentDelete
         fun deleteAll(): Int
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -87,10 +91,13 @@
 
     @Test
     fun validDeleteWithUriLessEntity() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentDelete(uri = ":uri")
         fun deleteUriLessEntity(uri: String): Int?
-        """.trimIndent(), true)
+            """.trimIndent(),
+            true
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -99,10 +106,13 @@
 
     @Test
     fun checkThereIsAUriSomewhere() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentDelete
         fun deleteWithNoUri(): Int?
-        """.trimIndent(), true)
+            """.trimIndent(),
+            true
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -112,10 +122,12 @@
 
     @Test
     fun ensureContentEntityInAnnotationTakesPrecedence() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentDelete(contentEntity = EntityWithoutUri::class)
         fun deleteAll(): Int?
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -127,10 +139,12 @@
 
     @Test
     fun ensureReturnsAnInt() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentDelete
         fun deleteAll(): String?
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -142,10 +156,12 @@
 
     @Test
     fun ensureColumnsInWhereExist() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentDelete(where = "unknown_column = :param")
         fun deleteAll(param: String): Int?
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessorTest.kt
index 6ff74c0..8f303ed 100644
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessorTest.kt
+++ b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentEntityProcessorTest.kt
@@ -38,7 +38,9 @@
     val entityName = "androidx.contentaccess.compiler.processor.test.Entity"
 
     fun generateMainSourceFile(entityCode: String = ""): SourceFile {
-        return SourceFile.kotlin("MyClass.kt", """
+        return SourceFile.kotlin(
+            "MyClass.kt",
+            """
         package androidx.contentaccess.compiler.processor.test
 
         import androidx.contentaccess.ContentAccessObject
@@ -54,11 +56,14 @@
         }
 
         $entityCode
-        """)
+        """
+        )
     }
 
     fun generateJavaEntity(entityBody: String): SourceFile {
-        return SourceFile.java("Entity.java", """
+        return SourceFile.java(
+            "Entity.java",
+            """
         package androidx.contentaccess.compiler.processor.test;
 
         import org.jetbrains.annotations.Nullable;
@@ -71,18 +76,21 @@
         public class Entity {
             $entityBody
         }
-        """.trimIndent())
+            """.trimIndent()
+        )
     }
 
     @Test
     fun validContentEntity() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentEntity("example.uri")
         data class Entity(
             @ContentPrimaryKey("_id") val id: Int,
             @ContentColumn("a_random_long") val randomLong: Long
         )
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -92,7 +100,8 @@
     @Test
     fun validJavaContentEntity() {
         val mainSourceFile = generateMainSourceFile()
-        val javaEntityFile = generateJavaEntity("""
+        val javaEntityFile = generateJavaEntity(
+            """
             @ContentPrimaryKey(columnName = "_id")
             public long eventId;
 
@@ -102,7 +111,8 @@
             @ContentColumn(columnName = "dtend")
             @Nullable
             public Long endTime;
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(mainSourceFile, javaEntityFile))
 
@@ -111,13 +121,15 @@
 
     @Test
     fun ensureExistingContentPrimaryKey() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentEntity("example.uri")
         data class Entity(
             @ContentColumn("_id") val id: Int,
             @ContentColumn("a_random_long") val randomLong: Long
         )
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -127,10 +139,12 @@
 
     @Test
     fun ensureEntityContainsFields() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentEntity("example.uri")
         data class Entity()
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -140,12 +154,14 @@
 
     @Test
     fun ensureAllFieldsAreAnnotated() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentEntity("example.uri")
         data class Entity(
             val id: Int
         )
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -156,7 +172,8 @@
 
     @Test
     fun ensureOnlyOneAnnotation() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentEntity("example.uri")
         data class Entity(
             @ContentPrimaryKey("_id")
@@ -164,7 +181,8 @@
             val id: Int,
             @ContentColumn("a_random_long") val randomLong: Long
         )
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -175,13 +193,15 @@
 
     @Test
     fun ensureSupportedColumnType() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentEntity("example.uri")
         data class Entity(
             @ContentPrimaryKey("_id") val id: List<Long>,
             @ContentColumn("a_random_long") val randomLong: Long
         )
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -192,7 +212,8 @@
 
     @Test
     fun ensureSingleNonPrivateNonIgnoredConstructor() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentEntity("example.uri")
         data class Entity(
             @ContentPrimaryKey("_id") val id: Long,
@@ -200,7 +221,8 @@
         ) {
             constructor(@ContentPrimaryKey("_id") id: Long) : this(id, null)
         }
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -211,7 +233,8 @@
     @Test
     fun ensureInstantiableEntity() {
         val mainSourceFile = generateMainSourceFile()
-        val javaEntitySourceFile = generateJavaEntity("""
+        val javaEntitySourceFile = generateJavaEntity(
+            """
             @ContentColumn(columnName = "_id")
             public long eventId;
 
@@ -224,7 +247,8 @@
             public Entity(int randomParameter) {}
 
             private Entity() {}
-        """.trimIndent())
+            """.trimIndent()
+        )
         val result = runCompilation(listOf(mainSourceFile, javaEntitySourceFile))
 
         assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
@@ -234,19 +258,25 @@
     @Test
     fun ensureNonNullablePrimitives() {
         val mainSourceFile = generateMainSourceFile()
-        val javaEntitySourceFile = generateJavaEntity("""
+        val javaEntitySourceFile = generateJavaEntity(
+            """
             @ContentPrimaryKey(columnName = "_id")
             public long eventId;
 
             @ContentColumn(columnName = "dtstart")
             @Nullable
             public long startTime;
-        """.trimIndent())
+            """.trimIndent()
+        )
         val result = runCompilation(listOf(mainSourceFile, javaEntitySourceFile))
 
         assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
-        assertThat(result.messages).contains(entityWithNullablePrimitiveType("startTime",
-            entityName))
+        assertThat(result.messages).contains(
+            entityWithNullablePrimitiveType(
+                "startTime",
+                entityName
+            )
+        )
     }
 }
 
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessorTest.kt
index 0376051..a1b2ce7b 100644
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessorTest.kt
+++ b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentInsertProcessorTest.kt
@@ -31,8 +31,10 @@
 class ContentInsertProcessorTest {
 
     fun generateMainSourceFile(accessorBody: String):
-            SourceFile {
-        return SourceFile.kotlin("MyClass.kt", """
+        SourceFile {
+            return SourceFile.kotlin(
+                "MyClass.kt",
+                """
         package androidx.contentaccess.compiler.processor.test
 
         import androidx.contentaccess.ContentAccessObject
@@ -69,15 +71,17 @@
             $accessorBody
         }
         """
-        )
-    }
+            )
+        }
 
     @Test
     fun validInsert() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentInsert
         fun insertEntity(entity: Entity): Uri?
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -86,13 +90,15 @@
 
     @Test
     fun validInsertWithUriLessEntity() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentInsert(uri = ":uri")
         fun insertUriLessEntity(
             entity: EntityWithoutUri,
             uri: String
         ): Uri?
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -101,10 +107,12 @@
 
     @Test
     fun checkThereIsAnEntityInParameters() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentInsert
         fun insertWithNoEntity(randomNonEntityParam: String): Uri?
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -114,10 +122,12 @@
 
     @Test
     fun checkNoMoreThanOneEntityInParameters() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentInsert
         fun insertMultipleEntities(entity1: Entity, entity2: Entity): Uri?
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -127,29 +137,35 @@
 
     @Test
     fun ensureReturnTypeIsUri() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentInsert
         fun insertEntity(entity: Entity): Int?
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
         assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
-        assertThat(result.messages).contains(contentInsertAnnotatedMethodNotReturningAUri()
+        assertThat(result.messages).contains(
+            contentInsertAnnotatedMethodNotReturningAUri()
         )
     }
 
     @Test
     fun ensureUriExists() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentInsert
         fun insertEntity(entity: EntityWithoutUri): Int?
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
         assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
-        assertThat(result.messages).contains(missingUriOnMethod()
+        assertThat(result.messages).contains(
+            missingUriOnMethod()
         )
     }
 }
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessorTest.kt
index 2d6bcea..2021d8f 100644
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessorTest.kt
+++ b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentQueryProcessorTest.kt
@@ -49,7 +49,9 @@
         pojos: String = "",
         withEntity: Boolean = true
     ): SourceFile {
-        return SourceFile.kotlin("MyClass.kt", """
+        return SourceFile.kotlin(
+            "MyClass.kt",
+            """
         package androidx.contentaccess.compiler.processor.test
 
         import androidx.contentaccess.ContentAccessObject
@@ -90,7 +92,9 @@
     }
 
     fun generateJavaPojo(pojoBody: String): SourceFile {
-        return SourceFile.java("Pojo.java", """
+        return SourceFile.java(
+            "Pojo.java",
+            """
         package androidx.contentaccess.compiler.processor.test;
 
         import org.jetbrains.annotations.Nullable;
@@ -101,12 +105,14 @@
         public class Pojo {
             $pojoBody
         }
-        """.trimIndent())
+            """.trimIndent()
+        )
     }
 
     @Test
     fun validQueries() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery
         fun getAllStartTimeDescriptionAnnotatedPojo(): List<StartTimeDescription2>
 
@@ -148,7 +154,8 @@
 
         @ContentQuery
         suspend fun getAllEntitiesSuspend(): List<EntityWithUri>
-        """.trimIndent(), """
+            """.trimIndent(),
+            """
         data class StartTimeDescription1(
             @ContentColumn("dtstart") val startingTime: Long?,
             @ContentColumn("description") val theDescription: String?
@@ -158,7 +165,8 @@
             val dtstart: Long?,
             val description: String?
         )
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -167,10 +175,13 @@
 
     @Test
     fun checkExistingEntity() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery
         fun getAll(): List<String>
-        """.trimIndent(), withEntity = false)
+            """.trimIndent(),
+            withEntity = false
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -180,10 +191,12 @@
 
     @Test
     fun checkingExistingUri() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery(contentEntity = EntityWithoutUri::class)
         fun getAll(): List<String>
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -193,10 +206,12 @@
 
     @Test
     fun missingOrderByColumn() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery(orderBy = arrayOf("nonExistingColumn"))
         fun getAll(): List<String>
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -206,63 +221,81 @@
 
     @Test
     fun badlyFormulatedOrderBy() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery(orderBy = arrayOf("dtstart desc thisshouldntbehere"))
         fun getAll(): List<String>
-        """.trimIndent())
-
-        val result = runCompilation(listOf(sourceFile))
-
-        assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
-        assertThat(result.messages).contains(badlyFormulatedOrderBy("dtstart desc " +
-                "thisshouldntbehere"))
-    }
-
-    @Test
-    fun ensureExistingColumn() {
-        val sourceFile = generateMainSourceFile("""
-        @ContentQuery(projection = arrayOf("nonExisting"))
-        fun getAll(): List<String>
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
         assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
         assertThat(result.messages).contains(
-            queriedColumnInProjectionNotInEntity("nonExisting",
-                "androidx.contentaccess.compiler.processor.test.EntityWithUri")
+            badlyFormulatedOrderBy(
+                "dtstart desc " +
+                    "thisshouldntbehere"
+            )
+        )
+    }
+
+    @Test
+    fun ensureExistingColumn() {
+        val sourceFile = generateMainSourceFile(
+            """
+        @ContentQuery(projection = arrayOf("nonExisting"))
+        fun getAll(): List<String>
+            """.trimIndent()
+        )
+
+        val result = runCompilation(listOf(sourceFile))
+
+        assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
+        assertThat(result.messages).contains(
+            queriedColumnInProjectionNotInEntity(
+                "nonExisting",
+                "androidx.contentaccess.compiler.processor.test.EntityWithUri"
+            )
         )
     }
 
     @Test
     fun ensureMatchingReturnTypeNonPojo() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery(projection = arrayOf("description"))
         fun getAll(): Long
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
         assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
         assertThat(result.messages).contains(
-            queriedColumnInProjectionTypeDoesntMatchReturnType("long",
+            queriedColumnInProjectionTypeDoesntMatchReturnType(
+                "long",
                 "java.lang.String",
-                "description")
+                "description"
+            )
         )
     }
 
     @Test
     // A "qualifying" constructor is a non private and non ignored constructor
     fun ensurePojoHasNoMoreThanOneQualifyingConstructor() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery
         fun getAll(): Pojo
-        """.trimIndent())
-        val javaPojoFile = generateJavaPojo("""
+            """.trimIndent()
+        )
+        val javaPojoFile = generateJavaPojo(
+            """
             // Two public constructors
             public Pojo() {}
             public Pojo(int unused) {}
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile, javaPojoFile))
 
@@ -272,16 +305,20 @@
 
     @Test
     fun ensurePojoIsInstantiable() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery
         fun getAll(): Pojo
-        """.trimIndent())
-        val javaPojoFile = generateJavaPojo("""
+            """.trimIndent()
+        )
+        val javaPojoFile = generateJavaPojo(
+            """
             // Two public constructors
             private Pojo() {}
             @IgnoreConstructor
             public Pojo(int unused) {}
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile, javaPojoFile))
 
@@ -291,14 +328,18 @@
 
     @Test
     fun ensurePojoDoesntHaveANullablePrimitive() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery
         fun getAll(): Pojo
-        """.trimIndent())
-        val javaPojoFile = generateJavaPojo("""
+            """.trimIndent()
+        )
+        val javaPojoFile = generateJavaPojo(
+            """
             @Nullable
             public long dtstart;
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile, javaPojoFile))
 
@@ -308,66 +349,86 @@
 
     @Test
     fun ensurePojoFieldsMatchOnesInEntity() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery
         fun getAll(): IncorrectPojo
-        """.trimIndent(), """
+            """.trimIndent(),
+            """
             data class IncorrectPojo(@ContentColumn("irrelevant_column")val irrelevantField: String)
-        """.trimIndent())
-
-        val result = runCompilation(listOf(sourceFile))
-
-        assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
-        assertThat(result.messages).contains(pojoFieldNotInEntity("irrelevantField",
-            "java.lang.String", "irrelevant_column",
-            "androidx.contentaccess.compiler.processor.test.IncorrectPojo",
-            entityName))
-    }
-
-    @Test
-    fun ensureFieldsNotInProjectionButInConstructorAreNullable() {
-        val sourceFile = generateMainSourceFile("""
-        @ContentQuery(projection = arrayOf("dtstart"))
-        fun getAll(): CustomPojo
-        """.trimIndent(), """
-            data class CustomPojo(val dtstart: Long?, val nonNullableField: Long)
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
         assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
         assertThat(result.messages).contains(
-            constructorFieldNotIncludedInProjectionNotNullable("nonNullableField",
-                "androidx.contentaccess.compiler.processor.test.CustomPojo")
+            pojoFieldNotInEntity(
+                "irrelevantField",
+                "java.lang.String", "irrelevant_column",
+                "androidx.contentaccess.compiler.processor.test.IncorrectPojo",
+                entityName
+            )
+        )
+    }
+
+    @Test
+    fun ensureFieldsNotInProjectionButInConstructorAreNullable() {
+        val sourceFile = generateMainSourceFile(
+            """
+        @ContentQuery(projection = arrayOf("dtstart"))
+        fun getAll(): CustomPojo
+            """.trimIndent(),
+            """
+            data class CustomPojo(val dtstart: Long?, val nonNullableField: Long)
+            """.trimIndent()
+        )
+
+        val result = runCompilation(listOf(sourceFile))
+
+        assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
+        assertThat(result.messages).contains(
+            constructorFieldNotIncludedInProjectionNotNullable(
+                "nonNullableField",
+                "androidx.contentaccess.compiler.processor.test.CustomPojo"
+            )
         )
     }
 
     @Test
     fun ensurePojoContainsAllProjectionFields() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery(projection = arrayOf("dtstart", "description"))
         fun getAll(): PojoMissingField
-        """.trimIndent(), """
+            """.trimIndent(),
+            """
             data class PojoMissingField(val dtstart: Long?)
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
         assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
         assertThat(result.messages).contains(
-            columnInProjectionNotIncludedInReturnPojo("description",
-                "androidx.contentaccess.compiler.processor.test.PojoMissingField")
+            columnInProjectionNotIncludedInReturnPojo(
+                "description",
+                "androidx.contentaccess.compiler.processor.test.PojoMissingField"
+            )
         )
     }
 
     @Test
     fun ensureNullableEntityFieldsAreAlsoNullableInPojo() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery
         fun getAll(): PojoWithNonNullableField
-        """.trimIndent(), """
+            """.trimIndent(),
+            """
             data class PojoWithNonNullableField(val dtstart: Long)
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -384,10 +445,12 @@
 
     @Test
     fun ensureUriParameterProperlySpecified() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery(uri = ":")
         fun getAll(): List<EntityWithUri>
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -397,10 +460,12 @@
 
     @Test
     fun ensureUriParameterExists() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery(uri = ":param")
         fun getAll(): List<EntityWithUri>
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -410,10 +475,12 @@
 
     @Test
     fun ensureUriParameterIsString() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery(uri = ":param")
         fun getAll(param: Long): List<EntityWithUri>
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessorTest.kt
index b2182bc..5072e95 100644
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessorTest.kt
+++ b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/ContentUpdateProcessorTest.kt
@@ -36,8 +36,10 @@
     val entityName = "androidx.contentaccess.compiler.processor.test.Entity"
 
     fun generateMainSourceFile(accessorBody: String, entityWithoutUri: Boolean = false):
-            SourceFile {
-        return SourceFile.kotlin("MyClass.kt", """
+        SourceFile {
+            return SourceFile.kotlin(
+                "MyClass.kt",
+                """
         package androidx.contentaccess.compiler.processor.test
 
         import androidx.contentaccess.ContentAccessObject
@@ -69,17 +71,18 @@
         )
 
         @ContentAccessObject(${if (entityWithoutUri) "EntityWithoutUri::class" else
-            "Entity::class"})
+                    "Entity::class"})
         interface ContentAccessor {
             $accessorBody
         }
         """
-        )
-    }
+            )
+        }
 
     @Test
     fun validUpdates() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentUpdate
         fun updateDescription(@ContentColumn("description") desc: String): Int
 
@@ -90,7 +93,8 @@
             id: Long,
             uri: String
         ): Int
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -99,7 +103,8 @@
 
     @Test
     fun validUpdatesWithUriLessEntity() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentUpdate(where = "_id = 123", uri = ":uri")
         fun updateDescriptionWithUri(
             @ContentColumn("description") desc: String,
@@ -110,7 +115,9 @@
         fun updateDescription(
             @ContentColumn("description") desc: String
         ): Int
-        """.trimIndent(), entityWithoutUri = true)
+            """.trimIndent(),
+            entityWithoutUri = true
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -119,40 +126,52 @@
 
     @Test
     fun checkColumnsExist() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentUpdate(where = "_id = :id")
         fun updateDescription(@ContentColumn("nonexistent") desc: String, id: Long): Int
-        """.trimIndent())
-
-        val result = runCompilation(listOf(sourceFile))
-
-        assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
-        assertThat(result.messages).contains(columnInContentUpdateParametersNotInEntity("desc",
-            "nonexistent", entityName))
-    }
-
-    @Test
-    fun ensureTypesMatch() {
-        val sourceFile = generateMainSourceFile("""
-        @ContentUpdate
-        fun updateDescription(@ContentColumn("description") desc: Long): Int
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
         assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
         assertThat(result.messages).contains(
-            mismatchedColumnTypeForColumnToBeUpdated("desc",
-            "description", "long", entityName, "java.lang.String")
+            columnInContentUpdateParametersNotInEntity(
+                "desc",
+                "nonexistent", entityName
+            )
+        )
+    }
+
+    @Test
+    fun ensureTypesMatch() {
+        val sourceFile = generateMainSourceFile(
+            """
+        @ContentUpdate
+        fun updateDescription(@ContentColumn("description") desc: Long): Int
+            """.trimIndent()
+        )
+
+        val result = runCompilation(listOf(sourceFile))
+
+        assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
+        assertThat(result.messages).contains(
+            mismatchedColumnTypeForColumnToBeUpdated(
+                "desc",
+                "description", "long", entityName, "java.lang.String"
+            )
         )
     }
 
     @Test
     fun ensureNoWhereClauseWhenUpdatingEntity() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentUpdate(where = "_id = 123")
         fun updateDescription(entityParam: Entity): Int
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -164,10 +183,12 @@
 
     @Test
     fun ensureOnlyOneEntityIsUpdatedAtTheSameTime() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentUpdate
         fun updateDescription(entityParam1: Entity, entityParam2: Entity): Int
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -179,10 +200,12 @@
 
     @Test
     fun ensureContentUpdateMethodReturnsAnInteger() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentUpdate
         fun updateDescription(entityParam1: Entity): Long
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -192,10 +215,12 @@
 
     @Test
     fun ensureSomethingIsBeingUpdated() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentUpdate
         fun updateDescription(entities: List<Entity>): Int
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -205,15 +230,19 @@
 
     @Test
     fun ensureNonNullableUpdateParametersForNonNullablEntityColumn() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentUpdate
         fun updateDescription(@ContentColumn("dtend") newEndTime: Long?): Int
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
         assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
-        assertThat(result.messages).contains(nullableUpdateParamForNonNullableEntityColumn
-            ("newEndTime", "dtend", entityName))
+        assertThat(result.messages).contains(
+            nullableUpdateParamForNonNullableEntityColumn
+            ("newEndTime", "dtend", entityName)
+        )
     }
 }
\ No newline at end of file
diff --git a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessorTest.kt b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessorTest.kt
index 202a018..449aaf5 100644
--- a/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessorTest.kt
+++ b/contentaccess/contentaccess-compiler/src/test/kotlin/androidx/contentaccess/compiler/processor/SelectionProcessorTest.kt
@@ -33,7 +33,9 @@
     val entityName = "androidx.contentaccess.compiler.processor.test.Entity"
 
     fun generateMainSourceFile(accessorBody: String): SourceFile {
-        return SourceFile.kotlin("MyClass.kt", """
+        return SourceFile.kotlin(
+            "MyClass.kt",
+            """
         package androidx.contentaccess.compiler.processor.test
 
         import androidx.contentaccess.ContentAccessObject
@@ -62,11 +64,13 @@
 
     @Test
     fun validSelection() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery(selection = "dtstart > 1 OR (dtstart < 5 AND description =  \"abc\")" + 
             " OR ((description = :parameter AND (dtstart * 6 = 30)))")
         fun getAll(parameter: String): List<Entity>
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -75,10 +79,12 @@
 
     @Test
     fun ensureNoStraySelectionColumns() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery(selection = "dtstart = : AND description > :parameter")
         fun getAll(parameter: String): List<Entity>
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -88,10 +94,12 @@
 
     @Test
     fun ensureSelectionArgumentsAreSpecifiedInParameter() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery(selection = "description > :parameter")
         fun getAll(): List<Entity>
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
@@ -101,16 +109,19 @@
 
     @Test
     fun ensureColumnsMentionedInSelectionExistInEntity() {
-        val sourceFile = generateMainSourceFile("""
+        val sourceFile = generateMainSourceFile(
+            """
         @ContentQuery(selection = "unknown_column > 5")
         fun getAll(): List<Entity>
-        """.trimIndent())
+            """.trimIndent()
+        )
 
         val result = runCompilation(listOf(sourceFile))
 
         assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR)
         assertThat(result.messages).contains(
-            columnInSelectionMissingFromEntity("unknown_column", entityName))
+            columnInSelectionMissingFromEntity("unknown_column", entityName)
+        )
     }
 
     @Test
diff --git a/contentaccess/contentaccess-entities/src/main/kotlin/androidx/contentaccess/entities/ContentAccessMediaStore.kt b/contentaccess/contentaccess-entities/src/main/kotlin/androidx/contentaccess/entities/ContentAccessMediaStore.kt
index 7148cdf..8ecc18a 100644
--- a/contentaccess/contentaccess-entities/src/main/kotlin/androidx/contentaccess/entities/ContentAccessMediaStore.kt
+++ b/contentaccess/contentaccess-entities/src/main/kotlin/androidx/contentaccess/entities/ContentAccessMediaStore.kt
@@ -54,9 +54,11 @@
         public var _id: Int? = null
 
         @JvmField
-        @Deprecated("Apps may not have filesystem permissions to directly access this path. " +
+        @Deprecated(
+            "Apps may not have filesystem permissions to directly access this path. " +
                 "Instead of trying to open this path directly, apps should use " +
-                "ContentResolver#openFileDescriptor(Uri, String) to gain access.")
+                "ContentResolver#openFileDescriptor(Uri, String) to gain access."
+        )
         @ContentColumn(android.provider.MediaStore.MediaColumns.DATA)
         public var data: String? = null
 
@@ -137,28 +139,36 @@
 
     open class ImageColumns : MediaColumns() {
         @JvmField
-        @Deprecated("As of API 29, this value was only relevant for images hosted on Picasa, " +
-                "which are no longer supported.")
+        @Deprecated(
+            "As of API 29, this value was only relevant for images hosted on Picasa, " +
+                "which are no longer supported."
+        )
         @ContentColumn(android.provider.MediaStore.Images.ImageColumns.PICASA_ID)
         public var picasaId: String? = null
 
         @JvmField
-        @Deprecated("As of API 29, location details are no longer indexed for privacy reasons, " +
+        @Deprecated(
+            "As of API 29, location details are no longer indexed for privacy reasons, " +
                 "and this value is now always null. You can still manually obtain location " +
-                "metadata using ExifInterface#getLatLong(float[]).")
+                "metadata using ExifInterface#getLatLong(float[])."
+        )
         @ContentColumn(android.provider.MediaStore.Images.ImageColumns.LATITUDE)
         public var latitude: Float? = null
 
         @JvmField
-        @Deprecated("As of API 29, location details are no longer indexed for privacy reasons, " +
+        @Deprecated(
+            "As of API 29, location details are no longer indexed for privacy reasons, " +
                 "and this value is now always null. You can still manually obtain location " +
-                "metadata using ExifInterface#getLatLong(float[]).")
+                "metadata using ExifInterface#getLatLong(float[])."
+        )
         @ContentColumn(android.provider.MediaStore.Images.ImageColumns.LONGITUDE)
         public var longitude: Float? = null
 
         @JvmField
-        @Deprecated("As of API 29, all thumbnails should be obtained via MediaStore.Images" +
-                ".Thumbnails#getThumbnail, as this value is no longer supported.")
+        @Deprecated(
+            "As of API 29, all thumbnails should be obtained via MediaStore.Images" +
+                ".Thumbnails#getThumbnail, as this value is no longer supported."
+        )
         @ContentColumn(android.provider.MediaStore.Images.ImageColumns.MINI_THUMB_MAGIC)
         public var miniThumbMagic: Int? = null
 
@@ -252,9 +262,11 @@
         public var _id: Int? = null
 
         @JvmField
-        @Deprecated("Deprecated in API 29. Apps may not have filesystem permissions to directly " +
+        @Deprecated(
+            "Deprecated in API 29. Apps may not have filesystem permissions to directly " +
                 "access this path. Instead of trying to open this path directly, apps should use " +
-                "ContentResolver#loadThumbnail to gain access.")
+                "ContentResolver#loadThumbnail to gain access."
+        )
         @ContentColumn(android.provider.MediaStore.Images.Thumbnails.DATA)
         public var data: String? = null
 
@@ -275,8 +287,10 @@
         public var height: Int? = null
     }
 
-    @Deprecated("Callers should migrate to using ContentResolver#loadThumbnail, since it offers " +
-            "richer control over requested thumbnail sizes and cancellationbehavior.")
+    @Deprecated(
+        "Callers should migrate to using ContentResolver#loadThumbnail, since it offers " +
+            "richer control over requested thumbnail sizes and cancellationbehavior."
+    )
     @ContentEntity("content://media/external/images/thumbnails")
     class ImageThumbnail : ImageThumbnailColumns()
 
@@ -287,9 +301,11 @@
         public var _id: Int? = null
 
         @JvmField
-        @Deprecated("Deprecated in API 29. Apps may not have filesystem permissions to directly " +
+        @Deprecated(
+            "Deprecated in API 29. Apps may not have filesystem permissions to directly " +
                 "access this path. Instead of trying to open this path directly, apps should use " +
-                "ContentResolver#loadThumbnail to gain access.")
+                "ContentResolver#loadThumbnail to gain access."
+        )
         @ContentColumn(android.provider.MediaStore.Video.Thumbnails.DATA)
         public var data: String? = null
 
@@ -310,23 +326,29 @@
         public var height: Int? = null
     }
 
-    @Deprecated("Callers should migrate to using ContentResolver#loadThumbnail, since it offers " +
-            "richer control over requested thumbnail sizes and cancellationbehavior.")
+    @Deprecated(
+        "Callers should migrate to using ContentResolver#loadThumbnail, since it offers " +
+            "richer control over requested thumbnail sizes and cancellationbehavior."
+    )
     @ContentEntity("content://media/external/video/thumbnails")
     class VideoThumbnail : VideoThumbnailColumns()
 
     open class VideoColumns : MediaColumns() {
         @JvmField
-        @Deprecated("As of API 29, location details are no longer indexed for privacy reasons, " +
+        @Deprecated(
+            "As of API 29, location details are no longer indexed for privacy reasons, " +
                 "and this value is now always null. You can still manually obtain location " +
-                "metadata using ExifInterface#getLatLong(float[]).")
+                "metadata using ExifInterface#getLatLong(float[])."
+        )
         @ContentColumn(android.provider.MediaStore.Video.VideoColumns.LATITUDE)
         public var latitude: Float? = null
 
         @JvmField
-        @Deprecated("As of API 29, location details are no longer indexed for privacy reasons, " +
+        @Deprecated(
+            "As of API 29, location details are no longer indexed for privacy reasons, " +
                 "and this value is now always null. You can still manually obtain location " +
-                "metadata using ExifInterface#getLatLong(float[]).")
+                "metadata using ExifInterface#getLatLong(float[])."
+        )
         @ContentColumn(android.provider.MediaStore.Video.VideoColumns.LONGITUDE)
         public var longitude: Float? = null
 
@@ -351,8 +373,10 @@
         public var language: String? = null
 
         @JvmField
-        @Deprecated("As for API 29, all thumbnails should be obtained via MediaStore.Images" +
-                ".Thumbnails#getThumbnail, as this value is no longer supported.")
+        @Deprecated(
+            "As for API 29, all thumbnails should be obtained via MediaStore.Images" +
+                ".Thumbnails#getThumbnail, as this value is no longer supported."
+        )
         @ContentColumn(android.provider.MediaStore.Video.VideoColumns.MINI_THUMB_MAGIC)
         public var miniThumbMagic: Int? = null
 
@@ -429,11 +453,13 @@
 
     open class AudioColumns : MediaColumns() {
         @JvmField
-        @Deprecated("Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
+        @Deprecated(
+            "Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
                 "means they don't reflect locale-specific sorting preferences. To apply " +
                 "locale-specific sorting preferences, use " +
                 "ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
-                "ContentResolver#QUERY_ARG_SORT_LOCALE. ")
+                "ContentResolver#QUERY_ARG_SORT_LOCALE. "
+        )
         @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.TITLE_KEY)
         public var titleKey: String? = null
 
@@ -446,11 +472,13 @@
         public var artistId: Int? = null
 
         @JvmField
-        @Deprecated("Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
+        @Deprecated(
+            "Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
                 "means they don't reflect locale-specific sorting preferences. To apply " +
                 "locale-specific sorting preferences, use " +
                 "ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
-                "ContentResolver#QUERY_ARG_SORT_LOCALE. ")
+                "ContentResolver#QUERY_ARG_SORT_LOCALE. "
+        )
         @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.ARTIST_KEY)
         public var artistKey: String? = null
 
@@ -459,11 +487,13 @@
         public var albumId: Int? = null
 
         @JvmField
-        @Deprecated("Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
+        @Deprecated(
+            "Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
                 "means they don't reflect locale-specific sorting preferences. To apply " +
                 "locale-specific sorting preferences, use " +
                 "ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
-                "ContentResolver#QUERY_ARG_SORT_LOCALE. ")
+                "ContentResolver#QUERY_ARG_SORT_LOCALE. "
+        )
         @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.ALBUM_KEY)
         public var albumKey: String? = null
 
@@ -506,11 +536,13 @@
         public var genreId: Int? = null
 
         @JvmField
-        @Deprecated("Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
+        @Deprecated(
+            "Deprecated in API 30, These keys are generated using Locale.ROOT, which " +
                 "means they don't reflect locale-specific sorting preferences. To apply " +
                 "locale-specific sorting preferences, use " +
                 "ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
-                "ContentResolver#QUERY_ARG_SORT_LOCALE. ")
+                "ContentResolver#QUERY_ARG_SORT_LOCALE. "
+        )
         @RequiresApi(30)
         @ContentColumn(android.provider.MediaStore.Audio.AudioColumns.GENRE_KEY)
         public var genreKey: String? = null
@@ -581,9 +613,11 @@
         public var album: String? = null
 
         @JvmField
-        @Deprecated("This constant was deprecated in API level 29. Apps may not have filesystem " +
+        @Deprecated(
+            "This constant was deprecated in API level 29. Apps may not have filesystem " +
                 "permissions to directly access this path. Instead of trying to open this path " +
-                "directly, apps should use ContentResolver#loadThumbnail to gain access.")
+                "directly, apps should use ContentResolver#loadThumbnail to gain access."
+        )
         @ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.ALBUM_ART)
         public var albumArt: String? = null
 
@@ -593,11 +627,13 @@
         public var albumId: Int? = null
 
         @JvmField
-        @Deprecated("This constant was deprecated in API level 30. These keys are generated using" +
+        @Deprecated(
+            "This constant was deprecated in API level 30. These keys are generated using" +
                 " Locale.ROOT, which means they don't reflect locale-specific sorting preferences" +
                 ". To apply locale-specific sorting preferences, use " +
                 "ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
-                "ContentResolver#QUERY_ARG_SORT_LOCALE.")
+                "ContentResolver#QUERY_ARG_SORT_LOCALE."
+        )
         @ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.ALBUM_KEY)
         public var albumKey: String? = null
 
@@ -611,11 +647,13 @@
         public var artistId: Int? = null
 
         @JvmField
-        @Deprecated("This constant was deprecated in API level 30. These keys are generated using" +
+        @Deprecated(
+            "This constant was deprecated in API level 30. These keys are generated using" +
                 " Locale.ROOT, which means they don't reflect locale-specific sorting preferences" +
                 ". To apply locale-specific sorting preferences, use " +
                 "ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
-                "ContentResolver#QUERY_ARG_SORT_LOCALE.")
+                "ContentResolver#QUERY_ARG_SORT_LOCALE."
+        )
         @RequiresApi(30)
         @ContentColumn(android.provider.MediaStore.Audio.AlbumColumns.ARTIST_KEY)
         public var artistKey: String? = null
@@ -648,11 +686,13 @@
         public var _id: Int? = null
 
         @JvmField
-        @Deprecated("This constant was deprecated in API level 30. These keys are generated using" +
+        @Deprecated(
+            "This constant was deprecated in API level 30. These keys are generated using" +
                 " Locale.ROOT, which means they don't reflect locale-specific sorting preferences" +
                 ". To apply locale-specific sorting preferences, use " +
                 "ContentResolver#QUERY_ARG_SQL_SORT_ORDER with COLLATE LOCALIZED, or " +
-                "ContentResolver#QUERY_ARG_SORT_LOCALE.")
+                "ContentResolver#QUERY_ARG_SORT_LOCALE."
+        )
         @ContentColumn(android.provider.MediaStore.Audio.ArtistColumns.ARTIST_KEY)
         public var artistKey: String? = null
 
@@ -693,10 +733,12 @@
         public var _id: Int? = null
 
         @JvmField
-        @Deprecated("This constant was deprecated in API level 29. Apps may not have filesystem " +
+        @Deprecated(
+            "This constant was deprecated in API level 29. Apps may not have filesystem " +
                 "permissions to directly access this path. Instead of trying to open this path " +
                 "directly, apps should use ContentResolver#openFileDescriptor(Uri, String) to " +
-                "gain access.")
+                "gain access."
+        )
         @ContentColumn(android.provider.MediaStore.Audio.PlaylistsColumns.DATA)
         public var data: String? = null
 
diff --git a/contentaccess/contentaccess-runtime/src/main/kotlin/androidx/contentaccess/runtime/ContentAccess.kt b/contentaccess/contentaccess-runtime/src/main/kotlin/androidx/contentaccess/runtime/ContentAccess.kt
index c418bc2..3646d7b 100644
--- a/contentaccess/contentaccess-runtime/src/main/kotlin/androidx/contentaccess/runtime/ContentAccess.kt
+++ b/contentaccess/contentaccess-runtime/src/main/kotlin/androidx/contentaccess/runtime/ContentAccess.kt
@@ -41,16 +41,23 @@
                     ContentResolver::class.java,
                     CoroutineDispatcher::class.java
                 )
-                return constructor.newInstance(contentResolver, queryExecutor
-                    .asCoroutineDispatcher()) as T
+                return constructor.newInstance(
+                    contentResolver,
+                    queryExecutor
+                        .asCoroutineDispatcher()
+                ) as T
             } catch (e: ClassNotFoundException) {
-                error("Cannot find generated class for content accessor ${contentAccessObject
-                    .qualifiedName}, this is most likely because the class is not annotated " +
+                error(
+                    "Cannot find generated class for content accessor ${contentAccessObject
+                        .qualifiedName}, this is most likely because the class is not annotated " +
                         "with @ContentAccessObject or because the contentaccess-compiler " +
-                        "annotation processor was not ran properly.")
+                        "annotation processor was not ran properly."
+                )
             } catch (e: InstantiationException) {
-                error("Unable to instantiate implementation $packageName.$generatedClassName of " +
-                        "${contentAccessObject.qualifiedName}.")
+                error(
+                    "Unable to instantiate implementation $packageName.$generatedClassName of " +
+                        "${contentAccessObject.qualifiedName}."
+                )
             }
         }
     }
diff --git a/core/core/src/androidTest/java/androidx/core/os/LocaleListCompatTest.java b/core/core/src/androidTest/java/androidx/core/os/LocaleListCompatTest.java
index f071c00..3fd5f6d 100644
--- a/core/core/src/androidTest/java/androidx/core/os/LocaleListCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/os/LocaleListCompatTest.java
@@ -114,18 +114,6 @@
     }
 
     @Test
-    public void testRepeatedArguments() {
-        final Locale[] la = {Locale.US, Locale.US};
-        try {
-            LocaleListCompat.create(la);
-            fail("Initializing a LocaleListCompat with an array containing duplicates should "
-                    + "throw.");
-        } catch (Throwable e) {
-            assertEquals(IllegalArgumentException.class, e.getClass());
-        }
-    }
-
-    @Test
     public void testIndexOf() {
         final LocaleListCompat empty = LocaleListCompat.create();
         assertEquals(-1, empty.indexOf(Locale.US));
diff --git a/core/core/src/main/java/androidx/core/os/LocaleListCompatWrapper.java b/core/core/src/main/java/androidx/core/os/LocaleListCompatWrapper.java
index 4e7411f..db9306a 100644
--- a/core/core/src/main/java/androidx/core/os/LocaleListCompatWrapper.java
+++ b/core/core/src/main/java/androidx/core/os/LocaleListCompatWrapper.java
@@ -23,9 +23,11 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
 
 final class LocaleListCompatWrapper implements LocaleListInterface {
@@ -122,7 +124,7 @@
             mList = sEmptyList;
             mStringRepresentation = "";
         } else {
-            final Locale[] localeList = new Locale[list.length];
+            final List<Locale> localeList = new ArrayList<>();
             final HashSet<Locale> seenLocales = new HashSet<Locale>();
             final StringBuilder sb = new StringBuilder();
             for (int i = 0; i < list.length; i++) {
@@ -130,10 +132,10 @@
                 if (l == null) {
                     throw new NullPointerException("list[" + i + "] is null");
                 } else if (seenLocales.contains(l)) {
-                    throw new IllegalArgumentException("list[" + i + "] is a repetition");
+                    // Ignore repeated locale
                 } else {
                     final Locale localeClone = (Locale) l.clone();
-                    localeList[i] = localeClone;
+                    localeList.add(localeClone);
                     toLanguageTag(sb, localeClone);
                     if (i < list.length - 1) {
                         sb.append(',');
@@ -141,7 +143,7 @@
                     seenLocales.add(localeClone);
                 }
             }
-            mList = localeList;
+            mList = localeList.toArray(new Locale[localeList.size()]);
             mStringRepresentation = sb.toString();
         }
     }
diff --git a/customview/customview/build.gradle b/customview/customview/build.gradle
index 474e25e..4ec89b0 100644
--- a/customview/customview/build.gradle
+++ b/customview/customview/build.gradle
@@ -1,11 +1,11 @@
 import static androidx.build.dependencies.DependenciesKt.*
 import androidx.build.LibraryGroups
-import androidx.build.LibraryVersions
 import androidx.build.Publish
 
 plugins {
     id("AndroidXPlugin")
     id("com.android.library")
+    id("kotlin-android")
 }
 
 android {
@@ -20,6 +20,7 @@
     api("androidx.core:core:1.3.0-beta01")
     implementation("androidx.collection:collection:1.1.0")
 
+    androidTestImplementation(KOTLIN_STDLIB)
     androidTestImplementation(JUNIT)
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
     androidTestImplementation(ANDROIDX_TEST_CORE)
diff --git a/customview/customview/src/androidTest/AndroidManifest.xml b/customview/customview/src/androidTest/AndroidManifest.xml
index 97b7919..4e5bad6 100644
--- a/customview/customview/src/androidTest/AndroidManifest.xml
+++ b/customview/customview/src/androidTest/AndroidManifest.xml
@@ -18,7 +18,8 @@
           package="androidx.customview.test">
 
     <application android:supportsRtl="true">
-        <activity android:name="androidx.customview.widget.ExploreByTouchHelperTestActivity"/>
+        <activity android:name="androidx.customview.widget.ExploreByTouchHelperTestActivity" />
+        <activity android:name="androidx.customview.widget.TestActivity" />
     </application>
 
 </manifest>
diff --git a/customview/customview/src/androidTest/java/androidx/customview/widget/TestActivity.kt b/customview/customview/src/androidTest/java/androidx/customview/widget/TestActivity.kt
new file mode 100644
index 0000000..65fd739
--- /dev/null
+++ b/customview/customview/src/androidTest/java/androidx/customview/widget/TestActivity.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 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.customview.widget
+
+import android.app.Activity
+import android.os.Bundle
+
+import androidx.customview.test.R
+
+class TestActivity : Activity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.text_view_activity)
+    }
+}
diff --git a/customview/customview/src/androidTest/java/androidx/customview/widget/ViewDragHelperTest.kt b/customview/customview/src/androidTest/java/androidx/customview/widget/ViewDragHelperTest.kt
new file mode 100644
index 0000000..abc2e38
--- /dev/null
+++ b/customview/customview/src/androidTest/java/androidx/customview/widget/ViewDragHelperTest.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 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.customview.widget
+
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewGroup
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ViewDragHelperTest {
+    @Suppress("DEPRECATION")
+    @get:Rule
+    val activityRule = androidx.test.rule.ActivityTestRule(TestActivity::class.java)
+
+    @Test
+    fun testProcessTouchEventWithInconsistentStream() {
+        val callback = object : ViewDragHelper.Callback() {
+            override fun tryCaptureView(child: View, pointerId: Int): Boolean = false
+        }
+        activityRule.runOnUiThread {
+            val activity = activityRule.activity
+            val content = activity.findViewById<View>(android.R.id.content)!! as ViewGroup
+            val helper = ViewDragHelper.create(content, callback)
+
+            // Ensure the state is STATE_DRAGGING with the pointer DOWN.
+            helper.processTouchEvent(obtainMotionEvent(MotionEvent.ACTION_DOWN, 2))
+
+            // Set the active pointer ID to match.
+            helper.captureChildView(content.getChildAt(0), 2)
+
+            // Feed in touch event without the pointer ID.
+            helper.processTouchEvent(obtainMotionEvent(MotionEvent.ACTION_MOVE, 0))
+        }
+    }
+}
+
+fun obtainMotionEvent(action: Int, pointerId: Int): MotionEvent {
+    @Suppress("DEPRECATION")
+    return MotionEvent.obtain(
+        System.currentTimeMillis(),
+        System.currentTimeMillis(),
+        action,
+        1,
+        intArrayOf(pointerId),
+        arrayOf(MotionEvent.PointerCoords()),
+        0,
+        0f,
+        0f,
+        0,
+        0,
+        0,
+        0
+    )
+}
diff --git a/customview/customview/src/androidTest/res/layout/text_view_activity.xml b/customview/customview/src/androidTest/res/layout/text_view_activity.xml
new file mode 100644
index 0000000..ba5d688
--- /dev/null
+++ b/customview/customview/src/androidTest/res/layout/text_view_activity.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/content"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <TextView
+        android:id="@+id/text_view"
+        android:layout_width="200dip"
+        android:layout_height="60dip" />
+</FrameLayout>
diff --git a/customview/customview/src/main/java/androidx/customview/widget/ViewDragHelper.java b/customview/customview/src/main/java/androidx/customview/widget/ViewDragHelper.java
index e6a32cc..9916886 100644
--- a/customview/customview/src/main/java/androidx/customview/widget/ViewDragHelper.java
+++ b/customview/customview/src/main/java/androidx/customview/widget/ViewDragHelper.java
@@ -1191,7 +1191,15 @@
                     // If pointer is invalid then skip the ACTION_MOVE.
                     if (!isValidPointerForActionMove(mActivePointerId)) break;
 
+                    // If pointer index is not found then skip.
                     final int index = ev.findPointerIndex(mActivePointerId);
+                    if (index == -1) {
+                        Log.w(TAG, "Failed to find pointer index for active pointer ID "
+                                + mActivePointerId + ", which may indicate an inconsistent "
+                                + "MotionEvent stream");
+                        break;
+                    }
+
                     final float x = ev.getX(index);
                     final float y = ev.getY(index);
                     final int idx = (int) (x - mLastMotionX[mActivePointerId]);
diff --git a/development/build_log_processor.sh b/development/build_log_processor.sh
index e4ddd19..17462d2 100755
--- a/development/build_log_processor.sh
+++ b/development/build_log_processor.sh
@@ -24,7 +24,7 @@
   echo "-Pandroidx.summarizeStderr"
   echo "  Run build_log_simplifier.py on failure to produce a summary of the build output"
   echo
-  echo "-Pandroidx.validateNoExtraMessages"
+  echo "-Pandroidx.validateNoUnrecognizedMessages"
   echo "  Run build_log_simplifier.py --validate on success to confirm that the build generated no unrecognized messages"
   exit 1
 }
@@ -37,9 +37,9 @@
 if [[ " ${@} " =~ " -Pandroidx.summarizeStderr " ]]; then
   summarizeOnFailure=true
 fi
-validateNoExtraMessagesOnSuccess=false
-if [[ " ${@} " =~ " -Pandroidx.validateNoExtraMessages " ]]; then
-  validateNoExtraMessagesOnSuccess=true
+validateNoUnrecognizedMessagesOnSuccess=false
+if [[ " ${@} " =~ " -Pandroidx.validateNoUnrecognizedMessages " ]]; then
+  validateNoUnrecognizedMessagesOnSuccess=true
 fi
 
 # run Gradle and save stdout and stderr into $logFile
@@ -66,14 +66,14 @@
 shift
 echo Running "$programName" "$@"
 if "$programName" "$@" > >(tee -a "$logFile") 2>&1; then
-  echo "Succeeded: $*" >&2
-  if [ "$validateNoExtraMessagesOnSuccess" == "true" ]; then
+  echo "Succeeded: $programName $*" >&2
+  if [ "$validateNoUnrecognizedMessagesOnSuccess" == "true" ]; then
     echo "##########################################################################" >&2
     $SCRIPT_PATH/build_log_simplifier.py --validate $logFile >&2
   fi
 else
   echo >&2
-  echo "Failed: $*" >&2
+  echo "Failed: $programName $*" >&2
   echo "############################################################################" >&2
   echo "Attempting to locate the relevant error messages via build_log_simplifier.py" >&2
   echo "############################################################################" >&2
diff --git a/development/build_log_simplifier/build_log_simplifier.py b/development/build_log_simplifier/build_log_simplifier.py
index 51d7b75..fb24371 100755
--- a/development/build_log_simplifier/build_log_simplifier.py
+++ b/development/build_log_simplifier/build_log_simplifier.py
@@ -199,6 +199,10 @@
             # skip comments
             continue
         regexes.append(line)
+        if remove_control_characters(line) != line:
+            raise Exception("Unexpected control characters found in configuration line:\n\n " +
+                "'" + line + "'\n\n. This line is unexpected to match anything. Is this a copying mistake?")
+
     return regexes_matcher(sorted(regexes))
 
 # Returns a regexes_matcher that matches the content of our config file
@@ -286,6 +290,22 @@
             result.append(line)
     return result
 
+# Removes color characters and other ANSI control characters from this input
+control_character_regex = re.compile(r"""
+        \x1B  # Escape
+        (?:   # 7-bit C1 Fe (except CSI)
+            [@-Z\\-_]
+        |     # or [ for CSI, followed by a control sequence
+            \[
+            [0-?]*  # Parameters
+            [ -/]*  # Intermediate bytes
+            [@-~]   # End
+        )
+        """, re.VERBOSE)
+
+def remove_control_characters(line):
+    return control_character_regex.sub("", line)
+
 # Normalizes some filepaths to more easily simplify/skip some messages
 def normalize_paths(lines):
     # get OUT_DIR, DIST_DIR, and the path of the root of the checkout
@@ -434,6 +454,7 @@
     # read file
     log_path = arguments.log_path[0]
     lines = readlines(log_path)
+    lines = [remove_control_characters(line) for line in lines]
     lines = normalize_paths(lines)
     # load configuration
     exemption_regexes_from_file = readlines(get_exemptions_path())
@@ -470,7 +491,7 @@
     elif arguments.update:
         if len(lines) != 0:
             update_path = get_exemptions_path()
-            suggested = generate_suggested_exemptions(lines, configuration_lines)
+            suggested = generate_suggested_exemptions(lines, exemption_regexes_from_file)
             writelines(update_path, suggested)
             print("build_log_simplifier.py updated exemptions " + update_path)
     else:
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index a4be74b2..c7017e9 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -1,11 +1,1147 @@
 # This file is a list of regexes of messages that are permitted to appear in stdout/stderr
 # Comments and blank lines are ignored
 # Before adding a suppression to this file, please attempt to suppress the output inside the generating tool instead
-
 # > Task :docs-runner:dokkaJavaPublicDocs
 (logging: loading modules: \[java\.se.*)|(.*No file found when processing Java @sample.*)
 # > Task :contentaccess:integration-tests:testapp:kaptDebugAndroidTestKotlin
 \[WARN\] Issue detected with androidx\.contentaccess\.compiler\.ContentAccessProcessor\. Expected 1 originating source file when generating [^ ]*, but detected [0-9][0-9]*: \[\]\.
 # > Task :icing:extractIncludeDebugAndroidTestProto
 proto file '[^ ]*' directly specified in configuration\. It's likely you specified files\('path/to/foo\.proto'\) or fileTree\('path/to/directory'\) in protobuf or compile configuration\. This makes you vulnerable to https://github\.com/google/protobuf\-gradle\-plugin/issues/[0-9][0-9]*\. Please use files\('path/to/directory'\) instead\.
-
+OUT_DIR=\$OUT_DIR
+DIST_DIR=\$DIST_DIR
+CHECKOUT=\$CHECKOUT
+Downloading file:\$SUPPORT/gradle/wrapper/\.\./\.\./\.\./\.\./tools/external/gradle/gradle\-[0-9]+\.[0-9]+\.[0-9]+\-bin\.zip
+\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.[0-9]+%\.\.\.\.\.\.\.\.\.\.[0-9]+%
+Welcome to Gradle [0-9]+\.[0-9]+\.[0-9]+!
+Here are the highlights of this release:
+\- Experimental file\-system watching
+\- Improved version ordering
+\- New samples
+For more details see https://docs\.gradle\.org/[0-9]+\.[0-9]+\.[0-9]+/release\-notes\.html
+To honour the JVM settings for this build a new JVM will be forked\. Please consider using the daemon: https://docs\.gradle\.org/[0-9]+\.[0-9]+\.[0-9]+/userguide/gradle_daemon\.html\.
+Daemon will be stopped at the end of the build stopping after processing
+# > Task :buildSrc:build
+> Configure project :appsearch:appsearch\-local\-backend
+WARNING: NDK was located by using ndk\.dir property\. This method is deprecated and will be removed in a future release\. Please use android\.ndkVersion or android\.ndkPath in build\.gradle to specify the NDK to use\. https://developer\.android\.com/r/studio\-ui/ndk\-dir
+NDK was located by using ndk\.dir property\. This method is deprecated and will be removed in a future release\. Please use android\.ndkVersion or android\.ndkPath in build\.gradle to specify the NDK to use\. https://developer\.android\.com/r/studio\-ui/ndk\-dir
+Configuration on demand is an incubating feature\.
+> Configure project :
+updated local\.properties
+> Configure project :compose:test\-utils
+Kotlin Multiplatform Projects are an Alpha feature\.
+The following Kotlin source sets were configured but not added to any Kotlin compilation:
+\* androidAndroidTestRelease
+\* androidTestRelease
+\* test
+You can add a source set to a target's compilation by connecting it with the compilation's default source set using 'dependsOn'\.
+See https://kotlinlang\.org/docs/reference/building\-mpp\-with\-gradle\.html\#connecting\-source\-sets
+The Kotlin source set test was configured but not added to any Kotlin compilation\. You can add a source set to a target's compilation by connecting it with the compilation's default source set using 'dependsOn'\.
+\* jvmMain
+# > Task :listTaskOutputs
+Wrote \$DIST_DIR/task_outputs\.txt
+See https://docs\.gradle\.org/[0-9]+\.[0-9]+\.[0-9]+/userguide/command_line_interface\.html\#sec:command_line_warnings
+BUILD SUCCESSFUL in [0-9]+m [0-9]+s
+[0-9]+ actionable task: [0-9]+ executed
+# > Task :docs-fake:processPublicReleaseMainManifest
+\$SUPPORT/docs\-fake/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+application@android:appComponentFactory was tagged at AndroidManifest\.xml:[0-9]+ to replace other declarations but no other declaration present
+# > Task :doclava:compileJava
+Note: Some input files use or override a deprecated API that is marked for removal\.
+Note: Recompile with \-Xlint:removal for details\.
+# > Task :test-screenshot:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/test\-screenshot_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :benchmark:benchmark-junit4:processDebugAndroidTestManifest
+\$SUPPORT/benchmark/junit[0-9]+/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.benchmark\.junit[0-9]+\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :benchmark:benchmark-common:processDebugAndroidTestManifest
+\$SUPPORT/benchmark/common/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :tracing:tracing:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/tracing/tracing/src/androidTest/java/androidx/tracing/TraceTest\.java uses or overrides a deprecated API\.
+# > Task :tracing:tracing-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/tracing\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :ui:ui-tooling:processDebugAndroidTestManifest
+\$SUPPORT/ui/ui\-tooling/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.ui\.tooling\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/ui/ui/ui\-tooling/build/intermediates/tmp/manifest/androidTest/debug/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+application@android:debuggable was tagged at manifestMerger[0-9]+\.xml:[0-9]+ to replace other declarations but no other declaration present
+# > Task :generateSdkApi
+javadoc: warning \- The old Doclet and Taglet APIs in the packages
+com\.sun\.javadoc, com\.sun\.tools\.doclets and their implementations
+are planned to be removed in a future JDK release\. These
+components have been superseded by the new APIs in jdk\.javadoc\.doclet\.
+Users are strongly recommended to migrate to the new APIs\.
+# > Task :compose:foundation:foundation-layout:processDebugAndroidTestManifest
+\$OUT_DIR/ui/compose/foundation/foundation\-layout/build/intermediates/tmp/manifest/androidTest/debug/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :benchmark:benchmark-junit4:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/benchmark\-junit[0-9]+_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :benchmark:benchmark-common:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/benchmark\-common_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:integration-tests:benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/compose/integration\-tests/benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.ui\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/ui/compose/integration\-tests/benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :compose:ui:ui-geometry:compileKotlinMetadata
+w: \$SUPPORT/compose/ui/ui\-geometry/src/commonMain/kotlin/androidx/compose/ui/geometry/Radius\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+# > Task :compose:navigation:navigation:processDebugAndroidTestManifest
+\$SUPPORT/compose/navigation/navigation/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.compose\.navigation\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :compose:runtime:runtime-saved-instance-state:processDebugAndroidTestManifest
+\$OUT_DIR/ui/compose/runtime/runtime\-saved\-instance\-state/build/intermediates/tmp/manifest/androidTest/debug/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :compose:runtime:runtime-dispatch:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/runtime\-dispatch_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:ui:ui-graphics:compileKotlinMetadata
+w: \$SUPPORT/compose/ui/ui\-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Color\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+w: \$SUPPORT/compose/ui/ui\-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Float[0-9]+\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+# > Task :distpublicDocs
+'Wrote API reference to \$DIST_DIR/androidx\-public\-docs\-[0-9]+\.zip
+# > Task :compose:runtime:runtime:benchmark:processReleaseAndroidTestManifest
+\$OUT_DIR/ui/compose/runtime/runtime/benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :compose:material:material-icons-extended:processDebugAndroidTestManifest
+\[:compose:material:material\-icons\-extended\] \$OUT_DIR/ui/compose/material/material\-icons\-extended/build/intermediates/library_manifest/debug/AndroidManifest\.xml Warning:
+Package name 'androidx\.compose\.material\.icons' used in: :compose:material:material\-icons\-extended, :compose:material:material\-icons\-core\.
+# > Task :compose:ui:ui-text-android:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui\-text\-android_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:ui:ui:compileKotlinMetadata
+w: Runtime JAR files in the classpath should have the same version\. These files were found in the classpath:
+\$CHECKOUT/prebuilts/androidx/external/org/jetbrains/kotlin/kotlin\-stdlib/[0-9]+\.[0-9]+\.[0-9]+/kotlin\-stdlib\-[0-9]+\.[0-9]+\.[0-9]+\.jar \(version [0-9]+\.[0-9]+\)
+\$CHECKOUT/prebuilts/androidx/external/org/jetbrains/kotlin/kotlin\-stdlib\-common/[0-9]+\.[0-9]+\.[0-9]+/kotlin\-stdlib\-common\-[0-9]+\.[0-9]+\.[0-9]+\.jar \(version [0-9]+\.[0-9]+\)
+w: Some runtime JAR files in the classpath have an incompatible version\. Consider removing them from the classpath
+w: \$SUPPORT/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/DrawLayerModifier\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+w: \$SUPPORT/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/VectorAssetBuilder\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+w: \$SUPPORT/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/input/key/Key\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+w: \$SUPPORT/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/Measured\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+w: \$SUPPORT/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DepthSortedSet\.kt: \([0-9]+, [0-9]+\): The corresponding parameter in the supertype 'Comparator' is named 'a'\. This may cause problems when calling this function with named arguments\.
+w: \$SUPPORT/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/DepthSortedSet\.kt: \([0-9]+, [0-9]+\): The corresponding parameter in the supertype 'Comparator' is named 'b'\. This may cause problems when calling this function with named arguments\.
+# > Task :compose:animation:animation:compileKotlinMetadata
+w: \$SUPPORT/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/PropertyKeys\.kt: \([0-9]+, [0-9]+\): 'PxBounds' is deprecated\. Use Rect instead
+w: \$SUPPORT/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/SingleValueAnimation\.kt: \([0-9]+, [0-9]+\): 'PxBounds' is deprecated\. Use Rect instead
+# > Task :compose:foundation:foundation:compileKotlinMetadata
+w: \$SUPPORT/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/lazy/LazyForState\.kt: \([0-9]+, [0-9]+\): The feature "inline classes" is experimental
+# > Task :benchmark:benchmark-common:runErrorProne
+\$SUPPORT/benchmark/common/src/main/java/androidx/benchmark/simpleperf/RecordOptions\.java:[0-9]+: warning: \[JavaTimeDefaultTimeZone\] LocalDateTime\.now\(\) is not allowed because it silently uses the system default time\-zone\. You must pass an explicit time\-zone \(e\.g\., ZoneId\.of\("America/Los_Angeles"\)\) to this method\.
+LocalDateTime time = LocalDateTime\.now\(\);
+\^
+\(see https://errorprone\.info/bugpattern/JavaTimeDefaultTimeZone\)
+Did you mean 'LocalDateTime time = LocalDateTime\.now\(ZoneId\.systemDefault\(\)\);'\?
+[0-9]+ warning
+# > Task :compose:runtime:runtime:generateApi
+src/commonMain/kotlin/androidx/compose/runtime/Composer\.kt:[0-9]+: warning: Field ComposerKt\.ambientMap references hidden type androidx\.compose\.runtime\.OpaqueKey\. \[HiddenTypeParameter\]
+src/commonMain/kotlin/androidx/compose/runtime/Composer\.kt:[0-9]+: warning: Field ComposerKt\.invocation references hidden type androidx\.compose\.runtime\.OpaqueKey\. \[HiddenTypeParameter\]
+src/commonMain/kotlin/androidx/compose/runtime/Composer\.kt:[0-9]+: warning: Field ComposerKt\.provider references hidden type androidx\.compose\.runtime\.OpaqueKey\. \[HiddenTypeParameter\]
+src/commonMain/kotlin/androidx/compose/runtime/Composer\.kt:[0-9]+: warning: Field ComposerKt\.providerMaps references hidden type androidx\.compose\.runtime\.OpaqueKey\. \[HiddenTypeParameter\]
+src/commonMain/kotlin/androidx/compose/runtime/Composer\.kt:[0-9]+: warning: Field ComposerKt\.providerValues references hidden type androidx\.compose\.runtime\.OpaqueKey\. \[HiddenTypeParameter\]
+src/commonMain/kotlin/androidx/compose/runtime/Composer\.kt:[0-9]+: warning: Field ComposerKt\.reference references hidden type androidx\.compose\.runtime\.OpaqueKey\. \[HiddenTypeParameter\]
+# > Task :compose:ui:ui-geometry:generateApi
+src/commonMain/kotlin/androidx/compose/ui/geometry/MutableRect\.kt:[0-9]+: info: Note that adding the `operator` keyword would allow calling this method using operator syntax \[KotlinOperator\]
+# > Task :compose:animation:animation-core:generateApi
+src/commonMain/kotlin/androidx/compose/animation/core/AnimationClock\.kt:[0-9]+: warning: Field BaseAnimationClock\.Companion references hidden type androidx\.compose\.animation\.core\.BaseAnimationClock\.Companion\. \[HiddenTypeParameter\]
+# > Task :compose:ui:ui-unit:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui\-unit_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:foundation:foundation-layout:generateApi
+src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl\.kt:[0-9]+: warning: Parameter orientation references hidden type androidx\.compose\.foundation\.layout\.LayoutOrientation\. \[HiddenTypeParameter\]
+src/commonMain/kotlin/androidx/compose/foundation/layout/RowColumnImpl\.kt:[0-9]+: warning: Parameter crossAxisAlignment references hidden type androidx\.compose\.foundation\.layout\.CrossAxisAlignment\. \[HiddenTypeParameter\]
+# > Task :compose:animation:animation:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/animation_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:runtime:runtime-livedata:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/runtime\-livedata_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:foundation:foundation-text:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/foundation\-text_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:runtime:runtime:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/runtime_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:navigation:navigation:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:foundation:foundation:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/foundation_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:runtime:runtime-rxjava2:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/runtime\-rxjava[0-9]+_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:runtime:runtime-saved-instance-state:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/runtime\-saved\-instance\-state_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:ui:ui-graphics:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui\-graphics_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:ui:ui-text:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui\-text_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:ui:ui-viewbinding:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui\-viewbinding_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:foundation:foundation-layout:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/foundation\-layout_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:test-utils:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/test\-utils_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:integration-tests:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/integration\-tests_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :ui:ui-test:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui\-test_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :ui:ui-tooling:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui\-tooling_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:ui:ui:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/ui_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :compose:material:material:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/material_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :disttipOfTreeDocs
+'Wrote API reference to \$DIST_DIR/androidx\-tipOfTree\-docs\-[0-9]+\.zip
+# > Task :compose:material:material-icons-extended:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/material\-icons\-extended_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :buildOnServer
+[0-9]+ actionable tasks: [0-9]+ executed, [0-9]+ up\-to\-date
+[0-9]+ actionable tasks: [0-9]+ executed, [0-9]+ from cache, [0-9]+ up\-to\-date
+[0-9]+ actionable tasks: [0-9]+ executed, [0-9]+ from cache
+# > Task :lifecycle:lifecycle-common:compileJava
+Note: \$SUPPORT/lifecycle/lifecycle\-common/src/main/java/androidx/lifecycle/Lifecycling\.java uses or overrides a deprecated API\.
+# > Task :concurrent:concurrent-futures:compileJava
+Note: \$SUPPORT/concurrent/futures/src/main/java/androidx/concurrent/futures/CallbackToFutureAdapter\.java uses or overrides a deprecated API\.
+# > Task :contentpager:contentpager:compileReleaseJavaWithJavac
+Note: \$SUPPORT/contentpager/contentpager/src/main/java/androidx/contentpager/content/LoaderQueryRunner\.java uses or overrides a deprecated API\.
+# > Task :coordinatorlayout:coordinatorlayout:compileReleaseJavaWithJavac
+Note: \$SUPPORT/coordinatorlayout/coordinatorlayout/src/main/java/androidx/coordinatorlayout/widget/CoordinatorLayout\.java uses or overrides a deprecated API\.
+# > Task :customview:customview:compileReleaseJavaWithJavac
+Note: \$SUPPORT/customview/customview/src/main/java/androidx/customview/widget/ExploreByTouchHelper\.java uses or overrides a deprecated API\.
+# > Task :recommendation:recommendation:compileReleaseJavaWithJavac
+Note: \$SUPPORT/recommendation/recommendation/src/main/java/androidx/recommendation/app/ContentRecommendation\.java uses or overrides a deprecated API\.
+# > Task :textclassifier:textclassifier:compileReleaseJavaWithJavac
+Note: \$SUPPORT/textclassifier/textclassifier/src/main/java/androidx/textclassifier/TextClassifier\.java uses or overrides a deprecated API\.
+# > Task :publicDocsTask
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ByteArrayFrame\.java:[0-9]+: error: cannot find symbol
+import androidx\.media[0-9]+\.exoplayer\.external\.Format;
+symbol:   class Format
+location: package androidx\.media[0-9]+\.exoplayer\.external
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ByteArrayFrame\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.metadata does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.metadata\.Metadata;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ByteArrayFrame\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.util does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.util\.Util;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ByteArrayFrame\.java:[0-9]+: error: package Metadata does not exist
+/\* package \*/ final class ByteArrayFrame implements Metadata\.Entry \{
+public static final Creator<ByteArrayFrame> CREATOR =
+symbol:   class Creator
+location: class ByteArrayFrame
+public Format getWrappedMetadataFormat\(\) \{
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/DataSourceCallbackDataSource\.java:[0-9]+: error: cannot find symbol
+import androidx\.media[0-9]+\.exoplayer\.external\.C;
+symbol:   class C
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/DataSourceCallbackDataSource\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.upstream does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.upstream\.BaseDataSource;
+import androidx\.media[0-9]+\.exoplayer\.external\.upstream\.DataSource;
+import androidx\.media[0-9]+\.exoplayer\.external\.upstream\.DataSpec;
+/\* package \*/ final class DataSourceCallbackDataSource extends BaseDataSource \{
+symbol: class BaseDataSource
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/DataSourceCallbackDataSource\.java:[0-9]+: error: package DataSource does not exist
+static DataSource\.Factory getFactory\(
+public long open\(DataSpec dataSpec\) throws IOException \{
+symbol:   class DataSpec
+location: class DataSourceCallbackDataSource
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerMediaPlayer[0-9]+Impl\.java:[0-9]+: error: cannot find symbol
+import androidx\.media[0-9]+\.exoplayer\.external\.Player;
+symbol:   class Player
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: cannot find symbol
+import androidx\.media[0-9]+\.exoplayer\.external\.ExoPlaybackException;
+symbol:   class ExoPlaybackException
+import androidx\.media[0-9]+\.exoplayer\.external\.SimpleExoPlayer;
+symbol:   class SimpleExoPlayer
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.audio does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.AudioAttributes;
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.AudioCapabilities;
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.AudioListener;
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.AudioProcessor;
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.AuxEffectInfo;
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.DefaultAudioSink;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.decoder does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.decoder\.DecoderCounters;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.metadata does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.metadata\.MetadataOutput;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.source does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.source\.ClippingMediaSource;
+import androidx\.media[0-9]+\.exoplayer\.external\.source\.ConcatenatingMediaSource;
+import androidx\.media[0-9]+\.exoplayer\.external\.source\.MediaSource;
+import androidx\.media[0-9]+\.exoplayer\.external\.source\.TrackGroup;
+import androidx\.media[0-9]+\.exoplayer\.external\.source\.TrackGroupArray;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.trackselection does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.trackselection\.TrackSelectionArray;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.upstream does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.upstream\.DefaultBandwidthMeter;
+import androidx\.media[0-9]+\.exoplayer\.external\.upstream\.DefaultDataSourceFactory;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.util does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.util\.MimeTypes;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.video does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.video\.VideoRendererEventListener;
+private final DefaultBandwidthMeter mBandwidthMeter;
+symbol:   class DefaultBandwidthMeter
+location: class ExoPlayerWrapper
+private SimpleExoPlayer mPlayer;
+private DefaultAudioSink mAudioSink;
+symbol:   class DefaultAudioSink
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/RenderersFactory\.java:[0-9]+: error: cannot find symbol
+import androidx\.media[0-9]+\.exoplayer\.external\.Renderer;
+symbol:   class Renderer
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/RenderersFactory\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.audio does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.AudioRendererEventListener;
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.AudioSink;
+import androidx\.media[0-9]+\.exoplayer\.external\.audio\.MediaCodecAudioRenderer;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/RenderersFactory\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.drm does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.drm\.DrmSessionManager;
+import androidx\.media[0-9]+\.exoplayer\.external\.drm\.FrameworkMediaCrypto;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/RenderersFactory\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.mediacodec does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.mediacodec\.MediaCodecSelector;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/RenderersFactory\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.metadata does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.metadata\.MetadataRenderer;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/RenderersFactory\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.text does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.text\.TextOutput;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/RenderersFactory\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.video does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.video\.MediaCodecVideoRenderer;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/TextRenderer\.java:[0-9]+: error: cannot find symbol
+import androidx\.media[0-9]+\.exoplayer\.external\.BaseRenderer;
+symbol:   class BaseRenderer
+import androidx\.media[0-9]+\.exoplayer\.external\.FormatHolder;
+symbol:   class FormatHolder
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/TextRenderer\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.text does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.text\.SubtitleInputBuffer;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/TextRenderer\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.util does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.util\.ParsableByteArray;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/TrackSelector\.java:[0-9]+: error: cannot find symbol
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/TrackSelector\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.source does not exist
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/TrackSelector\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.trackselection does not exist
+import androidx\.media[0-9]+\.exoplayer\.external\.trackselection\.DefaultTrackSelector;
+import androidx\.media[0-9]+\.exoplayer\.external\.trackselection\.MappingTrackSelector;
+import androidx\.media[0-9]+\.exoplayer\.external\.trackselection\.TrackSelection;
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/TrackSelector\.java:[0-9]+: error: package androidx\.media[0-9]+\.exoplayer\.external\.util does not exist
+implements androidx\.media[0-9]+\.exoplayer\.external\.RenderersFactory \{
+symbol:   class RenderersFactory
+/\* package \*/ class TextRenderer extends BaseRenderer \{
+symbol: class BaseRenderer
+void handlePlayerTracksChanged\(TrackSelectionArray trackSelections\) \{
+symbol:   class TrackSelectionArray
+void handlePlayerError\(ExoPlaybackException exception\) \{
+void handleMetadata\(Metadata metadata\) \{
+symbol:   class Metadata
+final DefaultAudioSink audioSink,
+private final SimpleExoPlayer mPlayer;
+location: class MediaItemQueue
+\$OUT_DIR/androidx/docs\-fake/build/tmp/expandedArchives/media[0-9]+\-player\-[0-9]+\.[0-9]+\.[0-9]+\-beta[0-9]+\-sources\.jar_[0-9a-f]{32}/androidx/media[0-9]+/player/ExoPlayerWrapper\.java:[0-9]+: error: package DataSource does not exist
+private final DataSource\.Factory mDataSourceFactory;
+private final ConcatenatingMediaSource mConcatenatingMediaSource;
+symbol:   class ConcatenatingMediaSource
+MediaItemQueue\(Context context, SimpleExoPlayer player, Listener listener\) \{
+Collection<MediaSource> mediaSources\) \{
+symbol:   class MediaSource
+private final DefaultTrackSelector mDefaultTrackSelector;
+symbol:   class DefaultTrackSelector
+location: class TrackSelector
+public DefaultTrackSelector getPlayerTrackSelector\(\) \{
+public void handlePlayerTracksChanged\(MediaItem item, TrackSelectionArray trackSelections\) \{
+private final AudioSink mAudioSink;
+symbol:   class AudioSink
+location: class RenderersFactory
+AudioSink audioSink,
+VideoRendererEventListener videoRendererEventListener,
+symbol:   class VideoRendererEventListener
+AudioRendererEventListener audioRendererEventListener,
+symbol:   class AudioRendererEventListener
+TextOutput textRendererOutput,
+symbol:   class TextOutput
+MetadataOutput metadataRendererOutput,
+symbol:   class MetadataOutput
+@Nullable DrmSessionManager<FrameworkMediaCrypto> drmSessionManager\) \{
+symbol:   class DrmSessionManager
+symbol:   class FrameworkMediaCrypto
+public Renderer\[\] createRenderers\(
+private final ParsableByteArray mCcData;
+symbol:   class ParsableByteArray
+location: class TextRenderer
+private final FormatHolder mFormatHolder;
+private final SubtitleInputBuffer mInputBuffer;
+symbol:   class SubtitleInputBuffer
+private final ParsableByteArray mScratch;
+public int supportsFormat\(Format format\) \{
+[0-9]+ warnings
+# > Task :appsearch:appsearch-local-backend:externalNativeBuildRelease
+ninja: no work to do\.
+Build icing_armeabi\-v[0-9]+a
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/release/armeabi\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/io_win[0-9]+\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/zero_copy_stream\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/statusor\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/bytestream\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/strtod\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/arena\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/gzip_stream\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/time\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/zero_copy_stream_impl\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/status\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/structurally_valid\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/any_lite\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/implicit_weak_message\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/generated_enum_util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/stringprintf\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/service\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/int[0-9]+\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/stringpiece\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/mathlimits\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/any\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/common\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/message_lite\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/empty\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/wire_format_lite\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/any\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/coded_stream\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/substitute\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/error_listener\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/delimited_message_util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object icu\-target/CMakeFiles/libandroidicu\.dir/static_shim/shim\.cpp\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/parse_context\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/field_mask\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/tokenizer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/duration\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/unknown_field_set\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_escaping\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/timestamp\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/io/printer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/field_comparator\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/api\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/stubs/strutil\.cc\.o
+\[[0-9]+/[0-9]+\] Linking CXX static library icu\-target/liblibandroidicu\.a
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/source_context\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/object_writer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/generated_message_util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/compiler/importer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.cc\.o
+In file included from \$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.cc:[0-9]+:
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'StartObject' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* StartObject\(StringPiece name\);
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/object_writer\.h:[0-9]+:[0-9]+: note: overridden virtual function is here
+virtual ObjectWriter\* StartObject\(StringPiece name\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'EndObject' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* EndObject\(\);
+virtual ObjectWriter\* EndObject\(\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'StartList' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* StartList\(StringPiece name\);
+virtual ObjectWriter\* StartList\(StringPiece name\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'EndList' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* EndList\(\);
+virtual ObjectWriter\* EndList\(\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderBool' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderBool\(StringPiece name, bool value\);
+virtual ObjectWriter\* RenderBool\(StringPiece name, bool value\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderInt[0-9]+' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderInt[0-9]+\(StringPiece name, int[0-9]+ value\);
+virtual ObjectWriter\* RenderInt[0-9]+\(StringPiece name, int[0-9]+ value\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderUint[0-9]+' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderUint[0-9]+\(StringPiece name, uint[0-9]+ value\);
+virtual ObjectWriter\* RenderUint[0-9]+\(StringPiece name, uint[0-9]+ value\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderDouble' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderDouble\(StringPiece name, double value\);
+virtual ObjectWriter\* RenderDouble\(StringPiece name, double value\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderFloat' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderFloat\(StringPiece name, float value\);
+virtual ObjectWriter\* RenderFloat\(StringPiece name, float value\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderString' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderString\(StringPiece name,
+virtual ObjectWriter\* RenderString\(StringPiece name,
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderBytes' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderBytes\(StringPiece name, StringPiece value\);
+virtual ObjectWriter\* RenderBytes\(StringPiece name, StringPiece value\) = [0-9]+;
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderNull' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual JsonObjectWriter\* RenderNull\(StringPiece name\);
+virtual ObjectWriter\* RenderNull\(StringPiece name\) = [0-9]+;
+[0-9]+ warnings generated\.
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/reflection_ops\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/extension_set_heavy\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/json_stream_parser\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/repeated_field\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/dynamic_message\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/field_mask_util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/field_mask_utility\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/type_info_test_helper\.cc\.o
+In file included from \$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/type_info_test_helper\.cc:[0-9]+:
+In file included from \$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/type_info_test_helper\.h:[0-9]+:
+\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/default_value_objectwriter\.h:[0-9]+:[0-9]+: warning: 'RenderNull' overrides a member function but is not marked 'override' \[\-Winconsistent\-missing\-override\]
+virtual DefaultValueObjectWriter\* RenderNull\(StringPiece name\);
+[0-9]+ warning generated\.
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/time_util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/utility\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/type\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/json_util\.cc\.o
+In file included from \$CHECKOUT/external/protobuf/src/google/protobuf/util/json_util\.cc:[0-9]+:
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/map_field\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/datapiece\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/type_info\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/generated_message_table_driven_lite\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/type_resolver_util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/generated_message_reflection\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/protostream_objectsource\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/extension_set\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/default_value_objectwriter\.cc\.o
+In file included from \$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/default_value_objectwriter\.cc:[0-9]+:
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/struct\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/wrappers\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/message\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/generated_message_table_driven\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/proto_writer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/wire_format\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/compiler/parser\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/internal/protostream_objectwriter\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/descriptor_database\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/text_format\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/util/message_differencer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/descriptor\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object protobuf\-target/CMakeFiles/libprotobuf\.dir\$CHECKOUT/external/protobuf/src/google/protobuf/descriptor\.cc\.o
+\[[0-9]+/[0-9]+\] Linking CXX static library protobuf\-target/libprotobuf\.a
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/reset\.pb\.cc, icing\-protobuf\-gen/icing/proto/reset\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/term\.pb\.cc, icing\-protobuf\-gen/icing/proto/term\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/status\.pb\.cc, icing\-protobuf\-gen/icing/proto/status\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/scoring\.pb\.cc, icing\-protobuf\-gen/icing/proto/scoring\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/initialize\.pb\.cc, icing\-protobuf\-gen/icing/proto/initialize\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/optimize\.pb\.cc, icing\-protobuf\-gen/icing/proto/optimize\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/legacy/index/proto/icing\-dynamic\-trie\-header\.pb\.cc, icing\-protobuf\-gen/icing/legacy/index/proto/icing\-dynamic\-trie\-header\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/persist\.pb\.cc, icing\-protobuf\-gen/icing/proto/persist\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/document_wrapper\.pb\.cc, icing\-protobuf\-gen/icing/proto/document_wrapper\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/document\.pb\.cc, icing\-protobuf\-gen/icing/proto/document\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/search\.pb\.cc, icing\-protobuf\-gen/icing/proto/search\.pb\.h
+\[[0-9]+/[0-9]+\] Generating icing\-protobuf\-gen/icing/proto/schema\.pb\.cc, icing\-protobuf\-gen/icing/proto/schema\.pb\.h
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/absl_ports/canonical_errors\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/core/icing\-timer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/absl_ports/str_cat\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/core/icing\-string\-util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/text_classifier/lib[0-9]+/utils/base/logging\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/file/memory\-mapped\-file\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/term\-id\-codec\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/text_classifier/lib[0-9]+/utils/base/logging_raw\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-mmapper\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/absl_ports/annotate\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-storage\-file\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/text_classifier/lib[0-9]+/utils/java/jni\-base\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/util/clock\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/jni/jni\-cache\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/text_classifier/lib[0-9]+/utils/base/status\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/hit/hit\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/hit/doc\-hit\-info\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/file/file\-backed\-bitmap\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/tokenization/reverse_jni/reverse\-jni\-language\-segmenter\-factory\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-flash\-bitmap\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-array\-storage\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-storage\-collection\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/text_classifier/lib[0-9]+/utils/hash/farmhash\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/transform/map/map\-normalizer\-factory\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/tokenization/raw\-query\-tokenizer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/text_classifier/lib[0-9]+/utils/java/jni\-helper\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/iterator/doc\-hit\-info\-iterator\-all\-document\-id\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/file/filesystem\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/main/index\-block\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/util/crc[0-9]+\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/tokenization/plain\-tokenizer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/iterator/doc\-hit\-info\-iterator\-not\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-lite\-index\-options\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/term\-property\-id\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/tokenization/reverse_jni/reverse\-jni\-language\-segmenter\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-filesystem\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/main/posting\-list\-used\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/transform/map/normalization\-map\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/jni/reverse\-jni\-break\-iterator\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/transform/map/map\-normalizer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/iterator/doc\-hit\-info\-iterator\-or\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/util/i[0-9]+n\-utils\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/performance\-configuration\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/main/posting\-list\-utils\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/iterator/doc\-hit\-info\-iterator\-section\-restrict\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/index\-processor\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/tokenization/tokenizer\-factory\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/index\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/scoring/ranker\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/result/result\-state\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/iterator/doc\-hit\-info\-iterator\-and\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/iterator/doc\-hit\-info\-iterator\-filter\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/iterator/doc\-hit\-info\-iterator\-term\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/document_wrapper\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/jni/icing\-search\-engine\-jni\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/scoring/scoring\-processor\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/optimize\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/initialize\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/term\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/persist\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/index/lite/lite\-index\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/result/result\-retriever\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/legacy/index/proto/icing\-dynamic\-trie\-header\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/scoring/scorer\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/reset\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/scoring\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/status\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/result/snippet\-retriever\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/util/document\-validator\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/document\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/schema/schema\-util\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/query/query\-processor\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/schema\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/schema/section\-manager\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/result/result\-state\-manager\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/schema/schema\-store\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/legacy/index/icing\-dynamic\-trie\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing\-protobuf\-gen/icing/proto/search\.pb\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/icing\-search\-engine\.cc\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/icing\.dir/icing/store/document\-store\.cc\.o
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/release/obj/armeabi\-v[0-9]+a/libicing\.so
+Build icing_arm[0-9]+\-v[0-9]+a
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/release/arm[0-9]+\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/release/obj/arm[0-9]+\-v[0-9]+a/libicing\.so
+Build icing_x[0-9]+
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/release/x[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/release/obj/x[0-9]+/libicing\.so
+Build icing_x[0-9]+_[0-9]+
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/release/x[0-9]+_[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/release/obj/x[0-9]+_[0-9]+/libicing\.so
+# > Task :support-animation-demos:compileDebugJavaWithJavac
+Note: \$SUPPORT/samples/SupportAnimationDemos/src/main/java/com/example/android/support/animation/SpringView\.java uses or overrides a deprecated API\.
+# > Task :lint-demos:lint-demo-appcompat:compileDebugJavaWithJavac
+Note: \$SUPPORT/lint\-demos/lint\-demo\-appcompat/src/main/java/com/example/android/appcompat/AppCompatLintDemo\.java uses or overrides a deprecated API\.
+# > Task :support-transition-demos:compileDebugJavaWithJavac
+Note: \$SUPPORT/samples/SupportTransitionDemos/src/main/java/com/example/android/support/transition/widget/FragmentTransitionUsage\.java uses or overrides a deprecated API\.
+# > Task :support-content-demos:compileDebugJavaWithJavac
+Note: \$SUPPORT/samples/SupportContentDemos/src/main/java/com/example/android/support/content/demos/ContentPagerDemoActivity\.java uses or overrides a deprecated API\.
+# > Task :support-preference-demos:compileDebugJavaWithJavac
+Note: \$SUPPORT/samples/SupportPreferenceDemos/src/main/java/com/example/androidx/preference/LeanbackPreferences\.java uses or overrides a deprecated API\.
+# > Task :startup:integration-tests:first-library:processDebugManifest
+\$SUPPORT/startup/integration\-tests/first\-library/src/main/AndroidManifest\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+provider\#androidx\.work\.impl\.WorkManagerInitializer was tagged at AndroidManifest\.xml:[0-9]+ to remove other declarations but no other declaration present
+# > Task :camera:integration-tests:camera-testapp-extensions:compileDebugJavaWithJavac
+Note: \$SUPPORT/camera/integration\-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity\.java uses or overrides a deprecated API\.
+# > Task :camera:integration-tests:camera-testapp-core:compileDebugJavaWithJavac
+Note: \$SUPPORT/camera/integration\-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity\.java uses or overrides a deprecated API\.
+# > Task :room:integration-tests:room-testapp:processDebugMainManifest
+\[androidx\.vectordrawable:vectordrawable\-animated:[0-9]+\.[0-9]+\.[0-9]+\] \$OUT_DIR/\.gradle/caches/transforms\-[0-9]+/files\-[0-9]+\.[0-9]+/[0-9a-f]{32}/vectordrawable\-animated\-[0-9]+\.[0-9]+\.[0-9]+/AndroidManifest\.xml Warning:
+Package name 'androidx\.vectordrawable' used in: androidx\.vectordrawable:vectordrawable\-animated:[0-9]+\.[0-9]+\.[0-9]+, androidx\.vectordrawable:vectordrawable:[0-9]+\.[0-9]+\.[0-9]+\.
+# > Task :lifecycle:integration-tests:lifecycle-testapp:compileDebugJavaWithJavac
+Note: \$SUPPORT/lifecycle/integration\-tests/testapp/src/main/java/androidx/lifecycle/testapp/FrameworkLifecycleRegistryActivity\.java uses or overrides a deprecated API\.
+# > Task :support-slices-demos:compileDebugJavaWithJavac
+Note: \$SUPPORT/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser\.java uses unchecked or unsafe operations\.
+# > Task :ads-identifier:processDebugAndroidTestManifest
+\$SUPPORT/ads/ads\-identifier/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.ads\.identifier\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :sharetarget:integration-tests:testapp:compileDebugJavaWithJavac
+Note: \$SUPPORT/sharetarget/integration\-tests/testapp/src/main/java/androidx/sharetarget/testapp/MainActivity\.java uses or overrides a deprecated API\.
+# > Task :ads-identifier-provider:processDebugAndroidTestManifest
+\$SUPPORT/ads/ads\-identifier\-provider/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.ads\.identifier\.provider\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :hilt:integration-tests:hilt-testapp-viewmodel:compileDebugJavaWithJavac
+Note: \$OUT_DIR/androidx/hilt/integration\-tests/hilt\-testapp\-viewmodel/build/generated/source/kapt/debug/androidx/hilt/integration/viewmodelapp/Hilt_SimpleFragment\.java uses or overrides a deprecated API\.
+# > Task :ads-identifier-benchmark:processReleaseAndroidTestManifest
+\$OUT_DIR/androidx/ads\-identifier\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :internal-testutils-runtime:processDebugAndroidTestManifest
+\$SUPPORT/testutils/testutils\-runtime/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.testutils\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :slice-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/slices/benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.slice\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/slice\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :internal-testutils-runtime:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/internal\-testutils\-runtime_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :internal-testutils-navigation:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/internal\-testutils\-navigation_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :slice-builders-ktx:processDebugAndroidTestManifest
+\$SUPPORT/slices/builders/ktx/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.slice\.builders\.ktx\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :slice-core:processDebugAndroidTestManifest
+\$SUPPORT/slices/core/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.slice\.core\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :slice-remotecallback:processDebugAndroidTestManifest
+\$SUPPORT/slices/remotecallback/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.slice\.remotecallback\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :slice-view:processDebugAndroidTestManifest
+\$SUPPORT/slices/view/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.slice\.view\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :slice-benchmark:compileReleaseAndroidTestJavaWithJavac
+Note: \$SUPPORT/slices/benchmark/src/androidTest/java/androidx/slice/SliceSerializeMetrics\.java uses or overrides a deprecated API\.
+# > Task :slice-builders-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/slice\-builders\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :support-media-test-client:processDebugAndroidTestManifest
+\$SUPPORT/media/version\-compat\-tests/current/client/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'android\.support\.mediacompat\.client\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :support-media-test-client-previous:processDebugAndroidTestManifest
+\$SUPPORT/media/version\-compat\-tests/previous/client/src/androidTest/AndroidManifest\.xml Warning:
+# > Task :support-media-test-service:processDebugAndroidTestManifest
+\$SUPPORT/media/version\-compat\-tests/current/service/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'android\.support\.mediacompat\.service\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :support-media-test-service-previous:processDebugAndroidTestManifest
+\$SUPPORT/media/version\-compat\-tests/previous/service/src/androidTest/AndroidManifest\.xml Warning:
+# > Task :support-media2-test-client:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/session/version\-compat\-tests/current/client/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.media[0-9]+\.test\.client\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :support-media-test-service:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/media/version\-compat\-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest\.java uses or overrides a deprecated API\.
+# > Task :support-media2-test-client-previous:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/session/version\-compat\-tests/previous/client/src/androidTest/AndroidManifest\.xml Warning:
+# > Task :support-media2-test-service:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/session/version\-compat\-tests/current/service/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.media[0-9]+\.test\.service\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :support-media2-test-service-previous:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/session/version\-compat\-tests/previous/service/src/androidTest/AndroidManifest\.xml Warning:
+# > Task :support-media-test-client:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/media/version\-compat\-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaControllerCompatCallbackTest\.java uses or overrides a deprecated API\.
+# > Task :support-media2-test-service:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/media[0-9]+/session/version\-compat\-tests/current/service/src/androidTest/java/androidx/media[0-9]+/test/service/MockPlayer\.java uses unchecked or unsafe operations\.
+# > Task :support-media2-test-service-previous:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/media[0-9]+/session/version\-compat\-tests/previous/service/src/androidTest/java/androidx/media[0-9]+/test/service/MockPlayer\.java uses unchecked or unsafe operations\.
+# > Task :activity:activity:processDebugAndroidTestManifest
+\$SUPPORT/activity/activity/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.activity\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :appcompat:appcompat:processDebugAndroidTestManifest
+\[:internal\-testutils\-appcompat\] \$OUT_DIR/androidx/internal\-testutils\-appcompat/build/intermediates/library_manifest/debug/AndroidManifest\.xml Warning:
+Package name 'androidx\.testutils' used in: :internal\-testutils\-appcompat, :internal\-testutils\-runtime\.
+# > Task :appcompat:appcompat-resources:processDebugAndroidTestManifest
+\$SUPPORT/appcompat/appcompat\-resources/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.appcompat\.resources\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :appcompat:appcompat-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/appcompat/appcompat\-benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.appcompat\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/appcompat/appcompat\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :activity:activity-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/activity\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :benchmark:benchmark-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/benchmark/benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.benchmark\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/benchmark/benchmark\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :camera:camera-camera2:processDebugAndroidTestManifest
+\$SUPPORT/camera/camera\-camera[0-9]+/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.camera\.camera[0-9]+\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :camera:camera-core:processDebugAndroidTestManifest
+\$SUPPORT/camera/camera\-core/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.camera\.core\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :camera:camera-extensions:processDebugAndroidTestManifest
+\$SUPPORT/camera/camera\-extensions/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.camera\.extensions\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :camera:camera-lifecycle:processDebugAndroidTestManifest
+\$SUPPORT/camera/camera\-lifecycle/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.camera\.lifecycle\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :camera:camera-testing:externalNativeBuildDebug
+Build testing_surface_format_jni_armeabi\-v[0-9]+a
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/debug/armeabi\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/testing_surface_format_jni\.dir/surface_format_jni\.cpp\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/testing_surface_format_jni\.dir/jni_hooks\.cpp\.o
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/debug/obj/armeabi\-v[0-9]+a/libtesting_surface_format_jni\.so
+Build testing_surface_format_jni_arm[0-9]+\-v[0-9]+a
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/debug/arm[0-9]+\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/debug/obj/arm[0-9]+\-v[0-9]+a/libtesting_surface_format_jni\.so
+Build testing_surface_format_jni_x[0-9]+
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/debug/x[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/debug/obj/x[0-9]+/libtesting_surface_format_jni\.so
+Build testing_surface_format_jni_x[0-9]+_[0-9]+
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/debug/x[0-9]+_[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/debug/obj/x[0-9]+_[0-9]+/libtesting_surface_format_jni\.so
+# > Task :tipOfTreeDocsTask
+\$OUT_DIR/androidx/sqlite/sqlite\-inspection/build/generated/source/proto/release/java/androidx/sqlite/inspection/SqliteInspectorProtocol\.java:[0-9]+: error: cannot find symbol
+public static com\.google\.protobuf\.Internal\.EnumVerifier
+symbol:   class EnumVerifier
+location: class Internal
+com\.google\.protobuf\.Internal\.EnumVerifier \{
+static final com\.google\.protobuf\.Internal\.EnumVerifier           INSTANCE = new ErrorCodeVerifier\(\);
+\$OUT_DIR/androidx/work/work\-inspection/build/generated/source/proto/release/java/androidx/work/inspection/WorkManagerInspectorProtocol\.java:[0-9]+: error: cannot find symbol
+static final com\.google\.protobuf\.Internal\.EnumVerifier           INSTANCE = new StateVerifier\(\);
+static final com\.google\.protobuf\.Internal\.EnumVerifier           INSTANCE = new NetworkTypeVerifier\(\);
+\$SUPPORT/annotation/annotation\-experimental\-lint/integration\-tests/src/main/java/sample/UseJavaExperimentalFromJava\.java:[0-9]+: error: annotation value not of an allowable type
+@UseExperimental\(markerClass = \{ ExperimentalDateTime\.class, ExperimentalLocation\.class \}\)
+\$CHECKOUT/prebuilts/androidx/external/com/android/tools/external/com\-intellij/intellij\-core/[0-9]+\.[0-9]+\.[0-9]+/intellij\-core\-[0-9]+\.[0-9]+\.[0-9]+\.jar\(/javax/annotation/meta/TypeQualifierNickname\.java\):[0-9]+: lint: Invalid tag: @Documented \[[0-9]+\]
+\$CHECKOUT/prebuilts/androidx/external/com/android/tools/external/com\-intellij/intellij\-core/[0-9]+\.[0-9]+\.[0-9]+/intellij\-core\-[0-9]+\.[0-9]+\.[0-9]+\.jar\(/javax/annotation/meta/TypeQualifierNickname\.java\):[0-9]+: lint: Invalid tag: @TypeQualifierNickname \[[0-9]+\]
+\$CHECKOUT/prebuilts/androidx/external/com/android/tools/external/com\-intellij/intellij\-core/[0-9]+\.[0-9]+\.[0-9]+/intellij\-core\-[0-9]+\.[0-9]+\.[0-9]+\.jar\(/javax/annotation/meta/TypeQualifierNickname\.java\):[0-9]+: lint: Invalid tag: @Retention\(RetentionPolicy\.RUNTIME\) \[[0-9]+\]
+# > Task :camera:camera-camera2-pipe-integration:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/camera\-camera[0-9]+\-pipe\-integration_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :collection:collection-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/collection/collection\-benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.collection\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/collection/collection\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :camera:camera-extensions:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/camera/camera\-extensions/src/androidTest/java/androidx/camera/extensions/PreviewExtenderTest\.java uses unchecked or unsafe operations\.
+# > Task :camera:camera-camera2-pipe:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/camera\-camera[0-9]+\-pipe_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :customview:customview:processDebugAndroidTestManifest
+\$SUPPORT/customview/customview/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.customview\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :core:core-ktx:processDebugAndroidTestManifest
+\$SUPPORT/core/core\-ktx/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.core\.ktx\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :appsearch:appsearch:processDebugAndroidTestManifest
+\$SUPPORT/appsearch/appsearch/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.appsearch\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :customview:customview:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/customview/customview/src/androidTest/java/androidx/customview/widget/ExploreByTouchHelperTest\.java uses or overrides a deprecated API\.
+# > Task :datastore:datastore-core:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/datastore\-core_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :core:core:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/core/core/src/androidTest/java/androidx/core/content/pm/ShortcutManagerCompatTest\.java uses unchecked or unsafe operations\.
+# > Task :datastore:datastore-preferences:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/datastore\-preferences_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :core:core-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/core\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :drawerlayout:drawerlayout:processDebugAndroidTestManifest
+\$SUPPORT/drawerlayout/drawerlayout/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.drawerlayout\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :dynamicanimation:dynamicanimation:processDebugAndroidTestManifest
+\$SUPPORT/dynamic\-animation/dynamic\-animation/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.dynamicanimation\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :dynamicanimation:dynamicanimation-ktx:processDebugAndroidTestManifest
+\$SUPPORT/dynamic\-animation/dynamic\-animation\-ktx/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.dynamicanimation\.ktx\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :exifinterface:exifinterface:processDebugAndroidTestManifest
+\$SUPPORT/exifinterface/exifinterface/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.exifinterface\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :fragment:fragment-testing:processDebugAndroidTestManifest
+\$SUPPORT/fragment/fragment\-testing/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.fragment\.testing\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :appsearch:appsearch-local-backend:externalNativeBuildDebug
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/debug/armeabi\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX static library protobuf\-target/libprotobufd\.a
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/debug/obj/armeabi\-v[0-9]+a/libicing\.so
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/debug/arm[0-9]+\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/debug/obj/arm[0-9]+\-v[0-9]+a/libicing\.so
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/debug/x[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/debug/obj/x[0-9]+/libicing\.so
+ninja: Entering directory `\$SUPPORT/appsearch/local\-backend/\.cxx/cmake/debug/x[0-9]+_[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/appsearch/appsearch\-local\-backend/build/intermediates/cmake/debug/obj/x[0-9]+_[0-9]+/libicing\.so
+# > Task :gridlayout:gridlayout:processDebugAndroidTestManifest
+\$SUPPORT/gridlayout/gridlayout/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.gridlayout\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :heifwriter:heifwriter:processDebugAndroidTestManifest
+\$SUPPORT/heifwriter/heifwriter/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.heifwriter\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :exifinterface:exifinterface:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/exifinterface/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest\.java uses or overrides a deprecated API\.
+Note: \$SUPPORT/exifinterface/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest\.java uses unchecked or unsafe operations\.
+# > Task :gridlayout:gridlayout:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/gridlayout/gridlayout/src/androidTest/java/androidx/gridlayout/widget/GridLayoutTest\.java uses or overrides a deprecated API\.
+# > Task :dynamicanimation:dynamicanimation-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/dynamicanimation\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :leanback:leanback:processDebugAndroidTestManifest
+\$SUPPORT/leanback/leanback/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.leanback\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\[:internal\-testutils\-runtime\] \$OUT_DIR/androidx/internal\-testutils\-runtime/build/intermediates/library_manifest/debug/AndroidManifest\.xml Warning:
+Package name 'androidx\.testutils' used in: :internal\-testutils\-runtime, :internal\-testutils\-espresso\.
+# > Task :leanback:leanback-tab:processDebugAndroidTestManifest
+\$SUPPORT/leanback/leanback\-tab/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.leanback\.tab\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :lifecycle:lifecycle-extensions:processDebugAndroidTestManifest
+\$SUPPORT/lifecycle/lifecycle\-extensions/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.lifecycle\.extensions\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :fragment:fragment-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/fragment\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :fragment:fragment-truth:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/fragment\-truth_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :inspection:inspection-testing:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/inspection\-testing_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :leanback:leanback:compileDebugAndroidTestJavaWithJavac
+warning: unknown enum constant AnnotationTarget\.CLASS
+reason: class file for kotlin\.annotation\.AnnotationTarget not found
+warning: unknown enum constant AnnotationTarget\.FUNCTION
+warning: unknown enum constant AnnotationRetention\.RUNTIME
+reason: class file for kotlin\.annotation\.AnnotationRetention not found
+# > Task :fragment:fragment-testing:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/fragment\-testing_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :leanback:leanback-paging:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/leanback\-paging_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :lifecycle:lifecycle-service:processDebugAndroidTestManifest
+\$SUPPORT/lifecycle/lifecycle\-service/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.lifecycle\.service\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :lifecycle:lifecycle-viewmodel-savedstate:processDebugAndroidTestManifest
+\$SUPPORT/lifecycle/lifecycle\-viewmodel\-savedstate/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.lifecycle\.viewmodel\.savedstate\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :leanback:leanback-tab:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/leanback/leanback\-tab/src/androidTest/java/androidx/leanback/tab/app/PagerAdapter\.java uses or overrides a deprecated API\.
+# > Task :lifecycle:lifecycle-runtime-testing:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/lifecycle\-runtime\-testing_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :lifecycle:lifecycle-runtime-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/lifecycle\-runtime\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :lifecycle:lifecycle-viewmodel-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/lifecycle\-viewmodel\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :lifecycle:lifecycle-livedata-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/lifecycle\-livedata\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :media2:media2-common:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/common/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.media[0-9]+\.common\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :media2:media2-player:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/player/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.media[0-9]+\.player\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :media2:media2-session:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/session/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.media[0-9]+\.session\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :media2:media2-common:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/media[0-9]+/common/src/androidTest/java/androidx/media[0-9]+/common/SubtitleDataTest\.java uses or overrides a deprecated API\.
+# > Task :navigation:navigation-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/navigation/benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.navigation\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/navigation/navigation\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :media2:media2-widget:processDebugAndroidTestManifest
+\$SUPPORT/media[0-9]+/widget/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.media[0-9]+\.widget\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :loader:loader-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/loader\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :navigation:navigation-dynamic-features-runtime:processDebugAndroidTestManifest
+\$SUPPORT/navigation/navigation\-dynamic\-features\-runtime/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.navigation\.dynamicfeatures\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :navigation:navigation-fragment:processDebugAndroidTestManifest
+Package name 'androidx\.testutils' used in: :internal\-testutils\-runtime, :internal\-testutils\-navigation\.
+# > Task :navigation:navigation-common-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation\-common\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :navigation:navigation-dynamic-features-fragment:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation\-dynamic\-features\-fragment_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :mediarouter:mediarouter:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/app/MediaRouteChooserDialogTest\.java uses or overrides a deprecated API\.
+# > Task :navigation:navigation-dynamic-features-runtime:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation\-dynamic\-features\-runtime_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :navigation:navigation-fragment-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation\-fragment\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :palette:palette:processDebugAndroidTestManifest
+\$SUPPORT/palette/palette/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.palette\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :percentlayout:percentlayout:processDebugAndroidTestManifest
+\$SUPPORT/percentlayout/percentlayout/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.percentlayout\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :preference:preference-ktx:processDebugAndroidTestManifest
+\$SUPPORT/preference/preference\-ktx/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.preference\.ktx\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :paging:paging-rxjava2:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/paging\-rxjava[0-9]+_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :navigation:navigation-runtime-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation\-runtime\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :navigation:navigation-runtime-truth:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation\-runtime\-truth_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :palette:palette-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/palette\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :navigation:navigation-testing:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/navigation\-testing_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :paging:paging-runtime:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/paging\-runtime_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :recyclerview:recyclerview-benchmark:processReleaseAndroidTestManifest
+\$OUT_DIR/androidx/recyclerview/recyclerview\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :recyclerview:recyclerview-selection:processDebugAndroidTestManifest
+\$SUPPORT/recyclerview/recyclerview\-selection/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.recyclerview\.selection\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :preference:preference:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/preference/preference/src/androidTest/java/androidx/preference/tests/PreferenceDataStoreTest\.java uses unchecked or unsafe operations\.
+# > Task :remotecallback:remotecallback:processDebugAndroidTestManifest
+\$SUPPORT/remotecallback/remotecallback/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.remotecallback\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :preference:preference-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/preference\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :recyclerview:recyclerview-selection:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/recyclerview/recyclerview\-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest\.java uses or overrides a deprecated API\.
+# > Task :savedstate:savedstate:processDebugAndroidTestManifest
+\$SUPPORT/savedstate/savedstate/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.savedstate\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :room:room-benchmark:processReleaseAndroidTestManifest
+\$OUT_DIR/androidx/room/room\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :savedstate:savedstate-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/savedstate\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :room:room-runtime:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/room/runtime/src/androidTest/java/androidx/room/migration/TableInfoTest\.java uses unchecked or unsafe operations\.
+# > Task :room:room-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/room\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :room:room-benchmark:kaptReleaseAndroidTestKotlin
+\$OUT_DIR/androidx/room/room\-benchmark/build/tmp/kapt[0-9]+/stubs/releaseAndroidTest/androidx/room/benchmark/RelationBenchmark\.java:[0-9]+: warning: The return value includes a POJO with a @Relation\. It is usually desired to annotate this method with @Transaction to avoid possibility of inconsistent results between the POJO and its relations\. See https://developer\.android\.com/reference/androidx/room/Transaction\.html for details\.
+public abstract java\.util\.List<androidx\.room\.benchmark\.RelationBenchmark\.UserWithItems> getUserWithItems\(\);
+# > Task :sharetarget:sharetarget:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/sharetarget/sharetarget/src/androidTest/java/androidx/sharetarget/ChooserTargetServiceCompatTest\.java uses or overrides a deprecated API\.
+Note: \$SUPPORT/sharetarget/sharetarget/src/androidTest/java/androidx/sharetarget/ChooserTargetServiceCompatTest\.java uses unchecked or unsafe operations\.
+# > Task :security:security-crypto-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/security\-crypto\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :appsearch:appsearch-local-backend:processDebugAndroidTestManifest
+\$SUPPORT/appsearch/local\-backend/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.appsearch\.localbackend\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :textclassifier:textclassifier:processDebugAndroidTestManifest
+\$SUPPORT/textclassifier/textclassifier/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.textclassifier\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :transition:transition:processDebugAndroidTestManifest
+\$SUPPORT/transition/transition/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.transition\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :transition:transition-ktx:processDebugAndroidTestManifest
+\$SUPPORT/transition/transition\-ktx/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.transition\.ktx\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :tvprovider:tvprovider:processDebugAndroidTestManifest
+\$SUPPORT/tv\-provider/tv\-provider/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.tvprovider\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :wear:wear:processDebugAndroidTestManifest
+\$SUPPORT/wear/wear/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.wear\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :vectordrawable:vectordrawable:processDebugAndroidTestManifest
+\$SUPPORT/vectordrawable/vectordrawable/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.vectordrawable\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :viewpager:viewpager:processDebugAndroidTestManifest
+\$SUPPORT/viewpager/viewpager/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.viewpager\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :vectordrawable:vectordrawable-animated:processDebugAndroidTestManifest
+\$SUPPORT/vectordrawable/vectordrawable\-animated/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.vectordrawable\.animated\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :vectordrawable:vectordrawable-seekable:processDebugAndroidTestManifest
+\$SUPPORT/vectordrawable/vectordrawable\-seekable/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.vectordrawable\.seekable\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :viewpager2:viewpager2:processDebugAndroidTestManifest
+\$SUPPORT/viewpager[0-9]+/viewpager[0-9]+/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.viewpager[0-9]+\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+Package name 'androidx\.testutils' used in: :internal\-testutils\-appcompat, :internal\-testutils\-runtime, :internal\-testutils\-espresso\.
+# > Task :transition:transition-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/transition\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :wear:wear-watchface:processDebugAndroidTestManifest
+\$SUPPORT/wear/wear\-watchface/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.wear\.watchface\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :window:window:processDebugAndroidTestManifest
+\$SUPPORT/window/window/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.window\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :webkit:webkit:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/webkit/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatForceDarkTest\.java uses or overrides a deprecated API\.
+# > Task :wear:wear-watchface:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/wear\-watchface_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :work:work-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/work/workmanager\-benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.work\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/work/work\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :work:work-inspection:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/work\-inspection_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :work:work-runtime-ktx:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/work\-runtime\-ktx_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :benchmark:integration-tests:dry-run-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/benchmark/integration\-tests/dry\-run\-benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.benchmark\.integration\.dryrun\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/benchmark/integration\-tests/dry\-run\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :benchmark:integration-tests:startup-benchmark:processReleaseAndroidTestManifest
+\$SUPPORT/benchmark/integration\-tests/startup\-benchmark/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.benchmark\.integration\.startup\.benchmark\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+\$OUT_DIR/androidx/benchmark/integration\-tests/startup\-benchmark/build/intermediates/tmp/manifest/androidTest/release/manifestMerger[0-9]+\.xml:[0-9]+:[0-9]+\-[0-9]+:[0-9]+ Warning:
+# > Task :work:work-testing:mergeDebugAndroidTestJavaResource
+More than one file was found with OS independent path 'META\-INF/work\-testing_debug\.kotlin_module'\. This version of the Android Gradle Plugin chooses the file from the app or dynamic\-feature module, but this can cause unexpected behavior or errors at runtime\. Future versions of the Android Gradle Plugin will throw an error in this case\.
+# > Task :camera:integration-tests:camera-testapp-core:externalNativeBuildDebug
+Build opengl_renderer_jni_armeabi\-v[0-9]+a
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/debug/armeabi\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/opengl_renderer_jni\.dir/jni_hooks\.cpp\.o
+\[[0-9]+/[0-9]+\] Building CXX object CMakeFiles/opengl_renderer_jni\.dir/opengl_renderer_jni\.cpp\.o
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/debug/obj/armeabi\-v[0-9]+a/libopengl_renderer_jni\.so
+Build opengl_renderer_jni_arm[0-9]+\-v[0-9]+a
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/debug/arm[0-9]+\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/debug/obj/arm[0-9]+\-v[0-9]+a/libopengl_renderer_jni\.so
+Build opengl_renderer_jni_x[0-9]+
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/debug/x[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/debug/obj/x[0-9]+/libopengl_renderer_jni\.so
+Build opengl_renderer_jni_x[0-9]+_[0-9]+
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/debug/x[0-9]+_[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/debug/obj/x[0-9]+_[0-9]+/libopengl_renderer_jni\.so
+# > Task :camera:integration-tests:camera-testapp-extensions:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/camera/integration\-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/ToggleButtonTest\.java uses or overrides a deprecated API\.
+# > Task :camera:integration-tests:camera-testapp-camera2-pipe:minifyReleaseWithR8
+R[0-9]+: Missing class: java\.lang\.instrument\.ClassFileTransformer
+R[0-9]+: Missing class: sun\.misc\.SignalHandler
+# > Task :camera:integration-tests:camera-testapp-view:minifyReleaseWithR8
+R[0-9]+: Missing class: java\.lang\.ClassValue
+# > Task :camera:integration-tests:camera-testapp-core:externalNativeBuildRelease
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/release/armeabi\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/release/obj/armeabi\-v[0-9]+a/libopengl_renderer_jni\.so
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/release/arm[0-9]+\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/release/obj/arm[0-9]+\-v[0-9]+a/libopengl_renderer_jni\.so
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/release/x[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/release/obj/x[0-9]+/libopengl_renderer_jni\.so
+ninja: Entering directory `\$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/nativeBuildStaging/cmake/release/x[0-9]+_[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/integration\-tests/camera\-testapp\-core/build/intermediates/cmake/release/obj/x[0-9]+_[0-9]+/libopengl_renderer_jni\.so
+# > Task :room:integration-tests:room-testapp-noappcompat:compileDebugAndroidTestJavaWithJavac
+\$SUPPORT/room/integration\-tests/noappcompattestapp/src/androidTest/java/androidx/room/integration/noappcompat/BareRelationDatabaseTest\.java:[0-9]+: warning: The return value includes a POJO with a @Relation\. It is usually desired to annotate this method with @Transaction to avoid possibility of inconsistent results between the POJO and its relations\. See https://developer\.android\.com/reference/androidx/room/Transaction\.html for details\.
+UserAndPets getUserWithPets\(long id\);
+List<UserAndPet> getUsersWithPet\(\);
+# > Task :textclassifier:integration-tests:testapp:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/textclassifier/integration\-tests/testapp/src/androidTest/java/androidx/textclassifier/integration/testapp/MainActivityTest\.java uses or overrides a deprecated API\.
+# > Task :room:integration-tests:room-testapp:compileDebugAndroidTestJavaWithJavac
+Note: \$SUPPORT/room/integration\-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/TestUtil\.java uses unchecked or unsafe operations\.
+# > Task :hilt:integration-tests:hilt-testapp-worker:kaptDebugAndroidTestKotlin
+warning: The following options were not recognized by any processor: '\[dagger\.hilt\.android\.internal\.disableAndroidSuperclassValidation, kapt\.kotlin\.generated\]'
+# > Task :hilt:integration-tests:hilt-testapp-viewmodel:compileReleaseJavaWithJavac
+Note: \$OUT_DIR/androidx/hilt/integration\-tests/hilt\-testapp\-viewmodel/build/generated/source/kapt/release/androidx/hilt/integration/viewmodelapp/Hilt_SimpleFragment\.java uses or overrides a deprecated API\.
+# > Task :slice-core:generateApi
+src/main/java/androidx/slice/compat/SliceProviderCompat\.java:[0-9]+: warning: Parameter permissionManager references hidden type androidx\.slice\.compat\.CompatPermissionManager\. \[HiddenTypeParameter\]
+# > Task :appsearch:appsearch-compiler:lint
+\$SUPPORT/appsearch/compiler/lint\-baseline\.xml: Information: [0-9]+ error was filtered out because it is listed in the baseline file, lint\-baseline\.xml
+\[LintBaseline\]
+[0-9]+ errors, [0-9]+ warnings \([0-9]+ error filtered by baseline lint\-baseline\.xml\)
+# > Task :slice-view:generateApi
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of hidden type SliceContent in androidx\.slice\.widget\.ListContent\.getListHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceStyle in androidx\.slice\.widget\.ListContent\.getHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceViewPolicy in androidx\.slice\.widget\.ListContent\.getHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceStyle in androidx\.slice\.widget\.ListContent\.getRowItems\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceViewPolicy in androidx\.slice\.widget\.ListContent\.getRowItems\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Method androidx\.slice\.widget\.ListContent\.getSeeMoreItem returns unavailable type SliceContent \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceContent in androidx\.slice\.widget\.ListContent\.getRowType\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceStyle in androidx\.slice\.widget\.ListContent\.getListHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceViewPolicy in androidx\.slice\.widget\.ListContent\.getListHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/GridContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceStyle in androidx\.slice\.widget\.GridContent\.getHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/GridContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceViewPolicy in androidx\.slice\.widget\.GridContent\.getHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/RowContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceStyle in androidx\.slice\.widget\.RowContent\.getHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/RowContent\.java:[0-9]+: warning: Parameter of unavailable type androidx\.slice\.widget\.SliceViewPolicy in androidx\.slice\.widget\.RowContent\.getHeight\(\) \[UnavailableSymbol\]
+src/main/java/androidx/slice/widget/GridContent\.java:[0-9]+: warning: Parameter style references hidden type androidx\.slice\.widget\.SliceStyle\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/GridContent\.java:[0-9]+: warning: Parameter policy references hidden type androidx\.slice\.widget\.SliceViewPolicy\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter style references hidden type androidx\.slice\.widget\.SliceStyle\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter policy references hidden type androidx\.slice\.widget\.SliceViewPolicy\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter listItems references hidden type class androidx\.slice\.widget\.SliceContent\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Method androidx\.slice\.widget\.ListContent\.getRowItems\(int, androidx\.slice\.widget\.SliceStyle, androidx\.slice\.widget\.SliceViewPolicy\) references hidden type class androidx\.slice\.widget\.SliceContent\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Method androidx\.slice\.widget\.ListContent\.getRowItems\(\) references hidden type class androidx\.slice\.widget\.SliceContent\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Parameter content references hidden type androidx\.slice\.widget\.SliceContent\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/ListContent\.java:[0-9]+: warning: Method androidx\.slice\.widget\.ListContent\.getSeeMoreItem\(\) references hidden type androidx\.slice\.widget\.SliceContent\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/RowContent\.java:[0-9]+: warning: Parameter style references hidden type androidx\.slice\.widget\.SliceStyle\. \[HiddenTypeParameter\]
+src/main/java/androidx/slice/widget/RowContent\.java:[0-9]+: warning: Parameter policy references hidden type androidx\.slice\.widget\.SliceViewPolicy\. \[HiddenTypeParameter\]
+# > Task :appcompat:appcompat-resources:generateApi
+src/main/java/androidx/appcompat/widget/ResourceManagerInternal\.java:[0-9]+: warning: Parameter hooks references hidden type androidx\.appcompat\.widget\.ResourceManagerInternal\.ResourceManagerHooks\. \[HiddenTypeParameter\]
+# > Task :arch:core-common:generateApi
+src/main/java/androidx/arch/core/internal/FastSafeIterableMap\.java:[0-9]+: warning: Method androidx\.arch\.core\.internal\.FastSafeIterableMap\.get\(K\) references hidden type androidx\.arch\.core\.internal\.SafeIterableMap\.Entry<K,V>\. \[HiddenTypeParameter\]
+src/main/java/androidx/arch/core/internal/SafeIterableMap\.java:[0-9]+: warning: Method androidx\.arch\.core\.internal\.SafeIterableMap\.get\(K\) references hidden type androidx\.arch\.core\.internal\.SafeIterableMap\.Entry<K,V>\. \[HiddenTypeParameter\]
+src/main/java/androidx/arch/core/internal/SafeIterableMap\.java:[0-9]+: warning: Method androidx\.arch\.core\.internal\.SafeIterableMap\.iteratorWithAdditions\(\) references hidden type androidx\.arch\.core\.internal\.SafeIterableMap\.IteratorWithAdditions\. \[HiddenTypeParameter\]
+src/main/java/androidx/arch/core/internal/SafeIterableMap\.java:[0-9]+: warning: Method androidx\.arch\.core\.internal\.SafeIterableMap\.put\(K, V\) references hidden type androidx\.arch\.core\.internal\.SafeIterableMap\.Entry<K,V>\. \[HiddenTypeParameter\]
+# > Task :appcompat:appcompat:generateApi
+src/main/java/androidx/appcompat/view/menu/MenuPopupHelper\.java:[0-9]+: warning: Method androidx\.appcompat\.view\.menu\.MenuPopupHelper\.getPopup\(\) references hidden type androidx\.appcompat\.view\.menu\.MenuPopup\. \[HiddenTypeParameter\]
+src/main/java/androidx/appcompat/widget/ActionMenuView\.java:[0-9]+: warning: Parameter presenter references hidden type androidx\.appcompat\.widget\.ActionMenuPresenter\. \[HiddenTypeParameter\]
+src/main/java/androidx/appcompat/widget/ActivityChooserView\.java:[0-9]+: warning: Method androidx\.appcompat\.widget\.ActivityChooserView\.getDataModel\(\) references hidden type androidx\.appcompat\.widget\.ActivityChooserModel\. \[HiddenTypeParameter\]
+src/main/java/androidx/appcompat/widget/ActivityChooserView\.java:[0-9]+: warning: Parameter dataModel references hidden type androidx\.appcompat\.widget\.ActivityChooserModel\. \[HiddenTypeParameter\]
+src/main/java/androidx/appcompat/widget/Toolbar\.java:[0-9]+: warning: Parameter outerPresenter references hidden type androidx\.appcompat\.widget\.ActionMenuPresenter\. \[HiddenTypeParameter\]
+# > Task :core:core-appdigest:processDebugAndroidTestManifest
+\$SUPPORT/core/core\-appdigest/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.core\.appdigest\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :core:core:generateApi
+src\/main\/java\/androidx\/core\/app\/NotificationCompat\.java\:[0-9]+\: warning\: Builder constructor arguments must be mandatory \(i\.e\. not \@Nullable\)\: parameter title in androidx\.core\.app\.NotificationCompat\.Action\.Builder\(int icon\, CharSequence title\, android\.app\.PendingIntent intent\) \[OptionalBuilderConstructorArgument\]See tools\/metalava\/API\-LINT\.md for how to handle these\.
+src/main/java/androidx/core/app/NotificationCompat\.java:[0-9]+: warning: Builder constructor arguments must be mandatory \(i\.e\. not @Nullable\): parameter title in androidx\.core\.app\.NotificationCompat\.Action\.Builder\(int icon, CharSequence title, android\.app\.PendingIntent intent\) \[OptionalBuilderConstructorArgument\]
+src/main/java/androidx/core/app/NotificationCompat\.java:[0-9]+: warning: Builder constructor arguments must be mandatory \(i\.e\. not @Nullable\): parameter intent in androidx\.core\.app\.NotificationCompat\.Action\.Builder\(int icon, CharSequence title, android\.app\.PendingIntent intent\) \[OptionalBuilderConstructorArgument\]
+[0-9]+ new API lint issues were found\.
+See tools/metalava/API\-LINT\.md for how to handle these\.
+# > Task :cursoradapter:cursoradapter:generateApi
+src/main/java/androidx/cursoradapter/widget/CursorAdapter\.java:[0-9]+: warning: Field CursorAdapter\.mChangeObserver references hidden type androidx\.cursoradapter\.widget\.CursorAdapter\.ChangeObserver\. \[HiddenTypeParameter\]
+src/main/java/androidx/cursoradapter/widget/CursorAdapter\.java:[0-9]+: warning: Field CursorAdapter\.mCursorFilter references hidden type androidx\.cursoradapter\.widget\.CursorFilter\. \[HiddenTypeParameter\]
+# > Task :camera:camera-testing:externalNativeBuildRelease
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/release/armeabi\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/release/obj/armeabi\-v[0-9]+a/libtesting_surface_format_jni\.so
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/release/arm[0-9]+\-v[0-9]+a'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/release/obj/arm[0-9]+\-v[0-9]+a/libtesting_surface_format_jni\.so
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/release/x[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/release/obj/x[0-9]+/libtesting_surface_format_jni\.so
+ninja: Entering directory `\$OUT_DIR/androidx/camera/camera\-testing/nativeBuildStaging/cmake/release/x[0-9]+_[0-9]+'
+\[[0-9]+/[0-9]+\] Linking CXX shared library \$OUT_DIR/androidx/camera/camera\-testing/build/intermediates/cmake/release/obj/x[0-9]+_[0-9]+/libtesting_surface_format_jni\.so
+# > Task :camera:camera-camera2:runErrorProne
+\$SUPPORT/camera/camera\-camera[0-9]+/src/main/java/androidx/camera/camera[0-9]+/internal/SupportedSizeConstraints\.java:[0-9]+: warning: \[AutoValueImmutableFields\] AutoValue instances should be deeply immutable\. Therefore, we recommend returning ImmutableSet instead\. Read more at http://goo\.gl/qWo[0-9]+sC
+public abstract Set<Integer> getAffectedFormats\(\);
+\(see https://errorprone\.info/bugpattern/AutoValueImmutableFields\)
+\$SUPPORT/camera/camera\-camera[0-9]+/src/main/java/androidx/camera/camera[0-9]+/internal/SupportedSizeConstraints\.java:[0-9]+: warning: \[AutoValueImmutableFields\] AutoValue instances should be deeply immutable\. Therefore, we recommend returning ImmutableList instead\. Read more at http://goo\.gl/qWo[0-9]+sC
+public abstract List<Size> getExcludedSizes\(\);
+# > Task :leanback:leanback:generateApi
+src/main/java/androidx/leanback/transition/TransitionHelper\.java:[0-9]+: warning: Parameter of unavailable type androidx\.leanback\.transition\.TransitionEpicenterCallback in androidx\.leanback\.transition\.TransitionHelper\.setEpicenterCallback\(\) \[UnavailableSymbol\]
+src/main/java/androidx/leanback/transition/TransitionHelper\.java:[0-9]+: warning: Parameter callback references hidden type androidx\.leanback\.transition\.TransitionEpicenterCallback\. \[HiddenTypeParameter\]
+# > Task :media:media:generateApi
+src/main/java/android/support/v[0-9]+/media/session/MediaControllerCompat\.java:[0-9]+: warning: Method android\.support\.v[0-9]+\.media\.session\.MediaControllerCompat\.Callback\.getIControllerCallback returns unavailable type IMediaControllerCallback \[UnavailableSymbol\]
+src/main/java/android/support/v[0-9]+/media/session/MediaControllerCompat\.java:[0-9]+: warning: Method android\.support\.v[0-9]+\.media\.session\.MediaControllerCompat\.Callback\.getIControllerCallback\(\) references hidden type android\.support\.v[0-9]+\.media\.session\.IMediaControllerCallback\. \[HiddenTypeParameter\]
+# > Task :remotecallback:remotecallback-processor:lint
+\$SUPPORT/remotecallback/processor/lint\-baseline\.xml: Information: [0-9]+ error was filtered out because it is listed in the baseline file, lint\-baseline\.xml
+# > Task :core:core:runErrorProne
+\$SUPPORT/core/core/src/main/java/androidx/core/content/pm/ShortcutManagerCompat\.java:[0-9]+: warning: \[ModifyCollectionInEnhancedForLoop\] Modifying a collection while iterating over it in a loop may cause a ConcurrentModificationException to be thrown\.
+shortcutInfoList\.remove\(info\);
+\(see https://errorprone\.info/bugpattern/ModifyCollectionInEnhancedForLoop\)
+# > Task :versionedparcelable:versionedparcelable-compiler:lint
+\$SUPPORT/versionedparcelable/versionedparcelable\-compiler/lint\-baseline\.xml: Information: [0-9]+ error was filtered out because it is listed in the baseline file, lint\-baseline\.xml
+# > Task :textclassifier:textclassifier:generateApi
+src/main/java/androidx/textclassifier/widget/ToolbarController\.java:[0-9]+: warning: Method androidx\.textclassifier\.widget\.ToolbarController\.FloatingToolbarFactory\.create returns unavailable type IFloatingToolbar \[UnavailableSymbol\]
+src/main/java/androidx/textclassifier/widget/ToolbarController\.java:[0-9]+: warning: Method androidx\.textclassifier\.widget\.ToolbarController\.FloatingToolbarFactory\.create\(android\.widget\.TextView\) references hidden type androidx\.textclassifier\.widget\.IFloatingToolbar\. \[HiddenTypeParameter\]
+# > Task :transition:transition:generateApi
+src/main/java/androidx/transition/Transition\.java:[0-9]+: warning: Parameter startValues references hidden type androidx\.transition\.TransitionValuesMaps\. \[HiddenTypeParameter\]
+src/main/java/androidx/transition/Transition\.java:[0-9]+: warning: Parameter endValues references hidden type androidx\.transition\.TransitionValuesMaps\. \[HiddenTypeParameter\]
+src/main/java/androidx/transition/TransitionSet\.java:[0-9]+: warning: Parameter startValues references hidden type androidx\.transition\.TransitionValuesMaps\. \[HiddenTypeParameter\]
+src/main/java/androidx/transition/TransitionSet\.java:[0-9]+: warning: Parameter endValues references hidden type androidx\.transition\.TransitionValuesMaps\. \[HiddenTypeParameter\]
+# > Task :activity:integration-tests:testapp:processDebugAndroidTestManifest
+\$SUPPORT/activity/integration\-tests/testapp/src/androidTest/AndroidManifest\.xml Warning:
+Package name 'androidx\.activity\.integration\.testapp\.test' used in: AndroidManifest\.xml, manifestMerger[0-9]+\.xml\.
+# > Task :room:integration-tests:room-testapp-autovalue:compileDebugAndroidTestJavaWithJavac
+Stream closed
+# > Task :benchmark:benchmark-macro:processDebugAndroidTestManifest
+\$SUPPORT\/benchmark\/macro\/src\/androidTest\/AndroidManifest\.xml Warning\:
+Package name \'androidx\.benchmark\.macro\.test\' used in\: AndroidManifest\.xml\, manifestMerger[0-9]+\.xml\.
diff --git a/development/build_log_simplifier/test.py b/development/build_log_simplifier/test.py
index 57ab11d..d59aa4a 100755
--- a/development/build_log_simplifier/test.py
+++ b/development/build_log_simplifier/test.py
@@ -19,6 +19,7 @@
 from build_log_simplifier import generate_suggested_exemptions
 from build_log_simplifier import normalize_paths
 from build_log_simplifier import regexes_matcher
+from build_log_simplifier import remove_control_characters
 import re
 
 def fail(message):
@@ -54,7 +55,7 @@
     actual = normalize_paths(lines)
     if expected_normalized != actual:
         fail("test_normalize_paths returned incorrect response.\n" +
-            "Input: " + str(lines) + "\n" + 
+            "Input: " + str(lines) + "\n" +
             "Output: " + str(actual) + "\n" +
             "Expected output: " + str(expected_normalized)
         )
@@ -287,6 +288,26 @@
     if (actual != expected):
         fail("collapse_tasks_having_no_output gave incorrect error. Expected: " + str(expected) + ", actual = " + str(actual))
 
+def test_remove_control_characters():
+    print("test_remove_control_characters")
+    given = [
+        # a line starting with several color codes in it
+        "src/main/java/androidx/arch/core/internal/FastSafeIterableMap.java:39: warning: Method androidx.arch.core.internal.FastSafeIterableMap.get(K) references hidden type androidx.arch.core.internal.SafeIterableMap.Entry<K,V>. [HiddenTypeParameter]",
+        # a line with a variety of characters, none of which are color codes
+        "space tab\tCAPITAL underscore_ slash/ colon: number 1 newline\n",
+    ]
+    expected = [
+        "src/main/java/androidx/arch/core/internal/FastSafeIterableMap.java:39: warning: Method androidx.arch.core.internal.FastSafeIterableMap.get(K) references hidden type androidx.arch.core.internal.SafeIterableMap.Entry<K,V>. [HiddenTypeParameter]",
+        "space tab\tCAPITAL underscore_ slash/ colon: number 1 newline\n",
+    ]
+    actual = [remove_control_characters(line) for line in given]
+    if actual != expected:
+        fail("remove_control_charactres gave incorrect response.\n\n" +
+            "Input          : " + str(given) + ".\n\n" +
+            "Expected output: " + str(expected) + ".\n\n" +
+            "Actual output  : " + str(actual) + ".")
+
+
 def main():
     test_collapse_consecutive_blank_lines()
     test_collapse_tasks_having_no_output()
@@ -294,6 +315,7 @@
     test_normalize_paths()
     test_regexes_matcher_get_matching_regexes()
     test_regexes_matcher_index_first_matching_regex()
+    test_remove_control_characters()
 
 if __name__ == "__main__":
     main()
diff --git a/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java b/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
index ec9ce09..28f3f93 100644
--- a/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
+++ b/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
@@ -24,6 +24,7 @@
 import android.media.MediaDataSource;
 import android.media.MediaMetadataRetriever;
 import android.os.Build;
+import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
 import android.util.Log;
@@ -32,6 +33,7 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 
 import java.io.BufferedInputStream;
@@ -67,7 +69,6 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.TimeZone;
-import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -3946,12 +3947,8 @@
             // Keep the original file descriptor in order to save attributes when it's seekable.
             // Otherwise, just close the given file descriptor after reading it because the save
             // feature won't be working.
-            try {
-                fileDescriptor = Os.dup(fileDescriptor);
-                isFdDuped = true;
-            } catch (Exception e) {
-                throw new IOException("Failed to duplicate file descriptor", e);
-            }
+            fileDescriptor = OsApi21Impl.dup(fileDescriptor);
+            isFdDuped = true;
         } else {
             mSeekableFileDescriptor = null;
         }
@@ -4607,7 +4604,7 @@
     private static boolean isSeekableFD(FileDescriptor fd) {
         if (Build.VERSION.SDK_INT >= 21) {
             try {
-                Os.lseek(fd, 0, OsConstants.SEEK_CUR);
+                OsApi21Impl.lseek(fd, 0, OsConstants.SEEK_CUR);
                 return true;
             } catch (Exception e) {
                 if (DEBUG) {
@@ -4667,28 +4664,18 @@
 
         FileInputStream in = null;
         FileOutputStream out = null;
-        File originalFile = null;
-        if (mFilename != null) {
-            originalFile = new File(mFilename);
-        }
         File tempFile = null;
         try {
-            // Move the original file to temporary file.
+            // Copy the original file to temporary file.
+            tempFile = File.createTempFile("temp", "tmp");
             if (mFilename != null) {
-                String parent = originalFile.getParent();
-                String name = originalFile.getName();
-                String tempPrefix = UUID.randomUUID().toString() + "_";
-                tempFile = new File(parent, tempPrefix + name);
-                if (!originalFile.renameTo(tempFile)) {
-                    throw new IOException("Couldn't rename to " + tempFile.getAbsolutePath());
-                }
+                in = new FileInputStream(mFilename);
             } else if (Build.VERSION.SDK_INT >= 21 && mSeekableFileDescriptor != null) {
-                tempFile = File.createTempFile("temp", "tmp");
-                Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
+                OsApi21Impl.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
                 in = new FileInputStream(mSeekableFileDescriptor);
-                out = new FileOutputStream(tempFile);
-                copy(in, out);
             }
+            out = new FileOutputStream(tempFile);
+            copy(in, out);
         } catch (Exception e) {
             throw new IOException("Failed to copy original file to temp file", e);
         } finally {
@@ -4706,7 +4693,7 @@
             if (mFilename != null) {
                 out = new FileOutputStream(mFilename);
             } else if (Build.VERSION.SDK_INT >= 21 && mSeekableFileDescriptor != null) {
-                Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
+                OsApi21Impl.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
                 out = new FileOutputStream(mSeekableFileDescriptor);
             }
             bufferedIn = new BufferedInputStream(in);
@@ -4719,12 +4706,26 @@
                 saveWebpAttributes(bufferedIn, bufferedOut);
             }
         } catch (Exception e) {
+            // Restore original file
+            closeQuietly(bufferedIn);
+            closeQuietly(bufferedOut);
+            in = new FileInputStream(tempFile);
             if (mFilename != null) {
-                if (!tempFile.renameTo(originalFile)) {
-                    throw new IOException("Couldn't restore original file: "
-                            + originalFile.getAbsolutePath());
+                out = new FileOutputStream(mFilename);
+            } else if (Build.VERSION.SDK_INT >= 21 && mSeekableFileDescriptor != null) {
+                try {
+                    OsApi21Impl.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
+                    // Catching ErrnoException will raise error in API < 21
+                } catch (Exception exception) {
+                    throw new IOException("Failed to save new file. Original file may be "
+                            + "corrupted since error occurred while trying to restore it.",
+                            exception);
                 }
+                out = new FileOutputStream(mSeekableFileDescriptor);
             }
+            copy(in, out);
+            closeQuietly(in);
+            closeQuietly(out);
             throw new IOException("Failed to save new file", e);
         } finally {
             closeQuietly(bufferedIn);
@@ -4794,8 +4795,8 @@
             } else if (mFilename != null) {
                 in = new FileInputStream(mFilename);
             } else if (Build.VERSION.SDK_INT >= 21 && mSeekableFileDescriptor != null) {
-                newFileDescriptor = Os.dup(mSeekableFileDescriptor);
-                Os.lseek(newFileDescriptor, 0, OsConstants.SEEK_SET);
+                newFileDescriptor = OsApi21Impl.dup(mSeekableFileDescriptor);
+                OsApi21Impl.lseek(newFileDescriptor, 0, OsConstants.SEEK_SET);
                 in = new FileInputStream(newFileDescriptor);
             }
             if (in == null) {
@@ -7985,12 +7986,7 @@
         // Os.dup and Os.close was introduced in API 21 so this method shouldn't be called
         // in API < 21.
         if (Build.VERSION.SDK_INT >= 21) {
-            try {
-                Os.close(fd);
-                // Catching ErrnoException will raise error in API < 21
-            } catch (Exception ex) {
-                Log.e(TAG, "Error closing fd.");
-            }
+            OsApi21Impl.close(fd);
         } else {
             Log.e(TAG, "closeFileDescriptor is called in API < 21, which must be wrong.");
         }
@@ -8078,4 +8074,39 @@
         }
         return false;
     }
+
+    /**
+     * Nested class to avoid verification errors for methods introduced in Android 5.0 (API 21).
+     */
+    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+    private static class OsApi21Impl {
+        // Prevent instantiation.
+        private OsApi21Impl() {}
+
+        static FileDescriptor dup(FileDescriptor fd) throws IOException {
+            FileDescriptor duplicateFD = null;
+            try {
+                duplicateFD = Os.dup(fd);
+            } catch (ErrnoException e) {
+                throw new IOException("Failed to duplicate file descriptor", e);
+            }
+            return duplicateFD;
+        }
+
+        static void close(FileDescriptor fd) {
+            try {
+                Os.close(fd);
+            } catch (ErrnoException ex) {
+                Log.e(TAG, "Error closing fd.");
+            }
+        }
+
+        static void lseek(FileDescriptor fd, int offset, int osConstant) throws IOException {
+            try {
+                Os.lseek(fd, offset, osConstant);
+            } catch (ErrnoException e) {
+                throw new IOException("Failed to seek file descriptor", e);
+            }
+        }
+    }
 }
diff --git a/fragment/fragment-ktx/api/1.3.0-beta01.txt b/fragment/fragment-ktx/api/1.3.0-beta01.txt
new file mode 100644
index 0000000..d3e6dff
--- /dev/null
+++ b/fragment/fragment-ktx/api/1.3.0-beta01.txt
@@ -0,0 +1,34 @@
+// Signature format: 3.0
+package androidx.fragment.app {
+
+  public final class FragmentKt {
+    method public static void clearFragmentResult(androidx.fragment.app.Fragment, String requestKey);
+    method public static void clearFragmentResultListener(androidx.fragment.app.Fragment, String requestKey);
+    method public static void setFragmentResult(androidx.fragment.app.Fragment, String requestKey, android.os.Bundle result);
+    method public static void setFragmentResultListener(androidx.fragment.app.Fragment, String requestKey, kotlin.jvm.functions.Function2<? super java.lang.String,? super android.os.Bundle,kotlin.Unit> listener);
+  }
+
+  public final class FragmentManagerKt {
+    method public static inline void commit(androidx.fragment.app.FragmentManager, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+    method public static inline void commitNow(androidx.fragment.app.FragmentManager, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+    method @Deprecated public static inline void transaction(androidx.fragment.app.FragmentManager, boolean now = false, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+  }
+
+  public final class FragmentTransactionKt {
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! add(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, String tag = null, android.os.Bundle? args = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! add(androidx.fragment.app.FragmentTransaction, String tag, android.os.Bundle? args = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! replace(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, String tag = null, android.os.Bundle? args = null);
+  }
+
+  public final class FragmentViewModelLazyKt {
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! activityViewModels(androidx.fragment.app.Fragment, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+    method @MainThread public static <VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> createViewModelLazy(androidx.fragment.app.Fragment, kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! viewModels(androidx.fragment.app.Fragment, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStoreOwner> ownerProducer = { return this }, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+  }
+
+  public final class ViewKt {
+    method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+  }
+
+}
+
diff --git a/fragment/fragment-ktx/api/public_plus_experimental_1.3.0-beta01.txt b/fragment/fragment-ktx/api/public_plus_experimental_1.3.0-beta01.txt
new file mode 100644
index 0000000..d3e6dff
--- /dev/null
+++ b/fragment/fragment-ktx/api/public_plus_experimental_1.3.0-beta01.txt
@@ -0,0 +1,34 @@
+// Signature format: 3.0
+package androidx.fragment.app {
+
+  public final class FragmentKt {
+    method public static void clearFragmentResult(androidx.fragment.app.Fragment, String requestKey);
+    method public static void clearFragmentResultListener(androidx.fragment.app.Fragment, String requestKey);
+    method public static void setFragmentResult(androidx.fragment.app.Fragment, String requestKey, android.os.Bundle result);
+    method public static void setFragmentResultListener(androidx.fragment.app.Fragment, String requestKey, kotlin.jvm.functions.Function2<? super java.lang.String,? super android.os.Bundle,kotlin.Unit> listener);
+  }
+
+  public final class FragmentManagerKt {
+    method public static inline void commit(androidx.fragment.app.FragmentManager, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+    method public static inline void commitNow(androidx.fragment.app.FragmentManager, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+    method @Deprecated public static inline void transaction(androidx.fragment.app.FragmentManager, boolean now = false, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+  }
+
+  public final class FragmentTransactionKt {
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! add(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, String tag = null, android.os.Bundle? args = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! add(androidx.fragment.app.FragmentTransaction, String tag, android.os.Bundle? args = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! replace(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, String tag = null, android.os.Bundle? args = null);
+  }
+
+  public final class FragmentViewModelLazyKt {
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! activityViewModels(androidx.fragment.app.Fragment, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+    method @MainThread public static <VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> createViewModelLazy(androidx.fragment.app.Fragment, kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! viewModels(androidx.fragment.app.Fragment, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStoreOwner> ownerProducer = { return this }, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+  }
+
+  public final class ViewKt {
+    method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+  }
+
+}
+
diff --git a/fragment/fragment-ktx/api/res-1.3.0-beta01.txt b/fragment/fragment-ktx/api/res-1.3.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/fragment/fragment-ktx/api/res-1.3.0-beta01.txt
diff --git a/fragment/fragment-ktx/api/restricted_1.3.0-beta01.txt b/fragment/fragment-ktx/api/restricted_1.3.0-beta01.txt
new file mode 100644
index 0000000..d3e6dff
--- /dev/null
+++ b/fragment/fragment-ktx/api/restricted_1.3.0-beta01.txt
@@ -0,0 +1,34 @@
+// Signature format: 3.0
+package androidx.fragment.app {
+
+  public final class FragmentKt {
+    method public static void clearFragmentResult(androidx.fragment.app.Fragment, String requestKey);
+    method public static void clearFragmentResultListener(androidx.fragment.app.Fragment, String requestKey);
+    method public static void setFragmentResult(androidx.fragment.app.Fragment, String requestKey, android.os.Bundle result);
+    method public static void setFragmentResultListener(androidx.fragment.app.Fragment, String requestKey, kotlin.jvm.functions.Function2<? super java.lang.String,? super android.os.Bundle,kotlin.Unit> listener);
+  }
+
+  public final class FragmentManagerKt {
+    method public static inline void commit(androidx.fragment.app.FragmentManager, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+    method public static inline void commitNow(androidx.fragment.app.FragmentManager, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+    method @Deprecated public static inline void transaction(androidx.fragment.app.FragmentManager, boolean now = false, boolean allowStateLoss = false, kotlin.jvm.functions.Function1<? super androidx.fragment.app.FragmentTransaction,kotlin.Unit> body);
+  }
+
+  public final class FragmentTransactionKt {
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! add(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, String tag = null, android.os.Bundle? args = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! add(androidx.fragment.app.FragmentTransaction, String tag, android.os.Bundle? args = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.FragmentTransaction! replace(androidx.fragment.app.FragmentTransaction, @IdRes int containerViewId, String tag = null, android.os.Bundle? args = null);
+  }
+
+  public final class FragmentViewModelLazyKt {
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! activityViewModels(androidx.fragment.app.Fragment, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+    method @MainThread public static <VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<VM> createViewModelLazy(androidx.fragment.app.Fragment, kotlin.reflect.KClass<VM> viewModelClass, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStore> storeProducer, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+    method @MainThread public static inline <reified VM extends androidx.lifecycle.ViewModel> kotlin.Lazy<? extends VM>! viewModels(androidx.fragment.app.Fragment, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelStoreOwner> ownerProducer = { return this }, kotlin.jvm.functions.Function0<? extends androidx.lifecycle.ViewModelProvider.Factory>? factoryProducer = null);
+  }
+
+  public final class ViewKt {
+    method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+  }
+
+}
+
diff --git a/fragment/fragment-testing/api/1.3.0-beta01.txt b/fragment/fragment-testing/api/1.3.0-beta01.txt
new file mode 100644
index 0000000..c3e223b
--- /dev/null
+++ b/fragment/fragment-testing/api/1.3.0-beta01.txt
@@ -0,0 +1,37 @@
+// Signature format: 3.0
+package androidx.fragment.app.testing {
+
+  public final class FragmentScenario<F extends androidx.fragment.app.Fragment> {
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, androidx.fragment.app.FragmentFactory?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.fragment.app.FragmentFactory?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.lifecycle.Lifecycle.State, androidx.fragment.app.FragmentFactory?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, androidx.fragment.app.FragmentFactory?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.fragment.app.FragmentFactory?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.lifecycle.Lifecycle.State, androidx.fragment.app.FragmentFactory?);
+    method public androidx.fragment.app.testing.FragmentScenario<F!> moveToState(androidx.lifecycle.Lifecycle.State);
+    method public androidx.fragment.app.testing.FragmentScenario<F!> onFragment(androidx.fragment.app.testing.FragmentScenario.FragmentAction<F!>);
+    method public androidx.fragment.app.testing.FragmentScenario<F!> recreate();
+  }
+
+  public static interface FragmentScenario.FragmentAction<F extends androidx.fragment.app.Fragment> {
+    method public void perform(F);
+  }
+
+  public final class FragmentScenarioKt {
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.fragment.app.FragmentFactory? factory = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, androidx.fragment.app.FragmentFactory? factory = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.fragment.app.FragmentFactory? factory = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, androidx.fragment.app.FragmentFactory? factory = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment, T> T! withFragment(androidx.fragment.app.testing.FragmentScenario<F>, kotlin.jvm.functions.Function1<? super F,? extends T> block);
+  }
+
+}
+
diff --git a/fragment/fragment-testing/api/public_plus_experimental_1.3.0-beta01.txt b/fragment/fragment-testing/api/public_plus_experimental_1.3.0-beta01.txt
new file mode 100644
index 0000000..c3e223b
--- /dev/null
+++ b/fragment/fragment-testing/api/public_plus_experimental_1.3.0-beta01.txt
@@ -0,0 +1,37 @@
+// Signature format: 3.0
+package androidx.fragment.app.testing {
+
+  public final class FragmentScenario<F extends androidx.fragment.app.Fragment> {
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, androidx.fragment.app.FragmentFactory?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.fragment.app.FragmentFactory?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.lifecycle.Lifecycle.State, androidx.fragment.app.FragmentFactory?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, androidx.fragment.app.FragmentFactory?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.fragment.app.FragmentFactory?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.lifecycle.Lifecycle.State, androidx.fragment.app.FragmentFactory?);
+    method public androidx.fragment.app.testing.FragmentScenario<F!> moveToState(androidx.lifecycle.Lifecycle.State);
+    method public androidx.fragment.app.testing.FragmentScenario<F!> onFragment(androidx.fragment.app.testing.FragmentScenario.FragmentAction<F!>);
+    method public androidx.fragment.app.testing.FragmentScenario<F!> recreate();
+  }
+
+  public static interface FragmentScenario.FragmentAction<F extends androidx.fragment.app.Fragment> {
+    method public void perform(F);
+  }
+
+  public final class FragmentScenarioKt {
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.fragment.app.FragmentFactory? factory = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, androidx.fragment.app.FragmentFactory? factory = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.fragment.app.FragmentFactory? factory = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, androidx.fragment.app.FragmentFactory? factory = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment, T> T! withFragment(androidx.fragment.app.testing.FragmentScenario<F>, kotlin.jvm.functions.Function1<? super F,? extends T> block);
+  }
+
+}
+
diff --git a/fragment/fragment-testing/api/res-1.3.0-beta01.txt b/fragment/fragment-testing/api/res-1.3.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/fragment/fragment-testing/api/res-1.3.0-beta01.txt
diff --git a/fragment/fragment-testing/api/restricted_1.3.0-beta01.txt b/fragment/fragment-testing/api/restricted_1.3.0-beta01.txt
new file mode 100644
index 0000000..c3e223b
--- /dev/null
+++ b/fragment/fragment-testing/api/restricted_1.3.0-beta01.txt
@@ -0,0 +1,37 @@
+// Signature format: 3.0
+package androidx.fragment.app.testing {
+
+  public final class FragmentScenario<F extends androidx.fragment.app.Fragment> {
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, androidx.fragment.app.FragmentFactory?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.fragment.app.FragmentFactory?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launch(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.lifecycle.Lifecycle.State, androidx.fragment.app.FragmentFactory?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, androidx.fragment.app.FragmentFactory?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.fragment.app.FragmentFactory?);
+    method public static <F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F!> launchInContainer(Class<F!>, android.os.Bundle?, @StyleRes int, androidx.lifecycle.Lifecycle.State, androidx.fragment.app.FragmentFactory?);
+    method public androidx.fragment.app.testing.FragmentScenario<F!> moveToState(androidx.lifecycle.Lifecycle.State);
+    method public androidx.fragment.app.testing.FragmentScenario<F!> onFragment(androidx.fragment.app.testing.FragmentScenario.FragmentAction<F!>);
+    method public androidx.fragment.app.testing.FragmentScenario<F!> recreate();
+  }
+
+  public static interface FragmentScenario.FragmentAction<F extends androidx.fragment.app.Fragment> {
+    method public void perform(F);
+  }
+
+  public final class FragmentScenarioKt {
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.fragment.app.FragmentFactory? factory = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, androidx.fragment.app.FragmentFactory? factory = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragment(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.fragment.app.FragmentFactory? factory = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, androidx.fragment.app.FragmentFactory? factory = null);
+    method public static inline <reified F extends androidx.fragment.app.Fragment> androidx.fragment.app.testing.FragmentScenario<F>! launchFragmentInContainer(android.os.Bundle? fragmentArgs = null, @StyleRes int themeResId = androidx.fragment.testing.R.style.FragmentScenarioEmptyFragmentActivityTheme, androidx.lifecycle.Lifecycle.State initialState = androidx.lifecycle.Lifecycle.State.RESUMED, kotlin.jvm.functions.Function0<? extends F> instantiate);
+    method public static inline <reified F extends androidx.fragment.app.Fragment, T> T! withFragment(androidx.fragment.app.testing.FragmentScenario<F>, kotlin.jvm.functions.Function1<? super F,? extends T> block);
+  }
+
+}
+
diff --git a/fragment/fragment/api/1.3.0-beta01.txt b/fragment/fragment/api/1.3.0-beta01.txt
new file mode 100644
index 0000000..6fd13dc
--- /dev/null
+++ b/fragment/fragment/api/1.3.0-beta01.txt
@@ -0,0 +1,450 @@
+// Signature format: 3.0
+package androidx.fragment.app {
+
+  public class DialogFragment extends androidx.fragment.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+    ctor public DialogFragment();
+    ctor public DialogFragment(@LayoutRes int);
+    method public void dismiss();
+    method public void dismissAllowingStateLoss();
+    method public android.app.Dialog? getDialog();
+    method public boolean getShowsDialog();
+    method @StyleRes public int getTheme();
+    method public boolean isCancelable();
+    method public void onCancel(android.content.DialogInterface);
+    method @MainThread public android.app.Dialog onCreateDialog(android.os.Bundle?);
+    method public void onDismiss(android.content.DialogInterface);
+    method public final android.app.Dialog requireDialog();
+    method public void setCancelable(boolean);
+    method public void setShowsDialog(boolean);
+    method public void setStyle(int, @StyleRes int);
+    method public void show(androidx.fragment.app.FragmentManager, String?);
+    method public int show(androidx.fragment.app.FragmentTransaction, String?);
+    method public void showNow(androidx.fragment.app.FragmentManager, String?);
+    field public static final int STYLE_NORMAL = 0; // 0x0
+    field public static final int STYLE_NO_FRAME = 2; // 0x2
+    field public static final int STYLE_NO_INPUT = 3; // 0x3
+    field public static final int STYLE_NO_TITLE = 1; // 0x1
+  }
+
+  public class Fragment implements androidx.activity.result.ActivityResultCaller android.content.ComponentCallbacks androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
+    ctor public Fragment();
+    ctor @ContentView public Fragment(@LayoutRes int);
+    method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public final boolean equals(Object?);
+    method public final androidx.fragment.app.FragmentActivity? getActivity();
+    method public boolean getAllowEnterTransitionOverlap();
+    method public boolean getAllowReturnTransitionOverlap();
+    method public final android.os.Bundle? getArguments();
+    method public final androidx.fragment.app.FragmentManager getChildFragmentManager();
+    method public android.content.Context? getContext();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+    method public Object? getEnterTransition();
+    method public Object? getExitTransition();
+    method @Deprecated public final androidx.fragment.app.FragmentManager? getFragmentManager();
+    method public final Object? getHost();
+    method public final int getId();
+    method public final android.view.LayoutInflater getLayoutInflater();
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+    method @Deprecated public androidx.loader.app.LoaderManager getLoaderManager();
+    method public final androidx.fragment.app.Fragment? getParentFragment();
+    method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
+    method public Object? getReenterTransition();
+    method public final android.content.res.Resources getResources();
+    method @Deprecated public final boolean getRetainInstance();
+    method public Object? getReturnTransition();
+    method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+    method public Object? getSharedElementEnterTransition();
+    method public Object? getSharedElementReturnTransition();
+    method public final String getString(@StringRes int);
+    method public final String getString(@StringRes int, java.lang.Object!...);
+    method public final String? getTag();
+    method @Deprecated public final androidx.fragment.app.Fragment? getTargetFragment();
+    method @Deprecated public final int getTargetRequestCode();
+    method public final CharSequence getText(@StringRes int);
+    method @Deprecated public boolean getUserVisibleHint();
+    method public android.view.View? getView();
+    method @MainThread public androidx.lifecycle.LifecycleOwner getViewLifecycleOwner();
+    method public androidx.lifecycle.LiveData<androidx.lifecycle.LifecycleOwner!> getViewLifecycleOwnerLiveData();
+    method public androidx.lifecycle.ViewModelStore getViewModelStore();
+    method public final int hashCode();
+    method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String);
+    method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+    method public final boolean isAdded();
+    method public final boolean isDetached();
+    method public final boolean isHidden();
+    method public final boolean isInLayout();
+    method public final boolean isRemoving();
+    method public final boolean isResumed();
+    method public final boolean isStateSaved();
+    method public final boolean isVisible();
+    method @Deprecated @CallSuper @MainThread public void onActivityCreated(android.os.Bundle?);
+    method @Deprecated public void onActivityResult(int, int, android.content.Intent?);
+    method @CallSuper @MainThread public void onAttach(android.content.Context);
+    method @Deprecated @CallSuper @MainThread public void onAttach(android.app.Activity);
+    method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+    method @CallSuper public void onConfigurationChanged(android.content.res.Configuration);
+    method @MainThread public boolean onContextItemSelected(android.view.MenuItem);
+    method @CallSuper @MainThread public void onCreate(android.os.Bundle?);
+    method @MainThread public android.view.animation.Animation? onCreateAnimation(int, boolean, int);
+    method @MainThread public android.animation.Animator? onCreateAnimator(int, boolean, int);
+    method @MainThread public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo?);
+    method @MainThread public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method @MainThread public android.view.View? onCreateView(android.view.LayoutInflater, android.view.ViewGroup?, android.os.Bundle?);
+    method @CallSuper @MainThread public void onDestroy();
+    method @MainThread public void onDestroyOptionsMenu();
+    method @CallSuper @MainThread public void onDestroyView();
+    method @CallSuper @MainThread public void onDetach();
+    method public android.view.LayoutInflater onGetLayoutInflater(android.os.Bundle?);
+    method @MainThread public void onHiddenChanged(boolean);
+    method @CallSuper @UiThread public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle?);
+    method @Deprecated @CallSuper @UiThread public void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle?);
+    method @CallSuper @MainThread public void onLowMemory();
+    method public void onMultiWindowModeChanged(boolean);
+    method @MainThread public boolean onOptionsItemSelected(android.view.MenuItem);
+    method @MainThread public void onOptionsMenuClosed(android.view.Menu);
+    method @CallSuper @MainThread public void onPause();
+    method public void onPictureInPictureModeChanged(boolean);
+    method @MainThread public void onPrepareOptionsMenu(android.view.Menu);
+    method @MainThread public void onPrimaryNavigationFragmentChanged(boolean);
+    method @Deprecated public void onRequestPermissionsResult(int, String![], int[]);
+    method @CallSuper @MainThread public void onResume();
+    method @MainThread public void onSaveInstanceState(android.os.Bundle);
+    method @CallSuper @MainThread public void onStart();
+    method @CallSuper @MainThread public void onStop();
+    method @MainThread public void onViewCreated(android.view.View, android.os.Bundle?);
+    method @CallSuper @MainThread public void onViewStateRestored(android.os.Bundle?);
+    method public void postponeEnterTransition();
+    method public final void postponeEnterTransition(long, java.util.concurrent.TimeUnit);
+    method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+    method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+    method public void registerForContextMenu(android.view.View);
+    method @Deprecated public final void requestPermissions(String![], int);
+    method public final androidx.fragment.app.FragmentActivity requireActivity();
+    method public final android.os.Bundle requireArguments();
+    method public final android.content.Context requireContext();
+    method @Deprecated public final androidx.fragment.app.FragmentManager requireFragmentManager();
+    method public final Object requireHost();
+    method public final androidx.fragment.app.Fragment requireParentFragment();
+    method public final android.view.View requireView();
+    method public void setAllowEnterTransitionOverlap(boolean);
+    method public void setAllowReturnTransitionOverlap(boolean);
+    method public void setArguments(android.os.Bundle?);
+    method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setEnterTransition(Object?);
+    method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setExitTransition(Object?);
+    method public void setHasOptionsMenu(boolean);
+    method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
+    method public void setMenuVisibility(boolean);
+    method public void setReenterTransition(Object?);
+    method @Deprecated public void setRetainInstance(boolean);
+    method public void setReturnTransition(Object?);
+    method public void setSharedElementEnterTransition(Object?);
+    method public void setSharedElementReturnTransition(Object?);
+    method @Deprecated public void setTargetFragment(androidx.fragment.app.Fragment?, int);
+    method @Deprecated public void setUserVisibleHint(boolean);
+    method public boolean shouldShowRequestPermissionRationale(String);
+    method public void startActivity(android.content.Intent!);
+    method public void startActivity(android.content.Intent!, android.os.Bundle?);
+    method @Deprecated public void startActivityForResult(android.content.Intent!, int);
+    method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
+    method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void startPostponedEnterTransition();
+    method public void unregisterForContextMenu(android.view.View);
+  }
+
+  public static class Fragment.InstantiationException extends java.lang.RuntimeException {
+    ctor public Fragment.InstantiationException(String, Exception?);
+  }
+
+  public static class Fragment.SavedState implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.fragment.app.Fragment.SavedState!> CREATOR;
+  }
+
+  public class FragmentActivity extends androidx.activity.ComponentActivity implements androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback androidx.lifecycle.LifecycleOwner {
+    ctor public FragmentActivity();
+    ctor @ContentView public FragmentActivity(@LayoutRes int);
+    method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+    method @Deprecated public androidx.loader.app.LoaderManager getSupportLoaderManager();
+    method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+    method @CallSuper public void onMultiWindowModeChanged(boolean);
+    method @CallSuper public void onPictureInPictureModeChanged(boolean);
+    method protected void onResumeFragments();
+    method public void onStateNotSaved();
+    method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
+    method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
+    method @Deprecated public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void supportFinishAfterTransition();
+    method @Deprecated public void supportInvalidateOptionsMenu();
+    method public void supportPostponeEnterTransition();
+    method public void supportStartPostponedEnterTransition();
+    method @Deprecated public final void validateRequestPermissionsRequestCode(int);
+  }
+
+  public abstract class FragmentContainer {
+    ctor public FragmentContainer();
+    method @Deprecated public androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+    method public abstract android.view.View? onFindViewById(@IdRes int);
+    method public abstract boolean onHasView();
+  }
+
+  public final class FragmentContainerView extends android.widget.FrameLayout {
+    ctor public FragmentContainerView(android.content.Context);
+    ctor public FragmentContainerView(android.content.Context, android.util.AttributeSet?);
+    ctor public FragmentContainerView(android.content.Context, android.util.AttributeSet?, int);
+  }
+
+  public class FragmentController {
+    method public void attachHost(androidx.fragment.app.Fragment?);
+    method public static androidx.fragment.app.FragmentController createController(androidx.fragment.app.FragmentHostCallback<?>);
+    method public void dispatchActivityCreated();
+    method public void dispatchConfigurationChanged(android.content.res.Configuration);
+    method public boolean dispatchContextItemSelected(android.view.MenuItem);
+    method public void dispatchCreate();
+    method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method public void dispatchDestroy();
+    method public void dispatchDestroyView();
+    method public void dispatchLowMemory();
+    method public void dispatchMultiWindowModeChanged(boolean);
+    method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+    method public void dispatchOptionsMenuClosed(android.view.Menu);
+    method public void dispatchPause();
+    method public void dispatchPictureInPictureModeChanged(boolean);
+    method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+    method @Deprecated public void dispatchReallyStop();
+    method public void dispatchResume();
+    method public void dispatchStart();
+    method public void dispatchStop();
+    method @Deprecated public void doLoaderDestroy();
+    method @Deprecated public void doLoaderRetain();
+    method @Deprecated public void doLoaderStart();
+    method @Deprecated public void doLoaderStop(boolean);
+    method @Deprecated public void dumpLoaders(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public boolean execPendingActions();
+    method public androidx.fragment.app.Fragment? findFragmentByWho(String);
+    method public java.util.List<androidx.fragment.app.Fragment!> getActiveFragments(java.util.List<androidx.fragment.app.Fragment!>!);
+    method public int getActiveFragmentsCount();
+    method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+    method @Deprecated public androidx.loader.app.LoaderManager! getSupportLoaderManager();
+    method public void noteStateNotSaved();
+    method public android.view.View? onCreateView(android.view.View?, String, android.content.Context, android.util.AttributeSet);
+    method @Deprecated public void reportLoaderStart();
+    method @Deprecated public void restoreAllState(android.os.Parcelable?, java.util.List<androidx.fragment.app.Fragment!>?);
+    method @Deprecated public void restoreAllState(android.os.Parcelable?, androidx.fragment.app.FragmentManagerNonConfig?);
+    method @Deprecated public void restoreLoaderNonConfig(androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>!);
+    method public void restoreSaveState(android.os.Parcelable?);
+    method @Deprecated public androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>? retainLoaderNonConfig();
+    method @Deprecated public androidx.fragment.app.FragmentManagerNonConfig? retainNestedNonConfig();
+    method @Deprecated public java.util.List<androidx.fragment.app.Fragment!>? retainNonConfig();
+    method public android.os.Parcelable? saveAllState();
+  }
+
+  public class FragmentFactory {
+    ctor public FragmentFactory();
+    method public androidx.fragment.app.Fragment instantiate(ClassLoader, String);
+    method public static Class<? extends androidx.fragment.app.Fragment> loadFragmentClass(ClassLoader, String);
+  }
+
+  public abstract class FragmentHostCallback<E> extends androidx.fragment.app.FragmentContainer {
+    ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+    method public void onDump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public android.view.View? onFindViewById(int);
+    method public abstract E? onGetHost();
+    method public android.view.LayoutInflater onGetLayoutInflater();
+    method public int onGetWindowAnimations();
+    method public boolean onHasView();
+    method public boolean onHasWindowAnimations();
+    method @Deprecated public void onRequestPermissionsFromFragment(androidx.fragment.app.Fragment, String![], int);
+    method public boolean onShouldSaveFragmentState(androidx.fragment.app.Fragment);
+    method public boolean onShouldShowRequestPermissionRationale(String);
+    method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
+    method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
+    method @Deprecated public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void onSupportInvalidateOptionsMenu();
+  }
+
+  public abstract class FragmentManager implements androidx.fragment.app.FragmentResultOwner {
+    ctor public FragmentManager();
+    method public void addFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+    method public void addOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+    method public androidx.fragment.app.FragmentTransaction beginTransaction();
+    method public final void clearFragmentResult(String);
+    method public final void clearFragmentResultListener(String);
+    method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method @Deprecated public static void enableDebugLogging(boolean);
+    method public boolean executePendingTransactions();
+    method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+    method public androidx.fragment.app.Fragment? findFragmentById(@IdRes int);
+    method public androidx.fragment.app.Fragment? findFragmentByTag(String?);
+    method public androidx.fragment.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
+    method public int getBackStackEntryCount();
+    method public androidx.fragment.app.Fragment? getFragment(android.os.Bundle, String);
+    method public androidx.fragment.app.FragmentFactory getFragmentFactory();
+    method public java.util.List<androidx.fragment.app.Fragment!> getFragments();
+    method public androidx.fragment.app.Fragment? getPrimaryNavigationFragment();
+    method public boolean isDestroyed();
+    method public boolean isStateSaved();
+    method public void popBackStack();
+    method public void popBackStack(String?, int);
+    method public void popBackStack(int, int);
+    method public boolean popBackStackImmediate();
+    method public boolean popBackStackImmediate(String?, int);
+    method public boolean popBackStackImmediate(int, int);
+    method public void putFragment(android.os.Bundle, String, androidx.fragment.app.Fragment);
+    method public void registerFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks, boolean);
+    method public void removeFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+    method public void removeOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+    method public androidx.fragment.app.Fragment.SavedState? saveFragmentInstanceState(androidx.fragment.app.Fragment);
+    method public void setFragmentFactory(androidx.fragment.app.FragmentFactory);
+    method public final void setFragmentResult(String, android.os.Bundle);
+    method public final void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+    method public void unregisterFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks);
+    field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
+  }
+
+  public static interface FragmentManager.BackStackEntry {
+    method @Deprecated public CharSequence? getBreadCrumbShortTitle();
+    method @Deprecated @StringRes public int getBreadCrumbShortTitleRes();
+    method @Deprecated public CharSequence? getBreadCrumbTitle();
+    method @Deprecated @StringRes public int getBreadCrumbTitleRes();
+    method public int getId();
+    method public String? getName();
+  }
+
+  public abstract static class FragmentManager.FragmentLifecycleCallbacks {
+    ctor public FragmentManager.FragmentLifecycleCallbacks();
+    method @Deprecated public void onFragmentActivityCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+    method public void onFragmentCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentDetached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentPaused(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentPreAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+    method public void onFragmentPreCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentResumed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentSaveInstanceState(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle);
+    method public void onFragmentStarted(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentStopped(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentViewCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.view.View, android.os.Bundle?);
+    method public void onFragmentViewDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+  }
+
+  public static interface FragmentManager.OnBackStackChangedListener {
+    method @MainThread public void onBackStackChanged();
+  }
+
+  @Deprecated public class FragmentManagerNonConfig {
+  }
+
+  public interface FragmentOnAttachListener {
+    method @MainThread public void onAttachFragment(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+  }
+
+  @Deprecated public abstract class FragmentPagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+    ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager);
+    ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager, int);
+    method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+    method @Deprecated public long getItemId(int);
+    method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+    field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+    field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+  }
+
+  public interface FragmentResultListener {
+    method public void onFragmentResult(String, android.os.Bundle);
+  }
+
+  public interface FragmentResultOwner {
+    method public void clearFragmentResult(String);
+    method public void clearFragmentResultListener(String);
+    method public void setFragmentResult(String, android.os.Bundle);
+    method public void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+  }
+
+  @Deprecated public abstract class FragmentStatePagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+    ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager);
+    ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager, int);
+    method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+    method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+    field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+    field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+  }
+
+  @Deprecated public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+    ctor @Deprecated public FragmentTabHost(android.content.Context);
+    ctor @Deprecated public FragmentTabHost(android.content.Context, android.util.AttributeSet?);
+    method @Deprecated public void addTab(android.widget.TabHost.TabSpec, Class<?>, android.os.Bundle?);
+    method @Deprecated public void onTabChanged(String?);
+    method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager);
+    method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager, int);
+  }
+
+  public abstract class FragmentTransaction {
+    ctor @Deprecated public FragmentTransaction();
+    method public final androidx.fragment.app.FragmentTransaction add(Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.Fragment, String?);
+    method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+    method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment, String?);
+    method public androidx.fragment.app.FragmentTransaction addSharedElement(android.view.View, String);
+    method public androidx.fragment.app.FragmentTransaction addToBackStack(String?);
+    method public androidx.fragment.app.FragmentTransaction attach(androidx.fragment.app.Fragment);
+    method public abstract int commit();
+    method public abstract int commitAllowingStateLoss();
+    method public abstract void commitNow();
+    method public abstract void commitNowAllowingStateLoss();
+    method public androidx.fragment.app.FragmentTransaction detach(androidx.fragment.app.Fragment);
+    method public androidx.fragment.app.FragmentTransaction disallowAddToBackStack();
+    method public androidx.fragment.app.FragmentTransaction hide(androidx.fragment.app.Fragment);
+    method public boolean isAddToBackStackAllowed();
+    method public boolean isEmpty();
+    method public androidx.fragment.app.FragmentTransaction remove(androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+    method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment, String?);
+    method public androidx.fragment.app.FragmentTransaction runOnCommit(Runnable);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setAllowOptimization(boolean);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(@StringRes int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(CharSequence?);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(@StringRes int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(CharSequence?);
+    method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+    method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+    method public androidx.fragment.app.FragmentTransaction setMaxLifecycle(androidx.fragment.app.Fragment, androidx.lifecycle.Lifecycle.State);
+    method public androidx.fragment.app.FragmentTransaction setPrimaryNavigationFragment(androidx.fragment.app.Fragment?);
+    method public androidx.fragment.app.FragmentTransaction setReorderingAllowed(boolean);
+    method public androidx.fragment.app.FragmentTransaction setTransition(int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setTransitionStyle(@StyleRes int);
+    method public androidx.fragment.app.FragmentTransaction show(androidx.fragment.app.Fragment);
+    field public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
+    field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
+    field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
+    field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+    field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
+    field public static final int TRANSIT_NONE = 0; // 0x0
+    field public static final int TRANSIT_UNSET = -1; // 0xffffffff
+  }
+
+  public class ListFragment extends androidx.fragment.app.Fragment {
+    ctor public ListFragment();
+    method public android.widget.ListAdapter? getListAdapter();
+    method public android.widget.ListView getListView();
+    method public long getSelectedItemId();
+    method public int getSelectedItemPosition();
+    method public void onListItemClick(android.widget.ListView, android.view.View, int, long);
+    method public final android.widget.ListAdapter requireListAdapter();
+    method public void setEmptyText(CharSequence?);
+    method public void setListAdapter(android.widget.ListAdapter?);
+    method public void setListShown(boolean);
+    method public void setListShownNoAnimation(boolean);
+    method public void setSelection(int);
+  }
+
+}
+
diff --git a/fragment/fragment/api/public_plus_experimental_1.3.0-beta01.txt b/fragment/fragment/api/public_plus_experimental_1.3.0-beta01.txt
new file mode 100644
index 0000000..7512f13
--- /dev/null
+++ b/fragment/fragment/api/public_plus_experimental_1.3.0-beta01.txt
@@ -0,0 +1,454 @@
+// Signature format: 3.0
+package androidx.fragment.app {
+
+  public class DialogFragment extends androidx.fragment.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+    ctor public DialogFragment();
+    ctor public DialogFragment(@LayoutRes int);
+    method public void dismiss();
+    method public void dismissAllowingStateLoss();
+    method public android.app.Dialog? getDialog();
+    method public boolean getShowsDialog();
+    method @StyleRes public int getTheme();
+    method public boolean isCancelable();
+    method public void onCancel(android.content.DialogInterface);
+    method @MainThread public android.app.Dialog onCreateDialog(android.os.Bundle?);
+    method public void onDismiss(android.content.DialogInterface);
+    method public final android.app.Dialog requireDialog();
+    method public void setCancelable(boolean);
+    method public void setShowsDialog(boolean);
+    method public void setStyle(int, @StyleRes int);
+    method public void show(androidx.fragment.app.FragmentManager, String?);
+    method public int show(androidx.fragment.app.FragmentTransaction, String?);
+    method public void showNow(androidx.fragment.app.FragmentManager, String?);
+    field public static final int STYLE_NORMAL = 0; // 0x0
+    field public static final int STYLE_NO_FRAME = 2; // 0x2
+    field public static final int STYLE_NO_INPUT = 3; // 0x3
+    field public static final int STYLE_NO_TITLE = 1; // 0x1
+  }
+
+  public class Fragment implements androidx.activity.result.ActivityResultCaller android.content.ComponentCallbacks androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
+    ctor public Fragment();
+    ctor @ContentView public Fragment(@LayoutRes int);
+    method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public final boolean equals(Object?);
+    method public final androidx.fragment.app.FragmentActivity? getActivity();
+    method public boolean getAllowEnterTransitionOverlap();
+    method public boolean getAllowReturnTransitionOverlap();
+    method public final android.os.Bundle? getArguments();
+    method public final androidx.fragment.app.FragmentManager getChildFragmentManager();
+    method public android.content.Context? getContext();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+    method public Object? getEnterTransition();
+    method public Object? getExitTransition();
+    method @Deprecated public final androidx.fragment.app.FragmentManager? getFragmentManager();
+    method public final Object? getHost();
+    method public final int getId();
+    method public final android.view.LayoutInflater getLayoutInflater();
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+    method @Deprecated public androidx.loader.app.LoaderManager getLoaderManager();
+    method public final androidx.fragment.app.Fragment? getParentFragment();
+    method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
+    method public Object? getReenterTransition();
+    method public final android.content.res.Resources getResources();
+    method @Deprecated public final boolean getRetainInstance();
+    method public Object? getReturnTransition();
+    method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+    method public Object? getSharedElementEnterTransition();
+    method public Object? getSharedElementReturnTransition();
+    method public final String getString(@StringRes int);
+    method public final String getString(@StringRes int, java.lang.Object!...);
+    method public final String? getTag();
+    method @Deprecated public final androidx.fragment.app.Fragment? getTargetFragment();
+    method @Deprecated public final int getTargetRequestCode();
+    method public final CharSequence getText(@StringRes int);
+    method @Deprecated public boolean getUserVisibleHint();
+    method public android.view.View? getView();
+    method @MainThread public androidx.lifecycle.LifecycleOwner getViewLifecycleOwner();
+    method public androidx.lifecycle.LiveData<androidx.lifecycle.LifecycleOwner!> getViewLifecycleOwnerLiveData();
+    method public androidx.lifecycle.ViewModelStore getViewModelStore();
+    method public final int hashCode();
+    method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String);
+    method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+    method public final boolean isAdded();
+    method public final boolean isDetached();
+    method public final boolean isHidden();
+    method public final boolean isInLayout();
+    method public final boolean isRemoving();
+    method public final boolean isResumed();
+    method public final boolean isStateSaved();
+    method public final boolean isVisible();
+    method @Deprecated @CallSuper @MainThread public void onActivityCreated(android.os.Bundle?);
+    method @Deprecated public void onActivityResult(int, int, android.content.Intent?);
+    method @CallSuper @MainThread public void onAttach(android.content.Context);
+    method @Deprecated @CallSuper @MainThread public void onAttach(android.app.Activity);
+    method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+    method @CallSuper public void onConfigurationChanged(android.content.res.Configuration);
+    method @MainThread public boolean onContextItemSelected(android.view.MenuItem);
+    method @CallSuper @MainThread public void onCreate(android.os.Bundle?);
+    method @MainThread public android.view.animation.Animation? onCreateAnimation(int, boolean, int);
+    method @MainThread public android.animation.Animator? onCreateAnimator(int, boolean, int);
+    method @MainThread public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo?);
+    method @MainThread public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method @MainThread public android.view.View? onCreateView(android.view.LayoutInflater, android.view.ViewGroup?, android.os.Bundle?);
+    method @CallSuper @MainThread public void onDestroy();
+    method @MainThread public void onDestroyOptionsMenu();
+    method @CallSuper @MainThread public void onDestroyView();
+    method @CallSuper @MainThread public void onDetach();
+    method public android.view.LayoutInflater onGetLayoutInflater(android.os.Bundle?);
+    method @MainThread public void onHiddenChanged(boolean);
+    method @CallSuper @UiThread public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle?);
+    method @Deprecated @CallSuper @UiThread public void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle?);
+    method @CallSuper @MainThread public void onLowMemory();
+    method public void onMultiWindowModeChanged(boolean);
+    method @MainThread public boolean onOptionsItemSelected(android.view.MenuItem);
+    method @MainThread public void onOptionsMenuClosed(android.view.Menu);
+    method @CallSuper @MainThread public void onPause();
+    method public void onPictureInPictureModeChanged(boolean);
+    method @MainThread public void onPrepareOptionsMenu(android.view.Menu);
+    method @MainThread public void onPrimaryNavigationFragmentChanged(boolean);
+    method @Deprecated public void onRequestPermissionsResult(int, String![], int[]);
+    method @CallSuper @MainThread public void onResume();
+    method @MainThread public void onSaveInstanceState(android.os.Bundle);
+    method @CallSuper @MainThread public void onStart();
+    method @CallSuper @MainThread public void onStop();
+    method @MainThread public void onViewCreated(android.view.View, android.os.Bundle?);
+    method @CallSuper @MainThread public void onViewStateRestored(android.os.Bundle?);
+    method public void postponeEnterTransition();
+    method public final void postponeEnterTransition(long, java.util.concurrent.TimeUnit);
+    method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+    method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+    method public void registerForContextMenu(android.view.View);
+    method @Deprecated public final void requestPermissions(String![], int);
+    method public final androidx.fragment.app.FragmentActivity requireActivity();
+    method public final android.os.Bundle requireArguments();
+    method public final android.content.Context requireContext();
+    method @Deprecated public final androidx.fragment.app.FragmentManager requireFragmentManager();
+    method public final Object requireHost();
+    method public final androidx.fragment.app.Fragment requireParentFragment();
+    method public final android.view.View requireView();
+    method public void setAllowEnterTransitionOverlap(boolean);
+    method public void setAllowReturnTransitionOverlap(boolean);
+    method public void setArguments(android.os.Bundle?);
+    method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setEnterTransition(Object?);
+    method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setExitTransition(Object?);
+    method public void setHasOptionsMenu(boolean);
+    method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
+    method public void setMenuVisibility(boolean);
+    method public void setReenterTransition(Object?);
+    method @Deprecated public void setRetainInstance(boolean);
+    method public void setReturnTransition(Object?);
+    method public void setSharedElementEnterTransition(Object?);
+    method public void setSharedElementReturnTransition(Object?);
+    method @Deprecated public void setTargetFragment(androidx.fragment.app.Fragment?, int);
+    method @Deprecated public void setUserVisibleHint(boolean);
+    method public boolean shouldShowRequestPermissionRationale(String);
+    method public void startActivity(android.content.Intent!);
+    method public void startActivity(android.content.Intent!, android.os.Bundle?);
+    method @Deprecated public void startActivityForResult(android.content.Intent!, int);
+    method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
+    method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void startPostponedEnterTransition();
+    method public void unregisterForContextMenu(android.view.View);
+  }
+
+  public static class Fragment.InstantiationException extends java.lang.RuntimeException {
+    ctor public Fragment.InstantiationException(String, Exception?);
+  }
+
+  public static class Fragment.SavedState implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.fragment.app.Fragment.SavedState!> CREATOR;
+  }
+
+  public class FragmentActivity extends androidx.activity.ComponentActivity implements androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback androidx.core.app.ActivityCompat.RequestPermissionsRequestCodeValidator {
+    ctor public FragmentActivity();
+    ctor @ContentView public FragmentActivity(@LayoutRes int);
+    method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+    method @Deprecated public androidx.loader.app.LoaderManager getSupportLoaderManager();
+    method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+    method @CallSuper public void onMultiWindowModeChanged(boolean);
+    method @CallSuper public void onPictureInPictureModeChanged(boolean);
+    method protected void onResumeFragments();
+    method public void onStateNotSaved();
+    method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
+    method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
+    method @Deprecated public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void supportFinishAfterTransition();
+    method @Deprecated public void supportInvalidateOptionsMenu();
+    method public void supportPostponeEnterTransition();
+    method public void supportStartPostponedEnterTransition();
+    method @Deprecated public final void validateRequestPermissionsRequestCode(int);
+  }
+
+  public abstract class FragmentContainer {
+    ctor public FragmentContainer();
+    method @Deprecated public androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+    method public abstract android.view.View? onFindViewById(@IdRes int);
+    method public abstract boolean onHasView();
+  }
+
+  public final class FragmentContainerView extends android.widget.FrameLayout {
+    ctor public FragmentContainerView(android.content.Context);
+    ctor public FragmentContainerView(android.content.Context, android.util.AttributeSet?);
+    ctor public FragmentContainerView(android.content.Context, android.util.AttributeSet?, int);
+  }
+
+  public class FragmentController {
+    method public void attachHost(androidx.fragment.app.Fragment?);
+    method public static androidx.fragment.app.FragmentController createController(androidx.fragment.app.FragmentHostCallback<?>);
+    method public void dispatchActivityCreated();
+    method public void dispatchConfigurationChanged(android.content.res.Configuration);
+    method public boolean dispatchContextItemSelected(android.view.MenuItem);
+    method public void dispatchCreate();
+    method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method public void dispatchDestroy();
+    method public void dispatchDestroyView();
+    method public void dispatchLowMemory();
+    method public void dispatchMultiWindowModeChanged(boolean);
+    method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+    method public void dispatchOptionsMenuClosed(android.view.Menu);
+    method public void dispatchPause();
+    method public void dispatchPictureInPictureModeChanged(boolean);
+    method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+    method @Deprecated public void dispatchReallyStop();
+    method public void dispatchResume();
+    method public void dispatchStart();
+    method public void dispatchStop();
+    method @Deprecated public void doLoaderDestroy();
+    method @Deprecated public void doLoaderRetain();
+    method @Deprecated public void doLoaderStart();
+    method @Deprecated public void doLoaderStop(boolean);
+    method @Deprecated public void dumpLoaders(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public boolean execPendingActions();
+    method public androidx.fragment.app.Fragment? findFragmentByWho(String);
+    method public java.util.List<androidx.fragment.app.Fragment!> getActiveFragments(java.util.List<androidx.fragment.app.Fragment!>!);
+    method public int getActiveFragmentsCount();
+    method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+    method @Deprecated public androidx.loader.app.LoaderManager! getSupportLoaderManager();
+    method public void noteStateNotSaved();
+    method public android.view.View? onCreateView(android.view.View?, String, android.content.Context, android.util.AttributeSet);
+    method @Deprecated public void reportLoaderStart();
+    method @Deprecated public void restoreAllState(android.os.Parcelable?, java.util.List<androidx.fragment.app.Fragment!>?);
+    method @Deprecated public void restoreAllState(android.os.Parcelable?, androidx.fragment.app.FragmentManagerNonConfig?);
+    method @Deprecated public void restoreLoaderNonConfig(androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>!);
+    method public void restoreSaveState(android.os.Parcelable?);
+    method @Deprecated public androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>? retainLoaderNonConfig();
+    method @Deprecated public androidx.fragment.app.FragmentManagerNonConfig? retainNestedNonConfig();
+    method @Deprecated public java.util.List<androidx.fragment.app.Fragment!>? retainNonConfig();
+    method public android.os.Parcelable? saveAllState();
+  }
+
+  public class FragmentFactory {
+    ctor public FragmentFactory();
+    method public androidx.fragment.app.Fragment instantiate(ClassLoader, String);
+    method public static Class<? extends androidx.fragment.app.Fragment> loadFragmentClass(ClassLoader, String);
+  }
+
+  public abstract class FragmentHostCallback<E> extends androidx.fragment.app.FragmentContainer {
+    ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+    method public void onDump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public android.view.View? onFindViewById(int);
+    method public abstract E? onGetHost();
+    method public android.view.LayoutInflater onGetLayoutInflater();
+    method public int onGetWindowAnimations();
+    method public boolean onHasView();
+    method public boolean onHasWindowAnimations();
+    method @Deprecated public void onRequestPermissionsFromFragment(androidx.fragment.app.Fragment, String![], int);
+    method public boolean onShouldSaveFragmentState(androidx.fragment.app.Fragment);
+    method public boolean onShouldShowRequestPermissionRationale(String);
+    method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
+    method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
+    method @Deprecated public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void onSupportInvalidateOptionsMenu();
+  }
+
+  public abstract class FragmentManager implements androidx.fragment.app.FragmentResultOwner {
+    ctor public FragmentManager();
+    method public void addFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+    method public void addOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+    method public androidx.fragment.app.FragmentTransaction beginTransaction();
+    method public final void clearFragmentResult(String);
+    method public final void clearFragmentResultListener(String);
+    method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method @Deprecated public static void enableDebugLogging(boolean);
+    method @androidx.fragment.app.FragmentStateManagerControl public static void enableNewStateManager(boolean);
+    method public boolean executePendingTransactions();
+    method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+    method public androidx.fragment.app.Fragment? findFragmentById(@IdRes int);
+    method public androidx.fragment.app.Fragment? findFragmentByTag(String?);
+    method public androidx.fragment.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
+    method public int getBackStackEntryCount();
+    method public androidx.fragment.app.Fragment? getFragment(android.os.Bundle, String);
+    method public androidx.fragment.app.FragmentFactory getFragmentFactory();
+    method public java.util.List<androidx.fragment.app.Fragment!> getFragments();
+    method public androidx.fragment.app.Fragment? getPrimaryNavigationFragment();
+    method public boolean isDestroyed();
+    method public boolean isStateSaved();
+    method public void popBackStack();
+    method public void popBackStack(String?, int);
+    method public void popBackStack(int, int);
+    method public boolean popBackStackImmediate();
+    method public boolean popBackStackImmediate(String?, int);
+    method public boolean popBackStackImmediate(int, int);
+    method public void putFragment(android.os.Bundle, String, androidx.fragment.app.Fragment);
+    method public void registerFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks, boolean);
+    method public void removeFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+    method public void removeOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+    method public androidx.fragment.app.Fragment.SavedState? saveFragmentInstanceState(androidx.fragment.app.Fragment);
+    method public void setFragmentFactory(androidx.fragment.app.FragmentFactory);
+    method public final void setFragmentResult(String, android.os.Bundle);
+    method public final void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+    method public void unregisterFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks);
+    field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
+  }
+
+  public static interface FragmentManager.BackStackEntry {
+    method @Deprecated public CharSequence? getBreadCrumbShortTitle();
+    method @Deprecated @StringRes public int getBreadCrumbShortTitleRes();
+    method @Deprecated public CharSequence? getBreadCrumbTitle();
+    method @Deprecated @StringRes public int getBreadCrumbTitleRes();
+    method public int getId();
+    method public String? getName();
+  }
+
+  public abstract static class FragmentManager.FragmentLifecycleCallbacks {
+    ctor public FragmentManager.FragmentLifecycleCallbacks();
+    method @Deprecated public void onFragmentActivityCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+    method public void onFragmentCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentDetached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentPaused(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentPreAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+    method public void onFragmentPreCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentResumed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentSaveInstanceState(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle);
+    method public void onFragmentStarted(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentStopped(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentViewCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.view.View, android.os.Bundle?);
+    method public void onFragmentViewDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+  }
+
+  public static interface FragmentManager.OnBackStackChangedListener {
+    method @MainThread public void onBackStackChanged();
+  }
+
+  @Deprecated public class FragmentManagerNonConfig {
+  }
+
+  public interface FragmentOnAttachListener {
+    method @MainThread public void onAttachFragment(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+  }
+
+  @Deprecated public abstract class FragmentPagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+    ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager);
+    ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager, int);
+    method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+    method @Deprecated public long getItemId(int);
+    method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+    field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+    field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+  }
+
+  public interface FragmentResultListener {
+    method public void onFragmentResult(String, android.os.Bundle);
+  }
+
+  public interface FragmentResultOwner {
+    method public void clearFragmentResult(String);
+    method public void clearFragmentResultListener(String);
+    method public void setFragmentResult(String, android.os.Bundle);
+    method public void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+  }
+
+  @experimental.Experimental(level=androidx.annotation.experimental.Experimental.Level.WARNING) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) public @interface FragmentStateManagerControl {
+  }
+
+  @Deprecated public abstract class FragmentStatePagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+    ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager);
+    ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager, int);
+    method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+    method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+    field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+    field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+  }
+
+  @Deprecated public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+    ctor @Deprecated public FragmentTabHost(android.content.Context);
+    ctor @Deprecated public FragmentTabHost(android.content.Context, android.util.AttributeSet?);
+    method @Deprecated public void addTab(android.widget.TabHost.TabSpec, Class<?>, android.os.Bundle?);
+    method @Deprecated public void onTabChanged(String?);
+    method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager);
+    method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager, int);
+  }
+
+  public abstract class FragmentTransaction {
+    ctor @Deprecated public FragmentTransaction();
+    method public final androidx.fragment.app.FragmentTransaction add(Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.Fragment, String?);
+    method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+    method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment, String?);
+    method public androidx.fragment.app.FragmentTransaction addSharedElement(android.view.View, String);
+    method public androidx.fragment.app.FragmentTransaction addToBackStack(String?);
+    method public androidx.fragment.app.FragmentTransaction attach(androidx.fragment.app.Fragment);
+    method public abstract int commit();
+    method public abstract int commitAllowingStateLoss();
+    method public abstract void commitNow();
+    method public abstract void commitNowAllowingStateLoss();
+    method public androidx.fragment.app.FragmentTransaction detach(androidx.fragment.app.Fragment);
+    method public androidx.fragment.app.FragmentTransaction disallowAddToBackStack();
+    method public androidx.fragment.app.FragmentTransaction hide(androidx.fragment.app.Fragment);
+    method public boolean isAddToBackStackAllowed();
+    method public boolean isEmpty();
+    method public androidx.fragment.app.FragmentTransaction remove(androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+    method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment, String?);
+    method public androidx.fragment.app.FragmentTransaction runOnCommit(Runnable);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setAllowOptimization(boolean);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(@StringRes int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(CharSequence?);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(@StringRes int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(CharSequence?);
+    method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+    method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+    method public androidx.fragment.app.FragmentTransaction setMaxLifecycle(androidx.fragment.app.Fragment, androidx.lifecycle.Lifecycle.State);
+    method public androidx.fragment.app.FragmentTransaction setPrimaryNavigationFragment(androidx.fragment.app.Fragment?);
+    method public androidx.fragment.app.FragmentTransaction setReorderingAllowed(boolean);
+    method public androidx.fragment.app.FragmentTransaction setTransition(int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setTransitionStyle(@StyleRes int);
+    method public androidx.fragment.app.FragmentTransaction show(androidx.fragment.app.Fragment);
+    field public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
+    field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
+    field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
+    field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+    field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
+    field public static final int TRANSIT_NONE = 0; // 0x0
+    field public static final int TRANSIT_UNSET = -1; // 0xffffffff
+  }
+
+  public class ListFragment extends androidx.fragment.app.Fragment {
+    ctor public ListFragment();
+    method public android.widget.ListAdapter? getListAdapter();
+    method public android.widget.ListView getListView();
+    method public long getSelectedItemId();
+    method public int getSelectedItemPosition();
+    method public void onListItemClick(android.widget.ListView, android.view.View, int, long);
+    method public final android.widget.ListAdapter requireListAdapter();
+    method public void setEmptyText(CharSequence?);
+    method public void setListAdapter(android.widget.ListAdapter?);
+    method public void setListShown(boolean);
+    method public void setListShownNoAnimation(boolean);
+    method public void setSelection(int);
+  }
+
+}
+
diff --git a/fragment/fragment/api/res-1.3.0-beta01.txt b/fragment/fragment/api/res-1.3.0-beta01.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/fragment/fragment/api/res-1.3.0-beta01.txt
diff --git a/fragment/fragment/api/restricted_1.3.0-beta01.txt b/fragment/fragment/api/restricted_1.3.0-beta01.txt
new file mode 100644
index 0000000..a2689d8
--- /dev/null
+++ b/fragment/fragment/api/restricted_1.3.0-beta01.txt
@@ -0,0 +1,480 @@
+// Signature format: 3.0
+package androidx.fragment.app {
+
+  public class DialogFragment extends androidx.fragment.app.Fragment implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener {
+    ctor public DialogFragment();
+    ctor public DialogFragment(@LayoutRes int);
+    method public void dismiss();
+    method public void dismissAllowingStateLoss();
+    method public android.app.Dialog? getDialog();
+    method public boolean getShowsDialog();
+    method @StyleRes public int getTheme();
+    method public boolean isCancelable();
+    method public void onCancel(android.content.DialogInterface);
+    method @MainThread public android.app.Dialog onCreateDialog(android.os.Bundle?);
+    method public void onDismiss(android.content.DialogInterface);
+    method public final android.app.Dialog requireDialog();
+    method public void setCancelable(boolean);
+    method public void setShowsDialog(boolean);
+    method public void setStyle(int, @StyleRes int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setupDialog(android.app.Dialog, int);
+    method public void show(androidx.fragment.app.FragmentManager, String?);
+    method public int show(androidx.fragment.app.FragmentTransaction, String?);
+    method public void showNow(androidx.fragment.app.FragmentManager, String?);
+    field public static final int STYLE_NORMAL = 0; // 0x0
+    field public static final int STYLE_NO_FRAME = 2; // 0x2
+    field public static final int STYLE_NO_INPUT = 3; // 0x3
+    field public static final int STYLE_NO_TITLE = 1; // 0x1
+  }
+
+  public class Fragment implements androidx.activity.result.ActivityResultCaller android.content.ComponentCallbacks androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
+    ctor public Fragment();
+    ctor @ContentView public Fragment(@LayoutRes int);
+    method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public final boolean equals(Object?);
+    method public final androidx.fragment.app.FragmentActivity? getActivity();
+    method public boolean getAllowEnterTransitionOverlap();
+    method public boolean getAllowReturnTransitionOverlap();
+    method public final android.os.Bundle? getArguments();
+    method public final androidx.fragment.app.FragmentManager getChildFragmentManager();
+    method public android.content.Context? getContext();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+    method public Object? getEnterTransition();
+    method public Object? getExitTransition();
+    method @Deprecated public final androidx.fragment.app.FragmentManager? getFragmentManager();
+    method public final Object? getHost();
+    method public final int getId();
+    method public final android.view.LayoutInflater getLayoutInflater();
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.view.LayoutInflater getLayoutInflater(android.os.Bundle?);
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+    method @Deprecated public androidx.loader.app.LoaderManager getLoaderManager();
+    method public final androidx.fragment.app.Fragment? getParentFragment();
+    method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
+    method public Object? getReenterTransition();
+    method public final android.content.res.Resources getResources();
+    method @Deprecated public final boolean getRetainInstance();
+    method public Object? getReturnTransition();
+    method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
+    method public Object? getSharedElementEnterTransition();
+    method public Object? getSharedElementReturnTransition();
+    method public final String getString(@StringRes int);
+    method public final String getString(@StringRes int, java.lang.Object!...);
+    method public final String? getTag();
+    method @Deprecated public final androidx.fragment.app.Fragment? getTargetFragment();
+    method @Deprecated public final int getTargetRequestCode();
+    method public final CharSequence getText(@StringRes int);
+    method @Deprecated public boolean getUserVisibleHint();
+    method public android.view.View? getView();
+    method @MainThread public androidx.lifecycle.LifecycleOwner getViewLifecycleOwner();
+    method public androidx.lifecycle.LiveData<androidx.lifecycle.LifecycleOwner!> getViewLifecycleOwnerLiveData();
+    method public androidx.lifecycle.ViewModelStore getViewModelStore();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final boolean hasOptionsMenu();
+    method public final int hashCode();
+    method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String);
+    method @Deprecated public static androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+    method public final boolean isAdded();
+    method public final boolean isDetached();
+    method public final boolean isHidden();
+    method public final boolean isInLayout();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final boolean isMenuVisible();
+    method public final boolean isRemoving();
+    method public final boolean isResumed();
+    method public final boolean isStateSaved();
+    method public final boolean isVisible();
+    method @Deprecated @CallSuper @MainThread public void onActivityCreated(android.os.Bundle?);
+    method @Deprecated public void onActivityResult(int, int, android.content.Intent?);
+    method @CallSuper @MainThread public void onAttach(android.content.Context);
+    method @Deprecated @CallSuper @MainThread public void onAttach(android.app.Activity);
+    method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+    method @CallSuper public void onConfigurationChanged(android.content.res.Configuration);
+    method @MainThread public boolean onContextItemSelected(android.view.MenuItem);
+    method @CallSuper @MainThread public void onCreate(android.os.Bundle?);
+    method @MainThread public android.view.animation.Animation? onCreateAnimation(int, boolean, int);
+    method @MainThread public android.animation.Animator? onCreateAnimator(int, boolean, int);
+    method @MainThread public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo?);
+    method @MainThread public void onCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method @MainThread public android.view.View? onCreateView(android.view.LayoutInflater, android.view.ViewGroup?, android.os.Bundle?);
+    method @CallSuper @MainThread public void onDestroy();
+    method @MainThread public void onDestroyOptionsMenu();
+    method @CallSuper @MainThread public void onDestroyView();
+    method @CallSuper @MainThread public void onDetach();
+    method public android.view.LayoutInflater onGetLayoutInflater(android.os.Bundle?);
+    method @MainThread public void onHiddenChanged(boolean);
+    method @CallSuper @UiThread public void onInflate(android.content.Context, android.util.AttributeSet, android.os.Bundle?);
+    method @Deprecated @CallSuper @UiThread public void onInflate(android.app.Activity, android.util.AttributeSet, android.os.Bundle?);
+    method @CallSuper @MainThread public void onLowMemory();
+    method public void onMultiWindowModeChanged(boolean);
+    method @MainThread public boolean onOptionsItemSelected(android.view.MenuItem);
+    method @MainThread public void onOptionsMenuClosed(android.view.Menu);
+    method @CallSuper @MainThread public void onPause();
+    method public void onPictureInPictureModeChanged(boolean);
+    method @MainThread public void onPrepareOptionsMenu(android.view.Menu);
+    method @MainThread public void onPrimaryNavigationFragmentChanged(boolean);
+    method @Deprecated public void onRequestPermissionsResult(int, String![], int[]);
+    method @CallSuper @MainThread public void onResume();
+    method @MainThread public void onSaveInstanceState(android.os.Bundle);
+    method @CallSuper @MainThread public void onStart();
+    method @CallSuper @MainThread public void onStop();
+    method @MainThread public void onViewCreated(android.view.View, android.os.Bundle?);
+    method @CallSuper @MainThread public void onViewStateRestored(android.os.Bundle?);
+    method public void postponeEnterTransition();
+    method public final void postponeEnterTransition(long, java.util.concurrent.TimeUnit);
+    method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultCallback<O!>);
+    method @MainThread public final <I, O> androidx.activity.result.ActivityResultLauncher<I!> registerForActivityResult(androidx.activity.result.contract.ActivityResultContract<I!,O!>, androidx.activity.result.ActivityResultRegistry, androidx.activity.result.ActivityResultCallback<O!>);
+    method public void registerForContextMenu(android.view.View);
+    method @Deprecated public final void requestPermissions(String![], int);
+    method public final androidx.fragment.app.FragmentActivity requireActivity();
+    method public final android.os.Bundle requireArguments();
+    method public final android.content.Context requireContext();
+    method @Deprecated public final androidx.fragment.app.FragmentManager requireFragmentManager();
+    method public final Object requireHost();
+    method public final androidx.fragment.app.Fragment requireParentFragment();
+    method public final android.view.View requireView();
+    method public void setAllowEnterTransitionOverlap(boolean);
+    method public void setAllowReturnTransitionOverlap(boolean);
+    method public void setArguments(android.os.Bundle?);
+    method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setEnterTransition(Object?);
+    method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setExitTransition(Object?);
+    method public void setHasOptionsMenu(boolean);
+    method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
+    method public void setMenuVisibility(boolean);
+    method public void setReenterTransition(Object?);
+    method @Deprecated public void setRetainInstance(boolean);
+    method public void setReturnTransition(Object?);
+    method public void setSharedElementEnterTransition(Object?);
+    method public void setSharedElementReturnTransition(Object?);
+    method @Deprecated public void setTargetFragment(androidx.fragment.app.Fragment?, int);
+    method @Deprecated public void setUserVisibleHint(boolean);
+    method public boolean shouldShowRequestPermissionRationale(String);
+    method public void startActivity(android.content.Intent!);
+    method public void startActivity(android.content.Intent!, android.os.Bundle?);
+    method @Deprecated public void startActivityForResult(android.content.Intent!, int);
+    method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
+    method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void startPostponedEnterTransition();
+    method public void unregisterForContextMenu(android.view.View);
+  }
+
+  public static class Fragment.InstantiationException extends java.lang.RuntimeException {
+    ctor public Fragment.InstantiationException(String, Exception?);
+  }
+
+  public static class Fragment.SavedState implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.fragment.app.Fragment.SavedState!> CREATOR;
+  }
+
+  public class FragmentActivity extends androidx.activity.ComponentActivity implements androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback androidx.core.app.ActivityCompat.RequestPermissionsRequestCodeValidator {
+    ctor public FragmentActivity();
+    ctor @ContentView public FragmentActivity(@LayoutRes int);
+    method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+    method @Deprecated public androidx.loader.app.LoaderManager getSupportLoaderManager();
+    method @Deprecated @MainThread public void onAttachFragment(androidx.fragment.app.Fragment);
+    method @CallSuper public void onMultiWindowModeChanged(boolean);
+    method @CallSuper public void onPictureInPictureModeChanged(boolean);
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected boolean onPrepareOptionsPanel(android.view.View?, android.view.Menu);
+    method protected void onResumeFragments();
+    method public void onStateNotSaved();
+    method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
+    method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
+    method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
+    method @Deprecated public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void supportFinishAfterTransition();
+    method @Deprecated public void supportInvalidateOptionsMenu();
+    method public void supportPostponeEnterTransition();
+    method public void supportStartPostponedEnterTransition();
+    method @Deprecated public final void validateRequestPermissionsRequestCode(int);
+  }
+
+  public abstract class FragmentContainer {
+    ctor public FragmentContainer();
+    method @Deprecated public androidx.fragment.app.Fragment instantiate(android.content.Context, String, android.os.Bundle?);
+    method public abstract android.view.View? onFindViewById(@IdRes int);
+    method public abstract boolean onHasView();
+  }
+
+  public final class FragmentContainerView extends android.widget.FrameLayout {
+    ctor public FragmentContainerView(android.content.Context);
+    ctor public FragmentContainerView(android.content.Context, android.util.AttributeSet?);
+    ctor public FragmentContainerView(android.content.Context, android.util.AttributeSet?, int);
+  }
+
+  public class FragmentController {
+    method public void attachHost(androidx.fragment.app.Fragment?);
+    method public static androidx.fragment.app.FragmentController createController(androidx.fragment.app.FragmentHostCallback<?>);
+    method public void dispatchActivityCreated();
+    method public void dispatchConfigurationChanged(android.content.res.Configuration);
+    method public boolean dispatchContextItemSelected(android.view.MenuItem);
+    method public void dispatchCreate();
+    method public boolean dispatchCreateOptionsMenu(android.view.Menu, android.view.MenuInflater);
+    method public void dispatchDestroy();
+    method public void dispatchDestroyView();
+    method public void dispatchLowMemory();
+    method public void dispatchMultiWindowModeChanged(boolean);
+    method public boolean dispatchOptionsItemSelected(android.view.MenuItem);
+    method public void dispatchOptionsMenuClosed(android.view.Menu);
+    method public void dispatchPause();
+    method public void dispatchPictureInPictureModeChanged(boolean);
+    method public boolean dispatchPrepareOptionsMenu(android.view.Menu);
+    method @Deprecated public void dispatchReallyStop();
+    method public void dispatchResume();
+    method public void dispatchStart();
+    method public void dispatchStop();
+    method @Deprecated public void doLoaderDestroy();
+    method @Deprecated public void doLoaderRetain();
+    method @Deprecated public void doLoaderStart();
+    method @Deprecated public void doLoaderStop(boolean);
+    method @Deprecated public void dumpLoaders(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public boolean execPendingActions();
+    method public androidx.fragment.app.Fragment? findFragmentByWho(String);
+    method public java.util.List<androidx.fragment.app.Fragment!> getActiveFragments(java.util.List<androidx.fragment.app.Fragment!>!);
+    method public int getActiveFragmentsCount();
+    method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
+    method @Deprecated public androidx.loader.app.LoaderManager! getSupportLoaderManager();
+    method public void noteStateNotSaved();
+    method public android.view.View? onCreateView(android.view.View?, String, android.content.Context, android.util.AttributeSet);
+    method @Deprecated public void reportLoaderStart();
+    method @Deprecated public void restoreAllState(android.os.Parcelable?, java.util.List<androidx.fragment.app.Fragment!>?);
+    method @Deprecated public void restoreAllState(android.os.Parcelable?, androidx.fragment.app.FragmentManagerNonConfig?);
+    method @Deprecated public void restoreLoaderNonConfig(androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>!);
+    method public void restoreSaveState(android.os.Parcelable?);
+    method @Deprecated public androidx.collection.SimpleArrayMap<java.lang.String!,androidx.loader.app.LoaderManager!>? retainLoaderNonConfig();
+    method @Deprecated public androidx.fragment.app.FragmentManagerNonConfig? retainNestedNonConfig();
+    method @Deprecated public java.util.List<androidx.fragment.app.Fragment!>? retainNonConfig();
+    method public android.os.Parcelable? saveAllState();
+  }
+
+  public class FragmentFactory {
+    ctor public FragmentFactory();
+    method public androidx.fragment.app.Fragment instantiate(ClassLoader, String);
+    method public static Class<? extends androidx.fragment.app.Fragment> loadFragmentClass(ClassLoader, String);
+  }
+
+  public abstract class FragmentHostCallback<E> extends androidx.fragment.app.FragmentContainer {
+    ctor public FragmentHostCallback(android.content.Context, android.os.Handler, int);
+    method public void onDump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method public android.view.View? onFindViewById(int);
+    method public abstract E? onGetHost();
+    method public android.view.LayoutInflater onGetLayoutInflater();
+    method public int onGetWindowAnimations();
+    method public boolean onHasView();
+    method public boolean onHasWindowAnimations();
+    method @Deprecated public void onRequestPermissionsFromFragment(androidx.fragment.app.Fragment, String![], int);
+    method public boolean onShouldSaveFragmentState(androidx.fragment.app.Fragment);
+    method public boolean onShouldShowRequestPermissionRationale(String);
+    method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
+    method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
+    method @Deprecated public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public void onSupportInvalidateOptionsMenu();
+  }
+
+  public abstract class FragmentManager implements androidx.fragment.app.FragmentResultOwner {
+    ctor public FragmentManager();
+    method public void addFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+    method public void addOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+    method public androidx.fragment.app.FragmentTransaction beginTransaction();
+    method public final void clearFragmentResult(String);
+    method public final void clearFragmentResultListener(String);
+    method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
+    method @Deprecated public static void enableDebugLogging(boolean);
+    method public boolean executePendingTransactions();
+    method public static <F extends androidx.fragment.app.Fragment> F findFragment(android.view.View);
+    method public androidx.fragment.app.Fragment? findFragmentById(@IdRes int);
+    method public androidx.fragment.app.Fragment? findFragmentByTag(String?);
+    method public androidx.fragment.app.FragmentManager.BackStackEntry getBackStackEntryAt(int);
+    method public int getBackStackEntryCount();
+    method public androidx.fragment.app.Fragment? getFragment(android.os.Bundle, String);
+    method public androidx.fragment.app.FragmentFactory getFragmentFactory();
+    method public java.util.List<androidx.fragment.app.Fragment!> getFragments();
+    method public androidx.fragment.app.Fragment? getPrimaryNavigationFragment();
+    method public boolean isDestroyed();
+    method public boolean isStateSaved();
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.fragment.app.FragmentTransaction openTransaction();
+    method public void popBackStack();
+    method public void popBackStack(String?, int);
+    method public void popBackStack(int, int);
+    method public boolean popBackStackImmediate();
+    method public boolean popBackStackImmediate(String?, int);
+    method public boolean popBackStackImmediate(int, int);
+    method public void putFragment(android.os.Bundle, String, androidx.fragment.app.Fragment);
+    method public void registerFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks, boolean);
+    method public void removeFragmentOnAttachListener(androidx.fragment.app.FragmentOnAttachListener);
+    method public void removeOnBackStackChangedListener(androidx.fragment.app.FragmentManager.OnBackStackChangedListener);
+    method public androidx.fragment.app.Fragment.SavedState? saveFragmentInstanceState(androidx.fragment.app.Fragment);
+    method public void setFragmentFactory(androidx.fragment.app.FragmentFactory);
+    method public final void setFragmentResult(String, android.os.Bundle);
+    method public final void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+    method public void unregisterFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks);
+    field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
+  }
+
+  public static interface FragmentManager.BackStackEntry {
+    method @Deprecated public CharSequence? getBreadCrumbShortTitle();
+    method @Deprecated @StringRes public int getBreadCrumbShortTitleRes();
+    method @Deprecated public CharSequence? getBreadCrumbTitle();
+    method @Deprecated @StringRes public int getBreadCrumbTitleRes();
+    method public int getId();
+    method public String? getName();
+  }
+
+  public abstract static class FragmentManager.FragmentLifecycleCallbacks {
+    ctor public FragmentManager.FragmentLifecycleCallbacks();
+    method @Deprecated public void onFragmentActivityCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+    method public void onFragmentCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentDetached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentPaused(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentPreAttached(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.content.Context);
+    method public void onFragmentPreCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle?);
+    method public void onFragmentResumed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentSaveInstanceState(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.os.Bundle);
+    method public void onFragmentStarted(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentStopped(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+    method public void onFragmentViewCreated(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment, android.view.View, android.os.Bundle?);
+    method public void onFragmentViewDestroyed(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+  }
+
+  public static interface FragmentManager.OnBackStackChangedListener {
+    method @MainThread public void onBackStackChanged();
+  }
+
+  @Deprecated public class FragmentManagerNonConfig {
+  }
+
+  public interface FragmentOnAttachListener {
+    method @MainThread public void onAttachFragment(androidx.fragment.app.FragmentManager, androidx.fragment.app.Fragment);
+  }
+
+  @Deprecated public abstract class FragmentPagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+    ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager);
+    ctor @Deprecated public FragmentPagerAdapter(androidx.fragment.app.FragmentManager, int);
+    method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+    method @Deprecated public long getItemId(int);
+    method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+    field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+    field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+  }
+
+  public interface FragmentResultListener {
+    method public void onFragmentResult(String, android.os.Bundle);
+  }
+
+  public interface FragmentResultOwner {
+    method public void clearFragmentResult(String);
+    method public void clearFragmentResultListener(String);
+    method public void setFragmentResult(String, android.os.Bundle);
+    method public void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
+  }
+
+  @Deprecated public abstract class FragmentStatePagerAdapter extends androidx.viewpager.widget.PagerAdapter {
+    ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager);
+    ctor @Deprecated public FragmentStatePagerAdapter(androidx.fragment.app.FragmentManager, int);
+    method @Deprecated public abstract androidx.fragment.app.Fragment getItem(int);
+    method @Deprecated public boolean isViewFromObject(android.view.View, Object);
+    field @Deprecated public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1; // 0x1
+    field @Deprecated public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0; // 0x0
+  }
+
+  @Deprecated public class FragmentTabHost extends android.widget.TabHost implements android.widget.TabHost.OnTabChangeListener {
+    ctor @Deprecated public FragmentTabHost(android.content.Context);
+    ctor @Deprecated public FragmentTabHost(android.content.Context, android.util.AttributeSet?);
+    method @Deprecated public void addTab(android.widget.TabHost.TabSpec, Class<?>, android.os.Bundle?);
+    method @Deprecated public void onTabChanged(String?);
+    method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager);
+    method @Deprecated public void setup(android.content.Context, androidx.fragment.app.FragmentManager, int);
+  }
+
+  public abstract class FragmentTransaction {
+    ctor @Deprecated public FragmentTransaction();
+    method public final androidx.fragment.app.FragmentTransaction add(Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction add(androidx.fragment.app.Fragment, String?);
+    method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+    method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction add(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction add(@IdRes int, androidx.fragment.app.Fragment, String?);
+    method public androidx.fragment.app.FragmentTransaction addSharedElement(android.view.View, String);
+    method public androidx.fragment.app.FragmentTransaction addToBackStack(String?);
+    method public androidx.fragment.app.FragmentTransaction attach(androidx.fragment.app.Fragment);
+    method public abstract int commit();
+    method public abstract int commitAllowingStateLoss();
+    method public abstract void commitNow();
+    method public abstract void commitNowAllowingStateLoss();
+    method public androidx.fragment.app.FragmentTransaction detach(androidx.fragment.app.Fragment);
+    method public androidx.fragment.app.FragmentTransaction disallowAddToBackStack();
+    method public androidx.fragment.app.FragmentTransaction hide(androidx.fragment.app.Fragment);
+    method public boolean isAddToBackStackAllowed();
+    method public boolean isEmpty();
+    method public androidx.fragment.app.FragmentTransaction remove(androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?);
+    method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment);
+    method public final androidx.fragment.app.FragmentTransaction replace(@IdRes int, Class<? extends androidx.fragment.app.Fragment>, android.os.Bundle?, String?);
+    method public androidx.fragment.app.FragmentTransaction replace(@IdRes int, androidx.fragment.app.Fragment, String?);
+    method public androidx.fragment.app.FragmentTransaction runOnCommit(Runnable);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setAllowOptimization(boolean);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(@StringRes int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbShortTitle(CharSequence?);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(@StringRes int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setBreadCrumbTitle(CharSequence?);
+    method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+    method public androidx.fragment.app.FragmentTransaction setCustomAnimations(@AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int, @AnimRes @AnimatorRes int);
+    method public androidx.fragment.app.FragmentTransaction setMaxLifecycle(androidx.fragment.app.Fragment, androidx.lifecycle.Lifecycle.State);
+    method public androidx.fragment.app.FragmentTransaction setPrimaryNavigationFragment(androidx.fragment.app.Fragment?);
+    method public androidx.fragment.app.FragmentTransaction setReorderingAllowed(boolean);
+    method public androidx.fragment.app.FragmentTransaction setTransition(int);
+    method @Deprecated public androidx.fragment.app.FragmentTransaction setTransitionStyle(@StyleRes int);
+    method public androidx.fragment.app.FragmentTransaction show(androidx.fragment.app.Fragment);
+    field public static final int TRANSIT_ENTER_MASK = 4096; // 0x1000
+    field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
+    field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
+    field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+    field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
+    field public static final int TRANSIT_NONE = 0; // 0x0
+    field public static final int TRANSIT_UNSET = -1; // 0xffffffff
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public abstract class FragmentTransitionImpl {
+    ctor public FragmentTransitionImpl();
+    method public abstract void addTarget(Object!, android.view.View!);
+    method public abstract void addTargets(Object!, java.util.ArrayList<android.view.View!>!);
+    method public abstract void beginDelayedTransition(android.view.ViewGroup!, Object!);
+    method protected static void bfsAddViewChildren(java.util.List<android.view.View!>!, android.view.View!);
+    method public abstract boolean canHandle(Object!);
+    method public abstract Object! cloneTransition(Object!);
+    method protected void getBoundsOnScreen(android.view.View!, android.graphics.Rect!);
+    method protected static boolean isNullOrEmpty(java.util.List!);
+    method public abstract Object! mergeTransitionsInSequence(Object!, Object!, Object!);
+    method public abstract Object! mergeTransitionsTogether(Object!, Object!, Object!);
+    method public abstract void removeTarget(Object!, android.view.View!);
+    method public abstract void replaceTargets(Object!, java.util.ArrayList<android.view.View!>!, java.util.ArrayList<android.view.View!>!);
+    method public abstract void scheduleHideFragmentView(Object!, android.view.View!, java.util.ArrayList<android.view.View!>!);
+    method public abstract void scheduleRemoveTargets(Object!, Object!, java.util.ArrayList<android.view.View!>!, Object!, java.util.ArrayList<android.view.View!>!, Object!, java.util.ArrayList<android.view.View!>!);
+    method public abstract void setEpicenter(Object!, android.view.View!);
+    method public abstract void setEpicenter(Object!, android.graphics.Rect!);
+    method public void setListenerForTransitionEnd(androidx.fragment.app.Fragment, Object, androidx.core.os.CancellationSignal, Runnable);
+    method public abstract void setSharedElementTargets(Object!, android.view.View!, java.util.ArrayList<android.view.View!>!);
+    method public abstract void swapSharedElementTargets(Object!, java.util.ArrayList<android.view.View!>!, java.util.ArrayList<android.view.View!>!);
+    method public abstract Object! wrapTransitionInSet(Object!);
+  }
+
+  public class ListFragment extends androidx.fragment.app.Fragment {
+    ctor public ListFragment();
+    method public android.widget.ListAdapter? getListAdapter();
+    method public android.widget.ListView getListView();
+    method public long getSelectedItemId();
+    method public int getSelectedItemPosition();
+    method public void onListItemClick(android.widget.ListView, android.view.View, int, long);
+    method public final android.widget.ListAdapter requireListAdapter();
+    method public void setEmptyText(CharSequence?);
+    method public void setListAdapter(android.widget.ListAdapter?);
+    method public void setListShown(boolean);
+    method public void setListShownNoAnimation(boolean);
+    method public void setSelection(int);
+  }
+
+}
+
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionTest.kt
index e66d0f0..34a7ff9 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitionTest.kt
@@ -224,6 +224,21 @@
         verifyPopTransition(1, fragment2, fragment1)
     }
 
+    @Test
+    fun noSharedElementToSharedElement() {
+        val fragment1 = setupInitialFragment()
+
+        // Now do a transition to scene2
+        val fragment2 = SharedElementOnlyTransitionFragment()
+
+        verifyTransition(fragment1, fragment2, "blueSquare")
+
+        // Now pop the back stack
+        verifyPopTransition(1, fragment2, fragment1)
+
+        assertThat(fragment2.destroyViewCountDownLatch.await(1000, TimeUnit.MILLISECONDS)).isTrue()
+    }
+
     // Test that shared elements transition from one fragment to the next
     // and back during pop.
     @Suppress("DEPRECATION")
@@ -1242,9 +1257,11 @@
         }
         verifyNoOtherTransitions(from)
 
-        to.enterTransition.verifyAndClearTransition {
-            epicenter = endBlueRect
-            enteringViews += listOfNotNull(endGreen, endRed)
+        if (to.getEnterTransition() != null) {
+            to.enterTransition.verifyAndClearTransition {
+                epicenter = endBlueRect
+                enteringViews += listOfNotNull(endGreen, endRed)
+            }
         }
 
         to.sharedElementEnter.verifyAndClearTransition {
@@ -1420,9 +1437,11 @@
         val endRed = activityRule.findRed()
         val endSharedRect = endBlue.boundsOnScreen
 
-        from.returnTransition.verifyAndClearTransition {
-            epicenter = startSharedRect
-            exitingViews += listOfNotNull(startGreen, startRed)
+        if (from.getReturnTransition() != null) {
+            from.returnTransition.verifyAndClearTransition {
+                epicenter = startSharedRect
+                exitingViews += listOfNotNull(startGreen, startRed)
+            }
         }
         from.sharedElementReturn.verifyAndClearTransition {
             epicenter = startSharedRect
@@ -1483,6 +1502,28 @@
         }
     }
 
+    // Transition fragment with only shared element transitions
+    class SharedElementOnlyTransitionFragment : TransitionFragment(R.layout.scene2) {
+        val destroyViewCountDownLatch = CountDownLatch(1)
+        override fun onCreate(savedInstanceState: Bundle?) {
+            super.onCreate(savedInstanceState)
+
+            setEnterTransition(null)
+            setReenterTransition(null)
+            setExitTransition(null)
+            setReturnTransition(null)
+            enterTransition.addListener(null)
+            reenterTransition.addListener(null)
+            exitTransition.addListener(null)
+            returnTransition.addListener(null)
+        }
+
+        override fun onDestroyView() {
+            super.onDestroyView()
+            destroyViewCountDownLatch.countDown()
+        }
+    }
+
     class TestShowHideTransitionListener(
         fragment: TransitionFragment
     ) : TestTransitionFragmentListener(
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/PrimaryNavFragmentTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/PrimaryNavFragmentTest.kt
index 487b217..26c2dec 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/PrimaryNavFragmentTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/PrimaryNavFragmentTest.kt
@@ -233,7 +233,7 @@
             .commit()
         executePendingTransactions(fm)
 
-        assertThat(navigations.drain()).isEqualTo(listOf(trackingFragment1 to true))
+        assertThat(navigations.drain()).containsExactly(trackingFragment1 to true).inOrder()
         assertWithMessage("new fragment is not primary nav fragment")
             .that(fm.primaryNavigationFragment)
             .isSameInstanceAs(trackingFragment1)
@@ -246,8 +246,8 @@
             .commit()
         executePendingTransactions(fm)
 
-        assertThat(navigations.drain()).isEqualTo(
-            listOf(trackingFragment1 to false, trackingFragment2 to true))
+        assertThat(navigations.drain()).containsExactly(
+            trackingFragment1 to false, trackingFragment2 to true).inOrder()
         assertWithMessage("primary nav fragment not set correctly after replace")
             .that(fm.primaryNavigationFragment)
             .isSameInstanceAs(trackingFragment2)
@@ -256,7 +256,8 @@
 
         // Note that strictFragment2 does not get a callback since the
         // pop of the replace happens before the pop of the setPrimaryFragment
-        assertThat(navigations.drain()).isEqualTo(listOf(trackingFragment1 to true))
+        assertThat(navigations.drain()).containsExactly(
+            trackingFragment2 to false, trackingFragment1 to true).inOrder()
         assertWithMessage("primary nav fragment is restored after popping replace")
             .that(fm.primaryNavigationFragment)
             .isSameInstanceAs(trackingFragment1)
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/StrictViewFragment.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/StrictViewFragment.kt
index 5bca8e8..17d7bab 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/StrictViewFragment.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/StrictViewFragment.kt
@@ -69,6 +69,13 @@
         assertWithMessage("getView returned null in onDestroyView")
             .that(view)
             .isNotNull()
+        if (requireView().parent != null &&
+            requireView().animation != null &&
+            FragmentManager.USE_STATE_MANAGER) {
+            assertWithMessage("View should be removed from parent if there is no animation")
+                .that((requireView().parent as ViewGroup).layoutTransition)
+                .isNotNull()
+        }
         checkGetActivity()
         checkState("onDestroyView", State.CREATED)
         onDestroyViewCalled = true
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java b/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
index 4bc88fb..ce2159f 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
@@ -443,14 +443,12 @@
                     throw new IllegalArgumentException("Unknown cmd: " + op.mCmd);
             }
             if (!mReorderingAllowed && op.mCmd != OP_ADD && f != null) {
-                if (FragmentManager.USE_STATE_MANAGER) {
-                    mManager.createOrGetFragmentStateManager(f).moveToExpectedState();
-                } else {
+                if (!FragmentManager.USE_STATE_MANAGER) {
                     mManager.moveFragmentToExpectedState(f);
                 }
             }
         }
-        if (!mReorderingAllowed) {
+        if (!mReorderingAllowed && !FragmentManager.USE_STATE_MANAGER) {
             // Added fragments are added at the end to comply with prior behavior.
             mManager.moveToState(mManager.mCurState, true);
         }
@@ -513,14 +511,12 @@
                     throw new IllegalArgumentException("Unknown cmd: " + op.mCmd);
             }
             if (!mReorderingAllowed && op.mCmd != OP_REMOVE && f != null) {
-                if (FragmentManager.USE_STATE_MANAGER) {
-                    mManager.createOrGetFragmentStateManager(f).moveToExpectedState();
-                } else {
+                if (!FragmentManager.USE_STATE_MANAGER) {
                     mManager.moveFragmentToExpectedState(f);
                 }
             }
         }
-        if (!mReorderingAllowed && moveToState) {
+        if (!mReorderingAllowed && moveToState && !FragmentManager.USE_STATE_MANAGER) {
             mManager.moveToState(mManager.mCurState, true);
         }
     }
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java b/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java
index dbfc93b..5ce764d 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java
@@ -601,7 +601,10 @@
                 continue;
             }
             Object transition = transitionInfo.getTransition();
-            if (transition != null) {
+            Operation operation = transitionInfo.getOperation();
+            boolean involvedInSharedElementTransition = sharedElementTransition != null
+                    && (operation == firstOut || operation == lastIn);
+            if (transition != null || involvedInSharedElementTransition) {
                 transitionImpl.setListenerForTransitionEnd(
                         transitionInfo.getOperation().getFragment(),
                         mergedTransition,
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
index ea8735a..5edfbff 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
@@ -2662,7 +2662,8 @@
      * Calling postponeEnterTransition on Fragments with a null View will not postpone the
      * transition. Likewise, postponement only works if
      * {@link FragmentTransaction#setReorderingAllowed(boolean) FragmentTransaction reordering} is
-     * enabled.
+     * enabled if you have called {@link FragmentManager#enableNewStateManager(boolean)} with
+     * <code>false</code>.
      *
      * @see Activity#postponeEnterTransition()
      * @see FragmentTransaction#setReorderingAllowed(boolean)
@@ -2694,7 +2695,8 @@
      * Calling postponeEnterTransition on Fragments with a null View will not postpone the
      * transition. Likewise, postponement only works if
      * {@link FragmentTransaction#setReorderingAllowed(boolean) FragmentTransaction reordering} is
-     * enabled.
+     * enabled if you have called {@link FragmentManager#enableNewStateManager(boolean)} with
+     * <code>false</code>.
      *
      * @param duration The length of the delay in {@code timeUnit} units
      * @param timeUnit The units of time for {@code duration}
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentLayoutInflaterFactory.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentLayoutInflaterFactory.java
index 89852add..db10bbf 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentLayoutInflaterFactory.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentLayoutInflaterFactory.java
@@ -22,6 +22,7 @@
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -88,11 +89,6 @@
             fragment = mFragmentManager.findFragmentById(containerId);
         }
 
-        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
-            Log.v(TAG, "onCreateView: id=0x"
-                    + Integer.toHexString(id) + " fname=" + fname
-                    + " existing=" + fragment);
-        }
         FragmentStateManager fragmentStateManager;
         if (fragment == null) {
             fragment = mFragmentManager.getFragmentFactory().instantiate(
@@ -108,6 +104,10 @@
                     fragment.mSavedFragmentState);
             fragmentStateManager = mFragmentManager.createOrGetFragmentStateManager(fragment);
             mFragmentManager.addFragment(fragment);
+            if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+                Log.v(FragmentManager.TAG, "Fragment " + fragment + " has been inflated via "
+                        + "the <fragment> tag: id=0x" + Integer.toHexString(id));
+            }
 
         } else if (fragment.mInLayout) {
             // A fragment already exists and it is not one we restored from
@@ -126,8 +126,16 @@
             fragment.onInflate(mFragmentManager.getHost().getContext(), attrs,
                     fragment.mSavedFragmentState);
             fragmentStateManager = mFragmentManager.createOrGetFragmentStateManager(fragment);
+            if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+                Log.v(FragmentManager.TAG, "Retained Fragment " + fragment + " has been "
+                        + "re-attached via the <fragment> tag: id=0x" + Integer.toHexString(id));
+            }
         }
 
+        // Explicitly set the container for the fragment as we already know
+        // the parent that the fragment will be added to by the LayoutInflater
+        fragment.mContainer = (ViewGroup) parent;
+
         // The <fragment> tag is the one case where we:
         // 1) Move the Fragment to CREATED even if the FragmentManager isn't yet CREATED
         fragmentStateManager.moveToExpectedState();
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
index ae73f30..6445a872 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -1419,6 +1419,10 @@
                                             mFragmentTransitionCallback);
                                 }
                                 container.removeView(view);
+                                if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+                                    Log.v(FragmentManager.TAG, "Removing view " + view + " for "
+                                            + "fragment " + f + " from container " + container);
+                                }
                                 // If the local container is different from the fragment
                                 // container, that means onAnimationEnd was called, onDestroyView
                                 // was dispatched and the fragment was already moved to state, so
@@ -2149,37 +2153,35 @@
             // The last operation determines the overall direction, this ensures that operations
             // such as push, push, pop, push are correctly considered a push
             boolean isPop = isRecordPop.get(endIndex - 1);
-            if (allowReordering) {
-                // Ensure that Fragments directly affected by operations
-                // are moved to their expected state in operation order
-                for (int index = startIndex; index < endIndex; index++) {
-                    BackStackRecord record = records.get(index);
-                    if (isPop) {
-                        // Pop operations get applied in reverse order
-                        for (int opIndex = record.mOps.size() - 1; opIndex >= 0; opIndex--) {
-                            FragmentTransaction.Op op = record.mOps.get(opIndex);
-                            Fragment fragment = op.mFragment;
-                            if (fragment != null) {
-                                FragmentStateManager fragmentStateManager =
-                                        createOrGetFragmentStateManager(fragment);
-                                fragmentStateManager.moveToExpectedState();
-                            }
-                        }
-                    } else {
-                        for (FragmentTransaction.Op op : record.mOps) {
-                            Fragment fragment = op.mFragment;
-                            if (fragment != null) {
-                                FragmentStateManager fragmentStateManager =
-                                        createOrGetFragmentStateManager(fragment);
-                                fragmentStateManager.moveToExpectedState();
-                            }
+            // Ensure that Fragments directly affected by operations
+            // are moved to their expected state in operation order
+            for (int index = startIndex; index < endIndex; index++) {
+                BackStackRecord record = records.get(index);
+                if (isPop) {
+                    // Pop operations get applied in reverse order
+                    for (int opIndex = record.mOps.size() - 1; opIndex >= 0; opIndex--) {
+                        FragmentTransaction.Op op = record.mOps.get(opIndex);
+                        Fragment fragment = op.mFragment;
+                        if (fragment != null) {
+                            FragmentStateManager fragmentStateManager =
+                                    createOrGetFragmentStateManager(fragment);
+                            fragmentStateManager.moveToExpectedState();
                         }
                     }
-
+                } else {
+                    for (FragmentTransaction.Op op : record.mOps) {
+                        Fragment fragment = op.mFragment;
+                        if (fragment != null) {
+                            FragmentStateManager fragmentStateManager =
+                                    createOrGetFragmentStateManager(fragment);
+                            fragmentStateManager.moveToExpectedState();
+                        }
+                    }
                 }
-                // And only then do we move all other fragments to the current state
-                moveToState(mCurState, true);
+
             }
+            // And only then do we move all other fragments to the current state
+            moveToState(mCurState, true);
             Set<SpecialEffectsController> changedControllers = collectChangedControllers(
                     records, startIndex, endIndex);
             for (SpecialEffectsController controller : changedControllers) {
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
index 1776ee9..b694598 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
@@ -334,8 +334,7 @@
                                     saveViewState();
                                 }
                             }
-                            if (mFragment.mView != null && mFragment.mContainer != null
-                                    && mFragmentManagerState > Fragment.INITIALIZING) {
+                            if (mFragment.mView != null && mFragment.mContainer != null) {
                                 SpecialEffectsController controller = SpecialEffectsController
                                         .getOrCreateController(mFragment.mContainer,
                                                 mFragment.getParentFragmentManager());
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/SpecialEffectsController.java b/fragment/fragment/src/main/java/androidx/fragment/app/SpecialEffectsController.java
index e0682f7..94ad2ba 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/SpecialEffectsController.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/SpecialEffectsController.java
@@ -16,6 +16,7 @@
 
 package androidx.fragment.app;
 
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -147,18 +148,38 @@
 
     void enqueueAdd(@NonNull Operation.State finalState,
             @NonNull FragmentStateManager fragmentStateManager) {
+        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+            Log.v(FragmentManager.TAG,
+                    "SpecialEffectsController: Enqueuing add operation for fragment "
+                            + fragmentStateManager.getFragment());
+        }
         enqueue(finalState, Operation.LifecycleImpact.ADDING, fragmentStateManager);
     }
 
     void enqueueShow(@NonNull FragmentStateManager fragmentStateManager) {
+        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+            Log.v(FragmentManager.TAG,
+                    "SpecialEffectsController: Enqueuing show operation for fragment "
+                            + fragmentStateManager.getFragment());
+        }
         enqueue(Operation.State.VISIBLE, Operation.LifecycleImpact.NONE, fragmentStateManager);
     }
 
     void enqueueHide(@NonNull FragmentStateManager fragmentStateManager) {
+        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+            Log.v(FragmentManager.TAG,
+                    "SpecialEffectsController: Enqueuing hide operation for fragment "
+                            + fragmentStateManager.getFragment());
+        }
         enqueue(Operation.State.GONE, Operation.LifecycleImpact.NONE, fragmentStateManager);
     }
 
     void enqueueRemove(@NonNull FragmentStateManager fragmentStateManager) {
+        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+            Log.v(FragmentManager.TAG,
+                    "SpecialEffectsController: Enqueuing remove operation for fragment "
+                            + fragmentStateManager.getFragment());
+        }
         enqueue(Operation.State.REMOVED, Operation.LifecycleImpact.REMOVING, fragmentStateManager);
     }
 
@@ -205,7 +226,7 @@
 
     void markPostponedState() {
         synchronized (mPendingOperations) {
-            updateFinalState(false);
+            updateFinalState();
             // Default to not postponed
             mIsContainerPostponed = false;
             for (int index = mPendingOperations.size() - 1; index >= 0; index--) {
@@ -240,6 +261,10 @@
             ArrayList<Operation> currentlyRunningOperations = new ArrayList<>(mRunningOperations);
             mRunningOperations.clear();
             for (Operation operation : currentlyRunningOperations) {
+                if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+                    Log.v(FragmentManager.TAG,
+                            "SpecialEffectsController: Cancelling operation " + operation);
+                }
                 operation.cancel();
                 if (!operation.isComplete()) {
                     // Re-add any animations that didn't synchronously call complete()
@@ -247,12 +272,16 @@
                     mRunningOperations.add(operation);
                 }
             }
-            updateFinalState(true);
+
+            updateFinalState();
 
             if (!mPendingOperations.isEmpty()) {
                 ArrayList<Operation> newPendingOperations = new ArrayList<>(mPendingOperations);
                 mPendingOperations.clear();
                 mRunningOperations.addAll(newPendingOperations);
+                for (Operation operation : newPendingOperations) {
+                    operation.onStart();
+                }
                 executeOperations(newPendingOperations, mOperationDirectionIsPop);
                 mOperationDirectionIsPop = false;
             }
@@ -261,23 +290,36 @@
 
     void forceCompleteAllOperations() {
         synchronized (mPendingOperations) {
-            updateFinalState(true);
+            updateFinalState();
+            for (Operation operation : mPendingOperations) {
+                operation.onStart();
+            }
 
             // First cancel running operations
             ArrayList<Operation> runningOperations = new ArrayList<>(mRunningOperations);
             for (Operation operation : runningOperations) {
+                if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+                    Log.v(FragmentManager.TAG,
+                            "SpecialEffectsController: Cancelling running operation "
+                                    + operation);
+                }
                 operation.cancel();
             }
 
             // Then cancel pending operations
             ArrayList<Operation> pendingOperations = new ArrayList<>(mPendingOperations);
             for (Operation operation : pendingOperations) {
+                if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+                    Log.v(FragmentManager.TAG,
+                            "SpecialEffectsController: Cancelling pending operation "
+                                    + operation);
+                }
                 operation.cancel();
             }
         }
     }
 
-    private void updateFinalState(boolean updateAlpha) {
+    private void updateFinalState() {
         for (Operation operation: mPendingOperations) {
             // update the final state of adding operations
             if (operation.getLifecycleImpact() == Operation.LifecycleImpact.ADDING) {
@@ -285,14 +327,6 @@
                 View view = fragment.requireView();
                 Operation.State finalState = Operation.State.from(view.getVisibility());
                 operation.mergeWith(finalState, Operation.LifecycleImpact.NONE);
-                // Change the view alphas back to their original values before we execute our
-                // transitions.
-                if (updateAlpha) {
-                    if (view.getAlpha() == 0f && view.getVisibility() == View.VISIBLE) {
-                        view.setVisibility(View.INVISIBLE);
-                    }
-                    view.setAlpha(fragment.getPostOnViewCreatedAlpha());
-                }
             }
         }
     }
@@ -396,16 +430,33 @@
                     case REMOVED:
                         ViewGroup parent = (ViewGroup) view.getParent();
                         if (parent != null) {
+                            if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+                                Log.v(FragmentManager.TAG, "SpecialEffectsController: Removing "
+                                        + "view " + view + " from container " + parent);
+                            }
                             parent.removeView(view);
                         }
                         break;
                     case VISIBLE:
+                        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+                            Log.v(FragmentManager.TAG, "SpecialEffectsController: Setting view "
+                                    + view + " to VISIBLE");
+                        }
                         view.setVisibility(View.VISIBLE);
                         break;
                     case GONE:
+                        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+                            Log.v(FragmentManager.TAG,
+                                    "SpecialEffectsController: Setting view " + view + " to GONE");
+                        }
                         view.setVisibility(View.GONE);
                         break;
                     case INVISIBLE:
+                        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+                            Log.v(FragmentManager.TAG,
+                                    "SpecialEffectsController: Setting view " + view + " to "
+                                            + "INVISIBLE");
+                        }
                         view.setVisibility(View.INVISIBLE);
                         break;
                 }
@@ -499,6 +550,29 @@
             return mIsCanceled;
         }
 
+        @NonNull
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("Operation ");
+            sb.append("{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append("} ");
+            sb.append("{");
+            sb.append("mFinalState = ");
+            sb.append(mFinalState);
+            sb.append("} ");
+            sb.append("{");
+            sb.append("mLifecycleImpact = ");
+            sb.append(mLifecycleImpact);
+            sb.append("} ");
+            sb.append("{");
+            sb.append("mFragment = ");
+            sb.append(mFragment);
+            sb.append("}");
+            return sb.toString();
+        }
+
         final void cancel() {
             if (isCanceled()) {
                 return;
@@ -518,6 +592,11 @@
             switch (lifecycleImpact) {
                 case ADDING:
                     if (mFinalState == State.REMOVED) {
+                        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+                            Log.v(FragmentManager.TAG, "SpecialEffectsController: For fragment "
+                                    + mFragment + " mFinalState = REMOVED -> VISIBLE. "
+                                    + "mLifecycleImpact = " + mLifecycleImpact + " to ADDING.");
+                        }
                         // Applying an ADDING operation to a REMOVED fragment
                         // moves it back to ADDING
                         mFinalState = State.VISIBLE;
@@ -525,6 +604,11 @@
                     }
                     break;
                 case REMOVING:
+                    if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+                        Log.v(FragmentManager.TAG, "SpecialEffectsController: For fragment "
+                                + mFragment + " mFinalState = " + mFinalState + " -> REMOVED. "
+                                + "mLifecycleImpact  = " + mLifecycleImpact + " to REMOVING.");
+                    }
                     // Any REMOVING operation overrides whatever we had before
                     mFinalState = State.REMOVED;
                     mLifecycleImpact = LifecycleImpact.REMOVING;
@@ -532,6 +616,11 @@
                 case NONE:
                     // This is a hide or show operation
                     if (mFinalState != State.REMOVED) {
+                        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+                            Log.v(FragmentManager.TAG, "SpecialEffectsController: For fragment "
+                                    + mFragment + " mFinalState = " + mFinalState + " -> "
+                                    + finalState + ". ");
+                        }
                         mFinalState = finalState;
                     }
             }
@@ -542,11 +631,17 @@
         }
 
         /**
+         * Callback for when the operation is about to start.
+         */
+        void onStart() {}
+
+        /**
          * Add new {@link CancellationSignal} for special effects.
          *
          * @param signal A CancellationSignal that can be used to cancel this special effect.
          */
         public final void markStartedSpecialEffect(@NonNull CancellationSignal signal) {
+            onStart();
             mSpecialEffectsSignals.add(signal);
         }
 
@@ -576,6 +671,10 @@
             if (mIsComplete) {
                 return;
             }
+            if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+                Log.v(FragmentManager.TAG,
+                        "SpecialEffectsController: " + this + " has called complete.");
+            }
             mIsComplete = true;
             for (Runnable listener : mCompletionListeners) {
                 listener.run();
@@ -597,6 +696,28 @@
         }
 
         @Override
+        void onStart() {
+            Fragment fragment = mFragmentStateManager.getFragment();
+            View focusedView = fragment.mView.findFocus();
+            if (focusedView != null) {
+                fragment.setFocusedView(focusedView);
+                if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
+                    Log.v(FragmentManager.TAG, "requestFocus: Saved focused view " + focusedView
+                            + " for Fragment " + fragment);
+                }
+            }
+            if (getLifecycleImpact() == Operation.LifecycleImpact.ADDING) {
+                View view = getFragment().requireView();
+                // Change the view alphas back to their original values before we execute our
+                // transitions.
+                if (view.getAlpha() == 0f && view.getVisibility() == View.VISIBLE) {
+                    view.setVisibility(View.INVISIBLE);
+                }
+                view.setAlpha(fragment.getPostOnViewCreatedAlpha());
+            }
+        }
+
+        @Override
         public void complete() {
             super.complete();
             mFragmentStateManager.moveToExpectedState();
diff --git a/gradlew b/gradlew
index b99c9f3..efd6003 100755
--- a/gradlew
+++ b/gradlew
@@ -231,7 +231,7 @@
 
 function runGradle() {
   processOutput=false
-  if [[ " ${@} " =~ " -Pandroidx.validateNoExtraMessages " ]]; then
+  if [[ " ${@} " =~ " -Pandroidx.validateNoUnrecognizedMessages " ]]; then
     processOutput=true
   fi
   if [[ " ${@} " =~ " -Pandroidx.summarizeStderr " ]]; then
diff --git a/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java b/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java
index d1b6cb92..dbfadd6 100644
--- a/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java
+++ b/heifwriter/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java
@@ -48,6 +48,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.LargeTest;
+import androidx.test.filters.SmallTest;
 import androidx.test.rule.GrantPermissionRule;
 
 import org.junit.After;
@@ -280,6 +281,25 @@
         }
     }
 
+    @Test
+    @SmallTest
+    public void testCloseWithoutStart() throws Throwable {
+        if (shouldSkip()) return;
+
+        final String outputPath = new File(getApplicationContext().getExternalFilesDir(null),
+                        OUTPUT_FILENAME).getAbsolutePath();
+        HeifWriter heifWriter = new HeifWriter.Builder(
+                    outputPath, 1920, 1080, INPUT_MODE_SURFACE)
+                    .setGridEnabled(true)
+                    .setMaxImages(4)
+                    .setQuality(90)
+                    .setPrimaryIndex(0)
+                    .setHandler(mHandler)
+                    .build();
+
+        heifWriter.close();
+    }
+
     private void doTestForVariousNumberImages(TestConfig.Builder builder) throws Exception {
         builder.setNumImages(4);
         doTest(builder.setRotation(270).build());
diff --git a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java
index 025cce9..5e08a73 100644
--- a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java
+++ b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java
@@ -46,7 +46,6 @@
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.CountDownLatch;
 
 /**
  * This class encodes images into HEIF-compatible samples using HEVC encoder.
@@ -128,7 +127,6 @@
     private int mTextureId;
     private final float[] mTmpMatrix = new float[16];
     private final AtomicBoolean mStopping = new AtomicBoolean(false);
-    private final CountDownLatch mStoppedLatch;
 
     public static final int INPUT_MODE_BUFFER = HeifWriter.INPUT_MODE_BUFFER;
     public static final int INPUT_MODE_SURFACE = HeifWriter.INPUT_MODE_SURFACE;
@@ -380,8 +378,6 @@
 
         mDstRect = new Rect(0, 0, mGridWidth, mGridHeight);
         mSrcRect = new Rect();
-
-        mStoppedLatch = new CountDownLatch(1);
     }
 
     private String findHevcFallback() {
@@ -748,9 +744,13 @@
         mStopping.set(true);
 
         // after start, mEncoder is only accessed on handler, so no need to sync.
-        if (mEncoder != null) {
-            mEncoder.stop();
-            mEncoder.release();
+        try {
+            if (mEncoder != null) {
+                mEncoder.stop();
+                mEncoder.release();
+            }
+        } catch (Exception e) {
+        } finally {
             mEncoder = null;
         }
 
@@ -768,26 +768,36 @@
         // those outputs were not returned. Shutting down the encoder will make break
         // the tile copier out of that.
         synchronized(this) {
-            if (mRectBlt != null) {
-                mRectBlt.release(false);
+            try {
+                if (mRectBlt != null) {
+                    mRectBlt.release(false);
+                }
+            } catch (Exception e) {
+            } finally {
                 mRectBlt = null;
             }
 
-            if (mEncoderEglSurface != null) {
-                // Note that this frees mEncoderSurface too. If mEncoderEglSurface is not
-                // there, client is responsible to release the input surface it got from us,
-                // we don't release mEncoderSurface here.
-                mEncoderEglSurface.release();
+            try {
+                if (mEncoderEglSurface != null) {
+                    // Note that this frees mEncoderSurface too. If mEncoderEglSurface is not
+                    // there, client is responsible to release the input surface it got from us,
+                    // we don't release mEncoderSurface here.
+                    mEncoderEglSurface.release();
+                }
+            } catch (Exception e) {
+            } finally {
                 mEncoderEglSurface = null;
             }
 
-            if (mInputTexture != null) {
-                mInputTexture.release();
+            try {
+                if (mInputTexture != null) {
+                    mInputTexture.release();
+                }
+            } catch (Exception e) {
+            } finally {
                 mInputTexture = null;
             }
         }
-
-        mStoppedLatch.countDown();
     }
 
     /**
@@ -997,11 +1007,12 @@
         mHandler.postAtFrontOfQueue(new Runnable() {
             @Override
             public void run() {
-                stopInternal();
+                try {
+                    stopInternal();
+                } catch (Exception e) {
+                    // We don't want to crash when closing.
+                }
             }
         });
-        try {
-            mStoppedLatch.await();
-        } catch(InterruptedException e) {}
     }
 }
diff --git a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java
index db947eb..c086fb5 100644
--- a/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java
+++ b/heifwriter/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java
@@ -42,7 +42,6 @@
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -104,7 +103,6 @@
     @SuppressWarnings("WeakerAccess") /* synthetic access */
     int mOutputIndex;
     private boolean mStarted;
-    private final CountDownLatch mStoppedLatch;
 
     private final List<Pair<Integer, ByteBuffer>> mExifList = new ArrayList<>();
 
@@ -353,8 +351,6 @@
 
         mHeifEncoder = new HeifEncoder(width, height, gridEnabled, quality,
                 mInputMode, mHandler, new HeifCallback());
-
-        mStoppedLatch = new CountDownLatch(1);
     }
 
     /**
@@ -537,21 +533,28 @@
     @SuppressWarnings("WeakerAccess") /* synthetic access */
     void closeInternal() {
         if (DEBUG) Log.d(TAG, "closeInternal");
-
-        if (mMuxer != null) {
-            mMuxer.stop();
-            mMuxer.release();
+        // We don't want to crash when closing, catch all exceptions.
+        try {
+            // Muxer could throw exceptions if stop is called without samples.
+            // Don't crash in that case.
+            if (mMuxer != null) {
+                mMuxer.stop();
+                mMuxer.release();
+            }
+        } catch (Exception e) {
+        } finally {
             mMuxer = null;
         }
-
-        if (mHeifEncoder != null) {
-            mHeifEncoder.close();
+        try {
+            if (mHeifEncoder != null) {
+                mHeifEncoder.close();
+            }
+        } catch (Exception e) {
+        } finally {
             synchronized (this) {
                 mHeifEncoder = null;
             }
         }
-
-        mStoppedLatch.countDown();
     }
 
     /**
@@ -712,8 +715,5 @@
                 }
             }
         });
-        try {
-            mStoppedLatch.await();
-        } catch (InterruptedException e) {}
     }
 }
diff --git a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/assisted/AssistedFactoryGenerator.kt b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/assisted/AssistedFactoryGenerator.kt
index 34de592..1257acd 100644
--- a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/assisted/AssistedFactoryGenerator.kt
+++ b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/assisted/AssistedFactoryGenerator.kt
@@ -107,8 +107,10 @@
             .addModifiers(Modifier.PUBLIC)
             .returns(productClassName)
             .addParameters(parameterSpecs)
-            .addStatement("return new $T($L)",
-                productClassName, CodeBlock.join(constructorArgs, ",$W"))
+            .addStatement(
+                "return new $T($L)",
+                productClassName, CodeBlock.join(constructorArgs, ",$W")
+            )
             .build()
     }
 }
\ No newline at end of file
diff --git a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelGenerator.kt b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelGenerator.kt
index bd1225f..af92a93 100644
--- a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelGenerator.kt
+++ b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelGenerator.kt
@@ -88,7 +88,8 @@
             .addAnnotation(
                 AnnotationSpec.builder(ClassNames.INSTALL_IN)
                     .addMember("value", "$T.class", ClassNames.ACTIVITY_RETAINED_COMPONENT)
-                    .build())
+                    .build()
+            )
             .addAnnotation(
                 AnnotationSpec.builder(ClassNames.ORIGINATING_ELEMENT)
                     .addMember(
@@ -106,14 +107,18 @@
                     .addAnnotation(
                         AnnotationSpec.builder(ClassNames.STRING_KEY)
                             .addMember("value", S, injectedViewModel.className.reflectionName())
-                            .build())
+                            .build()
+                    )
                     .addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
                     .returns(
                         ParameterizedTypeName.get(
                             ClassNames.VIEW_MODEL_ASSISTED_FACTORY,
-                            WildcardTypeName.subtypeOf(ClassNames.VIEW_MODEL)))
+                            WildcardTypeName.subtypeOf(ClassNames.VIEW_MODEL)
+                        )
+                    )
                     .addParameter(injectedViewModel.factoryClassName, "factory")
-                    .build())
+                    .build()
+            )
             .build()
         JavaFile.builder(injectedViewModel.moduleClassName.packageName(), hiltModuleTypeSpec)
             .build()
diff --git a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectElements.kt b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectElements.kt
index 206c4f6..a7bf032 100644
--- a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectElements.kt
+++ b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectElements.kt
@@ -35,15 +35,18 @@
 
     val factoryClassName = ClassName.get(
         MoreElements.getPackage(typeElement).qualifiedName.toString(),
-        "${className.simpleNames().joinToString("_")}_AssistedFactory")
+        "${className.simpleNames().joinToString("_")}_AssistedFactory"
+    )
 
     val factorySuperTypeName = ParameterizedTypeName.get(
         ClassNames.VIEW_MODEL_ASSISTED_FACTORY,
-        className)
+        className
+    )
 
     val moduleClassName = ClassName.get(
         MoreElements.getPackage(typeElement).qualifiedName.toString(),
-        "${className.simpleNames().joinToString("_")}_HiltModule")
+        "${className.simpleNames().joinToString("_")}_HiltModule"
+    )
 
     val dependencyRequests = constructorElement.parameters.map { constructorArg ->
         constructorArg.toDependencyRequest()
diff --git a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectStep.kt b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectStep.kt
index ec7bf75..c86a7bf 100644
--- a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectStep.kt
+++ b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/lifecycle/ViewModelInjectStep.kt
@@ -66,15 +66,22 @@
         var valid = true
 
         if (elements.getTypeElement(ClassNames.VIEW_MODEL_ASSISTED_FACTORY.toString()) == null) {
-            error("To use @ViewModelInject you must add the 'lifecycle-viewmodel' " +
-                    "artifact. androidx.hilt:hilt-lifecyclew-viewmodel:<version>")
+            error(
+                "To use @ViewModelInject you must add the 'lifecycle-viewmodel' " +
+                    "artifact. androidx.hilt:hilt-lifecyclew-viewmodel:<version>"
+            )
             valid = false
         }
 
-        if (!types.isSubtype(typeElement.asType(),
-                elements.getTypeElement(ClassNames.VIEW_MODEL.toString()).asType())) {
-            error("@ViewModelInject is only supported on types that subclass " +
-                    "${ClassNames.VIEW_MODEL}.")
+        if (!types.isSubtype(
+                typeElement.asType(),
+                elements.getTypeElement(ClassNames.VIEW_MODEL.toString()).asType()
+            )
+        ) {
+            error(
+                "@ViewModelInject is only supported on types that subclass " +
+                    "${ClassNames.VIEW_MODEL}."
+            )
             valid = false
         }
 
@@ -92,9 +99,12 @@
         }
 
         if (typeElement.nestingKind == NestingKind.MEMBER &&
-            !typeElement.modifiers.contains(Modifier.STATIC)) {
-            error("@ViewModelInject may only be used on inner classes if they are static.",
-                typeElement)
+            !typeElement.modifiers.contains(Modifier.STATIC)
+        ) {
+            error(
+                "@ViewModelInject may only be used on inner classes if they are static.",
+                typeElement
+            )
             valid = false
         }
 
@@ -103,8 +113,11 @@
             TypeName.get(it.asType()) == ClassNames.SAVED_STATE_HANDLE
         }.apply {
             if (size > 1) {
-                error("Expected zero or one constructor argument of type " +
-                        "${ClassNames.SAVED_STATE_HANDLE}, found $size", constructorElement)
+                error(
+                    "Expected zero or one constructor argument of type " +
+                        "${ClassNames.SAVED_STATE_HANDLE}, found $size",
+                    constructorElement
+                )
                 valid = false
             }
             firstOrNull()?.let {
diff --git a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerGenerator.kt b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerGenerator.kt
index 95b3d43..3552dfc 100644
--- a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerGenerator.kt
+++ b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerGenerator.kt
@@ -88,7 +88,8 @@
             .addAnnotation(
                 AnnotationSpec.builder(ClassNames.INSTALL_IN)
                     .addMember("value", "$T.class", ClassNames.SINGLETON_COMPONENT)
-                    .build())
+                    .build()
+            )
             .addAnnotation(
                 AnnotationSpec.builder(ClassNames.ORIGINATING_ELEMENT)
                     .addMember(
@@ -106,14 +107,18 @@
                     .addAnnotation(
                         AnnotationSpec.builder(ClassNames.STRING_KEY)
                             .addMember("value", S, injectedWorker.className.reflectionName())
-                            .build())
+                            .build()
+                    )
                     .addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC)
                     .returns(
                         ParameterizedTypeName.get(
                             ClassNames.WORKER_ASSISTED_FACTORY,
-                            WildcardTypeName.subtypeOf(ClassNames.LISTENABLE_WORKER)))
+                            WildcardTypeName.subtypeOf(ClassNames.LISTENABLE_WORKER)
+                        )
+                    )
                     .addParameter(injectedWorker.factoryClassName, "factory")
-                    .build())
+                    .build()
+            )
             .build()
         JavaFile.builder(injectedWorker.moduleClassName.packageName(), hiltModuleTypeSpec)
             .build()
diff --git a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectElements.kt b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectElements.kt
index 5f830a6..03f4c05 100644
--- a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectElements.kt
+++ b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectElements.kt
@@ -35,15 +35,18 @@
 
     val factoryClassName = ClassName.get(
         MoreElements.getPackage(typeElement).qualifiedName.toString(),
-        "${className.simpleNames().joinToString("_")}_AssistedFactory")
+        "${className.simpleNames().joinToString("_")}_AssistedFactory"
+    )
 
     val factorySuperTypeName = ParameterizedTypeName.get(
         ClassNames.WORKER_ASSISTED_FACTORY,
-        className)
+        className
+    )
 
     val moduleClassName = ClassName.get(
         MoreElements.getPackage(typeElement).qualifiedName.toString(),
-        "${className.simpleNames().joinToString("_")}_HiltModule")
+        "${className.simpleNames().joinToString("_")}_HiltModule"
+    )
 
     val dependencyRequests = constructorElement.parameters.map { constructorArg ->
         constructorArg.toDependencyRequest()
diff --git a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectStep.kt b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectStep.kt
index 3e5c77d..346f308 100644
--- a/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectStep.kt
+++ b/hilt/hilt-compiler/src/main/kotlin/androidx/hilt/work/WorkerInjectStep.kt
@@ -68,15 +68,22 @@
         var valid = true
 
         if (elements.getTypeElement(ClassNames.WORKER_ASSISTED_FACTORY.toString()) == null) {
-            error("To use @WorkerInject you must add the 'work' artifact. " +
-                    "androidx.hilt:hilt-work:<version>")
+            error(
+                "To use @WorkerInject you must add the 'work' artifact. " +
+                    "androidx.hilt:hilt-work:<version>"
+            )
             valid = false
         }
 
-        if (!types.isSubtype(typeElement.asType(),
-                elements.getTypeElement(ClassNames.LISTENABLE_WORKER.toString()).asType())) {
-            error("@WorkerInject is only supported on types that subclass " +
-                    "${ClassNames.LISTENABLE_WORKER}.")
+        if (!types.isSubtype(
+                typeElement.asType(),
+                elements.getTypeElement(ClassNames.LISTENABLE_WORKER.toString()).asType()
+            )
+        ) {
+            error(
+                "@WorkerInject is only supported on types that subclass " +
+                    "${ClassNames.LISTENABLE_WORKER}."
+            )
             valid = false
         }
 
@@ -94,9 +101,12 @@
         }
 
         if (typeElement.nestingKind == NestingKind.MEMBER &&
-            !typeElement.modifiers.contains(Modifier.STATIC)) {
-            error("@WorkerInject may only be used on inner classes if they are static.",
-                typeElement)
+            !typeElement.modifiers.contains(Modifier.STATIC)
+        ) {
+            error(
+                "@WorkerInject may only be used on inner classes if they are static.",
+                typeElement
+            )
             valid = false
         }
 
@@ -104,8 +114,11 @@
             TypeName.get(it.asType()) == ClassNames.CONTEXT
         }.apply {
             if (size != 1) {
-                error("Expected exactly one constructor argument of type " +
-                        "${ClassNames.CONTEXT}, found $size", constructorElement)
+                error(
+                    "Expected exactly one constructor argument of type " +
+                        "${ClassNames.CONTEXT}, found $size",
+                    constructorElement
+                )
                 valid = false
             }
             firstOrNull()?.let {
@@ -120,8 +133,11 @@
             TypeName.get(it.asType()) == ClassNames.WORKER_PARAMETERS
         }.apply {
             if (size != 1) {
-                error("Expected exactly one constructor argument of type " +
-                        "${ClassNames.WORKER_PARAMETERS}, found $size", constructorElement)
+                error(
+                    "Expected exactly one constructor argument of type " +
+                        "${ClassNames.WORKER_PARAMETERS}, found $size",
+                    constructorElement
+                )
                 valid = false
             }
             firstOrNull()?.let {
diff --git a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelGeneratorTest.kt b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelGeneratorTest.kt
index 2711070..b150e7f 100644
--- a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelGeneratorTest.kt
+++ b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelGeneratorTest.kt
@@ -458,11 +458,15 @@
             .compile(viewModel, Sources.VIEW_MODEL, Sources.SAVED_STATE_HANDLE)
         assertThat(compilation).apply {
             succeeded()
-            generatedSourceFile("androidx.hilt.lifecycle.test" +
-                        ".Outer_InnerViewModel_AssistedFactory")
+            generatedSourceFile(
+                "androidx.hilt.lifecycle.test" +
+                    ".Outer_InnerViewModel_AssistedFactory"
+            )
                 .hasSourceEquivalentTo(expectedFactory)
-            generatedSourceFile("androidx.hilt.lifecycle.test" +
-                        ".Outer_InnerViewModel_HiltModule")
+            generatedSourceFile(
+                "androidx.hilt.lifecycle.test" +
+                    ".Outer_InnerViewModel_HiltModule"
+            )
                 .hasSourceEquivalentTo(expectedModule)
         }
     }
diff --git a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelInjectStepTest.kt b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelInjectStepTest.kt
index 8b764a1..3a01a49 100644
--- a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelInjectStepTest.kt
+++ b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/lifecycle/ViewModelInjectStepTest.kt
@@ -42,7 +42,8 @@
         """.toJFO("androidx.hilt.lifecycle.test.MyViewModel")
 
         val compilation = compiler()
-            .compile(myViewModel,
+            .compile(
+                myViewModel,
                 Sources.VIEW_MODEL,
                 Sources.SAVED_STATE_HANDLE
             )
@@ -67,8 +68,10 @@
         assertThat(compilation).apply {
             failed()
             hadErrorCount(1)
-            hadErrorContainingMatch("@ViewModelInject is only supported on types that subclass " +
-                        "androidx.lifecycle.ViewModel.")
+            hadErrorContainingMatch(
+                "@ViewModelInject is only supported on types that subclass " +
+                    "androidx.lifecycle.ViewModel."
+            )
         }
     }
 
@@ -117,8 +120,10 @@
         assertThat(compilation).apply {
             failed()
             hadErrorCount(1)
-            hadErrorContainingMatch("@ViewModelInject annotated constructors must not be " +
-                        "private.")
+            hadErrorContainingMatch(
+                "@ViewModelInject annotated constructors must not be " +
+                    "private."
+            )
         }
     }
 
@@ -143,8 +148,10 @@
         assertThat(compilation).apply {
             failed()
             hadErrorCount(1)
-            hadErrorContainingMatch("@ViewModelInject may only be used on inner classes " +
-                        "if they are static.")
+            hadErrorContainingMatch(
+                "@ViewModelInject may only be used on inner classes " +
+                    "if they are static."
+            )
         }
     }
 
@@ -166,15 +173,18 @@
         """.toJFO("androidx.hilt.lifecycle.test.MyViewModel")
 
         val compilation = compiler()
-            .compile(myViewModel,
+            .compile(
+                myViewModel,
                 Sources.VIEW_MODEL,
                 Sources.SAVED_STATE_HANDLE
             )
         assertThat(compilation).apply {
             failed()
             hadErrorCount(1)
-            hadErrorContainingMatch("Expected zero or one constructor argument of type " +
-                        "androidx.lifecycle.SavedStateHandle, found 2")
+            hadErrorContainingMatch(
+                "Expected zero or one constructor argument of type " +
+                    "androidx.lifecycle.SavedStateHandle, found 2"
+            )
         }
     }
 
@@ -194,7 +204,8 @@
         """.toJFO("androidx.hilt.lifecycle.test.MyViewModel")
 
         val compilation = compiler()
-            .compile(myViewModel,
+            .compile(
+                myViewModel,
                 Sources.VIEW_MODEL,
                 Sources.SAVED_STATE_HANDLE
             )
diff --git a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerGeneratorTest.kt b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerGeneratorTest.kt
index 5fd1cc0..b7e8cdad 100644
--- a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerGeneratorTest.kt
+++ b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerGeneratorTest.kt
@@ -94,8 +94,10 @@
         """.toJFO("androidx.hilt.work.test.MyWorker_AssistedFactory")
 
         val compilation = compiler()
-            .compile(foo, myWorker, Sources.LISTENABLE_WORKER, Sources.WORKER,
-                Sources.WORKER_PARAMETERS)
+            .compile(
+                foo, myWorker, Sources.LISTENABLE_WORKER, Sources.WORKER,
+                Sources.WORKER_PARAMETERS
+            )
         assertThat(compilation).apply {
             succeeded()
             generatedSourceFile("androidx.hilt.work.test.MyWorker_AssistedFactory")
diff --git a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerInjectStepTest.kt b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerInjectStepTest.kt
index bf92381..0f83fb6 100644
--- a/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerInjectStepTest.kt
+++ b/hilt/hilt-compiler/src/test/kotlin/androidx/hilt/work/WorkerInjectStepTest.kt
@@ -48,8 +48,10 @@
         assertThat(compilation).apply {
             failed()
             hadErrorCount(1)
-            hadErrorContainingMatch("@WorkerInject is only supported on types that subclass " +
-                        "androidx.work.ListenableWorker.")
+            hadErrorContainingMatch(
+                "@WorkerInject is only supported on types that subclass " +
+                    "androidx.work.ListenableWorker."
+            )
         }
     }
 
@@ -111,8 +113,10 @@
         assertThat(compilation).apply {
             failed()
             hadErrorCount(1)
-            hadErrorContainingMatch("@WorkerInject annotated constructors must not be " +
-                        "private.")
+            hadErrorContainingMatch(
+                "@WorkerInject annotated constructors must not be " +
+                    "private."
+            )
         }
     }
 
@@ -142,8 +146,10 @@
         assertThat(compilation).apply {
             failed()
             hadErrorCount(1)
-            hadErrorContainingMatch("@WorkerInject may only be used on inner classes " +
-                        "if they are static.")
+            hadErrorContainingMatch(
+                "@WorkerInject may only be used on inner classes " +
+                    "if they are static."
+            )
         }
     }
 }
\ No newline at end of file
diff --git a/leanback/leanback-paging/src/androidTest/java/androidx/leanback/paging/PagingDataAdapterTest.kt b/leanback/leanback-paging/src/androidTest/java/androidx/leanback/paging/PagingDataAdapterTest.kt
index b2c47b2..fc22370 100644
--- a/leanback/leanback-paging/src/androidTest/java/androidx/leanback/paging/PagingDataAdapterTest.kt
+++ b/leanback/leanback-paging/src/androidTest/java/androidx/leanback/paging/PagingDataAdapterTest.kt
@@ -63,14 +63,17 @@
     fun testGetItem() = testScope.runBlockingTest {
         val pagingSource = TestPagingSource()
         val pagingDataAdapter =
-            PagingDataAdapter(diffCallback = object : DiffUtil.ItemCallback<Int>() {
-                override fun areContentsTheSame(oldItem: Int, newItem: Int): Boolean {
-                    return oldItem == newItem
-                }
-                override fun areItemsTheSame(oldItem: Int, newItem: Int): Boolean {
-                    return oldItem == newItem
-                }
-        }, workerDispatcher = Dispatchers.Main)
+            PagingDataAdapter(
+                diffCallback = object : DiffUtil.ItemCallback<Int>() {
+                    override fun areContentsTheSame(oldItem: Int, newItem: Int): Boolean {
+                        return oldItem == newItem
+                    }
+                    override fun areItemsTheSame(oldItem: Int, newItem: Int): Boolean {
+                        return oldItem == newItem
+                    }
+                },
+                workerDispatcher = Dispatchers.Main
+            )
         val refreshEvents = mutableListOf<Boolean>()
         pagingDataAdapter.addDataRefreshListener { refreshEvents.add(it) }
         val pager = Pager(
@@ -102,14 +105,17 @@
     @Test
     fun testDataRefreshListenerCallbacks() = testScope.runBlockingTest {
         val pagingDataAdapter =
-            PagingDataAdapter(diffCallback = object : DiffUtil.ItemCallback<Int>() {
-                override fun areContentsTheSame(oldItem: Int, newItem: Int): Boolean {
-                    return oldItem == newItem
-                }
-                override fun areItemsTheSame(oldItem: Int, newItem: Int): Boolean {
-                    return oldItem == newItem
-                }
-        }, workerDispatcher = Dispatchers.Main)
+            PagingDataAdapter(
+                diffCallback = object : DiffUtil.ItemCallback<Int>() {
+                    override fun areContentsTheSame(oldItem: Int, newItem: Int): Boolean {
+                        return oldItem == newItem
+                    }
+                    override fun areItemsTheSame(oldItem: Int, newItem: Int): Boolean {
+                        return oldItem == newItem
+                    }
+                },
+                workerDispatcher = Dispatchers.Main
+            )
         val refreshEvents = mutableListOf<Boolean>()
         pagingDataAdapter.addDataRefreshListener { refreshEvents.add(it) }
         val pager = Pager(
@@ -145,14 +151,17 @@
     @Test
     fun testLoadStateListenerCallbacks() = testScope.runBlockingTest {
         val pagingDataAdapter =
-            PagingDataAdapter(diffCallback = object : DiffUtil.ItemCallback<Int>() {
-                override fun areContentsTheSame(oldItem: Int, newItem: Int): Boolean {
-                    return oldItem == newItem
-                }
-                override fun areItemsTheSame(oldItem: Int, newItem: Int): Boolean {
-                    return oldItem == newItem
-                }
-        }, workerDispatcher = Dispatchers.Main)
+            PagingDataAdapter(
+                diffCallback = object : DiffUtil.ItemCallback<Int>() {
+                    override fun areContentsTheSame(oldItem: Int, newItem: Int): Boolean {
+                        return oldItem == newItem
+                    }
+                    override fun areItemsTheSame(oldItem: Int, newItem: Int): Boolean {
+                        return oldItem == newItem
+                    }
+                },
+                workerDispatcher = Dispatchers.Main
+            )
         val loadEvents = mutableListOf<CombinedLoadStates>()
         pagingDataAdapter.addLoadStateListener { loadEvents.add(it) }
         val pager = Pager(
diff --git a/leanback/leanback/src/main/res/values-as/strings.xml b/leanback/leanback/src/main/res/values-as/strings.xml
index aaba187..0d47c7f3 100644
--- a/leanback/leanback/src/main/res/values-as/strings.xml
+++ b/leanback/leanback/src/main/res/values-as/strings.xml
@@ -19,7 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="lb_navigation_menu_contentDescription" msgid="8084428500709675515">"নেভিগেশ্বন মেনু"</string>
     <string name="orb_search_action" msgid="1301877238242752863">"সন্ধান সম্পৰ্কীয় কাৰ্য"</string>
-    <string name="lb_search_bar_hint" msgid="5700349211583074131">"সন্ধান"</string>
+    <string name="lb_search_bar_hint" msgid="5700349211583074131">"Search"</string>
     <string name="lb_search_bar_hint_speech" msgid="5926531297066387462">"সন্ধান কৰিবলৈ কথা কওক"</string>
     <string name="lb_search_bar_hint_with_title" msgid="4826526877249029043">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> সন্ধান কৰক"</string>
     <string name="lb_search_bar_hint_with_title_speech" msgid="6032250334706920550">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> সন্ধান কৰিবলৈ কথা কওক"</string>
diff --git a/leanback/leanback/src/main/res/values-eu/strings.xml b/leanback/leanback/src/main/res/values-eu/strings.xml
index bc7f0f3..a4529bd 100644
--- a/leanback/leanback/src/main/res/values-eu/strings.xml
+++ b/leanback/leanback/src/main/res/values-eu/strings.xml
@@ -47,7 +47,7 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="1209119371486219736">"Desgaitu kalitate handiko erreprodukzioa"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2346334170216706076">"Gaitu azpitituluak"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="8691966842977635128">"Desgaitu azpitituluak"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="5770668162543767702">"Aktibatu \"Pantaila txiki gainjarri\" modua"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="5770668162543767702">"Aktibatu pantaila txiki gainjarriko modua"</string>
     <string name="lb_playback_time_separator" msgid="1471121602610716654">"/"</string>
     <string name="lb_playback_controls_shown" msgid="8690223891515602822">"Multimedia-edukia kontrolatzeko aukerak ikusgai"</string>
     <string name="lb_playback_controls_hidden" msgid="5859666950961624736">"Ezkutatuta daude multimedia-edukia kontrolatzeko aukerak. Haiek erakusteko, sakatu nabigazio-gurutzea."</string>
diff --git a/leanback/leanback/src/main/res/values-fr-rCA/strings.xml b/leanback/leanback/src/main/res/values-fr-rCA/strings.xml
index 4f0d856..8bc2af9 100644
--- a/leanback/leanback/src/main/res/values-fr-rCA/strings.xml
+++ b/leanback/leanback/src/main/res/values-fr-rCA/strings.xml
@@ -34,8 +34,8 @@
     <string name="lb_playback_controls_skip_next" msgid="8117512422682146745">"Passer à l\'élément suivant"</string>
     <string name="lb_playback_controls_skip_previous" msgid="3481218248309447059">"Retourner à l\'élément précédent"</string>
     <string name="lb_playback_controls_more_actions" msgid="8730341244454469032">"Autres actions"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="3458671378107738666">"Désélectionner la mention « J\'aime »"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1385865732502550659">"Sélectionner la mention « J\'aime »"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="3458671378107738666">"Désélectionner la mention J\'aime"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1385865732502550659">"Sélectionner la mention J\'aime"</string>
     <string name="lb_playback_controls_thumb_down" msgid="3544533410444618518">"Désélectionner la mention « Je n\'aime pas »"</string>
     <string name="lb_playback_controls_thumb_down_outline" msgid="8475278766138652105">"Sélectionner la mention « Je n\'aime pas »"</string>
     <string name="lb_playback_controls_repeat_none" msgid="1614290959784265209">"Aucune répétition"</string>
diff --git a/leanback/leanback/src/main/res/values-gl/strings.xml b/leanback/leanback/src/main/res/values-gl/strings.xml
index 3b77766..83ddff9 100644
--- a/leanback/leanback/src/main/res/values-gl/strings.xml
+++ b/leanback/leanback/src/main/res/values-gl/strings.xml
@@ -29,8 +29,8 @@
     <string name="lb_playback_controls_pause" msgid="917331776961802657">"Pausar"</string>
     <string name="lb_playback_controls_fast_forward" msgid="740570111678243493">"Avance rápido"</string>
     <string name="lb_playback_controls_fast_forward_multiplier" msgid="5734614175721471329">"Avance rápido %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2866333981131020771">"Rebobinar"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="6038956370475252734">"Rebobinado %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="2866333981131020771">"Retroceder"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="6038956370475252734">"Retroceso %1$dX"</string>
     <string name="lb_playback_controls_skip_next" msgid="8117512422682146745">"Saltar ao seguinte"</string>
     <string name="lb_playback_controls_skip_previous" msgid="3481218248309447059">"Saltar ao anterior"</string>
     <string name="lb_playback_controls_more_actions" msgid="8730341244454469032">"Máis accións"</string>
diff --git a/leanback/leanback/src/main/res/values-kn/strings.xml b/leanback/leanback/src/main/res/values-kn/strings.xml
index 4cdd8a6..c49761f 100644
--- a/leanback/leanback/src/main/res/values-kn/strings.xml
+++ b/leanback/leanback/src/main/res/values-kn/strings.xml
@@ -19,7 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="lb_navigation_menu_contentDescription" msgid="8084428500709675515">"ನ್ಯಾವಿಗೇಶನ್‌ ಮೆನು"</string>
     <string name="orb_search_action" msgid="1301877238242752863">"ಹುಡುಕಾಟ ಕ್ರಿಯೆ"</string>
-    <string name="lb_search_bar_hint" msgid="5700349211583074131">"ಹುಡುಕಿ"</string>
+    <string name="lb_search_bar_hint" msgid="5700349211583074131">"Search"</string>
     <string name="lb_search_bar_hint_speech" msgid="5926531297066387462">"ಹುಡುಕಲು ಮಾತನಾಡಿ"</string>
     <string name="lb_search_bar_hint_with_title" msgid="4826526877249029043">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ಹುಡುಕಿ"</string>
     <string name="lb_search_bar_hint_with_title_speech" msgid="6032250334706920550">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ಮಾತನಾಡಿ ಹುಡುಕಾಟ ನಡೆಸಿ"</string>
diff --git a/leanback/leanback/src/main/res/values-ml/strings.xml b/leanback/leanback/src/main/res/values-ml/strings.xml
index 2122b08..58570f9 100644
--- a/leanback/leanback/src/main/res/values-ml/strings.xml
+++ b/leanback/leanback/src/main/res/values-ml/strings.xml
@@ -19,7 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="lb_navigation_menu_contentDescription" msgid="8084428500709675515">"നാവിഗേഷൻ മെനു"</string>
     <string name="orb_search_action" msgid="1301877238242752863">"തിരയൽ പ്രവർത്തനം"</string>
-    <string name="lb_search_bar_hint" msgid="5700349211583074131">"തിരയുക"</string>
+    <string name="lb_search_bar_hint" msgid="5700349211583074131">"Search"</string>
     <string name="lb_search_bar_hint_speech" msgid="5926531297066387462">"ശബ്‌ദം ഉപയോഗിച്ച് തിരയുക"</string>
     <string name="lb_search_bar_hint_with_title" msgid="4826526877249029043">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> തിരയുക"</string>
     <string name="lb_search_bar_hint_with_title_speech" msgid="6032250334706920550">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> തിരയുന്നതിന് സംസാരിക്കുക"</string>
diff --git a/leanback/leanback/src/main/res/values-mr/strings.xml b/leanback/leanback/src/main/res/values-mr/strings.xml
index 17a5a38..94c2c5c 100644
--- a/leanback/leanback/src/main/res/values-mr/strings.xml
+++ b/leanback/leanback/src/main/res/values-mr/strings.xml
@@ -19,7 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="lb_navigation_menu_contentDescription" msgid="8084428500709675515">"नेव्हिगेशन मेनू"</string>
     <string name="orb_search_action" msgid="1301877238242752863">"शोध क्रिया"</string>
-    <string name="lb_search_bar_hint" msgid="5700349211583074131">"शोधा"</string>
+    <string name="lb_search_bar_hint" msgid="5700349211583074131">"Search"</string>
     <string name="lb_search_bar_hint_speech" msgid="5926531297066387462">"शोधण्यासाठी बोला"</string>
     <string name="lb_search_bar_hint_with_title" msgid="4826526877249029043">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> शोधा"</string>
     <string name="lb_search_bar_hint_with_title_speech" msgid="6032250334706920550">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> शोधण्यासाठी बोला"</string>
diff --git a/leanback/leanback/src/main/res/values-ne/strings.xml b/leanback/leanback/src/main/res/values-ne/strings.xml
index ff431f5..6e05863 100644
--- a/leanback/leanback/src/main/res/values-ne/strings.xml
+++ b/leanback/leanback/src/main/res/values-ne/strings.xml
@@ -47,7 +47,7 @@
     <string name="lb_playback_controls_high_quality_disable" msgid="1209119371486219736">"उच्च गुणस्तरलाई असक्षम पार्नुहोस्"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="2346334170216706076">"उप शीर्षकहरू देखाउने सुविधालाई सक्षम पार्नुहोस्"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="8691966842977635128">"उप शीर्षकहरू देखाउने सुविधालाई असक्षम पार्नुहोस्"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="5770668162543767702">"तस्बिरभित्र तस्बिर नामक मोडमा प्रविष्टि गर्नुहोस्"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="5770668162543767702">"फोटोभित्र फोटो नामक मोडमा प्रविष्टि गर्नुहोस्"</string>
     <string name="lb_playback_time_separator" msgid="1471121602610716654">"/"</string>
     <string name="lb_playback_controls_shown" msgid="8690223891515602822">"मिडियाका नियन्त्रणहरू देखाइएका छन्"</string>
     <string name="lb_playback_controls_hidden" msgid="5859666950961624736">"मिडियाका नियन्त्रणहरूलाई लुकाइएको छ, देखाउनका लागि d-pad नामक बटन थिच्नुहोस्"</string>
diff --git a/leanback/leanback/src/main/res/values-or/strings.xml b/leanback/leanback/src/main/res/values-or/strings.xml
index 3fb650a..94d6eb3 100644
--- a/leanback/leanback/src/main/res/values-or/strings.xml
+++ b/leanback/leanback/src/main/res/values-or/strings.xml
@@ -19,7 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="lb_navigation_menu_contentDescription" msgid="8084428500709675515">"ନେଭିଗେଶନ୍ ମେନୁ"</string>
     <string name="orb_search_action" msgid="1301877238242752863">"ଖୋଜିବା କାମ"</string>
-    <string name="lb_search_bar_hint" msgid="5700349211583074131">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
+    <string name="lb_search_bar_hint" msgid="5700349211583074131">"Search"</string>
     <string name="lb_search_bar_hint_speech" msgid="5926531297066387462">"ଖୋଜିବା ପାଇଁ କୁହନ୍ତୁ"</string>
     <string name="lb_search_bar_hint_with_title" msgid="4826526877249029043">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ଖୋଜନ୍ତୁ"</string>
     <string name="lb_search_bar_hint_with_title_speech" msgid="6032250334706920550">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ଖୋଜିବା ପାଇଁ କୁହନ୍ତୁ"</string>
diff --git a/leanback/leanback/src/main/res/values-te/strings.xml b/leanback/leanback/src/main/res/values-te/strings.xml
index 372b590..5662227 100644
--- a/leanback/leanback/src/main/res/values-te/strings.xml
+++ b/leanback/leanback/src/main/res/values-te/strings.xml
@@ -19,7 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="lb_navigation_menu_contentDescription" msgid="8084428500709675515">"నావిగేషన్ మెను"</string>
     <string name="orb_search_action" msgid="1301877238242752863">"శోధన చర్య"</string>
-    <string name="lb_search_bar_hint" msgid="5700349211583074131">"శోధన"</string>
+    <string name="lb_search_bar_hint" msgid="5700349211583074131">"సెర్చ్"</string>
     <string name="lb_search_bar_hint_speech" msgid="5926531297066387462">"శోధించడానికి మాటల ద్వారా చెప్పండి"</string>
     <string name="lb_search_bar_hint_with_title" msgid="4826526877249029043">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> కోసం వెతకండి"</string>
     <string name="lb_search_bar_hint_with_title_speech" msgid="6032250334706920550">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>లో శోధించడానికి మాటల ద్వారా చెప్పండి"</string>
diff --git a/media2/session/src/main/res/values-pt-rPT/strings.xml b/media2/session/src/main/res/values-pt-rPT/strings.xml
index 413b9a6..48a0151 100644
--- a/media2/session/src/main/res/values-pt-rPT/strings.xml
+++ b/media2/session/src/main/res/values-pt-rPT/strings.xml
@@ -19,7 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="default_notification_channel_name" msgid="6743534657295236036">"A tocar"</string>
     <string name="play_button_content_description" msgid="6034272287948142298">"Reproduzir"</string>
-    <string name="pause_button_content_description" msgid="4221330012095125431">"Colocar em pausa"</string>
+    <string name="pause_button_content_description" msgid="4221330012095125431">"Pausar"</string>
     <string name="skip_to_previous_item_button_content_description" msgid="7233771088610629683">"Ir para o item anterior"</string>
     <string name="skip_to_next_item_button_content_description" msgid="17824442457643717">"Ir para o item seguinte"</string>
 </resources>
diff --git a/media2/widget/src/main/res/values-cs/strings.xml b/media2/widget/src/main/res/values-cs/strings.xml
index 139c9bf..f14483d 100644
--- a/media2/widget/src/main/res/values-cs/strings.xml
+++ b/media2/widget/src/main/res/values-cs/strings.xml
@@ -17,7 +17,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="MediaControlView_subtitle_off_text" msgid="1845015629089301203">"Vyp"</string>
+    <string name="MediaControlView_subtitle_off_text" msgid="1845015629089301203">"Vyp."</string>
     <string name="MediaControlView_audio_track_text" msgid="3532548952520840186">"Zvuková stopa"</string>
     <string name="MediaControlView_audio_track_none_text" msgid="549548876131348304">"Žádné"</string>
     <string name="MediaControlView_playback_speed_text" msgid="8150324864582460559">"Rychlost přehrávání"</string>
diff --git a/media2/widget/src/main/res/values-pt-rPT/strings.xml b/media2/widget/src/main/res/values-pt-rPT/strings.xml
index 078266f..697f595 100644
--- a/media2/widget/src/main/res/values-pt-rPT/strings.xml
+++ b/media2/widget/src/main/res/values-pt-rPT/strings.xml
@@ -40,7 +40,7 @@
     <string name="mcv2_cc_is_off" msgid="6888583680833967030">"As legendas estão desativadas. Clique para as mostrar."</string>
     <string name="mcv2_replay_button_desc" msgid="3498082316888662782">"Repetir"</string>
     <string name="mcv2_play_button_desc" msgid="1994649551115596877">"Reproduzir"</string>
-    <string name="mcv2_pause_button_desc" msgid="997297527148989963">"Colocar em pausa"</string>
+    <string name="mcv2_pause_button_desc" msgid="997297527148989963">"Pausar"</string>
     <string name="mcv2_previous_button_desc" msgid="5367141424871007842">"Conteúdo multimédia anterior"</string>
     <string name="mcv2_next_button_desc" msgid="4799850472802157220">"Conteúdo multimédia seguinte"</string>
     <string name="mcv2_rewind_button_desc" msgid="5725552141091554735">"Recuar 10 segundos"</string>
diff --git a/mediarouter/mediarouter/src/androidTest/AndroidManifest.xml b/mediarouter/mediarouter/src/androidTest/AndroidManifest.xml
index 512bb09..0b06c49 100644
--- a/mediarouter/mediarouter/src/androidTest/AndroidManifest.xml
+++ b/mediarouter/mediarouter/src/androidTest/AndroidManifest.xml
@@ -38,6 +38,12 @@
             </intent-filter>
         </receiver>
 
+        <service android:name="androidx.mediarouter.media.MediaRouteProviderServiceTest$MediaRouteProviderServiceImpl"
+                 android:enabled="true">
+            <intent-filter>
+                <action android:name="aandroid.media.MediaRouteProviderService"/>
+            </intent-filter>
+        </service>
     </application>
 
 </manifest>
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouteProviderServiceTest.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouteProviderServiceTest.java
new file mode 100644
index 0000000..287ac3b
--- /dev/null
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouteProviderServiceTest.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2020 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.mediarouter.media;
+
+import static androidx.mediarouter.media.MediaRouterActiveScanThrottlingHelper.MAX_ACTIVE_SCAN_DURATION_MS;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ServiceTestRule;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test {@link MediaRouteProviderService} and its related classes.
+ */
+@RunWith(AndroidJUnit4.class)
+public class MediaRouteProviderServiceTest {
+    private static final long TIME_OUT_MS = 3000;
+
+    @Rule
+    public final ServiceTestRule mServiceRule = new ServiceTestRule();
+    private IBinder mService;
+    private Messenger mServiceMessenger;
+    private Messenger mReceiveMessenger1;
+    private Messenger mReceiveMessenger2;
+    private int mRequestId;
+    private MediaRouteSelector mSelector;
+
+    private static CountDownLatch sActiveScanCountDownLatch;
+    private static CountDownLatch sPassiveScanCountDownLatch;
+    private static MediaRouteDiscoveryRequest sLastDiscoveryRequest;
+
+    @Before
+    public void setUp() throws Exception {
+        resetActiveAndPassiveScanCountDownLatches();
+        Context context = ApplicationProvider.getApplicationContext();
+        Intent intent =
+                new Intent(context, MediaRouteProviderServiceImpl.class)
+                        .setAction(MediaRouteProviderProtocol.SERVICE_INTERFACE);
+        mService = mServiceRule.bindService(intent);
+        mServiceMessenger = new Messenger(mService);
+        mReceiveMessenger1 = new Messenger(new Handler(Looper.getMainLooper()));
+        mReceiveMessenger2 = new Messenger(new Handler(Looper.getMainLooper()));
+        mSelector = new MediaRouteSelector.Builder()
+                .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO).build();
+        registerClient(mReceiveMessenger1);
+        registerClient(mReceiveMessenger2);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        unregisterClient(mReceiveMessenger1);
+        unregisterClient(mReceiveMessenger2);
+        mServiceRule.unbindService();
+        sLastDiscoveryRequest = null;
+    }
+
+    @LargeTest
+    @Test
+    public void testSetEmptyPassiveDiscoveryRequest_shouldNotRequestScan() throws Exception {
+        sendDiscoveryRequest(mReceiveMessenger1,
+                new MediaRouteDiscoveryRequest(MediaRouteSelector.EMPTY, false));
+
+        Thread.sleep(TIME_OUT_MS);
+
+        assertNull(sLastDiscoveryRequest);
+    }
+
+    @LargeTest
+    @Test
+    public void testSetEmptyActiveDiscoveryRequest_shouldRequestScan() throws Exception {
+        resetActiveAndPassiveScanCountDownLatches();
+        sendDiscoveryRequest(mReceiveMessenger1,
+                new MediaRouteDiscoveryRequest(MediaRouteSelector.EMPTY, true));
+
+        assertTrue(sActiveScanCountDownLatch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @LargeTest
+    @Test
+    public void testRequestActiveScan_suppressActiveScanAfter30Seconds() throws Exception {
+        // Request active discovery.
+        resetActiveAndPassiveScanCountDownLatches();
+        sendDiscoveryRequest(mReceiveMessenger1, new MediaRouteDiscoveryRequest(mSelector, true));
+
+        // Active scan should be true.
+        assertTrue(sActiveScanCountDownLatch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS));
+
+        // Right before active scan duration passes, active scan flag should still be true.
+        resetActiveAndPassiveScanCountDownLatches();
+        assertFalse(sPassiveScanCountDownLatch.await(
+                MAX_ACTIVE_SCAN_DURATION_MS - 1000, TimeUnit.MILLISECONDS));
+
+        // After active scan duration passed, active scan flag should be false.
+        resetActiveAndPassiveScanCountDownLatches();
+        assertTrue(sPassiveScanCountDownLatch.await(1000 + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+
+        // Request active discovery again.
+        sendDiscoveryRequest(mReceiveMessenger1, new MediaRouteDiscoveryRequest(mSelector, false));
+        resetActiveAndPassiveScanCountDownLatches();
+        sendDiscoveryRequest(mReceiveMessenger1, new MediaRouteDiscoveryRequest(mSelector, true));
+
+        // Active scan should be true.
+        assertTrue(sActiveScanCountDownLatch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS));
+
+        // Right before active scan duration passes, active scan flag should still be true.
+        resetActiveAndPassiveScanCountDownLatches();
+        assertFalse(sPassiveScanCountDownLatch.await(
+                MAX_ACTIVE_SCAN_DURATION_MS - 1000, TimeUnit.MILLISECONDS));
+
+        // After active scan duration passed, active scan flag should be false.
+        resetActiveAndPassiveScanCountDownLatches();
+        assertTrue(sPassiveScanCountDownLatch.await(1000 + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @LargeTest
+    @Test
+    public void testRequestActiveScanFromMultipleClients_suppressActiveScanAfter30Seconds()
+            throws Exception {
+        // Request active scan from client 1.
+        sendDiscoveryRequest(mReceiveMessenger1, new MediaRouteDiscoveryRequest(mSelector, true));
+
+        // Sleep 10 seconds and request active scan from client 2.
+        Thread.sleep(10000);
+        sendDiscoveryRequest(mReceiveMessenger2, new MediaRouteDiscoveryRequest(mSelector, true));
+
+        // Active scan should be true.
+        assertTrue(sActiveScanCountDownLatch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS));
+
+        // Right before the last client times out, active scan flag should still be true.
+        resetActiveAndPassiveScanCountDownLatches();
+        assertFalse(sActiveScanCountDownLatch.await(
+                MAX_ACTIVE_SCAN_DURATION_MS - 1000, TimeUnit.MILLISECONDS));
+
+        // Right after the active scan duration passed, active scan flag should be false.
+        resetActiveAndPassiveScanCountDownLatches();
+        assertTrue(sPassiveScanCountDownLatch.await(1000 + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+    }
+
+    private void registerClient(Messenger receiveMessenger) throws Exception {
+        Message msg = Message.obtain();
+        msg.what = MediaRouteProviderProtocol.CLIENT_MSG_REGISTER;
+        msg.arg1 = mRequestId++;
+        msg.arg2 = MediaRouteProviderProtocol.CLIENT_VERSION_CURRENT;
+        msg.replyTo = receiveMessenger;
+
+        mServiceMessenger.send(msg);
+    }
+
+    private void unregisterClient(Messenger receiveMessenger) throws Exception {
+        Message msg = Message.obtain();
+        msg.what = MediaRouteProviderProtocol.CLIENT_MSG_UNREGISTER;
+        msg.replyTo = receiveMessenger;
+
+        mServiceMessenger.send(msg);
+    }
+
+    private void sendDiscoveryRequest(Messenger receiveMessenger,
+            MediaRouteDiscoveryRequest request) throws Exception {
+        Message msg = Message.obtain();
+        msg.what = MediaRouteProviderProtocol.CLIENT_MSG_SET_DISCOVERY_REQUEST;
+        msg.arg1 = mRequestId++;
+        msg.obj = (request != null) ? request.asBundle() : null;
+        msg.replyTo = receiveMessenger;
+
+        mServiceMessenger.send(msg);
+    }
+
+    /** Fake {@link MediaRouteProviderService} implementation. */
+    public static final class MediaRouteProviderServiceImpl extends MediaRouteProviderService {
+        @Override
+        public MediaRouteProvider onCreateMediaRouteProvider() {
+            return new MediaRouteProviderImpl(this);
+        }
+    }
+
+    /** Fake {@link MediaRouteProvider} implementation. */
+    public static class MediaRouteProviderImpl extends MediaRouteProvider {
+        MediaRouteProviderImpl(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest discoveryRequest) {
+            boolean wasActiveScan =
+                    (sLastDiscoveryRequest != null) ? sLastDiscoveryRequest.isActiveScan() : false;
+            boolean isActiveScan =
+                    (discoveryRequest != null) ? discoveryRequest.isActiveScan() : false;
+            if (wasActiveScan != isActiveScan) {
+                if (isActiveScan) {
+                    sActiveScanCountDownLatch.countDown();
+                } else {
+                    sPassiveScanCountDownLatch.countDown();
+                }
+            }
+            sLastDiscoveryRequest = discoveryRequest;
+        }
+    }
+
+    private void resetActiveAndPassiveScanCountDownLatches() {
+        sActiveScanCountDownLatch = new CountDownLatch(1);
+        sPassiveScanCountDownLatch = new CountDownLatch(1);
+    }
+}
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java
index f64a65b..9f13b0486 100644
--- a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java
@@ -54,7 +54,7 @@
 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.R)
 public class MediaRouter2Test {
     private static final String TAG = "MR2Test";
-    private static final int TIMEOUT_MS = 5000;
+    private static final int TIMEOUT_MS = 5_000;
 
     Context mContext;
     MediaRouter mRouter;
@@ -113,6 +113,7 @@
     public void selectFromMr1AndStopFromSystem_unselect() throws Exception {
         CountDownLatch onRouteSelectedLatch = new CountDownLatch(1);
         CountDownLatch onRouteUnselectedLatch = new CountDownLatch(1);
+        CountDownLatch onRouteEnabledLatch = new CountDownLatch(1);
         String descriptorId = StubMediaRouteProviderService.ROUTE_ID1;
 
         addCallback(new MediaRouter.Callback() {
@@ -133,6 +134,15 @@
                     onRouteUnselectedLatch.countDown();
                 }
             }
+
+            @Override
+            public void onRouteChanged(MediaRouter router, RouteInfo route) {
+                if (onRouteUnselectedLatch.getCount() == 0
+                        && TextUtils.equals(route.getDescriptorId(), descriptorId)
+                        && route.isEnabled()) {
+                    onRouteEnabledLatch.countDown();
+                }
+            }
         });
         waitForRoutesAdded();
         assertNotNull(mRoutes);
@@ -148,10 +158,14 @@
                 () -> !mMr2ProviderServiceAdapter.getAllSessionInfo().isEmpty());
         //TODO: Find a correct session info
         for (RoutingSessionInfo sessionInfo : mMr2ProviderServiceAdapter.getAllSessionInfo()) {
-            mMr2ProviderServiceAdapter.onReleaseSession(MediaRoute2ProviderService.REQUEST_ID_NONE,
-                    sessionInfo.getId());
+            getInstrumentation().runOnMainSync(() ->
+                    mMr2ProviderServiceAdapter.onReleaseSession(
+                            MediaRoute2ProviderService.REQUEST_ID_NONE,
+                            sessionInfo.getId()));
         }
         assertTrue(onRouteUnselectedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        // Make sure the route is enabled
+        assertTrue(onRouteEnabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
     void addCallback(MediaRouter.Callback callback) {
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterActiveScanThrottlingHelperTest.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterActiveScanThrottlingHelperTest.java
new file mode 100644
index 0000000..dc439aa
--- /dev/null
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterActiveScanThrottlingHelperTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2020 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.mediarouter.media;
+
+import static androidx.mediarouter.media.MediaRouterActiveScanThrottlingHelper.MAX_ACTIVE_SCAN_DURATION_MS;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.SystemClock;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test {@link MediaRouterActiveScanThrottlingHelper}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class MediaRouterActiveScanThrottlingHelperTest {
+    private static final long TIME_OUT_MS = 3000;
+    private CountDownLatch mCountDownLatch;
+    private Runnable mRunnable;
+
+    @Before
+    public void setUp() {
+        resetCountDownLatch();
+        mRunnable = new Runnable() {
+            @Override
+            public void run() {
+                mCountDownLatch.countDown();
+            }
+        };
+    }
+
+    @Test
+    @LargeTest
+    public void testActiveScan_noActiveScan() throws Exception {
+        long currentTime = SystemClock.elapsedRealtime();
+        MediaRouterActiveScanThrottlingHelper helper = new MediaRouterActiveScanThrottlingHelper(
+                mRunnable);
+
+        helper.reset();
+
+        helper.requestActiveScan(false, currentTime);
+        helper.requestActiveScan(false, currentTime);
+        helper.requestActiveScan(false, currentTime);
+
+        assertFalse(helper.finalizeActiveScanAndScheduleSuppressActiveScanRunnable());
+
+        assertFalse(mCountDownLatch.await(
+                MAX_ACTIVE_SCAN_DURATION_MS + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    @LargeTest
+    public void testActiveScan_hasNonExpiredActiveScan() throws Exception {
+        long currentTime = SystemClock.elapsedRealtime();
+        MediaRouterActiveScanThrottlingHelper helper = new MediaRouterActiveScanThrottlingHelper(
+                mRunnable);
+
+        helper.reset();
+
+        helper.requestActiveScan(true, currentTime);
+        helper.requestActiveScan(false, currentTime);
+        helper.requestActiveScan(false, currentTime);
+
+        assertTrue(helper.finalizeActiveScanAndScheduleSuppressActiveScanRunnable());
+
+        assertTrue(mCountDownLatch.await(
+                MAX_ACTIVE_SCAN_DURATION_MS + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    @LargeTest
+    public void testActiveScan_allActiveScanRequestsExpired() throws Exception {
+        long currentTime = SystemClock.elapsedRealtime();
+        MediaRouterActiveScanThrottlingHelper helper =
+                new MediaRouterActiveScanThrottlingHelper(mRunnable);
+
+        helper.reset();
+
+        helper.requestActiveScan(true, currentTime - MAX_ACTIVE_SCAN_DURATION_MS);
+        helper.requestActiveScan(true, currentTime - MAX_ACTIVE_SCAN_DURATION_MS);
+        helper.requestActiveScan(true, currentTime - MAX_ACTIVE_SCAN_DURATION_MS);
+
+        assertFalse(helper.finalizeActiveScanAndScheduleSuppressActiveScanRunnable());
+
+        assertFalse(mCountDownLatch.await(
+                MAX_ACTIVE_SCAN_DURATION_MS + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+    }
+
+
+    @Test
+    @LargeTest
+    public void testActiveScan_allActiveScanRequestsWithMixedTimestamps() throws Exception {
+        long currentTime = SystemClock.elapsedRealtime();
+        MediaRouterActiveScanThrottlingHelper helper =
+                new MediaRouterActiveScanThrottlingHelper(mRunnable);
+
+        helper.reset();
+
+        helper.requestActiveScan(true, currentTime - 2000);
+        helper.requestActiveScan(true, currentTime - 5000);
+        helper.requestActiveScan(true, currentTime - 7000);
+
+        assertTrue(helper.finalizeActiveScanAndScheduleSuppressActiveScanRunnable());
+
+        // Active scan should not be suppressed before the last active scan is in effect.
+        assertFalse(mCountDownLatch.await(MAX_ACTIVE_SCAN_DURATION_MS - 2000 - 1000,
+                TimeUnit.MILLISECONDS));
+
+        // Active scan should be suppressed after the last active scan times out.
+        assertTrue(mCountDownLatch.await(1000 + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    @LargeTest
+    public void testReset_shouldCleanupActiveScanAndSuppressingRunnable() throws Exception {
+        long currentTime = SystemClock.elapsedRealtime();
+        MediaRouterActiveScanThrottlingHelper helper =
+                new MediaRouterActiveScanThrottlingHelper(mRunnable);
+
+        helper.reset();
+
+        helper.requestActiveScan(true, currentTime);
+        helper.requestActiveScan(false, currentTime);
+        helper.requestActiveScan(false, currentTime);
+
+        assertTrue(helper.finalizeActiveScanAndScheduleSuppressActiveScanRunnable());
+
+        helper.reset();
+
+        assertFalse(mCountDownLatch.await(
+                MAX_ACTIVE_SCAN_DURATION_MS + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+        assertFalse(helper.finalizeActiveScanAndScheduleSuppressActiveScanRunnable());
+    }
+
+    private void resetCountDownLatch() {
+        mCountDownLatch = new CountDownLatch(1);
+    }
+}
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterTest.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterTest.java
index 9834612..ad9c2b2 100644
--- a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterTest.java
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouterTest.java
@@ -16,6 +16,7 @@
 
 package androidx.mediarouter.media;
 
+import static androidx.mediarouter.media.MediaRouterActiveScanThrottlingHelper.MAX_ACTIVE_SCAN_DURATION_MS;
 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
@@ -32,6 +33,7 @@
 
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
 import androidx.test.filters.SmallTest;
 
 import org.junit.After;
@@ -39,6 +41,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Test {@link MediaRouter}.
  */
@@ -57,15 +62,20 @@
     private MediaRouter mRouter;
     private MediaSessionCompat mSession;
     private MediaSessionCallback mSessionCallback = new MediaSessionCallback();
+    private MediaRouteProviderImpl mProvider;
+    private CountDownLatch mActiveScanCountDownLatch;
+    private CountDownLatch mPassiveScanCountDownLatch;
 
     @Before
     public void setUp() throws Exception {
+        resetActiveAndPassiveScanCountDownLatches();
         getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 mContext = getApplicationContext();
                 mRouter = MediaRouter.getInstance(mContext);
                 mSession = new MediaSessionCompat(mContext, SESSION_TAG);
+                mProvider = new MediaRouteProviderImpl(mContext);
             }
         });
     }
@@ -168,6 +178,91 @@
         assertEquals(expectedParams, actualParams);
     }
 
+    @Test
+    @LargeTest
+    public void testRegisterActiveScanCallback_suppressActiveScanAfter30Seconds() throws Exception {
+        MediaRouteSelector selector =
+                new MediaRouteSelector.Builder()
+                        .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO).build();
+        MediaRouterCallbackImpl callback = new MediaRouterCallbackImpl();
+
+        // Add the provider and callback.
+        resetActiveAndPassiveScanCountDownLatches();
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mRouter.addProvider(mProvider);
+                mRouter.addCallback(selector, callback,
+                        MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
+            }
+        });
+
+        // Active scan should be true.
+        assertTrue(mActiveScanCountDownLatch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS));
+
+        // After active scan duration, active scan should be false.
+        resetActiveAndPassiveScanCountDownLatches();
+        assertTrue(mPassiveScanCountDownLatch.await(
+                MAX_ACTIVE_SCAN_DURATION_MS + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+
+        // Add the same callback again.
+        resetActiveAndPassiveScanCountDownLatches();
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mRouter.addCallback(selector, callback,
+                        MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
+            }
+        });
+
+        // Active scan should be true.
+        assertTrue(mActiveScanCountDownLatch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS));
+
+        // After active scan duration, active scan should be false.
+        resetActiveAndPassiveScanCountDownLatches();
+        assertTrue(mPassiveScanCountDownLatch.await(
+                MAX_ACTIVE_SCAN_DURATION_MS + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    @LargeTest
+    public void testRegisterMultipleActiveScanCallbacks_suppressActiveScanAfter30Seconds()
+            throws Exception {
+        MediaRouteSelector selector =
+                new MediaRouteSelector.Builder()
+                        .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO).build();
+        MediaRouterCallbackImpl callback1 = new MediaRouterCallbackImpl();
+        MediaRouterCallbackImpl callback2 = new MediaRouterCallbackImpl();
+
+        // Add the provider and the first callback.
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mRouter.addProvider(mProvider);
+                mRouter.addCallback(selector, callback1,
+                        MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
+            }
+        });
+
+        // Wait for 5 seconds, add the second callback.
+        Thread.sleep(5000);
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mRouter.addCallback(selector, callback2,
+                        MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
+            }
+        });
+
+        resetActiveAndPassiveScanCountDownLatches();
+        // Wait for active scan duration to nearly end, active scan flag should be true.
+        assertFalse(mPassiveScanCountDownLatch.await(MAX_ACTIVE_SCAN_DURATION_MS - 1000,
+                TimeUnit.MILLISECONDS));
+
+        // Wait until active scan duration ends, active scan flag should be false.
+        assertTrue(mPassiveScanCountDownLatch.await(1000 + TIME_OUT_MS, TimeUnit.MILLISECONDS));
+    }
+
     /**
      * Asserts that two Bundles are equal.
      */
@@ -206,4 +301,32 @@
             }
         }
     }
+
+    private class MediaRouteProviderImpl extends MediaRouteProvider {
+        private boolean mIsActiveScan;
+
+        MediaRouteProviderImpl(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest discoveryRequest) {
+            if (mIsActiveScan != discoveryRequest.isActiveScan()) {
+                mIsActiveScan = discoveryRequest.isActiveScan();
+                if (mIsActiveScan) {
+                    mActiveScanCountDownLatch.countDown();
+                } else {
+                    mPassiveScanCountDownLatch.countDown();
+                }
+            }
+        }
+
+    }
+
+    private void resetActiveAndPassiveScanCountDownLatches() {
+        mActiveScanCountDownLatch = new CountDownLatch(1);
+        mPassiveScanCountDownLatch = new CountDownLatch(1);
+    }
+
+    private static class MediaRouterCallbackImpl extends MediaRouter.Callback {}
 }
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java
index f742900..401eb08 100644
--- a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/StubMediaRouteProviderService.java
@@ -18,10 +18,10 @@
 
 import android.content.Context;
 import android.content.IntentFilter;
-import android.util.ArrayMap;
 
 import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
+import androidx.collection.ArrayMap;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java
index 4b90f65..a279629 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRoute2ProviderServiceAdapter.java
@@ -773,8 +773,9 @@
                 }
 
                 if (shouldUnselect) {
+                    mController.onUnselect(MediaRouter.UNSELECT_REASON_STOPPED);
+                    mController.onRelease();
                     if ((mFlags & SESSION_FLAG_MR2) == 0) {
-                        // Let the client release the controller
                         ClientRecord clientRecord = mClientRecord.get();
                         if (clientRecord != null) {
                             RouteController controller = mController;
@@ -782,12 +783,8 @@
                                 controller = ((DynamicGroupRouteControllerProxy) mController)
                                         .mRouteController;
                             }
-                            mServiceImpl.requestReleaseController(clientRecord,
-                                    controller, mRouteId);
+                            clientRecord.releaseControllerByProvider(controller, mRouteId);
                         }
-                    } else {
-                        mController.onUnselect(MediaRouter.UNSELECT_REASON_STOPPED);
-                        mController.onRelease();
                     }
                 }
                 mIsReleased = true;
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderProtocol.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderProtocol.java
index 27305d4..d82e4d1 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderProtocol.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderProtocol.java
@@ -236,11 +236,11 @@
     public static final int SERVICE_MSG_DYNAMIC_ROUTE_DESCRIPTORS_CHANGED = 7;
 
     /** (service v3) / (client v4)
-     * Request to release a route controller. (unsolicited event)
+     * Route controller released by the provider. (unsolicited event)
      * - arg1    : reserved(0)
      * - arg2    : controllerId
      */
-    public static final int SERVICE_MSG_RELEASE_CONTROLLER = 8;
+    public static final int SERVICE_MSG_CONTROLLER_RELEASED = 8;
 
     public static final String SERVICE_DATA_ERROR = "error";
 
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderService.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderService.java
index 9ff3b77..1261c18 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderService.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouteProviderService.java
@@ -43,6 +43,7 @@
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.DATA_KEY_GROUP_ROUTE_DESCRIPTOR;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.DATA_KEY_TRANSFERABLE_SECTION_TITLE;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_DATA_ERROR;
+import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_CONTROLLER_RELEASED;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_CONTROL_REQUEST_FAILED;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_DESCRIPTOR_CHANGED;
@@ -51,7 +52,6 @@
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_GENERIC_FAILURE;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_GENERIC_SUCCESS;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_REGISTERED;
-import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_RELEASE_CONTROLLER;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_VERSION_CURRENT;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.isValidRemoteMessenger;
 import static androidx.mediarouter.media.MediaRouter.UNSELECT_REASON_UNKNOWN;
@@ -66,10 +66,11 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
+import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
-import android.text.TextUtils;
+import android.os.SystemClock;
 import android.util.Log;
 import android.util.SparseArray;
 
@@ -87,6 +88,7 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
@@ -275,17 +277,17 @@
 
     static void sendGenericFailure(Messenger messenger, int requestId) {
         if (requestId != 0) {
-            sendReply(messenger, SERVICE_MSG_GENERIC_FAILURE, requestId, 0, null, null);
+            sendMessage(messenger, SERVICE_MSG_GENERIC_FAILURE, requestId, 0, null, null);
         }
     }
 
     static void sendGenericSuccess(Messenger messenger, int requestId) {
         if (requestId != 0) {
-            sendReply(messenger, SERVICE_MSG_GENERIC_SUCCESS, requestId, 0, null, null);
+            sendMessage(messenger, SERVICE_MSG_GENERIC_SUCCESS, requestId, 0, null, null);
         }
     }
 
-    static void sendReply(Messenger messenger, int what,
+    static void sendMessage(Messenger messenger, int what,
             int requestId, int arg, Object obj, Bundle data) {
         Message msg = Message.obtain();
         msg.what = what;
@@ -491,6 +493,14 @@
         final ArrayList<ClientRecord> mClients = new ArrayList<ClientRecord>();
         MediaRouteDiscoveryRequest mCompositeDiscoveryRequest;
         MediaRouteDiscoveryRequest mBaseDiscoveryRequest;
+        long mBaseDiscoveryRequestTimestamp;
+        private final MediaRouterActiveScanThrottlingHelper mActiveScanThrottlingHelper =
+                new MediaRouterActiveScanThrottlingHelper(new Runnable() {
+                    @Override
+                    public void run() {
+                        updateCompositeDiscoveryRequest();
+                    }
+                });
 
         MediaRouteProviderServiceImplBase(MediaRouteProviderService service) {
             mService = service;
@@ -534,7 +544,7 @@
                         if (requestId != 0) {
                             MediaRouteProviderDescriptor descriptor =
                                     mService.getMediaRouteProvider().getDescriptor();
-                            sendReply(messenger, SERVICE_MSG_REGISTERED,
+                            sendMessage(messenger, SERVICE_MSG_REGISTERED,
                                     requestId, SERVICE_VERSION_CURRENT,
                                     createDescriptorBundleForClientVersion(descriptor,
                                             client.mVersion), null);
@@ -604,7 +614,7 @@
                                 + controllerId
                                 + ", initialMemberRouteId=" + initialMemberRouteId);
                     }
-                    sendReply(messenger, SERVICE_MSG_DYNAMIC_ROUTE_CREATED,
+                    sendMessage(messenger, SERVICE_MSG_DYNAMIC_ROUTE_CREATED,
                             requestId, SERVICE_VERSION_CURRENT,
                             bundle, null);
                     return true;
@@ -793,7 +803,7 @@
                                             + ", data=" + data);
                                 }
                                 if (findClient(messenger) >= 0) {
-                                    sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED,
+                                    sendMessage(messenger, SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED,
                                             requestId, 0, data, null);
                                 }
                             }
@@ -810,10 +820,10 @@
                                     if (error != null) {
                                         Bundle bundle = new Bundle();
                                         bundle.putString(SERVICE_DATA_ERROR, error);
-                                        sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
+                                        sendMessage(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
                                                 requestId, 0, data, bundle);
                                     } else {
-                                        sendReply(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
+                                        sendMessage(messenger, SERVICE_MSG_CONTROL_REQUEST_FAILED,
                                                 requestId, 0, data, null);
                                     }
                                 }
@@ -853,8 +863,8 @@
             final int count = mClients.size();
             for (int i = 0; i < count; i++) {
                 ClientRecord client = mClients.get(i);
-                sendReply(client.mMessenger, SERVICE_MSG_DESCRIPTOR_CHANGED, 0, 0,
-                        createDescriptorBundleForClientVersion(descriptor, client.mVersion), null);
+                sendMessage(client.mMessenger, SERVICE_MSG_DESCRIPTOR_CHANGED, 0, 0,
+                        client.createDescriptorBundle(descriptor), null);
                 if (DEBUG) {
                     Log.d(TAG, client + ": Sent descriptor change event, descriptor=" + descriptor);
                 }
@@ -862,8 +872,11 @@
         }
 
         boolean setBaseDiscoveryRequest(MediaRouteDiscoveryRequest request) {
-            if (!ObjectsCompat.equals(mBaseDiscoveryRequest, request)) {
+            long timestamp = SystemClock.elapsedRealtime();
+            if (!ObjectsCompat.equals(mBaseDiscoveryRequest, request) || request.isActiveScan()) {
                 mBaseDiscoveryRequest = request;
+                mBaseDiscoveryRequestTimestamp = timestamp;
+
                 return updateCompositeDiscoveryRequest();
             }
             return false;
@@ -871,20 +884,24 @@
 
         boolean updateCompositeDiscoveryRequest() {
             MediaRouteSelector.Builder selectorBuilder = null;
-            boolean activeScan = false;
+            mActiveScanThrottlingHelper.reset();
 
             if (mBaseDiscoveryRequest != null) {
-                activeScan = mBaseDiscoveryRequest.isActiveScan();
+                mActiveScanThrottlingHelper.requestActiveScan(
+                        mBaseDiscoveryRequest.isActiveScan(),
+                        mBaseDiscoveryRequestTimestamp);
                 selectorBuilder = new MediaRouteSelector.Builder(
                         mBaseDiscoveryRequest.getSelector());
             }
 
             final int count = mClients.size();
             for (int i = 0; i < count; i++) {
-                MediaRouteDiscoveryRequest request = mClients.get(i).mDiscoveryRequest;
+                ClientRecord clientRecord = mClients.get(i);
+                MediaRouteDiscoveryRequest request = clientRecord.mDiscoveryRequest;
                 if (request != null
                         && (!request.getSelector().isEmpty() || request.isActiveScan())) {
-                    activeScan |= request.isActiveScan();
+                    mActiveScanThrottlingHelper.requestActiveScan(request.isActiveScan(),
+                            clientRecord.mDiscoveryRequestTimestamp);
                     if (selectorBuilder == null) {
                         selectorBuilder = new MediaRouteSelector.Builder(request.getSelector());
                     } else {
@@ -893,6 +910,9 @@
                 }
             }
 
+            boolean activeScan =
+                    mActiveScanThrottlingHelper
+                            .finalizeActiveScanAndScheduleSuppressActiveScanRunnable();
             MediaRouteDiscoveryRequest composite = (selectorBuilder == null) ? null
                     : new MediaRouteDiscoveryRequest(selectorBuilder.build(), activeScan);
             if (!ObjectsCompat.equals(mCompositeDiscoveryRequest, composite)) {
@@ -919,12 +939,12 @@
             return -1;
         }
 
-        //TODO: Reconsider "ClientRecord" structure
         class ClientRecord implements DeathRecipient {
             public final Messenger mMessenger;
             public final int mVersion;
             public final String mPackageName;
             public MediaRouteDiscoveryRequest mDiscoveryRequest;
+            public long mDiscoveryRequestTimestamp;
 
             final SparseArray<RouteController> mControllers = new SparseArray<>();
 
@@ -1023,13 +1043,23 @@
             }
 
             public boolean setDiscoveryRequest(MediaRouteDiscoveryRequest request) {
+                long timestamp = SystemClock.elapsedRealtime();
                 if (!ObjectsCompat.equals(mDiscoveryRequest, request)) {
                     mDiscoveryRequest = request;
+                    mDiscoveryRequestTimestamp = timestamp;
                     return updateCompositeDiscoveryRequest();
                 }
+
                 return false;
             }
 
+            /**
+             * Creates a bundle of the given provider descriptor for this client.
+             */
+            public Bundle createDescriptorBundle(MediaRouteProviderDescriptor descriptor) {
+                return createDescriptorBundleForClientVersion(descriptor, mVersion);
+            }
+
             // Runs on a binder thread.
             @Override
             public void binderDied() {
@@ -1063,7 +1093,7 @@
                 }
                 bundle.putParcelableArrayList(DATA_KEY_DYNAMIC_ROUTE_DESCRIPTORS,
                         dynamicRouteBundles);
-                sendReply(mMessenger, SERVICE_MSG_DYNAMIC_ROUTE_DESCRIPTORS_CHANGED,
+                sendMessage(mMessenger, SERVICE_MSG_DYNAMIC_ROUTE_DESCRIPTORS_CHANGED,
                         0, controllerId, bundle, null);
             }
         }
@@ -1121,48 +1151,6 @@
             mMR2ProviderServiceAdapter.setProviderDescriptor(descriptor);
         }
 
-        void requestReleaseController(ClientRecord client,
-                RouteController controller, String routeId) {
-            if (client.mVersion >= CLIENT_VERSION_4) {
-                int controllerId = client.findControllerIdByController(controller);
-                if (controllerId < 0) {
-                    Log.w(TAG, "requestReleaseController: Can't find the controller."
-                            + " route ID=" + routeId);
-                    return;
-                }
-                sendReply(client.mMessenger, SERVICE_MSG_RELEASE_CONTROLLER, 0, controllerId,
-                        null, null);
-                return;
-            }
-
-            // The below is a workaround to unselect the selected route of previous clients.
-            // The logic is based on the behavior that MediaRouter unselects its selected route if
-            // the route becomes disabled.
-            MediaRouteProviderDescriptor lastDescriptor =
-                    getService().getMediaRouteProvider().getDescriptor();
-            if (lastDescriptor == null) {
-                Log.w(TAG, "requestReleaseController: null provider descriptor found. "
-                        + "It shouldn't happen.");
-                return;
-            }
-
-            List<MediaRouteDescriptor> routes = new ArrayList<>();
-            for (MediaRouteDescriptor descriptor : lastDescriptor.getRoutes()) {
-                if (TextUtils.equals(descriptor.getId(), routeId)) {
-                    routes.add(new MediaRouteDescriptor.Builder(descriptor)
-                            .setEnabled(false).build());
-                } else {
-                    routes.add(descriptor);
-                }
-            }
-
-            MediaRouteProviderDescriptor providerDescriptor =
-                    new MediaRouteProviderDescriptor.Builder(lastDescriptor)
-                    .setRoutes(routes).build();
-            sendReply(client.mMessenger, SERVICE_MSG_DESCRIPTOR_CHANGED, 0, 0,
-                    createDescriptorBundleForClientVersion(providerDescriptor, client.mVersion),
-                    null);
-        }
 
         @Override
         MediaRouteProviderServiceImplBase.ClientRecord createClientRecord(
@@ -1179,9 +1167,20 @@
         class ClientRecord extends MediaRouteProviderServiceImplBase.ClientRecord {
             // Maps the route ID to member route controller.
             private final Map<String, RouteController> mRouteIdToControllerMap = new ArrayMap<>();
+            private final Handler mClientHandler = new Handler(Looper.getMainLooper());
+
+            // Maps disabled route ID to ID of controllers released by provider.
+            private final Map<String, Integer> mReleasedControllerIds;
+            private static final long DISABLE_ROUTE_FOR_RELEASED_CONTROLLER_TIMEOUT_MS = 5_000;
 
             ClientRecord(Messenger messenger, int version, String packageName) {
                 super(messenger, version, packageName);
+                // Only required by clients that don't support SERVICE_MSG_CONTROLLER_RELEASED.
+                if (version < CLIENT_VERSION_4) {
+                    mReleasedControllerIds = new ArrayMap<>();
+                } else {
+                    mReleasedControllerIds = Collections.emptyMap();
+                }
             }
 
             @Override
@@ -1233,6 +1232,12 @@
                         }
                     }
                 }
+                for (Map.Entry<String, Integer> entry : mReleasedControllerIds.entrySet()) {
+                    if (entry.getValue() == controllerId) {
+                        enableRouteForReleasedRouteController(/*routeId=*/entry.getKey());
+                        break;
+                    }
+                }
                 return super.releaseRouteController(controllerId);
             }
 
@@ -1248,6 +1253,81 @@
                 }
             }
 
+            @Override
+            public Bundle createDescriptorBundle(MediaRouteProviderDescriptor descriptor) {
+                if (mReleasedControllerIds.isEmpty()) {
+                    return super.createDescriptorBundle(descriptor);
+                }
+
+                List<MediaRouteDescriptor> routes = new ArrayList<>();
+                for (MediaRouteDescriptor routeDescriptor : descriptor.getRoutes()) {
+                    if (mReleasedControllerIds.containsKey(routeDescriptor.getId())) {
+                        routes.add(new MediaRouteDescriptor.Builder(routeDescriptor)
+                                .setEnabled(false).build());
+                    } else {
+                        routes.add(routeDescriptor);
+                    }
+                }
+
+                MediaRouteProviderDescriptor newDescriptor =
+                        new MediaRouteProviderDescriptor.Builder(descriptor)
+                                .setRoutes(routes).build();
+                return super.createDescriptorBundle(newDescriptor);
+            }
+
+            void releaseControllerByProvider(RouteController controller, String routeId) {
+                int controllerId = findControllerIdByController(controller);
+                releaseRouteController(controllerId);
+
+                // Let the client unselect the corresponding route.
+                if (mVersion >= CLIENT_VERSION_4) {
+                    if (controllerId < 0) {
+                        Log.w(TAG, "releaseControllerByProvider: Can't find the controller."
+                                + " route ID=" + routeId);
+                        return;
+                    }
+                    sendMessage(mMessenger, SERVICE_MSG_CONTROLLER_RELEASED, 0, controllerId,
+                            null, null);
+                } else {
+                    // Use a workaround for old versions.
+                    disableRouteForReleasedRouteController(routeId, controllerId);
+                }
+            }
+
+            /**
+             * Sets the route that corresponds to the given released route controller as disabled
+             * so that media router client unselects the route and releases the route controller
+             * on the client side.
+             * The route becomes enabled when the route controller on the client side is released
+             * or it times out.
+             */
+            private void disableRouteForReleasedRouteController(String routeId, int controllerId) {
+                mReleasedControllerIds.put(routeId, controllerId);
+
+                mClientHandler.postDelayed(() -> enableRouteForReleasedRouteController(routeId),
+                        DISABLE_ROUTE_FOR_RELEASED_CONTROLLER_TIMEOUT_MS);
+                sendDescriptor();
+            }
+
+            private void enableRouteForReleasedRouteController(String routeId) {
+                if (mReleasedControllerIds.remove(routeId) == null) {
+                    return;
+                }
+                sendDescriptor();
+            }
+
+            /**
+             * Sends the lastly known provider descriptor to the client.
+             */
+            void sendDescriptor() {
+                MediaRouteProviderDescriptor providerDescriptor =
+                        getService().getMediaRouteProvider().getDescriptor();
+                if (providerDescriptor != null) {
+                    sendMessage(mMessenger, SERVICE_MSG_DESCRIPTOR_CHANGED, 0, 0,
+                            createDescriptorBundle(providerDescriptor), null);
+                }
+            }
+
             public RouteController findControllerByRouteId(String routeId) {
                 return mRouteIdToControllerMap.get(routeId);
             }
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java
index b5dcd5d..0c52eb7 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java
@@ -34,6 +34,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.SystemClock;
 import android.support.v4.media.session.MediaSessionCompat;
 import android.text.TextUtils;
 import android.util.Log;
@@ -581,7 +582,9 @@
      * The {@link #CALLBACK_FLAG_PERFORM_ACTIVE_SCAN} flag should be used when the
      * media route chooser dialog is showing to confirm the presence of available
      * routes that the user may connect to.  This flag may use substantially more
-     * power.
+     * power. Once active scan is requested, it will be effective for 30 seconds and will be
+     * suppressed after the delay. If you need active scan after this duration, you have to add
+     * your callback again with the {@link #CALLBACK_FLAG_PERFORM_ACTIVE_SCAN} flag.
      * </p>
      *
      * <h3>Example</h3>
@@ -677,6 +680,15 @@
             record.mFlags = flags;
             updateNeeded = true;
         }
+        long currentTime = SystemClock.elapsedRealtime();
+        if ((flags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) {
+            // If the flag has active scan, the active scan might be suppressed previously if the
+            // previous change is too long ago. In this case, the discovery request needs to be
+            // updated so that the active scan state can be true again.
+            updateNeeded = true;
+        }
+        record.mTimestamp = currentTime;
+
         if (!record.mSelector.contains(selector)) {
             record.mSelector = new MediaRouteSelector.Builder(record.mSelector)
                     .addSelector(selector)
@@ -2276,6 +2288,7 @@
         public final Callback mCallback;
         public MediaRouteSelector mSelector;
         public int mFlags;
+        public long mTimestamp;
 
         public CallbackRecord(MediaRouter router, Callback callback) {
             mRouter = router;
@@ -2330,6 +2343,14 @@
         private final DisplayManagerCompat mDisplayManager;
         final SystemMediaRouteProvider mSystemProvider;
         private final boolean mLowRam;
+        private MediaRouterActiveScanThrottlingHelper mActiveScanThrottlingHelper =
+                new MediaRouterActiveScanThrottlingHelper(
+                        new Runnable() {
+                        @Override
+                        public void run() {
+                            updateDiscoveryRequest();
+                        }
+                });
 
         private MediaRouterParams mRouterParams;
         private RegisteredMediaRouteProviderWatcher mRegisteredProviderWatcher;
@@ -2650,8 +2671,8 @@
         public void updateDiscoveryRequest() {
             // Combine all of the callback selectors and active scan flags.
             boolean discover = false;
-            boolean activeScan = false;
             MediaRouteSelector.Builder builder = new MediaRouteSelector.Builder();
+            mActiveScanThrottlingHelper.reset();
 
             int callbackCount = 0;
             for (int i = mRouters.size(); --i >= 0; ) {
@@ -2664,8 +2685,12 @@
                     for (int j = 0; j < count; j++) {
                         CallbackRecord callback = router.mCallbackRecords.get(j);
                         builder.addSelector(callback.mSelector);
-                        if ((callback.mFlags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0) {
-                            activeScan = true;
+                        boolean callbackRequestingActiveScan =
+                                (callback.mFlags & CALLBACK_FLAG_PERFORM_ACTIVE_SCAN) != 0;
+                        mActiveScanThrottlingHelper.requestActiveScan(
+                                callbackRequestingActiveScan,
+                                callback.mTimestamp);
+                        if (callbackRequestingActiveScan) {
                             discover = true; // perform active scan implies request discovery
                         }
                         if ((callback.mFlags & CALLBACK_FLAG_REQUEST_DISCOVERY) != 0) {
@@ -2680,6 +2705,10 @@
                 }
             }
 
+            boolean activeScan =
+                    mActiveScanThrottlingHelper
+                    .finalizeActiveScanAndScheduleSuppressActiveScanRunnable();
+
             mCallbackCount = callbackCount;
             MediaRouteSelector selector = discover ? builder.build() : MediaRouteSelector.EMPTY;
 
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouterActiveScanThrottlingHelper.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouterActiveScanThrottlingHelper.java
new file mode 100644
index 0000000..4e05ca5
--- /dev/null
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouterActiveScanThrottlingHelper.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2020 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.mediarouter.media;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+
+/**
+ * Helper class for deciding whether active scan is allowed and when should active scan should be
+ * suppressed.
+ */
+class MediaRouterActiveScanThrottlingHelper {
+    // The constant is package visible for tests can set it to a shorter durationaq.
+    static final long MAX_ACTIVE_SCAN_DURATION_MS = 30000;
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+    private final Runnable mUpdateDiscoveryRequestRunnable;
+    private long mSuppressActiveScanTimeout;
+    private long mCurrentTime;
+    private boolean mActiveScan;
+
+    MediaRouterActiveScanThrottlingHelper(Runnable updateDiscoveryRequestRunnable) {
+        mUpdateDiscoveryRequestRunnable = updateDiscoveryRequestRunnable;
+    }
+
+    /** Resets the helper as if no active scan is requested. */
+    public void reset() {
+        mSuppressActiveScanTimeout = 0;
+        mActiveScan = false;
+        mCurrentTime = SystemClock.elapsedRealtime();
+        mHandler.removeCallbacks(mUpdateDiscoveryRequestRunnable);
+    }
+
+    /** Add an active scan request. */
+    public void requestActiveScan(boolean activeScanAsRequested, long requestTimestamp) {
+        if (!activeScanAsRequested) {
+            // Active scan not requested.
+            return;
+        }
+
+        if (mCurrentTime - requestTimestamp >= MAX_ACTIVE_SCAN_DURATION_MS) {
+            // Active scan should be suppressed.
+            return;
+        }
+
+        mSuppressActiveScanTimeout =
+                Math.max(
+                        mSuppressActiveScanTimeout,
+                        requestTimestamp + MAX_ACTIVE_SCAN_DURATION_MS - mCurrentTime);
+
+        mActiveScan = true;
+    }
+
+    /**
+     * Calculate whether active scan is needed based on all active scan requests since last
+     *  {@link #reset()} and schedule a runnable to suppress active scan if needed.
+     */
+    public boolean finalizeActiveScanAndScheduleSuppressActiveScanRunnable() {
+        if (mActiveScan && mSuppressActiveScanTimeout > 0) {
+            mHandler.postDelayed(mUpdateDiscoveryRequestRunnable, mSuppressActiveScanTimeout);
+        }
+        return mActiveScan;
+    }
+}
diff --git a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/RegisteredMediaRouteProvider.java b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/RegisteredMediaRouteProvider.java
index 1182537..ccd9e0b 100644
--- a/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/RegisteredMediaRouteProvider.java
+++ b/mediarouter/mediarouter/src/main/java/androidx/mediarouter/media/RegisteredMediaRouteProvider.java
@@ -42,6 +42,7 @@
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.DATA_KEY_GROUP_ROUTE_DESCRIPTOR;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.DATA_KEY_TRANSFERABLE_SECTION_TITLE;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_DATA_ERROR;
+import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_CONTROLLER_RELEASED;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_CONTROL_REQUEST_FAILED;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_DESCRIPTOR_CHANGED;
@@ -50,7 +51,6 @@
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_GENERIC_FAILURE;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_GENERIC_SUCCESS;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_REGISTERED;
-import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_MSG_RELEASE_CONTROLLER;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.SERVICE_VERSION_1;
 import static androidx.mediarouter.media.MediaRouteProviderProtocol.isValidRemoteMessenger;
 
@@ -383,12 +383,13 @@
         }
     }
 
-    void onConnectionRequestReleaseController(Connection connection, int controllerId) {
+    void onConnectionControllerReleasedByProvider(Connection connection, int controllerId) {
         if (mActiveConnection == connection) {
             ControllerConnection controller = findControllerById(controllerId);
             if (mControllerCallback != null && controller instanceof RouteController) {
-                mControllerCallback.onRequestReleaseController(((RouteController) controller));
+                mControllerCallback.onControllerReleasedByProvider(((RouteController) controller));
             }
+            onControllerReleased(controller);
         }
     }
 
@@ -850,8 +851,8 @@
             }
         }
 
-        public void onRequestReleaseController(int controllerId) {
-            onConnectionRequestReleaseController(this, controllerId);
+        public void onControllerReleasedByProvider(int controllerId) {
+            onConnectionControllerReleasedByProvider(this, controllerId);
         }
 
         @Override
@@ -1075,8 +1076,8 @@
                     }
                     break;
 
-                case SERVICE_MSG_RELEASE_CONTROLLER:
-                    connection.onRequestReleaseController(arg /* controllerId */);
+                case SERVICE_MSG_CONTROLLER_RELEASED:
+                    connection.onControllerReleasedByProvider(arg /* controllerId */);
                     break;
             }
             return false;
@@ -1084,6 +1085,6 @@
     }
 
     interface ControllerCallback {
-        void onRequestReleaseController(RouteController controller);
+        void onControllerReleasedByProvider(RouteController controller);
     }
 }
diff --git a/navigation/navigation-ui/api/res-current.txt b/navigation/navigation-ui/api/res-current.txt
index e69de29..e65fdbe 100644
--- a/navigation/navigation-ui/api/res-current.txt
+++ b/navigation/navigation-ui/api/res-current.txt
@@ -0,0 +1,8 @@
+anim nav_default_enter_anim
+anim nav_default_exit_anim
+anim nav_default_pop_enter_anim
+anim nav_default_pop_exit_anim
+animator nav_default_enter_anim
+animator nav_default_exit_anim
+animator nav_default_pop_enter_anim
+animator nav_default_pop_exit_anim
diff --git a/navigation/navigation-ui/src/main/res-public/values/public_anim.xml b/navigation/navigation-ui/src/main/res-public/values/public_anim.xml
deleted file mode 100644
index 267d6b7..0000000
--- a/navigation/navigation-ui/src/main/res-public/values/public_anim.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright 2018 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ 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.
-  -->
-
-<!-- Definitions of animations to be exposed as public -->
-<resources>
-    <public type="anim" name="nav_default_enter_anim"/>
-    <public type="anim" name="nav_default_exit_anim"/>
-    <public type="anim" name="nav_default_pop_enter_anim"/>
-    <public type="anim" name="nav_default_pop_exit_anim"/>
-    <public type="animator" name="nav_default_enter_anim"/>
-    <public type="animator" name="nav_default_exit_anim"/>
-    <public type="animator" name="nav_default_pop_enter_anim"/>
-    <public type="animator" name="nav_default_pop_exit_anim"/>
-</resources>
diff --git a/navigation/navigation-ui/src/main/res/values/public.xml b/navigation/navigation-ui/src/main/res/values/public.xml
new file mode 100644
index 0000000..5613d15
--- /dev/null
+++ b/navigation/navigation-ui/src/main/res/values/public.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2020 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.
+  -->
+
+<resources>
+    <public type="animator" name="nav_default_enter_anim"/>
+    <public type="animator" name="nav_default_exit_anim"/>
+    <public type="animator" name="nav_default_pop_enter_anim"/>
+    <public type="animator" name="nav_default_pop_exit_anim"/>
+    <!-- Deprecated. Use nav_default_enter_animator instead.-->
+    <public type="anim" name="nav_default_enter_anim"/>
+    <!-- Deprecated. Use nav_default_exit_animator instead.-->
+    <public type="anim" name="nav_default_exit_anim"/>
+    <!-- Deprecated. Use nav_default_pop_enter_animator instead.-->
+    <public type="anim" name="nav_default_pop_enter_anim"/>
+    <!-- Deprecated. Use nav_default_pop_exit_animator instead.-->
+    <public type="anim" name="nav_default_pop_exit_anim"/>
+</resources>
diff --git a/paging/common/src/main/kotlin/androidx/paging/PageFetcher.kt b/paging/common/src/main/kotlin/androidx/paging/PageFetcher.kt
index f9e946c..afce683 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PageFetcher.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PageFetcher.kt
@@ -62,29 +62,19 @@
             }
             .scan(null) { previousGeneration: PageFetcherSnapshot<Key, Value>?,
                           triggerRemoteRefresh ->
-                val pagingSource = pagingSourceFactory()
-
-                // Ensure pagingSourceFactory produces a new instance of PagingSource.
-                check(pagingSource !== previousGeneration?.pagingSource) {
-                    """
-                    An instance of PagingSource was re-used when Pager expected to create a new
-                    instance. Ensure that the pagingSourceFactory passed to Pager always returns a
-                    new instance of PagingSource.
-                    """.trimIndent()
+                var pagingSource = generateNewPagingSource(previousGeneration?.pagingSource)
+                while (pagingSource.invalid) {
+                    pagingSource = generateNewPagingSource(previousGeneration?.pagingSource)
                 }
 
                 @OptIn(ExperimentalPagingApi::class)
-                val initialKey = previousGeneration?.refreshKeyInfo()
+                val initialKey: Key? = previousGeneration?.refreshKeyInfo()
                     ?.let { pagingSource.getRefreshKey(it) }
                     ?: initialKey
 
-                // Hook up refresh signals from DataSource / PagingSource.
-                pagingSource.registerInvalidatedCallback(::invalidate)
-                previousGeneration?.pagingSource?.unregisterInvalidatedCallback(::invalidate)
-                previousGeneration?.pagingSource?.invalidate() // Note: Invalidate is idempotent.
                 previousGeneration?.close()
 
-                PageFetcherSnapshot(
+                PageFetcherSnapshot<Key, Value>(
                     initialKey = initialKey,
                     pagingSource = pagingSource,
                     config = config,
@@ -111,6 +101,28 @@
         refreshChannel.offer(false)
     }
 
+    private fun generateNewPagingSource(
+        previousPagingSource: PagingSource<Key, Value>?
+    ): PagingSource<Key, Value> {
+        val pagingSource = pagingSourceFactory()
+
+        // Ensure pagingSourceFactory produces a new instance of PagingSource.
+        check(pagingSource !== previousPagingSource) {
+            """
+            An instance of PagingSource was re-used when Pager expected to create a new
+            instance. Ensure that the pagingSourceFactory passed to Pager always returns a
+            new instance of PagingSource.
+            """.trimIndent()
+        }
+
+        // Hook up refresh signals from PagingSource.
+        pagingSource.registerInvalidatedCallback(::invalidate)
+        previousPagingSource?.unregisterInvalidatedCallback(::invalidate)
+        previousPagingSource?.invalidate() // Note: Invalidate is idempotent.
+
+        return pagingSource
+    }
+
     inner class PagerUiReceiver<Key : Any, Value : Any> constructor(
         private val pageFetcherSnapshot: PageFetcherSnapshot<Key, Value>,
         private val retryChannel: SendChannel<Unit>
diff --git a/paging/common/src/test/kotlin/androidx/paging/PageFetcherTest.kt b/paging/common/src/test/kotlin/androidx/paging/PageFetcherTest.kt
index d3e87ce..85855ef 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PageFetcherTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PageFetcherTest.kt
@@ -23,12 +23,14 @@
 import androidx.paging.RemoteMediator.InitializeAction.LAUNCH_INITIAL_REFRESH
 import androidx.paging.RemoteMediator.InitializeAction.SKIP_INITIAL_REFRESH
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.async
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.collectIndexed
+import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.onCompletion
 import kotlinx.coroutines.flow.onStart
 import kotlinx.coroutines.flow.toList
@@ -395,6 +397,41 @@
             assertTrue { job.isCompleted }
         }
     }
+
+    @ExperimentalStdlibApi
+    @Test
+    fun pagingSourceInvalidBeforeCallbackAdded() = testScope.runBlockingTest {
+        var invalidatesFromAdapter = 0
+        var i = 0
+        var pagingSource: TestPagingSource? = null
+        val pager = Pager(PagingConfig(10)) {
+            i++
+            TestPagingSource().also {
+                if (i == 1) {
+                    it.invalidate()
+                }
+
+                advanceUntilIdle()
+                it.registerInvalidatedCallback { invalidatesFromAdapter++ }
+                pagingSource = it
+            }
+        }
+
+        val job = launch {
+            pager.flow.collectLatest { pagingData ->
+                TestPagingDataDiffer<Int>(
+                    testScope.coroutineContext[CoroutineDispatcher.Key]!!
+                ).collectFrom(pagingData)
+            }
+        }
+
+        advanceUntilIdle()
+        pagingSource!!.invalidate()
+        advanceUntilIdle()
+
+        assertEquals(1, invalidatesFromAdapter)
+        job.cancel()
+    }
 }
 
 internal class FetcherState<T : Any>(
diff --git a/paging/guava/api/current.txt b/paging/guava/api/current.txt
index 1fd7af5..52f6cf3 100644
--- a/paging/guava/api/current.txt
+++ b/paging/guava/api/current.txt
@@ -25,10 +25,10 @@
   }
 
   public final class PagingDataFutures {
-    method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Boolean> predicate);
-    method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Iterable<R>> transform);
-    method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<androidx.paging.AdjacentItems<T>,R> generator);
-    method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,R> transform);
+    method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Boolean> predicate, java.util.concurrent.Executor executor);
+    method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Iterable<R>> transform, java.util.concurrent.Executor executor);
+    method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<androidx.paging.AdjacentItems<T>,R> generator, java.util.concurrent.Executor executor);
+    method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,R> transform, java.util.concurrent.Executor executor);
   }
 
 }
diff --git a/paging/guava/api/public_plus_experimental_current.txt b/paging/guava/api/public_plus_experimental_current.txt
index 1fd7af5..52f6cf3 100644
--- a/paging/guava/api/public_plus_experimental_current.txt
+++ b/paging/guava/api/public_plus_experimental_current.txt
@@ -25,10 +25,10 @@
   }
 
   public final class PagingDataFutures {
-    method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Boolean> predicate);
-    method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Iterable<R>> transform);
-    method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<androidx.paging.AdjacentItems<T>,R> generator);
-    method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,R> transform);
+    method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Boolean> predicate, java.util.concurrent.Executor executor);
+    method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Iterable<R>> transform, java.util.concurrent.Executor executor);
+    method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<androidx.paging.AdjacentItems<T>,R> generator, java.util.concurrent.Executor executor);
+    method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,R> transform, java.util.concurrent.Executor executor);
   }
 
 }
diff --git a/paging/guava/api/restricted_current.txt b/paging/guava/api/restricted_current.txt
index 1fd7af5..52f6cf3 100644
--- a/paging/guava/api/restricted_current.txt
+++ b/paging/guava/api/restricted_current.txt
@@ -25,10 +25,10 @@
   }
 
   public final class PagingDataFutures {
-    method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Boolean> predicate);
-    method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Iterable<R>> transform);
-    method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<androidx.paging.AdjacentItems<T>,R> generator);
-    method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,R> transform);
+    method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Boolean> predicate, java.util.concurrent.Executor executor);
+    method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,java.lang.Iterable<R>> transform, java.util.concurrent.Executor executor);
+    method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<androidx.paging.AdjacentItems<T>,R> generator, java.util.concurrent.Executor executor);
+    method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, com.google.common.util.concurrent.AsyncFunction<T,R> transform, java.util.concurrent.Executor executor);
   }
 
 }
diff --git a/paging/guava/src/main/java/androidx/paging/ListenableFuturePagingData.kt b/paging/guava/src/main/java/androidx/paging/ListenableFuturePagingData.kt
index 9b92592..9a0d0bd 100644
--- a/paging/guava/src/main/java/androidx/paging/ListenableFuturePagingData.kt
+++ b/paging/guava/src/main/java/androidx/paging/ListenableFuturePagingData.kt
@@ -20,36 +20,63 @@
 
 import androidx.annotation.CheckResult
 import com.google.common.util.concurrent.AsyncFunction
+import kotlinx.coroutines.asCoroutineDispatcher
 import kotlinx.coroutines.guava.await
+import kotlinx.coroutines.withContext
+import java.util.concurrent.Executor
 
 /**
  * Returns a [PagingData] containing the result of applying the given [transform] to each
  * element, as it is loaded.
+ *
+ * @param transform [AsyncFunction] to transform an item of type [T] to [R].
+ * @param executor [Executor] to run the [AsyncFunction] in.
  */
 @JvmName("map")
 @CheckResult
 fun <T : Any, R : Any> PagingData<T>.mapAsync(
-    transform: AsyncFunction<T, R>
-): PagingData<R> = map { transform.apply(it).await() }
+    transform: AsyncFunction<T, R>,
+    executor: Executor
+): PagingData<R> = map {
+    withContext(executor.asCoroutineDispatcher()) {
+        transform.apply(it).await()
+    }
+}
 
 /**
  * Returns a [PagingData] of all elements returned from applying the given [transform] to each
  * element, as it is loaded.
+ *
+ * @param transform [AsyncFunction] to transform an item of type [T] a list of items of type [R].
+ * @param executor [Executor] to run the [AsyncFunction] in.
  */
 @JvmName("flatMap")
 @CheckResult
 fun <T : Any, R : Any> PagingData<T>.flatMapAsync(
-    transform: AsyncFunction<T, Iterable<R>>
-): PagingData<R> = flatMap { transform.apply(it).await() }
+    transform: AsyncFunction<T, Iterable<R>>,
+    executor: Executor
+): PagingData<R> = flatMap {
+    withContext(executor.asCoroutineDispatcher()) {
+        transform.apply(it).await()
+    }
+}
 
 /**
  * Returns a [PagingData] containing only elements matching the given [predicate].
+ *
+ * @param predicate [AsyncFunction] returning `false` for unmatched items which should be filtered.
+ * @param executor [Executor] to run the [AsyncFunction] in.
  */
 @JvmName("filter")
 @CheckResult
 fun <T : Any> PagingData<T>.filterAsync(
-    predicate: AsyncFunction<T, Boolean>
-): PagingData<T> = filter { predicate.apply(it).await() }
+    predicate: AsyncFunction<T, Boolean>,
+    executor: Executor
+): PagingData<T> = filter {
+    withContext(executor.asCoroutineDispatcher()) {
+        predicate.apply(it).await()
+    }
+}
 
 /**
  * Returns a [PagingData] containing each original element, with an optional separator generated
@@ -58,15 +85,22 @@
  * Note that this transform is applied asynchronously, as pages are loaded. Potential separators
  * between pages are only computed once both pages are loaded.
  *
+ * @param generator [AsyncFunction] used to generate separator between two [AdjacentItems] or the
+ * header or footer if either [AdjacentItems.before] or [AdjacentItems.after] is `null`.
+ * @param executor [Executor] to run the [AsyncFunction] in.
+ *
  * @sample androidx.paging.samples.insertSeparatorsFutureSample
  * @sample androidx.paging.samples.insertSeparatorsUiModelFutureSample
  */
 @JvmName("insertSeparators")
 @CheckResult
 fun <T : R, R : Any> PagingData<T>.insertSeparatorsAsync(
-    generator: AsyncFunction<AdjacentItems<T>, R?>
+    generator: AsyncFunction<AdjacentItems<T>, R?>,
+    executor: Executor
 ): PagingData<R> = insertSeparators { before, after ->
-    generator.apply(AdjacentItems(before, after)).await()
+    withContext(executor.asCoroutineDispatcher()) {
+        generator.apply(AdjacentItems(before, after)).await()
+    }
 }
 
 /**
diff --git a/paging/guava/src/test/java/androidx/paging/ListenableFuturePagingDataTest.kt b/paging/guava/src/test/java/androidx/paging/ListenableFuturePagingDataTest.kt
index 497c50f..e7557ab 100644
--- a/paging/guava/src/test/java/androidx/paging/ListenableFuturePagingDataTest.kt
+++ b/paging/guava/src/test/java/androidx/paging/ListenableFuturePagingDataTest.kt
@@ -19,6 +19,7 @@
 import com.google.common.util.concurrent.AsyncFunction
 import com.google.common.util.concurrent.Futures
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.asExecutor
 import kotlinx.coroutines.test.TestCoroutineDispatcher
 import kotlinx.coroutines.test.runBlockingTest
 import org.junit.Assert.assertEquals
@@ -38,7 +39,7 @@
     fun map() = testDispatcher.runBlockingTest {
         val transformed = original.mapAsync(AsyncFunction<String, String> {
             Futures.immediateFuture(it + it)
-        })
+        }, testDispatcher.asExecutor())
         differ.collectFrom(transformed)
         assertEquals(listOf("aa", "bb", "cc"), differ.currentList)
     }
@@ -47,7 +48,7 @@
     fun flatMap() = testDispatcher.runBlockingTest {
         val transformed = original.flatMapAsync(AsyncFunction<String, Iterable<String>> {
             Futures.immediateFuture(listOf(it!!, it))
-        })
+        }, testDispatcher.asExecutor())
         differ.collectFrom(transformed)
         assertEquals(listOf("a", "a", "b", "b", "c", "c"), differ.currentList)
     }
@@ -56,7 +57,7 @@
     fun filter() = testDispatcher.runBlockingTest {
         val filtered = original.filterAsync(AsyncFunction {
             Futures.immediateFuture(it != "b")
-        })
+        }, testDispatcher.asExecutor())
         differ.collectFrom(filtered)
         assertEquals(listOf("a", "c"), differ.currentList)
     }
@@ -67,7 +68,8 @@
             AsyncFunction<AdjacentItems<String>, String?> {
                 val (before, after) = it!!
                 Futures.immediateFuture(if (before == null || after == null) null else "|")
-            }
+            },
+            testDispatcher.asExecutor()
         )
         differ.collectFrom(separated)
         assertEquals(listOf("a", "|", "b", "|", "c"), differ.currentList)
diff --git a/paging/integration-tests/testapp/build.gradle b/paging/integration-tests/testapp/build.gradle
index 86a448d..5e16287 100644
--- a/paging/integration-tests/testapp/build.gradle
+++ b/paging/integration-tests/testapp/build.gradle
@@ -29,8 +29,8 @@
 
 dependencies {
     implementation("androidx.arch.core:core-runtime:2.1.0")
-    implementation("androidx.room:room-ktx:2.2.5")
-    implementation("androidx.room:room-rxjava2:2.2.5")
+    implementation(projectOrArtifact(":room:room-ktx"))
+    implementation(projectOrArtifact(":room:room-rxjava2"))
 
     implementation(project(":paging:paging-common-ktx"))
     implementation(project(":paging:paging-runtime"))
diff --git a/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsSample.kt b/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsSample.kt
index a9449be..27cfb29 100644
--- a/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsSample.kt
+++ b/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsSample.kt
@@ -114,6 +114,6 @@
                     null
                 }
             }, executor)
-        })
+        }, executor)
     }
 }
diff --git a/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsUiModelSample.kt b/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsUiModelSample.kt
index 4e07f64..0f90965 100644
--- a/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsUiModelSample.kt
+++ b/paging/samples/src/main/java/androidx/paging/samples/InsertSeparatorsUiModelSample.kt
@@ -146,6 +146,6 @@
                         null
                     }
                 }, executor)
-            })
+            }, executor)
     }
 }
diff --git a/preference/preference/res/values-bs/strings.xml b/preference/preference/res/values-bs/strings.xml
index 9c72782..f03be77 100644
--- a/preference/preference/res/values-bs/strings.xml
+++ b/preference/preference/res/values-bs/strings.xml
@@ -6,6 +6,6 @@
     <string name="expand_button_title" msgid="2427401033573778270">"Napredno"</string>
     <string name="summary_collapsed_preference_list" msgid="9167775378838880170">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
     <string name="copy" msgid="6083905920877235314">"Kopiraj"</string>
-    <string name="preference_copied" msgid="6685851473431805375">"\"<xliff:g id="SUMMARY">%1$s</xliff:g>\" kopirano u međuspremnik."</string>
+    <string name="preference_copied" msgid="6685851473431805375">"\"<xliff:g id="SUMMARY">%1$s</xliff:g>\" kopirano u međumemoriju."</string>
     <string name="not_set" msgid="6573031135582639649">"Nije postavljeno"</string>
 </resources>
diff --git a/preference/preference/res/values-es-rUS/strings.xml b/preference/preference/res/values-es-rUS/strings.xml
index 1285185..7f45355 100644
--- a/preference/preference/res/values-es-rUS/strings.xml
+++ b/preference/preference/res/values-es-rUS/strings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="v7_preference_on" msgid="89551595707643515">"ACTIVADA"</string>
+    <string name="v7_preference_on" msgid="89551595707643515">"ACTIVADO"</string>
     <string name="v7_preference_off" msgid="3140233346420563315">"DESACTIVADA"</string>
     <string name="expand_button_title" msgid="2427401033573778270">"Opciones avanzadas"</string>
     <string name="summary_collapsed_preference_list" msgid="9167775378838880170">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
diff --git a/preference/preference/res/values-lt/strings.xml b/preference/preference/res/values-lt/strings.xml
index 682dd1c..cded560 100644
--- a/preference/preference/res/values-lt/strings.xml
+++ b/preference/preference/res/values-lt/strings.xml
@@ -3,7 +3,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="v7_preference_on" msgid="89551595707643515">"ĮJUNGTA"</string>
     <string name="v7_preference_off" msgid="3140233346420563315">"IŠJUNGTA"</string>
-    <string name="expand_button_title" msgid="2427401033573778270">"Išplėstinė"</string>
+    <string name="expand_button_title" msgid="2427401033573778270">"Išplėstiniai"</string>
     <string name="summary_collapsed_preference_list" msgid="9167775378838880170">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
     <string name="copy" msgid="6083905920877235314">"Kopijuoti"</string>
     <string name="preference_copied" msgid="6685851473431805375">"Suvestinė „<xliff:g id="SUMMARY">%1$s</xliff:g>“ nukopijuota į iškarpinę."</string>
diff --git a/room/common/api/current.txt b/room/common/api/current.txt
index 6fdb17f..3e5fd91 100644
--- a/room/common/api/current.txt
+++ b/room/common/api/current.txt
@@ -60,7 +60,7 @@
     method public abstract String tableName() default "";
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ForeignKey {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({}) public @interface ForeignKey {
     method public abstract String[] childColumns();
     method public abstract boolean deferred() default false;
     method public abstract Class<?> entity();
@@ -142,6 +142,9 @@
     method public abstract boolean autoGenerate() default false;
   }
 
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE) public @interface ProvidedTypeConverter {
+  }
+
   @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface Query {
     method public abstract String value();
   }
diff --git a/room/common/api/public_plus_experimental_current.txt b/room/common/api/public_plus_experimental_current.txt
index 6fdb17f..3e5fd91 100644
--- a/room/common/api/public_plus_experimental_current.txt
+++ b/room/common/api/public_plus_experimental_current.txt
@@ -60,7 +60,7 @@
     method public abstract String tableName() default "";
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ForeignKey {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({}) public @interface ForeignKey {
     method public abstract String[] childColumns();
     method public abstract boolean deferred() default false;
     method public abstract Class<?> entity();
@@ -142,6 +142,9 @@
     method public abstract boolean autoGenerate() default false;
   }
 
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE) public @interface ProvidedTypeConverter {
+  }
+
   @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface Query {
     method public abstract String value();
   }
diff --git a/room/common/api/restricted_current.txt b/room/common/api/restricted_current.txt
index a51a804..94d42bd 100644
--- a/room/common/api/restricted_current.txt
+++ b/room/common/api/restricted_current.txt
@@ -60,7 +60,7 @@
     method public abstract String tableName() default "";
   }
 
-  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public @interface ForeignKey {
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target({}) public @interface ForeignKey {
     method public abstract String[] childColumns();
     method public abstract boolean deferred() default false;
     method public abstract Class<?> entity();
@@ -142,6 +142,9 @@
     method public abstract boolean autoGenerate() default false;
   }
 
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.TYPE) public @interface ProvidedTypeConverter {
+  }
+
   @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD) public @interface Query {
     method public abstract String value();
   }
diff --git a/room/common/src/main/java/androidx/room/ForeignKey.java b/room/common/src/main/java/androidx/room/ForeignKey.java
index 0ee68ea..d3c7f5e 100644
--- a/room/common/src/main/java/androidx/room/ForeignKey.java
+++ b/room/common/src/main/java/androidx/room/ForeignKey.java
@@ -19,6 +19,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
  * Declares a foreign key on another {@link Entity}.
@@ -45,6 +46,7 @@
  * Please refer to the SQLite <a href="https://sqlite.org/foreignkeys.html">foreign keys</a>
  * documentation for details.
  */
+@Target({})
 @Retention(RetentionPolicy.CLASS)
 public @interface ForeignKey {
     /**
diff --git a/room/common/src/main/java/androidx/room/ProvidedTypeConverter.java b/room/common/src/main/java/androidx/room/ProvidedTypeConverter.java
new file mode 100644
index 0000000..fa83bdc
--- /dev/null
+++ b/room/common/src/main/java/androidx/room/ProvidedTypeConverter.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2020 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.room;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a class as a type converter that will be provided to Room at runtime.
+ * If Room uses the annotated type converter class, it will verify that it is provided in the
+ * builder and if not, will throw an exception.
+ * An instance of a class annotated with this annotation has to be provided to Room using
+ * {@code Room.databaseBuilder.addTypeConverter(Object)}
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+public @interface ProvidedTypeConverter {
+}
diff --git a/room/common/src/main/java/androidx/room/TypeConverters.java b/room/common/src/main/java/androidx/room/TypeConverters.java
index e68525b..e4c99dd 100644
--- a/room/common/src/main/java/androidx/room/TypeConverters.java
+++ b/room/common/src/main/java/androidx/room/TypeConverters.java
@@ -25,6 +25,11 @@
  * Specifies additional type converters that Room can use. The TypeConverter is added to the scope
  * of the element so if you put it on a class / interface, all methods / fields in that class will
  * be able to use the converters.
+ *
+ * <p>
+ * TypeConverters can only be used to convert columns / fields, hence cannot be used by a method
+ * with a row return value such as DAO methods that query rows.
+ *
  * <ul>
  * <li>If you put it on a {@link Database}, all Daos and Entities in that database will be able to
  * use it.
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSDeclarationExt.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSDeclarationExt.kt
new file mode 100644
index 0000000..77c3509
--- /dev/null
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSDeclarationExt.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020 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.room.compiler.processing.ksp
+
+import org.jetbrains.kotlin.ksp.symbol.KSClassDeclaration
+import org.jetbrains.kotlin.ksp.symbol.KSDeclaration
+
+/**
+ * Finds the class that contains this declaration and throws [IllegalStateException] if it cannot
+ * be found.
+ * @see [findEnclosingAncestorClassDeclaration]
+ */
+internal fun KSDeclaration.requireEnclosingTypeElement(env: KspProcessingEnv): KspTypeElement {
+    return checkNotNull(findEnclosingTypeElement(env)) {
+        "Cannot find required enclosing type for $this"
+    }
+}
+
+/**
+ * Find the class that contains this declaration.
+ *
+ * Node that this is not necessarily the parent declaration. e.g. when a property is declared in
+ * a constructor, its containing type is actual two levels up.
+ */
+internal fun KSDeclaration.findEnclosingTypeElement(env: KspProcessingEnv): KspTypeElement? {
+    return findEnclosingAncestorClassDeclaration()?.let {
+        env.wrapClassDeclaration(it)
+    }
+}
+
+internal fun KSDeclaration.findEnclosingAncestorClassDeclaration(): KSClassDeclaration? {
+    var parent = parentDeclaration
+    while (parent != null && parent !is KSClassDeclaration) {
+        parent = parent.parentDeclaration
+    }
+    return parent as? KSClassDeclaration
+}
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSPropertyDeclarationExt.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSPropertyDeclarationExt.kt
new file mode 100644
index 0000000..15dfd80
--- /dev/null
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSPropertyDeclarationExt.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 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.room.compiler.processing.ksp
+
+import org.jetbrains.kotlin.ksp.getAllSuperTypes
+import org.jetbrains.kotlin.ksp.symbol.KSClassDeclaration
+import org.jetbrains.kotlin.ksp.symbol.KSName
+import org.jetbrains.kotlin.ksp.symbol.KSPropertyDeclaration
+import org.jetbrains.kotlin.ksp.symbol.KSType
+import org.jetbrains.kotlin.ksp.symbol.KSTypeArgument
+import org.jetbrains.kotlin.ksp.symbol.KSTypeParameter
+
+/**
+ * Returns the type of a property as if it is member of the given [ksType].
+ *
+ * This is a temporary / inefficient implementation until KSP provides the API. It also does not
+ * handle inner classes properly.
+ * TODO: remove once https://github.com/android/kotlin/issues/26 is implemented
+ */
+internal fun KSPropertyDeclaration.typeAsMemberOf(ksType: KSType): KSType {
+    val myType: KSType = checkNotNull(type?.requireType()) {
+        "Cannot find type of Kotlin property: $this"
+    }
+    val parent = checkNotNull(findEnclosingAncestorClassDeclaration()) {
+        "Cannot find containing class for property. $this"
+    }
+    // TODO traverse grandparents if parent is an inner class as TypeArguments might be declared
+    //  there as well.
+    val matchingParentType: KSType = (ksType.declaration as? KSClassDeclaration)
+        ?.getAllSuperTypes()
+        ?.firstOrNull {
+            it.starProjection().declaration == parentDeclaration
+        } ?: return myType
+    // create a map of replacements.
+    val replacements = parent.typeParameters.mapIndexed { index, ksTypeParameter ->
+        ksTypeParameter.name to matchingParentType.arguments.getOrNull(index)
+    }.toMap()
+    return myType.replaceFromMap(replacements)
+}
+
+private fun KSTypeArgument.replaceFromMap(arguments: Map<KSName, KSTypeArgument?>): KSTypeArgument {
+    val myTypeDeclaration = type?.resolve()?.declaration
+    if (myTypeDeclaration is KSTypeParameter) {
+        return arguments[myTypeDeclaration.name] ?: this
+    }
+    return this
+}
+
+private fun KSType.replaceFromMap(arguments: Map<KSName, KSTypeArgument?>): KSType {
+    val myDeclaration = this.declaration
+    if (myDeclaration is KSTypeParameter) {
+        return arguments[myDeclaration.name]?.type?.resolve() ?: this
+    }
+    if (this.arguments.isEmpty()) {
+        return this
+    }
+    return replace(this.arguments.map {
+        it.replaceFromMap(arguments)
+    })
+}
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeExt.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeExt.kt
index f0d47c7..7671b04 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeExt.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KSTypeExt.kt
@@ -19,16 +19,15 @@
 import com.squareup.javapoet.ClassName
 import com.squareup.javapoet.ParameterizedTypeName
 import com.squareup.javapoet.TypeName
-import org.jetbrains.kotlin.ksp.symbol.KSClassifierReference
 import org.jetbrains.kotlin.ksp.symbol.KSDeclaration
-import org.jetbrains.kotlin.ksp.symbol.KSName
 import org.jetbrains.kotlin.ksp.symbol.KSType
+import org.jetbrains.kotlin.ksp.symbol.KSTypeArgument
 import org.jetbrains.kotlin.ksp.symbol.KSTypeReference
 
-internal val ERROR_PACKAGE_NAME = "androidx.room.compiler.processing.kotlin.error"
+internal const val ERROR_PACKAGE_NAME = "androidx.room.compiler.processing.kotlin.error"
 
 // catch-all type name when we cannot resolve to anything.
-internal val UNDEFINED = ClassName.get(ERROR_PACKAGE_NAME, "Undefined")
+internal val ERROR_TYPE_NAME = ClassName.get(ERROR_PACKAGE_NAME, "CannotResolve")
 
 /**
  * Turns a KSTypeReference into a TypeName
@@ -39,34 +38,19 @@
  */
 internal fun KSTypeReference?.typeName(): TypeName {
     return if (this == null) {
-        UNDEFINED
+        ERROR_TYPE_NAME
     } else {
-        resolve()?.typeName() ?: fallbackClassName()
+        requireType().typeName()
     }
 }
 
-private fun KSTypeReference.fallbackClassName(): ClassName {
-    return (element as? KSClassifierReference)?.let {
-        ClassName.bestGuess(it.referencedName())
-    } ?: UNDEFINED
-}
-
-private fun KSName.typeName(): ClassName? {
-    if (asString().isBlank()) {
-        // fallback to reference
-        return null
-    }
-    // TODO KSP currently do not model package names separate from the simple names.
-    //  see: https://github.com/android/kotlin/issues/23
-    val shortNames = getShortName().split(".")
-    return ClassName.get(getQualifier(), shortNames.first(), *(shortNames.drop(1).toTypedArray()))
-}
-
-internal fun KSDeclaration.typeName(): ClassName? {
-    // if there is no qualified name, it is an error for room
-    val qualified = qualifiedName?.asString() ?: return null
+internal fun KSDeclaration.typeName(): ClassName {
+    // if there is no qualified name, it is a resolution error so just return shared instance
+    // KSP may improve that later and if not, we can improve it in Room
+    // TODO: https://issuetracker.google.com/issues/168639183
+    val qualified = qualifiedName?.asString() ?: return ERROR_TYPE_NAME
     // get the package name first, it might throw for invalid types, hence we use safeGetPackageName
-    val pkg = safeGetPackageName() ?: return null
+    val pkg = getNormalizedPackageName()
     // using qualified name and pkg, figure out the short names.
     val shortNames = if (pkg == "") {
         qualified
@@ -76,12 +60,12 @@
     return ClassName.get(pkg, shortNames.first(), *(shortNames.drop(1).toTypedArray()))
 }
 
-internal fun KSType.typeName(): TypeName? {
+internal fun KSType.typeName(): TypeName {
     return if (this.arguments.isNotEmpty()) {
         val args: Array<TypeName> = this.arguments.map {
             it.type.typeName()
         }.toTypedArray()
-        val className = declaration.typeName() ?: return null
+        val className = declaration.typeName()
         ParameterizedTypeName.get(
             className,
             *args
@@ -92,26 +76,26 @@
 }
 
 /**
- * KSDeclaration.packageName might throw for error types.
- * https://github.com/android/kotlin/issues/121
+ * Root package comes as <root> instead of "" so we work around it here.
  */
-internal fun KSDeclaration.safeGetPackageName(): String? {
-    return try {
-        packageName.asString().let {
-            if (it == "<root>") {
-                ""
-            } else {
-                it
-            }
+internal fun KSDeclaration.getNormalizedPackageName(): String {
+    return packageName.asString().let {
+        if (it == "<root>") {
+            ""
+        } else {
+            it
         }
-    } catch (t: Throwable) {
-        null
     }
 }
 
-// TODO remove after https://github.com/android/kotlin/issues/123
-internal fun KSType?.isAssignableFromWithErrorWorkaround(other: KSType?): Boolean {
-    if (other == null || this == null) return false
-    if (isError || other.isError) return false
-    return isAssignableFrom(other)
+internal fun KSTypeReference.requireType(): KSType {
+    return checkNotNull(resolve()) {
+        "Resolve in type reference should not have returned null, please file a bug. $this"
+    }
 }
+
+internal fun KSTypeArgument.requireType(): KSType {
+    return checkNotNull(type?.requireType()) {
+        "KSTypeArgument.type should not have been null, please file a bug. $this"
+    }
+}
\ No newline at end of file
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspFieldElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspFieldElement.kt
new file mode 100644
index 0000000..d2634bb
--- /dev/null
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspFieldElement.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2020 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.room.compiler.processing.ksp
+
+import androidx.room.compiler.processing.XDeclaredType
+import androidx.room.compiler.processing.XFieldElement
+import androidx.room.compiler.processing.XHasModifiers
+import androidx.room.compiler.processing.XType
+import androidx.room.compiler.processing.XTypeElement
+import org.jetbrains.kotlin.ksp.symbol.KSPropertyDeclaration
+
+internal class KspFieldElement(
+    env: KspProcessingEnv,
+    override val declaration: KSPropertyDeclaration,
+    val containing: KspTypeElement
+) : KspElement(env, declaration), XFieldElement, XHasModifiers by KspHasModifiers(declaration) {
+
+    override val equalityItems: Array<out Any?> by lazy {
+        arrayOf(declaration, containing)
+    }
+
+    override val enclosingTypeElement: XTypeElement by lazy {
+        declaration.requireEnclosingTypeElement(env)
+    }
+
+    override val name: String by lazy {
+        declaration.simpleName.asString()
+    }
+
+    override val type: XType by lazy {
+        env.wrap(declaration.typeAsMemberOf(containing.type.ksType))
+    }
+
+    override fun asMemberOf(other: XDeclaredType): XType {
+        if (containing.type.isSameType(other)) {
+            return type
+        }
+        check(other is KspType)
+        val asMember = declaration.typeAsMemberOf(other.ksType)
+        return env.wrap(asMember)
+    }
+}
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt
index bce4dd0..9c2bcb9 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspProcessingEnv.kt
@@ -82,7 +82,7 @@
     fun wrap(ksType: KSType): KspType {
         return KspType(
             env = this,
-            resolved = ksType)
+            ksType = ksType)
     }
 
     fun wrap(ksTypeReference: KSTypeReference): KspType {
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspRawType.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspRawType.kt
index 9f5fa90..7dc0ba6 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspRawType.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspRawType.kt
@@ -22,20 +22,17 @@
 import org.jetbrains.kotlin.ksp.symbol.KSType
 
 internal class KspRawType private constructor(
-    private val ksType: KSType?,
+    private val ksType: KSType,
     override val typeName: TypeName
 ) : XRawType {
     constructor(original: KspType) : this(
-        ksType = original.ksType?.starProjection(),
+        ksType = original.ksType.starProjection(),
         typeName = original.typeName.rawTypeName()
     )
 
     override fun isAssignableFrom(other: XRawType): Boolean {
         check(other is KspRawType)
-        return when {
-            other.ksType == null || ksType == null -> this == other
-            else -> ksType.isAssignableFrom(other.ksType)
-        }
+        return ksType.isAssignableFrom(other.ksType)
     }
 
     override fun equals(other: Any?): Boolean {
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
index 995fd0e..c83c021 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
@@ -36,72 +36,66 @@
  * We don't necessarily have a [KSTypeReference] (e.g. if we are getting it from an element).
  * Similarly, we may not be able to get a [KSType] (e.g. if it resolves to error).
  */
-internal class KspType private constructor(
+internal class KspType(
     private val env: KspProcessingEnv,
-    private val ksTypeReference: KSTypeReference?,
-    resolved: KSType?
+    val ksType: KSType
 ) : XDeclaredType, XEquality {
     constructor(env: KspProcessingEnv, ksTypeReference: KSTypeReference) : this(
         env = env,
-        ksTypeReference = ksTypeReference,
-        resolved = null
+        ksType = ksTypeReference.requireType()
     )
 
-    constructor(env: KspProcessingEnv, resolved: KSType) : this(
-        env = env,
-        ksTypeReference = null,
-        resolved = resolved
-    )
-
-    internal val ksType by lazy {
-        resolved ?: ksTypeReference?.resolve()
-    }
     override val rawType by lazy {
         KspRawType(this)
     }
+
     override val typeArguments: List<XType> by lazy {
-        // prioritize type reference if it exists as it will have actual types user picked.
-        val args = ksTypeReference?.element?.typeArguments
-            ?: resolved?.arguments
-            ?: emptyList()
-        args.map {
-            // TODO what if it.type is null?
+        ksType.arguments.map {
             env.wrap(it.type!!)
         }
     }
     override val typeName: TypeName by lazy {
-        ksType?.typeName() ?: ksTypeReference?.typeName() ?: UNDEFINED
+        ksType.typeName()
     }
+
     override val nullability by lazy {
-        when (ksType?.nullability) {
+        when (ksType.nullability) {
             Nullability.NULLABLE -> XNullability.NULLABLE
             Nullability.NOT_NULL -> XNullability.NONNULL
             else -> XNullability.UNKNOWN
         }
     }
 
+    private val _typeElement by lazy {
+        check(ksType.declaration is KSClassDeclaration) { """
+            Unexpected case where ksType's declaration is not a KSClassDeclaration.
+            Please file a bug.
+        """.trimIndent()
+        }
+        env.wrapClassDeclaration(ksType.declaration as KSClassDeclaration)
+    }
+
     override fun asTypeElement(): XTypeElement {
-        TODO("elements are not implemented yet")
+        return _typeElement
     }
 
     override fun isAssignableFrom(other: XType): Boolean {
         check(other is KspType)
-        return ksType.isAssignableFromWithErrorWorkaround(other.ksType)
+        return ksType.isAssignableFrom(other.ksType)
     }
 
     override fun isError(): Boolean {
-        return ksType == null || ksType!!.isError
+        return ksType.isError
     }
 
     override fun defaultValue(): String {
-        val type = ksType ?: return "null"
         // NOTE: this does not match the java implementation though it is probably more correct for
         // kotlin.
-        if (type.nullability == Nullability.NULLABLE) {
+        if (ksType.nullability == Nullability.NULLABLE) {
             return "null"
         }
         val builtIns = env.resolver.builtIns
-        return when (type) {
+        return when (ksType) {
             builtIns.booleanType -> "false"
             builtIns.byteType, builtIns.shortType, builtIns.intType, builtIns.longType, builtIns
                 .charType -> "0"
@@ -116,23 +110,25 @@
     }
 
     override fun isInt(): Boolean {
-        return env.commonTypes.nullableInt.isAssignableFromWithErrorWorkaround(ksType)
+        return env.commonTypes.nullableInt.isAssignableFrom(ksType)
     }
 
     override fun isLong(): Boolean {
-        return env.commonTypes.nullableLong.isAssignableFromWithErrorWorkaround(ksType)
+        return env.commonTypes.nullableLong.isAssignableFrom(ksType)
     }
 
     override fun isByte(): Boolean {
-        return env.commonTypes.nullableByte.isAssignableFromWithErrorWorkaround(ksType)
+        return env.commonTypes.nullableByte.isAssignableFrom(ksType)
     }
 
     override fun isNone(): Boolean {
-        return ksType == null
+        // even void is converted to Unit so we don't have none type in KSP
+        // see: KspTypeTest.noneType
+        return false
     }
 
     override fun isType(): Boolean {
-        return ksType != null && ksType!!.declaration is KSClassDeclaration
+        return ksType.declaration is KSClassDeclaration
     }
 
     override fun isTypeOf(other: KClass<*>): Boolean {
@@ -144,7 +140,7 @@
         check(other is KspType)
         // NOTE: this is inconsistent with java where nullability is ignored.
         // it is intentional but might be reversed if it happens to break use cases.
-        return ksType != null && ksType == other.ksType
+        return ksType == other.ksType
     }
 
     override fun extendsBound(): XType? {
@@ -167,6 +163,6 @@
     }
 
     override fun toString(): String {
-        return ksType?.toString() ?: ksTypeReference?.toString() ?: super.toString()
+        return ksType.toString()
     }
 }
diff --git a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
index 1300ed6..6b74520 100644
--- a/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
+++ b/room/compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspTypeElement.kt
@@ -17,13 +17,14 @@
 package androidx.room.compiler.processing.ksp
 
 import androidx.room.compiler.processing.XConstructorElement
-import androidx.room.compiler.processing.XDeclaredType
 import androidx.room.compiler.processing.XFieldElement
 import androidx.room.compiler.processing.XHasModifiers
 import androidx.room.compiler.processing.XMethodElement
 import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.XTypeElement
 import com.squareup.javapoet.ClassName
+import org.jetbrains.kotlin.ksp.getAllSuperTypes
+import org.jetbrains.kotlin.ksp.getDeclaredProperties
 import org.jetbrains.kotlin.ksp.isOpen
 import org.jetbrains.kotlin.ksp.symbol.ClassKind
 import org.jetbrains.kotlin.ksp.symbol.KSClassDeclaration
@@ -38,16 +39,11 @@
     }
 
     override val packageName: String by lazy {
-        declaration.safeGetPackageName() ?: ERROR_PACKAGE_NAME
+        declaration.getNormalizedPackageName()
     }
 
     override val enclosingTypeElement: XTypeElement? by lazy {
-        val parent = declaration.parentDeclaration
-        if (parent is KSClassDeclaration) {
-            env.wrapClassDeclaration(parent)
-        } else {
-            null
-        }
+        declaration.findEnclosingTypeElement(env)
     }
 
     override val equalityItems: Array<out Any?> by lazy {
@@ -55,15 +51,15 @@
     }
 
     override val qualifiedName: String by lazy {
-        val pkgName = declaration.safeGetPackageName()
-        if (pkgName == null || pkgName.isBlank()) {
+        val pkgName = declaration.getNormalizedPackageName()
+        if (pkgName.isBlank()) {
             declaration.simpleName.asString()
         } else {
             "$pkgName.${declaration.simpleName.asString()}"
         }
     }
 
-    override val type: XDeclaredType by lazy {
+    override val type: KspType by lazy {
         env.wrap(declaration.asStarProjectedType())
     }
 
@@ -77,7 +73,35 @@
     }
 
     override val className: ClassName by lazy {
-        declaration.typeName() ?: ClassName.get(packageName, name)
+        declaration.typeName()
+    }
+
+    private val _declaredFieldsIncludingSupers by lazy {
+        // Read all properties from all supers and select the ones that are not overridden.
+        // TODO: remove once it is implemented in KSP
+        // https://github.com/android/kotlin/issues/133
+        val selection = declaration
+            .getDeclaredProperties()
+            .associateByTo(mutableMapOf()) {
+            it.simpleName
+        }
+        declaration.getAllSuperTypes().map {
+            it.declaration
+        }.filterIsInstance(KSClassDeclaration::class.java)
+            .flatMap {
+                it.getDeclaredProperties()
+            }.forEach {
+                if (!selection.containsKey(it.simpleName)) {
+                    selection[it.simpleName] = it
+                }
+            }
+        selection.values.map {
+            KspFieldElement(
+                env = env,
+                declaration = it,
+                containing = this
+            )
+        }
     }
 
     override fun isInterface(): Boolean {
@@ -94,7 +118,7 @@
     }
 
     override fun getAllFieldsIncludingPrivateSupers(): List<XFieldElement> {
-        TODO("Not yet implemented")
+        return _declaredFieldsIncludingSupers
     }
 
     override fun findPrimaryConstructor(): XConstructorElement? {
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KSProertyDeclarationExtTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KSProertyDeclarationExtTest.kt
new file mode 100644
index 0000000..287c7b7
--- /dev/null
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KSProertyDeclarationExtTest.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2020 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.room.compiler.processing.ksp
+
+import androidx.room.compiler.processing.util.KotlinTypeNames.INT_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.LIST_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.MAP_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.PAIR_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.STRING_CLASS_NAME
+import androidx.room.compiler.processing.util.Source
+import androidx.room.compiler.processing.util.TestInvocation
+import androidx.room.compiler.processing.util.runKspTest
+import com.google.common.truth.Truth.assertThat
+import com.squareup.javapoet.ParameterizedTypeName
+import org.jetbrains.kotlin.ksp.getDeclaredProperties
+import org.jetbrains.kotlin.ksp.symbol.KSClassDeclaration
+import org.jetbrains.kotlin.ksp.symbol.KSPropertyDeclaration
+import org.junit.Test
+
+class KSProertyDeclarationExtTest {
+    @Test
+    fun asMemberOfInheritance() {
+        val src = Source.kotlin(
+            "Foo.kt", """
+            open class BaseClass<T, R>(val genericProp : T) {
+                val listOfGeneric : List<T> = TODO()
+                val mapOfStringToGeneric2 : Map<String, R> = TODO()
+                val pairOfGenerics : Pair<T, R> = TODO()
+            }
+            class SubClass(x : Int) : BaseClass<Int, List<String>>(x) {
+                val subClassProp : String = "abc"
+            }
+        """.trimIndent()
+        )
+
+        runKspTest(sources = listOf(src), succeed = true) { invocation ->
+            val base = invocation.requireClass("BaseClass")
+            val sub = invocation.requireClass("SubClass").asStarProjectedType()
+            base.requireProperty("genericProp").let { prop ->
+                assertThat(prop.typeAsMemberOf(sub).typeName()).isEqualTo(INT_CLASS_NAME)
+            }
+            base.requireProperty("listOfGeneric").let { prop ->
+                assertThat(prop.typeAsMemberOf(sub).typeName())
+                    .isEqualTo(ParameterizedTypeName.get(LIST_CLASS_NAME, INT_CLASS_NAME))
+            }
+
+            val listOfStringsTypeName =
+                ParameterizedTypeName.get(LIST_CLASS_NAME, STRING_CLASS_NAME)
+            base.requireProperty("mapOfStringToGeneric2").let { prop ->
+                assertThat(prop.typeAsMemberOf(sub).typeName())
+                    .isEqualTo(
+                        ParameterizedTypeName.get(
+                            MAP_CLASS_NAME, STRING_CLASS_NAME, listOfStringsTypeName
+                        )
+                    )
+            }
+
+            base.requireProperty("pairOfGenerics").let { prop ->
+                assertThat(prop.typeAsMemberOf(sub).typeName())
+                    .isEqualTo(
+                        ParameterizedTypeName.get(
+                            PAIR_CLASS_NAME, INT_CLASS_NAME, listOfStringsTypeName
+                        )
+                    )
+            }
+        }
+    }
+
+    private fun TestInvocation.requireClass(name: String): KSClassDeclaration {
+        val resolver = (processingEnv as KspProcessingEnv).resolver
+        return resolver.requireClass(name)
+    }
+
+    private fun KSClassDeclaration.requireProperty(name: String): KSPropertyDeclaration {
+        return this.getDeclaredProperties().first {
+            it.simpleName.asString() == name
+        }
+    }
+}
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KSTypeExtTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KSTypeExtTest.kt
index 45d3f67..60d9d6b 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KSTypeExtTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KSTypeExtTest.kt
@@ -119,16 +119,15 @@
             }
         """.trimIndent()
         )
-        val doesNotExistTypeName = ClassName.get("", "DoesNotExist")
         runTest(subjectSrc, succeed = false) { resolver ->
             val subject = resolver.requireClass("Foo")
             assertThat(subject.propertyType("errorField").typeName())
-                .isEqualTo(doesNotExistTypeName)
+                .isEqualTo(ERROR_TYPE_NAME)
             assertThat(subject.propertyType("listOfError").typeName())
                 .isEqualTo(
                     ParameterizedTypeName.get(
                         LIST_TYPE_NAME,
-                        doesNotExistTypeName
+                        ERROR_TYPE_NAME
                     )
                 )
             assertThat(subject.propertyType("mutableMapOfDontExist").typeName())
@@ -136,7 +135,7 @@
                     ParameterizedTypeName.get(
                         MUTABLE_MAP_TYPE_NAME,
                         STRING_TYPE_NAME,
-                        doesNotExistTypeName
+                        ERROR_TYPE_NAME
                     )
                 )
         }
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspFieldElementTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspFieldElementTest.kt
new file mode 100644
index 0000000..8960503
--- /dev/null
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspFieldElementTest.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2020 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.room.compiler.processing.ksp
+
+import androidx.room.compiler.processing.util.KotlinTypeNames.INT_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.LIST_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.STRING_CLASS_NAME
+import androidx.room.compiler.processing.util.Source
+import androidx.room.compiler.processing.util.getField
+import androidx.room.compiler.processing.util.runKspTest
+import com.google.common.truth.Truth.assertThat
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.ParameterizedTypeName
+import org.junit.Test
+
+class KspFieldElementTest {
+    @Test
+    fun simple() {
+        val src = Source.kotlin(
+            "Foo.kt", """
+            class Foo {
+                val intField: Int = 0
+            }
+        """.trimIndent()
+        )
+        runKspTest(sources = listOf(src), succeed = true) { invocation ->
+            val fooElement = invocation.processingEnv.requireTypeElement("Foo")
+            fooElement
+                .getField("intField").let { field ->
+                    assertThat(field.name).isEqualTo("intField")
+                    assertThat(field.kindName()).isEqualTo("property")
+                    assertThat(field.enclosingTypeElement).isEqualTo(fooElement)
+                }
+        }
+    }
+
+    @Test
+    fun asMemberOf() {
+        val src = Source.kotlin(
+            "Foo.kt", """
+            open class Base<T, R> {
+                val t : T = TODO()
+                val listOfR : List<R> = TODO()
+            }
+            class Sub1 : Base<Int, String>()
+        """.trimIndent()
+        )
+        runKspTest(sources = listOf(src), succeed = true) { invocation ->
+            val sub = invocation.processingEnv.requireTypeElement("Sub1")
+            val base = invocation.processingEnv.requireTypeElement("Base")
+            val t = base.getField("t")
+            val listOfR = base.getField("listOfR")
+            assertThat(t.type.typeName).isEqualTo(ClassName.get("Base", "T"))
+            assertThat(listOfR.type.typeName)
+                .isEqualTo(
+                    ParameterizedTypeName.get(LIST_CLASS_NAME, ClassName.get("Base", "R"))
+                )
+            assertThat(t.enclosingTypeElement).isEqualTo(base)
+            assertThat(listOfR.enclosingTypeElement).isEqualTo(base)
+            assertThat(t.asMemberOf(sub.type).typeName).isEqualTo(INT_CLASS_NAME)
+            assertThat(listOfR.asMemberOf(sub.type).typeName)
+                .isEqualTo(ParameterizedTypeName.get(LIST_CLASS_NAME, STRING_CLASS_NAME))
+        }
+    }
+}
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeElementTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeElementTest.kt
index 7107244..70d6a5e 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeElementTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeElementTest.kt
@@ -17,10 +17,16 @@
 package androidx.room.compiler.processing.ksp
 
 import androidx.room.compiler.processing.XTypeElement
+import androidx.room.compiler.processing.util.KotlinTypeNames.INT_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.LIST_CLASS_NAME
+import androidx.room.compiler.processing.util.KotlinTypeNames.MUTABLELIST_CLASS_NAME
 import androidx.room.compiler.processing.util.Source
+import androidx.room.compiler.processing.util.getAllFieldNames
+import androidx.room.compiler.processing.util.getField
 import androidx.room.compiler.processing.util.runKspTest
 import com.google.common.truth.Truth.assertThat
 import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.ParameterizedTypeName
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -198,4 +204,58 @@
             }
         }
     }
-}
\ No newline at end of file
+
+    @Test
+    fun fieldBasic() {
+        val src = Source.kotlin(
+            "Foo.kt", """
+            open class BaseClass<T>(val genericProp : T)
+            class SubClass(x : Int) : BaseClass<Int>(x) {
+                val subClassProp : String = "abc"
+            }
+        """.trimIndent()
+        )
+        runKspTest(sources = listOf(src), succeed = true) { invocation ->
+            val baseClass = invocation.processingEnv.requireTypeElement("BaseClass")
+            assertThat(baseClass.getAllFieldNames()).containsExactly("genericProp")
+            val subClass = invocation.processingEnv.requireTypeElement("SubClass")
+            assertThat(subClass.getAllFieldNames()).containsExactly("genericProp", "subClassProp")
+            baseClass.getField("genericProp").let { field ->
+                assertThat(field.type.typeName).isEqualTo(ClassName.get("", "BaseClass", "T"))
+            }
+            subClass.getField("genericProp").let { field ->
+                assertThat(field.type.typeName).isEqualTo(ClassName.get("kotlin", "Int"))
+            }
+        }
+    }
+
+    @Test
+    fun fieldsOverride() {
+        val src = Source.kotlin(
+            "Foo.kt", """
+            open class BaseClass(
+                open val value : List<Int>
+            )
+            class SubClass(
+                override val value : MutableList<Int>
+            ) : BaseClass(value)
+        """.trimIndent()
+        )
+        runKspTest(sources = listOf(src), succeed = true) { invocation ->
+            val baseClass = invocation.processingEnv.requireTypeElement("BaseClass")
+            assertThat(baseClass.getAllFieldNames()).containsExactly("value")
+            val subClass = invocation.processingEnv.requireTypeElement("SubClass")
+            assertThat(subClass.getAllFieldNames()).containsExactly("value")
+            assertThat(
+                baseClass.getField("value").type.typeName
+            ).isEqualTo(
+                ParameterizedTypeName.get(LIST_CLASS_NAME, INT_CLASS_NAME)
+            )
+            assertThat(
+                subClass.getField("value").type.typeName
+            ).isEqualTo(
+                ParameterizedTypeName.get(MUTABLELIST_CLASS_NAME, INT_CLASS_NAME)
+            )
+        }
+    }
+}
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt
index 241b7b2..e5e3b0a 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/ksp/KspTypeTest.kt
@@ -23,6 +23,7 @@
 import androidx.room.compiler.processing.util.runKspTest
 import com.google.common.truth.Truth.assertThat
 import com.squareup.javapoet.ClassName
+import org.jetbrains.kotlin.ksp.getClassDeclarationByName
 import org.jetbrains.kotlin.ksp.getDeclaredFunctions
 import org.jetbrains.kotlin.ksp.symbol.KSPropertyDeclaration
 import org.jetbrains.kotlin.ksp.symbol.KSTypeReference
@@ -87,7 +88,8 @@
             invocation.requirePropertyType("errorType").let { type ->
                 assertThat(type.isError()).isTrue()
                 assertThat(type.typeArguments).isEmpty()
-                assertThat(type.typeName).isEqualTo(ClassName.bestGuess("IDontExist"))
+                assertThat(type.typeName).isEqualTo(ERROR_TYPE_NAME)
+                assertThat(type.asTypeElement().className).isEqualTo(ERROR_TYPE_NAME)
             }
 
             invocation.requirePropertyType("listOfErrorType").let { type ->
@@ -95,7 +97,7 @@
                 assertThat(type.typeArguments).hasSize(1)
                 type.typeArguments.single().let { typeArg ->
                     assertThat(typeArg.isError()).isTrue()
-                    assertThat(typeArg.typeName).isEqualTo(ClassName.bestGuess("IDontExist"))
+                    assertThat(typeArg.typeName).isEqualTo(ERROR_TYPE_NAME)
                 }
             }
         }
@@ -117,6 +119,9 @@
             invocation.requirePropertyType("listOfNullableStrings").let { type ->
                 assertThat(type.nullability).isEqualTo(NONNULL)
                 assertThat(type.typeArguments).hasSize(1)
+                assertThat(type.asTypeElement().className).isEqualTo(
+                    ClassName.get("kotlin.collections", "List")
+                )
                 type.typeArguments.single().let { typeArg ->
                     assertThat(typeArg.nullability).isEqualTo(NULLABLE)
                     assertThat(
@@ -138,6 +143,9 @@
                         )
                     ).isTrue()
                 }
+                assertThat(type.asTypeElement().className).isEqualTo(
+                    ClassName.get("kotlin.collections", "List")
+                )
             }
         }
     }
@@ -224,6 +232,29 @@
     }
 
     @Test
+    fun noneType() {
+        val src = Source.java(
+            "foo.bar.Baz", """
+            package foo.bar;
+            public class Baz {
+                void voidMethod() {
+                }
+            }
+        """.trimIndent()
+        )
+        runKspTest(sources = listOf(src), succeed = true) { invocation ->
+            val resolver = (invocation.processingEnv as KspProcessingEnv).resolver
+            val voidMethod = resolver.getClassDeclarationByName("foo.bar.Baz")!!
+                .getDeclaredFunctions()
+                .first {
+                    it.simpleName.asString() == "voidMethod"
+                }
+            val returnType = voidMethod.returnType
+            assertThat(returnType?.typeName()).isEqualTo(ClassName.get("kotlin", "Unit"))
+        }
+    }
+
+    @Test
     fun isTypeChecks() {
         val src = Source.kotlin(
             "foo.kt", """
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/KotlinTypeNames.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/KotlinTypeNames.kt
new file mode 100644
index 0000000..a1b0f22
--- /dev/null
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/KotlinTypeNames.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2020 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.room.compiler.processing.util
+
+import com.squareup.javapoet.ClassName
+
+internal object KotlinTypeNames {
+    val INT_CLASS_NAME = ClassName.get("kotlin", "Int")
+    val STRING_CLASS_NAME = ClassName.get("kotlin", "String")
+    val LIST_CLASS_NAME = ClassName.get("kotlin.collections", "List")
+    val MUTABLELIST_CLASS_NAME = ClassName.get("kotlin.collections", "MutableList")
+    val MAP_CLASS_NAME = ClassName.get("kotlin.collections", "Map")
+    val PAIR_CLASS_NAME = ClassName.get(Pair::class.java)
+}
diff --git a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/TestExtensions.kt b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/TestExtensions.kt
index ef3de1a..0e8f322 100644
--- a/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/TestExtensions.kt
+++ b/room/compiler-processing/src/test/java/androidx/room/compiler/processing/util/TestExtensions.kt
@@ -19,6 +19,10 @@
 import androidx.room.compiler.processing.XExecutableElement
 import androidx.room.compiler.processing.XTypeElement
 
+fun XTypeElement.getAllFieldNames() = getAllFieldsIncludingPrivateSupers().map {
+    it.name
+}
+
 fun XTypeElement.getField(name: String) = getAllFieldsIncludingPrivateSupers().first {
     it.name == name
 }
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/CustomConverterProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/CustomConverterProcessor.kt
index 849710e..1300b96 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/CustomConverterProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/CustomConverterProcessor.kt
@@ -16,6 +16,7 @@
 
 package androidx.room.processor
 
+import androidx.room.ProvidedTypeConverter
 import androidx.room.TypeConverter
 import androidx.room.TypeConverters
 import androidx.room.compiler.processing.XDeclaredType
@@ -77,21 +78,26 @@
         val converterMethods = methods.filter {
             it.hasAnnotation(TypeConverter::class)
         }
+        val isProvidedConverter = declaredType.asTypeElement()
+            .hasAnnotation(ProvidedTypeConverter::class)
         context.checker.check(converterMethods.isNotEmpty(), element, TYPE_CONVERTER_EMPTY_CLASS)
         val allStatic = converterMethods.all { it.isStatic() }
         val constructors = element.getConstructors()
         val isKotlinObjectDeclaration = element.isKotlinObject()
-        context.checker.check(
-            isKotlinObjectDeclaration || allStatic || constructors.isEmpty() ||
-                    constructors.any {
-                        it.parameters.isEmpty()
-                    }, element, TYPE_CONVERTER_MISSING_NOARG_CONSTRUCTOR
-        )
+        if (!isProvidedConverter) {
+            context.checker.check(
+                isKotlinObjectDeclaration || allStatic || constructors.isEmpty() ||
+                        constructors.any {
+                            it.parameters.isEmpty()
+                        }, element, TYPE_CONVERTER_MISSING_NOARG_CONSTRUCTOR
+            )
+        }
         return converterMethods.mapNotNull {
             processMethod(
                 container = declaredType,
                 isContainerKotlinObject = isKotlinObjectDeclaration,
-                methodElement = it
+                methodElement = it,
+                isProvidedConverter = isProvidedConverter
             )
         }
     }
@@ -99,7 +105,8 @@
     private fun processMethod(
         container: XDeclaredType,
         methodElement: XMethodElement,
-        isContainerKotlinObject: Boolean
+        isContainerKotlinObject: Boolean,
+        isProvidedConverter: Boolean
     ): CustomTypeConverter? {
         val asMember = methodElement.asMemberOf(container)
         val returnType = asMember.returnType
@@ -130,7 +137,8 @@
             isEnclosingClassKotlinObject = isContainerKotlinObject,
             method = methodElement,
             from = param,
-            to = returnType
+            to = returnType,
+            isProvidedConverter = isProvidedConverter
         )
     }
 
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/FtsTableEntityProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/FtsTableEntityProcessor.kt
index c522647..7971604 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/FtsTableEntityProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/FtsTableEntityProcessor.kt
@@ -20,11 +20,11 @@
 import androidx.room.Fts4
 import androidx.room.FtsOptions.MatchInfo
 import androidx.room.FtsOptions.Order
-import androidx.room.parser.FtsVersion
-import androidx.room.parser.SQLTypeAffinity
 import androidx.room.compiler.processing.XAnnotationBox
 import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.XTypeElement
+import androidx.room.parser.FtsVersion
+import androidx.room.parser.SQLTypeAffinity
 import androidx.room.processor.EntityProcessor.Companion.extractForeignKeys
 import androidx.room.processor.EntityProcessor.Companion.extractIndices
 import androidx.room.processor.EntityProcessor.Companion.extractTableName
@@ -99,10 +99,6 @@
         context.checker.check(missingNotIndexed.isEmpty(), element,
                 ProcessorErrors.missingNotIndexedField(missingNotIndexed))
 
-        pojo.fields.filter { it.element.hasAnnotation(androidx.room.ForeignKey::class) }.forEach {
-            context.logger.e(ProcessorErrors.INVALID_FOREIGN_KEY_IN_FTS_ENTITY, it.element)
-        }
-
         context.checker.check(ftsOptions.prefixSizes.all { it > 0 },
                 element, ProcessorErrors.INVALID_FTS_ENTITY_PREFIX_SIZES)
 
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt b/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
index 8cff3a3..1fb9bca 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
@@ -294,7 +294,8 @@
     val TYPE_CONVERTER_EMPTY_CLASS = "Class is referenced as a converter but it does not have any" +
             " converter methods."
     val TYPE_CONVERTER_MISSING_NOARG_CONSTRUCTOR = "Classes that are used as TypeConverters must" +
-            " have no-argument public constructors."
+            " have no-argument public constructors. Use a ProvidedTypeConverter annotation if you" +
+            " need to take control over creating an instance of a TypeConverter."
     val TYPE_CONVERTER_MUST_BE_PUBLIC = "Type converters must be public."
 
     fun duplicateTypeConverters(converters: List<CustomTypeConverter>): String {
@@ -667,8 +668,6 @@
 
     val INVALID_FTS_ENTITY_PREFIX_SIZES = "Prefix sizes to index must non-zero positive values."
 
-    val INVALID_FOREIGN_KEY_IN_FTS_ENTITY = "@ForeignKey is not allowed in an FTS entity fields."
-
     val FTS_EXTERNAL_CONTENT_CANNOT_FIND_ENTITY = "Cannot find external content entity class."
 
     fun externalContentNotAnEntity(className: String) = "External content entity referenced in " +
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/types/CustomTypeConverterWrapper.kt b/room/compiler/src/main/kotlin/androidx/room/solver/types/CustomTypeConverterWrapper.kt
index aa1e4e5..6d2b5e9 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/types/CustomTypeConverterWrapper.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/types/CustomTypeConverterWrapper.kt
@@ -16,14 +16,18 @@
 
 package androidx.room.solver.types
 
+import androidx.room.ProvidedTypeConverter
 import androidx.room.ext.L
 import androidx.room.ext.N
 import androidx.room.ext.T
 import androidx.room.solver.CodeGenScope
 import androidx.room.vo.CustomTypeConverter
 import androidx.room.writer.ClassWriter
+import androidx.room.writer.DaoWriter
 import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.CodeBlock
 import com.squareup.javapoet.FieldSpec
+import com.squareup.javapoet.MethodSpec
 import decapitalize
 import java.util.Locale
 import javax.lang.model.element.Modifier
@@ -45,13 +49,77 @@
                         outputVarName, custom.typeName,
                         custom.methodName, inputVarName)
             } else {
-                addStatement("$L = $N.$L($L)",
-                        outputVarName, typeConverter(scope),
+                if (custom.isProvidedConverter) {
+                    addStatement("$L = $N().$L($L)",
+                        outputVarName, providedTypeConverter(scope),
                         custom.methodName, inputVarName)
+                } else {
+                    addStatement(
+                        "$L = $N.$L($L)",
+                        outputVarName, typeConverter(scope),
+                        custom.methodName, inputVarName
+                    )
+                }
             }
         }
     }
 
+    private fun providedTypeConverter(scope: CodeGenScope): MethodSpec {
+        val className = custom.typeName as ClassName
+        val baseName = className.simpleName().decapitalize(Locale.US)
+
+        val converterClassName = custom.typeName as ClassName
+        scope.writer.addRequiredTypeConverter(converterClassName)
+        val converterField = scope.writer.getOrCreateField(object : ClassWriter.SharedFieldSpec(
+            baseName, custom.typeName
+        ) {
+            override fun getUniqueKey(): String {
+                return "converter_${custom.typeName}"
+            }
+
+            override fun prepare(writer: ClassWriter, builder: FieldSpec.Builder) {
+                builder.addModifiers(Modifier.PRIVATE)
+            }
+        })
+
+        return scope.writer.getOrCreateMethod(object : ClassWriter.SharedMethodSpec(baseName) {
+            override fun getUniqueKey(): String {
+                return "converterMethod_${custom.typeName}"
+            }
+
+            override fun prepare(
+                methodName: String,
+                writer: ClassWriter,
+                builder: MethodSpec.Builder
+            ) {
+                builder.apply {
+                    addModifiers(Modifier.PRIVATE)
+                    addModifiers(Modifier.SYNCHRONIZED)
+                    returns(custom.typeName)
+                    addCode(buildConvertMethodBody(writer))
+                }
+            }
+
+            private fun buildConvertMethodBody(
+                writer: ClassWriter
+            ): CodeBlock {
+                val methodScope = CodeGenScope(writer)
+                methodScope.builder().apply {
+                    beginControlFlow("if ($N == null)", converterField)
+                    addStatement(
+                        "$N = $N.getTypeConverter($T.class)",
+                        converterField,
+                        DaoWriter.dbField,
+                        custom.typeName
+                    )
+                    endControlFlow()
+                    addStatement("return $N", converterField)
+                }
+                return methodScope.builder().build()
+            }
+        })
+    }
+
     fun typeConverter(scope: CodeGenScope): FieldSpec {
         val baseName = (custom.typeName as ClassName).simpleName().decapitalize(Locale.US)
         return scope.writer.getOrCreateField(object : ClassWriter.SharedFieldSpec(
@@ -68,3 +136,11 @@
         })
     }
 }
+
+fun ClassWriter.addRequiredTypeConverter(className: ClassName) {
+    this[ProvidedTypeConverter::class] = getRequiredTypeConverters() + setOf(className)
+}
+
+fun ClassWriter.getRequiredTypeConverters(): Set<ClassName> {
+    return this.get<Set<ClassName>>(ProvidedTypeConverter::class) ?: emptySet()
+}
diff --git a/room/compiler/src/main/kotlin/androidx/room/vo/CustomTypeConverter.kt b/room/compiler/src/main/kotlin/androidx/room/vo/CustomTypeConverter.kt
index 96fac0f..dcbcc90 100644
--- a/room/compiler/src/main/kotlin/androidx/room/vo/CustomTypeConverter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/vo/CustomTypeConverter.kt
@@ -28,7 +28,8 @@
     val isEnclosingClassKotlinObject: Boolean,
     val method: XMethodElement,
     val from: XType,
-    val to: XType
+    val to: XType,
+    val isProvidedConverter: Boolean
 ) {
     val typeName: TypeName by lazy { enclosingClass.typeName }
     val fromTypeName: TypeName by lazy { from.typeName }
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/ClassWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/ClassWriter.kt
index 77976ff..46267c5a 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/ClassWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/ClassWriter.kt
@@ -28,6 +28,7 @@
 import com.squareup.javapoet.MethodSpec
 import com.squareup.javapoet.TypeName
 import com.squareup.javapoet.TypeSpec
+import kotlin.reflect.KClass
 
 /**
  * Base class for all writers that can produce a class.
@@ -37,9 +38,31 @@
     private val sharedMethodSpecs = mutableMapOf<String, MethodSpec>()
     private val sharedFieldNames = mutableSetOf<String>()
     private val sharedMethodNames = mutableSetOf<String>()
+    private val metadata = mutableMapOf<KClass<*>, Any>()
 
     abstract fun createTypeSpecBuilder(): TypeSpec.Builder
 
+    /**
+     * Read additional metadata that can be put by sub code generators.
+     *
+     * @see set for more details.
+     */
+    operator fun <T> get(key: KClass<*>): T? {
+        @Suppress("UNCHECKED_CAST")
+        return metadata[key] as? T
+    }
+
+    /**
+     * Add additional metadata to the ClassWriter that can be read back later.
+     * This is useful for additional functionality where a sub code generator needs to bubble up
+     * information to the main ClassWriter without copying it in every intermediate step.
+     *
+     * @see get
+     */
+    operator fun set(key: KClass<*>, value: Any) {
+        metadata[key] = value
+    }
+
     fun write(processingEnv: XProcessingEnv) {
         val builder = createTypeSpecBuilder()
         sharedFieldSpecs.values.forEach { builder.addField(it) }
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
index d4d0af7..30f09b6 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
@@ -27,9 +27,11 @@
 import androidx.room.compiler.processing.XMethodElement
 import androidx.room.compiler.processing.XProcessingEnv
 import androidx.room.compiler.processing.addOriginatingElement
+import androidx.room.ext.CommonTypeNames
 import androidx.room.processor.OnConflictProcessor
 import androidx.room.solver.CodeGenScope
 import androidx.room.solver.KotlinDefaultMethodDelegateBinder
+import androidx.room.solver.types.getRequiredTypeConverters
 import androidx.room.vo.Dao
 import androidx.room.vo.InsertionMethod
 import androidx.room.vo.KotlinDefaultMethodDelegate
@@ -49,11 +51,15 @@
 import com.squareup.javapoet.ParameterizedTypeName
 import com.squareup.javapoet.TypeName
 import com.squareup.javapoet.TypeSpec
+import com.squareup.javapoet.WildcardTypeName
 import stripNonJava
+import java.util.Arrays
+import java.util.Collections
 import java.util.Locale
 import javax.lang.model.element.Modifier.FINAL
 import javax.lang.model.element.Modifier.PRIVATE
 import javax.lang.model.element.Modifier.PUBLIC
+import javax.lang.model.element.Modifier.STATIC
 
 /**
  * Creates the implementation for a class annotated with Dao.
@@ -67,6 +73,7 @@
     private val declaredDao = dao.element.asDeclaredType()
 
     companion object {
+        const val GET_LIST_OF_TYPE_CONVERTERS_METHOD = "getRequiredConverters"
         // TODO nothing prevents this from conflicting, we should fix.
         val dbField: FieldSpec = FieldSpec
                 .builder(RoomTypeNames.ROOM_DB, "__db", PRIVATE, FINAL)
@@ -139,10 +146,38 @@
             dao.kotlinDefaultMethodDelegates.forEach {
                 addMethod(createDefaultMethodDelegate(it))
             }
+            // keep this the last one to be generated because used custom converters will register
+            // fields with a payload which we collect in dao to report used Type Converters.
+            addMethod(createConverterListMethod())
         }
         return builder
     }
 
+    private fun createConverterListMethod(): MethodSpec {
+        return MethodSpec.methodBuilder(GET_LIST_OF_TYPE_CONVERTERS_METHOD).apply {
+            addModifiers(STATIC, PUBLIC)
+            returns(
+                ParameterizedTypeName.get(
+                    CommonTypeNames.LIST,
+                    ParameterizedTypeName.get(
+                        ClassName.get(Class::class.java),
+                        WildcardTypeName.subtypeOf(Object::class.java)
+                    )
+                )
+            )
+            val requiredTypeConverters = getRequiredTypeConverters()
+            if (requiredTypeConverters.isEmpty()) {
+                addStatement("return $T.emptyList()", ClassName.get(Collections::class.java))
+            } else {
+                val placeholders = requiredTypeConverters.joinToString(",") {
+                    "$T.class"
+                }
+                val args = arrayOf(ClassName.get(Arrays::class.java)) + requiredTypeConverters
+                addStatement("return $T.asList($placeholders)", *args)
+            }
+        }.build()
+    }
+
     private fun createPreparedQueries(
         preparedQueries: List<WriteQueryMethod>
     ): List<PreparedStmtQuery> {
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
index 0ad8ad1..6b07453 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/DatabaseWriter.kt
@@ -30,12 +30,14 @@
 import androidx.room.solver.CodeGenScope
 import androidx.room.vo.DaoMethod
 import androidx.room.vo.Database
+import com.squareup.javapoet.ClassName
 import com.squareup.javapoet.FieldSpec
 import com.squareup.javapoet.MethodSpec
 import com.squareup.javapoet.ParameterSpec
 import com.squareup.javapoet.ParameterizedTypeName
 import com.squareup.javapoet.TypeName
 import com.squareup.javapoet.TypeSpec
+import com.squareup.javapoet.WildcardTypeName
 import decapitalize
 import stripNonJava
 import java.util.Locale
@@ -59,11 +61,63 @@
             addMethod(createCreateOpenHelper())
             addMethod(createCreateInvalidationTracker())
             addMethod(createClearAllTables())
+            addMethod(createCreateTypeConvertersMap())
         }
         addDaoImpls(builder)
         return builder
     }
 
+    private fun createCreateTypeConvertersMap(): MethodSpec {
+        val scope = CodeGenScope(this)
+        return MethodSpec.methodBuilder("getRequiredTypeConverters").apply {
+            addAnnotation(Override::class.java)
+            addModifiers(PROTECTED)
+            returns(ParameterizedTypeName.get(
+                CommonTypeNames.MAP,
+                ParameterizedTypeName.get(
+                    ClassName.get(Class::class.java),
+                    WildcardTypeName.subtypeOf(Object::class.java)
+                ),
+                ParameterizedTypeName.get(
+                    CommonTypeNames.LIST,
+                    ParameterizedTypeName.get(
+                        ClassName.get(Class::class.java),
+                        WildcardTypeName.subtypeOf(Object::class.java)
+                    )
+                )
+            ))
+            val typeConvertersVar = scope.getTmpVar("_typeConvertersMap")
+            val typeConvertersTypeName = ParameterizedTypeName.get(
+                ClassName.get(HashMap::class.java),
+                ParameterizedTypeName.get(
+                    ClassName.get(Class::class.java),
+                    WildcardTypeName.subtypeOf(Object::class.java)
+                ),
+                ParameterizedTypeName.get(
+                    ClassName.get(List::class.java),
+                    ParameterizedTypeName.get(
+                        ClassName.get(Class::class.java),
+                        WildcardTypeName.subtypeOf(Object::class.java)
+                    )
+                )
+            )
+            addStatement(
+                "final $T $L = new $T()",
+                typeConvertersTypeName,
+                typeConvertersVar,
+                typeConvertersTypeName
+            )
+            database.daoMethods.forEach {
+                addStatement("$L.put($T.class, $T.$L())",
+                typeConvertersVar,
+                it.dao.typeName,
+                it.dao.implTypeName,
+                DaoWriter.GET_LIST_OF_TYPE_CONVERTERS_METHOD)
+            }
+            addStatement("return $L", typeConvertersVar)
+        }.build()
+    }
+
     private fun createClearAllTables(): MethodSpec {
         val scope = CodeGenScope(this)
         return MethodSpec.methodBuilder("clearAllTables").apply {
diff --git a/room/compiler/src/test/data/daoWriter/output/ComplexDao.java b/room/compiler/src/test/data/daoWriter/output/ComplexDao.java
index b5d2256..5de9bb5 100644
--- a/room/compiler/src/test/data/daoWriter/output/ComplexDao.java
+++ b/room/compiler/src/test/data/daoWriter/output/ComplexDao.java
@@ -10,6 +10,7 @@
 import androidx.room.util.DBUtil;
 import androidx.room.util.StringUtil;
 import com.google.common.util.concurrent.ListenableFuture;
+import java.lang.Class;
 import java.lang.Exception;
 import java.lang.Integer;
 import java.lang.Override;
@@ -17,6 +18,7 @@
 import java.lang.StringBuilder;
 import java.lang.SuppressWarnings;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Callable;
 import javax.annotation.processing.Generated;
@@ -534,4 +536,8 @@
             }
         }, _statement, true, _cancellationSignal);
     }
+
+    public static List<Class<?>> getRequiredConverters() {
+        return Collections.emptyList();
+    }
 }
\ No newline at end of file
diff --git a/room/compiler/src/test/data/daoWriter/output/DeletionDao.java b/room/compiler/src/test/data/daoWriter/output/DeletionDao.java
index 713442b..04979c9 100644
--- a/room/compiler/src/test/data/daoWriter/output/DeletionDao.java
+++ b/room/compiler/src/test/data/daoWriter/output/DeletionDao.java
@@ -8,6 +8,7 @@
 import io.reactivex.Completable;
 import io.reactivex.Maybe;
 import io.reactivex.Single;
+import java.lang.Class;
 import java.lang.Exception;
 import java.lang.Integer;
 import java.lang.Override;
@@ -15,6 +16,7 @@
 import java.lang.StringBuilder;
 import java.lang.SuppressWarnings;
 import java.lang.Void;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Callable;
 import javax.annotation.processing.Generated;
@@ -387,4 +389,8 @@
       __db.endTransaction();
     }
   }
-}
+
+  public static List<Class<?>> getRequiredConverters() {
+    return Collections.emptyList();
+  }
+}
\ No newline at end of file
diff --git a/room/compiler/src/test/data/daoWriter/output/UpdateDao.java b/room/compiler/src/test/data/daoWriter/output/UpdateDao.java
index 973ebca..e2e9775 100644
--- a/room/compiler/src/test/data/daoWriter/output/UpdateDao.java
+++ b/room/compiler/src/test/data/daoWriter/output/UpdateDao.java
@@ -7,12 +7,14 @@
 import io.reactivex.Completable;
 import io.reactivex.Maybe;
 import io.reactivex.Single;
+import java.lang.Class;
 import java.lang.Exception;
 import java.lang.Integer;
 import java.lang.Override;
 import java.lang.String;
 import java.lang.SuppressWarnings;
 import java.lang.Void;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Callable;
 import javax.annotation.processing.Generated;
@@ -391,4 +393,8 @@
       }
     });
   }
+
+  public static List<Class<?>> getRequiredConverters() {
+    return Collections.emptyList();
+  }
 }
\ No newline at end of file
diff --git a/room/compiler/src/test/data/daoWriter/output/WriterDao.java b/room/compiler/src/test/data/daoWriter/output/WriterDao.java
index a3871dd..3c453dd 100644
--- a/room/compiler/src/test/data/daoWriter/output/WriterDao.java
+++ b/room/compiler/src/test/data/daoWriter/output/WriterDao.java
@@ -19,9 +19,11 @@
 import androidx.room.EntityInsertionAdapter;
 import androidx.room.RoomDatabase;
 import androidx.sqlite.db.SupportSQLiteStatement;
+import java.lang.Class;
 import java.lang.Override;
 import java.lang.String;
 import java.lang.SuppressWarnings;
+import java.util.Collections;
 import java.util.List;
 import javax.annotation.processing.Generated;
 
@@ -145,4 +147,8 @@
             __db.endTransaction();
         }
     }
-}
+
+    public static List<Class<?>> getRequiredConverters() {
+        return Collections.emptyList();
+    }
+}
\ No newline at end of file
diff --git a/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java b/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
index 31ca838..aa123f3 100644
--- a/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
+++ b/room/compiler/src/test/data/databasewriter/output/ComplexDatabase.java
@@ -15,11 +15,14 @@
 import androidx.sqlite.db.SupportSQLiteOpenHelper;
 import androidx.sqlite.db.SupportSQLiteOpenHelper.Callback;
 import androidx.sqlite.db.SupportSQLiteOpenHelper.Configuration;
+import java.lang.Class;
 import java.lang.Override;
 import java.lang.String;
 import java.lang.SuppressWarnings;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import javax.annotation.processing.Generated;
 
@@ -175,6 +178,13 @@
     }
 
     @Override
+    protected Map<Class<?>, List<Class<?>>> getRequiredTypeConverters() {
+        final HashMap<Class<?>, List<Class<?>>> _typeConvertersMap = new HashMap<Class<?>, List<Class<?>>>();
+        _typeConvertersMap.put(ComplexDao.class, ComplexDao_Impl.getRequiredConverters());
+        return _typeConvertersMap;
+    }
+
+    @Override
     ComplexDao getComplexDao() {
         if (_complexDao != null) {
             return _complexDao;
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/Fts3TableEntityProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/Fts3TableEntityProcessorTest.kt
index 7147a29..144e045 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/Fts3TableEntityProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/Fts3TableEntityProcessorTest.kt
@@ -141,18 +141,6 @@
     }
 
     @Test
-    fun badForeignKey() {
-        singleEntity("""
-                @PrimaryKey
-                public int rowid;
-                @ForeignKey(entity = MyEntity.class, parentColumns = {}, childColumns = {})
-                public int fkId;
-                """) { _, _ -> }
-                .failsToCompile()
-                .withErrorContaining(ProcessorErrors.INVALID_FOREIGN_KEY_IN_FTS_ENTITY)
-    }
-
-    @Test
     fun nonDefaultTokenizer() {
         singleEntity("""
                 @PrimaryKey
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/Fts4TableEntityProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/Fts4TableEntityProcessorTest.kt
index 1888c6f..7686775 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/Fts4TableEntityProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/Fts4TableEntityProcessorTest.kt
@@ -208,18 +208,6 @@
     }
 
     @Test
-    fun badForeignKey() {
-        singleEntity("""
-                @PrimaryKey
-                public int rowid;
-                @ForeignKey(entity = MyEntity.class, parentColumns = {}, childColumns = {})
-                public int fkId;
-                """) { _, _ -> }
-                .failsToCompile()
-                .withErrorContaining(ProcessorErrors.INVALID_FOREIGN_KEY_IN_FTS_ENTITY)
-    }
-
-    @Test
     fun nonDefaultTokenizer() {
         singleEntity("""
                 @PrimaryKey
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/ProvidedTypeConverterTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/ProvidedTypeConverterTest.java
new file mode 100644
index 0000000..55537e9
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/ProvidedTypeConverterTest.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.room.integration.testapp.test;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.room.Database;
+import androidx.room.Entity;
+import androidx.room.Insert;
+import androidx.room.PrimaryKey;
+import androidx.room.ProvidedTypeConverter;
+import androidx.room.Query;
+import androidx.room.Room;
+import androidx.room.RoomDatabase;
+import androidx.room.TypeConverter;
+import androidx.room.TypeConverters;
+import androidx.room.integration.testapp.TestDatabase;
+import androidx.room.integration.testapp.dao.PetDao;
+import androidx.room.integration.testapp.dao.RobotsDao;
+import androidx.room.integration.testapp.vo.Hivemind;
+import androidx.room.integration.testapp.vo.Pet;
+import androidx.room.integration.testapp.vo.PetWithUser;
+import androidx.room.integration.testapp.vo.Robot;
+import androidx.room.integration.testapp.vo.Toy;
+import androidx.room.integration.testapp.vo.User;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.nio.ByteBuffer;
+import java.util.Date;
+import java.util.Objects;
+import java.util.UUID;
+
+@SuppressWarnings("unchecked")
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ProvidedTypeConverterTest {
+
+    @Test
+    public void testProvidedTypeConverter() {
+        Context context = ApplicationProvider.getApplicationContext();
+        TestDatabaseWithConverter db =
+                Room.inMemoryDatabaseBuilder(context, TestDatabaseWithConverter.class)
+                        .addTypeConverter(new TimeStampConverter())
+                        .addTypeConverter(new UUIDConverter())
+                        .build();
+        Pet pet = TestUtil.createPet(3);
+        pet.setName("pet");
+        db.getPetDao().insertOrReplace(pet);
+
+        Robot robot = new Robot(UUID.randomUUID(), UUID.randomUUID());
+        db.getRobotsDao().putRobot(robot);
+        db.close();
+    }
+
+    @Test
+    public void testMissingProvidedTypeConverterInstance() {
+        Context context = ApplicationProvider.getApplicationContext();
+        try {
+            TestDatabaseWithConverter db =
+                    Room.inMemoryDatabaseBuilder(context, TestDatabaseWithConverter.class).build();
+            Pet pet = TestUtil.createPet(3);
+            pet.setName("pet");
+            db.getPetDao().insertOrReplace(pet);
+            fail("Show have thrown an IllegalArgumentException");
+        } catch (Throwable throwable) {
+            Assert.assertThat(throwable, instanceOf(IllegalArgumentException.class));
+        }
+    }
+
+    @Test
+    public void testMissingProvidedTypeConverterAnnotation() {
+        Context context = ApplicationProvider.getApplicationContext();
+        try {
+            TestDatabase db = Room.inMemoryDatabaseBuilder(context, TestDatabase.class)
+                    .addTypeConverter(new TimeStampConverter())
+                    .build();
+            Pet pet = TestUtil.createPet(3);
+            pet.setName("pet");
+            db.getPetDao().insertOrReplace(pet);
+            fail("Show have thrown an IllegalArgumentException");
+        } catch (Throwable throwable) {
+            Assert.assertThat(throwable, instanceOf(IllegalArgumentException.class));
+        }
+    }
+
+    @Test
+    public void differentSerializerForTheSameClassInDifferentDatabases() {
+        Context context = ApplicationProvider.getApplicationContext();
+        ProvidedTypeConverterNameLastNameDb db1 = Room
+                .inMemoryDatabaseBuilder(context, ProvidedTypeConverterNameLastNameDb.class)
+                .addTypeConverter(new NameLastNameSerializer())
+                .build();
+        ProvidedTypeConverterLastNameNameDb db2 = Room
+                .inMemoryDatabaseBuilder(context, ProvidedTypeConverterLastNameNameDb.class)
+                .addTypeConverter(new LastNameNameSerializer())
+                .build();
+        ProvidedTypeConverterEntity entity1 = new ProvidedTypeConverterEntity(1,
+                new Username("foo1", "bar1"));
+        ProvidedTypeConverterEntity entity2 = new ProvidedTypeConverterEntity(2,
+                new Username("foo2", "bar2"));
+        db1.getDao().insert(entity1);
+        db2.getDao().insert(entity2);
+        assertThat(db1.getDao().get(1)).isEqualTo(entity1);
+        assertThat(db2.getDao().get(2)).isEqualTo(entity2);
+        assertThat(db1.getDao().getRawUsername(1)).isEqualTo("foo1-bar1");
+        assertThat(db2.getDao().getRawUsername(2)).isEqualTo("bar2-foo2");
+    }
+
+    @Database(entities = {Pet.class, Toy.class, User.class, Robot.class, Hivemind.class},
+            views = {PetWithUser.class},
+            version = 1, exportSchema = false)
+    @TypeConverters({TimeStampConverter.class, UUIDConverter.class})
+    abstract static class TestDatabaseWithConverter extends RoomDatabase {
+        public abstract PetDao getPetDao();
+
+        public abstract RobotsDao getRobotsDao();
+    }
+
+
+
+    @Database(entities = {ProvidedTypeConverterEntity.class}, version = 1, exportSchema = false)
+    @TypeConverters(NameLastNameSerializer.class)
+    abstract static class ProvidedTypeConverterNameLastNameDb extends
+            ProvidedTypeConverterEntityDb {
+    }
+
+    @Database(entities = {ProvidedTypeConverterEntity.class}, version = 1, exportSchema = false)
+    @TypeConverters(LastNameNameSerializer.class)
+    abstract static class ProvidedTypeConverterLastNameNameDb extends
+            ProvidedTypeConverterEntityDb {
+    }
+
+    abstract static class ProvidedTypeConverterEntityDb extends RoomDatabase {
+        public abstract ProvidedTypeConverterEntity.Dao getDao();
+    }
+
+    @ProvidedTypeConverter
+    public static class TimeStampConverter {
+        @TypeConverter
+        public Date fromTimestamp(Long value) {
+            return value == null ? null : new Date(value);
+        }
+
+        @TypeConverter
+        public Long dateToTimestamp(Date date) {
+            if (date == null) {
+                return null;
+            } else {
+                return date.getTime();
+            }
+        }
+    }
+
+    @ProvidedTypeConverter
+    public static class UUIDConverter {
+        @TypeConverter
+        public UUID asUuid(byte[] bytes) {
+            ByteBuffer bb = ByteBuffer.wrap(bytes);
+            long firstLong = bb.getLong();
+            long secondLong = bb.getLong();
+            return new UUID(firstLong, secondLong);
+        }
+
+        @TypeConverter
+        public byte[] asBytes(UUID uuid) {
+            ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
+            bb.putLong(uuid.getMostSignificantBits());
+            bb.putLong(uuid.getLeastSignificantBits());
+            return bb.array();
+        }
+    }
+
+    @Entity
+    public static class ProvidedTypeConverterEntity {
+        @PrimaryKey
+        private final int mId;
+        private final Username mUsername;
+
+        public ProvidedTypeConverterEntity(int id, Username username) {
+            mId = id;
+            mUsername = username;
+        }
+
+        public int getId() {
+            return mId;
+        }
+
+        public Username getUsername() {
+            return mUsername;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            ProvidedTypeConverterEntity that = (ProvidedTypeConverterEntity) o;
+            return mId == that.mId &&
+                    mUsername.equals(that.mUsername);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mId, mUsername);
+        }
+
+        @androidx.room.Dao
+        public interface Dao {
+            @Insert
+            void insert(ProvidedTypeConverterEntity entity);
+
+            @Query("SELECT mUsername FROM ProvidedTypeConverterEntity WHERE mId = :id")
+            String getRawUsername(int id);
+
+            @Query("SELECT * FROM ProvidedTypeConverterEntity WHERE mId = :id")
+            ProvidedTypeConverterEntity get(int id);
+        }
+    }
+
+    /**
+     * Class that is serialized differently based on database
+     */
+    public static class Username {
+        @NonNull
+        private final String mName;
+        @NonNull
+        private final String mLastName;
+
+        public Username(@NonNull String name, @NonNull String lastName) {
+            mName = name;
+            mLastName = lastName;
+        }
+
+        @NonNull
+        public String getName() {
+            return mName;
+        }
+
+        @NonNull
+        public String getLastName() {
+            return mLastName;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            Username username = (Username) o;
+            return mName.equals(username.mName) &&
+                    mLastName.equals(username.mLastName);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mName, mLastName);
+        }
+    }
+
+    @ProvidedTypeConverter
+    public class NameLastNameSerializer {
+        @TypeConverter
+        public Username fromString(String input) {
+            String[] sections = input.split("-");
+            return new Username(sections[0], sections[1]);
+        }
+
+        @TypeConverter
+        public String toString(Username input) {
+            return input.getName() + "-" + input.getLastName();
+        }
+    }
+
+    @ProvidedTypeConverter
+    public class LastNameNameSerializer {
+        @TypeConverter
+        public Username fromString(String input) {
+            String[] sections = input.split("-");
+            return new Username(sections[1], sections[0]);
+        }
+
+        @TypeConverter
+        public String toString(Username input) {
+            return input.getLastName() + "-" + input.getName();
+        }
+    }
+}
diff --git a/room/runtime/api/current.txt b/room/runtime/api/current.txt
index 6690920..821e4d8 100644
--- a/room/runtime/api/current.txt
+++ b/room/runtime/api/current.txt
@@ -20,6 +20,7 @@
     field public final boolean requireMigration;
     field public final androidx.sqlite.db.SupportSQLiteOpenHelper.Factory sqliteOpenHelperFactory;
     field public final java.util.concurrent.Executor transactionExecutor;
+    field public final java.util.List<java.lang.Object!> typeConverters;
   }
 
   public class InvalidationTracker {
@@ -54,6 +55,7 @@
     method public androidx.sqlite.db.SupportSQLiteOpenHelper getOpenHelper();
     method public java.util.concurrent.Executor getQueryExecutor();
     method public java.util.concurrent.Executor getTransactionExecutor();
+    method public <T> T? getTypeConverter(Class<T!>);
     method public boolean inTransaction();
     method @CallSuper public void init(androidx.room.DatabaseConfiguration);
     method protected void internalInitInvalidationTracker(androidx.sqlite.db.SupportSQLiteDatabase);
@@ -70,6 +72,7 @@
   public static class RoomDatabase.Builder<T extends androidx.room.RoomDatabase> {
     method public androidx.room.RoomDatabase.Builder<T!> addCallback(androidx.room.RoomDatabase.Callback);
     method public androidx.room.RoomDatabase.Builder<T!> addMigrations(androidx.room.migration.Migration!...);
+    method public androidx.room.RoomDatabase.Builder<T!> addTypeConverter(Object);
     method public androidx.room.RoomDatabase.Builder<T!> allowMainThreadQueries();
     method public T build();
     method public androidx.room.RoomDatabase.Builder<T!> createFromAsset(String);
diff --git a/room/runtime/api/public_plus_experimental_current.txt b/room/runtime/api/public_plus_experimental_current.txt
index 6690920..af7f13c 100644
--- a/room/runtime/api/public_plus_experimental_current.txt
+++ b/room/runtime/api/public_plus_experimental_current.txt
@@ -20,6 +20,7 @@
     field public final boolean requireMigration;
     field public final androidx.sqlite.db.SupportSQLiteOpenHelper.Factory sqliteOpenHelperFactory;
     field public final java.util.concurrent.Executor transactionExecutor;
+    field public final java.util.List<java.lang.Object!> typeConverters;
   }
 
   public class InvalidationTracker {
@@ -53,7 +54,9 @@
     method public androidx.room.InvalidationTracker getInvalidationTracker();
     method public androidx.sqlite.db.SupportSQLiteOpenHelper getOpenHelper();
     method public java.util.concurrent.Executor getQueryExecutor();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) protected java.util.Map<java.lang.Class<?>!,java.util.List<java.lang.Class<?>!>!> getRequiredTypeConverters();
     method public java.util.concurrent.Executor getTransactionExecutor();
+    method public <T> T? getTypeConverter(Class<T!>);
     method public boolean inTransaction();
     method @CallSuper public void init(androidx.room.DatabaseConfiguration);
     method protected void internalInitInvalidationTracker(androidx.sqlite.db.SupportSQLiteDatabase);
@@ -70,6 +73,7 @@
   public static class RoomDatabase.Builder<T extends androidx.room.RoomDatabase> {
     method public androidx.room.RoomDatabase.Builder<T!> addCallback(androidx.room.RoomDatabase.Callback);
     method public androidx.room.RoomDatabase.Builder<T!> addMigrations(androidx.room.migration.Migration!...);
+    method public androidx.room.RoomDatabase.Builder<T!> addTypeConverter(Object);
     method public androidx.room.RoomDatabase.Builder<T!> allowMainThreadQueries();
     method public T build();
     method public androidx.room.RoomDatabase.Builder<T!> createFromAsset(String);
diff --git a/room/runtime/api/restricted_current.txt b/room/runtime/api/restricted_current.txt
index 60e1d8c..a08ad59 100644
--- a/room/runtime/api/restricted_current.txt
+++ b/room/runtime/api/restricted_current.txt
@@ -6,7 +6,8 @@
     ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode!, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?);
     ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode!, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?);
     ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?, java.util.concurrent.Callable<java.io.InputStream!>?);
-    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?, java.util.concurrent.Callable<java.io.InputStream!>?, androidx.room.RoomDatabase.PrepackagedDatabaseCallback?);
+    ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?, java.util.concurrent.Callable<java.io.InputStream!>?, androidx.room.RoomDatabase.PrepackagedDatabaseCallback?);
+    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public DatabaseConfiguration(android.content.Context, String?, androidx.sqlite.db.SupportSQLiteOpenHelper.Factory, androidx.room.RoomDatabase.MigrationContainer, java.util.List<androidx.room.RoomDatabase.Callback!>?, boolean, androidx.room.RoomDatabase.JournalMode, java.util.concurrent.Executor, java.util.concurrent.Executor, boolean, boolean, boolean, java.util.Set<java.lang.Integer!>?, String?, java.io.File?, java.util.concurrent.Callable<java.io.InputStream!>?, androidx.room.RoomDatabase.PrepackagedDatabaseCallback?, java.util.List<java.lang.Object!>?);
     method public boolean isMigrationRequired(int, int);
     method @Deprecated public boolean isMigrationRequiredFrom(int);
     field public final boolean allowDestructiveMigrationOnDowngrade;
@@ -25,6 +26,7 @@
     field public final boolean requireMigration;
     field public final androidx.sqlite.db.SupportSQLiteOpenHelper.Factory sqliteOpenHelperFactory;
     field public final java.util.concurrent.Executor transactionExecutor;
+    field public final java.util.List<java.lang.Object!> typeConverters;
   }
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public abstract class EntityDeletionOrUpdateAdapter<T> extends androidx.room.SharedSQLiteStatement {
@@ -94,6 +96,7 @@
     method public androidx.sqlite.db.SupportSQLiteOpenHelper getOpenHelper();
     method public java.util.concurrent.Executor getQueryExecutor();
     method public java.util.concurrent.Executor getTransactionExecutor();
+    method public <T> T? getTypeConverter(Class<T!>);
     method public boolean inTransaction();
     method @CallSuper public void init(androidx.room.DatabaseConfiguration);
     method protected void internalInitInvalidationTracker(androidx.sqlite.db.SupportSQLiteDatabase);
@@ -112,6 +115,7 @@
   public static class RoomDatabase.Builder<T extends androidx.room.RoomDatabase> {
     method public androidx.room.RoomDatabase.Builder<T!> addCallback(androidx.room.RoomDatabase.Callback);
     method public androidx.room.RoomDatabase.Builder<T!> addMigrations(androidx.room.migration.Migration!...);
+    method public androidx.room.RoomDatabase.Builder<T!> addTypeConverter(Object);
     method public androidx.room.RoomDatabase.Builder<T!> allowMainThreadQueries();
     method public T build();
     method public androidx.room.RoomDatabase.Builder<T!> createFromAsset(String);
diff --git a/room/runtime/src/main/java/androidx/room/DatabaseConfiguration.java b/room/runtime/src/main/java/androidx/room/DatabaseConfiguration.java
index 753ae77..d19c0cb 100644
--- a/room/runtime/src/main/java/androidx/room/DatabaseConfiguration.java
+++ b/room/runtime/src/main/java/androidx/room/DatabaseConfiguration.java
@@ -26,6 +26,7 @@
 
 import java.io.File;
 import java.io.InputStream;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.Callable;
@@ -65,6 +66,9 @@
     @Nullable
     public final RoomDatabase.PrepackagedDatabaseCallback prepackagedDatabaseCallback;
 
+    @NonNull
+    public final List<Object> typeConverters;
+
     /**
      * Whether Room should throw an exception for queries run on the main thread.
      */
@@ -136,7 +140,7 @@
      * @deprecated Use {@link #DatabaseConfiguration(Context, String,
      * SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
      * RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
-     * Callable, RoomDatabase.PrepackagedDatabaseCallback)}
+     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>)}
      *
      * @param context The application context.
      * @param name Name of the database, can be null if it is in memory.
@@ -166,7 +170,7 @@
             @Nullable Set<Integer> migrationNotRequiredFrom) {
         this(context, name, sqliteOpenHelperFactory, migrationContainer, callbacks,
                 allowMainThreadQueries, journalMode, queryExecutor, queryExecutor, false,
-                requireMigration, false, migrationNotRequiredFrom, null, null, null, null);
+                requireMigration, false, migrationNotRequiredFrom, null, null, null, null, null);
     }
 
     /**
@@ -175,7 +179,7 @@
      * @deprecated Use {@link #DatabaseConfiguration(Context, String,
      * SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
      * RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
-     * Callable, RoomDatabase.PrepackagedDatabaseCallback)}
+     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>)}
      *
      * @param context The application context.
      * @param name Name of the database, can be null if it is in memory.
@@ -212,7 +216,7 @@
         this(context, name, sqliteOpenHelperFactory, migrationContainer, callbacks,
                 allowMainThreadQueries, journalMode, queryExecutor, transactionExecutor,
                 multiInstanceInvalidation, requireMigration, allowDestructiveMigrationOnDowngrade,
-                migrationNotRequiredFrom, null, null, null, null);
+                migrationNotRequiredFrom, null, null, null, null, null);
     }
 
     /**
@@ -221,7 +225,7 @@
      * @deprecated Use {@link #DatabaseConfiguration(Context, String,
      * SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
      * RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
-     * Callable, RoomDatabase.PrepackagedDatabaseCallback)}
+     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>)}
      *
      * @param context The application context.
      * @param name Name of the database, can be null if it is in memory.
@@ -262,7 +266,7 @@
         this(context, name, sqliteOpenHelperFactory, migrationContainer, callbacks,
                 allowMainThreadQueries, journalMode, queryExecutor, transactionExecutor,
                 multiInstanceInvalidation, requireMigration, allowDestructiveMigrationOnDowngrade,
-                migrationNotRequiredFrom, copyFromAssetPath, copyFromFile, null, null);
+                migrationNotRequiredFrom, copyFromAssetPath, copyFromFile, null, null, null);
     }
 
     /**
@@ -271,7 +275,7 @@
      * @deprecated Use {@link #DatabaseConfiguration(Context, String,
      * SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
      * RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
-     * Callable, RoomDatabase.PrepackagedDatabaseCallback)}
+     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>)}
      *
      * @param context The application context.
      * @param name Name of the database, can be null if it is in memory.
@@ -316,7 +320,64 @@
                 allowMainThreadQueries, journalMode, queryExecutor, transactionExecutor,
                 multiInstanceInvalidation, requireMigration, allowDestructiveMigrationOnDowngrade,
                 migrationNotRequiredFrom, copyFromAssetPath, copyFromFile, copyFromInputStream,
-                null);
+                null, null);
+    }
+
+     /**
+      * Creates a database configuration with the given values.
+      *
+      * @deprecated Use {@link #DatabaseConfiguration(Context, String,
+     * SupportSQLiteOpenHelper.Factory, RoomDatabase.MigrationContainer, List, boolean,
+     * RoomDatabase.JournalMode, Executor, Executor, boolean, boolean, boolean, Set, String, File,
+     * Callable, RoomDatabase.PrepackagedDatabaseCallback, List<Object>)}
+     *
+     * @param context The application context.
+     * @param name Name of the database, can be null if it is in memory.
+     * @param sqliteOpenHelperFactory The open helper factory to use.
+     * @param migrationContainer The migration container for migrations.
+     * @param callbacks The list of callbacks for database events.
+     * @param allowMainThreadQueries Whether to allow main thread reads/writes or not.
+     * @param journalMode The journal mode. This has to be either TRUNCATE or WRITE_AHEAD_LOGGING.
+     * @param queryExecutor The Executor used to execute asynchronous queries.
+     * @param transactionExecutor The Executor used to execute asynchronous transactions.
+     * @param multiInstanceInvalidation True if Room should perform multi-instance invalidation.
+     * @param requireMigration True if Room should require a valid migration if version changes,
+     * @param allowDestructiveMigrationOnDowngrade True if Room should recreate tables if no
+     *                                             migration is supplied during a downgrade.
+     * @param migrationNotRequiredFrom The collection of schema versions from which migrations
+     *                                 aren't required.
+     * @param copyFromAssetPath The assets path to the pre-packaged database.
+     * @param copyFromFile The pre-packaged database file.
+     * @param copyFromInputStream The callable to get the input stream from which a
+     *                            pre-package database file will be copied from.
+     * @param prepackagedDatabaseCallback The pre-packaged callback.
+     *
+     * @hide
+     */
+    @Deprecated
+    @SuppressLint("LambdaLast")
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+    public DatabaseConfiguration(@NonNull Context context, @Nullable String name,
+            @NonNull SupportSQLiteOpenHelper.Factory sqliteOpenHelperFactory,
+            @NonNull RoomDatabase.MigrationContainer migrationContainer,
+            @Nullable List<RoomDatabase.Callback> callbacks,
+            boolean allowMainThreadQueries,
+            @NonNull RoomDatabase.JournalMode journalMode,
+            @NonNull Executor queryExecutor,
+            @NonNull Executor transactionExecutor,
+            boolean multiInstanceInvalidation,
+            boolean requireMigration,
+            boolean allowDestructiveMigrationOnDowngrade,
+            @Nullable Set<Integer> migrationNotRequiredFrom,
+            @Nullable String copyFromAssetPath,
+            @Nullable File copyFromFile,
+            @Nullable Callable<InputStream> copyFromInputStream,
+            @Nullable RoomDatabase.PrepackagedDatabaseCallback prepackagedDatabaseCallback) {
+        this(context, name, sqliteOpenHelperFactory, migrationContainer, callbacks,
+                allowMainThreadQueries, journalMode, queryExecutor, transactionExecutor,
+                multiInstanceInvalidation, requireMigration, allowDestructiveMigrationOnDowngrade,
+                migrationNotRequiredFrom, copyFromAssetPath, copyFromFile, copyFromInputStream,
+                prepackagedDatabaseCallback, null);
     }
 
     /**
@@ -342,6 +403,7 @@
      * @param copyFromInputStream The callable to get the input stream from which a
      *                            pre-package database file will be copied from.
      * @param prepackagedDatabaseCallback The pre-packaged callback.
+     * @param typeConverters The type converters.
      *
      * @hide
      */
@@ -362,7 +424,8 @@
             @Nullable String copyFromAssetPath,
             @Nullable File copyFromFile,
             @Nullable Callable<InputStream> copyFromInputStream,
-            @Nullable RoomDatabase.PrepackagedDatabaseCallback prepackagedDatabaseCallback) {
+            @Nullable RoomDatabase.PrepackagedDatabaseCallback prepackagedDatabaseCallback,
+            @Nullable List<Object> typeConverters) {
         this.sqliteOpenHelperFactory = sqliteOpenHelperFactory;
         this.context = context;
         this.name = name;
@@ -380,6 +443,7 @@
         this.copyFromFile = copyFromFile;
         this.copyFromInputStream = copyFromInputStream;
         this.prepackagedDatabaseCallback = prepackagedDatabaseCallback;
+        this.typeConverters = typeConverters == null ? Collections.emptyList() : typeConverters;
     }
 
     /**
diff --git a/room/runtime/src/main/java/androidx/room/RoomDatabase.java b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
index 97f40e6..88f427d 100644
--- a/room/runtime/src/main/java/androidx/room/RoomDatabase.java
+++ b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
@@ -44,6 +44,7 @@
 import java.io.File;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.BitSet;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -141,6 +142,23 @@
         return mBackingFieldMap;
     }
 
+    // Updated later to an unmodifiable map when init is called.
+    private final Map<Class<?>, Object> mTypeConverters;
+
+
+    /**
+     * Gets the instance of the given Type Converter.
+     *
+     * @param klass The Type Converter class.
+     * @param <T> The type of the expected Type Converter subclass.
+     * @return An instance of T if it is provided in the builder.
+     */
+    @SuppressWarnings("unchecked")
+    @Nullable
+    public <T> T getTypeConverter(@NonNull Class<T> klass) {
+        return (T) mTypeConverters.get(klass);
+    }
+
     /**
      * Creates a RoomDatabase.
      * <p>
@@ -150,6 +168,7 @@
      */
     public RoomDatabase() {
         mInvalidationTracker = createInvalidationTracker();
+        mTypeConverters = new HashMap<>();
     }
 
     /**
@@ -178,6 +197,45 @@
             mInvalidationTracker.startMultiInstanceInvalidation(configuration.context,
                     configuration.name);
         }
+
+        Map<Class<?>, List<Class<?>>> requiredFactories = getRequiredTypeConverters();
+        // indices for each converter on whether it is used or not so that we can throw an exception
+        // if developer provides an unused converter. It is not necessarily an error but likely
+        // to be because why would developer add a converter if it won't be used?
+        BitSet used = new BitSet();
+        for (Map.Entry<Class<?>, List<Class<?>>> entry : requiredFactories.entrySet()) {
+            Class<?> daoName = entry.getKey();
+            for (Class<?> converter : entry.getValue()) {
+                int foundIndex = -1;
+                // traverse provided converters in reverse so that newer one overrides
+                for (int providedIndex = configuration.typeConverters.size() - 1;
+                        providedIndex >= 0; providedIndex--) {
+                    Object provided = configuration.typeConverters.get(providedIndex);
+                    if (converter.isAssignableFrom(provided.getClass())) {
+                        foundIndex = providedIndex;
+                        used.set(foundIndex);
+                        break;
+                    }
+                }
+                if (foundIndex < 0) {
+                    throw new IllegalArgumentException(
+                            "A required type converter (" + converter + ") for"
+                                    + " " + daoName.getCanonicalName()
+                                    + " is missing in the database configuration.");
+                }
+                mTypeConverters.put(converter, configuration.typeConverters.get(foundIndex));
+            }
+        }
+        // now, make sure all provided factories are used
+        for (int providedIndex = configuration.typeConverters.size() - 1;
+                providedIndex >= 0; providedIndex--) {
+            if (!used.get(providedIndex)) {
+                Object converter = configuration.typeConverters.get(providedIndex);
+                throw new IllegalArgumentException("Unexpected type converter " + converter + ". "
+                        + "Annotate TypeConverter class with @ProvidedTypeConverter annotation "
+                        + "or remove this converter from the builder.");
+            }
+        }
     }
 
     /**
@@ -212,6 +270,21 @@
     protected abstract InvalidationTracker createInvalidationTracker();
 
     /**
+     * Returns a Map of String -> List&lt;Class&gt; where each entry has the `key` as the DAO name
+     * and `value` as the list of type converter classes that are necessary for the database to
+     * function.
+     * <p>
+     * This is implemented by the generated code.
+     *
+     * @return Creates a map that will include all required type converters for this database.
+     */
+    @NonNull
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    protected Map<Class<?>, List<Class<?>>> getRequiredTypeConverters() {
+        return Collections.emptyMap();
+    }
+
+    /**
      * Deletes all rows from all the tables that are registered to this database as
      * {@link Database#entities()}.
      * <p>
@@ -542,6 +615,7 @@
         private final Context mContext;
         private ArrayList<Callback> mCallbacks;
         private PrepackagedDatabaseCallback mPrepackagedDatabaseCallback;
+        private List<Object> mTypeConverters;
 
         /** The Executor used to run database queries. This should be background-threaded. */
         private Executor mQueryExecutor;
@@ -1013,6 +1087,22 @@
         }
 
         /**
+         * Adds a type converter instance to this database.
+         *
+         * @param typeConverter The converter. It must be an instance of a class annotated with
+         * {@link ProvidedTypeConverter} otherwise Room will throw an exception.
+         * @return This {@link Builder} instance.
+         */
+        @NonNull
+        public Builder<T> addTypeConverter(@NonNull Object typeConverter) {
+            if (mTypeConverters == null) {
+                mTypeConverters = new ArrayList<>();
+            }
+            mTypeConverters.add(typeConverter);
+            return this;
+        }
+
+        /**
          * Creates the databases and initializes it.
          * <p>
          * By default, all RoomDatabases use in memory storage for TEMP tables and enables recursive
@@ -1096,7 +1186,8 @@
                             mCopyFromAssetPath,
                             mCopyFromFile,
                             mCopyFromInputStream,
-                            mPrepackagedDatabaseCallback);
+                            mPrepackagedDatabaseCallback,
+                            mTypeConverters);
             T db = Room.getGeneratedImplementation(mDatabaseClass, DB_IMPL_SUFFIX);
             db.init(configuration);
             return db;
diff --git a/room/testing/src/main/java/androidx/room/testing/MigrationTestHelper.java b/room/testing/src/main/java/androidx/room/testing/MigrationTestHelper.java
index baa0f947..fcb1b87 100644
--- a/room/testing/src/main/java/androidx/room/testing/MigrationTestHelper.java
+++ b/room/testing/src/main/java/androidx/room/testing/MigrationTestHelper.java
@@ -168,6 +168,7 @@
                 null,
                 null,
                 null,
+                null,
                 null);
         RoomOpenHelper roomOpenHelper = new RoomOpenHelper(configuration,
                 new CreatingDelegate(schemaBundle.getDatabase()),
@@ -230,6 +231,7 @@
                 null,
                 null,
                 null,
+                null,
                 null);
         RoomOpenHelper roomOpenHelper = new RoomOpenHelper(configuration,
                 new MigratingDelegate(schemaBundle.getDatabase(), validateDroppedTables),
diff --git a/settings.gradle b/settings.gradle
index f5c4824..a711917 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -87,6 +87,7 @@
 includeProject(":autofill:autofill", "autofill/autofill")
 includeProject(":benchmark:benchmark-common", "benchmark/common")
 includeProject(":benchmark:benchmark-junit4", "benchmark/junit4")
+includeProject(":benchmark:benchmark-macro", "benchmark/macro")
 includeProject(":benchmark:benchmark-benchmark", "benchmark/benchmark")
 includeProject(":benchmark:benchmark-gradle-plugin", "benchmark/gradle-plugin")
 includeProject(":benchmark:integration-tests:dry-run-benchmark", "benchmark/integration-tests/dry-run-benchmark")
diff --git a/slices/builders/api/current.txt b/slices/builders/api/current.txt
index 3898425..acd2a0f 100644
--- a/slices/builders/api/current.txt
+++ b/slices/builders/api/current.txt
@@ -38,7 +38,7 @@
     method public androidx.slice.builders.ListBuilder addSelection(androidx.slice.builders.SelectionBuilder);
     method public androidx.slice.builders.ListBuilder setAccentColor(@ColorInt int);
     method public androidx.slice.builders.ListBuilder setHeader(androidx.slice.builders.ListBuilder.HeaderBuilder);
-    method public androidx.slice.builders.ListBuilder setHostExtra(String, String);
+    method @RequiresApi(21) public androidx.slice.builders.ListBuilder setHostExtras(android.os.PersistableBundle);
     method public androidx.slice.builders.ListBuilder setIsError(boolean);
     method public androidx.slice.builders.ListBuilder setKeywords(java.util.Set<java.lang.String!>);
     method public androidx.slice.builders.ListBuilder setLayoutDirection(int);
diff --git a/slices/builders/api/public_plus_experimental_current.txt b/slices/builders/api/public_plus_experimental_current.txt
index 3898425..acd2a0f 100644
--- a/slices/builders/api/public_plus_experimental_current.txt
+++ b/slices/builders/api/public_plus_experimental_current.txt
@@ -38,7 +38,7 @@
     method public androidx.slice.builders.ListBuilder addSelection(androidx.slice.builders.SelectionBuilder);
     method public androidx.slice.builders.ListBuilder setAccentColor(@ColorInt int);
     method public androidx.slice.builders.ListBuilder setHeader(androidx.slice.builders.ListBuilder.HeaderBuilder);
-    method public androidx.slice.builders.ListBuilder setHostExtra(String, String);
+    method @RequiresApi(21) public androidx.slice.builders.ListBuilder setHostExtras(android.os.PersistableBundle);
     method public androidx.slice.builders.ListBuilder setIsError(boolean);
     method public androidx.slice.builders.ListBuilder setKeywords(java.util.Set<java.lang.String!>);
     method public androidx.slice.builders.ListBuilder setLayoutDirection(int);
diff --git a/slices/builders/api/restricted_current.txt b/slices/builders/api/restricted_current.txt
index a658151..f013db9 100644
--- a/slices/builders/api/restricted_current.txt
+++ b/slices/builders/api/restricted_current.txt
@@ -38,7 +38,7 @@
     method public androidx.slice.builders.ListBuilder addSelection(androidx.slice.builders.SelectionBuilder);
     method public androidx.slice.builders.ListBuilder setAccentColor(@ColorInt int);
     method public androidx.slice.builders.ListBuilder setHeader(androidx.slice.builders.ListBuilder.HeaderBuilder);
-    method public androidx.slice.builders.ListBuilder setHostExtra(String, String);
+    method @RequiresApi(21) public androidx.slice.builders.ListBuilder setHostExtras(android.os.PersistableBundle);
     method public androidx.slice.builders.ListBuilder setIsError(boolean);
     method public androidx.slice.builders.ListBuilder setKeywords(java.util.Set<java.lang.String!>);
     method public androidx.slice.builders.ListBuilder setLayoutDirection(int);
diff --git a/slices/builders/src/main/java/androidx/slice/builders/ListBuilder.java b/slices/builders/src/main/java/androidx/slice/builders/ListBuilder.java
index a507b3e..c20cac1 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/ListBuilder.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/ListBuilder.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
+import android.os.PersistableBundle;
 import android.view.View;
 
 import androidx.annotation.ColorInt;
@@ -385,12 +386,12 @@
     /**
      * Sets additional information to be passed to the host of the slice.
      *
-     * @param key The name of the extra data
-     * @param value The String data value
+     * @param extras The Bundle of extras to add to this slice.
      */
     @NonNull
-    public ListBuilder setHostExtra(@NonNull String key, @NonNull String value) {
-        mImpl.setHostExtra(key, value);
+    @RequiresApi(21)
+    public ListBuilder setHostExtras(@NonNull PersistableBundle extras) {
+        mImpl.setHostExtras(extras);
         return this;
     }
 
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java
index 8de49db..a54e56d 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java
@@ -19,6 +19,7 @@
 import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 
 import android.app.PendingIntent;
+import android.os.PersistableBundle;
 
 import androidx.annotation.ColorInt;
 import androidx.annotation.NonNull;
@@ -146,9 +147,9 @@
     /**
      * Sets additional information to be passed to the host of the slice.
      *
-     * @param key The name of the extra data
-     * @param value The String data value
+     * @param extras The Bundle of extras to add to this slice.
      */
-    void setHostExtra(@NonNull String key, @NonNull String value);
+    @RequiresApi(21)
+    void setHostExtras(@NonNull PersistableBundle extras);
 }
 
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java
index f41ab33..d008227 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java
@@ -32,6 +32,7 @@
 
 import android.app.PendingIntent;
 import android.os.Bundle;
+import android.os.PersistableBundle;
 
 import androidx.annotation.ColorInt;
 import androidx.annotation.NonNull;
@@ -243,11 +244,17 @@
     }
 
     @Override
-    public void setHostExtra(@NonNull String key, @NonNull String value) {
-        if (mHostExtras == null) {
-            mHostExtras = new Bundle();
+    @RequiresApi(21)
+    public void setHostExtras(@NonNull PersistableBundle extras) {
+        mHostExtras = ConvertPersistableBundleApi21Impl.toBundle(extras);
+    }
+
+    @RequiresApi(21)
+    private static class ConvertPersistableBundleApi21Impl {
+        private ConvertPersistableBundleApi21Impl() {}
+        static Bundle toBundle(@NonNull PersistableBundle extras) {
+            return new Bundle(extras);
         }
-        mHostExtras.putString(key, value);
     }
 
     /**
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderImpl.java b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderImpl.java
index a4b5984..835b0ac 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderImpl.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderImpl.java
@@ -51,6 +51,7 @@
 import android.app.PendingIntent;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.PersistableBundle;
 
 import androidx.annotation.ColorInt;
 import androidx.annotation.NonNull;
@@ -306,11 +307,17 @@
     }
 
     @Override
-    public void setHostExtra(@NonNull String key, @NonNull String value) {
-        if (mHostExtras == null) {
-            mHostExtras = new Bundle();
+    @RequiresApi(21)
+    public void setHostExtras(@NonNull PersistableBundle extras) {
+        mHostExtras = ConvertPersistableBundleApi21Impl.toBundle(extras);
+    }
+
+    @RequiresApi(21)
+    private static class ConvertPersistableBundleApi21Impl {
+        private ConvertPersistableBundleApi21Impl() {}
+        static Bundle toBundle(@NonNull PersistableBundle extras) {
+            return new Bundle(extras);
         }
-        mHostExtras.putString(key, value);
     }
 
 
diff --git a/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java b/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java
index 4e52c6b..d770648 100644
--- a/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java
+++ b/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java
@@ -31,7 +31,9 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
+import android.os.Build;
 import android.os.Handler;
+import android.os.PersistableBundle;
 import android.provider.Settings;
 import android.text.SpannableString;
 import android.text.TextUtils;
@@ -1397,11 +1399,7 @@
     }
 
     private Slice createTtsSlice(Uri sliceUri) {
-        Slice slice = new ListBuilder(getContext(), sliceUri, INFINITY)
-                // Attach additional information for host. Depending on the host apps, this
-                // information might or might not be used.
-                // In this case, SliceBrowser is customized to play TTS when binding the slice.
-                .setHostExtra("tts", "hello world")
+        ListBuilder slice = new ListBuilder(getContext(), sliceUri, INFINITY)
                 .addRow(
                         new RowBuilder().setPrimaryAction(
                                 SliceAction.create(
@@ -1410,8 +1408,25 @@
                                                 R.drawable.message),
                                         ICON_IMAGE, "TTS"
                                 )
-                        ).setTitle("Text to speech").setSubtitle("Play")).build();
-        return slice;
+                        ).setTitle("Text to speech").setSubtitle("Play"));
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            SetHostExtraApi21Impl.setHostExtra(slice, "tts", "hello world");
+        }
+
+        return slice.build();
+    }
+
+    @RequiresApi(21)
+    private static class SetHostExtraApi21Impl {
+        private SetHostExtraApi21Impl() {}
+        static void setHostExtra(ListBuilder listBuilder, String key, String value) {
+            PersistableBundle extras = new PersistableBundle();
+            extras.putString("tts", "hello world");
+            // Attach additional information for host. Depending on the host apps, this
+            // information might or might not be used.
+            // In this case, SliceBrowser is customized to play TTS when binding the slice.
+            listBuilder.setHostExtras(extras);
+        }
     }
 
     private PendingIntent getIntent(String action) {
diff --git a/slices/view/src/main/java/androidx/slice/widget/RowStyle.java b/slices/view/src/main/java/androidx/slice/widget/RowStyle.java
index 05055df..a8dffd3 100644
--- a/slices/view/src/main/java/androidx/slice/widget/RowStyle.java
+++ b/slices/view/src/main/java/androidx/slice/widget/RowStyle.java
@@ -95,7 +95,9 @@
             mDisableRecyclerViewItemAnimator = a.getBoolean(
                     R.styleable.RowStyle_disableRecyclerViewItemAnimator, false);
             mImageSize = (int) a.getDimension(
-                    R.styleable.RowStyle_imageSize, UNBOUNDED);
+                    R.styleable.RowStyle_imageSize,
+                    context.getResources().getDimensionPixelSize(
+                        R.dimen.abc_slice_small_image_size));
         } finally {
             a.recycle();
         }
diff --git a/slices/view/src/main/java/androidx/slice/widget/RowView.java b/slices/view/src/main/java/androidx/slice/widget/RowView.java
index 4a6eed8..9531f93 100644
--- a/slices/view/src/main/java/androidx/slice/widget/RowView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/RowView.java
@@ -178,7 +178,6 @@
 
     private int mImageSize;
     private int mIconSize;
-    private int mStyleRowHeight = HEIGHT_UNBOUND;
     // How big mRangeBar wants to be.
     private int mMeasuredRangeHeight;
 
@@ -921,7 +920,6 @@
                 container.addView(iv);
             }
             if (mSliceStyle != null) {
-                mStyleRowHeight = mSliceStyle.getRowMinHeight();
                 if (mSliceStyle.getRowStyle() != null) {
                     int styleIconSize = mSliceStyle.getRowStyle().getIconSize();
                     mIconSize = styleIconSize > 0 ? styleIconSize : mIconSize;
@@ -936,8 +934,8 @@
             iv.setLayoutParams(lp);
             int p = 0;
             if (isIcon) {
-                p = mStyleRowHeight == HEIGHT_UNBOUND
-                    ? mIconSize / 2 : (mStyleRowHeight - mIconSize) / 2;
+                p = mImageSize == HEIGHT_UNBOUND
+                    ? mIconSize / 2 : (mImageSize - mIconSize) / 2;
             }
             iv.setPadding(p, p, p, p);
             addedView = iv;
diff --git a/slices/view/src/main/java/androidx/slice/widget/SliceActionView.java b/slices/view/src/main/java/androidx/slice/widget/SliceActionView.java
index b2700f5..b3c6b97 100644
--- a/slices/view/src/main/java/androidx/slice/widget/SliceActionView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/SliceActionView.java
@@ -78,7 +78,6 @@
 
     private int mIconSize;
     private int mImageSize;
-    private int mStyleRowHeight = HEIGHT_UNBOUND;
 
     public SliceActionView(Context context, SliceStyle style) {
         super(context);
@@ -86,7 +85,6 @@
         mIconSize = res.getDimensionPixelSize(R.dimen.abc_slice_icon_size);
         mImageSize = res.getDimensionPixelSize(R.dimen.abc_slice_small_image_size);
         if (style != null) {
-            mStyleRowHeight = style.getRowMinHeight();
             if (style.getRowStyle() != null) {
                 mIconSize = style.getRowStyle().getIconSize();
                 mImageSize = style.getRowStyle().getImageSize();
@@ -176,8 +174,8 @@
             mActionView.setLayoutParams(lp);
             int p = 0;
             if (action.getImageMode() == ICON_IMAGE) {
-                p = mStyleRowHeight == HEIGHT_UNBOUND
-                    ? mIconSize / 2 : (mStyleRowHeight - mIconSize) / 2;
+                p = mImageSize == HEIGHT_UNBOUND
+                    ? mIconSize / 2 : (mImageSize - mIconSize) / 2;
             }
             mActionView.setPadding(p, p, p, p);
             int touchFeedbackAttr = android.R.attr.selectableItemBackground;
diff --git a/slices/view/src/main/res/values-bs/strings.xml b/slices/view/src/main/res/values-bs/strings.xml
index cb84c18..2a42cd4 100644
--- a/slices/view/src/main/res/values-bs/strings.xml
+++ b/slices/view/src/main/res/values-bs/strings.xml
@@ -22,9 +22,9 @@
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Prikaži više"</string>
     <string name="abc_slice_updated" msgid="8155085405396453848">"Ažurirano <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
-      <item quantity="one">Prije <xliff:g id="ID_2">%d</xliff:g> min.</item>
-      <item quantity="few">Prije <xliff:g id="ID_2">%d</xliff:g> min.</item>
-      <item quantity="other">Prije <xliff:g id="ID_2">%d</xliff:g> min.</item>
+      <item quantity="one">Prije <xliff:g id="ID_2">%d</xliff:g> min</item>
+      <item quantity="few">Prije <xliff:g id="ID_2">%d</xliff:g> min</item>
+      <item quantity="other">Prije <xliff:g id="ID_2">%d</xliff:g> min</item>
     </plurals>
     <plurals name="abc_slice_duration_years" formatted="false" msgid="6212691832333991589">
       <item quantity="one">Prije <xliff:g id="ID_2">%d</xliff:g> god.</item>
diff --git a/slices/view/src/main/res/values-hy/strings.xml b/slices/view/src/main/res/values-hy/strings.xml
index fcf96af..962f469 100644
--- a/slices/view/src/main/res/values-hy/strings.xml
+++ b/slices/view/src/main/res/values-hy/strings.xml
@@ -19,7 +19,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Ավելին"</string>
-    <string name="abc_slice_show_more" msgid="1567717014004692768">"Ցուցադրել ավելի շատ"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Ցույց տալ ավելի շատ"</string>
     <string name="abc_slice_updated" msgid="8155085405396453848">"Թարմացվել է <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <plurals name="abc_slice_duration_min" formatted="false" msgid="6996334305156847955">
       <item quantity="one"><xliff:g id="ID_2">%d</xliff:g> րոպե առաջ</item>
diff --git a/textclassifier/textclassifier/src/main/res/values-cs/strings.xml b/textclassifier/textclassifier/src/main/res/values-cs/strings.xml
index 2d1c5d2..5a999f5 100644
--- a/textclassifier/textclassifier/src/main/res/values-cs/strings.xml
+++ b/textclassifier/textclassifier/src/main/res/values-cs/strings.xml
@@ -26,7 +26,7 @@
     <string name="sms_desc" msgid="7733202356868441148">"Napsat SMS na vybrané telefonní číslo"</string>
     <string name="add_contact" msgid="386263007484061034">"Přidat"</string>
     <string name="add_contact_desc" msgid="1739272501140197425">"Přidat do kontaktů"</string>
-    <string name="floating_toolbar_open_overflow_description" msgid="6778458701858708647">"Více možností"</string>
+    <string name="floating_toolbar_open_overflow_description" msgid="6778458701858708647">"Další možnosti"</string>
     <string name="floating_toolbar_close_overflow_description" msgid="3112942430227166657">"Zavřít rozbalovací nabídku"</string>
     <string name="abc_share" msgid="37557693057519685">"Sdílet"</string>
 </resources>
diff --git a/tv-provider/tv-provider/api/current.txt b/tv-provider/tv-provider/api/current.txt
index 663790c..1c3721b 100644
--- a/tv-provider/tv-provider/api/current.txt
+++ b/tv-provider/tv-provider/api/current.txt
@@ -467,6 +467,7 @@
     field public static final int ASPECT_RATIO_MOVIE_POSTER = 5; // 0x5
     field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
     field public static final int AVAILABILITY_FREE = 4; // 0x4
+    field public static final int AVAILABILITY_FREE_WITH_ADS = 5; // 0x5
     field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
     field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
     field public static final int AVAILABILITY_PURCHASED = 3; // 0x3
@@ -669,6 +670,7 @@
     field public static final int ASPECT_RATIO_MOVIE_POSTER = 5; // 0x5
     field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
     field public static final int AVAILABILITY_FREE = 4; // 0x4
+    field public static final int AVAILABILITY_FREE_WITH_ADS = 5; // 0x5
     field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
     field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
     field public static final int AVAILABILITY_PURCHASED = 3; // 0x3
diff --git a/tv-provider/tv-provider/api/public_plus_experimental_current.txt b/tv-provider/tv-provider/api/public_plus_experimental_current.txt
index 663790c..1c3721b 100644
--- a/tv-provider/tv-provider/api/public_plus_experimental_current.txt
+++ b/tv-provider/tv-provider/api/public_plus_experimental_current.txt
@@ -467,6 +467,7 @@
     field public static final int ASPECT_RATIO_MOVIE_POSTER = 5; // 0x5
     field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
     field public static final int AVAILABILITY_FREE = 4; // 0x4
+    field public static final int AVAILABILITY_FREE_WITH_ADS = 5; // 0x5
     field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
     field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
     field public static final int AVAILABILITY_PURCHASED = 3; // 0x3
@@ -669,6 +670,7 @@
     field public static final int ASPECT_RATIO_MOVIE_POSTER = 5; // 0x5
     field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
     field public static final int AVAILABILITY_FREE = 4; // 0x4
+    field public static final int AVAILABILITY_FREE_WITH_ADS = 5; // 0x5
     field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
     field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
     field public static final int AVAILABILITY_PURCHASED = 3; // 0x3
diff --git a/tv-provider/tv-provider/api/restricted_current.txt b/tv-provider/tv-provider/api/restricted_current.txt
index 2e09571..7c04939 100644
--- a/tv-provider/tv-provider/api/restricted_current.txt
+++ b/tv-provider/tv-provider/api/restricted_current.txt
@@ -526,6 +526,7 @@
     field public static final int ASPECT_RATIO_MOVIE_POSTER = 5; // 0x5
     field public static final int AVAILABILITY_AVAILABLE = 0; // 0x0
     field public static final int AVAILABILITY_FREE = 4; // 0x4
+    field public static final int AVAILABILITY_FREE_WITH_ADS = 5; // 0x5
     field public static final int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1; // 0x1
     field public static final int AVAILABILITY_PAID_CONTENT = 2; // 0x2
     field public static final int AVAILABILITY_PURCHASED = 3; // 0x3
diff --git a/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/BasePreviewProgram.java b/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/BasePreviewProgram.java
index 97f5f71..99fc0d9 100644
--- a/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/BasePreviewProgram.java
+++ b/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/BasePreviewProgram.java
@@ -107,7 +107,8 @@
             PreviewProgramColumns.AVAILABILITY_FREE_WITH_SUBSCRIPTION,
             PreviewProgramColumns.AVAILABILITY_PAID_CONTENT,
             PreviewProgramColumns.AVAILABILITY_PURCHASED,
-            PreviewProgramColumns.AVAILABILITY_FREE
+            PreviewProgramColumns.AVAILABILITY_FREE,
+            PreviewProgramColumns.AVAILABILITY_FREE_WITH_ADS,
     })
     @Retention(RetentionPolicy.SOURCE)
     @RestrictTo(LIBRARY)
@@ -830,9 +831,11 @@
          * {@link androidx.tvprovider.media.tv.TvContractCompat
          * .PreviewPrograms#AVAILABILITY_PAID_CONTENT},
          * {@link androidx.tvprovider.media.tv.TvContractCompat
-         * .PreviewPrograms#AVAILABILITY_PURCHASED}, and
+         * .PreviewPrograms#AVAILABILITY_PURCHASED},
          * {@link androidx.tvprovider.media.tv.TvContractCompat
-         * .PreviewPrograms#AVAILABILITY_FREE}.
+         * .PreviewPrograms#AVAILABILITY_FREE}, and
+         * {@link androidx.tvprovider.media.tv.TvContractCompat
+         * .PreviewPrograms#AVAILABILITY_FREE_WITH_ADS}.
          *
          * @param availability The availability of the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
diff --git a/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java b/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java
index 05de3ea..dfd6c3a 100644
--- a/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java
+++ b/tv-provider/tv-provider/src/main/java/androidx/tvprovider/media/tv/TvContractCompat.java
@@ -1123,6 +1123,13 @@
         int AVAILABILITY_FREE = 4;
 
         /**
+         * The availability for free with ads content.
+         *
+         * @see #COLUMN_AVAILABILITY
+         */
+        int AVAILABILITY_FREE_WITH_ADS = 5;
+
+        /**
          * The interaction type for "views".
          *
          * @see #COLUMN_INTERACTION_TYPE
diff --git a/ui/settings.gradle b/ui/settings.gradle
index 42928da..b08fe43 100644
--- a/ui/settings.gradle
+++ b/ui/settings.gradle
@@ -52,9 +52,9 @@
 includeProject(":compose:animation:animation-core:samples", "../compose/animation/animation-core/samples")
 includeProject(":compose:animation:animation:integration-tests:animation-demos", "../compose/animation/animation/integration-tests/animation-demos")
 includeProject(":compose:animation:animation:samples", "../compose/animation/animation/samples")
-includeProject(":compose:compose-compiler", "../compose/compose-compiler")
-includeProject(":compose:compose-compiler-hosted", "../compose/compose-compiler-hosted")
-includeProject(":compose:compose-compiler-hosted:integration-tests", "../compose/compose-compiler-hosted/integration-tests")
+includeProject(":compose:compiler:compiler", "../compose/compiler/compiler")
+includeProject(":compose:compiler:compiler-hosted", "../compose/compiler/compiler-hosted")
+includeProject(":compose:compiler:compiler-hosted:integration-tests", "../compose/compiler/compiler-hosted/integration-tests")
 if (!startParameter.projectProperties.containsKey('compose.desktop.disable')) {
     includeProject(":compose:desktop", "../compose/desktop")
     includeProject(":compose:desktop:desktop", "../compose/desktop/desktop")
diff --git a/ui/ui-animation-tooling-internal/src/main/java/androidx/compose/animation/tooling/ComposeAnimation.kt b/ui/ui-animation-tooling-internal/src/main/java/androidx/compose/animation/tooling/ComposeAnimation.kt
index aa14ffb..15fb737 100644
--- a/ui/ui-animation-tooling-internal/src/main/java/androidx/compose/animation/tooling/ComposeAnimation.kt
+++ b/ui/ui-animation-tooling-internal/src/main/java/androidx/compose/animation/tooling/ComposeAnimation.kt
@@ -51,9 +51,9 @@
     val states: Set<Any>
         @Suppress("DocumentExceptions")
         get() =
-        throw UnsupportedOperationException(
-            "Only available when getType() is TRANSITION_ANIMATION"
-        )
+            throw UnsupportedOperationException(
+                "Only available when getType() is TRANSITION_ANIMATION"
+            )
 
     /**
      * A label which can be used to represent the animation as text in Android Studio.
diff --git a/ui/ui-test/build.gradle b/ui/ui-test/build.gradle
index ad41d3b..373bcb3c 100644
--- a/ui/ui-test/build.gradle
+++ b/ui/ui-test/build.gradle
@@ -29,7 +29,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 }
 
 kotlin {
diff --git a/ui/ui-test/src/androidMain/kotlin/androidx/ui/test/AndroidAssertions.kt b/ui/ui-test/src/androidMain/kotlin/androidx/ui/test/AndroidAssertions.kt
index b28b5e3..6ef9bb4 100644
--- a/ui/ui-test/src/androidMain/kotlin/androidx/ui/test/AndroidAssertions.kt
+++ b/ui/ui-test/src/androidMain/kotlin/androidx/ui/test/AndroidAssertions.kt
@@ -62,7 +62,7 @@
         composeView.getLocationInWindow(it)
         Offset(it[0].toFloat(), it[1].toFloat())
     }
-    return boundsInRoot.shift(rootLocationInWindow)
+    return boundsInRoot.translate(rootLocationInWindow)
 }
 
 @OptIn(ExperimentalLayoutNodeApi::class)
diff --git a/ui/ui-test/src/commonMain/kotlin/androidx/ui/test/Actions.kt b/ui/ui-test/src/commonMain/kotlin/androidx/ui/test/Actions.kt
index 4117b30..aeee257 100644
--- a/ui/ui-test/src/commonMain/kotlin/androidx/ui/test/Actions.kt
+++ b/ui/ui-test/src/commonMain/kotlin/androidx/ui/test/Actions.kt
@@ -71,7 +71,7 @@
     val parentInRoot = scrollableNode.componentNode.coordinates.parentCoordinates
         ?.positionInRoot ?: Offset.Zero
 
-    val viewPort = viewPortInParent.shift(parentInRoot)
+    val viewPort = viewPortInParent.translate(parentInRoot)
     val target = Rect(node.positionInRoot, node.size.toSize())
 
     val mustScrollUp = target.bottom > viewPort.bottom
diff --git a/ui/ui-tooling/build.gradle b/ui/ui-tooling/build.gradle
index 8d21b69..e094d2a 100644
--- a/ui/ui-tooling/build.gradle
+++ b/ui/ui-tooling/build.gradle
@@ -29,7 +29,7 @@
 }
 
 dependencies {
-    kotlinPlugin project(path: ":compose:compose-compiler")
+    kotlinPlugin project(path: ":compose:compiler:compiler")
 
     implementation(KOTLIN_STDLIB)
 
diff --git a/ui/ui-tooling/src/main/java/androidx/ui/tooling/preview/Preview.kt b/ui/ui-tooling/src/main/java/androidx/ui/tooling/preview/Preview.kt
index daac164..3c465d1 100644
--- a/ui/ui-tooling/src/main/java/androidx/ui/tooling/preview/Preview.kt
+++ b/ui/ui-tooling/src/main/java/androidx/ui/tooling/preview/Preview.kt
@@ -38,7 +38,7 @@
  * @param heightDp Max height in DP the annotated @[Composable] will be rendered in. Use this to
  * restrict the size of the rendering viewport.
  * @param locale Current user preference for the locale, corresponding to
- * [locale]({@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier) resource
+ * [locale](https://d.android.com/guide/topics/resources/providing-resources.html#LocaleQualifier) resource
  * qualifier. By default, the `default` folder will be used.
  * @param fontScale User preference for the scaling factor for fonts, relative to the base
  * density scaling.
@@ -46,7 +46,7 @@
  * The @[Composable] will be render in the context of a full activity.
  * @param showBackground If true, the @[Composable] will use a default background color.
  * @param backgroundColor The 32-bit ARGB color int for the background or 0 if not set
- * @param uiMode Bit mask of the ui mode as per [android.content.res.Configuration#uiMode]
+ * @param uiMode Bit mask of the ui mode as per [android.content.res.Configuration.uiMode]
  * @param device Device string indicating the device to use in the preview. See the available
  * devices in [Devices].
  */
diff --git a/wear/wear-watchface-data/build.gradle b/wear/wear-watchface-data/build.gradle
index e3f539a..f2cb67a 100644
--- a/wear/wear-watchface-data/build.gradle
+++ b/wear/wear-watchface-data/build.gradle
@@ -29,10 +29,12 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
+    api("androidx.versionedparcelable:versionedparcelable:1.1.0")
     api(project(":wear:wear-complications-data"))
     api(KOTLIN_STDLIB)
 
     implementation("androidx.core:core:1.1.0")
+    annotationProcessor(project(":versionedparcelable:versionedparcelable-compiler"))
 }
 
 android {
diff --git a/wear/wear-watchface-data/src/main/aidl/android/support/wearable/watchface/IWatchFaceCommand.aidl b/wear/wear-watchface-data/src/main/aidl/android/support/wearable/watchface/IWatchFaceCommand.aidl
index 2e0f8a0..2c65ffa 100644
--- a/wear/wear-watchface-data/src/main/aidl/android/support/wearable/watchface/IWatchFaceCommand.aidl
+++ b/wear/wear-watchface-data/src/main/aidl/android/support/wearable/watchface/IWatchFaceCommand.aidl
@@ -17,6 +17,9 @@
 package android.support.wearable.watchface;
 
 import android.support.wearable.complications.ComplicationData;
+import androidx.wear.watchface.data.ImmutableSystemState;
+import androidx.wear.watchface.data.IndicatorState;
+import androidx.wear.watchface.data.SystemState;
 
 /**
  * Interface for controlling the watchface from the wearable device.
@@ -48,30 +51,18 @@
     /**
      * Sends the current system state to the Watch Face.
      */
-    void setSystemState(
-        in boolean inAmbientMode,
-        in int interruptionFilter,
-        in int unreadCount,
-        in int notificationCount
-    ) = 3;
+    void setSystemState(in SystemState systemState) = 3;
 
     /**
-     * Sends the current system state to the Watch Face, only called if
+     * Sends the current watch indicator state to the Watch Face, only called if
      * {@link WatchFaceStyle#hideNotificationIndicator} is true.
      */
-    void setIndicatorState(
-        in boolean isCharging,
-        in boolean inAirplaneMode,
-        in boolean isConnectedToCompanion,
-        in boolean inTheaterMode,
-        in boolean isGpsActive,
-        in boolean isKeyguardLocked
-    ) = 4;
+    void setIndicatorState(in IndicatorState indicatorState) = 4;
 
     /**
      * Sends the immutable system state to the Watch Face.
      */
-    void setImmutableSystemState(in boolean hasLowBitAmbient, in boolean hasBurnInProtection) = 5;
+    void setImmutableSystemState(in ImmutableSystemState immutableSystemState) = 5;
 
     /**
      * Sends new complication data for the specified complicationId.
@@ -101,12 +92,15 @@
      * @param drawMode The {@link androidx.wear.watchface.DrawMode} to render with
      * @param compressionQuality The WebP compression quality, 100 = lossless
      * @param calendarTimeMillis The calendar time (millis since the epoch) to render with
+     * @param style A {@link Bundle} containing a mapping from {@link UserStyleCategory} to
+     *    {@link UserStyleCategory.Option}s. If null then the current style is used.
      * @return A bundle containing a compressed shared memory backed {@link Bitmap} of the watch
      *     face with the requested settings
      */
     Bundle takeWatchfaceScreenshot(in int drawMode,
                                    in int compressionQuality,
-                                   in long calendarTimeMillis) = 9;
+                                   in long calendarTimeMillis,
+                                   in Bundle style) = 9;
 
     /**
      * Request for a {@link Bundle} containing a WebP compressed shared memory backed {@link Bitmap}
@@ -120,6 +114,8 @@
      * @param calendarTimeMillis The calendar time (millis since the epoch) to render with
      * @param complicationData The {@link ComplicationData} to render the complication with, if
      *     null then the last ComplicationData sent to the watch face if any is used
+     * @param style A {@link Bundle} containing a mapping from {@link UserStyleCategory} to
+     *    {@link UserStyleCategory.Option}s. If null then the current style is used.
      * @return A bundle containing a compressed shared memory backed {@link Bitmap} of the
      *     complication with the requested settings
      */
@@ -127,7 +123,8 @@
                                       in int drawMode,
                                       in int compressionQuality,
                                       in long calendarTimeMillis,
-                                      in ComplicationData complicationData) = 10;
+                                      in ComplicationData complicationData,
+                                      in Bundle style) = 10;
 
     /**
      * Forwards a touch event for the WatchFace to process.
diff --git a/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/ImmutableSystemState.aidl b/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/ImmutableSystemState.aidl
new file mode 100644
index 0000000..c5ada43
--- /dev/null
+++ b/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/ImmutableSystemState.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2020 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.wear.watchface.data;
+
+/** @hide */
+parcelable ImmutableSystemState;
diff --git a/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/IndicatorState.aidl b/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/IndicatorState.aidl
new file mode 100644
index 0000000..f61ccdf
--- /dev/null
+++ b/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/IndicatorState.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2020 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.wear.watchface.data;
+
+/** @hide */
+parcelable IndicatorState;
diff --git a/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/SystemState.aidl b/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/SystemState.aidl
new file mode 100644
index 0000000..e648e52
--- /dev/null
+++ b/wear/wear-watchface-data/src/main/aidl/androidx/wear/watchface/data/SystemState.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2020 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.wear.watchface.data;
+
+/** @hide */
+parcelable SystemState;
diff --git a/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/ImmutableSystemState.java b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/ImmutableSystemState.java
new file mode 100644
index 0000000..442c0f0
--- /dev/null
+++ b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/ImmutableSystemState.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2020 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.wear.watchface.data;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.versionedparcelable.ParcelField;
+import androidx.versionedparcelable.ParcelUtils;
+import androidx.versionedparcelable.VersionedParcelable;
+import androidx.versionedparcelable.VersionedParcelize;
+
+/**
+ * Data sent over AIDL for {@link IWatchFaceCommand#setSystemState}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@VersionedParcelize
+public final class ImmutableSystemState implements VersionedParcelable {
+    @ParcelField(1)
+    boolean mHasLowBitAmbient;
+
+    @ParcelField(2)
+    boolean mHasBurnInProtection;
+
+    /** Used by VersionedParcelable. */
+    ImmutableSystemState() {}
+
+    public ImmutableSystemState(
+            boolean hasLowBitAmbient,
+            boolean hasBurnInProtection) {
+        mHasLowBitAmbient = hasLowBitAmbient;
+        mHasBurnInProtection = hasBurnInProtection;
+    }
+
+    public boolean getHasLowBitAmbient() {
+        return mHasLowBitAmbient;
+    }
+
+    public boolean getHasBurnInProtection() {
+        return mHasBurnInProtection;
+    }
+
+    /** Serializes this SystemState to the specified {@link Parcel}. */
+    public void writeToParcel(@NonNull Parcel parcel, int flags) {
+        parcel.writeParcelable(ParcelUtils.toParcelable(this), flags);
+    }
+
+    public static final Parcelable.Creator<ImmutableSystemState> CREATOR =
+            new Parcelable.Creator<ImmutableSystemState>() {
+                @Override
+                public ImmutableSystemState createFromParcel(Parcel source) {
+                    return ImmutableSystemStateParcelizer.read(
+                            ParcelUtils.fromParcelable(source.readParcelable(
+                                    getClass().getClassLoader())));
+                }
+
+                @Override
+                public ImmutableSystemState[] newArray(int size) {
+                    return new ImmutableSystemState[size];
+                }
+            };
+}
diff --git a/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/IndicatorState.java b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/IndicatorState.java
new file mode 100644
index 0000000..adc9bb1
--- /dev/null
+++ b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/IndicatorState.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2020 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.wear.watchface.data;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.versionedparcelable.ParcelField;
+import androidx.versionedparcelable.ParcelUtils;
+import androidx.versionedparcelable.VersionedParcelable;
+import androidx.versionedparcelable.VersionedParcelize;
+
+/**
+ * Data sent over AIDL for {@link IWatchFaceCommand#setIndicatorState}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@VersionedParcelize
+public final class IndicatorState implements VersionedParcelable {
+    @ParcelField(1)
+    boolean mIsCharging;
+
+    @ParcelField(2)
+    boolean mInAirplaneMode;
+
+    @ParcelField(3)
+    boolean mIsConnectedToCompanion;
+
+    @ParcelField(4)
+    boolean mInTheaterMode;
+
+    @ParcelField(5)
+    boolean mIsGpsActive;
+
+    @ParcelField(6)
+    boolean mIsKeyguardLocked;
+
+    /** Used by VersionedParcelable. */
+    IndicatorState() {}
+
+    public IndicatorState(
+            boolean isCharging,
+            boolean inAirplaneMode,
+            boolean isConnectedToCompanion,
+            boolean inTheaterMode,
+            boolean isGpsActive,
+            boolean isKeyguardLocked) {
+        mIsCharging = isCharging;
+        mInAirplaneMode = inAirplaneMode;
+        mIsConnectedToCompanion = isConnectedToCompanion;
+        mInTheaterMode = inTheaterMode;
+        mIsGpsActive = isGpsActive;
+        mIsKeyguardLocked = isKeyguardLocked;
+    }
+
+    public boolean getIsCharging() {
+        return mIsCharging;
+    }
+
+    public boolean getInAirplaneMode() {
+        return mInAirplaneMode;
+    }
+
+    public boolean getIsConnectedToCompanion() {
+        return mIsConnectedToCompanion;
+    }
+
+    public boolean getInTheaterMode() {
+        return mInTheaterMode;
+    }
+
+    public boolean getIsGpsActive() {
+        return mIsGpsActive;
+    }
+
+    public boolean getIsKeyguardLocked() {
+        return mIsKeyguardLocked;
+    }
+
+    /** Serializes this SystemState to the specified {@link Parcel}. */
+    public void writeToParcel(@NonNull Parcel parcel, int flags) {
+        parcel.writeParcelable(ParcelUtils.toParcelable(this), flags);
+    }
+
+    public static final Parcelable.Creator<IndicatorState> CREATOR =
+            new Parcelable.Creator<IndicatorState>() {
+                @Override
+                public IndicatorState createFromParcel(Parcel source) {
+                    return IndicatorStateParcelizer.read(
+                            ParcelUtils.fromParcelable(source.readParcelable(
+                                    getClass().getClassLoader())));
+                }
+
+                @Override
+                public IndicatorState[] newArray(int size) {
+                    return new IndicatorState[size];
+                }
+            };
+}
diff --git a/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/SystemState.java b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/SystemState.java
new file mode 100644
index 0000000..943d17f2
--- /dev/null
+++ b/wear/wear-watchface-data/src/main/java/androidx/wear/watchface/data/SystemState.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2020 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.wear.watchface.data;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.versionedparcelable.ParcelField;
+import androidx.versionedparcelable.ParcelUtils;
+import androidx.versionedparcelable.VersionedParcelable;
+import androidx.versionedparcelable.VersionedParcelize;
+
+/**
+ * Data sent over AIDL for {@link IWatchFaceCommand#setSystemState}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+@VersionedParcelize
+public final class SystemState implements VersionedParcelable {
+    @ParcelField(1)
+    boolean mInAmbientMode;
+
+    @ParcelField(2)
+    int mInterruptionFilter;
+
+    @ParcelField(3)
+    int mUnreadCount;
+
+    @ParcelField(4)
+    int mNotificationCount;
+
+    /** Used by VersionedParcelable. */
+    SystemState() {}
+
+    public SystemState(
+            boolean inAmbientMode,
+            int interruptionFilter,
+            int unreadCount,
+            int notificationCount) {
+        mInAmbientMode = inAmbientMode;
+        mInterruptionFilter = interruptionFilter;
+        mUnreadCount = unreadCount;
+        mNotificationCount = notificationCount;
+    }
+
+    public boolean getInAmbientMode() {
+        return mInAmbientMode;
+    }
+
+    public int getInterruptionFilter() {
+        return mInterruptionFilter;
+    }
+
+    public int getUnreadCount() {
+        return mUnreadCount;
+    }
+
+    public int getNotificationCount() {
+        return mNotificationCount;
+    }
+
+    /** Serializes this SystemState to the specified {@link Parcel}. */
+    public void writeToParcel(@NonNull Parcel parcel, int flags) {
+        parcel.writeParcelable(ParcelUtils.toParcelable(this), flags);
+    }
+
+    public static final Parcelable.Creator<SystemState> CREATOR =
+            new Parcelable.Creator<SystemState>() {
+                @Override
+                public SystemState createFromParcel(Parcel source) {
+                    return SystemStateParcelizer.read(
+                            ParcelUtils.fromParcelable(source.readParcelable(
+                                    getClass().getClassLoader())));
+                }
+
+                @Override
+                public SystemState[] newArray(int size) {
+                    return new SystemState[size];
+                }
+            };
+}
diff --git a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/BooleanUserStyleCategory.kt b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/BooleanUserStyleCategory.kt
index e10303f..a4af9a2 100644
--- a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/BooleanUserStyleCategory.kt
+++ b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/BooleanUserStyleCategory.kt
@@ -42,14 +42,43 @@
         icon: Icon?,
 
         /** The default value for this BooleanUserStyleCategory. */
-        defaultValue: Boolean
-    ) : super(
+        defaultValue: Boolean,
+
+        /**
+         * Used by the style configuration UI. Describes which rendering layer this style affects.
+         * Must be either 0 (for a style change with no visual effect, e.g. sound controls) or a
+         * combination of {@link #LAYER_WATCH_FACE_BASE}, {@link #LAYER_COMPLICATONS}, {@link
+         * #LAYER_UPPER}.
+         */
+        layerFlags: Int
+    ) : this(
         id,
         displayName,
         description,
         icon,
         listOf(BooleanOption(true), BooleanOption(false)),
-        BooleanOption(defaultValue)
+        defaultValue,
+        layerFlags
+    )
+
+    // Helper lets us obey the contract that the default value's object must be in the options list.
+    private constructor(
+        id: String,
+        displayName: String,
+        description: String,
+        icon: Icon?,
+        options: List<BooleanOption>,
+        defaultValue: Boolean,
+        layerFlags: Int
+    ) : super(
+        id,
+        displayName,
+        description,
+        icon,
+        options,
+        options.first
+        { it.value == defaultValue },
+        layerFlags
     )
 
     internal constructor(bundle: Bundle) : super(bundle)
diff --git a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/DoubleRangeUserStyleCategory.kt b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/DoubleRangeUserStyleCategory.kt
index dd92123..701c858 100644
--- a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/DoubleRangeUserStyleCategory.kt
+++ b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/DoubleRangeUserStyleCategory.kt
@@ -28,6 +28,26 @@
     internal companion object {
         internal const val CATEGORY_TYPE = "DoubleRangeUserStyleCategory"
         internal const val OPTION_TYPE = "DoubleRangeOption"
+
+        internal fun createOptionsList(
+            minimumValue: Double,
+            maximumValue: Double,
+            defaultValue: Double
+        ): List<DoubleRangeOption> {
+            require(minimumValue < maximumValue)
+            require(defaultValue >= minimumValue)
+            require(defaultValue <= maximumValue)
+
+            return if (defaultValue != minimumValue && defaultValue != maximumValue) {
+                listOf(
+                    DoubleRangeOption(minimumValue),
+                    DoubleRangeOption(defaultValue),
+                    DoubleRangeOption(maximumValue)
+                )
+            } else {
+                listOf(DoubleRangeOption(minimumValue), DoubleRangeOption(maximumValue))
+            }
+        }
     }
 
     constructor (
@@ -50,14 +70,42 @@
         maximumValue: Double,
 
         /** The default value for this DoubleRangeUserStyleCategory. */
-        defaultValue: Double
+        defaultValue: Double,
+
+        /**
+         * Used by the style configuration UI. Describes which rendering layer this style affects.
+         * Must be either 0 (for a style change with no visual effect, e.g. sound controls) or a
+         * combination  of {@link #LAYER_WATCH_FACE_BASE}, {@link #LAYER_COMPLICATONS}, {@link
+         * #LAYER_UPPER}.
+         */
+        layerFlags: Int
+    ) : this(
+        id,
+        displayName,
+        description,
+        icon,
+        createOptionsList(minimumValue, maximumValue, defaultValue),
+        defaultValue,
+        layerFlags
+    )
+
+    // Helper lets us obey the contract that the default value's object must be in the options list.
+    private constructor(
+        id: String,
+        displayName: String,
+        description: String,
+        icon: Icon?,
+        options: List<DoubleRangeOption>,
+        defaultValue: Double,
+        layerFlags: Int
     ) : super(
         id,
         displayName,
         description,
         icon,
-        listOf(DoubleRangeOption(minimumValue), DoubleRangeOption(maximumValue)),
-        DoubleRangeOption(defaultValue)
+        options,
+        options.first { it.value == defaultValue },
+        layerFlags
     )
 
     internal constructor(bundle: Bundle) : super(bundle)
diff --git a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/ListUserStyleCategory.kt b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/ListUserStyleCategory.kt
index 99c61fc..7adb030 100644
--- a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/ListUserStyleCategory.kt
+++ b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/ListUserStyleCategory.kt
@@ -45,9 +45,17 @@
         /** List of all options for this ListUserStyleCategory. */
         options: List<ListOption>,
 
+        /**
+         * Used by the style configuration UI. Describes which rendering layer this style affects.
+         * Must be either 0 (for a style change with no visual effect, e.g. sound controls) or a
+         * combination of {@link #LAYER_WATCH_FACE_BASE}, {@link #LAYER_COMPLICATONS}, {@link
+         * #LAYER_UPPER}.
+         */
+        layerFlags: Int,
+
         /** The default option, used when data isn't persisted. */
         defaultOption: ListOption = options.first()
-    ) : super(id, displayName, description, icon, options, defaultOption)
+    ) : super(id, displayName, description, icon, options, defaultOption, layerFlags)
 
     internal constructor(bundle: Bundle) : super(bundle)
 
diff --git a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/LongRangeUserStyleCategory.kt b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/LongRangeUserStyleCategory.kt
index 936b445..bb4a70e 100644
--- a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/LongRangeUserStyleCategory.kt
+++ b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/LongRangeUserStyleCategory.kt
@@ -28,6 +28,29 @@
     internal companion object {
         internal const val CATEGORY_TYPE = "LongRangeUserStyleCategory"
         internal const val OPTION_TYPE = "LongRangeOption"
+
+        internal fun createOptionsList(
+            minimumValue: Long,
+            maximumValue: Long,
+            defaultValue: Long
+        ): List<LongRangeOption> {
+            require(minimumValue < maximumValue)
+            require(defaultValue >= minimumValue)
+            require(defaultValue <= maximumValue)
+
+            return if (defaultValue != minimumValue && defaultValue != maximumValue) {
+                listOf(
+                    LongRangeOption(minimumValue),
+                    LongRangeOption(defaultValue),
+                    LongRangeOption(maximumValue)
+                )
+            } else {
+                listOf(
+                    LongRangeOption(minimumValue),
+                    LongRangeOption(maximumValue)
+                )
+            }
+        }
     }
 
     constructor (
@@ -50,14 +73,42 @@
         maximumValue: Long,
 
         /** The default value for this LongRangeUserStyleCategory. */
-        defaultValue: Long
+        defaultValue: Long,
+
+        /**
+         * Used by the style configuration UI. Describes which rendering layer this style affects.
+         * Must be either 0 (for a style change with no visual effect, e.g. sound controls) or a
+         * combination  of {@link #LAYER_WATCH_FACE_BASE}, {@link #LAYER_COMPLICATONS}, {@link
+         * #LAYER_UPPER}.
+         */
+        layerFlags: Int
+    ) : this(
+        id,
+        displayName,
+        description,
+        icon,
+        createOptionsList(minimumValue, maximumValue, defaultValue),
+        defaultValue,
+        layerFlags
+    )
+
+    // Helper lets us obey the contract that the default value's object must be in the options list.
+    private constructor(
+        id: String,
+        displayName: String,
+        description: String,
+        icon: Icon?,
+        options: List<LongRangeOption>,
+        defaultValue: Long,
+        layerFlags: Int
     ) : super(
         id,
         displayName,
         description,
         icon,
-        listOf(LongRangeOption(minimumValue), LongRangeOption(maximumValue)),
-        LongRangeOption(defaultValue)
+        options,
+        options.first { it.value == defaultValue },
+        layerFlags
     )
 
     internal constructor(bundle: Bundle) : super(bundle)
diff --git a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleCategory.kt b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleCategory.kt
index 4cdd4e5..c46fdd3 100644
--- a/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleCategory.kt
+++ b/wear/wear-watchface-style/src/main/java/androidx/wear/watchface/style/UserStyleCategory.kt
@@ -46,16 +46,40 @@
     val options: List<Option>,
 
     /** The default option if nothing has been selected. Must be in the {@link #options} list.*/
-    val defaultOption: Option
+    val defaultOption: Option,
+
+    /**
+     * Used by the style configuration UI. Describes which rendering layer this style affects. Must
+     * be either 0 (for a style change with no visual effect, e.g. sound controls) or a combination
+     * of {@link #LAYER_WATCH_FACE_BASE}, {@link #LAYER_COMPLICATONS},
+     * {@link #LAYER_WATCH_FACE_UPPER}.
+     */
+    val layerFlags: Int
 ) {
     companion object {
+        /**
+         * The base watch face without complications or watch hands (or any other elements that
+         * could occlude complications).
+         */
+        const val LAYER_WATCH_FACE_BASE = 1 shl 0
+
+        /** The complications layer. */
+        const val LAYER_COMPLICATONS = 1 shl 1
+
+        /** Anything that could occlude complications, typically watch hands. */
+        const val LAYER_WATCH_FACE_UPPER = 1 shl 2
+
+        internal const val INVALID_LAYER_MASK =
+            (LAYER_WATCH_FACE_BASE or LAYER_COMPLICATONS or LAYER_WATCH_FACE_UPPER).inv()
+
         internal const val KEY_CATEGORY_TYPE = "KEY_CATEGORY_TYPE"
-        internal const val KEY_DEFAULT_OPTION = "KEY_DEFAULT_OPTION"
+        internal const val KEY_DEFAULT_OPTION_INDEX = "KEY_DEFAULT_OPTION_INDEX"
         internal const val KEY_DESCRIPTION = "KEY_DESCRIPTION"
         internal const val KEY_DISPLAY_NAME = "KEY_DISPLAY_NAME"
         internal const val KEY_ICON = "KEY_ICON"
         internal const val KEY_OPTIONS = "KEY_OPTIONS"
         internal const val KEY_STYLE_CATEGORY_ID = "KEY_STYLE_CATEGORY_ID"
+        internal const val KEY_LAYER_FLAGS = "KEY_LAYER_FLAGS"
 
         /**
          * Constructs an {@link UserStyleCategory} serialized in a {@link Bundle}.
@@ -78,6 +102,16 @@
         }
     }
 
+    init {
+        require(layerFlags and INVALID_LAYER_MASK == 0) {
+            "layerFlags must be either 0 or a combination of LAYER_WATCH_FACE_BASE, " +
+                    "LAYER_COMPLICATONS, LAYER_WATCH_FACE_UPPER"
+        }
+        require(options.contains(defaultOption)) {
+            "The defaultOption must be in the options list"
+        }
+    }
+
     internal fun getCategoryOptionForId(id: String?) =
         if (id == null) {
             defaultOption
@@ -86,12 +120,18 @@
         }
 
     internal constructor(bundle: Bundle) : this(
+        bundle,
+        StyleUtils.readOptionsListFromBundle(bundle)
+    )
+
+    private constructor(bundle: Bundle, options: List<Option>) : this(
         bundle.getString(KEY_STYLE_CATEGORY_ID)!!,
         bundle.getString(KEY_DISPLAY_NAME)!!,
         bundle.getString(KEY_DESCRIPTION)!!,
         bundle.getParcelable(KEY_ICON),
-        StyleUtils.readOptionsListFromBundle(bundle),
-        Option.createFromBundle(bundle.getBundle(KEY_DEFAULT_OPTION)!!)
+        options,
+        options[bundle.getInt(KEY_DEFAULT_OPTION_INDEX)],
+        bundle.getInt(KEY_LAYER_FLAGS)
     )
 
     @CallSuper
@@ -101,10 +141,8 @@
         bundle.putString(KEY_DISPLAY_NAME, displayName)
         bundle.putString(KEY_DESCRIPTION, description)
         bundle.putParcelable(KEY_ICON, icon)
-        bundle.putBundle(
-            KEY_DEFAULT_OPTION,
-            Bundle().apply { defaultOption.writeToBundle(this) }
-        )
+        bundle.putInt(KEY_DEFAULT_OPTION_INDEX, options.indexOf(defaultOption))
+        bundle.putInt(KEY_LAYER_FLAGS, layerFlags)
         StyleUtils.writeOptionListToBundle(options, bundle)
     }
 
diff --git a/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/StyleUtilsTest.kt b/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/StyleUtilsTest.kt
index 3d72660..62d6150 100644
--- a/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/StyleUtilsTest.kt
+++ b/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/StyleUtilsTest.kt
@@ -38,7 +38,12 @@
     fun bundleAndUnbundleStyleCategoryAndOption() {
         val categoryIcon = Icon.createWithContentUri("categoryIcon")
         val styleCategory = ListUserStyleCategory(
-            "id", "displayName", "description", categoryIcon, listOf(option1, option2, option3)
+            "id",
+            "displayName",
+            "description",
+            categoryIcon,
+            listOf(option1, option2, option3),
+            UserStyleCategory.LAYER_WATCH_FACE_BASE
         )
 
         val bundle = Bundle()
@@ -51,6 +56,7 @@
         assertThat(unbundled.displayName).isEqualTo("displayName")
         assertThat(unbundled.description).isEqualTo("description")
         assertThat(unbundled.icon!!.uri.toString()).isEqualTo("categoryIcon")
+        assertThat(unbundled.layerFlags).isEqualTo(UserStyleCategory.LAYER_WATCH_FACE_BASE)
         val optionArray =
             unbundled.options.filterIsInstance<ListUserStyleCategory.ListOption>()
                 .toTypedArray()
@@ -92,10 +98,20 @@
         val categoryIcon1 = Icon.createWithContentUri("categoryIcon1")
         val categoryIcon2 = Icon.createWithContentUri("categoryIcon2")
         val styleCategory1 = ListUserStyleCategory(
-            "id1", "displayName1", "description1", categoryIcon1, listOf(option1, option2)
+            "id1",
+            "displayName1",
+            "description1",
+            categoryIcon1,
+            listOf(option1, option2),
+            UserStyleCategory.LAYER_WATCH_FACE_BASE
         )
         val styleCategory2 = ListUserStyleCategory(
-            "id2", "displayName2", "description2", categoryIcon2, listOf(option3, option4)
+            "id2",
+            "displayName2",
+            "description2",
+            categoryIcon2,
+            listOf(option3, option4),
+            UserStyleCategory.LAYER_WATCH_FACE_UPPER
         )
 
         val bundles = StyleUtils.userStyleCategoriesToBundles(
@@ -109,6 +125,7 @@
         assertThat(unbundled[0].displayName).isEqualTo("displayName1")
         assertThat(unbundled[0].description).isEqualTo("description1")
         assertThat(unbundled[0].icon!!.uri.toString()).isEqualTo("categoryIcon1")
+        assertThat(unbundled[0].layerFlags).isEqualTo(UserStyleCategory.LAYER_WATCH_FACE_BASE)
         val optionArray1 =
             unbundled[0].options.filterIsInstance<ListUserStyleCategory.ListOption>()
                 .toTypedArray()
@@ -125,6 +142,7 @@
         assertThat(unbundled[1].displayName).isEqualTo("displayName2")
         assertThat(unbundled[1].description).isEqualTo("description2")
         assertThat(unbundled[1].icon!!.uri.toString()).isEqualTo("categoryIcon2")
+        assertThat(unbundled[1].layerFlags).isEqualTo(UserStyleCategory.LAYER_WATCH_FACE_UPPER)
         val optionArray2 =
             unbundled[1].options.filterIsInstance<ListUserStyleCategory.ListOption>()
                 .toTypedArray()
@@ -142,10 +160,20 @@
         val categoryIcon1 = Icon.createWithContentUri("categoryIcon1")
         val categoryIcon2 = Icon.createWithContentUri("categoryIcon2")
         val styleCategory1 = ListUserStyleCategory(
-            "id1", "displayName1", "description1", categoryIcon1, listOf(option1, option2)
+            "id1",
+            "displayName1",
+            "description1",
+            categoryIcon1,
+            listOf(option1, option2),
+            UserStyleCategory.LAYER_WATCH_FACE_BASE
         )
         val styleCategory2 = ListUserStyleCategory(
-            "id2", "displayName2", "description2", categoryIcon2, listOf(option3, option4)
+            "id2",
+            "displayName2",
+            "description2",
+            categoryIcon2,
+            listOf(option3, option4),
+            UserStyleCategory.LAYER_WATCH_FACE_UPPER
         )
         val schema = listOf(styleCategory1, styleCategory2)
         val styleMap = mapOf(
diff --git a/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleCategoryTest.kt b/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleCategoryTest.kt
index 8fd836d..e83cf0a 100644
--- a/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleCategoryTest.kt
+++ b/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleCategoryTest.kt
@@ -16,31 +16,13 @@
 
 package androidx.wear.watchface.style
 
-import android.graphics.drawable.Icon
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.model.FrameworkMethod
-import org.robolectric.RobolectricTestRunner
-import org.robolectric.internal.bytecode.InstrumentationConfiguration
 
-// Without this we get test failures with an error:
-// "failed to access class kotlin.jvm.internal.DefaultConstructorMarker".
-class WatchFaceServiceTestRunner(testClass: Class<*>) : RobolectricTestRunner(testClass) {
-    override fun createClassLoaderConfig(method: FrameworkMethod): InstrumentationConfiguration =
-        InstrumentationConfiguration.Builder(super.createClassLoaderConfig(method))
-            .doNotInstrumentPackage("androidx.wear.watchface.style")
-            .build()
-}
-
-@RunWith(WatchFaceServiceTestRunner::class)
+@RunWith(StyleTestRunner::class)
 class UserStyleCategoryTest {
 
-    private val icon1 = Icon.createWithContentUri("icon1")
-    private val icon2 = Icon.createWithContentUri("icon2")
-    private val icon3 = Icon.createWithContentUri("icon3")
-    private val icon4 = Icon.createWithContentUri("icon4")
-
     @Test
     fun rangedUserStyleCategory_getOptionForId_returns_default_for_bad_input() {
         val defaultValue = 0.75
@@ -52,7 +34,8 @@
                 null,
                 0.0,
                 1.0,
-                defaultValue
+                defaultValue,
+                UserStyleCategory.LAYER_WATCH_FACE_BASE
             )
 
         assertThat(rangedUserStyleCategory.getOptionForId("not a number").id)
@@ -76,7 +59,8 @@
                 null,
                 0.0,
                 1.0,
-                defaultValue
+                defaultValue,
+                UserStyleCategory.LAYER_WATCH_FACE_BASE
             )
 
         assertThat(rangedUserStyleCategory.getOptionForId("0").id)
diff --git a/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleRepositoryTest.kt b/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleRepositoryTest.kt
index c26f164..805a899 100644
--- a/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleRepositoryTest.kt
+++ b/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/UserStyleRepositoryTest.kt
@@ -39,7 +39,8 @@
         "Colors",
         "Watchface colorization", /* icon = */
         null,
-        colorStyleList
+        colorStyleList,
+        UserStyleCategory.LAYER_WATCH_FACE_BASE
     )
 
     private val classicStyleOption =
@@ -59,7 +60,8 @@
         "Hand Style",
         "Hand visual look", /* icon = */
         null,
-        watchHandStyleList
+        watchHandStyleList,
+        UserStyleCategory.LAYER_WATCH_FACE_UPPER
     )
 
     private val mockListener1 = Mockito.mock(UserStyleRepository.UserStyleListener::class.java)
diff --git a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasWatchFaceService.kt b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasWatchFaceService.kt
index dd1a307..83d887b 100644
--- a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasWatchFaceService.kt
+++ b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleCanvasWatchFaceService.kt
@@ -87,7 +87,10 @@
                     "Green",
                     Icon.createWithResource(this, R.drawable.green_style)
                 )
-            )
+            ),
+            UserStyleCategory.LAYER_WATCH_FACE_BASE or
+                    UserStyleCategory.LAYER_COMPLICATONS or
+                    UserStyleCategory.LAYER_WATCH_FACE_UPPER
         )
         val drawHourPipsStyleCategory =
             BooleanUserStyleCategory(
@@ -95,7 +98,8 @@
                 "Hour Pips",
                 "Whether to draw or not",
                 null,
-                true
+                true,
+                UserStyleCategory.LAYER_WATCH_FACE_BASE
             )
         val watchHandLengthStyleCategory =
             DoubleRangeUserStyleCategory(
@@ -105,7 +109,8 @@
                 null,
                 0.25,
                 1.0,
-                0.75
+                0.75,
+                UserStyleCategory.LAYER_WATCH_FACE_UPPER
             )
         val userStyleRepository = UserStyleRepository(
             listOf(colorStyleCategory, drawHourPipsStyleCategory, watchHandLengthStyleCategory)
diff --git a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt
index bf54ed4..0fb9449 100644
--- a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt
+++ b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/ExampleOpenGLWatchFaceService.kt
@@ -34,6 +34,7 @@
 import androidx.wear.watchface.WatchFaceType
 import androidx.wear.watchface.WatchState
 import androidx.wear.watchface.style.ListUserStyleCategory
+import androidx.wear.watchface.style.UserStyleCategory
 import androidx.wear.watchface.style.UserStyleRepository
 import java.nio.ByteBuffer
 import java.nio.ByteOrder
@@ -83,7 +84,8 @@
                     "Green",
                     Icon.createWithResource(this, R.drawable.green_style)
                 )
-            )
+            ),
+            UserStyleCategory.LAYER_WATCH_FACE_BASE or UserStyleCategory.LAYER_WATCH_FACE_UPPER
         )
         val userStyleRepository = UserStyleRepository(listOf(colorStyleCategory))
         val complicationSlots = ComplicationsManager(emptyList())
diff --git a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt
index 14a8b28..0010dd3 100644
--- a/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt
+++ b/wear/wear-watchface/samples/src/main/java/androidx/wear/watchface/samples/KDocExampleWatchFace.kt
@@ -73,7 +73,10 @@
                                 "Blue",
                                 icon = null
                             )
-                        )
+                        ),
+                        UserStyleCategory.LAYER_WATCH_FACE_BASE or
+                                UserStyleCategory.LAYER_COMPLICATONS or
+                                UserStyleCategory.LAYER_WATCH_FACE_UPPER
                     ),
                     ListUserStyleCategory(
                         "hand_style_category",
@@ -92,7 +95,8 @@
                                 "Gothic",
                                 icon = null
                             )
-                        )
+                        ),
+                        UserStyleCategory.LAYER_WATCH_FACE_UPPER
                     )
                 )
             )
diff --git a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestCanvasWatchFaceService.kt b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestCanvasWatchFaceService.kt
index f66a499..8f33b99 100644
--- a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestCanvasWatchFaceService.kt
+++ b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestCanvasWatchFaceService.kt
@@ -25,6 +25,7 @@
 import androidx.wear.complications.SystemProviders
 import androidx.wear.watchface.Complication
 import androidx.wear.watchface.ComplicationsManager
+import androidx.wear.watchface.MutableWatchState
 import androidx.wear.watchface.NoInvalidateWatchFaceHostApi
 import androidx.wear.watchface.WatchFace
 import androidx.wear.watchface.WatchFaceHost
@@ -39,6 +40,7 @@
 import androidx.wear.watchface.style.BooleanUserStyleCategory
 import androidx.wear.watchface.style.DoubleRangeUserStyleCategory
 import androidx.wear.watchface.style.ListUserStyleCategory
+import androidx.wear.watchface.style.UserStyleCategory
 import androidx.wear.watchface.style.UserStyleRepository
 
 /** A simple canvas test watch face for integration tests. */
@@ -48,6 +50,10 @@
     var mockSystemTimeMillis: Long
 ) : WatchFaceService() {
 
+    private val mutableWatchState = MutableWatchState().apply {
+        isAmbient.value = false
+    }
+
     init {
         attachBaseContext(testContext)
     }
@@ -58,7 +64,7 @@
         watchState: WatchState
     ): WatchFace {
         // Override is necessary because the watch face isn't visible in this test.
-        watchState.onVisibilityChanged(true)
+        mutableWatchState.isVisible.value = true
 
         val watchFaceStyle = WatchFaceColorStyle.create(this, "red_style")
         val colorStyleCategory = ListUserStyleCategory(
@@ -77,7 +83,10 @@
                     "Green",
                     Icon.createWithResource(this, R.drawable.green_style)
                 )
-            )
+            ),
+            UserStyleCategory.LAYER_WATCH_FACE_BASE or
+                    UserStyleCategory.LAYER_COMPLICATONS or
+                    UserStyleCategory.LAYER_WATCH_FACE_UPPER
         )
         val drawHourPipsStyleCategory =
             BooleanUserStyleCategory(
@@ -85,7 +94,8 @@
                 "Hour Pips",
                 "Whether or not hour pips should be drawn",
                 null,
-                true
+                true,
+                UserStyleCategory.LAYER_WATCH_FACE_BASE
             )
         val watchHandLengthStyleCategory =
             DoubleRangeUserStyleCategory(
@@ -95,7 +105,8 @@
                 null,
                 0.25,
                 1.0,
-                1.0
+                1.0,
+                UserStyleCategory.LAYER_WATCH_FACE_UPPER
             )
         val userStyleRepository = UserStyleRepository(
             listOf(colorStyleCategory, drawHourPipsStyleCategory, watchHandLengthStyleCategory)
@@ -160,5 +171,7 @@
         }).build()
     }
 
+    override fun getMutableWatchState() = mutableWatchState
+
     override fun getHandler() = handler
 }
diff --git a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestGlesWatchFaceService.kt b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestGlesWatchFaceService.kt
index cf7a17e..5df4dda 100644
--- a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestGlesWatchFaceService.kt
+++ b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/TestGlesWatchFaceService.kt
@@ -21,6 +21,7 @@
 import android.os.Handler
 import android.view.SurfaceHolder
 import androidx.wear.watchface.ComplicationsManager
+import androidx.wear.watchface.MutableWatchState
 import androidx.wear.watchface.NoInvalidateWatchFaceHostApi
 import androidx.wear.watchface.WatchFace
 import androidx.wear.watchface.WatchFaceHost
@@ -30,6 +31,7 @@
 import androidx.wear.watchface.samples.ExampleOpenGLRenderer
 import androidx.wear.watchface.samples.R
 import androidx.wear.watchface.style.ListUserStyleCategory
+import androidx.wear.watchface.style.UserStyleCategory
 import androidx.wear.watchface.style.UserStyleRepository
 
 /** A simple OpenGL test watch face for integration tests. */
@@ -39,6 +41,10 @@
     var mockSystemTimeMillis: Long
 ) : WatchFaceService() {
 
+    private val mutableWatchState = MutableWatchState().apply {
+        isAmbient.value = false
+    }
+
     init {
         attachBaseContext(testContext)
     }
@@ -49,7 +55,7 @@
         watchState: WatchState
     ): WatchFace {
         // Override is necessary because the watch face isn't visible in this test.
-        watchState.onVisibilityChanged(true)
+        mutableWatchState.isVisible.value = true
 
         val colorStyleCategory = ListUserStyleCategory(
             "color_style_category",
@@ -67,7 +73,8 @@
                     "Green",
                     Icon.createWithResource(this, R.drawable.green_style)
                 )
-            )
+            ),
+            UserStyleCategory.LAYER_WATCH_FACE_BASE or UserStyleCategory.LAYER_WATCH_FACE_UPPER
         )
         val userStyleRepository = UserStyleRepository(listOf(colorStyleCategory))
         val complicationSlots = ComplicationsManager(emptyList())
@@ -94,5 +101,7 @@
         }).build()
     }
 
+    override fun getMutableWatchState() = mutableWatchState
+
     override fun getHandler() = handler
 }
diff --git a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt
index 5278b1d..d36ef74 100644
--- a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt
+++ b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt
@@ -44,6 +44,7 @@
 import androidx.wear.watchface.ComplicationBoundsType
 import androidx.wear.watchface.DrawMode
 import androidx.wear.watchface.WatchFaceService
+import androidx.wear.watchface.data.SystemState
 import androidx.wear.watchface.samples.EXAMPLE_CANVAS_WATCHFACE_LEFT_COMPLICATION_ID
 import org.junit.Before
 import org.junit.Rule
@@ -247,10 +248,12 @@
 
     private fun setAmbient(ambient: Boolean) {
         watchFaceServiceStub.iWatchFaceCommand!!.setSystemState(
-            ambient,
-            0,
-            0,
-            0
+            SystemState(
+                ambient,
+                0,
+                0,
+                0
+            )
         )
     }
 
@@ -287,10 +290,9 @@
             bitmap = watchFaceServiceStub.iWatchFaceCommand!!.takeWatchfaceScreenshot(
                 DrawMode.AMBIENT,
                 100,
-                123456789
-            ).ashmemCompressedImageBundleToBitmap(
-
-            )
+                123456789,
+                null
+            ).ashmemCompressedImageBundleToBitmap()
             latch.countDown()
         }
 
@@ -313,10 +315,9 @@
                 DrawMode.AMBIENT,
                 100,
                 123456789,
+                null,
                 null
-            ).ashmemCompressedImageBundleToBitmap(
-
-            )
+            ).ashmemCompressedImageBundleToBitmap()
             latch.countDown()
         }
 
@@ -337,7 +338,8 @@
             bitmap = watchFaceServiceStub.iWatchFaceCommand!!.takeWatchfaceScreenshot(
                 DrawMode.INTERACTIVE,
                 100,
-                123456789
+                123456789,
+                null
             ).ashmemCompressedImageBundleToBitmap()!!
             latch.countDown()
         }
@@ -364,10 +366,9 @@
                 ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
                     .setShortTitle(ComplicationText.plainText("Title"))
                     .setShortText(ComplicationText.plainText("Text"))
-                    .build()
-            ).ashmemCompressedImageBundleToBitmap(
-
-            )
+                    .build(),
+                null
+            ).ashmemCompressedImageBundleToBitmap()
             latch.countDown()
         }
 
@@ -388,6 +389,7 @@
                 DrawMode.INTERACTIVE,
                 100,
                 123456789,
+                null,
                 null
             ).ashmemCompressedImageBundleToBitmap()
             latch2.countDown()
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/CanvasRenderer.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/CanvasRenderer.kt
index 912361f..71cc90b 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/CanvasRenderer.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/CanvasRenderer.kt
@@ -73,7 +73,7 @@
             surfaceHolder.lockCanvas()
         }) ?: return
         try {
-            if (watchState.isVisible) {
+            if (watchState.isVisible.value) {
                 render(canvas, surfaceHolder.surfaceFrame, calendar)
             } else {
                 canvas.drawColor(Color.BLACK)
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Complication.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Complication.kt
index afda9b6..78bac5c 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Complication.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Complication.kt
@@ -25,6 +25,7 @@
 import android.icu.util.Calendar
 import android.support.wearable.complications.ComplicationData
 import androidx.annotation.UiThread
+import androidx.lifecycle.Observer
 import androidx.wear.complications.SystemProviders
 import androidx.wear.complications.rendering.ComplicationDrawable
 
@@ -116,36 +117,41 @@
         get() = _drawable
         set(value) {
             _drawable = value
-            _drawable.inAmbientMode = watchState.isAmbient
-            _drawable.lowBitAmbient = watchState.hasLowBitAmbient
-            _drawable.setBurnInProtection(watchState.hasBurnInProtection)
+            _drawable.inAmbientMode = watchState.isAmbient.value
+            _drawable.lowBitAmbient = watchState.hasLowBitAmbient.value
+            _drawable.setBurnInProtection(watchState.hasBurnInProtection.value)
 
             attachedComplication?.scheduleUpdateActiveComplications()
         }
 
-    private inner class SystemStateListener : WatchState.Listener {
-        override fun onAmbientModeChanged(isAmbient: Boolean) {
-            drawable.inAmbientMode = isAmbient
-        }
+    private val isAmbientObserver = Observer<Boolean> {
+        drawable.inAmbientMode = it
     }
 
-    private val systemStateListener = SystemStateListener()
+    private val lowBitAmbientObserver = Observer<Boolean> {
+        drawable.lowBitAmbient = it
+    }
+
+    private val burnInProtectionObserver = Observer<Boolean> {
+        drawable.setBurnInProtection(it)
+    }
+
     private var attachedComplication: Complication? = null
     private var complicationData: ComplicationData? = null
 
     /** {@inheritDoc} */
     override fun onAttach(complication: Complication) {
         attachedComplication = complication
-        drawable.inAmbientMode = watchState.isAmbient
-        drawable.lowBitAmbient = watchState.hasLowBitAmbient
-        drawable.setBurnInProtection(watchState.hasBurnInProtection)
-
-        watchState.addListener(systemStateListener)
+        watchState.isAmbient.observe(isAmbientObserver)
+        watchState.hasLowBitAmbient.observe(lowBitAmbientObserver)
+        watchState.hasBurnInProtection.observe(burnInProtectionObserver)
     }
 
     /** {@inheritDoc} */
     override fun onDetach() {
-        watchState.removeListener(systemStateListener)
+        watchState.isAmbient.removeObserver(isAmbientObserver)
+        watchState.hasLowBitAmbient.removeObserver(lowBitAmbientObserver)
+        watchState.hasBurnInProtection.removeObserver(burnInProtectionObserver)
         attachedComplication = null
     }
 
@@ -198,7 +204,7 @@
 class Complication internal constructor(
     internal val id: Int,
     @ComplicationBoundsType internal val boundsType: Int,
-    val unitSquareBounds: RectF,
+    unitSquareBounds: RectF,
     renderer: ComplicationRenderer,
     internal val supportedTypes: IntArray,
     internal val defaultProviderPolicy: DefaultComplicationProviderPolicy,
@@ -305,12 +311,27 @@
 
     private lateinit var complicationsManager: ComplicationsManager
     private lateinit var invalidateCallback: ComplicationRenderer.InvalidateCallback
-    private var _enabled = true
 
+    private var _unitSquareBounds = unitSquareBounds
+    var unitSquareBounds: RectF
+        @UiThread
+        get() = _unitSquareBounds
+
+        @UiThread
+        set(value) {
+            _unitSquareBounds = value
+
+            // The caller might modify a number of complications. For efficiency we need to coalesce
+            // these into one update task.
+            complicationsManager.scheduleUpdateActiveComplications()
+        }
+
+    private var _enabled = true
     var enabled: Boolean
         @JvmName("isEnabled")
         @UiThread
         get() = _enabled
+
         @UiThread
         set(value) {
             _enabled = value
@@ -321,10 +342,10 @@
         }
 
     private var _renderer = renderer
-
     var renderer: ComplicationRenderer
         @UiThread
         get() = _renderer
+
         @UiThread
         set(value) {
             renderer.onDetach()
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt
index f8f66db..eae10ae 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt
@@ -147,5 +147,5 @@
      * @return Whether we should schedule an onDraw call to maintain an interactive frame rate
      */
     @UiThread
-    open fun shouldAnimate() = watchState.isVisible && !watchState.isAmbient
+    open fun shouldAnimate() = watchState.isVisible.value && !watchState.isAmbient.value
 }
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchData.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchData.kt
new file mode 100644
index 0000000..ad5255b
--- /dev/null
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchData.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2020 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.wear.watchface
+
+import androidx.annotation.UiThread
+import androidx.lifecycle.Observer
+
+/**
+ * An observable UI thread only data holder class.
+ *
+ * @param <T> The type of data hold by this instance
+ */
+open class WatchData<T> protected constructor(protected var _value: T?) {
+    private var iterating = false
+    internal val observers = ArrayList<Observer<T>>()
+    internal val toBeRemoved = HashSet<Observer<T>>()
+
+    /** Whether or not this WatchData contains a value. */
+    fun hasValue() = _value != null
+
+    /** Returns the value contained within this WatchData or default if there isn't one. */
+    fun getValueOr(default: T) = if (_value != null) {
+        _value!!
+    } else {
+        default
+    }
+
+    open var value: T
+        @UiThread
+        get() = _value!!
+
+        @UiThread
+        protected set(v) {
+            require(!iterating)
+            iterating = true
+            _value = v
+            for (observer in observers) {
+                // The observer might unregister itself and removing elements from a collection
+                // while it's being iterated is not allowed, so check if we should skip over this
+                // observer.
+                if (!toBeRemoved.contains(observer)) {
+                    observer.onChanged(_value)
+                }
+            }
+            iterating = false
+            for (observer in toBeRemoved) {
+                observers.remove(observer)
+            }
+        }
+
+    /**
+     * Adds the given observer to the observers list. The events are dispatched on the ui thread.
+     * If there's any data held within the WatchData it will be immediately delivered to the
+     * observer.
+     */
+    @UiThread
+    fun observe(observer: Observer<T>) {
+        require(!observers.contains(observer))
+        observers.add(observer)
+        if (hasValue()) {
+            observer.onChanged(_value)
+        }
+    }
+
+    /** Removes an observer previously added by {@link observe}. */
+    @UiThread
+    fun removeObserver(observer: Observer<T>) {
+        require(observers.contains(observer))
+
+        if (iterating) {
+            toBeRemoved.add(observer)
+        } else {
+            observers.remove(observer)
+        }
+    }
+}
+
+/**
+ * {@link WatchData} which publicly exposes {@link #setValue(T)} method
+ *
+ * @param <T> The type of data hold by this instance
+ */
+@SuppressWarnings("WeakerAccess")
+class MutableWatchData<T>(initialValue: T?) : WatchData<T>(initialValue) {
+    constructor() : this(null)
+
+    override var value: T
+        @UiThread
+        get() = _value!!
+
+        @UiThread
+        public set(v) {
+            super.value = v
+        }
+}
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
index 16b9e29..49e2704 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
@@ -39,10 +39,11 @@
 import androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP
 import androidx.annotation.UiThread
 import androidx.annotation.VisibleForTesting
+import androidx.lifecycle.Observer
 import androidx.wear.complications.SystemProviders
-import androidx.wear.watchface.style.StyleUtils
 import androidx.wear.watchface.style.UserStyleCategory
 import androidx.wear.watchface.style.UserStyleRepository
+import androidx.wear.watchface.style.StyleUtils
 import androidx.wear.watchface.ui.WatchFaceConfigActivity
 import androidx.wear.watchface.ui.WatchFaceConfigDelegate
 import java.io.FileNotFoundException
@@ -370,14 +371,12 @@
     val batteryLevelReceiver: BroadcastReceiver = object : BroadcastReceiver() {
         @SuppressWarnings("SyntheticAccessor")
         override fun onReceive(context: Context, intent: Intent) {
+            val isBatteryLowAndNotCharging =
+                watchState.isBatteryLowAndNotCharging as MutableWatchData
             when (intent.action) {
-                Intent.ACTION_BATTERY_LOW -> watchState.onIsBatteryLowAndNotCharging(true)
-                Intent.ACTION_BATTERY_OKAY -> watchState.onIsBatteryLowAndNotCharging(
-                    false
-                )
-                Intent.ACTION_POWER_CONNECTED -> watchState.onIsBatteryLowAndNotCharging(
-                    false
-                )
+                Intent.ACTION_BATTERY_LOW -> isBatteryLowAndNotCharging.value = true
+                Intent.ACTION_BATTERY_OKAY -> isBatteryLowAndNotCharging.value = false
+                Intent.ACTION_POWER_CONNECTED -> isBatteryLowAndNotCharging.value = false
             }
             invalidate()
         }
@@ -462,38 +461,31 @@
         watchFaceHostApi.setCurrentUserStyle(userStyle)
     }
 
-    private inner class SystemStateListener : WatchState.Listener {
-        @SuppressWarnings("SyntheticAccessor")
-        override fun onAmbientModeChanged(isAmbient: Boolean) {
-            scheduleDraw()
+    private val ambientObserver = Observer<Boolean> {
+        scheduleDraw()
+        invalidate()
+    }
+
+    private val interruptionFilterObserver = Observer<Int> {
+        val inMuteMode = it == NotificationManager.INTERRUPTION_FILTER_NONE
+        if (muteMode != inMuteMode) {
+            muteMode = inMuteMode
             invalidate()
         }
-
-        @SuppressWarnings("SyntheticAccessor")
-        override fun onInterruptionFilterChanged(interruptionFilter: Int) {
-            val inMuteMode = interruptionFilter == NotificationManager.INTERRUPTION_FILTER_NONE
-            if (muteMode != inMuteMode) {
-                muteMode = inMuteMode
-                invalidate()
-            }
-        }
-
-        @SuppressWarnings("SyntheticAccessor")
-        override fun onVisibilityChanged(visible: Boolean) {
-            if (visible) {
-                registerReceivers()
-                // Update time zone in case it changed while we weren't visible.
-                calendar.timeZone = TimeZone.getDefault()
-                invalidate()
-            } else {
-                unregisterReceivers()
-            }
-
-            scheduleDraw()
-        }
     }
 
-    private val systemStateListener = SystemStateListener()
+    private val visibilityObserver = Observer<Boolean> {
+        if (it) {
+            registerReceivers()
+            // Update time zone in case it changed while we weren't visible.
+            calendar.timeZone = TimeZone.getDefault()
+            invalidate()
+        } else {
+            unregisterReceivers()
+        }
+
+        scheduleDraw()
+    }
 
     init {
         // We need to inhibit an immediate callback during initialization because members are not
@@ -572,8 +564,9 @@
 
         watchFaceHostApi.registerWatchFaceType(watchFaceType)
         watchFaceHostApi.registerUserStyleSchema(userStyleRepository.userStyleCategories)
-
-        watchState.addListener(systemStateListener)
+        watchState.isAmbient.observe(ambientObserver)
+        watchState.interruptionFilter.observe(interruptionFilterObserver)
+        watchState.isVisible.observe(visibilityObserver)
         userStyleRepository.addUserStyleListener(styleListener)
         sendCurrentUserStyle(userStyleRepository.userStyle)
 
@@ -595,7 +588,9 @@
         pendingUpdateTime.cancel()
         pendingPostDoubleTap.cancel()
         renderer.onDestroy()
-        watchState.removeListener(systemStateListener)
+        watchState.isAmbient.removeObserver(ambientObserver)
+        watchState.interruptionFilter.removeObserver(interruptionFilterObserver)
+        watchState.isVisible.removeObserver(visibilityObserver)
         userStyleRepository.removeUserStyleListener(styleListener)
         WatchFaceConfigActivity.unregisterWatchFace(componentName)
     }
@@ -635,6 +630,12 @@
     }
 
     private fun scheduleDraw() {
+        // Separate calls are issued to deliver the state of isAmbient and isVisible, so during init
+        // we might not yet know the state of both (which is required by the shouldAnimate logic).
+        if (!watchState.isAmbient.hasValue() || !watchState.isVisible.hasValue()) {
+            return
+        }
+
         setCalendarTime(systemTimeProvider.getSystemTimeMillis())
         if (renderer.shouldAnimate()) {
             pendingUpdateTime.postUnique {
@@ -676,14 +677,14 @@
     /** @hide */
     @UiThread
     internal fun maybeUpdateDrawMode() {
-        var newDrawMode = if (watchState.isBatteryLowAndNotCharging) {
+        var newDrawMode = if (watchState.isBatteryLowAndNotCharging.getValueOr(false)) {
             DrawMode.LOW_BATTERY_INTERACTIVE
         } else {
             DrawMode.INTERACTIVE
         }
         // Watch faces may wish to run an animation while entering ambient mode and we let them
         // defer entering ambient mode.
-        if (watchState.isAmbient && !renderer.shouldAnimate()) {
+        if (watchState.isAmbient.value && !renderer.shouldAnimate()) {
             newDrawMode = DrawMode.AMBIENT
         } else if (muteMode) {
             newDrawMode = DrawMode.MUTE
@@ -719,7 +720,7 @@
             Long {
         // Limit update rate to conserve power when the battery is low and not charging.
         val updateRateMillis =
-            if (watchState.isBatteryLowAndNotCharging) {
+            if (watchState.isBatteryLowAndNotCharging.getValueOr(false)) {
                 max(interactiveUpdateRateMillis, MAX_LOW_POWER_INTERACTIVE_UPDATE_RATE_MS)
             } else {
                 interactiveUpdateRateMillis
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
index 51e087a..b15eeff 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
@@ -37,13 +37,16 @@
 import android.support.wearable.watchface.Constants
 import android.support.wearable.watchface.IWatchFaceCommand
 import android.support.wearable.watchface.IWatchFaceService
-import android.support.wearable.watchface.toAshmemCompressedImageBundle
 import android.support.wearable.watchface.accessibility.ContentDescriptionLabel
+import android.support.wearable.watchface.toAshmemCompressedImageBundle
 import android.util.Log
 import android.view.Choreographer
 import android.view.SurfaceHolder
 import androidx.annotation.IntDef
 import androidx.wear.complications.SystemProviders.ProviderId
+import androidx.wear.watchface.data.ImmutableSystemState
+import androidx.wear.watchface.data.IndicatorState
+import androidx.wear.watchface.data.SystemState
 import androidx.wear.watchface.style.StyleUtils
 import androidx.wear.watchface.style.UserStyleCategory
 import java.util.concurrent.CountDownLatch
@@ -257,7 +260,7 @@
     internal open fun getHandler() = Handler(Looper.getMainLooper())
 
     // This is open to allow mocking.
-    internal open fun getSystemState() = WatchState()
+    internal open fun getMutableWatchState() = MutableWatchState()
 
     internal inner class EngineWrapper(
         private val _handler: Handler
@@ -272,8 +275,8 @@
         internal lateinit var iWatchFaceService: IWatchFaceService
         internal lateinit var watchFace: WatchFace
 
-        internal val systemState = getSystemState().apply {
-            onVisibilityChanged(isVisible)
+        internal val mutableWatchState = getMutableWatchState().apply {
+            isVisible.value = this@EngineWrapper.isVisible
         }
 
         private var timeTickRegistered = false
@@ -335,14 +338,14 @@
                 var returnVal: R? = null
                 var exception: Exception? = null
                 if (_handler.post {
-                    try {
-                        returnVal = task.invoke()
-                    } catch (e: Exception) {
-                        // Will rethrow on the calling thread.
-                        exception = e
-                    }
-                    latch.countDown()
-                }) {
+                        try {
+                            returnVal = task.invoke()
+                        } catch (e: Exception) {
+                            // Will rethrow on the calling thread.
+                            exception = e
+                        }
+                        latch.countDown()
+                    }) {
                     latch.await()
                     if (exception != null) {
                         throw exception as Exception
@@ -356,7 +359,7 @@
 
             override fun ambientUpdate() {
                 runOnUiThread {
-                    if (systemState.isAmbient) {
+                    if (mutableWatchState.isAmbient.value) {
                         ambientUpdateWakelock.acquire()
                         watchFace.invalidate()
                         ambientUpdateWakelock.acquire(SURFACE_DRAW_TIMEOUT_MS)
@@ -364,69 +367,75 @@
                 }
             }
 
-            override fun setSystemState(
-                inAmbientMode: Boolean,
-                interruptionFilter: Int,
-                unreadCount: Int,
-                notificationCount: Int
-            ) {
+            override fun setSystemState(systemState: SystemState) {
                 runOnUiThread {
-                    if (firstSetSystemState || inAmbientMode != systemState.isAmbient) {
-                        systemState.onAmbientModeChanged(inAmbientMode)
+                    if (firstSetSystemState ||
+                        systemState.inAmbientMode != mutableWatchState.isAmbient.value
+                    ) {
+                        mutableWatchState.isAmbient.value = systemState.inAmbientMode
                         updateTimeTickReceiver()
                     }
 
-                    if (firstSetSystemState || interruptionFilter !=
-                        systemState.interruptionFilter
+                    if (firstSetSystemState ||
+                        systemState.interruptionFilter != mutableWatchState.interruptionFilter.value
                     ) {
-                        systemState.onInterruptionFilterChanged(interruptionFilter)
+                        mutableWatchState.interruptionFilter.value = systemState.interruptionFilter
                     }
 
-                    if (firstSetSystemState || unreadCount != systemState.unreadNotificationCount) {
-                        systemState.onUnreadNotificationCountChanged(unreadCount)
+                    if (firstSetSystemState ||
+                        systemState.unreadCount != mutableWatchState.unreadNotificationCount.value
+                    ) {
+                        mutableWatchState.unreadNotificationCount.value = systemState.unreadCount
                     }
 
-                    if (firstSetSystemState || notificationCount != systemState.notificationCount) {
-                        systemState.onNotificationCountChanged(notificationCount)
+                    if (firstSetSystemState ||
+                        systemState.notificationCount != mutableWatchState.notificationCount.value
+                    ) {
+                        mutableWatchState.notificationCount.value = systemState.notificationCount
                     }
 
                     firstSetSystemState = false
                 }
             }
 
-            override fun setIndicatorState(
-                isCharging: Boolean,
-                inAirplaneMode: Boolean,
-                isConnectedToCompanion: Boolean,
-                inTheaterMode: Boolean,
-                isGpsActive: Boolean,
-                isKeyguardLocked: Boolean
-            ) {
+            override fun setIndicatorState(indicatorState: IndicatorState) {
                 runOnUiThread {
-                    if (firstIndicatorState || isCharging != systemState.isCharging) {
-                        systemState.onIsChargingChanged(isCharging)
-                    }
-
-                    if (firstIndicatorState || inAirplaneMode != systemState.inAirplaneMode) {
-                        systemState.onInAirplaneModeChanged(inAirplaneMode)
-                    }
-
-                    if (firstIndicatorState || isConnectedToCompanion !=
-                        systemState.isConnectedToCompanion
+                    if (firstIndicatorState ||
+                        indicatorState.isCharging != mutableWatchState.isCharging.value
                     ) {
-                        systemState.onIsConnectedToCompanionChanged(isConnectedToCompanion)
+                        mutableWatchState.isCharging.value = indicatorState.isCharging
                     }
 
-                    if (firstIndicatorState || inTheaterMode != systemState.isInTheaterMode) {
-                        systemState.onInTheaterModeChanged(inTheaterMode)
+                    if (firstIndicatorState ||
+                        indicatorState.inAirplaneMode != mutableWatchState.inAirplaneMode.value
+                    ) {
+                        mutableWatchState.inAirplaneMode.value = indicatorState.inAirplaneMode
                     }
 
-                    if (firstIndicatorState || isGpsActive != systemState.isGpsActive) {
-                        systemState.onIsGpsActiveChanged(isGpsActive)
+                    if (firstIndicatorState ||
+                        indicatorState.isConnectedToCompanion !=
+                        mutableWatchState.isConnectedToCompanion.value
+                    ) {
+                        mutableWatchState.isConnectedToCompanion.value =
+                            indicatorState.isConnectedToCompanion
                     }
 
-                    if (firstIndicatorState || isKeyguardLocked != systemState.isKeyguardLocked) {
-                        systemState.onIsKeyguardLockedChanged(isKeyguardLocked)
+                    if (firstIndicatorState ||
+                        indicatorState.inTheaterMode != mutableWatchState.isInTheaterMode.value
+                    ) {
+                        mutableWatchState.isInTheaterMode.value = indicatorState.inTheaterMode
+                    }
+
+                    if (firstIndicatorState ||
+                        indicatorState.isGpsActive != mutableWatchState.isGpsActive.value
+                    ) {
+                        mutableWatchState.isGpsActive.value = indicatorState.isGpsActive
+                    }
+
+                    if (firstIndicatorState ||
+                        indicatorState.isKeyguardLocked != mutableWatchState.isKeyguardLocked.value
+                    ) {
+                        mutableWatchState.isKeyguardLocked.value = indicatorState.isKeyguardLocked
                     }
 
                     firstIndicatorState = false
@@ -444,15 +453,14 @@
                 }
             }
 
-            override fun setImmutableSystemState(
-                hasLowBitAmbient: Boolean,
-                hasBurnInProtection: Boolean
-            ) {
+            override fun setImmutableSystemState(immutableSystemState: ImmutableSystemState) {
                 runOnUiThread {
                     // These properties never change so set them once only.
                     if (!immutableSystemStateDone) {
-                        systemState.setHasLowBitAmbient(hasLowBitAmbient)
-                        systemState.setHasBurnInProtection(hasBurnInProtection)
+                        mutableWatchState.hasLowBitAmbient.value =
+                            immutableSystemState.hasLowBitAmbient
+                        mutableWatchState.hasBurnInProtection.value =
+                            immutableSystemState.hasBurnInProtection
 
                         immutableSystemStateDone = true
                     }
@@ -488,15 +496,33 @@
             override fun takeWatchfaceScreenshot(
                 drawMode: Int,
                 compressionQuality: Int,
-                calendarTimeMillis: Long
+                calendarTimeMillis: Long,
+                userStyle: Bundle?
             ): Bundle {
                 return runOnUiThread {
-                    watchFace.renderer.takeScreenshot(
+                    val oldStyle = HashMap(watchFace.userStyleRepository.userStyle)
+                    if (userStyle != null) {
+                        watchFace.onSetStyleInternal(
+                            StyleUtils.bundleToStyleMap(
+                                userStyle,
+                                watchFace.userStyleRepository.userStyleCategories
+                            )
+                        )
+                    }
+
+                    val bitmap = watchFace.renderer.takeScreenshot(
                         Calendar.getInstance().apply {
                             timeInMillis = calendarTimeMillis
                         },
                         drawMode
                     )
+
+                    // Restore previous style if required.
+                    if (userStyle != null) {
+                        watchFace.onSetStyleInternal(oldStyle)
+                    }
+
+                    bitmap
                 }.toAshmemCompressedImageBundle(
                     compressionQuality
                 )
@@ -507,7 +533,8 @@
                 drawMode: Int,
                 compressionQuality: Int,
                 calendarTimeMillis: Long,
-                complicationData: ComplicationData?
+                complicationData: ComplicationData?,
+                userStyle: Bundle?
             ): Bundle? {
                 return runOnUiThread {
                     val calendar = Calendar.getInstance().apply {
@@ -515,6 +542,16 @@
                     }
                     val complication = watchFace.complicationsManager[complicationId]
                     if (complication != null) {
+                        val oldStyle = HashMap(watchFace.userStyleRepository.userStyle)
+                        if (userStyle != null) {
+                            watchFace.onSetStyleInternal(
+                                StyleUtils.bundleToStyleMap(
+                                    userStyle,
+                                    watchFace.userStyleRepository.userStyleCategories
+                                )
+                            )
+                        }
+
                         val bounds = complication.computeBounds(watchFace.renderer.screenBounds)
                         val complicationBitmap =
                             Bitmap.createBitmap(
@@ -535,11 +572,15 @@
                             drawMode
                         )
 
-                        // Restore previous ComplicationData if required.
+                        // Restore previous ComplicationData & style if required.
                         if (complicationData != null) {
                             complication.renderer.setData(prevComplicationData)
                         }
 
+                        if (userStyle != null) {
+                            watchFace.onSetStyleInternal(oldStyle)
+                        }
+
                         complicationBitmap.toAshmemCompressedImageBundle(
                             compressionQuality
                         )
@@ -644,21 +685,37 @@
             }
 
             watchFaceCommand.setSystemState(
-                extras.getBoolean(Constants.EXTRA_AMBIENT_MODE, systemState.isAmbient),
-                extras.getInt(Constants.EXTRA_INTERRUPTION_FILTER, systemState.interruptionFilter),
-                extras.getInt(Constants.EXTRA_UNREAD_COUNT, systemState.unreadNotificationCount),
-                extras.getInt(Constants.EXTRA_NOTIFICATION_COUNT, systemState.notificationCount)
+                SystemState(
+                    extras.getBoolean(
+                        Constants.EXTRA_AMBIENT_MODE,
+                        mutableWatchState.isAmbient.getValueOr(false)
+                    ),
+                    extras.getInt(
+                        Constants.EXTRA_INTERRUPTION_FILTER,
+                        mutableWatchState.interruptionFilter.getValueOr(0)
+                    ),
+                    extras.getInt(
+                        Constants.EXTRA_UNREAD_COUNT,
+                        mutableWatchState.unreadNotificationCount.getValueOr(0)
+                    ),
+                    extras.getInt(
+                        Constants.EXTRA_NOTIFICATION_COUNT,
+                        mutableWatchState.notificationCount.getValueOr(0)
+                    )
+                )
             )
 
             val statusBundle = extras.getBundle(Constants.EXTRA_INDICATOR_STATUS)
             if (statusBundle != null) {
                 watchFaceCommand.setIndicatorState(
-                    statusBundle.getBoolean(Constants.STATUS_CHARGING),
-                    statusBundle.getBoolean(Constants.STATUS_AIRPLANE_MODE),
-                    statusBundle.getBoolean(Constants.STATUS_CONNECTED),
-                    statusBundle.getBoolean(Constants.STATUS_THEATER_MODE),
-                    statusBundle.getBoolean(Constants.STATUS_GPS_ACTIVE),
-                    statusBundle.getBoolean(Constants.STATUS_KEYGUARD_LOCKED)
+                    IndicatorState(
+                        statusBundle.getBoolean(Constants.STATUS_CHARGING),
+                        statusBundle.getBoolean(Constants.STATUS_AIRPLANE_MODE),
+                        statusBundle.getBoolean(Constants.STATUS_CONNECTED),
+                        statusBundle.getBoolean(Constants.STATUS_THEATER_MODE),
+                        statusBundle.getBoolean(Constants.STATUS_GPS_ACTIVE),
+                        statusBundle.getBoolean(Constants.STATUS_KEYGUARD_LOCKED)
+                    )
                 )
             }
 
@@ -731,7 +788,7 @@
                 watchFace = createWatchFace(
                     currentSurfaceHolder,
                     host,
-                    systemState
+                    mutableWatchState.asWatchState()
                 )
 
                 // Watchfaces especially OpenGL ones often do initialization in
@@ -784,14 +841,22 @@
          * intent filter depending on whether we are in ambient mode or not.
          */
         internal fun updateTimeTickReceiver() {
+            // Separate calls are issued to deliver the state of isAmbient and isVisible, so during
+            // init we might not yet know the state of both.
+            if (!mutableWatchState.isAmbient.hasValue() ||
+                !mutableWatchState.isVisible.hasValue()
+            ) {
+                return
+            }
+
             if (timeTickRegistered) {
                 unregisterReceiver(timeTickReceiver)
                 timeTickRegistered = false
             }
 
             // We only register if we are visible, otherwise it doesn't make sense to waste cycles.
-            if (systemState.isVisible) {
-                if (systemState.isAmbient) {
+            if (mutableWatchState.isVisible.value) {
+                if (mutableWatchState.isAmbient.value) {
                     registerReceiver(timeTickReceiver, ambientTimeTickFilter)
                 } else {
                     registerReceiver(timeTickReceiver, interactiveTimeTickFilter)
@@ -824,7 +889,7 @@
                 return
             }
 
-            systemState.onVisibilityChanged(visible)
+            mutableWatchState.isVisible.value = visible
             updateTimeTickReceiver()
             pendingVisibilityChanged = null
         }
@@ -878,8 +943,10 @@
             }
 
             watchFaceCommand.setImmutableSystemState(
-                properties.getBoolean(Constants.PROPERTY_LOW_BIT_AMBIENT),
-                properties.getBoolean(Constants.PROPERTY_BURN_IN_PROTECTION)
+                ImmutableSystemState(
+                    properties.getBoolean(Constants.PROPERTY_LOW_BIT_AMBIENT),
+                    properties.getBoolean(Constants.PROPERTY_BURN_IN_PROTECTION)
+                )
             )
         }
 
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchState.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchState.kt
index e80d7a9..1d3ad2f 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchState.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchState.kt
@@ -16,351 +16,120 @@
 
 package androidx.wear.watchface
 
-import android.annotation.SuppressLint
-import android.app.NotificationManager
-import androidx.annotation.UiThread
+import androidx.annotation.RestrictTo
 
-/** An observer for changes in system state which are relevant to watch faces. */
-class WatchState {
-    /** The current user interruption settings. See {@link NotificationManager}. */
-    var interruptionFilter = NotificationManager.INTERRUPTION_FILTER_ALL
-        private set
+class WatchState(
+    /**
+     * The current user interruption settings. See {@link NotificationManager}. Based on the value
+     * the watch face should adjust the amount of information it displays. For example, if it
+     * displays the number of pending emails, it should hide it if interruptionFilter is equal to
+     * {@link NotificationManager.INTERRUPTION_FILTER_NONE}. {@code interruptionFilter} can be
+     * {@link NotificationManager.INTERRUPTION_FILTER_NONE}, {@link
+     * NotificationManager.INTERRUPTION_FILTER_PRIORITY},
+     * {@link NotificationManager.INTERRUPTION_FILTER_ALL},
+     * {@link NotificationManagerINTERRUPTION_FILTER_ALARMS}, or
+     * {@link NotificationManager.INTERRUPTION_FILTER_UNKNOWN}.
+     */
+    val interruptionFilter: WatchData<Int>,
 
-    /** Whether or not the watch is in ambient mode. */
-    var isAmbient = false
-        private set
+    /**
+     * Whether or not the watch is in ambient mode. The watch face should switch to a simplified low
+     * intensity display when in ambient mode. E.g. if the watch face displays seconds, it should
+     * hide them in ambient mode.
+     */
+    val isAmbient: WatchData<Boolean>,
 
     /**
      * Whether or not the watch is in airplane mode. Only valid if
      * {@link android.support.wearable.watchface.WatchFaceStyle#hideNotificationIndicator} is true.
      */
-    @get:JvmName("inAirplaneMode")
-    var inAirplaneMode = false
-        private set
+    val inAirplaneMode: WatchData<Boolean>,
 
     /**
-     * Whether or not we should conserve power due to low battery. Only valid if
-     * {@link android.support.wearable.watchface.WatchFaceStyle#hideNotificationIndicator} is true.
+     * Whether or not we should conserve power due to a low battery which isn't charging. Only
+     * valid if {@link android.support.wearable.watchface
+     * .WatchFaceStyle#hideNotificationIndicator} is true.
      */
-    var isBatteryLowAndNotCharging = false
-        private set
+    val isBatteryLowAndNotCharging: WatchData<Boolean>,
 
     /**
      * Whether or not the watch is charging. Only valid if
      * {@link android.support.wearable.watchface.WatchFaceStyle#hideNotificationIndicator} is true.
      */
-    var isCharging = false
-        private set
+    val isCharging: WatchData<Boolean>,
 
     /**
      * Whether or not the watch is connected to the companion phone. Only valid if
      * {@link android.support.wearable.watchface.WatchFaceStyle#hideNotificationIndicator} is true.
      */
-    var isConnectedToCompanion = false
-        private set
+    val isConnectedToCompanion: WatchData<Boolean>,
 
     /**
      * Whether or not GPS is active on the watch. Only valid if
      * {@link android.support.wearable.watchface.WatchFaceStyle#hideNotificationIndicator} is true.
      */
-    var isGpsActive = false
-        private set
+    val isGpsActive: WatchData<Boolean>,
 
     /**
      * Whether or not the watch's keyguard (lock screen) is locked. Only valid if
      * {@link android.support.wearable.watchface.WatchFaceStyle#hideNotificationIndicator} is true.
      */
-    var isKeyguardLocked = false
-        private set
+    val isKeyguardLocked: WatchData<Boolean>,
 
     /**
      * Whether or not the watch is in theater mode. Only valid if
      * {@link android.support.wearable.watchface.WatchFaceStyle#hideNotificationIndicator} is true.
      */
-    var isInTheaterMode = false
-        private set
+    val isInTheaterMode: WatchData<Boolean>,
 
     /** Whether or not the watch face is visible. */
-    var isVisible = false
-        private set
+    val isVisible: WatchData<Boolean>,
 
     /** The total number of notification cards in the stream. */
-    var notificationCount = 0
-        private set
+    val notificationCount: WatchData<Int>,
 
     /** The total number of unread notification cards in the stream. */
-    var unreadNotificationCount = 0
-        private set
+    val unreadNotificationCount: WatchData<Int>,
 
     /** Whether or not the watch has low bit ambient support. */
-    @get:JvmName("hasLowBitAmbient")
-    var hasLowBitAmbient = false
-        private set
+    val hasLowBitAmbient: WatchData<Boolean>,
 
     /** Whether or not the watch has burn in protection support. */
-    @get:JvmName("hasBurnInProtection")
-    var hasBurnInProtection = false
-        private set
+    val hasBurnInProtection: WatchData<Boolean>
+)
 
-    private val mListeners = HashSet<Listener>()
+/** @hide */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class MutableWatchState {
+    var interruptionFilter = MutableWatchData<Int>()
+    val isAmbient = MutableWatchData<Boolean>()
+    val inAirplaneMode = MutableWatchData<Boolean>()
+    val isBatteryLowAndNotCharging = MutableWatchData<Boolean>()
+    val isCharging = MutableWatchData<Boolean>()
+    val isConnectedToCompanion = MutableWatchData<Boolean>()
+    val isGpsActive = MutableWatchData<Boolean>()
+    val isKeyguardLocked = MutableWatchData<Boolean>()
+    val isInTheaterMode = MutableWatchData<Boolean>()
+    val isVisible = MutableWatchData<Boolean>()
+    val notificationCount = MutableWatchData<Int>()
+    val unreadNotificationCount = MutableWatchData<Int>()
+    val hasLowBitAmbient = MutableWatchData<Boolean>()
+    val hasBurnInProtection = MutableWatchData<Boolean>()
 
-    interface Listener {
-        /**
-         * Called when the device enters or exits ambient mode. The watch face should switch to a
-         * simplified low intensity display when in ambient mode. E.g. if the watch face displays
-         * seconds, it should hide them in ambient mode.
-         *
-         * @param isAmbient Whether or not the device is in ambient mode
-         */
-        @UiThread
-        fun onAmbientModeChanged(isAmbient: Boolean) {}
-
-        /**
-         * Called when the device enters or exits airplane mode.
-         *
-         * @param inAirplaneMode Whether or not the device is in airplane mode
-         */
-        @UiThread
-        fun onInAirplaneModeChanged(inAirplaneMode: Boolean) {}
-
-        /**
-         * Called when the devices enters or exits a condition where the battery is low and not
-         * charging.
-         *
-         * @param isBatteryLowAndNotCharging Whether or not the battery is low and not charging
-         */
-        @UiThread
-        fun onIsBatteryLowAndNotCharging(isBatteryLowAndNotCharging: Boolean) {}
-
-        /**
-         * Called when the device starts or stops charging.
-         *
-         * @param isCharging Whether or not the device is charging
-         */
-        @UiThread
-        fun onIsChargingChanged(isCharging: Boolean) {}
-
-        /**
-         * Called when the device connects or disconnects with the companion phone.
-         *
-         * @param isConnectedToCompanion Whether or not the device is connected to the phone
-         */
-        @UiThread
-        fun onIsConnectedToCompanionChanged(isConnectedToCompanion: Boolean) {}
-
-        /**
-         * Called when GPS is enabled or disabled.
-         *
-         * @param isGpsActive Whether or not GPS is enabled
-         */
-        @UiThread
-        fun onIsGpsActiveChanged(isGpsActive: Boolean) {}
-
-        /**
-         * Called when the keyguard (lock screen) is locked or unlocked.
-         *
-         * @param isKeyguardLocked Whether or not the keyguard (lock screen) is locked
-         */
-        @UiThread
-        fun onIsKeyguardLockedChanged(isKeyguardLocked: Boolean) {}
-
-        /**
-         * Called when the user changes the interruption filter. The watch face should adjust the amount
-         * of information it displays. For example, if it displays the number of pending emails,
-         * it should hide it if interruptionFilter is equal to
-         * {@link NotificationManager.INTERRUPTION_FILTER_NONE}. {@code interruptionFilter} can be
-         * {@link NotificationManager.INTERRUPTION_FILTER_NONE}, {@link
-         * NotificationManager.INTERRUPTION_FILTER_PRIORITY},
-         * {@link NotificationManager.INTERRUPTION_FILTER_ALL},
-         * {@link NotificationManagerINTERRUPTION_FILTER_ALARMS}, or
-         * {@link NotificationManager.INTERRUPTION_FILTER_UNKNOWN}.
-         *
-         * @param interruptionFilter The current interruption filter set by the user
-         */
-        @UiThread
-        fun onInterruptionFilterChanged(interruptionFilter: Int) {}
-
-        /**
-         * Called when the device enters or exits theater mode.
-         *
-         * @param inTheaterMode Whether or not the device is in theater mode
-         */
-        @UiThread
-        fun onInTheaterModeChanged(inTheaterMode: Boolean) {}
-
-        /**
-         * Called when the total number of notification cards in the stream has changed.
-         *
-         * @param notificationCount total number of the notification cards in the stream
-         */
-        @UiThread
-        fun onNotificationCountChanged(notificationCount: Int) {}
-
-        /**
-         * Called when the number of unread notification cards in the stream has changed.
-         *
-         * @param unreadNotificationCount number of the notification cards in the stream that
-         *       haven't yet been seen by the user
-         */
-        @UiThread
-        fun onUnreadNotificationCountChanged(unreadNotificationCount: Int) {}
-
-        /**
-         * Called to inform you of the watch face becoming visible or hidden. Note the
-         * {@link WatchFace} automatically schedules draw calls as necessary.
-         *
-         * @param visible Whether the watch face is visible or hidden
-         */
-        @UiThread
-        fun onVisibilityChanged(visible: Boolean) {}
-
-        /**
-         * Called when we've determined if the device has burn in protection or not.
-         *
-         * @param hasBurnInProtection Whether or not the device has burn in protection
-         */
-        @UiThread
-        fun onHasBurnInProtectionSet(hasBurnInProtection: Boolean) {}
-
-        /**
-         * Called when we've determined if the device has a lower bit depth in ambient mode or not.
-         *
-         * @param hasLowBitAmbient Whether or not the device has a lower bit depth in ambient mode
-         */
-        @UiThread
-        fun onHasLowBitAmbientSet(hasLowBitAmbient: Boolean) {}
-    }
-
-    /**
-     * Adds a {@link Listener} which will be called every time the system state changes.
-     *
-     * @param listener The {@link Listener} to add
-     */
-    @UiThread
-    @SuppressLint("ExecutorRegistration")
-    fun addListener(listener: Listener) {
-        mListeners.add(listener)
-    }
-
-    /**
-     * Removes a {@link Listener} previously added by {@link addListener}.
-     *
-     * @param listener The {@link #Listener} to remove
-     */
-    @UiThread
-    fun removeListener(listener: Listener) {
-        mListeners.remove(listener)
-    }
-
-    @UiThread
-    internal fun onAmbientModeChanged(isAmbient: Boolean) {
-        this.isAmbient = isAmbient
-        for (listener in mListeners) {
-            listener.onAmbientModeChanged(isAmbient)
-        }
-    }
-
-    @UiThread
-    internal fun onInAirplaneModeChanged(inAirplaneMode: Boolean) {
-        this.inAirplaneMode = inAirplaneMode
-        for (listener in mListeners) {
-            listener.onInAirplaneModeChanged(inAirplaneMode)
-        }
-    }
-
-    @UiThread
-    internal fun onIsBatteryLowAndNotCharging(isBatteryLowAndNotCharging: Boolean) {
-        this.isBatteryLowAndNotCharging = isBatteryLowAndNotCharging
-        for (listener in mListeners) {
-            listener.onIsBatteryLowAndNotCharging(isBatteryLowAndNotCharging)
-        }
-    }
-
-    @UiThread
-    internal fun onIsChargingChanged(isCharging: Boolean) {
-        this.isCharging = isCharging
-        for (listener in mListeners) {
-            listener.onIsChargingChanged(isCharging)
-        }
-    }
-
-    @UiThread
-    internal fun onIsConnectedToCompanionChanged(isConnectedToCompanion: Boolean) {
-        this.isConnectedToCompanion = isConnectedToCompanion
-        for (listener in mListeners) {
-            listener.onIsConnectedToCompanionChanged(isConnectedToCompanion)
-        }
-    }
-
-    @UiThread
-    internal fun onIsGpsActiveChanged(isGpsActive: Boolean) {
-        this.isGpsActive = isGpsActive
-        for (listener in mListeners) {
-            listener.onIsGpsActiveChanged(isGpsActive)
-        }
-    }
-
-    @UiThread
-    internal fun onIsKeyguardLockedChanged(isKeyguardLocked: Boolean) {
-        this.isKeyguardLocked = isKeyguardLocked
-        for (listener in mListeners) {
-            listener.onIsKeyguardLockedChanged(isKeyguardLocked)
-        }
-    }
-
-    @UiThread
-    internal fun onInterruptionFilterChanged(interruptionFilter: Int) {
-        this.interruptionFilter = interruptionFilter
-        for (listener in mListeners) {
-            listener.onInterruptionFilterChanged(interruptionFilter)
-        }
-    }
-
-    @UiThread
-    internal fun onInTheaterModeChanged(inTheaterMode: Boolean) {
-        this.isInTheaterMode = inTheaterMode
-        for (listener in mListeners) {
-            listener.onInTheaterModeChanged(inTheaterMode)
-        }
-    }
-
-    @UiThread
-    internal fun onNotificationCountChanged(notificationCount: Int) {
-        this.notificationCount = notificationCount
-        for (listener in mListeners) {
-            listener.onNotificationCountChanged(notificationCount)
-        }
-    }
-
-    @UiThread
-    internal fun onUnreadNotificationCountChanged(unreadNotificationCount: Int) {
-        this.unreadNotificationCount = unreadNotificationCount
-        for (listener in mListeners) {
-            listener.onUnreadNotificationCountChanged(unreadNotificationCount)
-        }
-    }
-
-    @UiThread
-    internal fun onVisibilityChanged(visible: Boolean) {
-        this.isVisible = visible
-        for (listener in mListeners) {
-            listener.onVisibilityChanged(visible)
-        }
-    }
-
-    @UiThread
-    internal fun setHasBurnInProtection(hasBurnInProtection: Boolean) {
-        this.hasBurnInProtection = hasBurnInProtection
-        for (listener in mListeners) {
-            listener.onHasBurnInProtectionSet(hasBurnInProtection)
-        }
-    }
-
-    @UiThread
-    internal fun setHasLowBitAmbient(hasLowBitAmbient: Boolean) {
-        this.hasLowBitAmbient = hasLowBitAmbient
-        for (listener in mListeners) {
-            listener.onHasLowBitAmbientSet(hasLowBitAmbient)
-        }
-    }
-}
+    fun asWatchState() = WatchState(
+        interruptionFilter = interruptionFilter,
+        isAmbient = isAmbient,
+        inAirplaneMode = inAirplaneMode,
+        isBatteryLowAndNotCharging = isBatteryLowAndNotCharging,
+        isCharging = isCharging,
+        isConnectedToCompanion = isConnectedToCompanion,
+        isGpsActive = isGpsActive,
+        isKeyguardLocked = isKeyguardLocked,
+        isInTheaterMode = isInTheaterMode,
+        isVisible = isVisible,
+        notificationCount = notificationCount,
+        unreadNotificationCount = unreadNotificationCount,
+        hasLowBitAmbient = hasLowBitAmbient,
+        hasBurnInProtection = hasBurnInProtection
+    )
+}
\ No newline at end of file
diff --git a/wear/wear-watchface/src/test/java/androidx/wear/watchface/TestCommon.kt b/wear/wear-watchface/src/test/java/androidx/wear/watchface/TestCommon.kt
index 013eb3c..d5e3e1c 100644
--- a/wear/wear-watchface/src/test/java/androidx/wear/watchface/TestCommon.kt
+++ b/wear/wear-watchface/src/test/java/androidx/wear/watchface/TestCommon.kt
@@ -37,12 +37,12 @@
 import org.robolectric.RobolectricTestRunner
 import org.robolectric.internal.bytecode.InstrumentationConfiguration
 
-class TestWatchFaceService(
+internal class TestWatchFaceService(
     @WatchFaceType private val watchFaceType: Int,
     private val complicationsManager: ComplicationsManager,
     private val renderer: TestRenderer,
     private val userStyleRepository: UserStyleRepository,
-    private val watchState: WatchState,
+    private val watchState: MutableWatchState,
     private val handler: Handler,
     private val interactiveFrameRateMs: Long
 ) : WatchFaceService() {
@@ -116,7 +116,7 @@
 
     override fun getHandler() = handler
 
-    override fun getSystemState() = watchState
+    override fun getMutableWatchState() = watchState
 }
 
 /**
diff --git a/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchDataTest.kt b/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchDataTest.kt
new file mode 100644
index 0000000..bfc377d
--- /dev/null
+++ b/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchDataTest.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2020 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.wear.watchface
+
+import androidx.lifecycle.Observer
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.any
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.robolectric.annotation.Config
+
+@Config(manifest = Config.NONE)
+@RunWith(WatchFaceTestRunner::class)
+class WatchDataTest {
+    @Mock
+    private lateinit var observer: Observer<Int>
+
+    @Mock
+    private lateinit var observer2: Observer<Int>
+
+    @Mock
+    private lateinit var observer3: Observer<Int>
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+    }
+
+    @Test
+    fun initialValue() {
+        val data = MutableWatchData(10)
+        assertThat(data.value).isEqualTo(10)
+    }
+
+    @Test
+    fun mutatedValue() {
+        val data = MutableWatchData(10)
+        data.value = 20
+        assertThat(data.value).isEqualTo(20)
+    }
+
+    @Test
+    fun addObserverNoData() {
+        val data = MutableWatchData<Int>()
+        data.observe(observer)
+        verify(observer, never()).onChanged(any())
+    }
+
+    @Test
+    fun addObserver() {
+        val data = MutableWatchData(10)
+        data.observe(observer)
+        verify(observer).onChanged(10)
+    }
+
+    @Test
+    fun addObserverAndAssign() {
+        val data = MutableWatchData(10)
+        data.observe(observer)
+        verify(observer).onChanged(10)
+
+        data.value = 20
+        verify(observer).onChanged(20)
+    }
+
+    @Test
+    fun addObserverNoDataThenAssign() {
+        val data = MutableWatchData<Int>()
+        data.observe(observer)
+
+        data.value = 20
+        verify(observer).onChanged(20)
+    }
+
+    @Test
+    fun addAndRemoveObserver() {
+        val data = MutableWatchData(10)
+        data.observe(observer)
+        data.removeObserver(observer)
+        verify(observer).onChanged(10)
+
+        data.value = 20
+        verify(observer, never()).onChanged(20)
+    }
+
+    @Test
+    fun removeObserverDuringCallback() {
+        val data = MutableWatchData(10)
+        data.observe(observer)
+        data.observe(observer2)
+        data.observe(observer3)
+
+        verify(observer).onChanged(10)
+        verify(observer2).onChanged(10)
+        verify(observer3).onChanged(10)
+
+        // Remove observer2 when observer invoked
+        Mockito.doAnswer {
+            data.removeObserver(observer2)
+        }.`when`(observer).onChanged(20)
+
+        data.value = 20
+        verify(observer2, never()).onChanged(20)
+        verify(observer3).onChanged(20)
+    }
+}
\ No newline at end of file
diff --git a/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt b/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
index 7b14533..59edbee 100644
--- a/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
+++ b/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
@@ -32,6 +32,7 @@
 import android.support.wearable.watchface.accessibility.ContentDescriptionLabel
 import android.view.SurfaceHolder
 import android.view.ViewConfiguration
+import androidx.lifecycle.Observer
 import androidx.test.core.app.ApplicationProvider
 import androidx.wear.complications.SystemProviders
 import androidx.wear.complications.rendering.ComplicationDrawable
@@ -40,6 +41,7 @@
 import androidx.wear.watchface.style.UserStyleCategory
 import androidx.wear.watchface.style.UserStyleRepository
 import com.google.common.truth.Truth.assertThat
+import com.nhaarman.mockitokotlin2.mock
 import org.junit.After
 import org.junit.Before
 import org.junit.Test
@@ -50,7 +52,6 @@
 import org.mockito.ArgumentMatchers.anyLong
 import org.mockito.Mockito.`when`
 import org.mockito.Mockito.doAnswer
-import org.mockito.Mockito.mock
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.times
 import org.mockito.Mockito.validateMockitoUsage
@@ -68,10 +69,10 @@
 @RunWith(WatchFaceTestRunner::class)
 class WatchFaceServiceTest {
 
-    private val handler = mock(Handler::class.java)
-    private val iWatchFaceService = mock(IWatchFaceService::class.java)
-    private val surfaceHolder = mock(SurfaceHolder::class.java)
-    private val systemState = WatchState()
+    private val handler = mock<Handler>()
+    private val iWatchFaceService = mock<IWatchFaceService>()
+    private val surfaceHolder = mock<SurfaceHolder>()
+    private val watchState = MutableWatchState()
 
     init {
         `when`(surfaceHolder.surfaceFrame).thenReturn(ONE_HUNDRED_BY_ONE_HUNDRED_RECT)
@@ -101,7 +102,8 @@
         "Colors",
         "Watchface colorization", /* icon = */
         null,
-        colorStyleList
+        colorStyleList,
+        UserStyleCategory.LAYER_WATCH_FACE_BASE
     )
 
     private val classicStyleOption =
@@ -121,7 +123,8 @@
         "Hand Style",
         "Hand visual look", /* icon = */
         null,
-        watchHandStyleList
+        watchHandStyleList,
+        UserStyleCategory.LAYER_WATCH_FACE_UPPER
     )
 
     private val badStyleOption =
@@ -130,7 +133,10 @@
     private val leftComplication =
         Complication.Builder(
             LEFT_COMPLICATION_ID,
-            ComplicationDrawableRenderer(complicationDrawableLeft, systemState).apply {
+            ComplicationDrawableRenderer(
+                complicationDrawableLeft,
+                watchState.asWatchState()
+            ).apply {
                 setData(createComplicationData())
             },
             intArrayOf(
@@ -148,7 +154,10 @@
     private val rightComplication =
         Complication.Builder(
             RIGHT_COMPLICATION_ID,
-            ComplicationDrawableRenderer(complicationDrawableRight, systemState).apply {
+            ComplicationDrawableRenderer(
+                complicationDrawableRight,
+                watchState.asWatchState()
+            ).apply {
                 setData(createComplicationData())
             },
             intArrayOf(
@@ -166,7 +175,10 @@
     private val backgroundComplication =
         Complication.Builder(
             BACKGROUND_COMPLICATION_ID,
-            ComplicationDrawableRenderer(complicationDrawableRight, systemState).apply {
+            ComplicationDrawableRenderer(
+                complicationDrawableRight,
+                watchState.asWatchState()
+            ).apply {
                 setData(createComplicationData())
             },
             intArrayOf(
@@ -209,13 +221,13 @@
         this.complicationsManager = ComplicationsManager(complications)
         userStyleRepository =
             UserStyleRepository(userStyleCategories)
-        renderer = TestRenderer(surfaceHolder, userStyleRepository, systemState)
+        renderer = TestRenderer(surfaceHolder, userStyleRepository, watchState.asWatchState())
         testWatchFaceService = TestWatchFaceService(
             watchFaceType,
             this.complicationsManager,
             renderer,
             userStyleRepository,
-            systemState,
+            watchState,
             handler,
             INTERACTIVE_UPDATE_RATE_MS
         )
@@ -288,45 +300,43 @@
     @Test
     fun maybeUpdateDrawMode_setsCorrectDrawMode() {
         initEngine(WatchFaceType.ANALOG, listOf(leftComplication, rightComplication), emptyList())
+        watchState.isAmbient.value = false
 
         assertThat(renderer.drawMode).isEqualTo(DrawMode.INTERACTIVE)
 
-        systemState.onIsBatteryLowAndNotCharging(true)
+        watchState.isBatteryLowAndNotCharging.value = true
         watchFace.maybeUpdateDrawMode()
         assertThat(renderer.drawMode).isEqualTo(DrawMode.LOW_BATTERY_INTERACTIVE)
 
-        systemState.onIsBatteryLowAndNotCharging(false)
-        systemState.onAmbientModeChanged(true)
+        watchState.isBatteryLowAndNotCharging.value = false
+        watchState.isAmbient.value = true
         watchFace.maybeUpdateDrawMode()
         assertThat(renderer.drawMode).isEqualTo(DrawMode.AMBIENT)
 
-        systemState.onAmbientModeChanged(false)
+        watchState.isAmbient.value = false
         watchFace.maybeUpdateDrawMode()
         assertThat(renderer.drawMode).isEqualTo(DrawMode.INTERACTIVE)
 
-        systemState.onInterruptionFilterChanged(
-            NotificationManager.INTERRUPTION_FILTER_NONE
-        )
+        watchState.interruptionFilter.value = NotificationManager.INTERRUPTION_FILTER_NONE
         watchFace.maybeUpdateDrawMode()
         assertThat(renderer.drawMode).isEqualTo(DrawMode.MUTE)
 
         // Ambient takes precidence over interruption filter.
-        systemState.onAmbientModeChanged(true)
+        watchState.isAmbient.value = true
         watchFace.maybeUpdateDrawMode()
         assertThat(renderer.drawMode).isEqualTo(DrawMode.AMBIENT)
 
-        systemState.onAmbientModeChanged(false)
-        systemState.onInterruptionFilterChanged(0)
+        watchState.isAmbient.value = false
+        watchState.interruptionFilter.value = 0
         watchFace.maybeUpdateDrawMode()
         assertThat(renderer.drawMode).isEqualTo(DrawMode.INTERACTIVE)
-
-        // WatchFaceService.DrawMode.COMPLICATION_SELECT is tested below.
     }
 
     @Test
     fun onDraw_calendar_setFromSystemTime() {
         initEngine(WatchFaceType.ANALOG, listOf(leftComplication, rightComplication), emptyList())
 
+        watchState.isAmbient.value = false
         testWatchFaceService.mockSystemTimeMillis = 1000L
         watchFace.onDraw()
         assertThat(watchFace.calendar.timeInMillis).isEqualTo(1000L)
@@ -335,6 +345,7 @@
     @Test
     fun onDraw_calendar_affectedCorrectly_with2xMockTime() {
         initEngine(WatchFaceType.ANALOG, listOf(leftComplication, rightComplication), emptyList())
+        watchState.isAmbient.value = false
         testWatchFaceService.mockSystemTimeMillis = 1000L
 
         watchFace.mockTimeReceiver.onReceive(
@@ -358,6 +369,7 @@
     @Test
     fun onDraw_calendar_affectedCorrectly_withMockTimeWrapping() {
         initEngine(WatchFaceType.ANALOG, listOf(leftComplication, rightComplication), emptyList())
+        watchState.isAmbient.value = false
         testWatchFaceService.mockSystemTimeMillis = 1000L
 
         watchFace.mockTimeReceiver.onReceive(
@@ -738,13 +750,14 @@
             listOf(colorStyleCategory, watchHandStyleCategory)
         )
 
-        val testRenderer2 = TestRenderer(surfaceHolder, userStyleRepository2, systemState)
+        val testRenderer2 =
+            TestRenderer(surfaceHolder, userStyleRepository2, watchState.asWatchState())
         val service2 = TestWatchFaceService(
             WatchFaceType.ANALOG,
             ComplicationsManager(emptyList()),
             testRenderer2,
             userStyleRepository2,
-            systemState,
+            watchState,
             handler,
             INTERACTIVE_UPDATE_RATE_MS
         )
@@ -793,13 +806,14 @@
             listOf(colorStyleCategory, watchHandStyleCategory)
         )
 
-        val testRenderer2 = TestRenderer(surfaceHolder, userStyleRepository2, systemState)
+        val testRenderer2 =
+            TestRenderer(surfaceHolder, userStyleRepository2, watchState.asWatchState())
         val service2 = TestWatchFaceService(
             WatchFaceType.ANALOG,
             ComplicationsManager(emptyList()),
             testRenderer2,
             userStyleRepository2,
-            systemState,
+            watchState,
             handler,
             INTERACTIVE_UPDATE_RATE_MS
         )
@@ -837,6 +851,7 @@
     @Test
     fun maybeUpdateStatus_issuesCorrectApiCalls() {
         initEngine(WatchFaceType.ANALOG, emptyList(), emptyList())
+
         val bundle = Bundle().apply {
             putBoolean(Constants.STATUS_CHARGING, true)
             putBoolean(Constants.STATUS_AIRPLANE_MODE, false)
@@ -846,34 +861,49 @@
             putBoolean(Constants.STATUS_KEYGUARD_LOCKED, false)
         }
 
-        val systemStateListener = mock(WatchState.Listener::class.java)
-        systemState.addListener(systemStateListener)
+        val isChargingObserver = mock<Observer<Boolean>>()
+        val inAirplaneModeObserver = mock<Observer<Boolean>>()
+        val isConnectedToCompanionObserver = mock<Observer<Boolean>>()
+        val isInTheaterModeObserver = mock<Observer<Boolean>>()
+        val isGpsActiveObserver = mock<Observer<Boolean>>()
+        val isKeyguardLockedObserver = mock<Observer<Boolean>>()
+        watchState.isCharging.observe(isChargingObserver)
+        watchState.inAirplaneMode.observe(inAirplaneModeObserver)
+        watchState.isConnectedToCompanion.observe(isConnectedToCompanionObserver)
+        watchState.isInTheaterMode.observe(isInTheaterModeObserver)
+        watchState.isGpsActive.observe(isGpsActiveObserver)
+        watchState.isKeyguardLocked.observe(isKeyguardLockedObserver)
 
         // Every indicator onXyz method should be called upon the initial update.
         engineWrapper.onBackgroundAction(Bundle().apply {
             putBundle(Constants.EXTRA_INDICATOR_STATUS, bundle)
         })
 
-        verify(systemStateListener).onIsChargingChanged(true)
-        verify(systemStateListener).onInAirplaneModeChanged(false)
-        verify(systemStateListener).onIsConnectedToCompanionChanged(true)
-        verify(systemStateListener).onInTheaterModeChanged(false)
-        verify(systemStateListener).onIsGpsActiveChanged(true)
-        verify(systemStateListener).onIsKeyguardLockedChanged(false)
+        verify(isChargingObserver).onChanged(true)
+        verify(inAirplaneModeObserver).onChanged(false)
+        verify(isConnectedToCompanionObserver).onChanged(true)
+        verify(isInTheaterModeObserver).onChanged(false)
+        verify(isGpsActiveObserver).onChanged(true)
+        verify(isKeyguardLockedObserver).onChanged(false)
 
-        reset(systemStateListener)
+        reset(isChargingObserver)
+        reset(inAirplaneModeObserver)
+        reset(isConnectedToCompanionObserver)
+        reset(isInTheaterModeObserver)
+        reset(isGpsActiveObserver)
+        reset(isKeyguardLockedObserver)
 
         // Check only the modified setIsCharging state leads to a call.
         bundle.putBoolean(Constants.STATUS_CHARGING, false)
         engineWrapper.onBackgroundAction(Bundle().apply {
             putBundle(Constants.EXTRA_INDICATOR_STATUS, bundle)
         })
-        verify(systemStateListener).onIsChargingChanged(false)
-        verify(systemStateListener, times(0)).onInAirplaneModeChanged(anyBoolean())
-        verify(systemStateListener, times(0)).onIsConnectedToCompanionChanged(anyBoolean())
-        verify(systemStateListener, times(0)).onInTheaterModeChanged(anyBoolean())
-        verify(systemStateListener, times(0)).onIsGpsActiveChanged(anyBoolean())
-        verify(systemStateListener, times(0)).onIsKeyguardLockedChanged(anyBoolean())
+        verify(isChargingObserver).onChanged(false)
+        verify(inAirplaneModeObserver, times(0)).onChanged(anyBoolean())
+        verify(isConnectedToCompanionObserver, times(0)).onChanged(anyBoolean())
+        verify(isInTheaterModeObserver, times(0)).onChanged(anyBoolean())
+        verify(isGpsActiveObserver, times(0)).onChanged(anyBoolean())
+        verify(isKeyguardLockedObserver, times(0)).onChanged(anyBoolean())
     }
 
     @Test
@@ -884,13 +914,15 @@
             putBoolean(Constants.PROPERTY_BURN_IN_PROTECTION, false)
         }
 
-        val systemStateListener = mock(WatchState.Listener::class.java)
-        systemState.addListener(systemStateListener)
+        val hasLowBitAmbientObserver = mock<Observer<Boolean>>()
+        val hasBurnInProtectionObserver = mock<Observer<Boolean>>()
+        watchState.hasLowBitAmbient.observe(hasLowBitAmbientObserver)
+        watchState.hasBurnInProtection.observe(hasBurnInProtectionObserver)
 
         // Check all the right methods are called on initial onPropertiesChanged call.
         engineWrapper.onPropertiesChanged(bundle)
-        verify(systemStateListener).onHasLowBitAmbientSet(true)
-        verify(systemStateListener).onHasBurnInProtectionSet(false)
+        verify(hasLowBitAmbientObserver).onChanged(true)
+        verify(hasBurnInProtectionObserver).onChanged(false)
     }
 
     @Test
@@ -958,13 +990,40 @@
         backgroundComplication.enabled = false
         runPostedTasksFor(0)
 
+        verify(iWatchFaceService).setActiveComplications(
+            intArrayOf(rightComplication.id),
+            true
+        )
+
         // Despite disabling the background complication we should still get a
         // ContentDescriptionLabel for the main clock element.
         val argument = ArgumentCaptor.forClass(Array<ContentDescriptionLabel>::class.java)
         verify(iWatchFaceService).setContentDescriptionLabels(argument.capture())
         assertThat(argument.value.size).isEqualTo(2)
         assertThat(argument.value[0].bounds).isEqualTo(Rect(25, 25, 75, 75)) // Clock element.
-        assertThat(argument.value[1].bounds).isEqualTo(Rect(60, 40, 80, 60)) // Right complicaiton.
+        assertThat(argument.value[1].bounds).isEqualTo(Rect(60, 40, 80, 60)) // Right complication.
+    }
+
+    @Test
+    fun moveComplications() {
+        initEngine(WatchFaceType.ANALOG, listOf(leftComplication, rightComplication), emptyList())
+
+        // Ignore initial setContentDescriptionLabels call.
+        reset(iWatchFaceService)
+
+        leftComplication.unitSquareBounds = RectF(0.3f, 0.3f, 0.5f, 0.5f)
+        rightComplication.unitSquareBounds = RectF(0.7f, 0.75f, 0.9f, 0.95f)
+
+        runPostedTasksFor(0)
+
+        // Despite disabling the background complication we should still get a
+        // ContentDescriptionLabel for the main clock element.
+        val argument = ArgumentCaptor.forClass(Array<ContentDescriptionLabel>::class.java)
+        verify(iWatchFaceService).setContentDescriptionLabels(argument.capture())
+        assertThat(argument.value.size).isEqualTo(3)
+        assertThat(argument.value[0].bounds).isEqualTo(Rect(25, 25, 75, 75)) // Clock element.
+        assertThat(argument.value[1].bounds).isEqualTo(Rect(30, 30, 50, 50)) // Left complication.
+        assertThat(argument.value[2].bounds).isEqualTo(Rect(70, 75, 90, 95)) // Right complication.
     }
 
     @Test
@@ -1003,7 +1062,8 @@
     fun requestStyleBeforeSetBinder() {
         var userStyleRepository =
             UserStyleRepository(emptyList())
-        var testRenderer = TestRenderer(surfaceHolder, userStyleRepository, systemState)
+        var testRenderer =
+            TestRenderer(surfaceHolder, userStyleRepository, watchState.asWatchState())
         val service = TestWatchFaceService(
             WatchFaceType.ANALOG,
             ComplicationsManager(
@@ -1011,7 +1071,7 @@
             ),
             testRenderer,
             UserStyleRepository(emptyList()),
-            systemState,
+            watchState,
             handler,
             INTERACTIVE_UPDATE_RATE_MS
         )
@@ -1036,7 +1096,7 @@
         val provider2 = ComponentName("com.app2", "com.app2.App2")
         val complication = Complication.Builder(
             LEFT_COMPLICATION_ID,
-            ComplicationDrawableRenderer(complicationDrawableLeft, systemState),
+            ComplicationDrawableRenderer(complicationDrawableLeft, watchState.asWatchState()),
             intArrayOf(),
             Complication.DefaultComplicationProviderPolicy(
                 listOf(provider1, provider2),
@@ -1061,7 +1121,7 @@
         val provider2 = ComponentName("com.app2", "com.app2.App2")
         val complication = Complication.Builder(
             LEFT_COMPLICATION_ID,
-            ComplicationDrawableRenderer(complicationDrawableLeft, systemState),
+            ComplicationDrawableRenderer(complicationDrawableLeft, watchState.asWatchState()),
             intArrayOf(),
             Complication.DefaultComplicationProviderPolicy(
                 listOf(provider1, provider2),
@@ -1098,7 +1158,8 @@
     @Test
     fun shouldAnimateOverrideControlsEnteringAmbientMode() {
         var userStyleRepository = UserStyleRepository(emptyList())
-        var testRenderer = object : TestRenderer(surfaceHolder, userStyleRepository, systemState) {
+        var testRenderer = object :
+            TestRenderer(surfaceHolder, userStyleRepository, watchState.asWatchState()) {
             var animate = true
             override fun shouldAnimate() = animate
         }
@@ -1107,7 +1168,7 @@
             ComplicationsManager(emptyList()),
             testRenderer,
             UserStyleRepository(emptyList()),
-            systemState,
+            watchState,
             handler,
             INTERACTIVE_UPDATE_RATE_MS
         )
@@ -1122,7 +1183,7 @@
         watchFace = service.watchFace
 
         // Enter ambient mode.
-        systemState.onAmbientModeChanged(true)
+        watchState.isAmbient.value = true
         watchFace.maybeUpdateDrawMode()
         assertThat(testRenderer.drawMode).isEqualTo(DrawMode.INTERACTIVE)
 
diff --git a/wear/wear-watchface/src/test/java/androidx/wear/watchface/ui/WatchFaceConfigUiTest.kt b/wear/wear-watchface/src/test/java/androidx/wear/watchface/ui/WatchFaceConfigUiTest.kt
index 48e42a3..cc60e3f 100644
--- a/wear/wear-watchface/src/test/java/androidx/wear/watchface/ui/WatchFaceConfigUiTest.kt
+++ b/wear/wear-watchface/src/test/java/androidx/wear/watchface/ui/WatchFaceConfigUiTest.kt
@@ -31,9 +31,9 @@
 import androidx.wear.watchface.Complication
 import androidx.wear.watchface.ComplicationDrawableRenderer
 import androidx.wear.watchface.ComplicationsManager
+import androidx.wear.watchface.MutableWatchState
 import androidx.wear.watchface.Renderer
 import androidx.wear.watchface.WatchFaceTestRunner
-import androidx.wear.watchface.WatchState
 import androidx.wear.watchface.createComplicationData
 import androidx.wear.watchface.style.ListUserStyleCategory
 import androidx.wear.watchface.style.StyleUtils
@@ -66,7 +66,7 @@
     private val watchFaceConfigDelegate = Mockito.mock(WatchFaceConfigDelegate::class.java)
     private val fragmentController = Mockito.mock(FragmentController::class.java)
     private val surfaceHolder = Mockito.mock(SurfaceHolder::class.java)
-    private val systemState = WatchState()
+    private val watchState = MutableWatchState()
 
     private val context: Context = ApplicationProvider.getApplicationContext()
     private val complicationDrawableLeft = ComplicationDrawable(context)
@@ -88,7 +88,8 @@
         "Colors",
         "Watchface colorization", /* icon = */
         null,
-        colorStyleList
+        colorStyleList,
+        UserStyleCategory.LAYER_WATCH_FACE_BASE
     )
 
     private val classicStyleOption =
@@ -108,13 +109,17 @@
         "Hand Style",
         "Hand visual look", /* icon = */
         null,
-        watchHandStyleList
+        watchHandStyleList,
+        UserStyleCategory.LAYER_WATCH_FACE_UPPER
     )
 
     private val leftComplication =
         Complication.Builder(
             LEFT_COMPLICATION_ID,
-            ComplicationDrawableRenderer(complicationDrawableLeft, systemState).apply {
+            ComplicationDrawableRenderer(
+                complicationDrawableLeft,
+                watchState.asWatchState()
+            ).apply {
                 setData(createComplicationData())
             },
             intArrayOf(
@@ -132,7 +137,10 @@
     private val rightComplication =
         Complication.Builder(
             RIGHT_COMPLICATION_ID,
-            ComplicationDrawableRenderer(complicationDrawableRight, systemState).apply {
+            ComplicationDrawableRenderer(
+                complicationDrawableRight,
+                watchState.asWatchState()
+            ).apply {
                 setData(createComplicationData())
             },
             intArrayOf(
@@ -150,7 +158,10 @@
     private val backgroundComplication =
         Complication.Builder(
             BACKGROUND_COMPLICATION_ID,
-            ComplicationDrawableRenderer(complicationDrawableRight, systemState).apply {
+            ComplicationDrawableRenderer(
+                complicationDrawableRight,
+                watchState.asWatchState()
+            ).apply {
                 setData(createComplicationData())
             },
             intArrayOf(
@@ -181,7 +192,7 @@
 
         val complicationSet = ComplicationsManager(
             complications,
-            object : Renderer(surfaceHolder, userStyleRepository, WatchState()) {
+            object : Renderer(surfaceHolder, userStyleRepository, watchState.asWatchState()) {
                 override fun renderInternal(calendar: Calendar) {}
 
                 override fun takeScreenshot(calendar: Calendar, drawMode: Int): Bitmap {
diff --git a/work/workmanager-multiprocess/proguard-rules.pro b/work/workmanager-multiprocess/proguard-rules.pro
index e69de29..40111ea 100644
--- a/work/workmanager-multiprocess/proguard-rules.pro
+++ b/work/workmanager-multiprocess/proguard-rules.pro
@@ -0,0 +1,4 @@
+# This is necessary so that RemoteWorkManager can be initialized (also marked with @Keep)
+-keep class androidx.work.multiprocess.RemoteWorkManagerClient {
+    public <init>(...);
+}
diff --git a/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkContinuationImpl.java b/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkContinuationImpl.java
index 5d03a5f..4acdf02 100644
--- a/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkContinuationImpl.java
+++ b/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkContinuationImpl.java
@@ -19,6 +19,7 @@
 import android.annotation.SuppressLint;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
 import androidx.work.OneTimeWorkRequest;
 import androidx.work.WorkContinuation;
 
@@ -29,7 +30,10 @@
 
 /**
  * An implementation of {@link RemoteWorkContinuation}.
+ *
+ * @hide
  */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public class RemoteWorkContinuationImpl extends RemoteWorkContinuation {
     private final RemoteWorkManagerClient mClient;
     private final WorkContinuation mContinuation;
diff --git a/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkManagerClient.java b/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkManagerClient.java
index 78a990b..1ebb4e4 100644
--- a/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkManagerClient.java
+++ b/work/workmanager-multiprocess/src/main/java/androidx/work/multiprocess/RemoteWorkManagerClient.java
@@ -28,6 +28,7 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 
+import androidx.annotation.Keep;
 import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.VisibleForTesting;
@@ -76,6 +77,7 @@
 
     private Session mSession;
 
+    @Keep
     public RemoteWorkManagerClient(@NonNull Context context, @NonNull WorkManagerImpl workManager) {
         mContext = context.getApplicationContext();
         mWorkManager = workManager;
diff --git a/work/workmanager/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt b/work/workmanager/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt
index de134fa..e4109c6 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt
+++ b/work/workmanager/src/androidTest/java/androidx/work/impl/foreground/SystemForegroundDispatcherTest.kt
@@ -40,6 +40,7 @@
 import androidx.work.impl.foreground.SystemForegroundDispatcher.createCancelWorkIntent
 import androidx.work.impl.foreground.SystemForegroundDispatcher.createNotifyIntent
 import androidx.work.impl.foreground.SystemForegroundDispatcher.createStartForegroundIntent
+import androidx.work.impl.foreground.SystemForegroundDispatcher.createStopForegroundIntent
 import androidx.work.impl.utils.StopWorkRunnable
 import androidx.work.impl.utils.SynchronousExecutor
 import androidx.work.impl.utils.taskexecutor.InstantWorkTaskExecutor
@@ -54,6 +55,7 @@
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mockito.`when`
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.reset
 import org.mockito.Mockito.spy
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
@@ -141,7 +143,7 @@
     fun testStopForeground() {
         // The Foreground Service now calls handleStop() directly without the need for an
         // additional startService().
-        dispatcher.handleStop()
+        dispatcher.handleStop(createStopForegroundIntent(context))
         verify(dispatcherCallback, times(1)).stop()
     }
 
@@ -200,7 +202,7 @@
         verify(dispatcherCallback, times(1))
             .cancelNotification(secondId)
         assertThat(dispatcher.mForegroundInfoById.count(), `is`(1))
-
+        reset(dispatcherCallback)
         dispatcher.onExecuted(secondWorkSpecId, false)
         verify(dispatcherCallback, times(1))
             .cancelNotification(secondId)
diff --git a/work/workmanager/src/main/java/androidx/work/impl/Processor.java b/work/workmanager/src/main/java/androidx/work/impl/Processor.java
index ed88dec..129294d 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/Processor.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/Processor.java
@@ -16,6 +16,7 @@
 package androidx.work.impl;
 
 import static androidx.work.impl.foreground.SystemForegroundDispatcher.createStartForegroundIntent;
+import static androidx.work.impl.foreground.SystemForegroundDispatcher.createStopForegroundIntent;
 
 import android.content.Context;
 import android.content.Intent;
@@ -30,7 +31,6 @@
 import androidx.work.Logger;
 import androidx.work.WorkerParameters;
 import androidx.work.impl.foreground.ForegroundProcessor;
-import androidx.work.impl.foreground.SystemForegroundService;
 import androidx.work.impl.utils.WakeLocks;
 import androidx.work.impl.utils.taskexecutor.TaskExecutor;
 
@@ -308,15 +308,8 @@
         synchronized (mLock) {
             boolean hasForegroundWork = !mForegroundWorkMap.isEmpty();
             if (!hasForegroundWork) {
-                final SystemForegroundService instance = SystemForegroundService.getInstance();
-                if (instance != null) {
-                    Logger.get().debug(TAG,
-                            "No more foreground work. Stopping SystemForegroundService");
-                    instance.stopForegroundService();
-                } else {
-                    Logger.get().debug(TAG,
-                            "No more foreground work. SystemForegroundService is already stopped");
-                }
+                Intent intent = createStopForegroundIntent(mAppContext);
+                mAppContext.startService(intent);
                 // Release wake lock if there is no more pending work.
                 if (mForegroundLock != null) {
                     mForegroundLock.release();
diff --git a/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundDispatcher.java b/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundDispatcher.java
index 8478d84..fcfea94 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundDispatcher.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundDispatcher.java
@@ -71,6 +71,7 @@
     private static final String ACTION_START_FOREGROUND = "ACTION_START_FOREGROUND";
     private static final String ACTION_NOTIFY = "ACTION_NOTIFY";
     private static final String ACTION_CANCEL_WORK = "ACTION_CANCEL_WORK";
+    private static final String ACTION_STOP_FOREGROUND = "ACTION_STOP_FOREGROUND";
 
     private Context mContext;
     private WorkManagerImpl mWorkManagerImpl;
@@ -84,9 +85,6 @@
     String mCurrentForegroundWorkSpecId;
 
     @SuppressWarnings("WeakerAccess") // Synthetic access
-    ForegroundInfo mLastForegroundInfo;
-
-    @SuppressWarnings("WeakerAccess") // Synthetic access
     final Map<String, ForegroundInfo> mForegroundInfoById;
 
     @SuppressWarnings("WeakerAccess") // Synthetic access
@@ -107,7 +105,6 @@
         mWorkManagerImpl = WorkManagerImpl.getInstance(mContext);
         mTaskExecutor = mWorkManagerImpl.getWorkTaskExecutor();
         mCurrentForegroundWorkSpecId = null;
-        mLastForegroundInfo = null;
         mForegroundInfoById = new LinkedHashMap<>();
         mTrackedWorkSpecs = new HashSet<>();
         mWorkSpecById = new HashMap<>();
@@ -148,8 +145,8 @@
             }
         }
 
+        ForegroundInfo removedInfo = mForegroundInfoById.remove(workSpecId);
         // Promote new notifications to the foreground if necessary.
-        mLastForegroundInfo = mForegroundInfoById.remove(workSpecId);
         if (workSpecId.equals(mCurrentForegroundWorkSpecId)) {
             if (mForegroundInfoById.size() > 0) {
                 // Find the next eligible ForegroundInfo
@@ -178,9 +175,23 @@
                     mCallback.cancelNotification(info.getNotificationId());
                 }
             }
-        } else if (mLastForegroundInfo != null && mCallback != null) {
+        }
+        if (removedInfo != null && mCallback != null) {
             // Explicitly decrement the reference count for the notification
-            mCallback.cancelNotification(mLastForegroundInfo.getNotificationId());
+
+            // We are doing this without having to wait for the handleStop() to clean up
+            // Notifications. This is because the Processor stops foreground workers on the
+            // dedicated task executor thread. Meanwhile Notifications are managed on the main
+            // thread, so there is a chance that handleStop() fires before onExecuted() is called
+            // on the main thread.
+            Logger.get().debug(TAG,
+                    String.format("Removing Notification (id: %s, workSpecId: %s ,"
+                                    + "notificationType: %s)",
+                            removedInfo.getNotificationId(),
+                            workSpecId,
+                            removedInfo.getForegroundServiceType())
+            );
+            mCallback.cancelNotification(removedInfo.getNotificationId());
         }
     }
 
@@ -208,6 +219,8 @@
             handleNotify(intent);
         } else if (ACTION_CANCEL_WORK.equals(action)) {
             handleCancelWork(intent);
+        } else if (ACTION_STOP_FOREGROUND.equals(action)) {
+            handleStop(intent);
         }
     }
 
@@ -289,14 +302,9 @@
     }
 
     @MainThread
-    void handleStop() {
+    void handleStop(@NonNull Intent intent) {
         Logger.get().info(TAG, "Stopping foreground service");
         if (mCallback != null) {
-            if (mLastForegroundInfo != null) {
-                // Explicitly decrement the reference count for the notification.
-                mCallback.cancelNotification(mLastForegroundInfo.getNotificationId());
-                mLastForegroundInfo = null;
-            }
             mCallback.stop();
         }
     }
@@ -393,6 +401,19 @@
     }
 
     /**
+     * The {@link Intent} which can be used to stop {@link SystemForegroundService}.
+     *
+     * @param context The application {@link Context}
+     * @return The {@link Intent}
+     */
+    @NonNull
+    public static Intent createStopForegroundIntent(@NonNull Context context) {
+        Intent intent = new Intent(context, SystemForegroundService.class);
+        intent.setAction(ACTION_STOP_FOREGROUND);
+        return  intent;
+    }
+
+    /**
      * Used to notify that all pending commands are now completed.
      */
     interface Callback {
diff --git a/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundService.java b/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundService.java
index 2c9c0f2..f893098 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundService.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/foreground/SystemForegroundService.java
@@ -97,19 +97,6 @@
         mDispatcher.setCallback(this);
     }
 
-    /**
-     * Stops the foreground {@link Service} by asking {@link SystemForegroundDispatcher} to
-     * handle a stop request.
-     */
-    public void stopForegroundService() {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                mDispatcher.handleStop();
-            }
-        });
-    }
-
     @MainThread
     @Override
     public void stop() {
diff --git a/work/workmanager/src/main/java/androidx/work/impl/utils/ProcessUtils.java b/work/workmanager/src/main/java/androidx/work/impl/utils/ProcessUtils.java
index d69e214..bab7665 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/utils/ProcessUtils.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/utils/ProcessUtils.java
@@ -24,6 +24,7 @@
 import android.app.ActivityManager;
 import android.app.Application;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.os.Process;
 import android.text.TextUtils;
 
@@ -57,10 +58,12 @@
             @NonNull Configuration configuration) {
 
         String processName = getProcessName(context);
+
         if (!TextUtils.isEmpty(configuration.getDefaultProcessName())) {
             return TextUtils.equals(processName, configuration.getDefaultProcessName());
         } else {
-            return TextUtils.equals(processName, context.getPackageName());
+            ApplicationInfo info = context.getApplicationInfo();
+            return TextUtils.equals(processName, info.processName);
         }
     }