Merge "Update KSP to alpha07" into androidx-main
diff --git a/activity/activity-ktx/OWNERS b/activity/activity-ktx/OWNERS
index e450f4c..6fd8227 100644
--- a/activity/activity-ktx/OWNERS
+++ b/activity/activity-ktx/OWNERS
@@ -1 +1 @@
-jakew@google.com
+yboyar@google.com
diff --git a/activity/settings.gradle b/activity/settings.gradle
index 387f67e..94d2b98 100644
--- a/activity/settings.gradle
+++ b/activity/settings.gradle
@@ -24,6 +24,8 @@
     if (name == ":internal-testutils-runtime") return true
     if (name == ":compose:lint:common") return true
     if (name == ":compose:lint:internal-lint-checks") return true
+    if (name == ":compose:test-utils") return true
+    if (name == ":test-screenshot") return true
     return false
 })
 
diff --git a/appcompat/appcompat/api/current.txt b/appcompat/appcompat/api/current.txt
index 6b91606..3d0e9f6 100644
--- a/appcompat/appcompat/api/current.txt
+++ b/appcompat/appcompat/api/current.txt
@@ -506,11 +506,16 @@
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSupportButtonTintMode(android.graphics.PorterDuff.Mode?);
   }
 
-  public class AppCompatCheckedTextView extends android.widget.CheckedTextView {
+  public class AppCompatCheckedTextView extends android.widget.CheckedTextView implements androidx.core.view.TintableBackgroundView {
     ctor public AppCompatCheckedTextView(android.content.Context);
     ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet?);
     ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet?, int);
-    method public void setTextAppearance(android.content.Context!, int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.content.res.ColorStateList? getSupportBackgroundTintList();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.graphics.PorterDuff.Mode? getSupportBackgroundTintMode();
+    method public void setBackgroundDrawable(android.graphics.drawable.Drawable?);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSupportBackgroundTintList(android.content.res.ColorStateList?);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode?);
+    method public void setTextAppearance(android.content.Context, int);
   }
 
   public class AppCompatEditText extends android.widget.EditText implements androidx.core.view.OnReceiveContentViewBehavior androidx.core.view.TintableBackgroundView {
diff --git a/appcompat/appcompat/api/public_plus_experimental_current.txt b/appcompat/appcompat/api/public_plus_experimental_current.txt
index 8886644..cef99ba 100644
--- a/appcompat/appcompat/api/public_plus_experimental_current.txt
+++ b/appcompat/appcompat/api/public_plus_experimental_current.txt
@@ -506,11 +506,20 @@
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSupportButtonTintMode(android.graphics.PorterDuff.Mode?);
   }
 
-  public class AppCompatCheckedTextView extends android.widget.CheckedTextView {
+  public class AppCompatCheckedTextView extends android.widget.CheckedTextView implements androidx.core.view.TintableBackgroundView androidx.core.widget.TintableCheckedTextView {
     ctor public AppCompatCheckedTextView(android.content.Context);
     ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet?);
     ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet?, int);
-    method public void setTextAppearance(android.content.Context!, int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.content.res.ColorStateList? getSupportBackgroundTintList();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.graphics.PorterDuff.Mode? getSupportBackgroundTintMode();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.content.res.ColorStateList? getSupportCheckMarkTintList();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.graphics.PorterDuff.Mode? getSupportCheckMarkTintMode();
+    method public void setBackgroundDrawable(android.graphics.drawable.Drawable?);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSupportBackgroundTintList(android.content.res.ColorStateList?);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode?);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSupportCheckMarkTintList(android.content.res.ColorStateList?);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSupportCheckMarkTintMode(android.graphics.PorterDuff.Mode?);
+    method public void setTextAppearance(android.content.Context, int);
   }
 
   public class AppCompatEditText extends android.widget.EditText implements androidx.core.view.OnReceiveContentViewBehavior androidx.core.view.TintableBackgroundView {
diff --git a/appcompat/appcompat/api/restricted_current.txt b/appcompat/appcompat/api/restricted_current.txt
index d86ea87..e0b7fe6 100644
--- a/appcompat/appcompat/api/restricted_current.txt
+++ b/appcompat/appcompat/api/restricted_current.txt
@@ -1374,11 +1374,20 @@
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSupportButtonTintMode(android.graphics.PorterDuff.Mode?);
   }
 
-  public class AppCompatCheckedTextView extends android.widget.CheckedTextView {
+  public class AppCompatCheckedTextView extends android.widget.CheckedTextView implements androidx.core.view.TintableBackgroundView androidx.core.widget.TintableCheckedTextView {
     ctor public AppCompatCheckedTextView(android.content.Context);
     ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet?);
     ctor public AppCompatCheckedTextView(android.content.Context, android.util.AttributeSet?, int);
-    method public void setTextAppearance(android.content.Context!, int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.content.res.ColorStateList? getSupportBackgroundTintList();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.graphics.PorterDuff.Mode? getSupportBackgroundTintMode();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.content.res.ColorStateList? getSupportCheckMarkTintList();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.graphics.PorterDuff.Mode? getSupportCheckMarkTintMode();
+    method public void setBackgroundDrawable(android.graphics.drawable.Drawable?);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSupportBackgroundTintList(android.content.res.ColorStateList?);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode?);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSupportCheckMarkTintList(android.content.res.ColorStateList?);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSupportCheckMarkTintMode(android.graphics.PorterDuff.Mode?);
+    method public void setTextAppearance(android.content.Context, int);
   }
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class AppCompatDrawableManager {
diff --git a/appcompat/appcompat/src/androidTest/AndroidManifest.xml b/appcompat/appcompat/src/androidTest/AndroidManifest.xml
index da2fca5..41d32b4 100644
--- a/appcompat/appcompat/src/androidTest/AndroidManifest.xml
+++ b/appcompat/appcompat/src/androidTest/AndroidManifest.xml
@@ -148,6 +148,11 @@
             android:theme="@style/Theme.AppCompat.Light"/>
 
         <activity
+            android:name="androidx.appcompat.widget.AppCompatCheckedTextViewActivity"
+            android:label="@string/app_compat_checkedtextview_activity"
+            android:theme="@style/Theme.AppCompat.Light"/>
+
+        <activity
             android:name="androidx.appcompat.widget.AppCompatToggleButtonActivity"
             android:label="@string/app_compat_toggle_button_activity"
             android:theme="@style/Theme.AppCompat.Light"/>
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatCheckedTextViewActivity.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatCheckedTextViewActivity.java
new file mode 100644
index 0000000..a0756d2
--- /dev/null
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatCheckedTextViewActivity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.appcompat.widget;
+
+import androidx.appcompat.test.R;
+import androidx.appcompat.testutils.BaseTestActivity;
+
+public final class AppCompatCheckedTextViewActivity extends BaseTestActivity {
+    @Override
+    protected int getContentViewLayoutResId() {
+        return R.layout.appcompat_checkedtextview_activity;
+    }
+}
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatCheckedTextViewTest.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatCheckedTextViewTest.java
new file mode 100644
index 0000000..92e3a95
--- /dev/null
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatCheckedTextViewTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.appcompat.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Typeface;
+import android.graphics.drawable.AnimatedStateListDrawable;
+import android.graphics.drawable.Drawable;
+
+import androidx.appcompat.graphics.drawable.AnimatedStateListDrawableCompat;
+import androidx.appcompat.test.R;
+import androidx.core.content.res.ResourcesCompat;
+import androidx.core.widget.CheckedTextViewCompat;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SdkSuppress;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Provides tests specific to {@link AppCompatCheckedTextView} class.
+ */
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class AppCompatCheckedTextViewTest extends AppCompatBaseViewTest<
+        AppCompatCheckedTextViewActivity, AppCompatCheckedTextView> {
+
+    public AppCompatCheckedTextViewTest() {
+        super(AppCompatCheckedTextViewActivity.class);
+    }
+
+    @Override
+    protected boolean hasBackgroundByDefault() {
+        return true;
+    }
+
+    @Test
+    public void testFontResources() {
+        AppCompatCheckedTextView textView =
+                mContainer.findViewById(R.id.checkedtextview_fontresource);
+        Typeface expected = ResourcesCompat.getFont(mActivity, R.font.samplefont);
+
+        assertEquals(expected, textView.getTypeface());
+    }
+
+    @Test
+    public void testCheckMarkDefault_isNull() {
+        // Given an ACCTV with the theme's check mark drawable
+        final AppCompatCheckedTextView textView =
+                mContainer.findViewById(R.id.checkedtextview_check_mark_default);
+        final Drawable checkMark = CheckedTextViewCompat.getCheckMarkDrawable(textView);
+
+        // Then this drawable should be null
+        assertNull(checkMark);
+    }
+
+    @Test
+    public void testCheckMarkBoth_isAnimated() {
+        // Given an ACCTV which specifies both non-null android:checkMark and app:checkMarkCompat
+        final AppCompatCheckedTextView checkedTextView =
+                mContainer.findViewById(R.id.checkedtextview_check_mark_both);
+        final Drawable checkMark = CheckedTextViewCompat.getCheckMarkDrawable(checkedTextView);
+
+        // Then this drawable should be an animated-selector
+        // i.e. compat version has precedence
+        assertTrue(checkMark instanceof AnimatedStateListDrawableCompat
+                || checkMark instanceof AnimatedStateListDrawable);
+    }
+
+    /* Max SDK as we use this test to verify the fallback behavior in situations where the ASLD
+       backport should not be used (e.g. building with AAPT1). */
+    @SdkSuppress(maxSdkVersion = 20)
+    @Test
+    public void testCheckMarkPlatformOnly_isNotNull() {
+        // Given an ACCTV which specifies a null app:checkMarkCompat and non-null android:checkMark
+        final AppCompatCheckedTextView checkedTextView =
+                mContainer.findViewById(R.id.checkedtextview_check_mark_platform);
+        final Drawable checkMark = CheckedTextViewCompat.getCheckMarkDrawable(checkedTextView);
+
+        // Then the drawable should be present
+        assertNotNull(checkMark);
+    }
+
+    @Test
+    public void testCheckMarkCompatOnly_isNotNull() {
+        // Given an ACCTV which specifies a null android:checkMark and non-null app:checkMarkCompat
+        final AppCompatCheckedTextView checkedTextView =
+                mContainer.findViewById(R.id.checkedtextview_check_mark_compat);
+        final Drawable checkMark = CheckedTextViewCompat.getCheckMarkDrawable(checkedTextView);
+
+        // Then the drawable should be present
+        assertNotNull(checkMark);
+    }
+}
diff --git a/appcompat/appcompat/src/androidTest/res/layout/appcompat_checkedtextview_activity.xml b/appcompat/appcompat/src/androidTest/res/layout/appcompat_checkedtextview_activity.xml
new file mode 100644
index 0000000..02ff5e5
--- /dev/null
+++ b/appcompat/appcompat/src/androidTest/res/layout/appcompat_checkedtextview_activity.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <androidx.appcompat.widget.AppCompatCheckedTextView
+        android:id="@+id/checkedtextview_fontresource"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/sample_text1"
+        app:fontFamily="@font/samplefont" />
+
+    <androidx.appcompat.widget.AppCompatCheckedTextView
+        android:id="@+id/checkedtextview_check_mark_default"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <androidx.appcompat.widget.AppCompatCheckedTextView
+        android:id="@+id/checkedtextview_check_mark_platform"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:checkMark="?android:attr/listChoiceIndicatorMultiple" />
+
+    <androidx.appcompat.widget.AppCompatCheckedTextView
+        android:id="@+id/checkedtextview_check_mark_compat"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:checkMarkCompat="?android:attr/listChoiceIndicatorMultiple" />
+
+    <androidx.appcompat.widget.AppCompatCheckedTextView
+        android:id="@+id/checkedtextview_check_mark_both"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:checkMark="?android:attr/listChoiceIndicatorMultiple"
+        app:checkMarkCompat="?attr/listChoiceIndicatorMultipleAnimated" />
+
+    <androidx.appcompat.widget.AppCompatCheckedTextView
+        android:id="@+id/view_tinted_no_background"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/sample_text1"
+        app:backgroundTint="@color/color_state_list_lilac"
+        app:backgroundTintMode="src_in" />
+
+    <androidx.appcompat.widget.AppCompatCheckedTextView
+        android:id="@+id/view_tinted_background"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/sample_text2"
+        android:background="@drawable/test_drawable"
+        app:backgroundTint="@color/color_state_list_lilac"
+        app:backgroundTintMode="src_in" />
+
+    <androidx.appcompat.widget.AppCompatCheckedTextView
+        android:id="@+id/view_untinted_no_background"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/sample_text2" />
+
+    <androidx.appcompat.widget.AppCompatCheckedTextView
+        android:id="@+id/view_untinted_background"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/sample_text2"
+        android:background="@drawable/test_background_green" />
+
+</LinearLayout>
diff --git a/appcompat/appcompat/src/androidTest/res/values/strings.xml b/appcompat/appcompat/src/androidTest/res/values/strings.xml
index 563bc0e..34698e7 100644
--- a/appcompat/appcompat/src/androidTest/res/values/strings.xml
+++ b/appcompat/appcompat/src/androidTest/res/values/strings.xml
@@ -67,6 +67,7 @@
     <string name="app_compat_image_view_activity">AppCompat image view</string>
     <string name="app_compat_button_activity">AppCompat button</string>
     <string name="app_compat_checkbox_activity">AppCompat checkbox</string>
+    <string name="app_compat_checkedtextview_activity">AppCompat checked text view</string>
     <string name="app_compat_radio_button_activity">AppCompat radio button</string>
     <string name="app_compat_toggle_button_activity">AppCompat toggle button</string>
     <string name="app_compat_icons_activity">AppCompat icons</string>
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatCheckedTextView.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatCheckedTextView.java
index 60d71e1..39d75d1 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatCheckedTextView.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatCheckedTextView.java
@@ -16,33 +16,56 @@
 
 package androidx.appcompat.widget;
 
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
+
 import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.ActionMode;
+import android.view.View;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.widget.CheckedTextView;
+import android.widget.TextView;
 
 import androidx.annotation.DrawableRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.appcompat.R;
 import androidx.appcompat.content.res.AppCompatResources;
+import androidx.core.view.TintableBackgroundView;
+import androidx.core.view.ViewCompat;
 import androidx.core.widget.TextViewCompat;
+import androidx.core.widget.TintableCheckedTextView;
 
 /**
- * A {@link CheckedTextView} which supports compatible features on older versions of the platform.
+ * A {@link CheckedTextView} which supports compatible features on older versions of the platform,
+ * including:
+ * <ul>
+ *     <li>Allows dynamic tint of its background via the background tint methods in
+ *     {@link androidx.core.view.ViewCompat}.</li>
+ *     <li>Allows setting of the background tint using {@link R.attr#backgroundTint} and
+ *     {@link R.attr#backgroundTintMode}.</li>
+ *     <li>Allows dynamic tint of its check mark via the check mark tint methods in
+ *     {@link androidx.core.widget.CheckedTextViewCompat}.</li>
+ *     <li>Allows setting of the check mark tint using {@link R.attr#checkMarkTint} and
+ *     {@link R.attr#checkMarkTintMode}.</li>
+ *     <li>Allows setting of the font family using {@link android.R.attr#fontFamily}</li>
+ * </ul>
  *
  * <p>This will automatically be used when you use {@link CheckedTextView} in your layouts
  * and the top-level activity / dialog is provided by
  * <a href="{@docRoot}topic/libraries/support-library/packages.html#v7-appcompat">appcompat</a>.
  * You should only need to manually use this class when writing custom views.</p>
  */
-public class AppCompatCheckedTextView extends CheckedTextView {
+public class AppCompatCheckedTextView extends CheckedTextView implements TintableCheckedTextView,
+        TintableBackgroundView {
 
-    private static final int[] TINT_ATTRS = {
-            android.R.attr.checkMark
-    };
-
+    private final AppCompatCheckedTextViewHelper mCheckedHelper;
+    private final AppCompatBackgroundHelper mBackgroundTintHelper;
     private final AppCompatTextHelper mTextHelper;
 
     public AppCompatCheckedTextView(@NonNull Context context) {
@@ -50,7 +73,7 @@
     }
 
     public AppCompatCheckedTextView(@NonNull Context context, @Nullable AttributeSet attrs) {
-        this(context, attrs, android.R.attr.checkedTextViewStyle);
+        this(context, attrs, R.attr.checkedTextViewStyle);
     }
 
     public AppCompatCheckedTextView(
@@ -63,10 +86,19 @@
         mTextHelper.loadFromAttributes(attrs, defStyleAttr);
         mTextHelper.applyCompoundDrawablesTints();
 
-        TintTypedArray a = TintTypedArray.obtainStyledAttributes(getContext(), attrs,
-                TINT_ATTRS, defStyleAttr, 0);
-        setCheckMarkDrawable(a.getDrawable(0));
-        a.recycle();
+        mBackgroundTintHelper = new AppCompatBackgroundHelper(this);
+        mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
+
+        mCheckedHelper = new AppCompatCheckedTextViewHelper(this);
+        mCheckedHelper.loadFromAttributes(attrs, defStyleAttr);
+    }
+
+    @Override
+    public void setCheckMarkDrawable(@Nullable Drawable d) {
+        super.setCheckMarkDrawable(d);
+        if (mCheckedHelper != null) {
+            mCheckedHelper.onSetCheckMarkDrawable();
+        }
     }
 
     @Override
@@ -74,8 +106,133 @@
         setCheckMarkDrawable(AppCompatResources.getDrawable(getContext(), resId));
     }
 
+    /**
+     * This should be accessed from {@link androidx.core.widget.CheckedTextViewCompat}
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP_PREFIX)
     @Override
-    public void setTextAppearance(Context context, int resId) {
+    public void setSupportCheckMarkTintList(@Nullable ColorStateList tint) {
+        if (mCheckedHelper != null) {
+            mCheckedHelper.setSupportCheckMarkTintList(tint);
+        }
+    }
+
+    /**
+     * This should be accessed from {@link androidx.core.widget.CheckedTextViewCompat}
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP_PREFIX)
+    @Nullable
+    @Override
+    public ColorStateList getSupportCheckMarkTintList() {
+        return mCheckedHelper != null
+                ? mCheckedHelper.getSupportCheckMarkTintList()
+                : null;
+    }
+
+    /**
+     * This should be accessed from {@link androidx.core.widget.CheckedTextViewCompat}
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP_PREFIX)
+    @Override
+    public void setSupportCheckMarkTintMode(@Nullable PorterDuff.Mode tintMode) {
+        if (mCheckedHelper != null) {
+            mCheckedHelper.setSupportCheckMarkTintMode(tintMode);
+        }
+    }
+
+    /**
+     * This should be accessed from {@link androidx.core.widget.CheckedTextViewCompat}
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP_PREFIX)
+    @Nullable
+    @Override
+    public PorterDuff.Mode getSupportCheckMarkTintMode() {
+        return mCheckedHelper != null
+                ? mCheckedHelper.getSupportCheckMarkTintMode()
+                : null;
+    }
+
+    /**
+     * This should be accessed via
+     * {@link ViewCompat#setBackgroundTintList(View, ColorStateList)}
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP_PREFIX)
+    @Override
+    public void setSupportBackgroundTintList(@Nullable ColorStateList tint) {
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.setSupportBackgroundTintList(tint);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link androidx.core.view.ViewCompat#getBackgroundTintList(android.view.View)}
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP_PREFIX)
+    @Override
+    @Nullable
+    public ColorStateList getSupportBackgroundTintList() {
+        return mBackgroundTintHelper != null
+                ? mBackgroundTintHelper.getSupportBackgroundTintList() : null;
+    }
+
+    /**
+     * This should be accessed via
+     * {@link ViewCompat#setBackgroundTintMode(View, PorterDuff.Mode)}
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP_PREFIX)
+    @Override
+    public void setSupportBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.setSupportBackgroundTintMode(tintMode);
+        }
+    }
+
+    /**
+     * This should be accessed via
+     * {@link androidx.core.view.ViewCompat#getBackgroundTintMode(android.view.View)}
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP_PREFIX)
+    @Override
+    @Nullable
+    public PorterDuff.Mode getSupportBackgroundTintMode() {
+        return mBackgroundTintHelper != null
+                ? mBackgroundTintHelper.getSupportBackgroundTintMode() : null;
+    }
+
+    @Override
+    public void setBackgroundDrawable(@Nullable Drawable background) {
+        super.setBackgroundDrawable(background);
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.onSetBackgroundDrawable(background);
+        }
+    }
+
+    @Override
+    public void setBackgroundResource(@DrawableRes int resId) {
+        super.setBackgroundResource(resId);
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.onSetBackgroundResource(resId);
+        }
+    }
+
+    @Override
+    public void setTextAppearance(@NonNull Context context, int resId) {
         super.setTextAppearance(context, resId);
         if (mTextHelper != null) {
             mTextHelper.onSetTextAppearance(context, resId);
@@ -88,10 +245,17 @@
         if (mTextHelper != null) {
             mTextHelper.applyCompoundDrawablesTints();
         }
+        if (mBackgroundTintHelper != null) {
+            mBackgroundTintHelper.applySupportBackgroundTint();
+        }
+        if (mCheckedHelper != null) {
+            mCheckedHelper.applyCheckMarkTint();
+        }
     }
 
     @Override
-    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+    @Nullable
+    public InputConnection onCreateInputConnection(@NonNull EditorInfo outAttrs) {
         return AppCompatHintHelper.onCreateInputConnection(super.onCreateInputConnection(outAttrs),
                 outAttrs, this);
     }
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatCheckedTextViewHelper.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatCheckedTextViewHelper.java
new file mode 100644
index 0000000..7fe18e6
--- /dev/null
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatCheckedTextViewHelper.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appcompat.widget;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
+
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.widget.CheckedTextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.appcompat.R;
+import androidx.appcompat.content.res.AppCompatResources;
+import androidx.core.graphics.drawable.DrawableCompat;
+import androidx.core.view.ViewCompat;
+import androidx.core.widget.CheckedTextViewCompat;
+
+/** @hide */
+@RestrictTo(LIBRARY)
+class AppCompatCheckedTextViewHelper {
+    @NonNull
+    private final CheckedTextView mView;
+
+    private ColorStateList mCheckMarkTintList = null;
+    private PorterDuff.Mode mCheckMarkTintMode = null;
+    private boolean mHasCheckMarkTint = false;
+    private boolean mHasCheckMarkTintMode = false;
+
+    private boolean mSkipNextApply;
+
+    AppCompatCheckedTextViewHelper(@NonNull CheckedTextView view) {
+        mView = view;
+    }
+
+    void loadFromAttributes(@Nullable AttributeSet attrs, int defStyleAttr) {
+        TintTypedArray a =
+                TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs,
+                        R.styleable.CheckedTextView, defStyleAttr, 0);
+        ViewCompat.saveAttributeDataForStyleable(mView, mView.getContext(),
+                R.styleable.CheckedTextView, attrs, a.getWrappedTypeArray(), defStyleAttr, 0);
+        try {
+            boolean checkMarkDrawableLoaded = false;
+            if (a.hasValue(R.styleable.CheckedTextView_checkMarkCompat)) {
+                final int resourceId = a.getResourceId(R.styleable.CheckedTextView_checkMarkCompat,
+                        0);
+                if (resourceId != 0) {
+                    try {
+                        mView.setCheckMarkDrawable(
+                                AppCompatResources.getDrawable(mView.getContext(), resourceId));
+                        checkMarkDrawableLoaded = true;
+                    } catch (Resources.NotFoundException ignore) {
+                        // Animated checkMarkCompat relies on AAPT2 features. If not found then
+                        // swallow this error and fall back to the regular drawable.
+                    }
+                }
+            }
+            if (!checkMarkDrawableLoaded && a.hasValue(
+                    R.styleable.CheckedTextView_android_checkMark)) {
+                final int resourceId = a.getResourceId(
+                        R.styleable.CheckedTextView_android_checkMark, 0);
+                if (resourceId != 0) {
+                    mView.setCheckMarkDrawable(
+                            AppCompatResources.getDrawable(mView.getContext(), resourceId));
+                }
+            }
+            if (a.hasValue(R.styleable.CheckedTextView_checkMarkTint)) {
+                CheckedTextViewCompat.setCheckMarkTintList(mView,
+                        a.getColorStateList(R.styleable.CheckedTextView_checkMarkTint));
+            }
+            if (a.hasValue(R.styleable.CheckedTextView_checkMarkTintMode)) {
+                CheckedTextViewCompat.setCheckMarkTintMode(mView,
+                        DrawableUtils.parseTintMode(
+                                a.getInt(R.styleable.CheckedTextView_checkMarkTintMode, -1),
+                                null));
+            }
+        } finally {
+            a.recycle();
+        }
+    }
+
+    void setSupportCheckMarkTintList(ColorStateList tint) {
+        mCheckMarkTintList = tint;
+        mHasCheckMarkTint = true;
+
+        applyCheckMarkTint();
+    }
+
+    ColorStateList getSupportCheckMarkTintList() {
+        return mCheckMarkTintList;
+    }
+
+    void setSupportCheckMarkTintMode(@Nullable PorterDuff.Mode tintMode) {
+        mCheckMarkTintMode = tintMode;
+        mHasCheckMarkTintMode = true;
+
+        applyCheckMarkTint();
+    }
+
+    PorterDuff.Mode getSupportCheckMarkTintMode() {
+        return mCheckMarkTintMode;
+    }
+
+    void onSetCheckMarkDrawable() {
+        if (mSkipNextApply) {
+            mSkipNextApply = false;
+            return;
+        }
+
+        mSkipNextApply = true;
+        applyCheckMarkTint();
+    }
+
+    void applyCheckMarkTint() {
+        Drawable checkMarkDrawable = CheckedTextViewCompat.getCheckMarkDrawable(mView);
+
+        if (checkMarkDrawable != null && (mHasCheckMarkTint || mHasCheckMarkTintMode)) {
+            checkMarkDrawable = DrawableCompat.wrap(checkMarkDrawable);
+            checkMarkDrawable = checkMarkDrawable.mutate();
+            if (mHasCheckMarkTint) {
+                DrawableCompat.setTintList(checkMarkDrawable, mCheckMarkTintList);
+            }
+            if (mHasCheckMarkTintMode) {
+                DrawableCompat.setTintMode(checkMarkDrawable, mCheckMarkTintMode);
+            }
+            // The drawable (or one of its children) may not have been
+            // stateful before applying the tint, so let's try again.
+            if (checkMarkDrawable.isStateful()) {
+                checkMarkDrawable.setState(mView.getDrawableState());
+            }
+            mView.setCheckMarkDrawable(checkMarkDrawable);
+        }
+    }
+}
diff --git a/appcompat/appcompat/src/main/res/values/attrs.xml b/appcompat/appcompat/src/main/res/values/attrs.xml
index c758fe3..1f7cb89 100644
--- a/appcompat/appcompat/src/main/res/values/attrs.xml
+++ b/appcompat/appcompat/src/main/res/values/attrs.xml
@@ -1125,6 +1125,35 @@
         </attr>
     </declare-styleable>
 
+    <declare-styleable name="CheckedTextView">
+        <attr name="android:checkMark"/>
+        <!-- Compat attr to load backported drawable types -->
+        <attr name="checkMarkCompat" format="reference"/>
+        <!-- Tint to apply to the check mark drawable. -->
+        <attr name="checkMarkTint" format="color" />
+
+        <!-- Blending mode used to apply the check mark tint. -->
+        <attr name="checkMarkTintMode">
+            <!-- The tint is drawn on top of the drawable.
+                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
+            <enum name="src_over" value="3" />
+            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
+                 color channels are thrown out. [Sa * Da, Sc * Da] -->
+            <enum name="src_in" value="5" />
+            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
+                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
+            <enum name="src_atop" value="9" />
+            <!-- Multiplies the color and alpha channels of the drawable with those of
+                 the tint. [Sa * Da, Sc * Dc] -->
+            <enum name="multiply" value="14" />
+            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+            <enum name="screen" value="15" />
+            <!-- Combines the tint and icon color and alpha channels, clamping the
+                 result to valid color values. Saturate(S + D) -->
+            <enum name="add" value="16" />
+        </attr>
+    </declare-styleable>
+
     <declare-styleable name="SwitchCompat">
         <!-- Drawable to use as the "thumb" that switches back and forth. -->
         <attr name="android:thumb" />
diff --git a/appcompat/appcompat/src/main/res/values/themes_base.xml b/appcompat/appcompat/src/main/res/values/themes_base.xml
index bed6f98..5d505c9 100644
--- a/appcompat/appcompat/src/main/res/values/themes_base.xml
+++ b/appcompat/appcompat/src/main/res/values/themes_base.xml
@@ -298,6 +298,7 @@
 
         <item name="drawerArrowStyle">@style/Widget.AppCompat.DrawerArrowToggle</item>
 
+        <item name="checkedTextViewStyle">?android:attr/checkedTextViewStyle</item>
         <item name="checkboxStyle">@style/Widget.AppCompat.CompoundButton.CheckBox</item>
         <item name="radioButtonStyle">@style/Widget.AppCompat.CompoundButton.RadioButton</item>
         <item name="switchStyle">@style/Widget.AppCompat.CompoundButton.Switch</item>
diff --git a/buildSrc/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt b/buildSrc/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
index f82adad..0e23046 100644
--- a/buildSrc/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/testConfiguration/GenerateTestConfigurationTask.kt
@@ -137,6 +137,8 @@
             configBuilder.isBenchmark(true)
             if (configBuilder.isPostsubmit) {
                 configBuilder.tag("microbenchmarks")
+            } else {
+                configBuilder.tag("microbenchmarks_presubmit")
             }
         } else if (testProjectPath.get().endsWith("macrobenchmark")) {
             configBuilder.tag("macrobenchmarks")
diff --git a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SignInTemplateDemoScreen.java b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SignInTemplateDemoScreen.java
index a1b4f05..000eb03 100644
--- a/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SignInTemplateDemoScreen.java
+++ b/car/app/app-samples/showcase/common/src/main/java/androidx/car/app/sample/showcase/common/templates/SignInTemplateDemoScreen.java
@@ -69,7 +69,7 @@
             () -> getScreenManager().push(new LongMessageTemplateDemoScreen(getCarContext())));
 
     private final Action mProviderSignInAction = new Action.Builder()
-            .setTitle("Sign In with Google")
+            .setTitle("Google Sign-In")
             .setOnClickListener(() -> {
                 mState = State.PROVIDER;
                 invalidate();
@@ -77,7 +77,7 @@
             .build();
 
     private final Action mPinSignInAction = new Action.Builder()
-            .setTitle("Sign In with PIN")
+            .setTitle("Use PIN")
             .setOnClickListener(() -> {
                 mState = State.PIN;
                 invalidate();
diff --git a/car/app/app-samples/showcase/mobile/src/main/AndroidManifest.xml b/car/app/app-samples/showcase/mobile/src/main/AndroidManifest.xml
index 8b58ce6..46ef1092 100644
--- a/car/app/app-samples/showcase/mobile/src/main/AndroidManifest.xml
+++ b/car/app/app-samples/showcase/mobile/src/main/AndroidManifest.xml
@@ -54,8 +54,6 @@
         <action android:name="androidx.car.app.CarAppService"/>
         <category android:name="androidx.car.app.category.NAVIGATION"/>
       </intent-filter>
-      <meta-data android:name="androidx.car.app.CAR_APP_ACTIVITY"
-          android:value="androidx.car.app.samples.showcase.Showcase" />
     </service>
 
     <service
diff --git a/compose/test-utils/build.gradle b/compose/test-utils/build.gradle
index feae637..419ee77 100644
--- a/compose/test-utils/build.gradle
+++ b/compose/test-utils/build.gradle
@@ -29,7 +29,7 @@
 AndroidXUiPlugin.applyAndConfigureKotlinPlugin(project)
 
 dependencies {
-    kotlinPlugin(project(":compose:compiler:compiler"))
+    kotlinPlugin(projectOrArtifact(":compose:compiler:compiler"))
 
     if(!AndroidXUiPlugin.isMultiplatformEnabled(project)) {
         /*
@@ -38,23 +38,23 @@
          */
 
         api("androidx.activity:activity:1.2.0")
-        api(project(":compose:ui:ui-test-junit4"))
+        api(projectOrArtifact(":compose:ui:ui-test-junit4"))
         api(project(":test-screenshot"))
 
         implementation(KOTLIN_STDLIB_COMMON)
-        implementation(project(":compose:runtime:runtime"))
-        implementation(project(":compose:ui:ui-unit"))
-        implementation(project(":compose:ui:ui-graphics"))
+        implementation(projectOrArtifact(":compose:runtime:runtime"))
+        implementation(projectOrArtifact(":compose:ui:ui-unit"))
+        implementation(projectOrArtifact(":compose:ui:ui-graphics"))
         implementation(ANDROIDX_TEST_RULES)
 
         // This has stub APIs for access to legacy Android APIs, so we don't want
         // any dependency on this module.
-        compileOnly(project(":compose:ui:ui-android-stubs"))
+        compileOnly(projectOrArtifact(":compose:ui:ui-android-stubs"))
 
         testImplementation(TRUTH)
 
         androidTestImplementation(TRUTH)
-        androidTestImplementation(project(":compose:material:material"))
+        androidTestImplementation(projectOrArtifact(":compose:material:material"))
     }
 }
 
@@ -68,19 +68,19 @@
         sourceSets {
             commonMain.dependencies {
                 implementation(KOTLIN_STDLIB_COMMON)
-                implementation(project(":compose:runtime:runtime"))
-                implementation(project(":compose:ui:ui-unit"))
-                implementation(project(":compose:ui:ui-graphics"))
-                implementation(project(":compose:ui:ui-test-junit4"))
+                implementation(projectOrArtifact(":compose:runtime:runtime"))
+                implementation(projectOrArtifact(":compose:ui:ui-unit"))
+                implementation(projectOrArtifact(":compose:ui:ui-graphics"))
+                implementation(projectOrArtifact(":compose:ui:ui-test-junit4"))
             }
 
             androidMain.dependencies {
                 api("androidx.activity:activity:1.2.0")
-                api(project(":compose:ui:ui-test-junit4"))
+                api(projectOrArtifact(":compose:ui:ui-test-junit4"))
                 api(project(":test-screenshot"))
                 // This has stub APIs for access to legacy Android APIs, so we don't want
                 // any dependency on this module.
-                compileOnly(project(":compose:ui:ui-android-stubs"))
+                compileOnly(projectOrArtifact(":compose:ui:ui-android-stubs"))
                 implementation(ANDROIDX_TEST_RULES)
             }
 
@@ -90,7 +90,7 @@
 
             androidAndroidTest.dependencies {
                 implementation(TRUTH)
-                implementation(project(":compose:material:material"))
+                implementation(projectOrArtifact(":compose:material:material"))
             }
         }
     }
diff --git a/core/core-ktx/OWNERS b/core/core-ktx/OWNERS
index e450f4c..6fd8227 100644
--- a/core/core-ktx/OWNERS
+++ b/core/core-ktx/OWNERS
@@ -1 +1 @@
-jakew@google.com
+yboyar@google.com
diff --git a/core/core/api/current.txt b/core/core/api/current.txt
index c8e7acb..024bf6e 100644
--- a/core/core/api/current.txt
+++ b/core/core/api/current.txt
@@ -3341,6 +3341,14 @@
     field public static final float RELATIVE_UNSPECIFIED = 0.0f;
   }
 
+  public final class CheckedTextViewCompat {
+    method public static android.graphics.drawable.Drawable? getCheckMarkDrawable(android.widget.CheckedTextView);
+    method public static android.content.res.ColorStateList? getCheckMarkTintList(android.widget.CheckedTextView);
+    method public static android.graphics.PorterDuff.Mode? getCheckMarkTintMode(android.widget.CheckedTextView);
+    method public static void setCheckMarkTintList(android.widget.CheckedTextView, android.content.res.ColorStateList?);
+    method public static void setCheckMarkTintMode(android.widget.CheckedTextView, android.graphics.PorterDuff.Mode?);
+  }
+
   public final class CompoundButtonCompat {
     method public static android.graphics.drawable.Drawable? getButtonDrawable(android.widget.CompoundButton);
     method public static android.content.res.ColorStateList? getButtonTintList(android.widget.CompoundButton);
diff --git a/core/core/api/public_plus_experimental_current.txt b/core/core/api/public_plus_experimental_current.txt
index 10dd3c9..7854121 100644
--- a/core/core/api/public_plus_experimental_current.txt
+++ b/core/core/api/public_plus_experimental_current.txt
@@ -3339,6 +3339,14 @@
     field public static final float RELATIVE_UNSPECIFIED = 0.0f;
   }
 
+  public final class CheckedTextViewCompat {
+    method public static android.graphics.drawable.Drawable? getCheckMarkDrawable(android.widget.CheckedTextView);
+    method public static android.content.res.ColorStateList? getCheckMarkTintList(android.widget.CheckedTextView);
+    method public static android.graphics.PorterDuff.Mode? getCheckMarkTintMode(android.widget.CheckedTextView);
+    method public static void setCheckMarkTintList(android.widget.CheckedTextView, android.content.res.ColorStateList?);
+    method public static void setCheckMarkTintMode(android.widget.CheckedTextView, android.graphics.PorterDuff.Mode?);
+  }
+
   public final class CompoundButtonCompat {
     method public static android.graphics.drawable.Drawable? getButtonDrawable(android.widget.CompoundButton);
     method public static android.content.res.ColorStateList? getButtonTintList(android.widget.CompoundButton);
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index a9f1cae..66203e4 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -3800,6 +3800,14 @@
     field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final boolean PLATFORM_SUPPORTS_AUTOSIZE;
   }
 
+  public final class CheckedTextViewCompat {
+    method public static android.graphics.drawable.Drawable? getCheckMarkDrawable(android.widget.CheckedTextView);
+    method public static android.content.res.ColorStateList? getCheckMarkTintList(android.widget.CheckedTextView);
+    method public static android.graphics.PorterDuff.Mode? getCheckMarkTintMode(android.widget.CheckedTextView);
+    method public static void setCheckMarkTintList(android.widget.CheckedTextView, android.content.res.ColorStateList?);
+    method public static void setCheckMarkTintMode(android.widget.CheckedTextView, android.graphics.PorterDuff.Mode?);
+  }
+
   public final class CompoundButtonCompat {
     method public static android.graphics.drawable.Drawable? getButtonDrawable(android.widget.CompoundButton);
     method public static android.content.res.ColorStateList? getButtonTintList(android.widget.CompoundButton);
@@ -3974,6 +3982,13 @@
     method public androidx.core.view.ContentInfoCompat? onReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
   }
 
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface TintableCheckedTextView {
+    method public android.content.res.ColorStateList? getSupportCheckMarkTintList();
+    method public android.graphics.PorterDuff.Mode? getSupportCheckMarkTintMode();
+    method public void setSupportCheckMarkTintList(android.content.res.ColorStateList?);
+    method public void setSupportCheckMarkTintMode(android.graphics.PorterDuff.Mode?);
+  }
+
   public interface TintableCompoundButton {
     method public android.content.res.ColorStateList? getSupportButtonTintList();
     method public android.graphics.PorterDuff.Mode? getSupportButtonTintMode();
diff --git a/core/core/src/main/java/androidx/core/widget/CheckedTextViewCompat.java b/core/core/src/main/java/androidx/core/widget/CheckedTextViewCompat.java
new file mode 100644
index 0000000..95d06da
--- /dev/null
+++ b/core/core/src/main/java/androidx/core/widget/CheckedTextViewCompat.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.widget;
+
+import static android.os.Build.VERSION.SDK_INT;
+
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+import android.widget.CheckedTextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.core.graphics.drawable.DrawableCompat;
+
+import java.lang.reflect.Field;
+
+/**
+ * Helper for accessing {@link CheckedTextView}.
+ */
+public final class CheckedTextViewCompat {
+    private static final String TAG = "CheckedTextViewCompat";
+
+    private CheckedTextViewCompat() {
+    }
+
+    /**
+     * Applies a tint to the check mark drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     * <p>
+     * Subsequent calls to {@link CheckedTextView#setCheckMarkDrawable(Drawable)} should
+     * automatically mutate the drawable and apply the specified tint and tint
+     * mode using {@link DrawableCompat#setTintList(Drawable, ColorStateList)}.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     * @see #setCheckMarkTintList(CheckedTextView, ColorStateList)
+     */
+    public static void setCheckMarkTintList(@NonNull CheckedTextView textView,
+            @Nullable ColorStateList tint) {
+        if (SDK_INT >= 21) {
+            Api21Impl.setCheckMarkTintList(textView, tint);
+        } else if (textView instanceof TintableCheckedTextView) {
+            ((TintableCheckedTextView) textView).setSupportCheckMarkTintList(tint);
+        }
+    }
+
+    /**
+     * Returns the tint applied to the check mark drawable
+     *
+     * @see #setCheckMarkTintList(CheckedTextView, ColorStateList)
+     */
+    @Nullable
+    public static ColorStateList getCheckMarkTintList(@NonNull CheckedTextView textView) {
+        if (SDK_INT >= 21) {
+            return Api21Impl.getCheckMarkTintList(textView);
+        }
+        if (textView instanceof TintableCheckedTextView) {
+            return ((TintableCheckedTextView) textView).getSupportCheckMarkTintList();
+        }
+        return null;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setCheckMarkTintList(CheckedTextView, ColorStateList)}} to the check mark drawable.
+     * The default mode is {@link PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @see #getCheckMarkTintMode(CheckedTextView)
+     * @see DrawableCompat#setTintMode(Drawable, PorterDuff.Mode)
+     */
+    public static void setCheckMarkTintMode(@NonNull CheckedTextView textView,
+            @Nullable PorterDuff.Mode tintMode) {
+        if (SDK_INT >= 21) {
+            Api21Impl.setCheckMarkTintMode(textView, tintMode);
+        } else if (textView instanceof TintableCheckedTextView) {
+            ((TintableCheckedTextView) textView).setSupportCheckMarkTintMode(tintMode);
+        }
+    }
+
+    /**
+     * @return the blending mode used to apply the tint to the check mark drawable
+     * @attr name android:checkMarkTintMode
+     * @see #setCheckMarkTintMode(CheckedTextView, PorterDuff.Mode)
+     */
+    @Nullable
+    public static PorterDuff.Mode getCheckMarkTintMode(@NonNull CheckedTextView textView) {
+        if (SDK_INT >= 21) {
+            return Api21Impl.getCheckMarkTintMode(textView);
+        }
+        if (textView instanceof TintableCheckedTextView) {
+            return ((TintableCheckedTextView) textView).getSupportCheckMarkTintMode();
+        }
+        return null;
+    }
+
+    /**
+     * Returns the drawable used as the check mark image
+     *
+     * @see CheckedTextView#setCheckMarkDrawable(Drawable)
+     */
+    @Nullable
+    public static Drawable getCheckMarkDrawable(@NonNull CheckedTextView textView) {
+        if (SDK_INT >= 16) {
+            return Api16Impl.getCheckMarkDrawable(textView);
+        } else {
+            return Api14Impl.getCheckMarkDrawable(textView);
+        }
+    }
+
+    @RequiresApi(21)
+    private static class Api21Impl {
+
+        private Api21Impl() {
+        }
+
+        static void setCheckMarkTintList(@NonNull CheckedTextView textView,
+                @Nullable ColorStateList tint) {
+            textView.setCheckMarkTintList(tint);
+        }
+
+        @Nullable
+        static ColorStateList getCheckMarkTintList(@NonNull CheckedTextView textView) {
+            return textView.getCheckMarkTintList();
+        }
+
+        static void setCheckMarkTintMode(@NonNull CheckedTextView textView,
+                @Nullable PorterDuff.Mode tintMode) {
+            textView.setCheckMarkTintMode(tintMode);
+        }
+
+        @Nullable
+        static PorterDuff.Mode getCheckMarkTintMode(@NonNull CheckedTextView textView) {
+            return textView.getCheckMarkTintMode();
+        }
+    }
+
+    @RequiresApi(16)
+    private static class Api16Impl {
+
+        private Api16Impl() {
+        }
+
+        @Nullable
+        static Drawable getCheckMarkDrawable(@NonNull CheckedTextView textView) {
+            return textView.getCheckMarkDrawable();
+        }
+    }
+
+    private static class Api14Impl {
+
+        private static Field sCheckMarkDrawableField;
+        private static boolean sResolved;
+
+        private Api14Impl() {
+        }
+
+        @Nullable
+        static Drawable getCheckMarkDrawable(@NonNull CheckedTextView textView) {
+            if (!sResolved) {
+                try {
+                    sCheckMarkDrawableField =
+                            CheckedTextView.class.getDeclaredField("mCheckMarkDrawable");
+                    sCheckMarkDrawableField.setAccessible(true);
+                } catch (NoSuchFieldException e) {
+                    Log.i(TAG, "Failed to retrieve mCheckMarkDrawable field", e);
+                }
+                sResolved = true;
+            }
+
+            if (sCheckMarkDrawableField != null) {
+                try {
+                    return (Drawable) sCheckMarkDrawableField.get(textView);
+                } catch (IllegalAccessException e) {
+                    Log.i(TAG, "Failed to get check mark drawable via reflection", e);
+                    sCheckMarkDrawableField = null;
+                }
+            }
+            return null;
+        }
+    }
+}
diff --git a/core/core/src/main/java/androidx/core/widget/TintableCheckedTextView.java b/core/core/src/main/java/androidx/core/widget/TintableCheckedTextView.java
new file mode 100644
index 0000000..748987d
--- /dev/null
+++ b/core/core/src/main/java/androidx/core/widget/TintableCheckedTextView.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.widget;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
+
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+
+/**
+ * Interface which allows a {@link android.widget.CheckedTextView} to receive tinting
+ * calls from {@code CheckedTextViewCompat} when running on API v20 devices or lower.
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP_PREFIX)
+public interface TintableCheckedTextView {
+
+    /**
+     * Applies a tint to the check mark drawable. Does not modify the current tint
+     * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     * <p>
+     * Subsequent calls to
+     * {@link android.widget.CheckedTextView#setCheckMarkDrawable(Drawable)
+     * setCheckMarkDrawable(Drawable)}
+     * should automatically mutate the drawable and apply the specified tint and tint mode.
+     *
+     * @param tint the tint to apply, may be {@code null} to clear tint
+     */
+    void setSupportCheckMarkTintList(@Nullable ColorStateList tint);
+
+    /**
+     * Returns the tint applied to the check mark drawable
+     *
+     * @see #setSupportCheckMarkTintList(ColorStateList)
+     */
+    @Nullable
+    ColorStateList getSupportCheckMarkTintList();
+
+    /**
+     * Specifies the blending mode which should be used to apply the tint specified by
+     * {@link #setSupportCheckMarkTintList(ColorStateList)} to the check mark drawable. The
+     * default mode is {@link PorterDuff.Mode#SRC_IN}.
+     *
+     * @param tintMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     *
+     * @see #getSupportCheckMarkTintMode()
+     * @see androidx.core.graphics.drawable.DrawableCompat#setTintMode(Drawable,
+     * PorterDuff.Mode)
+     */
+    void setSupportCheckMarkTintMode(@Nullable PorterDuff.Mode tintMode);
+
+    /**
+     * Returns the blending mode used to apply the tint to the check mark drawable
+     *
+     * @see #setSupportCheckMarkTintMode(PorterDuff.Mode)
+     */
+    @Nullable
+    PorterDuff.Mode getSupportCheckMarkTintMode();
+}
diff --git a/datastore/datastore/src/main/java/androidx/datastore/DataStoreDelegate.kt b/datastore/datastore/src/main/java/androidx/datastore/DataStoreDelegate.kt
index 9ac7640..3e50a16 100644
--- a/datastore/datastore/src/main/java/androidx/datastore/DataStoreDelegate.kt
+++ b/datastore/datastore/src/main/java/androidx/datastore/DataStoreDelegate.kt
@@ -101,7 +101,7 @@
                 val applicationContext = thisRef.applicationContext
                 INSTANCE = DataStoreFactory.create(
                     serializer = serializer,
-                    produceFile = { thisRef.dataStoreFile(fileName) },
+                    produceFile = { applicationContext.dataStoreFile(fileName) },
                     corruptionHandler = corruptionHandler,
                     migrations = produceMigrations(applicationContext),
                     scope = scope
diff --git a/fragment/fragment-ktx/OWNERS b/fragment/fragment-ktx/OWNERS
index e450f4c..6fd8227 100644
--- a/fragment/fragment-ktx/OWNERS
+++ b/fragment/fragment-ktx/OWNERS
@@ -1 +1 @@
-jakew@google.com
+yboyar@google.com
diff --git a/fragment/settings.gradle b/fragment/settings.gradle
index 46fed17..424ef67 100644
--- a/fragment/settings.gradle
+++ b/fragment/settings.gradle
@@ -20,7 +20,7 @@
 setupPlayground(this, "..")
 selectProjectsFromAndroidX({ name ->
     if (name.startsWith(":fragment")) return true
-    if (name.startsWith(":internal-testutils-runtime")) return true
-    if (name.startsWith(":internal-testutils-truth")) return true
+    if (name == ":internal-testutils-runtime") return true
+    if (name == ":internal-testutils-truth") return true
     return false
 })
diff --git a/lifecycle/lifecycle-reactivestreams-ktx/OWNERS b/lifecycle/lifecycle-reactivestreams-ktx/OWNERS
index e450f4c..6fd8227 100644
--- a/lifecycle/lifecycle-reactivestreams-ktx/OWNERS
+++ b/lifecycle/lifecycle-reactivestreams-ktx/OWNERS
@@ -1 +1 @@
-jakew@google.com
+yboyar@google.com
diff --git a/lifecycle/settings.gradle b/lifecycle/settings.gradle
index 84747cf..4ae5e5a 100644
--- a/lifecycle/settings.gradle
+++ b/lifecycle/settings.gradle
@@ -26,6 +26,8 @@
     if (name == ":internal-testutils-truth") return true
     if (name == ":compose:lint:common") return true
     if (name == ":compose:lint:internal-lint-checks") return true
+    if (name == ":compose:test-utils") return true
+    if (name == ":test-screenshot") return true
     return false
 })
 
diff --git a/loader/loader-ktx/OWNERS b/loader/loader-ktx/OWNERS
index e450f4c..6fd8227 100644
--- a/loader/loader-ktx/OWNERS
+++ b/loader/loader-ktx/OWNERS
@@ -1 +1 @@
-jakew@google.com
+yboyar@google.com
diff --git a/navigation/settings.gradle b/navigation/settings.gradle
index 4b2759e..6352fd2 100644
--- a/navigation/settings.gradle
+++ b/navigation/settings.gradle
@@ -25,11 +25,13 @@
     if (name == ":annotation:annotation-sampled") return true
     if (name == ":compose:integration-tests:demos:common") return true
     if (name == ":lifecycle:lifecycle-viewmodel-savedstate") return true
-    if (name.startsWith(":internal-testutils-navigation")) return true
-    if (name.startsWith(":internal-testutils-runtime")) return true
-    if (name.startsWith(":internal-testutils-truth")) return true
+    if (name == ":internal-testutils-navigation") return true
+    if (name == ":internal-testutils-runtime") return true
+    if (name == ":internal-testutils-truth") return true
     if (name == ":compose:lint:common") return true
     if (name == ":compose:lint:internal-lint-checks") return true
+    if (name == ":compose:test-utils") return true
+    if (name == ":test-screenshot") return true
     return false
 })
 
diff --git a/palette/palette-ktx/OWNERS b/palette/palette-ktx/OWNERS
index e450f4c..6fd8227 100644
--- a/palette/palette-ktx/OWNERS
+++ b/palette/palette-ktx/OWNERS
@@ -1 +1 @@
-jakew@google.com
+yboyar@google.com
diff --git a/preference/preference-ktx/OWNERS b/preference/preference-ktx/OWNERS
index e450f4c..6fd8227 100644
--- a/preference/preference-ktx/OWNERS
+++ b/preference/preference-ktx/OWNERS
@@ -1 +1 @@
-jakew@google.com
+yboyar@google.com
diff --git a/room/common/src/main/java/androidx/room/AutoMigration.java b/room/common/src/main/java/androidx/room/AutoMigration.java
index 4c9bc18..54361b0 100644
--- a/room/common/src/main/java/androidx/room/AutoMigration.java
+++ b/room/common/src/main/java/androidx/room/AutoMigration.java
@@ -46,4 +46,11 @@
      * @return Version number of the new database schema.
      */
     int to();
+
+    /**
+     * User implemented custom AutoMigration callback interface.
+     *
+     * @return Null if the user has not implemented a callback
+     */
+    Class<?> callback() default Object.class;
 }
diff --git a/room/common/src/main/java/androidx/room/Database.java b/room/common/src/main/java/androidx/room/Database.java
index 2659bc8..e4f9366 100644
--- a/room/common/src/main/java/androidx/room/Database.java
+++ b/room/common/src/main/java/androidx/room/Database.java
@@ -63,7 +63,7 @@
  */
 @Target(ElementType.TYPE)
 @Retention(RetentionPolicy.CLASS)
-public @interface Database {
+public @interface  Database {
     /**
      * The list of entities included in the database. Each entity turns into a table in the
      * database.
@@ -108,9 +108,9 @@
     /**
      * List of AutoMigrations that can be performed on this Database.
      *
-     * @return List of AutoMigrations.
+     * @return List of AutoMigration annotations.
      * @hide
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    Class<?>[] autoMigrations() default {};
+    AutoMigration[] autoMigrations() default {};
 }
diff --git a/room/common/src/main/java/androidx/room/DeleteColumn.java b/room/common/src/main/java/androidx/room/DeleteColumn.java
new file mode 100644
index 0000000..854b969
--- /dev/null
+++ b/room/common/src/main/java/androidx/room/DeleteColumn.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room;
+
+import androidx.annotation.RestrictTo;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Repeatable annotation to be used by the user in specifying deleted columns in the new versions
+ * of one database.
+ *
+ * @hide
+ */
+@Repeatable(DeleteColumn.Entries.class)
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public @interface DeleteColumn {
+    /**
+     * Name of the table in the previous version of the database the column was deleted from.
+     *
+     * @return Name of the table
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    String tableName();
+
+    /**
+     * Name of the column deleted in the new version of the database.
+     *
+     * @return Name of the column.
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    String deletedColumnName();
+
+    @Target(ElementType.TYPE)
+    @Retention(RetentionPolicy.CLASS)
+    @interface Entries {
+        DeleteColumn[] value();
+    }
+}
diff --git a/room/common/src/main/java/androidx/room/DeleteTable.java b/room/common/src/main/java/androidx/room/DeleteTable.java
new file mode 100644
index 0000000..a8dd32f
--- /dev/null
+++ b/room/common/src/main/java/androidx/room/DeleteTable.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room;
+
+import androidx.annotation.RestrictTo;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Repeatable annotation to be used by the user in specifying deleted tables between the old and
+ * new versions of one database.
+ *
+ * @hide
+ */
+@Repeatable(DeleteTable.Entries.class)
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public @interface DeleteTable {
+    /**
+     * Name of the table in the previous version of the database to be deleted.
+     *
+     * @return Name of the table.
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    String deletedTableName();
+
+    @Target(ElementType.TYPE)
+    @Retention(RetentionPolicy.CLASS)
+    @interface Entries {
+        DeleteTable[] value();
+    }
+}
diff --git a/room/common/src/main/java/androidx/room/RenameColumn.java b/room/common/src/main/java/androidx/room/RenameColumn.java
new file mode 100644
index 0000000..8663c6f
--- /dev/null
+++ b/room/common/src/main/java/androidx/room/RenameColumn.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room;
+
+import androidx.annotation.RestrictTo;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Repeatable annotation to be used by the user in specifying renamed columns between the old and
+ * new versions of one database.
+ *
+ * @hide
+ */
+@Repeatable(RenameColumn.Entries.class)
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public @interface RenameColumn {
+    /**
+     * Name of the table the renamed column is found in.
+     *
+     * @return Name of the table
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    String tableName();
+
+    /**
+     * Original name of the column to be renamed from.
+     *
+     * @return Name of the column in the previous version of the database.
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    String originalColumnName();
+
+    /**
+     * New name of the column to be renamed to.
+     *
+     * @return Name of the column in the new version of the database.
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    String newColumnName();
+
+    @Target(ElementType.TYPE)
+    @Retention(RetentionPolicy.CLASS)
+    @interface Entries {
+        RenameColumn[] value();
+    }
+}
+
diff --git a/room/common/src/main/java/androidx/room/RenameTable.java b/room/common/src/main/java/androidx/room/RenameTable.java
new file mode 100644
index 0000000..4599033
--- /dev/null
+++ b/room/common/src/main/java/androidx/room/RenameTable.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room;
+
+import androidx.annotation.RestrictTo;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * Repeatable annotation to be used by the user in specifying renamed tables between the old and
+ * new versions of one database.
+ *
+ * @hide
+ */
+@Repeatable(RenameTable.Entries.class)
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public @interface RenameTable {
+    /**
+     * Name of the table in the previous version of the database.
+     *
+     * @return Original name of the table.
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    String originalTableName();
+
+    /**
+     * Name of the table in the new version of the database.
+     *
+     * @return New name of the table.
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    String newTableName();
+
+    @Target(ElementType.TYPE)
+    @Retention(RetentionPolicy.CLASS)
+    @interface Entries {
+        RenameTable[] value();
+    }
+}
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/AutoMigrationProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/AutoMigrationProcessor.kt
index 1a8aa08..a6ddb62 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/AutoMigrationProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/AutoMigrationProcessor.kt
@@ -16,22 +16,30 @@
 
 package androidx.room.processor
 
-import androidx.room.AutoMigration
+import androidx.room.DeleteColumn
+import androidx.room.DeleteTable
+import androidx.room.RenameColumn
+import androidx.room.RenameTable
+import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.XTypeElement
 import androidx.room.ext.RoomTypeNames
 import androidx.room.migration.bundle.DatabaseBundle
 import androidx.room.migration.bundle.SchemaBundle.deserialize
+import androidx.room.processor.ProcessorErrors.AUTOMIGRATION_CALLBACK_MUST_BE_INTERFACE
+import androidx.room.processor.ProcessorErrors.autoMigrationElementMustExtendCallback
+import androidx.room.processor.ProcessorErrors.autoMigrationToVersionMustBeGreaterThanFrom
 import androidx.room.util.DiffException
 import androidx.room.util.SchemaDiffer
 import androidx.room.vo.AutoMigrationResult
 import java.io.File
 
 // TODO: (b/183435544) Support downgrades in AutoMigrations.
-// TODO: (b/183007590) Use the callback in the AutoMigration annotation while end-to-end
-//  testing, when column/table rename/deletes are supported
 class AutoMigrationProcessor(
-    val context: Context,
     val element: XTypeElement,
+    val context: Context,
+    val from: Int,
+    val to: Int,
+    val callback: XType,
     val latestDbSchema: DatabaseBundle
 ) {
     /**
@@ -41,41 +49,36 @@
      * @return the AutoMigrationResult containing the schema changes detected
      */
     fun process(): AutoMigrationResult? {
-        if (!element.isInterface()) {
-            context.logger.e(
-                ProcessorErrors.AUTOMIGRATION_ANNOTATED_TYPE_ELEMENT_MUST_BE_INTERFACE,
-                element
-            )
-            return null
-        }
+        val callbackElement = callback.typeElement
+        if (!callback.isTypeOf(Any::class)) {
+            if (callbackElement == null) {
+                context.logger.e(element, AUTOMIGRATION_CALLBACK_MUST_BE_INTERFACE)
+                return null
+            }
 
-        if (!context.processingEnv
-            .requireType(RoomTypeNames.AUTO_MIGRATION_CALLBACK)
-            .isAssignableFrom(element.type)
-        ) {
-            context.logger.e(
-                ProcessorErrors.AUTOMIGRATION_ELEMENT_MUST_IMPLEMENT_AUTOMIGRATION_CALLBACK,
-                element
-            )
-            return null
-        }
+            if (!callbackElement.isInterface()) {
+                context.logger.e(
+                    callbackElement,
+                    AUTOMIGRATION_CALLBACK_MUST_BE_INTERFACE
+                )
+                return null
+            }
 
-        val annotationBox = element.getAnnotation(AutoMigration::class)
-        if (annotationBox == null) {
-            context.logger.e(
-                element,
-                ProcessorErrors.AUTOMIGRATION_ANNOTATION_MISSING
-            )
-            return null
+            val extendsMigrationCallback =
+                context.processingEnv.requireType(RoomTypeNames.AUTO_MIGRATION_CALLBACK)
+                    .isAssignableFrom(callback)
+            if (!extendsMigrationCallback) {
+                context.logger.e(
+                    callbackElement,
+                    autoMigrationElementMustExtendCallback(callbackElement.className.simpleName())
+                )
+                return null
+            }
         }
 
-        val from = annotationBox.value.from
-        val to = annotationBox.value.to
-
         if (to <= from) {
             context.logger.e(
-                ProcessorErrors.autoMigrationToVersionMustBeGreaterThanFrom(to, from),
-                element
+                autoMigrationToVersionMustBeGreaterThanFrom(to, from)
             )
             return null
         }
@@ -94,10 +97,52 @@
             }
         }
 
+        val callbackClassName = callbackElement?.className?.simpleName()
+        val deleteColumnEntries = callbackElement?.let { element ->
+            element.getAnnotations(DeleteColumn::class).map {
+                AutoMigrationResult.DeletedColumn(
+                    tableName = it.value.tableName,
+                    columnName = it.value.deletedColumnName
+                )
+            }
+        } ?: emptyList()
+
+        val deleteTableEntries = callbackElement?.let { element ->
+            element.getAnnotations(DeleteTable::class).map {
+                AutoMigrationResult.DeletedTable(
+                    deletedTableName = it.value.deletedTableName
+                )
+            }
+        } ?: emptyList()
+
+        val renameTableEntries = callbackElement?.let { element ->
+            element.getAnnotations(RenameTable::class).map {
+                AutoMigrationResult.RenamedTable(
+                    originalTableName = it.value.originalTableName,
+                    newTableName = it.value.newTableName
+                )
+            }
+        } ?: emptyList()
+
+        val renameColumnEntries = callbackElement?.let { element ->
+            element.getAnnotations(RenameColumn::class).map {
+                AutoMigrationResult.RenamedColumn(
+                    tableName = it.value.tableName,
+                    originalColumnName = it.value.originalColumnName,
+                    newColumnName = it.value.newColumnName
+                )
+            }
+        } ?: emptyList()
+
         val schemaDiff = try {
             SchemaDiffer(
                 fromSchemaBundle = fromSchemaBundle,
-                toSchemaBundle = toSchemaBundle
+                toSchemaBundle = toSchemaBundle,
+                className = callbackClassName,
+                deleteColumnEntries = deleteColumnEntries,
+                deleteTableEntries = deleteTableEntries,
+                renameTableEntries = renameTableEntries,
+                renameColumnEntries = renameColumnEntries
             ).diffSchemas()
         } catch (ex: DiffException) {
             context.logger.e(ex.errorMessage)
@@ -116,13 +161,13 @@
     private fun getValidatedSchemaFile(version: Int): File? {
         val schemaFile = File(
             context.schemaOutFolder,
-            "${element.className.enclosingClassName()}/$version.json"
+            "${element.className.canonicalName()}/$version.json"
         )
         if (!schemaFile.exists()) {
             context.logger.e(
                 ProcessorErrors.autoMigrationSchemasNotFound(
                     context.schemaOutFolder.toString(),
-                    "${element.className.enclosingClassName()}/$version.json"
+                    "${element.className.canonicalName()}/$version.json"
                 ),
                 element
             )
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt
index 35ca51e..76dcc58 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/DatabaseProcessor.kt
@@ -16,6 +16,7 @@
 
 package androidx.room.processor
 
+import androidx.room.AutoMigration
 import androidx.room.SkipQueryVerification
 import androidx.room.compiler.processing.XAnnotationBox
 import androidx.room.compiler.processing.XElement
@@ -126,7 +127,8 @@
         latestDbSchema: DatabaseBundle
     ): List<AutoMigrationResult> {
         val dbAnnotation = element.getAnnotation(androidx.room.Database::class)!!
-        val autoMigrationList = dbAnnotation.getAsTypeList("autoMigrations")
+        val autoMigrationList = dbAnnotation
+            .getAsAnnotationBoxArray<AutoMigration>("autoMigrations")
         context.checker.check(
             autoMigrationList.isEmpty() || dbAnnotation.value.exportSchema,
             element,
@@ -134,22 +136,15 @@
         )
 
         return autoMigrationList.mapNotNull {
-            val typeElement = it.typeElement
-            if (typeElement == null) {
-                context.logger.e(
-                    element,
-                    ProcessorErrors.invalidAutoMigrationTypeInDatabaseAnnotation(
-                        it.typeName
-                    )
-                )
-                null
-            } else {
-                AutoMigrationProcessor(
-                    context = context,
-                    element = typeElement,
-                    latestDbSchema = latestDbSchema
-                ).process()
-            }
+            val autoMigration = it.value
+            AutoMigrationProcessor(
+                element = element,
+                context = context,
+                from = autoMigration.from,
+                to = autoMigration.to,
+                callback = it.getAsType("callback")!!,
+                latestDbSchema = latestDbSchema
+            ).process()
         }
     }
 
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 a426677..f6a8799 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
@@ -793,9 +793,9 @@
             "interface."
     }
 
-    fun invalidAutoMigrationTypeInDatabaseAnnotation(typeName: TypeName): String {
-        return "Invalid AutoMigration type: $typeName. An automigration in the database must be a" +
-            " class."
+    fun invalidAutoMigrationTypeInDatabaseAnnotation(): String {
+        return "Invalid AutoMigration type: An automigration in the database must be " +
+            "an @AutoMigration annotation."
     }
 
     val EMBEDDED_TYPES_MUST_BE_A_CLASS_OR_INTERFACE = "The type of an Embedded field must be a " +
@@ -809,12 +809,13 @@
         return "Invalid query argument: $typeName. It must be a class or an interface."
     }
 
-    val AUTOMIGRATION_ANNOTATED_TYPE_ELEMENT_MUST_BE_INTERFACE = "The @AutoMigration annotated " +
+    val AUTOMIGRATION_CALLBACK_MUST_BE_INTERFACE = "The @AutoMigration callback " +
         "type must be an interface."
-    val AUTOMIGRATION_ANNOTATION_MISSING = "The @AutoMigration annotation has not been found. " +
-        "Cannot generate auto migrations."
-    val AUTOMIGRATION_ELEMENT_MUST_IMPLEMENT_AUTOMIGRATION_CALLBACK = "AutoMigration element must" +
-        " implement the AutoMigrationCallback interface."
+
+    fun autoMigrationElementMustExtendCallback(callback: String): String {
+        return "The AutoMigration callback " +
+            "$callback must extend the AutoMigrationCallback interface."
+    }
 
     // TODO: (b/180389433) If the files don't exist the getSchemaFile() method should return
     //  null and before calling process
@@ -838,40 +839,109 @@
             "@ColumnInfo."
     }
 
-    fun nullabilityOfColumnChangedNotNullColumnMustHaveDefaultValue(columnName: String): String {
-        return "The nullability of the " +
-            "column '$columnName' " +
-            "has been changed from NULL to NOT NULL with no default value specified. Please " +
-            "specify the default value using @ColumnInfo."
-    }
-
     fun columnWithChangedSchemaFound(columnName: String): String {
         return "Encountered column '$columnName' with an unsupported schema change at the column " +
             "level (e.g. affinity change). These changes are not yet " +
             "supported by AutoMigration."
     }
 
-    fun removedOrRenamedColumnFound(columnName: String): String {
-        return "Column '$columnName' has been either removed or " +
-            "renamed. This change is not currently supported by AutoMigration."
+    fun deletedOrRenamedColumnFound(
+        className: String?,
+        columnName: String,
+        tableName: String
+    ): String {
+        return if (className != null) {
+            """
+            AutoMigration Failure in ‘$className’: Column ‘$columnName’ in table ‘$tableName’ has
+            been either removed or renamed. Please annotate ‘$className’ with the @RenameColumn
+            or @RemoveColumn annotation to specify the change to be performed:
+            1) RENAME: @RenameColumn.Entries(
+                    @RenameColumn(
+                        tableName = "$tableName",
+                        originalColumnName = "$columnName",
+                        newColumnName = <NEW_COLUMN_NAME>
+                    )
+                )
+            2) DELETE: @DeleteColumn.Entries(
+                    @DeleteColumn=(
+                        tableName = "$tableName",
+                        deletedColumnName = "$columnName"
+                    )
+                )
+            """
+        } else {
+            """
+            AutoMigration Failure: Please declare an interface extending 'AutoMigrationCallback',
+            and annotate with the @RenameColumn or @RemoveColumn annotation to specify the
+            change to be performed:
+            1) RENAME: @RenameColumn.Entries(
+                    @RenameColumn(
+                        tableName = "$tableName",
+                        originalColumnName = "$columnName",
+                        newColumnName = <NEW_COLUMN_NAME>
+                    )
+                )
+            2) DELETE: @DeleteColumn.Entries(
+                    @DeleteColumn=(
+                        tableName = "$tableName",
+                        deletedColumnName = "$columnName"
+                    )
+                )
+            """
+        }
     }
 
-    fun tableWithComplexChangedSchemaFound(tableName: String): String {
-        return "Encountered table '$tableName' with an unsupported schema change at the table " +
-            "level (e.g. primary key, foreign key or index change). These changes are not yet " +
-            "supported by AutoMigration."
+    fun deletedOrRenamedTableFound(
+        className: String?,
+        tableName: String
+    ): String {
+        return if (className != null) {
+            """
+            AutoMigration Failure in '$className': Table '$tableName' has been either removed or
+            renamed. Please annotate '$className' with the @RenameTable or @RemoveTable
+            annotation to specify the change to be performed:
+            1) RENAME: @RenameTable.Entries(
+                    @RenameTable(originalTableName = "$tableName", newTableName = <NEW_TABLE_NAME>))
+            2) DELETE: @DeleteTable.Entries(@DeleteTable(deletedTableName = "$tableName"))
+            """
+        } else {
+            """
+            AutoMigration Failure: Please declare an interface extending 'AutoMigrationCallback',
+            and annotate with the @RenameTable or @RemoveTable
+            annotation to specify the change to be performed:
+            1) RENAME: @RenameTable.Entries(
+                    @RenameTable(originalTableName = "$tableName", newTableName = <NEW_TABLE_NAME>))
+            2) DELETE: @DeleteTable.Entries(@DeleteTable(deletedTableName = "$tableName"))
+            """
+        }
     }
 
-    fun removedOrRenamedTableFound(tableName: String): String {
-        return "Table '$tableName' has been either removed or " +
-            "renamed. This change is not currently supported by AutoMigration."
+    fun tableRenameError(
+        className: String,
+        originalTableName: String,
+        newTableName: String
+    ): String {
+        return "AutoMigration Failure in '$className': The table renamed from " +
+            "'$originalTableName' to '$newTableName' is " +
+            "not found in the new version of the database."
+    }
+
+    fun conflictingRenameTableAnnotationsFound(annotations: String): String {
+        return "Conflicting @RenameTable annotations found: [$annotations]"
+    }
+    fun conflictingRenameColumnAnnotationsFound(annotations: String): String {
+        return "Conflicting @RenameColumn annotations found: [$annotations]"
     }
 
     val AUTO_MIGRATION_FOUND_BUT_EXPORT_SCHEMA_OFF = "Cannot create auto-migrations when export " +
         "schema is OFF."
 
-    fun tableWithNewTablePrefixFound(tableName: String): String {
-        return "The new version of the schema contains `$tableName` a table name" +
-            " with the prefix '_new_', which is causing a conflict during autoMigration."
+    fun tableWithConflictingPrefixFound(tableName: String): String {
+        return "The new version of the schema contains '$tableName' a table name" +
+            " with the prefix '_new_', which will cause conflicts for auto migrations. Please use" +
+            " a different name."
     }
+
+    val FTS_TABLE_NOT_CURRENTLY_SUPPORTED = "Schemas involving FTS tables are not currently " +
+        "supported."
 }
diff --git a/room/compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt b/room/compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt
index 2208483..7a2a4d8 100644
--- a/room/compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt
@@ -18,40 +18,81 @@
 
 import androidx.room.migration.bundle.DatabaseBundle
 import androidx.room.migration.bundle.EntityBundle
+import androidx.room.migration.bundle.FieldBundle
 import androidx.room.migration.bundle.ForeignKeyBundle
+import androidx.room.migration.bundle.FtsEntityBundle
 import androidx.room.migration.bundle.IndexBundle
+import androidx.room.processor.ProcessorErrors.FTS_TABLE_NOT_CURRENTLY_SUPPORTED
+import androidx.room.processor.ProcessorErrors.deletedOrRenamedTableFound
+import androidx.room.processor.ProcessorErrors.tableRenameError
+import androidx.room.processor.ProcessorErrors.conflictingRenameColumnAnnotationsFound
+import androidx.room.processor.ProcessorErrors.conflictingRenameTableAnnotationsFound
 import androidx.room.processor.ProcessorErrors.newNotNullColumnMustHaveDefaultValue
-import androidx.room.processor.ProcessorErrors.removedOrRenamedColumnFound
-import androidx.room.processor.ProcessorErrors.removedOrRenamedTableFound
-import androidx.room.processor.ProcessorErrors.tableWithNewTablePrefixFound
+import androidx.room.processor.ProcessorErrors.deletedOrRenamedColumnFound
+import androidx.room.processor.ProcessorErrors.tableWithConflictingPrefixFound
 import androidx.room.vo.AutoMigrationResult
 
 /**
  * This exception should be thrown to abandon processing an @AutoMigration.
+ *
+ * @param errorMessage Error message to be thrown with the exception
+ * @return RuntimeException with the provided error message
  */
 class DiffException(val errorMessage: String) : RuntimeException(errorMessage)
 
 /**
- * Contains the added, changed and removed columns detected.
+ * Contains the changes detected between the two schema versions provided.
  */
 data class SchemaDiffResult(
     val addedColumns: Map<String, AutoMigrationResult.AddedColumn>,
-    val removedOrRenamedColumns: List<AutoMigrationResult.RemovedOrRenamedColumn>,
-    val addedTables: List<AutoMigrationResult.AddedTable>,
+    val deletedColumns: List<AutoMigrationResult.DeletedColumn>,
+    val addedTables: Set<AutoMigrationResult.AddedTable>,
+    val renamedTables: Map<String, String>,
     val complexChangedTables: Map<String, AutoMigrationResult.ComplexChangedTable>,
-    val removedOrRenamedTables: List<AutoMigrationResult.RemovedOrRenamedTable>
+    val deletedTables: List<String>
 )
 
 /**
- * Receives the two bundles, diffs and returns a @SchemaDiffResult.
+ * Receives the two bundles, detects all changes between the two versions and returns a
+ * @SchemaDiffResult.
  *
- * Throws an @AutoMigrationException with a detailed error message when an AutoMigration cannot
+ * Throws an @DiffException with a detailed error message when an AutoMigration cannot
  * be generated.
+ *
+ * @param fromSchemaBundle Original database schema to migrate from
+ * @param toSchemaBundle New database schema to migrate to
+ * @param className Name of the user implemented AutoMigrationCallback interface, if available
+ * @param renameColumnEntries List of repeatable annotations specifying column renames
+ * @param deleteColumnEntries List of repeatable annotations specifying column deletes
+ * @param renameTableEntries List of repeatable annotations specifying table renames
+ * @param deleteTableEntries List of repeatable annotations specifying table deletes
  */
+// TODO: (b/181777611) Handle FTS tables
 class SchemaDiffer(
-    val fromSchemaBundle: DatabaseBundle,
-    val toSchemaBundle: DatabaseBundle
+    private val fromSchemaBundle: DatabaseBundle,
+    private val toSchemaBundle: DatabaseBundle,
+    private val className: String?,
+    private val renameColumnEntries: List<AutoMigrationResult.RenamedColumn>,
+    private val deleteColumnEntries: List<AutoMigrationResult.DeletedColumn>,
+    private val renameTableEntries: List<AutoMigrationResult.RenamedTable>,
+    private val deleteTableEntries: List<AutoMigrationResult.DeletedTable>
 ) {
+    private val potentiallyDeletedTables = mutableSetOf<String>()
+
+    private val addedTables = mutableSetOf<AutoMigrationResult.AddedTable>()
+    // Any table that has been renamed, but also does not contain any complex changes.
+    private val renamedTables = mutableMapOf<String, String>()
+
+    // Map of tables with complex changes, keyed by the table name, note that if the table is
+    // renamed, the original table name is used as key.
+    private val complexChangedTables =
+        mutableMapOf<String, AutoMigrationResult.ComplexChangedTable>()
+    private val deletedTables = deleteTableEntries.map { it.deletedTableName }.toSet()
+
+    // Map of columns that have been added in the database, keyed by the column name, note that
+    // the table these columns have been added to will not contain any complex schema changes.
+    private val addedColumns = mutableMapOf<String, AutoMigrationResult.AddedColumn>()
+    private val deletedColumns = deleteColumnEntries
 
     /**
      * Compares the two versions of the database based on the schemas provided, and detects
@@ -60,163 +101,258 @@
      * @return the AutoMigrationResult containing the schema changes detected
      */
     fun diffSchemas(): SchemaDiffResult {
-        val addedTables = mutableListOf<AutoMigrationResult.AddedTable>()
-        val complexChangedTables = mutableMapOf<String, AutoMigrationResult.ComplexChangedTable>()
-        val removedOrRenamedTables = mutableListOf<AutoMigrationResult.RemovedOrRenamedTable>()
-
-        val addedColumns = mutableMapOf<String, AutoMigrationResult.AddedColumn>()
-        val removedOrRenamedColumns = mutableListOf<AutoMigrationResult.RemovedOrRenamedColumn>()
+        val processedTablesAndColumnsInNewVersion = mutableMapOf<String, List<String>>()
 
         // Check going from the original version of the schema to the new version for changed and
-        // removed columns/tables
-        fromSchemaBundle.entitiesByTableName.forEach { fromTable ->
-            val toTable = toSchemaBundle.entitiesByTableName[fromTable.key]
-            if (toTable == null) {
-                // TODO: (b/183007590) When handling renames, check if a complex changed table
-                //  exists for the renamed table. If so, edit the entry to
-                //  reflect the rename. If not, create a new
-                //  RenamedTable object to be handled by addSimpleChangeStatements().
-                removedOrRenamedTables.add(
-                    AutoMigrationResult.RemovedOrRenamedTable(fromTable.value)
-                )
-            } else {
-                val complexChangedTable = tableContainsComplexChanges(fromTable.value, toTable)
-                if (complexChangedTable != null) {
-                    complexChangedTables[complexChangedTable.tableName] = complexChangedTable
-                }
-                val fromColumns = fromTable.value.fieldsByColumnName
-                val toColumns = toTable.fieldsByColumnName
-                fromColumns.entries.forEach { fromColumn ->
-                    val match = toColumns[fromColumn.key]
-                    if (match != null && !match.isSchemaEqual(fromColumn.value) &&
-                        !complexChangedTables.containsKey(fromTable.key)
-                    ) {
-                        if (toSchemaBundle.entitiesByTableName.containsKey(toTable.newTableName)) {
-                            // TODO: (b/183975119) Use another prefix automatically in these cases
-                            diffError(tableWithNewTablePrefixFound(toTable.newTableName))
-                        }
-                        complexChangedTables[fromTable.key] =
-                            AutoMigrationResult.ComplexChangedTable(
-                                tableName = fromTable.key,
-                                newTableName = toTable.newTableName,
-                                oldVersionEntityBundle = fromTable.value,
-                                newVersionEntityBundle = toTable,
-                                foreignKeyChanged = false,
-                                indexChanged = false
-                            )
-                    } else if (match == null) {
-                        // TODO: (b/183007590) When handling renames, check if a complex changed
-                        //  table exists for the table of the renamed column. If so, edit the
-                        //  entry to reflect the column rename. If not, create a new
-                        //  RenamedColumn object to be handled by addSimpleChangeStatements().
-                        removedOrRenamedColumns.add(
-                            AutoMigrationResult.RemovedOrRenamedColumn(
-                                fromTable.key,
-                                fromColumn.value
-                            )
-                        )
-                    }
-                }
+        // deleted columns/tables
+        fromSchemaBundle.entitiesByTableName.values.forEach { fromTable ->
+            val toTable = detectTableLevelChanges(fromTable)
+            if (fromTable is FtsEntityBundle) {
+                diffError(FTS_TABLE_NOT_CURRENTLY_SUPPORTED)
             }
-        }
-        // Check going from the new version of the schema to the original version for added
-        // tables/columns. Skip the columns with the same name as the previous loop would have
-        // processed them already.
-        toSchemaBundle.entitiesByTableName.forEach { toTable ->
-            val fromTable = fromSchemaBundle.entitiesByTableName[toTable.key]
-            if (fromTable == null) {
-                addedTables.add(AutoMigrationResult.AddedTable(toTable.value))
-            } else {
+
+            // Check for column related changes. Since we require toTable to not be null, any
+            // deleted tables will be skipped here.
+            if (toTable != null) {
                 val fromColumns = fromTable.fieldsByColumnName
-                val toColumns = toTable.value.fieldsByColumnName
-                toColumns.entries.forEach { toColumn ->
-                    val match = fromColumns[toColumn.key]
-                    if (match == null) {
-                        if (toColumn.value.isNonNull && toColumn.value.defaultValue == null) {
-                            diffError(
-                                newNotNullColumnMustHaveDefaultValue(toColumn.key)
-                            )
-                        }
-                        // Check if the new column is on a table with complex changes. If so, no
-                        // need to account for it as the table will be recreated with the new
-                        // table already.
-                        if (!complexChangedTables.containsKey(toTable.key)) {
-                            addedColumns[toColumn.value.columnName] =
-                                AutoMigrationResult.AddedColumn(
-                                    toTable.key,
-                                    toColumn.value
-                                )
-                        }
-                    }
+                val processedColumnsInNewVersion = fromColumns.values.mapNotNull { fromColumn ->
+                    detectColumnLevelChanges(
+                        fromTable,
+                        toTable,
+                        fromColumn
+                    )
                 }
+                processedTablesAndColumnsInNewVersion[toTable.tableName] =
+                    processedColumnsInNewVersion
             }
         }
 
-        if (removedOrRenamedColumns.isNotEmpty()) {
-            removedOrRenamedColumns.forEach { removedColumn ->
-                diffError(
-                    removedOrRenamedColumnFound(
-                        removedColumn.fieldBundle.columnName
-                    )
+        // Check going from the new version of the schema to the original version for added
+        // tables/columns. Skip the columns that have been processed already.
+        toSchemaBundle.entitiesByTableName.forEach { toTable ->
+            processAddedTableAndColumns(toTable.value, processedTablesAndColumnsInNewVersion)
+        }
+
+        potentiallyDeletedTables.forEach { tableName ->
+            diffError(
+                deletedOrRenamedTableFound(
+                    className = className,
+                    tableName = tableName
                 )
-            }
+            )
         }
 
-        if (removedOrRenamedTables.isNotEmpty()) {
-            removedOrRenamedTables.forEach { removedTable ->
-                diffError(
-                    removedOrRenamedTableFound(
-                        removedTable.entityBundle.tableName
-                    )
-                )
-            }
-        }
-
+        processDeletedColumns()
         return SchemaDiffResult(
             addedColumns = addedColumns,
-            removedOrRenamedColumns = removedOrRenamedColumns,
+            deletedColumns = deletedColumns,
             addedTables = addedTables,
+            renamedTables = renamedTables,
             complexChangedTables = complexChangedTables,
-            removedOrRenamedTables = removedOrRenamedTables
+            deletedTables = deletedTables.toList()
         )
     }
 
     /**
-     * Check for complex schema changes at a Table level and returns a ComplexTableChange
-     * including information on which table changes were found on, and whether foreign key or
-     * index related changes have occurred.
+     * Detects any changes at the table-level, independent of any changes that may be present at
+     * the column-level (e.g. column add/rename/delete).
      *
-     * @return null if complex schema change has not been found
+     * @param fromTable The original version of the table
+     * @return The EntityBundle of the table in the new version of the database. If the
+     * table was renamed, this will be reflected in the return value. If the table was removed, a
+     * null object will be returned.
      */
-    // TODO: (b/181777611) Handle FTS tables
-    private fun tableContainsComplexChanges(
-        fromTable: EntityBundle,
-        toTable: EntityBundle
-    ): AutoMigrationResult.ComplexChangedTable? {
-        val foreignKeyChanged = !isForeignKeyBundlesListEqual(
-            fromTable.foreignKeys,
-            toTable.foreignKeys
-        )
-        val indexChanged = !isIndexBundlesListEqual(fromTable.indices, toTable.indices)
-        val primaryKeyChanged = !fromTable.primaryKey.isSchemaEqual(toTable.primaryKey)
-
-        if (primaryKeyChanged || foreignKeyChanged || indexChanged) {
-            if (toSchemaBundle.entitiesByTableName.containsKey(toTable.newTableName)) {
-                diffError(tableWithNewTablePrefixFound(toTable.newTableName))
+    private fun detectTableLevelChanges(
+        fromTable: EntityBundle
+    ): EntityBundle? {
+        // Check if the table was renamed. If so, check for other complex changes that could
+        // be found on the table level. Save the end result to the complex changed tables map.
+        val renamedTable = isTableRenamed(fromTable.tableName)
+        if (renamedTable != null) {
+            val toTable = toSchemaBundle.entitiesByTableName[renamedTable.newTableName]
+            if (toTable != null) {
+                val isComplexChangedTable = tableContainsComplexChanges(
+                    fromTable,
+                    toTable
+                )
+                if (isComplexChangedTable) {
+                    if (toSchemaBundle.entitiesByTableName.containsKey(toTable.newTableName)) {
+                        diffError(tableWithConflictingPrefixFound(toTable.newTableName))
+                    }
+                    renamedTables.remove(renamedTable.originalTableName)
+                    complexChangedTables[renamedTable.originalTableName] =
+                        AutoMigrationResult.ComplexChangedTable(
+                            tableName = toTable.tableName,
+                            tableNameWithNewPrefix = toTable.newTableName,
+                            oldVersionEntityBundle = fromTable,
+                            newVersionEntityBundle = toTable,
+                            renamedColumnsMap = mutableMapOf()
+                        )
+                } else {
+                    renamedTables[fromTable.tableName] = toTable.tableName
+                }
+            } else {
+                // The table we renamed TO does not exist in the new version
+                diffError(
+                    tableRenameError(
+                        className!!,
+                        renamedTable.originalTableName,
+                        renamedTable.newTableName
+                    )
+                )
             }
-            return AutoMigrationResult.ComplexChangedTable(
-                tableName = toTable.tableName,
-                newTableName = toTable.newTableName,
-                oldVersionEntityBundle = fromTable,
-                newVersionEntityBundle = toTable,
-                foreignKeyChanged = foreignKeyChanged,
-                indexChanged = indexChanged
+            return toTable
+        }
+        val toTable = toSchemaBundle.entitiesByTableName[fromTable.tableName]
+        val isDeletedTable = deletedTables.contains(fromTable.tableName)
+        if (toTable != null) {
+            if (isDeletedTable) {
+                diffError(
+                    deletedOrRenamedTableFound(className, toTable.tableName)
+                )
+            }
+
+            // Check if this table exists in both versions of the schema, hence is not renamed or
+            // deleted, but contains other complex changes (index/primary key/foreign key change).
+            val isComplexChangedTable = tableContainsComplexChanges(
+                fromTable = fromTable,
+                toTable = toTable
+            )
+            if (isComplexChangedTable) {
+                complexChangedTables[fromTable.tableName] =
+                    AutoMigrationResult.ComplexChangedTable(
+                        tableName = toTable.tableName,
+                        tableNameWithNewPrefix = toTable.newTableName,
+                        oldVersionEntityBundle = fromTable,
+                        newVersionEntityBundle = toTable,
+                        renamedColumnsMap = mutableMapOf()
+                    )
+            }
+            return toTable
+        }
+        if (!isDeletedTable) {
+            potentiallyDeletedTables.add(fromTable.tableName)
+        }
+        return null
+    }
+
+    /**
+     * Detects any changes at the column-level.
+     *
+     * @param fromTable The original version of the table
+     * @param toTable The new version of the table
+     * @param fromColumn The original version of the column
+     * @return The name of the column in the new version of the database. Will return a null
+     * value if the column was deleted.
+     */
+    private fun detectColumnLevelChanges(
+        fromTable: EntityBundle,
+        toTable: EntityBundle,
+        fromColumn: FieldBundle,
+    ): String? {
+        // Check if this column was renamed. If so, no need to check further, we can mark this
+        // table as a complex change and include the renamed column.
+        val renamedToColumn = isColumnRenamed(fromColumn.columnName, fromTable.tableName)
+        if (renamedToColumn != null) {
+            val renamedColumnsMap = mutableMapOf(
+                renamedToColumn.newColumnName to fromColumn.columnName
+            )
+            // Make sure there are no conflicts in the new version of the table with the
+            // temporary new table name
+            // TODO: (b/183975119) Use another prefix automatically in these cases
+            if (toSchemaBundle.entitiesByTableName.containsKey(toTable.newTableName)) {
+                diffError(tableWithConflictingPrefixFound(toTable.newTableName))
+            }
+            renamedTables.remove(fromTable.tableName)
+            complexChangedTables[fromTable.tableName] =
+                AutoMigrationResult.ComplexChangedTable(
+                    tableName = fromTable.tableName,
+                    tableNameWithNewPrefix = toTable.newTableName,
+                    oldVersionEntityBundle = fromTable,
+                    newVersionEntityBundle = toTable,
+                    renamedColumnsMap = renamedColumnsMap
+                )
+            return renamedToColumn.newColumnName
+        }
+        // The column was not renamed. So we check if the column was deleted, and
+        // if not, we check for column level complex changes.
+        val match = toTable.fieldsByColumnName[fromColumn.columnName]
+        if (match != null) {
+            val columnChanged = !match.isSchemaEqual(fromColumn)
+            if (columnChanged && !complexChangedTables.containsKey(fromTable.tableName)) {
+                // Make sure there are no conflicts in the new version of the table with the
+                // temporary new table name
+                // TODO: (b/183975119) Use another prefix automatically in these cases
+                if (toSchemaBundle.entitiesByTableName.containsKey(toTable.newTableName)) {
+                    diffError(tableWithConflictingPrefixFound(toTable.newTableName))
+                }
+                renamedTables.remove(fromTable.tableName)
+                complexChangedTables[fromTable.tableName] =
+                    AutoMigrationResult.ComplexChangedTable(
+                        tableName = fromTable.tableName,
+                        tableNameWithNewPrefix = toTable.newTableName,
+                        oldVersionEntityBundle = fromTable,
+                        newVersionEntityBundle = toTable,
+                        renamedColumnsMap = mutableMapOf()
+                    )
+            }
+            return match.columnName
+        }
+
+        val isColumnDeleted = deletedColumns.any {
+            it.tableName == fromTable.tableName && it.columnName == fromColumn.columnName
+        }
+
+        if (!isColumnDeleted) {
+            // We have encountered an ambiguous scenario, need more input from the user.
+            diffError(
+                deletedOrRenamedColumnFound(
+                    className = className,
+                    tableName = fromTable.tableName,
+                    columnName = fromColumn.columnName
+                )
             )
         }
         return null
     }
 
-    private fun diffError(errorMsg: String) {
+    /**
+     * Checks for complex schema changes at a Table level and returns a ComplexTableChange
+     * including information on which table changes were found on, and whether foreign key or
+     * index related changes have occurred.
+     *
+     * @param fromTable The original version of the table
+     * @param toTable The new version of the table
+     * @return A ComplexChangedTable object, null if complex schema change has not been found
+     */
+    private fun tableContainsComplexChanges(
+        fromTable: EntityBundle,
+        toTable: EntityBundle
+    ): Boolean {
+        if (!isForeignKeyBundlesListEqual(fromTable.foreignKeys, toTable.foreignKeys)) {
+            return true
+        }
+        if (!isIndexBundlesListEqual(fromTable.indices, toTable.indices)) {
+            return true
+        }
+
+        if (!fromTable.primaryKey.isSchemaEqual(toTable.primaryKey)) {
+            return true
+        }
+        // Check if any foreign keys are referencing a renamed table.
+        return fromTable.foreignKeys.any { foreignKey ->
+            renameTableEntries.any {
+                it.originalTableName == foreignKey.table
+            }
+        }
+    }
+
+    /**
+     * Throws a DiffException with the provided error message.
+     *
+     * @param errorMsg Error message to be thrown with the exception
+     */
+    private fun diffError(errorMsg: String): Nothing {
         throw DiffException(errorMsg)
     }
 
@@ -224,6 +360,8 @@
      * Takes in two ForeignKeyBundle lists, attempts to find potential matches based on the columns
      * of the Foreign Keys. Processes these potential matches by checking for schema equality.
      *
+     * @param fromBundle List of foreign keys in the old schema version
+     * @param toBundle List of foreign keys in the new schema version
      * @return true if the two lists of foreign keys are equal
      */
     private fun isForeignKeyBundlesListEqual(
@@ -252,6 +390,8 @@
      * Takes in two IndexBundle lists, attempts to find potential matches based on the names
      * of the indexes. Processes these potential matches by checking for schema equality.
      *
+     * @param fromBundle List of indexes in the old schema version
+     * @param toBundle List of indexes in the new schema version
      * @return true if the two lists of indexes are equal
      */
     private fun isIndexBundlesListEqual(
@@ -272,4 +412,129 @@
         }
         return true
     }
-}
\ No newline at end of file
+
+    /**
+     * Checks if the table provided has been renamed in the new version of the database.
+     *
+     * @param tableName Name of the table in the original database version
+     * @return A RenameTable object if the table has been renamed, otherwise null
+     */
+    private fun isTableRenamed(tableName: String): AutoMigrationResult.RenamedTable? {
+        val annotations = renameTableEntries
+        val renamedTableAnnotations = annotations.filter {
+            it.originalTableName == tableName
+        }
+
+        // Make sure there aren't multiple renames on the same table
+        if (renamedTableAnnotations.size > 1) {
+            diffError(
+                conflictingRenameTableAnnotationsFound(
+                    renamedTableAnnotations.joinToString(",")
+                )
+            )
+        }
+        return renamedTableAnnotations.firstOrNull()
+    }
+
+    /**
+     * Checks if the column provided has been renamed in the new version of the database.
+     *
+     * @param columnName Name of the column in the original database version
+     * @param tableName Name of the table the column belongs to in the original database version
+     * @return A RenameColumn object if the column has been renamed, otherwise null
+     */
+    private fun isColumnRenamed(
+        columnName: String,
+        tableName: String
+    ): AutoMigrationResult.RenamedColumn? {
+        val annotations = renameColumnEntries
+        val renamedColumnAnnotations = annotations.filter {
+            it.originalColumnName == columnName && it.tableName == tableName
+        }
+
+        // Make sure there aren't multiple renames on the same column
+        if (renamedColumnAnnotations.size > 1) {
+            diffError(
+                conflictingRenameColumnAnnotationsFound(renamedColumnAnnotations.joinToString(","))
+            )
+        }
+        return renamedColumnAnnotations.firstOrNull()
+    }
+
+    /**
+     * Looks for any new tables and columns that have been added between versions.
+     *
+     * @param toTable The new version of the table
+     * @param processedTablesAndColumnsInNewVersion List of all columns in the new version of the
+     * database that have been already processed
+     */
+    private fun processAddedTableAndColumns(
+        toTable: EntityBundle,
+        processedTablesAndColumnsInNewVersion: MutableMap<String, List<String>>
+    ) {
+        // Old table bundle will be found even if table is renamed.
+        val isRenamed = renameTableEntries.firstOrNull {
+            it.newTableName == toTable.tableName
+        }
+        val fromTable = if (isRenamed != null) {
+            fromSchemaBundle.entitiesByTableName[isRenamed.originalTableName]
+        } else {
+            fromSchemaBundle.entitiesByTableName[toTable.tableName]
+        }
+
+        if (fromTable == null) {
+            // It's a new table
+            addedTables.add(AutoMigrationResult.AddedTable(toTable))
+            return
+        }
+        val fromColumns = fromTable.fieldsByColumnName
+        val toColumns =
+            processedTablesAndColumnsInNewVersion[toTable.tableName]?.let { processedColumns ->
+                toTable.fieldsByColumnName.filterKeys { !processedColumns.contains(it) }
+            } ?: toTable.fieldsByColumnName
+
+        toColumns.values.forEach { toColumn ->
+            val match = fromColumns[toColumn.columnName]
+            if (match == null) {
+                if (toColumn.isNonNull && toColumn.defaultValue == null) {
+                    diffError(
+                        newNotNullColumnMustHaveDefaultValue(toColumn.columnName)
+                    )
+                }
+                // Check if the new column is on a table with complex changes. If so, no
+                // need to account for it as the table will be recreated already with the new
+                // table.
+                if (!complexChangedTables.containsKey(toTable.tableName)) {
+                    addedColumns[toColumn.columnName] =
+                        AutoMigrationResult.AddedColumn(
+                            toTable.tableName,
+                            toColumn
+                        )
+                }
+            }
+        }
+    }
+
+    /**
+     * Goes through the deleted columns list and marks the table of each as a complex changed
+     * table if it was not already.
+     */
+    private fun processDeletedColumns() {
+        deletedColumns.filterNot {
+            complexChangedTables.contains(it.tableName)
+        }.forEach { deletedColumn ->
+            val fromTableBundle =
+                fromSchemaBundle.entitiesByTableName.getValue(deletedColumn.tableName)
+            val toTableBundle =
+                toSchemaBundle.entitiesByTableName.getValue(deletedColumn.tableName)
+            complexChangedTables[deletedColumn.tableName] =
+                AutoMigrationResult.ComplexChangedTable(
+                    tableName = deletedColumn.tableName,
+                    tableNameWithNewPrefix = fromTableBundle.newTableName,
+                    oldVersionEntityBundle = fromTableBundle,
+                    newVersionEntityBundle = toTableBundle,
+                    renamedColumnsMap = mutableMapOf()
+                )
+        }
+    }
+}
diff --git a/room/compiler/src/main/kotlin/androidx/room/vo/AutoMigrationResult.kt b/room/compiler/src/main/kotlin/androidx/room/vo/AutoMigrationResult.kt
index ba352db..6f5c0a8 100644
--- a/room/compiler/src/main/kotlin/androidx/room/vo/AutoMigrationResult.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/vo/AutoMigrationResult.kt
@@ -31,11 +31,10 @@
     val to: Int?,
     val schemaDiff: SchemaDiffResult
 ) {
-
     val implTypeName: ClassName by lazy {
         ClassName.get(
             element.className.packageName(),
-            "${element.className.simpleNames().joinToString("_")}_Impl"
+            "AutoMigration_${from}_${to}_Impl"
         )
     }
 
@@ -46,14 +45,19 @@
     data class AddedColumn(val tableName: String, val fieldBundle: FieldBundle)
 
     /**
-     * Stores the table name and the relevant field bundle of a column that was present in the
-     * old version of a database but is not present in a new version of the same database, either
-     * because it was removed or renamed.
-     *
-     * In the current implementation, we cannot differ between whether the column was removed or
-     * renamed.
+     * Stores the table name, original name, and the new name of a column that was renamed in the
+     * new version of the database.
      */
-    data class RemovedOrRenamedColumn(val tableName: String, val fieldBundle: FieldBundle)
+    data class RenamedColumn(
+        val tableName: String,
+        val originalColumnName: String,
+        val newColumnName: String
+    )
+
+    /**
+     * Stores the table name and the column name of a column that was deleted from the database.
+     */
+    data class DeletedColumn(val tableName: String, val columnName: String)
 
     /**
      * Stores the table that was added to a database in a newer version.
@@ -61,33 +65,36 @@
     data class AddedTable(val entityBundle: EntityBundle)
 
     /**
-     * Stores the table name that contains a change in the primary key, foreign key(s) or index(es)
-     * in a newer version. Explicitly provides information on whether a foreign key change and/or
-     * an index change has occurred.
+     * Stores the table that contains a change in the primary key, foreign key(s) or index(es)
+     * in a newer version, as well as any complex changes and renames on the column-level.
      *
      * As it is possible to have a table with only simple (non-complex) changes, which will be
-     * categorized as "AddedColumn" or "RemovedColumn" changes, all other
+     * categorized as "AddedColumn" or "DeletedColumn" changes, all other
      * changes at the table level are categorized as "complex" changes, using the category
      * "ComplexChangedTable".
      *
-     * At the column level, any change that is not a column add or a
-     * removal will be categorized as "ChangedColumn".
+     * The renamed columns map contains a mapping from the NEW name of the column to the OLD name
+     * of the column.
      */
     data class ComplexChangedTable(
         val tableName: String,
-        val newTableName: String,
+        val tableNameWithNewPrefix: String,
         val oldVersionEntityBundle: EntityBundle,
         val newVersionEntityBundle: EntityBundle,
-        val foreignKeyChanged: Boolean,
-        val indexChanged: Boolean
+        val renamedColumnsMap: MutableMap<String, String>
     )
 
     /**
-     * Stores the table that was present in the old version of a database but is not present in a
-     * new version of the same database, either because it was removed or renamed.
+     * Stores the original name and the new name of a table that was renamed in the
+     * new version of the database.
      *
-     * In the current implementation, we cannot differ between whether the table was removed or
-     * renamed.
+     * This container will only be used for tables that got renamed, but do not have any complex
+     * changes on it, both on the table and column level.
      */
-    data class RemovedOrRenamedTable(val entityBundle: EntityBundle)
+    data class RenamedTable(val originalTableName: String, val newTableName: String)
+
+    /**
+     * Stores the name of the table that was deleted from the database.
+     */
+    data class DeletedTable(val deletedTableName: String)
 }
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
index 9748802..254e282 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
@@ -23,6 +23,7 @@
 import androidx.room.ext.RoomTypeNames
 import androidx.room.ext.S
 import androidx.room.ext.SupportDbTypeNames
+import androidx.room.migration.bundle.EntityBundle
 import androidx.room.vo.AutoMigrationResult
 import com.squareup.javapoet.MethodSpec
 import com.squareup.javapoet.ParameterSpec
@@ -38,11 +39,11 @@
     private val dbElement: XElement,
     val autoMigrationResult: AutoMigrationResult
 ) : ClassWriter(autoMigrationResult.implTypeName) {
-    val addedColumns = autoMigrationResult.schemaDiff.addedColumns
-    val removedOrRenamedColumns = autoMigrationResult.schemaDiff.removedOrRenamedColumns
-    val addedTables = autoMigrationResult.schemaDiff.addedTables
-    val complexChangedTables = autoMigrationResult.schemaDiff.complexChangedTables
-    val removedOrRenamedTables = autoMigrationResult.schemaDiff.removedOrRenamedTables
+    private val addedColumns = autoMigrationResult.schemaDiff.addedColumns
+    private val addedTables = autoMigrationResult.schemaDiff.addedTables
+    private val renamedTables = autoMigrationResult.schemaDiff.renamedTables
+    private val complexChangedTables = autoMigrationResult.schemaDiff.complexChangedTables
+    private val deletedTables = autoMigrationResult.schemaDiff.deletedTables
 
     override fun createTypeSpecBuilder(): TypeSpec.Builder {
         val builder = TypeSpec.classBuilder(autoMigrationResult.implTypeName)
@@ -94,9 +95,7 @@
      * @param migrateBuilder Builder for the migrate() function to be generated
      */
     private fun addAutoMigrationResultToMigrate(migrateBuilder: MethodSpec.Builder) {
-        if (complexChangedTables.isNotEmpty()) {
-            addComplexChangeStatements(migrateBuilder)
-        }
+        addComplexChangeStatements(migrateBuilder)
         addSimpleChangeStatements(migrateBuilder)
     }
 
@@ -107,15 +106,34 @@
      * @param migrateBuilder Builder for the migrate() function to be generated
      */
     private fun addComplexChangeStatements(migrateBuilder: MethodSpec.Builder) {
-        val tablesToProcess = complexChangedTables
-        tablesToProcess.forEach { table ->
-            // TODO: (b/183007590) Check for column / table renames here before processing
-            //  complex changes
-            addStatementsToCreateNewTable(table.value, migrateBuilder)
-            addStatementsToContentTransfer(table.value, migrateBuilder)
-            addStatementsToDropTableAndRenameTempTable(table.value, migrateBuilder)
-            addStatementsToRecreateIndexes(table.value, migrateBuilder)
-            addStatementsToCheckForeignKeyConstraint(table.value, migrateBuilder)
+        complexChangedTables.values.forEach {
+            (
+                _,
+                tableNameWithNewPrefix,
+                oldEntityBundle,
+                newEntityBundle,
+                renamedColumnsMap
+            ) ->
+
+            addStatementsToCreateNewTable(newEntityBundle, migrateBuilder)
+            addStatementsToContentTransfer(
+                oldEntityBundle.tableName,
+                tableNameWithNewPrefix,
+                oldEntityBundle,
+                newEntityBundle,
+                renamedColumnsMap,
+                migrateBuilder
+            )
+            addStatementsToDropTableAndRenameTempTable(
+                oldEntityBundle.tableName,
+                newEntityBundle.tableName,
+                tableNameWithNewPrefix,
+                migrateBuilder
+            )
+            addStatementsToRecreateIndexes(newEntityBundle, migrateBuilder)
+            if (newEntityBundle.foreignKeys.isNotEmpty()) {
+                addStatementsToCheckForeignKeyConstraint(newEntityBundle.tableName, migrateBuilder)
+            }
         }
     }
 
@@ -126,55 +144,62 @@
      *
      * @param migrateBuilder Builder for the migrate() function to be generated
      */
-    // TODO: (b/183007590) Handle column/table renames here
     private fun addSimpleChangeStatements(migrateBuilder: MethodSpec.Builder) {
-
-        if (addedColumns.isNotEmpty()) {
-            addNewColumnStatements(migrateBuilder)
-        }
-
-        if (addedTables.isNotEmpty()) {
-            addNewTableStatements(migrateBuilder)
-        }
+        addDeleteTableStatements(migrateBuilder)
+        addRenameTableStatements(migrateBuilder)
+        addNewColumnStatements(migrateBuilder)
+        addNewTableStatements(migrateBuilder)
     }
 
     /**
      * Adds the SQL statements for creating a new table in the desired revised format of table.
      *
+     * @param newTable Schema of the new table to be created
      * @param migrateBuilder Builder for the migrate() function to be generated
      */
     private fun addStatementsToCreateNewTable(
-        table: AutoMigrationResult.ComplexChangedTable,
+        newTable: EntityBundle,
         migrateBuilder: MethodSpec.Builder
     ) {
         addDatabaseExecuteSqlStatement(
             migrateBuilder,
-            table.newVersionEntityBundle.createNewTable()
+            newTable.createNewTable()
         )
     }
 
     /**
      * Adds the SQL statements for transferring the contents of the old table to the new version.
      *
+     * @param oldTableName Name of the table in the old version of the database
+     * @param tableNameWithNewPrefix Name of the table with the '_new_' prefix added
+     * @param oldEntityBundle Entity bundle of the table in the old version of the database
+     * @param newEntityBundle Entity bundle of the table in the new version of the database
+     * @param renamedColumnsMap Map of the renamed columns of the table (new name -> old name)
      * @param migrateBuilder Builder for the migrate() function to be generated
      */
     private fun addStatementsToContentTransfer(
-        table: AutoMigrationResult.ComplexChangedTable,
+        oldTableName: String,
+        tableNameWithNewPrefix: String,
+        oldEntityBundle: EntityBundle,
+        newEntityBundle: EntityBundle,
+        renamedColumnsMap: MutableMap<String, String>,
         migrateBuilder: MethodSpec.Builder
     ) {
-        // TODO: (b/183007590) Account for renames and deletes here as ordering is important.
-        val oldColumnSequence = table.oldVersionEntityBundle.fieldsByColumnName.keys
-            .joinToString(",") { "`$it`" }
-        val newColumnSequence = (
-            table.newVersionEntityBundle.fieldsByColumnName.keys - addedColumns.keys
-            ).joinToString(",") { "`$it`" }
+        val newColumnSequence = newEntityBundle.fieldsByColumnName.keys.filter {
+            oldEntityBundle.fieldsByColumnName.keys.contains(it) ||
+                renamedColumnsMap.containsKey(it)
+        }
+        val oldColumnSequence = mutableListOf<String>()
+        newColumnSequence.forEach { column ->
+            oldColumnSequence.add(renamedColumnsMap[column] ?: column)
+        }
 
         addDatabaseExecuteSqlStatement(
             migrateBuilder,
             buildString {
                 append(
-                    "INSERT INTO `${table.newTableName}` ($newColumnSequence) " +
-                        "SELECT $oldColumnSequence FROM `${table.tableName}`"
+                    "INSERT INTO `$tableNameWithNewPrefix` (${newColumnSequence.joinToString(",")
+                    }) SELECT ${oldColumnSequence.joinToString(",")} FROM `$oldTableName`",
                 )
             }
         )
@@ -184,32 +209,38 @@
      * Adds the SQL statements for dropping the table at the old version and renaming the
      * temporary table to the name of the original table.
      *
+     * @param oldTableName Name of the table in the old version of the database
+     * @param newTableName Name of the table in the new version of the database
+     * @param tableNameWithNewPrefix Name of the table with the '_new_' prefix added
      * @param migrateBuilder Builder for the migrate() function to be generated
      */
     private fun addStatementsToDropTableAndRenameTempTable(
-        table: AutoMigrationResult.ComplexChangedTable,
+        oldTableName: String,
+        newTableName: String,
+        tableNameWithNewPrefix: String,
         migrateBuilder: MethodSpec.Builder
     ) {
         addDatabaseExecuteSqlStatement(
             migrateBuilder,
-            "DROP TABLE `${table.tableName}`"
+            "DROP TABLE `$oldTableName`"
         )
         addDatabaseExecuteSqlStatement(
             migrateBuilder,
-            "ALTER TABLE `${table.newTableName}` RENAME TO `${table.tableName}`"
+            "ALTER TABLE `$tableNameWithNewPrefix` RENAME TO `$newTableName`"
         )
     }
 
     /**
      * Adds the SQL statements for recreating indexes.
      *
+     * @param table The table the indexes of which will be recreated
      * @param migrateBuilder Builder for the migrate() function to be generated
      */
     private fun addStatementsToRecreateIndexes(
-        table: AutoMigrationResult.ComplexChangedTable,
+        table: EntityBundle,
         migrateBuilder: MethodSpec.Builder
     ) {
-        table.newVersionEntityBundle.indices.forEach { index ->
+        table.indices.forEach { index ->
             addDatabaseExecuteSqlStatement(
                 migrateBuilder,
                 index.getCreateSql(table.tableName)
@@ -220,19 +251,58 @@
     /**
      * Adds the SQL statement for checking the foreign key constraints.
      *
+     * @param tableName Name of the table
      * @param migrateBuilder Builder for the migrate() function to be generated
      */
     private fun addStatementsToCheckForeignKeyConstraint(
-        table: AutoMigrationResult.ComplexChangedTable,
+        tableName: String,
         migrateBuilder: MethodSpec.Builder
     ) {
         addDatabaseExecuteSqlStatement(
             migrateBuilder,
-            "PRAGMA foreign_key_check(`${table.tableName}`)"
+            "PRAGMA foreign_key_check(`$tableName`)"
         )
     }
 
     /**
+     * Adds the SQL statements for removing a table.
+     *
+     * @param migrateBuilder Builder for the migrate() function to be generated
+     */
+    private fun addDeleteTableStatements(migrateBuilder: MethodSpec.Builder) {
+        deletedTables.forEach { tableName ->
+            val deleteTableSql = buildString {
+                append(
+                    "DROP TABLE `$tableName`"
+                )
+            }
+            addDatabaseExecuteSqlStatement(
+                migrateBuilder,
+                deleteTableSql
+            )
+        }
+    }
+
+    /**
+     * Adds the SQL statements for renaming a table.
+     *
+     * @param migrateBuilder Builder for the migrate() function to be generated
+     */
+    private fun addRenameTableStatements(migrateBuilder: MethodSpec.Builder) {
+        renamedTables.forEach { (oldName, newName) ->
+            val renameTableSql = buildString {
+                append(
+                    "ALTER TABLE `$oldName` RENAME TO `$newName`"
+                )
+            }
+            addDatabaseExecuteSqlStatement(
+                migrateBuilder,
+                renameTableSql
+            )
+        }
+    }
+
+    /**
      * Adds the SQL statements for adding new columns to a table.
      *
      * @param migrateBuilder Builder for the migrate() function to be generated
@@ -276,13 +346,15 @@
      * database.
      *
      * @param migrateBuilder Builder for the migrate() function to be generated
+     * @param sql The SQL statement to be executed by the database
      */
     private fun addDatabaseExecuteSqlStatement(
         migrateBuilder: MethodSpec.Builder,
         sql: String
     ) {
         migrateBuilder.addStatement(
-            "database.execSQL($S)", sql
+            "database.execSQL($S)",
+            sql
         )
     }
 }
diff --git a/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithDefault.java b/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithDefault.java
index c75033d..e799cad 100644
--- a/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithDefault.java
+++ b/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithDefault.java
@@ -10,8 +10,8 @@
 
 @Generated("androidx.room.RoomProcessor")
 @SuppressWarnings({"unchecked", "deprecation"})
-class ValidAutoMigrationWithDefault_Impl extends Migration implements AutoMigrationCallback {
-    public ValidAutoMigrationWithDefault_Impl() {
+class AutoMigration_1_2_Impl extends Migration implements AutoMigrationCallback {
+    public AutoMigration_1_2_Impl() {
         super(1, 2);
     }
 
diff --git a/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithoutDefault.java b/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithoutDefault.java
index 93eb47d..ed2a2a9 100644
--- a/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithoutDefault.java
+++ b/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithoutDefault.java
@@ -10,8 +10,8 @@
 
 @Generated("androidx.room.RoomProcessor")
 @SuppressWarnings({"unchecked", "deprecation"})
-class ValidAutoMigrationWithoutDefault_Impl extends Migration implements AutoMigrationCallback {
-    public ValidAutoMigrationWithoutDefault_Impl() {
+class AutoMigration_1_2_Impl extends Migration implements AutoMigrationCallback {
+    public AutoMigration_1_2_Impl() {
         super(1, 2);
     }
 
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/AutoMigrationProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/AutoMigrationProcessorTest.kt
index be99a31..886bfbd 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/AutoMigrationProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/AutoMigrationProcessorTest.kt
@@ -23,6 +23,7 @@
 import androidx.room.migration.bundle.FieldBundle
 import androidx.room.migration.bundle.PrimaryKeyBundle
 import androidx.room.migration.bundle.SchemaBundle
+import androidx.room.processor.ProcessorErrors.autoMigrationElementMustExtendCallback
 import androidx.room.testing.context
 import org.junit.Test
 
@@ -34,19 +35,21 @@
             """
             package foo.bar;
             import androidx.room.AutoMigration;
-            @AutoMigration(from=1, to=2)
             class MyAutoMigration implements AutoMigration {}
             """.trimIndent()
         )
 
         runProcessorTest(listOf(source)) { invocation ->
             AutoMigrationProcessor(
-                invocation.context,
                 invocation.processingEnv.requireTypeElement("foo.bar.MyAutoMigration"),
+                invocation.context,
+                1,
+                2,
+                invocation.processingEnv.requireType("foo.bar.MyAutoMigration"),
                 from.database
             ).process()
             invocation.assertCompilationResult {
-                hasError(ProcessorErrors.AUTOMIGRATION_ANNOTATED_TYPE_ELEMENT_MUST_BE_INTERFACE)
+                hasError(ProcessorErrors.AUTOMIGRATION_CALLBACK_MUST_BE_INTERFACE)
             }
         }
     }
@@ -66,13 +69,16 @@
 
         runProcessorTest(listOf(source)) { invocation ->
             AutoMigrationProcessor(
-                invocation.context,
                 invocation.processingEnv.requireTypeElement("foo.bar.MyAutoMigration"),
+                invocation.context,
+                1,
+                2,
+                invocation.processingEnv.requireType("foo.bar.MyAutoMigration"),
                 from.database
             ).process()
             invocation.assertCompilationResult {
                 hasError(
-                    ProcessorErrors.AUTOMIGRATION_ELEMENT_MUST_IMPLEMENT_AUTOMIGRATION_CALLBACK
+                    autoMigrationElementMustExtendCallback("MyAutoMigration")
                 )
             }
         }
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt
index 700eb3c..baf2464 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/DatabaseProcessorTest.kt
@@ -1214,7 +1214,8 @@
         singleDb(
             """
                 @Database(entities = {User.class}, version = 42, exportSchema = false,
-                autoMigrations = {MyAutoMigration.class})
+                autoMigrations = {@AutoMigration(from = 1, to = 2, callback = MyAutoMigration
+                .class), @AutoMigration(from = 2, to = 3)})
                 public abstract class MyDb extends RoomDatabase {}
                 """,
             USER, AUTOMIGRATION
diff --git a/room/compiler/src/test/kotlin/androidx/room/util/SchemaDifferTest.kt b/room/compiler/src/test/kotlin/androidx/room/util/SchemaDifferTest.kt
index 402e271..c416c40 100644
--- a/room/compiler/src/test/kotlin/androidx/room/util/SchemaDifferTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/util/SchemaDifferTest.kt
@@ -34,7 +34,12 @@
     fun testPrimaryKeyChanged() {
         val diffResult = SchemaDiffer(
             fromSchemaBundle = from.database,
-            toSchemaBundle = toChangeInPrimaryKey.database
+            toSchemaBundle = toChangeInPrimaryKey.database,
+            className = "MyAutoMigration",
+            renameColumnEntries = listOf(),
+            deleteColumnEntries = listOf(),
+            renameTableEntries = listOf(),
+            deleteTableEntries = listOf()
         ).diffSchemas()
 
         assertThat(diffResult.complexChangedTables.keys).contains("Song")
@@ -44,31 +49,42 @@
     fun testForeignKeyFieldChanged() {
         val diffResult = SchemaDiffer(
             fromSchemaBundle = from.database,
-            toSchemaBundle = toForeignKeyAdded.database
+            toSchemaBundle = toForeignKeyAdded.database,
+            className = "MyAutoMigration",
+            renameColumnEntries = listOf(),
+            deleteColumnEntries = listOf(),
+            renameTableEntries = listOf(),
+            deleteTableEntries = listOf()
         ).diffSchemas()
 
-        assertThat(diffResult.complexChangedTables.isNotEmpty())
-        assertThat(diffResult.complexChangedTables["Song"]?.foreignKeyChanged).isTrue()
-        assertThat(diffResult.complexChangedTables["Song"]?.indexChanged).isFalse()
+        assertThat(diffResult.complexChangedTables["Song"] != null)
     }
 
     @Test
     fun testComplexChangeInvolvingIndex() {
         val diffResult = SchemaDiffer(
             fromSchemaBundle = from.database,
-            toSchemaBundle = toIndexAdded.database
+            toSchemaBundle = toIndexAdded.database,
+            className = "MyAutoMigration",
+            renameColumnEntries = listOf(),
+            deleteColumnEntries = listOf(),
+            renameTableEntries = listOf(),
+            deleteTableEntries = listOf()
         ).diffSchemas()
 
-        assertThat(diffResult.complexChangedTables.isNotEmpty())
-        assertThat(diffResult.complexChangedTables["Song"]?.foreignKeyChanged).isFalse()
-        assertThat(diffResult.complexChangedTables["Song"]?.indexChanged).isTrue()
+        assertThat(diffResult.complexChangedTables["Song"] != null)
     }
 
     @Test
     fun testColumnAddedWithColumnInfoDefaultValue() {
         val schemaDiffResult = SchemaDiffer(
             fromSchemaBundle = from.database,
-            toSchemaBundle = toColumnAddedWithColumnInfoDefaultValue.database
+            toSchemaBundle = toColumnAddedWithColumnInfoDefaultValue.database,
+            className = "MyAutoMigration",
+            renameColumnEntries = listOf(),
+            deleteColumnEntries = listOf(),
+            renameTableEntries = listOf(),
+            deleteTableEntries = listOf()
         ).diffSchemas()
         assertThat(schemaDiffResult.addedColumns["artistId"]?.fieldBundle?.columnName)
             .isEqualTo("artistId")
@@ -79,7 +95,12 @@
         try {
             SchemaDiffer(
                 fromSchemaBundle = from.database,
-                toSchemaBundle = toColumnAddedWithNoDefaultValue.database
+                toSchemaBundle = toColumnAddedWithNoDefaultValue.database,
+                className = "MyAutoMigration",
+                renameColumnEntries = listOf(),
+                deleteColumnEntries = listOf(),
+                renameTableEntries = listOf(),
+                deleteTableEntries = listOf()
             ).diffSchemas()
             fail("DiffException should have been thrown.")
         } catch (ex: DiffException) {
@@ -93,10 +114,15 @@
     fun testTableAddedWithColumnInfoDefaultValue() {
         val schemaDiffResult = SchemaDiffer(
             fromSchemaBundle = from.database,
-            toSchemaBundle = toTableAddedWithColumnInfoDefaultValue.database
+            toSchemaBundle = toTableAddedWithColumnInfoDefaultValue.database,
+            className = "MyAutoMigration",
+            renameColumnEntries = listOf(),
+            deleteColumnEntries = listOf(),
+            renameTableEntries = listOf(),
+            deleteTableEntries = listOf()
         ).diffSchemas()
-        assertThat(schemaDiffResult.addedTables[0].entityBundle.tableName).isEqualTo("Artist")
-        assertThat(schemaDiffResult.addedTables[1].entityBundle.tableName).isEqualTo("Album")
+        assertThat(schemaDiffResult.addedTables.toList()[0].entityBundle.tableName)
+            .isEqualTo("Album")
     }
 
     @Test
@@ -104,12 +130,17 @@
         try {
             SchemaDiffer(
                 fromSchemaBundle = from.database,
-                toSchemaBundle = toColumnRenamed.database
+                toSchemaBundle = toColumnRenamed.database,
+                className = "MyAutoMigration",
+                renameColumnEntries = listOf(),
+                deleteColumnEntries = listOf(),
+                renameTableEntries = listOf(),
+                deleteTableEntries = listOf()
             ).diffSchemas()
             fail("DiffException should have been thrown.")
         } catch (ex: DiffException) {
             assertThat(ex.errorMessage).isEqualTo(
-                ProcessorErrors.removedOrRenamedColumnFound("length")
+                ProcessorErrors.deletedOrRenamedColumnFound("MyAutoMigration", "length", "Song")
             )
         }
     }
@@ -119,12 +150,57 @@
         try {
             SchemaDiffer(
                 fromSchemaBundle = from.database,
-                toSchemaBundle = toColumnRemoved.database
+                toSchemaBundle = toColumnRemoved.database,
+                className = "MyAutoMigration",
+                renameColumnEntries = listOf(),
+                deleteColumnEntries = listOf(),
+                renameTableEntries = listOf(),
+                deleteTableEntries = listOf()
             ).diffSchemas()
             fail("DiffException should have been thrown.")
         } catch (ex: DiffException) {
             assertThat(ex.errorMessage).isEqualTo(
-                ProcessorErrors.removedOrRenamedColumnFound("length")
+                ProcessorErrors.deletedOrRenamedColumnFound("MyAutoMigration", "length", "Song")
+            )
+        }
+    }
+
+    @Test
+    fun testTableRenamedWithoutAnnotation() {
+        try {
+            SchemaDiffer(
+                fromSchemaBundle = from.database,
+                toSchemaBundle = toTableRenamed.database,
+                className = "MyAutoMigration",
+                renameColumnEntries = listOf(),
+                deleteColumnEntries = listOf(),
+                renameTableEntries = listOf(),
+                deleteTableEntries = listOf()
+            ).diffSchemas()
+            fail("DiffException should have been thrown.")
+        } catch (ex: DiffException) {
+            assertThat(ex.errorMessage).isEqualTo(
+                ProcessorErrors.deletedOrRenamedTableFound("MyAutoMigration", "Artist")
+            )
+        }
+    }
+
+    @Test
+    fun testTableRemovedWithoutAnnotation() {
+        try {
+            SchemaDiffer(
+                fromSchemaBundle = from.database,
+                toSchemaBundle = toTableDeleted.database,
+                className = "MyAutoMigration",
+                renameColumnEntries = listOf(),
+                deleteColumnEntries = listOf(),
+                renameTableEntries = listOf(),
+                deleteTableEntries = listOf()
+            ).diffSchemas()
+            fail("DiffException should have been thrown.")
+        } catch (ex: DiffException) {
+            assertThat(ex.errorMessage).isEqualTo(
+                ProcessorErrors.deletedOrRenamedTableFound("MyAutoMigration", "Artist")
             )
         }
     }
@@ -168,6 +244,40 @@
                     ),
                     mutableListOf(),
                     mutableListOf()
+                ),
+                EntityBundle(
+                    "Artist",
+                    "CREATE TABLE IF NOT EXISTS `Artist` (`id` INTEGER NOT NULL, " +
+                        "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+                    listOf(
+                        FieldBundle(
+                            "id",
+                            "id",
+                            "INTEGER",
+                            true,
+                            "1"
+                        ),
+                        FieldBundle(
+                            "title",
+                            "title",
+                            "TEXT",
+                            true,
+                            ""
+                        ),
+                        FieldBundle(
+                            "length",
+                            "length",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(
+                        false,
+                        mutableListOf("id")
+                    ),
+                    mutableListOf(),
+                    mutableListOf()
                 )
             ),
             mutableListOf(),
@@ -176,6 +286,132 @@
     )
 
     /** Valid "to" Schemas */
+    val toTableRenamed = SchemaBundle(
+        2,
+        DatabaseBundle(
+            2,
+            "",
+            mutableListOf(
+                EntityBundle(
+                    "Song",
+                    "CREATE TABLE IF NOT EXISTS `Song` (`id` INTEGER NOT NULL, " +
+                        "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+                    listOf(
+                        FieldBundle(
+                            "id",
+                            "id",
+                            "INTEGER",
+                            true,
+                            "1"
+                        ),
+                        FieldBundle(
+                            "title",
+                            "title",
+                            "TEXT",
+                            true,
+                            ""
+                        ),
+                        FieldBundle(
+                            "length",
+                            "length",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(
+                        false,
+                        mutableListOf("id")
+                    ),
+                    mutableListOf(),
+                    mutableListOf()
+                ),
+                EntityBundle(
+                    "Album",
+                    "CREATE TABLE IF NOT EXISTS `Song` (`id` INTEGER NOT NULL, " +
+                        "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+                    listOf(
+                        FieldBundle(
+                            "id",
+                            "id",
+                            "INTEGER",
+                            true,
+                            "1"
+                        ),
+                        FieldBundle(
+                            "title",
+                            "title",
+                            "TEXT",
+                            true,
+                            ""
+                        ),
+                        FieldBundle(
+                            "length",
+                            "length",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(
+                        false,
+                        mutableListOf("id")
+                    ),
+                    mutableListOf(),
+                    mutableListOf()
+                )
+            ),
+            mutableListOf(),
+            mutableListOf()
+        )
+    )
+
+    val toTableDeleted = SchemaBundle(
+        2,
+        DatabaseBundle(
+            2,
+            "",
+            mutableListOf(
+                EntityBundle(
+                    "Song",
+                    "CREATE TABLE IF NOT EXISTS `Song` (`id` INTEGER NOT NULL, " +
+                        "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+                    listOf(
+                        FieldBundle(
+                            "id",
+                            "id",
+                            "INTEGER",
+                            true,
+                            "1"
+                        ),
+                        FieldBundle(
+                            "title",
+                            "title",
+                            "TEXT",
+                            true,
+                            ""
+                        ),
+                        FieldBundle(
+                            "length",
+                            "length",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(
+                        false,
+                        mutableListOf("id")
+                    ),
+                    mutableListOf(),
+                    mutableListOf()
+                )
+            ),
+            mutableListOf(),
+            mutableListOf()
+        )
+    )
+
     val toColumnAddedWithColumnInfoDefaultValue = SchemaBundle(
         2,
         DatabaseBundle(
@@ -223,6 +459,40 @@
                     ),
                     emptyList(),
                     emptyList()
+                ),
+                EntityBundle(
+                    "Artist",
+                    "CREATE TABLE IF NOT EXISTS `Artist` (`id` INTEGER NOT NULL, " +
+                        "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+                    listOf(
+                        FieldBundle(
+                            "id",
+                            "id",
+                            "INTEGER",
+                            true,
+                            "1"
+                        ),
+                        FieldBundle(
+                            "title",
+                            "title",
+                            "TEXT",
+                            true,
+                            ""
+                        ),
+                        FieldBundle(
+                            "length",
+                            "length",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(
+                        false,
+                        mutableListOf("id")
+                    ),
+                    mutableListOf(),
+                    mutableListOf()
                 )
             ),
             mutableListOf(),
@@ -268,6 +538,40 @@
                     ),
                     emptyList(),
                     emptyList()
+                ),
+                EntityBundle(
+                    "Artist",
+                    "CREATE TABLE IF NOT EXISTS `Artist` (`id` INTEGER NOT NULL, " +
+                        "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+                    listOf(
+                        FieldBundle(
+                            "id",
+                            "id",
+                            "INTEGER",
+                            true,
+                            "1"
+                        ),
+                        FieldBundle(
+                            "title",
+                            "title",
+                            "TEXT",
+                            true,
+                            ""
+                        ),
+                        FieldBundle(
+                            "length",
+                            "length",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(
+                        false,
+                        mutableListOf("id")
+                    ),
+                    mutableListOf(),
+                    mutableListOf()
                 )
             ),
             mutableListOf(),
@@ -327,6 +631,40 @@
                     ),
                     emptyList(),
                     emptyList()
+                ),
+                EntityBundle(
+                    "Artist",
+                    "CREATE TABLE IF NOT EXISTS `Artist` (`id` INTEGER NOT NULL, " +
+                        "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+                    listOf(
+                        FieldBundle(
+                            "id",
+                            "id",
+                            "INTEGER",
+                            true,
+                            "1"
+                        ),
+                        FieldBundle(
+                            "title",
+                            "title",
+                            "TEXT",
+                            true,
+                            ""
+                        ),
+                        FieldBundle(
+                            "length",
+                            "length",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(
+                        false,
+                        mutableListOf("id")
+                    ),
+                    mutableListOf(),
+                    mutableListOf()
                 )
             ),
             mutableListOf(),
@@ -379,6 +717,40 @@
                     ),
                     mutableListOf(),
                     mutableListOf()
+                ),
+                EntityBundle(
+                    "Artist",
+                    "CREATE TABLE IF NOT EXISTS `Artist` (`id` INTEGER NOT NULL, " +
+                        "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+                    listOf(
+                        FieldBundle(
+                            "id",
+                            "id",
+                            "INTEGER",
+                            true,
+                            "1"
+                        ),
+                        FieldBundle(
+                            "title",
+                            "title",
+                            "TEXT",
+                            true,
+                            ""
+                        ),
+                        FieldBundle(
+                            "length",
+                            "length",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(
+                        false,
+                        mutableListOf("id")
+                    ),
+                    mutableListOf(),
+                    mutableListOf()
                 )
             ),
             mutableListOf(),
@@ -390,7 +762,6 @@
      * The affinity of a length column is changed from Integer to Text. No columns are
      * added/removed.
      */
-    // TODO: We currently do not support column affinity changes.
     val toColumnAffinityChanged = SchemaBundle(
         2,
         DatabaseBundle(
@@ -431,6 +802,40 @@
                     ),
                     mutableListOf(),
                     mutableListOf()
+                ),
+                EntityBundle(
+                    "Artist",
+                    "CREATE TABLE IF NOT EXISTS `Artist` (`id` INTEGER NOT NULL, " +
+                        "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+                    listOf(
+                        FieldBundle(
+                            "id",
+                            "id",
+                            "INTEGER",
+                            true,
+                            "1"
+                        ),
+                        FieldBundle(
+                            "title",
+                            "title",
+                            "TEXT",
+                            true,
+                            ""
+                        ),
+                        FieldBundle(
+                            "length",
+                            "length",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(
+                        false,
+                        mutableListOf("id")
+                    ),
+                    mutableListOf(),
+                    mutableListOf()
                 )
             ),
             mutableListOf(),
@@ -480,20 +885,37 @@
                 ),
                 EntityBundle(
                     "Artist",
-                    "CREATE TABLE IF NOT EXISTS `Artist` (`artistId` INTEGER NOT NULL, `name` " +
-                        "TEXT NOT NULL, PRIMARY KEY(`artistId`))",
+                    "CREATE TABLE IF NOT EXISTS `Artist` (`id` INTEGER NOT NULL, " +
+                        "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
                     listOf(
                         FieldBundle(
-                            "artistId",
-                            "artistId",
+                            "id",
+                            "id",
+                            "INTEGER",
+                            true,
+                            "1"
+                        ),
+                        FieldBundle(
+                            "title",
+                            "title",
+                            "TEXT",
+                            true,
+                            ""
+                        ),
+                        FieldBundle(
+                            "length",
+                            "length",
                             "INTEGER",
                             true,
                             "1"
                         )
                     ),
-                    PrimaryKeyBundle(true, listOf("artistId")),
-                    listOf(),
-                    listOf()
+                    PrimaryKeyBundle(
+                        false,
+                        mutableListOf("id")
+                    ),
+                    mutableListOf(),
+                    mutableListOf()
                 ),
                 EntityBundle(
                     "Album",
@@ -575,6 +997,40 @@
                             listOf("artistId")
                         )
                     )
+                ),
+                EntityBundle(
+                    "Artist",
+                    "CREATE TABLE IF NOT EXISTS `Artist` (`id` INTEGER NOT NULL, " +
+                        "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+                    listOf(
+                        FieldBundle(
+                            "id",
+                            "id",
+                            "INTEGER",
+                            true,
+                            "1"
+                        ),
+                        FieldBundle(
+                            "title",
+                            "title",
+                            "TEXT",
+                            true,
+                            ""
+                        ),
+                        FieldBundle(
+                            "length",
+                            "length",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(
+                        false,
+                        mutableListOf("id")
+                    ),
+                    mutableListOf(),
+                    mutableListOf()
                 )
             ),
             mutableListOf(),
@@ -629,6 +1085,40 @@
                         )
                     ),
                     mutableListOf()
+                ),
+                EntityBundle(
+                    "Artist",
+                    "CREATE TABLE IF NOT EXISTS `Artist` (`id` INTEGER NOT NULL, " +
+                        "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+                    listOf(
+                        FieldBundle(
+                            "id",
+                            "id",
+                            "INTEGER",
+                            true,
+                            "1"
+                        ),
+                        FieldBundle(
+                            "title",
+                            "title",
+                            "TEXT",
+                            true,
+                            ""
+                        ),
+                        FieldBundle(
+                            "length",
+                            "length",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(
+                        false,
+                        mutableListOf("id")
+                    ),
+                    mutableListOf(),
+                    mutableListOf()
                 )
             ),
             mutableListOf(),
@@ -675,6 +1165,40 @@
                     ),
                     mutableListOf(),
                     mutableListOf()
+                ),
+                EntityBundle(
+                    "Artist",
+                    "CREATE TABLE IF NOT EXISTS `Artist` (`id` INTEGER NOT NULL, " +
+                        "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+                    listOf(
+                        FieldBundle(
+                            "id",
+                            "id",
+                            "INTEGER",
+                            true,
+                            "1"
+                        ),
+                        FieldBundle(
+                            "title",
+                            "title",
+                            "TEXT",
+                            true,
+                            ""
+                        ),
+                        FieldBundle(
+                            "length",
+                            "length",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(
+                        false,
+                        mutableListOf("id")
+                    ),
+                    mutableListOf(),
+                    mutableListOf()
                 )
             ),
             mutableListOf(),
diff --git a/room/compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt b/room/compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt
index 4da432f..9497ce2 100644
--- a/room/compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt
@@ -36,7 +36,6 @@
             """
             package foo.bar;
             import androidx.room.migration.AutoMigrationCallback;
-            import androidx.room.AutoMigration;
             import androidx.sqlite.db.SupportSQLiteDatabase;
             interface ValidAutoMigrationWithDefault extends AutoMigrationCallback {}
             """.trimIndent()
@@ -65,10 +64,11 @@
                             )
                         )
                     ),
-                    removedOrRenamedColumns = listOf(),
-                    addedTables = listOf(),
+                    deletedColumns = listOf(),
+                    addedTables = setOf(),
                     complexChangedTables = mapOf(),
-                    removedOrRenamedTables = listOf()
+                    renamedTables = mapOf(),
+                    deletedTables = listOf()
                 ),
             )
             AutoMigrationWriter(
@@ -82,7 +82,7 @@
                     loadTestSource(
                         "autoMigrationWriter/output/ValidAutoMigrationWithDefault" +
                             ".java",
-                        "foo.bar.ValidAutoMigrationWithDefault_Impl"
+                        "foo.bar.AutoMigration_1_2_Impl"
                     )
                 )
             }
@@ -96,9 +96,7 @@
             """
             package foo.bar;
             import androidx.room.migration.AutoMigrationCallback;
-            import androidx.room.AutoMigration;
             import androidx.sqlite.db.SupportSQLiteDatabase;
-            @AutoMigration(from=1, to=2)
             interface ValidAutoMigrationWithoutDefault extends AutoMigrationCallback {}
             """.trimIndent()
         )
@@ -126,10 +124,11 @@
                             )
                         )
                     ),
-                    removedOrRenamedColumns = listOf(),
-                    addedTables = listOf(),
+                    deletedColumns = listOf(),
+                    addedTables = setOf(),
                     complexChangedTables = mapOf(),
-                    removedOrRenamedTables = listOf()
+                    renamedTables = mapOf(),
+                    deletedTables = listOf()
                 ),
             )
             AutoMigrationWriter(
@@ -142,7 +141,7 @@
                 generatedSource(
                     loadTestSource(
                         "autoMigrationWriter/output/ValidAutoMigrationWithoutDefault.java",
-                        "foo.bar.ValidAutoMigrationWithoutDefault_Impl"
+                        "foo.bar.AutoMigration_1_2_Impl"
                     )
                 )
             }
diff --git a/room/integration-tests/testapp/schemas/androidx.room.integration.testapp.migration.AutoMigrationDb/1.json b/room/integration-tests/testapp/schemas/androidx.room.integration.testapp.migration.AutoMigrationDb/1.json
index c02e4d1..8b7d1c0 100644
--- a/room/integration-tests/testapp/schemas/androidx.room.integration.testapp.migration.AutoMigrationDb/1.json
+++ b/room/integration-tests/testapp/schemas/androidx.room.integration.testapp.migration.AutoMigrationDb/1.json
@@ -467,6 +467,204 @@
           }
         ],
         "foreignKeys": []
+      },
+      {
+        "tableName": "Entity15",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `addedInV1` INTEGER NOT NULL DEFAULT 1, PRIMARY KEY(`id`))",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "addedInV1",
+            "columnName": "addedInV1",
+            "affinity": "INTEGER",
+            "notNull": true,
+            "defaultValue": "1"
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "Entity16",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `addedInV1` INTEGER NOT NULL DEFAULT 1, PRIMARY KEY(`id`))",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "addedInV1",
+            "columnName": "addedInV1",
+            "affinity": "INTEGER",
+            "notNull": true,
+            "defaultValue": "1"
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "Entity17",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `addedInV1` INTEGER NOT NULL DEFAULT 1, PRIMARY KEY(`id`))",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "addedInV1",
+            "columnName": "addedInV1",
+            "affinity": "INTEGER",
+            "notNull": true,
+            "defaultValue": "1"
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "Entity18",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `addedInV1` INTEGER NOT NULL DEFAULT 1, PRIMARY KEY(`id`))",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "addedInV1",
+            "columnName": "addedInV1",
+            "affinity": "INTEGER",
+            "notNull": true,
+            "defaultValue": "1"
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "Entity19",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `addedInV1` INTEGER NOT NULL DEFAULT 1, PRIMARY KEY(`id`))",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "addedInV1",
+            "columnName": "addedInV1",
+            "affinity": "INTEGER",
+            "notNull": true,
+            "defaultValue": "1"
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "Entity20",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `addedInV1` INTEGER NOT NULL DEFAULT 1, PRIMARY KEY(`id`))",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "addedInV1",
+            "columnName": "addedInV1",
+            "affinity": "INTEGER",
+            "notNull": true,
+            "defaultValue": "1"
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": []
       }
     ],
     "views": [],
diff --git a/room/integration-tests/testapp/schemas/androidx.room.integration.testapp.migration.AutoMigrationDb/2.json b/room/integration-tests/testapp/schemas/androidx.room.integration.testapp.migration.AutoMigrationDb/2.json
index 6ebbddb..a925d683 100644
--- a/room/integration-tests/testapp/schemas/androidx.room.integration.testapp.migration.AutoMigrationDb/2.json
+++ b/room/integration-tests/testapp/schemas/androidx.room.integration.testapp.migration.AutoMigrationDb/2.json
@@ -2,7 +2,7 @@
   "formatVersion": 1,
   "database": {
     "version": 2,
-    "identityHash": "cb0906b793f21e53ed5ff0db35729db5",
+    "identityHash": "083a4e91debef71d5d900ca2cf0baccf",
     "entities": [
       {
         "tableName": "Entity1",
@@ -314,7 +314,7 @@
       },
       {
         "tableName": "Entity10",
-        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `addedInV1` INTEGER NOT NULL DEFAULT 1, PRIMARY KEY(`id`), FOREIGN KEY(`addedInV1`) REFERENCES `Entity13`(`addedInV1`) ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED)",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `addedInV1` INTEGER NOT NULL DEFAULT 1, PRIMARY KEY(`id`), FOREIGN KEY(`addedInV1`) REFERENCES `Entity13_V2`(`addedInV1`) ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED)",
         "fields": [
           {
             "fieldPath": "id",
@@ -354,7 +354,7 @@
         ],
         "foreignKeys": [
           {
-            "table": "Entity13",
+            "table": "Entity13_V2",
             "onDelete": "NO ACTION",
             "onUpdate": "NO ACTION",
             "columns": [
@@ -442,7 +442,7 @@
         "foreignKeys": []
       },
       {
-        "tableName": "Entity13",
+        "tableName": "Entity13_V2",
         "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `addedInV1` INTEGER NOT NULL DEFAULT 1, PRIMARY KEY(`id`))",
         "fields": [
           {
@@ -473,12 +473,12 @@
         },
         "indices": [
           {
-            "name": "index_Entity13_addedInV1",
+            "name": "index_Entity13_V2_addedInV1",
             "unique": true,
             "columnNames": [
               "addedInV1"
             ],
-            "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Entity13_addedInV1` ON `${TABLE_NAME}` (`addedInV1`)"
+            "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_Entity13_V2_addedInV1` ON `${TABLE_NAME}` (`addedInV1`)"
           }
         ],
         "foreignKeys": []
@@ -508,12 +508,177 @@
         },
         "indices": [],
         "foreignKeys": []
+      },
+      {
+        "tableName": "Entity15",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, PRIMARY KEY(`id`))",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": false
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "Entity16",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `renamedInV2` INTEGER NOT NULL DEFAULT 1, PRIMARY KEY(`id`))",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "renamedInV2",
+            "columnName": "renamedInV2",
+            "affinity": "INTEGER",
+            "notNull": true,
+            "defaultValue": "1"
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "Entity17",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `renamedInV2` TEXT DEFAULT '1', PRIMARY KEY(`id`))",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "renamedInV2",
+            "columnName": "renamedInV2",
+            "affinity": "TEXT",
+            "notNull": false,
+            "defaultValue": "'1'"
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "Entity19_V2",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT, `addedInV1` INTEGER NOT NULL DEFAULT 1, PRIMARY KEY(`id`))",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "addedInV1",
+            "columnName": "addedInV1",
+            "affinity": "INTEGER",
+            "notNull": true,
+            "defaultValue": "1"
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "Entity20_V2",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER NOT NULL, `name` TEXT NOT NULL, `renamedInV2` TEXT DEFAULT '1', `addedInV2` INTEGER NOT NULL DEFAULT 2, PRIMARY KEY(`name`))",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "renamedInV2",
+            "columnName": "renamedInV2",
+            "affinity": "TEXT",
+            "notNull": false,
+            "defaultValue": "'1'"
+          },
+          {
+            "fieldPath": "addedInV2",
+            "columnName": "addedInV2",
+            "affinity": "INTEGER",
+            "notNull": true,
+            "defaultValue": "2"
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "name"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": []
       }
     ],
     "views": [],
     "setupQueries": [
       "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
-      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'cb0906b793f21e53ed5ff0db35729db5')"
+      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '083a4e91debef71d5d900ca2cf0baccf')"
     ]
   }
 }
\ No newline at end of file
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationDb.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationDb.java
index ce96535..db63fc3 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationDb.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationDb.java
@@ -22,11 +22,15 @@
 import androidx.room.ColumnInfo;
 import androidx.room.Dao;
 import androidx.room.Database;
+import androidx.room.DeleteColumn;
+import androidx.room.DeleteTable;
 import androidx.room.Entity;
 import androidx.room.ForeignKey;
 import androidx.room.Index;
 import androidx.room.PrimaryKey;
 import androidx.room.Query;
+import androidx.room.RenameColumn;
+import androidx.room.RenameTable;
 import androidx.room.RoomDatabase;
 import androidx.room.migration.AutoMigrationCallback;
 
@@ -47,15 +51,28 @@
                 AutoMigrationDb.Entity10.class,
                 AutoMigrationDb.Entity11.class,
                 AutoMigrationDb.Entity12.class,
-                AutoMigrationDb.Entity13.class,
-                AutoMigrationDb.Entity14.class
+                AutoMigrationDb.Entity13_V2.class,
+                AutoMigrationDb.Entity14.class,
+                AutoMigrationDb.Entity15.class,
+                AutoMigrationDb.Entity16.class,
+                AutoMigrationDb.Entity17.class,
+                AutoMigrationDb.Entity19_V2.class,
+                AutoMigrationDb.Entity20_V2.class
         },
-        autoMigrations = AutoMigrationDb.SimpleAutoMigration.class,
+        autoMigrations = {
+                @AutoMigration(
+                        from = 1, to = 2, callback = AutoMigrationDb.SimpleAutoMigration1.class
+                )
+        },
         exportSchema = true
 )
 public abstract class AutoMigrationDb extends RoomDatabase {
     static final int LATEST_VERSION = 2;
     abstract AutoMigrationDb.AutoMigrationDao dao();
+
+    /**
+     * No change between versions.
+     */
     @Entity
     static class Entity1 {
         public static final String TABLE_NAME = "Entity1";
@@ -66,6 +83,9 @@
         public int addedInV1;
     }
 
+    /**
+     * A new simple column added to Entity 2 with a default value.
+     */
     @Entity
     static class Entity2 {
         public static final String TABLE_NAME = "Entity2";
@@ -78,6 +98,9 @@
         public int addedInV2;
     }
 
+    /**
+     * Added Entity 3 to the schema. No foreign keys, views, indices added.
+     */
     @Entity
     static class Entity3 {
         public static final String TABLE_NAME = "Entity3";
@@ -86,6 +109,9 @@
         public String name;
     }
 
+    /**
+     * Changing the default value of ‘addedInV1’ in Entity 4.
+     */
     @Entity
     static class Entity4 {
         public static final String TABLE_NAME = "Entity4";
@@ -96,6 +122,9 @@
         public int addedInV1;
     }
 
+    /**
+     * Changing the affinity of ‘addedInV1’ in Entity 5.
+     */
     @Entity
     static class Entity5 {
         public static final String TABLE_NAME = "Entity5";
@@ -106,6 +135,9 @@
         public String addedInV1;
     }
 
+    /**
+     * Changing the nullability of ‘addedInV1’ in Entity 6.
+     */
     @Entity
     static class Entity6 {
         public static final String TABLE_NAME = "Entity6";
@@ -116,6 +148,9 @@
         public int addedInV1;
     }
 
+    /**
+     * No change between versions.
+     */
     @Entity
     static class Entity7 {
         public static final String TABLE_NAME = "Entity7";
@@ -126,6 +161,9 @@
         public int addedInV1;
     }
 
+    /**
+     * Change the primary key of Entity 8.
+     */
     @Entity
     static class Entity8 {
         public static final String TABLE_NAME = "Entity8";
@@ -137,6 +175,9 @@
         public int addedInV1;
     }
 
+    /**
+     * Add a foreign key to Entity 9.
+     */
     @Entity(foreignKeys = {
             @ForeignKey(entity = Entity12.class,
                     parentColumns = "id",
@@ -151,8 +192,13 @@
         public int addedInV1;
     }
 
+    /**
+     * Change the foreign key added in Entity 10 to ‘addedInV1’. Add index for addedInV1 on
+     * Entity 10. The reference table of the foreign key has been renamed from Entity13 to
+     * Entity13_V2.
+     */
     @Entity(foreignKeys = {
-            @ForeignKey(entity = Entity13.class,
+            @ForeignKey(entity = Entity13_V2.class,
                     parentColumns = "addedInV1",
                     childColumns = "addedInV1",
                     deferred = true)},
@@ -166,6 +212,9 @@
         public int addedInV1;
     }
 
+    /**
+     * Remove the foreign key in Entity 11.
+     */
     @Entity
     static class Entity11 {
         public static final String TABLE_NAME = "Entity11";
@@ -176,6 +225,9 @@
         public int addedInV1;
     }
 
+    /**
+     * Add an index ‘name’ to Entity 12.
+     */
     @Entity(indices = {@Index(value = "name", unique = true)})
     static class Entity12 {
         public static final String TABLE_NAME = "Entity12";
@@ -186,8 +238,12 @@
         public int addedInV1;
     }
 
+    /**
+     * Rename to Entity13_V2, it is a table referenced by the foreign key in Entity10. Change the
+     * index added in Entity 13 to ‘addedInV1’.
+     */
     @Entity(indices = {@Index(value = "addedInV1", unique = true)})
-    static class Entity13 {
+    static class Entity13_V2 {
         public static final String TABLE_NAME = "Entity13";
         @PrimaryKey
         public int id;
@@ -196,6 +252,9 @@
         public int addedInV1;
     }
 
+    /**
+     * Remove the index ‘name’ added in Entity 14.
+     */
     @Entity
     static class Entity14 {
         public static final String TABLE_NAME = "Entity14";
@@ -204,14 +263,94 @@
         public String name;
     }
 
+    /**
+     * Deleting the column ‘addedInV1’ from Entity 15.
+     */
+    @Entity
+    static class Entity15 {
+        public static final String TABLE_NAME = "Entity15";
+        @PrimaryKey
+        public int id;
+        public String name;
+    }
+
+    /**
+     * Renaming the column ‘addedInV1’ from Entity 16 to ‘renamedInV2’.
+     */
+    @Entity
+    static class Entity16 {
+        public static final String TABLE_NAME = "Entity16";
+        @PrimaryKey
+        public int id;
+        public String name;
+        @ColumnInfo(defaultValue = "1")
+        public int renamedInV2;
+    }
+
+    /**
+     * Renaming the column ‘addedInV1’ from Entity 17 to ‘renamedInV2’. Changing the affinity of
+     * this column.
+     */
+    @Entity
+    static class Entity17 {
+        public static final String TABLE_NAME = "Entity17";
+        @PrimaryKey
+        public int id;
+        public String name;
+        @ColumnInfo(defaultValue = "1")
+        public String renamedInV2;
+    }
+
+    /**
+     * Deleted Entity 18.
+     *
+     * Rename Entity19 to ‘Entity19_V2’.
+     */
+    @Entity
+    static class Entity19_V2 {
+        public static final String TABLE_NAME = "Entity19_V2";
+        @PrimaryKey
+        public int id;
+        public String name;
+        @ColumnInfo(defaultValue = "1")
+        public int addedInV1;
+    }
+
+    /**
+     * Rename Entity20 to ‘Entity20_V2’. Rename the column ‘addedInV1’ to ‘renamedInV2’. Change
+     * the primary key of this table to ‘name’. Change the affinity of the column ‘renamedInV2’.
+     * Add new column ‘addedInV2’.
+     */
+    @Entity
+    static class Entity20_V2 {
+        public static final String TABLE_NAME = "Entity20_V2";
+        public int id;
+        @PrimaryKey
+        @NonNull
+        public String name;
+        @ColumnInfo(defaultValue = "1")
+        public String renamedInV2;
+        @ColumnInfo(defaultValue = "2")
+        public int addedInV2;
+    }
+
     @Dao
     interface AutoMigrationDao {
         @Query("SELECT * from Entity1 ORDER BY id ASC")
         List<AutoMigrationDb.Entity1> getAllEntity1s();
     }
 
-    @AutoMigration(from=1, to=2)
-    interface SimpleAutoMigration extends AutoMigrationCallback {
-
+    @DeleteTable(deletedTableName = "Entity18")
+    @RenameTable(originalTableName = "Entity19", newTableName = "Entity19_V2")
+    @RenameTable(originalTableName = "Entity20", newTableName = "Entity20_V2")
+    @RenameTable(originalTableName = "Entity13", newTableName = "Entity13_V2")
+    @RenameColumn(tableName = "Entity16", originalColumnName = "addedInV1",
+            newColumnName = "renamedInV2")
+    @RenameColumn(tableName = "Entity17", originalColumnName = "addedInV1",
+            newColumnName = "renamedInV2")
+    @RenameColumn(tableName = "Entity20", originalColumnName = "addedInV1",
+            newColumnName = "renamedInV2")
+    @DeleteColumn(tableName = "Entity15", deletedColumnName = "addedInV1")
+    interface SimpleAutoMigration1 extends AutoMigrationCallback {
     }
 }
\ No newline at end of file
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationTest.java
index 5000a72..7a45a06 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/migration/AutoMigrationTest.java
@@ -48,6 +48,12 @@
                 AutoMigrationDb.class.getCanonicalName());
     }
 
+    // Run this to create the very 1st version of the db.
+    public void createFirstVersion() throws IOException {
+        SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 2);
+        db.close();
+    }
+
     @Test
     public void testBadAutoMigrationInput() throws IOException {
         try (SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 1)) {
@@ -57,15 +63,15 @@
                     TEST_DB,
                     2,
                     true,
-                    autoMigrationDbV2.getAutoGeneratedMigration(2, 3)
+                    autoMigrationDbV2.getAutoGeneratedMigration(3, 4)
             );
             fail();
         } catch (IllegalArgumentException ex) {
             assertThat(
                     ex.getMessage(),
-                    is("No AutoMigrations between versions 'from = 2', 'to = "
-                    + "3' have been provided. Annotate Database class with @AutoMigration(from = "
-                    + "2, to = 3) to generate this AutoMigration.")
+                    is("No AutoMigrations between versions 'from = 3', 'to = "
+                    + "4' have been provided. Annotate Database class with @AutoMigration(from = "
+                    + "3, to = 4) to generate this AutoMigration.")
             );
         }
     }
@@ -85,18 +91,6 @@
         assertThat(autoMigrationDbV2.dao().getAllEntity1s().size(), is(1));
     }
 
-    // Run this to create the very 1st version of the db.
-    public void createFirstVersion() throws IOException {
-        SupportSQLiteDatabase db = helper.createDatabase(TEST_DB, 1);
-        db.close();
-    }
-
-    public void createSecondVersion() {
-        AutoMigrationDb autoMigrationDbV2 = getLatestDb();
-
-        assertThat(autoMigrationDbV2.dao().getAllEntity1s().size(), is(1));
-    }
-
     private AutoMigrationDb getLatestDb() {
         AutoMigrationDb db = Room.databaseBuilder(
                 InstrumentationRegistry.getInstrumentation().getTargetContext(),
diff --git a/room/runtime/api/current.txt b/room/runtime/api/current.txt
index d708dbf..003bb27 100644
--- a/room/runtime/api/current.txt
+++ b/room/runtime/api/current.txt
@@ -111,6 +111,7 @@
     method public void addMigrations(androidx.room.migration.Migration!...);
     method public void addMigrations(java.util.List<androidx.room.migration.Migration!>);
     method public java.util.List<androidx.room.migration.Migration!>? findMigrationPath(int, int);
+    method public java.util.Map<java.lang.Integer!,java.util.Map<java.lang.Integer!,androidx.room.migration.Migration!>!> getMigrations();
   }
 
   public abstract static class RoomDatabase.PrepackagedDatabaseCallback {
diff --git a/room/runtime/api/public_plus_experimental_current.txt b/room/runtime/api/public_plus_experimental_current.txt
index 608cd54..fc91b21 100644
--- a/room/runtime/api/public_plus_experimental_current.txt
+++ b/room/runtime/api/public_plus_experimental_current.txt
@@ -116,6 +116,7 @@
     method public void addMigrations(androidx.room.migration.Migration!...);
     method public void addMigrations(java.util.List<androidx.room.migration.Migration!>);
     method public java.util.List<androidx.room.migration.Migration!>? findMigrationPath(int, int);
+    method public java.util.Map<java.lang.Integer!,java.util.Map<java.lang.Integer!,androidx.room.migration.Migration!>!> getMigrations();
   }
 
   public abstract static class RoomDatabase.PrepackagedDatabaseCallback {
diff --git a/room/runtime/api/restricted_current.txt b/room/runtime/api/restricted_current.txt
index 89994c2..7f8f611 100644
--- a/room/runtime/api/restricted_current.txt
+++ b/room/runtime/api/restricted_current.txt
@@ -154,6 +154,7 @@
     method public void addMigrations(androidx.room.migration.Migration!...);
     method public void addMigrations(java.util.List<androidx.room.migration.Migration!>);
     method public java.util.List<androidx.room.migration.Migration!>? findMigrationPath(int, int);
+    method public java.util.Map<java.lang.Integer!,java.util.Map<java.lang.Integer!,androidx.room.migration.Migration!>!> getMigrations();
   }
 
   public abstract static class RoomDatabase.PrepackagedDatabaseCallback {
diff --git a/room/runtime/src/main/java/androidx/room/RoomDatabase.java b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
index f0d88eb..cd187e2 100644
--- a/room/runtime/src/main/java/androidx/room/RoomDatabase.java
+++ b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
@@ -186,8 +186,12 @@
     public void init(@NonNull DatabaseConfiguration configuration) {
         mOpenHelper = createOpenHelper(configuration);
         List<Migration> autoMigrations = getAutoMigrations();
-        if (autoMigrations.size() > 0) {
-            configuration.migrationContainer.addMigrations(autoMigrations);
+        for (Migration autoMigration : autoMigrations) {
+            boolean migrationExists = configuration.migrationContainer.getMigrations()
+                            .containsKey(autoMigration.startVersion);
+            if (!migrationExists) {
+                configuration.migrationContainer.addMigrations(autoMigrations);
+            }
         }
 
         // Configure SqliteCopyOpenHelper if it is available:
@@ -261,13 +265,13 @@
         }
     }
 
-    @NonNull
+
     /**
-     * Returns a list of {@link Migration} of a database that have been generated using
-     * {@link AutoMigration}.
+     * Returns a list of {@link Migration} of a database that have been automatically generated.
      *
      * @return A list of migration instances each of which is a generated autoMigration
      */
+    @NonNull
     protected List<Migration> getAutoMigrations() {
         return Arrays.asList();
     }
@@ -1445,13 +1449,23 @@
             }
             Migration existing = targetMap.get(end);
             if (existing != null) {
-                // TODO: (b/182251019) Favor user specified migration over generated automigrations
                 Log.w(Room.LOG_TAG, "Overriding migration " + existing + " with " + migration);
             }
             targetMap.put(end, migration);
         }
 
         /**
+         * Returns the map of available migrations where the key is the start version of the
+         * migration, and the value is a map of (end version -> Migration).
+         *
+         * @return Map of migrations keyed by the start version
+         */
+        @NonNull
+        public Map<Integer, Map<Integer, Migration>> getMigrations() {
+            return Collections.unmodifiableMap(mMigrations);
+        }
+
+        /**
          * Finds the list of migrations that should be run to move from {@code start} version to
          * {@code end} version.
          *
diff --git a/slices/builders/ktx/OWNERS b/slices/builders/ktx/OWNERS
index 4e131e2..1706cb06 100644
--- a/slices/builders/ktx/OWNERS
+++ b/slices/builders/ktx/OWNERS
@@ -1,3 +1,2 @@
-sigelbaum@google.com
-jakew@google.com
+yboyar@google.com
 madym@google.com
diff --git a/sqlite/sqlite-ktx/OWNERS b/sqlite/sqlite-ktx/OWNERS
index e450f4c..6fd8227 100644
--- a/sqlite/sqlite-ktx/OWNERS
+++ b/sqlite/sqlite-ktx/OWNERS
@@ -1 +1 @@
-jakew@google.com
+yboyar@google.com
diff --git a/testutils/testutils-ktx/OWNERS b/testutils/testutils-ktx/OWNERS
index e450f4c..6fd8227 100644
--- a/testutils/testutils-ktx/OWNERS
+++ b/testutils/testutils-ktx/OWNERS
@@ -1 +1 @@
-jakew@google.com
+yboyar@google.com
diff --git a/tv-provider/OWNERS b/tv-provider/OWNERS
new file mode 100644
index 0000000..a386cda
--- /dev/null
+++ b/tv-provider/OWNERS
@@ -0,0 +1,2 @@
+shubang@google.com
+quxiangfang@google.com
diff --git a/wear/wear-complications-provider/api/current.txt b/wear/wear-complications-provider/api/current.txt
index 5a2cfe4..2273217 100644
--- a/wear/wear-complications-provider/api/current.txt
+++ b/wear/wear-complications-provider/api/current.txt
@@ -4,7 +4,7 @@
   public abstract class ComplicationProviderService extends android.app.Service {
     ctor public ComplicationProviderService();
     method public abstract androidx.wear.complications.data.ComplicationData? getPreviewData(androidx.wear.complications.data.ComplicationType);
-    method public android.os.IBinder? onBind(android.content.Intent);
+    method public final android.os.IBinder? onBind(android.content.Intent);
     method @UiThread public void onComplicationActivated(int, int);
     method @UiThread public void onComplicationDeactivated(int);
     method @UiThread public abstract void onComplicationUpdate(int, androidx.wear.complications.data.ComplicationType, androidx.wear.complications.ComplicationProviderService.ComplicationUpdateListener);
diff --git a/wear/wear-complications-provider/api/public_plus_experimental_current.txt b/wear/wear-complications-provider/api/public_plus_experimental_current.txt
index 5a2cfe4..2273217 100644
--- a/wear/wear-complications-provider/api/public_plus_experimental_current.txt
+++ b/wear/wear-complications-provider/api/public_plus_experimental_current.txt
@@ -4,7 +4,7 @@
   public abstract class ComplicationProviderService extends android.app.Service {
     ctor public ComplicationProviderService();
     method public abstract androidx.wear.complications.data.ComplicationData? getPreviewData(androidx.wear.complications.data.ComplicationType);
-    method public android.os.IBinder? onBind(android.content.Intent);
+    method public final android.os.IBinder? onBind(android.content.Intent);
     method @UiThread public void onComplicationActivated(int, int);
     method @UiThread public void onComplicationDeactivated(int);
     method @UiThread public abstract void onComplicationUpdate(int, androidx.wear.complications.data.ComplicationType, androidx.wear.complications.ComplicationProviderService.ComplicationUpdateListener);
diff --git a/wear/wear-complications-provider/api/restricted_current.txt b/wear/wear-complications-provider/api/restricted_current.txt
index 83d6e4b..0d4e30b 100644
--- a/wear/wear-complications-provider/api/restricted_current.txt
+++ b/wear/wear-complications-provider/api/restricted_current.txt
@@ -4,7 +4,7 @@
   public abstract class ComplicationProviderService extends android.app.Service {
     ctor public ComplicationProviderService();
     method public abstract androidx.wear.complications.data.ComplicationData? getPreviewData(androidx.wear.complications.data.ComplicationType);
-    method public android.os.IBinder? onBind(android.content.Intent);
+    method public final android.os.IBinder? onBind(android.content.Intent);
     method @UiThread public void onComplicationActivated(int, int);
     method @UiThread public void onComplicationDeactivated(int);
     method @UiThread public abstract void onComplicationUpdate(int, androidx.wear.complications.data.ComplicationType, androidx.wear.complications.ComplicationProviderService.ComplicationUpdateListener);
diff --git a/wear/wear-complications-provider/src/main/java/androidx/wear/complications/ComplicationProviderService.java b/wear/wear-complications-provider/src/main/java/androidx/wear/complications/ComplicationProviderService.java
index 32e1fe3..a7e5463 100644
--- a/wear/wear-complications-provider/src/main/java/androidx/wear/complications/ComplicationProviderService.java
+++ b/wear/wear-complications-provider/src/main/java/androidx/wear/complications/ComplicationProviderService.java
@@ -269,7 +269,7 @@
     @SuppressLint("SyntheticAccessor")
     @Override
     @Nullable
-    public IBinder onBind(@NonNull Intent intent) {
+    public final IBinder onBind(@NonNull Intent intent) {
         if (ACTION_COMPLICATION_UPDATE_REQUEST.equals(intent.getAction())) {
             if (mWrapper == null) {
                 mWrapper = new IComplicationProviderWrapper();