Merge "This CL updates the preferences to use the Car.NoActionBar theme by using attributes instead of hardcoded values.  It also updates the sample preferences app to use the new theme.  Lastly, it updates the Checkbox widget to use the new checkbox drawable." into androidx-master-dev
diff --git a/appcompat/api/current.txt b/appcompat/api/current.txt
index c7c17f4..cfba121 100644
--- a/appcompat/api/current.txt
+++ b/appcompat/api/current.txt
@@ -259,6 +259,7 @@
     method public abstract androidx.appcompat.app.ActionBarDrawerToggle.Delegate getDrawerToggleDelegate();
     method public abstract android.view.MenuInflater getMenuInflater();
     method public abstract androidx.appcompat.app.ActionBar getSupportActionBar();
+    method public abstract android.content.Context getThemedContext();
     method public abstract boolean hasWindowFeature(int);
     method public abstract void installViewFactory();
     method public abstract void invalidateOptionsMenu();
@@ -270,6 +271,7 @@
     method public abstract void onPostCreate(android.os.Bundle);
     method public abstract void onPostResume();
     method public abstract void onSaveInstanceState(android.os.Bundle);
+    method public abstract void onSetTheme(int);
     method public abstract void onStart();
     method public abstract void onStop();
     method public abstract boolean requestWindowFeature(int);
diff --git a/appcompat/src/androidTest/AndroidManifest.xml b/appcompat/src/androidTest/AndroidManifest.xml
index 443fa24..a425c02 100644
--- a/appcompat/src/androidTest/AndroidManifest.xml
+++ b/appcompat/src/androidTest/AndroidManifest.xml
@@ -144,6 +144,11 @@
                 android:theme="@style/Theme.AppCompat.DayNight"/>
 
         <activity
+                android:name="androidx.appcompat.app.NightModeConfigChangesActivity"
+                android:theme="@style/Theme.AppCompat.DayNight"
+                android:configChanges="uiMode"/>
+
+        <activity
                 android:name="androidx.appcompat.app.AppCompatVectorDrawableIntegrationActivity"/>
 
         <activity
diff --git a/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeActivity.java b/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeActivity.java
index 9871cb8..a4145df 100644
--- a/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeActivity.java
+++ b/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeActivity.java
@@ -16,6 +16,10 @@
 
 package androidx.appcompat.app;
 
+import android.content.res.Configuration;
+import android.view.View;
+import android.widget.Button;
+
 import androidx.appcompat.test.R;
 import androidx.appcompat.testutils.BaseTestActivity;
 
@@ -29,6 +33,14 @@
      */
     static NightModeActivity TOP_ACTIVITY = null;
 
+    Configuration lastChangeConfiguration = null;
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        lastChangeConfiguration = newConfig;
+    }
+
     @Override
     protected int getContentViewLayoutResId() {
         return R.layout.activity_night_mode;
@@ -47,4 +59,11 @@
             TOP_ACTIVITY = null;
         }
     }
+
+    /**
+     * This is referenced from an android:onClick in the layout
+     */
+    public void onButtonClicked(View view) {
+        ((Button) view).setText(R.string.clicked);
+    }
 }
diff --git a/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeConfigChangesActivity.java b/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeConfigChangesActivity.java
new file mode 100644
index 0000000..eb17cdd
--- /dev/null
+++ b/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeConfigChangesActivity.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appcompat.app;
+
+public class NightModeConfigChangesActivity extends NightModeActivity {}
diff --git a/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeConfigChangesTestCase.java b/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeConfigChangesTestCase.java
new file mode 100644
index 0000000..549c5cd
--- /dev/null
+++ b/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeConfigChangesTestCase.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appcompat.app;
+
+import static androidx.appcompat.testutils.NightModeUtils.assertConfigurationNightModeEquals;
+import static androidx.appcompat.testutils.NightModeUtils.setLocalNightModeAndWait;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.content.res.Configuration;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class NightModeConfigChangesTestCase {
+    @Rule
+    public final ActivityTestRule<NightModeConfigChangesActivity> mActivityTestRule;
+
+    public NightModeConfigChangesTestCase() {
+        mActivityTestRule = new ActivityTestRule<>(NightModeConfigChangesActivity.class);
+    }
+
+    @Before
+    public void setup() {
+        // By default we'll set the night mode to NO, which allows us to make better
+        // assumptions in the test below
+        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
+    }
+
+    @Test
+    public void testOnConfigurationChangedCalled() throws Throwable {
+        final NightModeConfigChangesActivity activity = mActivityTestRule.getActivity();
+
+        // Assert that the Activity does not have a config currently
+        assertNull(activity.lastChangeConfiguration);
+
+        // Set local night mode to YES
+        setLocalNightModeAndWait(mActivityTestRule, AppCompatDelegate.MODE_NIGHT_YES);
+
+        // Assert that the Activity received a new config
+        assertNotNull(activity.lastChangeConfiguration);
+        assertConfigurationNightModeEquals(Configuration.UI_MODE_NIGHT_YES,
+                activity.lastChangeConfiguration);
+
+        // Set local night mode back to NO
+        setLocalNightModeAndWait(mActivityTestRule, AppCompatDelegate.MODE_NIGHT_NO);
+
+        // Assert that the Activity received a new config
+        assertNotNull(activity.lastChangeConfiguration);
+        assertConfigurationNightModeEquals(Configuration.UI_MODE_NIGHT_NO,
+                activity.lastChangeConfiguration);
+    }
+}
diff --git a/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeTestCase.java b/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeTestCase.java
index b46481f6..09037c9 100644
--- a/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeTestCase.java
+++ b/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeTestCase.java
@@ -17,15 +17,21 @@
 package androidx.appcompat.app;
 
 import static androidx.appcompat.app.NightModeActivity.TOP_ACTIVITY;
+import static androidx.appcompat.testutils.NightModeUtils.assertConfigurationNightModeEquals;
+import static androidx.appcompat.testutils.NightModeUtils.setLocalNightModeAndWait;
 import static androidx.appcompat.testutils.TestUtilsMatchers.isBackground;
 import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import android.app.Instrumentation;
+import android.content.res.Configuration;
+import android.webkit.WebView;
 
 import androidx.appcompat.test.R;
 import androidx.core.content.ContextCompat;
@@ -175,6 +181,62 @@
         onView(withId(R.id.text_night_mode)).check(matches(withText(STRING_NIGHT)));
     }
 
+    @Test
+    public void testOnConfigurationChangedNotCalled() throws Throwable {
+        final NightModeActivity activity = mActivityTestRule.getActivity();
+
+        // Assert that the Activity does not have a config currently
+        assertNull(activity.lastChangeConfiguration);
+
+        // Set local night mode to YES
+        setLocalNightModeAndWait(mActivityTestRule, AppCompatDelegate.MODE_NIGHT_YES);
+
+        // Assert that the Activity still does not have a config currently
+        assertNull(activity.lastChangeConfiguration);
+
+        // Set local night mode back to NO
+        setLocalNightModeAndWait(mActivityTestRule, AppCompatDelegate.MODE_NIGHT_NO);
+
+        // Assert that the Activity still does not have a config currently
+        assertNull(activity.lastChangeConfiguration);
+    }
+
+    @Test
+    public void testWebViewMaintainsConfiguration() throws Throwable {
+        // Set night mode and wait for the new Activity
+        final NightModeActivity activity = setLocalNightModeAndWaitForRecreate(
+                mActivityTestRule.getActivity(), AppCompatDelegate.MODE_NIGHT_YES);
+
+        // Assert that the themed context has the correct config
+        assertConfigurationNightModeEquals(Configuration.UI_MODE_NIGHT_YES,
+                activity.getThemedContext().getResources().getConfiguration());
+
+        // Now load a WebView into the Activity
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final WebView webView = new WebView(activity);
+            }
+        });
+
+        // Now assert that the themed context has the correct config
+        assertConfigurationNightModeEquals(Configuration.UI_MODE_NIGHT_YES,
+                activity.getThemedContext().getResources().getConfiguration());
+    }
+
+    @Test
+    public void testXmlOnClickWithNightMode() throws Throwable {
+        // Set night mode and wait for the new Activity
+        setLocalNightModeAndWaitForRecreate(mActivityTestRule.getActivity(),
+                AppCompatDelegate.MODE_NIGHT_YES);
+
+        // Click the button and assert that the text changes. The text change logic is in
+        // an method in the Activity referenced from the XML layout
+        onView(withId(R.id.button))
+                .perform(click())
+                .check(matches(withText(R.string.clicked)));
+    }
+
     private static class FakeTwilightManager extends TwilightManager {
         private boolean mIsNight;
 
@@ -194,7 +256,8 @@
 
     private NightModeActivity setLocalNightModeAndWaitForRecreate(
             final NightModeActivity activity,
-            @AppCompatDelegate.NightMode final int nightMode) throws Throwable {
+            @AppCompatDelegate.NightMode final int nightMode
+    ) throws Throwable {
         final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
         mActivityTestRule.runOnUiThread(new Runnable() {
             @Override
diff --git a/appcompat/src/androidTest/java/androidx/appcompat/testutils/NightModeUtils.java b/appcompat/src/androidTest/java/androidx/appcompat/testutils/NightModeUtils.java
new file mode 100644
index 0000000..8880e99
--- /dev/null
+++ b/appcompat/src/androidTest/java/androidx/appcompat/testutils/NightModeUtils.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.appcompat.testutils;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.Instrumentation;
+import android.content.res.Configuration;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.app.AppCompatDelegate;
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+public class NightModeUtils {
+    public static void assertConfigurationNightModeEquals(int expectedNightMode,
+            Configuration configuration) {
+        assertEquals(expectedNightMode, configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK);
+    }
+
+    public static void setLocalNightModeAndWait(
+            final ActivityTestRule<? extends AppCompatActivity> activityRule,
+            @AppCompatDelegate.NightMode final int nightMode
+    ) throws Throwable {
+        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        activityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                activityRule.getActivity().getDelegate().setLocalNightMode(nightMode);
+            }
+        });
+        instrumentation.waitForIdleSync();
+    }
+}
diff --git a/appcompat/src/androidTest/res/layout/activity_night_mode.xml b/appcompat/src/androidTest/res/layout/activity_night_mode.xml
index 5cd8563..4e624f6 100644
--- a/appcompat/src/androidTest/res/layout/activity_night_mode.xml
+++ b/appcompat/src/androidTest/res/layout/activity_night_mode.xml
@@ -31,4 +31,11 @@
         android:layout_height="100dp"
         android:background="@drawable/test_night_color_conversion_background" />
 
+    <Button
+        android:id="@+id/button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:onClick="onButtonClicked"
+        android:text="@string/night_mode" />
+
 </LinearLayout>
\ No newline at end of file
diff --git a/appcompat/src/androidTest/res/values/strings.xml b/appcompat/src/androidTest/res/values/strings.xml
index 964c32b..997dd0d 100644
--- a/appcompat/src/androidTest/res/values/strings.xml
+++ b/appcompat/src/androidTest/res/values/strings.xml
@@ -104,4 +104,6 @@
     <string name="font_serif">serif</string>
 
     <string name="toolbar_collapse">Toolbar collapse</string>
+
+    <string name="clicked">Clicked</string>
 </resources>
diff --git a/appcompat/src/main/java/androidx/appcompat/app/AppCompatActivity.java b/appcompat/src/main/java/androidx/appcompat/app/AppCompatActivity.java
index 1acc767..0c9633f 100644
--- a/appcompat/src/main/java/androidx/appcompat/app/AppCompatActivity.java
+++ b/appcompat/src/main/java/androidx/appcompat/app/AppCompatActivity.java
@@ -16,6 +16,7 @@
 
 package androidx.appcompat.app;
 
+import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -63,33 +64,35 @@
         TaskStackBuilder.SupportParentable, ActionBarDrawerToggle.DelegateProvider {
 
     private AppCompatDelegate mDelegate;
-    private int mThemeId = 0;
     private Resources mResources;
 
+    /**
+     * {@inheritDoc}
+     *
+     * When inflating any resources, make sure to use this Activity's themed context from {@link #getThemedContext()}.
+     * The returned context is setup with the correct theme, and is especially important when using this library's
+     * DayNight functionality.
+     * <p>
+     * This context is automatically used when you call {@link #setContentView(int)}, {@link #setContentView(View)},
+     * {@link #setContentView(View, ViewGroup.LayoutParams)}, and is automatically used by
+     * {@link androidx.fragment.app.Fragment}'s layout inflater.
+     * <p>
+     * Please note: make sure that you call {@code super.onCreate()} before using this Activity's {@link Resources}
+     * or its {@link Configuration}.
+     */
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         final AppCompatDelegate delegate = getDelegate();
         delegate.installViewFactory();
         delegate.onCreate(savedInstanceState);
-        if (delegate.applyDayNight() && mThemeId != 0) {
-            // If DayNight has been applied, we need to re-apply the theme for
-            // the changes to take effect. On API 23+, we should bypass
-            // setTheme(), which will no-op if the theme ID is identical to the
-            // current theme ID.
-            if (Build.VERSION.SDK_INT >= 23) {
-                onApplyThemeResource(getTheme(), mThemeId, false);
-            } else {
-                setTheme(mThemeId);
-            }
-        }
+        delegate.applyDayNight();
         super.onCreate(savedInstanceState);
     }
 
     @Override
-    public void setTheme(@StyleRes final int resid) {
-        super.setTheme(resid);
-        // Keep hold of the theme id so that we can re-set it later if needed
-        mThemeId = resid;
+    public void setTheme(@StyleRes final int resId) {
+        super.setTheme(resId);
+        getDelegate().onSetTheme(resId);
     }
 
     @Override
@@ -98,6 +101,12 @@
         getDelegate().onPostCreate(savedInstanceState);
     }
 
+    @NonNull
+    @Override
+    public Context getThemedContext() {
+        return getDelegate().getThemedContext();
+    }
+
     /**
      * Support library version of {@link android.app.Activity#getActionBar}.
      *
diff --git a/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegate.java b/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegate.java
index 268d23e..7bb6a0c 100644
--- a/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegate.java
+++ b/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegate.java
@@ -36,6 +36,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
+import androidx.annotation.StyleRes;
 import androidx.appcompat.view.ActionMode;
 import androidx.appcompat.widget.Toolbar;
 import androidx.appcompat.widget.VectorEnabledTintResources;
@@ -487,6 +488,18 @@
     }
 
     /**
+     * Returns the context which should be used to inflate any view hierarchies.
+     */
+    @NonNull
+    public abstract Context getThemedContext();
+
+    /**
+     * This should be called from {@link Activity#setTheme(int)} to notify AppCompat of what
+     * the current theme resource id is.
+     */
+    public abstract void onSetTheme(@StyleRes int themeResId);
+
+    /**
      * Sets whether vector drawables on older platforms (< API 21) can be used within
      * {@link android.graphics.drawable.DrawableContainer} resources.
      *
diff --git a/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java b/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java
index b628904..b3be4d0 100644
--- a/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java
+++ b/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java
@@ -26,6 +26,7 @@
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
@@ -44,7 +45,6 @@
 import android.text.TextUtils;
 import android.util.AndroidRuntimeException;
 import android.util.AttributeSet;
-import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.Gravity;
@@ -164,6 +164,9 @@
     final Window.Callback mAppCompatWindowCallback;
     final AppCompatCallback mAppCompatCallback;
 
+    Context mThemedContext;
+    int mThemeResId;
+
     ActionBar mActionBar;
     MenuInflater mMenuInflater;
 
@@ -215,6 +218,8 @@
     @NightMode
     private int mLocalNightMode = MODE_NIGHT_UNSPECIFIED;
     private boolean mApplyDayNightCalled;
+    private boolean mActivityHandlesUiMode;
+    private boolean mActivityHandlesUiModeChecked;
 
     private AutoNightModeManager mAutoNightModeManager;
 
@@ -254,18 +259,18 @@
         mAppCompatWindowCallback = new AppCompatWindowCallback(mOriginalWindowCallback);
         // Now install the new callback
         mWindow.setCallback(mAppCompatWindowCallback);
+    }
 
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
         final TintTypedArray a = TintTypedArray.obtainStyledAttributes(
-                context, null, sWindowBackgroundStyleable);
+                getThemedContext(), null, sWindowBackgroundStyleable);
         final Drawable winBg = a.getDrawableIfKnown(0);
         if (winBg != null) {
             mWindow.setBackgroundDrawable(winBg);
         }
         a.recycle();
-    }
 
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
         if (mOriginalWindowCallback instanceof Activity) {
             String parentActivityName = null;
             try {
@@ -370,6 +375,12 @@
         invalidateOptionsMenu();
     }
 
+    @NonNull
+    @Override
+    public Context getThemedContext() {
+        return mThemedContext != null ? mThemedContext : mContext;
+    }
+
     final Context getActionBarThemedContext() {
         Context context = null;
 
@@ -380,7 +391,7 @@
         }
 
         if (context == null) {
-            context = mContext;
+            context = getThemedContext();
         }
         return context;
     }
@@ -390,8 +401,7 @@
         // Make sure that action views can get an appropriate theme.
         if (mMenuInflater == null) {
             initWindowDecorActionBar();
-            mMenuInflater = new SupportMenuInflater(
-                    mActionBar != null ? mActionBar.getThemedContext() : mContext);
+            mMenuInflater = new SupportMenuInflater(getActionBarThemedContext());
         }
         return mMenuInflater;
     }
@@ -418,7 +428,11 @@
         }
 
         // Make sure that the DrawableManager knows about the new config
-        AppCompatDrawableManager.get().onConfigurationChanged(mContext);
+        final AppCompatDrawableManager acdm = AppCompatDrawableManager.get();
+        acdm.onConfigurationChanged(mContext);
+        if (mThemedContext != null) {
+            acdm.onConfigurationChanged(mThemedContext);
+        }
 
         // Re-apply Day/Night to the new configuration
         applyDayNight();
@@ -455,7 +469,7 @@
     @Override
     public void setContentView(View v) {
         ensureSubDecor();
-        ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
+        ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
         contentParent.removeAllViews();
         contentParent.addView(v);
         mOriginalWindowCallback.onContentChanged();
@@ -464,16 +478,21 @@
     @Override
     public void setContentView(int resId) {
         ensureSubDecor();
-        ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
+        ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
         contentParent.removeAllViews();
-        LayoutInflater.from(mContext).inflate(resId, contentParent);
+        if (mThemedContext != null) {
+            LayoutInflater.from(mContext).cloneInContext(mThemedContext)
+                    .inflate(resId, contentParent);
+        } else {
+            LayoutInflater.from(mContext).inflate(resId, contentParent);
+        }
         mOriginalWindowCallback.onContentChanged();
     }
 
     @Override
     public void setContentView(View v, ViewGroup.LayoutParams lp) {
         ensureSubDecor();
-        ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
+        ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
         contentParent.removeAllViews();
         contentParent.addView(v, lp);
         mOriginalWindowCallback.onContentChanged();
@@ -482,7 +501,7 @@
     @Override
     public void addContentView(View v, ViewGroup.LayoutParams lp) {
         ensureSubDecor();
-        ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
+        ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
         contentParent.addView(v, lp);
         mOriginalWindowCallback.onContentChanged();
     }
@@ -548,7 +567,8 @@
     }
 
     private ViewGroup createSubDecor() {
-        TypedArray a = mContext.obtainStyledAttributes(R.styleable.AppCompatTheme);
+        final Context themedContext = getThemedContext();
+        TypedArray a = themedContext.obtainStyledAttributes(R.styleable.AppCompatTheme);
 
         if (!a.hasValue(R.styleable.AppCompatTheme_windowActionBar)) {
             a.recycle();
@@ -574,7 +594,7 @@
         // Now let's make sure that the Window has installed its decor by retrieving it
         mWindow.getDecorView();
 
-        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        final LayoutInflater inflater = LayoutInflater.from(mContext).cloneInContext(themedContext);
         ViewGroup subDecor = null;
 
 
@@ -593,24 +613,23 @@
                  * ContextThemeWrapper pointing to actionBarTheme.
                  */
                 TypedValue outValue = new TypedValue();
-                mContext.getTheme().resolveAttribute(R.attr.actionBarTheme, outValue, true);
+                themedContext.getTheme().resolveAttribute(R.attr.actionBarTheme, outValue, true);
 
-                Context themedContext;
+                Context abThemedContext;
                 if (outValue.resourceId != 0) {
-                    themedContext = new ContextThemeWrapper(mContext, outValue.resourceId);
+                    abThemedContext = new ContextThemeWrapper(themedContext, outValue.resourceId);
                 } else {
-                    themedContext = mContext;
+                    abThemedContext = themedContext;
                 }
 
                 // Now inflate the view using the themed context and set it as the content view
-                subDecor = (ViewGroup) LayoutInflater.from(themedContext)
+                subDecor = (ViewGroup) LayoutInflater.from(abThemedContext)
                         .inflate(R.layout.abc_screen_toolbar, null);
 
-                mDecorContentParent = (DecorContentParent) subDecor
-                        .findViewById(R.id.decor_content_parent);
+                mDecorContentParent = subDecor.findViewById(R.id.decor_content_parent);
                 mDecorContentParent.setWindowCallback(getWindowCallback());
 
-                /**
+                /*
                  * Propagate features to DecorContentParent
                  */
                 if (mOverlayActionBar) {
@@ -728,7 +747,7 @@
     void onSubDecorInstalled(ViewGroup subDecor) {}
 
     private void applyFixedSizeWindow() {
-        ContentFrameLayout cfl = (ContentFrameLayout) mSubDecor.findViewById(android.R.id.content);
+        ContentFrameLayout cfl = mSubDecor.findViewById(android.R.id.content);
 
         // This is a bit weird. In the framework, the window sizing attributes control
         // the decor view's size, meaning that any padding is inset for the min/max widths below.
@@ -739,7 +758,7 @@
                 windowDecor.getPaddingTop(), windowDecor.getPaddingRight(),
                 windowDecor.getPaddingBottom());
 
-        TypedArray a = mContext.obtainStyledAttributes(R.styleable.AppCompatTheme);
+        TypedArray a = getThemedContext().obtainStyledAttributes(R.styleable.AppCompatTheme);
         a.getValue(R.styleable.AppCompatTheme_windowMinWidthMajor, cfl.getMinWidthMajor());
         a.getValue(R.styleable.AppCompatTheme_windowMinWidthMinor, cfl.getMinWidthMinor());
 
@@ -952,6 +971,8 @@
             }
         }
 
+        final Context themedContext = getThemedContext();
+
         if (mode != null) {
             mActionMode = mode;
         } else {
@@ -959,19 +980,20 @@
                 if (mIsFloating) {
                     // Use the action bar theme.
                     final TypedValue outValue = new TypedValue();
-                    final Resources.Theme baseTheme = mContext.getTheme();
+                    final Resources.Theme baseTheme = themedContext.getTheme();
                     baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);
 
                     final Context actionBarContext;
                     if (outValue.resourceId != 0) {
-                        final Resources.Theme actionBarTheme = mContext.getResources().newTheme();
+                        final Resources.Theme actionBarTheme =
+                                themedContext.getResources().newTheme();
                         actionBarTheme.setTo(baseTheme);
                         actionBarTheme.applyStyle(outValue.resourceId, true);
 
-                        actionBarContext = new ContextThemeWrapper(mContext, 0);
+                        actionBarContext = new ContextThemeWrapper(themedContext, 0);
                         actionBarContext.getTheme().setTo(actionBarTheme);
                     } else {
-                        actionBarContext = mContext;
+                        actionBarContext = themedContext;
                     }
 
                     mActionModeView = new ActionBarContextView(actionBarContext);
@@ -1019,8 +1041,7 @@
                         }
                     };
                 } else {
-                    ViewStubCompat stub = (ViewStubCompat) mSubDecor
-                            .findViewById(R.id.action_mode_bar_stub);
+                    ViewStubCompat stub = mSubDecor.findViewById(R.id.action_mode_bar_stub);
                     if (stub != null) {
                         // Set the layout inflater so that it is inflated with the action bar's context
                         stub.setLayoutInflater(LayoutInflater.from(getActionBarThemedContext()));
@@ -1232,7 +1253,7 @@
     public View createView(View parent, final String name, @NonNull Context context,
             @NonNull AttributeSet attrs) {
         if (mAppCompatViewInflater == null) {
-            TypedArray a = mContext.obtainStyledAttributes(R.styleable.AppCompatTheme);
+            TypedArray a = getThemedContext().obtainStyledAttributes(R.styleable.AppCompatTheme);
             String viewInflaterClassName =
                     a.getString(R.styleable.AppCompatTheme_viewInflaterClass);
             if ((viewInflaterClassName == null)
@@ -1297,7 +1318,7 @@
 
     @Override
     public void installViewFactory() {
-        LayoutInflater layoutInflater = LayoutInflater.from(mContext);
+        LayoutInflater layoutInflater = LayoutInflater.from(getThemedContext());
         if (layoutInflater.getFactory() == null) {
             LayoutInflaterCompat.setFactory2(layoutInflater, this);
         } else {
@@ -1333,7 +1354,7 @@
         // Don't open an options panel on xlarge devices.
         // (The app should be using an action bar for menu items.)
         if (st.featureId == FEATURE_OPTIONS_PANEL) {
-            Configuration config = mContext.getResources().getConfiguration();
+            Configuration config = getThemedContext().getResources().getConfiguration();
             boolean isXLarge = (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK)
                     == Configuration.SCREENLAYOUT_SIZE_XLARGE;
             if (isXLarge) {
@@ -1348,7 +1369,8 @@
             return;
         }
 
-        final WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+        final WindowManager wm = (WindowManager) getThemedContext()
+                .getSystemService(Context.WINDOW_SERVICE);
         if (wm == null) {
             return;
         }
@@ -1429,7 +1451,7 @@
 
     private void reopenMenu(MenuBuilder menu, boolean toggleMenuMode) {
         if (mDecorContentParent != null && mDecorContentParent.canShowOverflowMenu()
-                && (!ViewConfiguration.get(mContext).hasPermanentMenuKey()
+                && (!ViewConfiguration.get(getThemedContext()).hasPermanentMenuKey()
                         || mDecorContentParent.isOverflowMenuShowPending())) {
 
             final Window.Callback cb = getWindowCallback();
@@ -1472,7 +1494,7 @@
     }
 
     private boolean initializePanelMenu(final PanelFeatureState st) {
-        Context context = mContext;
+        Context context = getThemedContext();
 
         // If we have an action bar, initialize the menu with the right theme.
         if ((st.featureId == FEATURE_OPTIONS_PANEL || st.featureId == FEATURE_SUPPORT_ACTION_BAR) &&
@@ -1664,7 +1686,8 @@
             return;
         }
 
-        final WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+        final WindowManager wm = (WindowManager) getThemedContext()
+                .getSystemService(Context.WINDOW_SERVICE);
         if (wm != null && st.isOpen && st.decorView != null) {
             wm.removeView(st.decorView);
 
@@ -1705,11 +1728,12 @@
             return false;
         }
 
+        final Context context = getThemedContext();
         boolean handled = false;
         final PanelFeatureState st = getPanelState(featureId, true);
         if (featureId == FEATURE_OPTIONS_PANEL && mDecorContentParent != null &&
                 mDecorContentParent.canShowOverflowMenu() &&
-                !ViewConfiguration.get(mContext).hasPermanentMenuKey()) {
+                !ViewConfiguration.get(context).hasPermanentMenuKey()) {
             if (!mDecorContentParent.isOverflowMenuShowing()) {
                 if (!mIsDestroyed && preparePanel(st, event)) {
                     handled = mDecorContentParent.showOverflowMenu();
@@ -1742,7 +1766,7 @@
         }
 
         if (handled) {
-            AudioManager audioManager = (AudioManager) mContext.getSystemService(
+            AudioManager audioManager = (AudioManager) context.getSystemService(
                     Context.AUDIO_SERVICE);
             if (audioManager != null) {
                 audioManager.playSoundEffect(AudioManager.FX_KEY_CLICK);
@@ -1902,8 +1926,9 @@
                         mlp.topMargin = insetTop;
 
                         if (mStatusGuard == null) {
-                            mStatusGuard = new View(mContext);
-                            mStatusGuard.setBackgroundColor(mContext.getResources()
+                            final Context context = getThemedContext();
+                            mStatusGuard = new View(context);
+                            mStatusGuard.setBackgroundColor(context.getResources()
                                     .getColor(R.color.abc_input_method_navigation_guard));
                             mSubDecor.addView(mStatusGuard, -1,
                                     new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
@@ -2014,6 +2039,18 @@
         }
 
         mApplyDayNightCalled = true;
+
+        if (applied) {
+            // If DayNight has been applied, we need to re-apply the theme for
+            // the changes to take effect. On API 23+, we need to force
+            // setTheme() since it will no-op if the theme ID is identical to the
+            // current theme ID. Instead, we set the theme twice.
+            if (Build.VERSION.SDK_INT >= 23) {
+                mContext.setTheme(0);
+            }
+            mContext.setTheme(mThemeResId);
+        }
+
         return applied;
     }
 
@@ -2071,6 +2108,15 @@
      * chosen {@code UI_MODE_NIGHT} value.
      */
     private boolean updateForNightMode(@ApplyableNightMode final int mode) {
+        // We still need to update the host context configuration for windowBackground, etc
+        boolean applied = updateContextConfigForNightMode(mode);
+        if (Build.VERSION.SDK_INT >= 17) {
+            applied = updateThemedContextForNightMode(mode) || applied;
+        }
+        return applied;
+    }
+
+    private boolean updateContextConfigForNightMode(@ApplyableNightMode final int mode) {
         final Resources res = mContext.getResources();
         final Configuration conf = res.getConfiguration();
         final int currentNightMode = conf.uiMode & Configuration.UI_MODE_NIGHT_MASK;
@@ -2080,29 +2126,35 @@
                 : Configuration.UI_MODE_NIGHT_NO;
 
         if (currentNightMode != newNightMode) {
-            if (shouldRecreateOnNightModeChange()) {
+            final boolean manifestHandlingUiMode = isActivityManifestHandlingUiMode();
+            final boolean shouldRecreateOnNightModeChange =
+                    mApplyDayNightCalled && mContext instanceof Activity && !manifestHandlingUiMode;
+
+            if (shouldRecreateOnNightModeChange) {
                 if (DEBUG) {
                     Log.d(TAG, "applyNightMode() | Night mode changed, recreating Activity");
                 }
                 // If we've already been created, we need to recreate the Activity for the
                 // mode to be applied
-                final Activity activity = (Activity) mContext;
-                activity.recreate();
+                ((Activity) mContext).recreate();
             } else {
                 if (DEBUG) {
                     Log.d(TAG, "applyNightMode() | Night mode changed, updating configuration");
                 }
                 final Configuration config = new Configuration(conf);
-                final DisplayMetrics metrics = res.getDisplayMetrics();
-
                 // Update the UI Mode to reflect the new night mode
                 config.uiMode = newNightMode | (config.uiMode & ~Configuration.UI_MODE_NIGHT_MASK);
-                res.updateConfiguration(config, metrics);
+                res.updateConfiguration(config, res.getDisplayMetrics());
 
                 // We may need to flush the Resources' drawable cache due to framework bugs.
-                if (!(Build.VERSION.SDK_INT >= 26)) {
+                if (Build.VERSION.SDK_INT < 26) {
                     ResourcesFlusher.flush(res);
                 }
+
+                // If the Activity is set to handle uiMode config changes, pass along the new config
+                if (manifestHandlingUiMode) {
+                    ((Activity) mContext).onConfigurationChanged(config);
+                }
             }
             return true;
         } else {
@@ -2113,9 +2165,75 @@
         return false;
     }
 
+    @RequiresApi(17)
+    private boolean updateThemedContextForNightMode(@ApplyableNightMode final int mode) {
+        int currentNightMode = Configuration.UI_MODE_NIGHT_UNDEFINED;
+        if (mThemedContext != null) {
+            final Resources res = mThemedContext.getResources();
+            final Configuration conf = res.getConfiguration();
+            currentNightMode = conf.uiMode & Configuration.UI_MODE_NIGHT_MASK;
+        }
+
+        final int newNightMode = (mode == MODE_NIGHT_YES)
+                ? Configuration.UI_MODE_NIGHT_YES
+                : Configuration.UI_MODE_NIGHT_NO;
+
+        if (currentNightMode != newNightMode) {
+            final boolean manifestHandlingUiMode = isActivityManifestHandlingUiMode();
+            final boolean shouldRecreateOnNightModeChange =
+                    mApplyDayNightCalled && mContext instanceof Activity && !manifestHandlingUiMode;
+
+            if (shouldRecreateOnNightModeChange) {
+                if (DEBUG) {
+                    Log.d(TAG, "applyNightMode() | Night mode changed, recreating Activity");
+                }
+                // If we've already been created, we need to recreate the Activity for the
+                // mode to be applied
+                ((Activity) mContext).recreate();
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "applyNightMode() | Night mode changed, updating configuration");
+                }
+                final Configuration config = new Configuration(
+                        mContext.getResources().getConfiguration());
+                // Update the UI Mode to reflect the new night mode
+                config.uiMode = newNightMode | (config.uiMode & ~Configuration.UI_MODE_NIGHT_MASK);
+
+                final Context inner = mContext.createConfigurationContext(config);
+                inner.setTheme(mThemeResId);
+
+                // This looks weird, but allows us to fake the context hierarchy through
+                // ContextWrapper. Lots of apps assume that a View's context contains the Activity
+                // so this allows us to fulfill that assumption. This also allows android:onClick
+                // to work
+                mThemedContext = new ContextWrapper(inner) {
+                    @Override
+                    public Context getBaseContext() {
+                        return mContext;
+                    }
+                };
+            }
+            return true;
+        } else {
+            if (DEBUG) {
+                Log.d(TAG, "applyNightMode() | Skipping. Night mode has not changed: " + mode);
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void onSetTheme(int themeResId) {
+        mThemeResId = themeResId;
+        if (mThemedContext != null) {
+            mThemedContext.setTheme(themeResId);
+        }
+    }
+
     private void ensureAutoNightModeManager() {
         if (mAutoNightModeManager == null) {
-            mAutoNightModeManager = new AutoNightModeManager(TwilightManager.getInstance(mContext));
+            final TwilightManager twilightManager = TwilightManager.getInstance(getThemedContext());
+            mAutoNightModeManager = new AutoNightModeManager(twilightManager);
         }
     }
 
@@ -2125,25 +2243,23 @@
         return mAutoNightModeManager;
     }
 
-    private boolean shouldRecreateOnNightModeChange() {
-        if (mApplyDayNightCalled && mContext instanceof Activity) {
-            // If we've already applyDayNight() (via setTheme), we need to check if the
-            // Activity has configChanges set to handle uiMode changes
+    private boolean isActivityManifestHandlingUiMode() {
+        if (!mActivityHandlesUiModeChecked && mContext instanceof Activity) {
             final PackageManager pm = mContext.getPackageManager();
             try {
                 final ActivityInfo info = pm.getActivityInfo(
                         new ComponentName(mContext, mContext.getClass()), 0);
-                // We should return true (to recreate) if configChanges does not want to
-                // handle uiMode
-                return (info.configChanges & ActivityInfo.CONFIG_UI_MODE) == 0;
+                mActivityHandlesUiMode = (info.configChanges & ActivityInfo.CONFIG_UI_MODE) != 0;
             } catch (PackageManager.NameNotFoundException e) {
                 // This shouldn't happen but let's not crash because of it, we'll just log and
-                // return true (since most apps will do that anyway)
+                // return false (since most apps won't be handling it)
                 Log.d(TAG, "Exception while getting ActivityInfo", e);
-                return true;
+                mActivityHandlesUiMode = false;
             }
         }
-        return false;
+        // Flip the checked flag so we don't check again
+        mActivityHandlesUiModeChecked = true;
+        return mActivityHandlesUiMode;
     }
 
     /**
@@ -2618,7 +2734,7 @@
                 android.view.ActionMode.Callback callback) {
             // Wrap the callback as a v7 ActionMode.Callback
             final SupportActionModeWrapper.CallbackWrapper callbackWrapper =
-                    new SupportActionModeWrapper.CallbackWrapper(mContext, callback);
+                    new SupportActionModeWrapper.CallbackWrapper(getThemedContext(), callback);
 
             // Try and start a support action mode using the wrapped callback
             final androidx.appcompat.view.ActionMode supportActionMode =
@@ -2735,7 +2851,7 @@
         @Override
         public Drawable getThemeUpIndicator() {
             final TintTypedArray a = TintTypedArray.obtainStyledAttributes(
-                    getActionBarThemedContext(), null, new int[]{ R.attr.homeAsUpIndicator });
+                    getActionBarThemedContext(), null, new int[]{R.attr.homeAsUpIndicator});
             final Drawable result = a.getDrawable(0);
             a.recycle();
             return result;
diff --git a/appcompat/src/main/java/androidx/appcompat/app/AppCompatDialog.java b/appcompat/src/main/java/androidx/appcompat/app/AppCompatDialog.java
index 5c93431..0c0605f 100644
--- a/appcompat/src/main/java/androidx/appcompat/app/AppCompatDialog.java
+++ b/appcompat/src/main/java/androidx/appcompat/app/AppCompatDialog.java
@@ -53,13 +53,18 @@
         this(context, 0);
     }
 
-    public AppCompatDialog(Context context, int theme) {
-        super(context, getThemeResId(context, theme));
+    public AppCompatDialog(Context context, int themeResId) {
+        this(context, getThemeResId(context, themeResId), false);
+    }
+
+    private AppCompatDialog(Context context, int themeResId, boolean unusedParam) {
+        super(context, themeResId);
 
         // This is a bit weird, but Dialog's are typically created and setup before being shown,
         // which means that we can't rely on onCreate() being called before a content view is set.
         // To workaround this, we call onCreate(null) in the ctor, and then again as usual in
         // onCreate().
+        getDelegate().onSetTheme(themeResId);
         getDelegate().onCreate(null);
 
         // Apply AppCompat's DayNight resources if needed
diff --git a/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
index c77a829..eacc696 100644
--- a/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
@@ -158,6 +158,7 @@
                 newApisTask,
                 jdiffConfiguration)
 
+        docsTasks.values.forEach { docs -> generateDiffsTask.dependsOn(docs) }
         setupDocsProject()
 
         return anchorTask
@@ -271,8 +272,8 @@
         val tasks = initializeApiChecksForProject(project,
                 aggregateOldApiTxtsTask, aggregateNewApiTxtsTask)
         registerJavaProjectForDocsTask(tasks.generateApi, compileJava)
-        setupDocsTasks(project, tasks)
-        anchorTask.dependsOn(tasks.checkApi)
+        setupApiVersioningInDocsTasks(extension, tasks)
+        addCheckApiTasksToGraph(tasks)
     }
 
     /**
@@ -306,23 +307,38 @@
                 val tasks = initializeApiChecksForProject(project, aggregateOldApiTxtsTask,
                         aggregateNewApiTxtsTask)
                 registerAndroidProjectForDocsTask(tasks.generateApi, variant)
-                setupDocsTasks(project, tasks)
-                anchorTask.dependsOn(tasks.checkApi)
+                setupApiVersioningInDocsTasks(extension, tasks)
+                addCheckApiTasksToGraph(tasks)
             }
         }
     }
 
-    private fun setupDocsTasks(project: Project, checkApiTasks: CheckApiTasks) {
-        docsTasks.values.forEach { docs ->
-            generateDiffsTask.dependsOn(docs)
+    private fun setupApiVersioningInDocsTasks(
+        extension: SupportLibraryExtension,
+        checkApiTasks: CheckApiTasks
+    ) {
+        rules.forEach { rules ->
+            val project = extension.project
+            val strategy = rules.resolve(extension)?.strategy
+            val version = if (strategy is Prebuilts) {
+                strategy.version
+            } else {
+                extension.project.version()
+            }
+            val docs = docsTasks[rules.name]!!
             // Track API change history.
             docs.addSinceFilesFrom(project.projectDir)
             // Associate current API surface with the Maven artifact.
-            val artifact = "${project.group}:${project.name}:${project.version}"
+            val artifact = "${project.group}:${project.name}:$version"
             docs.addArtifact(checkApiTasks.generateApi.apiFile!!.absolutePath, artifact)
             docs.dependsOn(checkApiTasks.generateApi)
         }
     }
+
+    private fun addCheckApiTasksToGraph(tasks: CheckApiTasks) {
+        docsTasks.values.forEach { docs -> docs.dependsOn(tasks.generateApi) }
+        anchorTask.dependsOn(tasks.checkApi)
+    }
 }
 
 /**
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
index 46e7e82..c68df07 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
@@ -71,7 +71,7 @@
     /**
      * Version code for WorkManager
      */
-    val WORKMANAGER = Version("1.0.0-alpha09")
+    val WORKMANAGER = Version("1.0.0-alpha10")
 
     /**
      * Version code for Jetifier
@@ -198,7 +198,7 @@
      */
     val FRAGMENT = Version("1.1.0-alpha01")
 
-    val FUTURES = Version("1.0.0-alpha01")
+    val FUTURES = Version("1.0.0-alpha02")
 
     val COLLECTION = Version("1.1.0-alpha01")
 
diff --git a/buildSrc/src/main/kotlin/androidx/build/checkapi/CheckApi.kt b/buildSrc/src/main/kotlin/androidx/build/checkapi/CheckApi.kt
index c56778c6..beee1ee 100644
--- a/buildSrc/src/main/kotlin/androidx/build/checkapi/CheckApi.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/checkapi/CheckApi.kt
@@ -52,7 +52,6 @@
         project.extensions.add("docsDir", File(project.rootProject.docsDir(), project.name))
     }
     val version = project.version()
-    val workingDir = project.projectDir
 
     val doclavaConfiguration = project.rootProject.configurations.getByName("doclava")
     val docletClasspath = doclavaConfiguration.resolve()
@@ -201,7 +200,8 @@
  * This is API file that checkApiRelease validates against
  * @return the API file
  */
-fun Project.getRequiredCompatibilityApiFile() = getLastReleasedApiFile(project.projectDir, project.version(), true, true)
+fun Project.getRequiredCompatibilityApiFile() =
+    getLastReleasedApiFile(project.projectDir, project.version(), true, true)
 
 private fun getApiFile(rootDir: File, refVersion: Version): File {
     return getApiFile(rootDir, refVersion, false)
diff --git a/car/core/api/current.txt b/car/core/api/current.txt
index 58cbcf4..dad67d2 100644
--- a/car/core/api/current.txt
+++ b/car/core/api/current.txt
@@ -179,16 +179,18 @@
     method public int getViewType();
     method public void onBind(androidx.car.widget.ActionListItem.ViewHolder);
     method protected void resolveDirtyState();
-    method public void setAction(java.lang.String, boolean, android.view.View.OnClickListener);
+    method public deprecated void setAction(java.lang.String, boolean, android.view.View.OnClickListener);
     method public void setActionBorderless(boolean);
-    method public void setActions(java.lang.String, boolean, android.view.View.OnClickListener, java.lang.String, boolean, android.view.View.OnClickListener);
+    method public deprecated void setActions(java.lang.String, boolean, android.view.View.OnClickListener, java.lang.String, boolean, android.view.View.OnClickListener);
     method public void setBody(java.lang.CharSequence);
     method public void setEnabled(boolean);
     method public void setOnClickListener(android.view.View.OnClickListener);
+    method public void setPrimaryAction(java.lang.String, boolean, android.view.View.OnClickListener);
     method public void setPrimaryActionEmptyIcon();
     method public void setPrimaryActionIcon(int, int);
     method public void setPrimaryActionIcon(android.graphics.drawable.Drawable, int);
     method public void setPrimaryActionNoIcon();
+    method public void setSecondaryAction(java.lang.String, boolean, android.view.View.OnClickListener);
     method public void setTitle(java.lang.CharSequence);
     field public static final int PRIMARY_ACTION_ICON_SIZE_LARGE = 2; // 0x2
     field public static final int PRIMARY_ACTION_ICON_SIZE_MEDIUM = 1; // 0x1
@@ -334,6 +336,7 @@
     method public int getPage(int);
     method public androidx.recyclerview.widget.RecyclerView getRecyclerView();
     method public int getRowsPerPage();
+    method public boolean getShowScrollBarThumb();
     method public void hideAlphaJump();
     method public boolean isAtEnd();
     method public boolean isAtStart();
@@ -360,6 +363,7 @@
     method public void setOnScrollListener(androidx.car.widget.PagedListView.OnScrollListener);
     method public void setScrollBarContainerWidth(int);
     method public void setScrollBarTopMargin(int);
+    method public void setShowScrollBarThumb(boolean);
     method public void setUpButtonIcon(android.graphics.drawable.Drawable);
     method public void snapToPosition(int);
     field public static final int DEFAULT_MAX_CLICKS = 6; // 0x6
@@ -400,6 +404,7 @@
     ctor public PagedScrollBarView(android.content.Context, android.util.AttributeSet);
     ctor public PagedScrollBarView(android.content.Context, android.util.AttributeSet, int);
     ctor public PagedScrollBarView(android.content.Context, android.util.AttributeSet, int, int);
+    method public boolean getShowScrollBarThumb();
     method public boolean isDownEnabled();
     method public boolean isDownPressed();
     method public boolean isUpPressed();
@@ -411,6 +416,7 @@
     method public void setPaginationListener(androidx.car.widget.PagedScrollBarView.PaginationListener);
     method public void setParameters(int, int, int, boolean);
     method public void setScrollbarThumbColor(int);
+    method public void setShowScrollBarThumb(boolean);
     method public void setUpButtonIcon(android.graphics.drawable.Drawable);
     method public void setUpEnabled(boolean);
   }
diff --git a/car/core/res-public/values/public_attrs.xml b/car/core/res-public/values/public_attrs.xml
index 47afc71..7ade86e 100644
--- a/car/core/res-public/values/public_attrs.xml
+++ b/car/core/res-public/values/public_attrs.xml
@@ -44,6 +44,7 @@
     <public type="attr" name="downButtonIcon" />
     <public type="attr" name="buttonTintColor" />
     <public type="attr" name="buttonRippleBackground" />
+    <public type="attr" name="showScrollBarThumb"/>
 
     <!-- ListItem -->
     <public type="attr" name="listItemBackgroundColor" />
diff --git a/car/core/res/layout/car_list_item_action_content.xml b/car/core/res/layout/car_list_item_action_content.xml
index 94c1f29..b7ded3e 100644
--- a/car/core/res/layout/car_list_item_action_content.xml
+++ b/car/core/res/layout/car_list_item_action_content.xml
@@ -22,6 +22,7 @@
     android:id="@+id/container"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:paddingEnd="@dimen/car_keyline_1"
     android:minHeight="@dimen/car_single_line_list_item_height"
     android:foreground="@drawable/car_card_ripple_background" >
 
@@ -107,7 +108,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         app:barrierDirection="start"
-        app:barrierAllowsGoneWidgets="false"
+        app:barrierAllowsGoneWidgets="true"
         app:constraint_referenced_ids="secondary_action_borderless,secondary_action" />
 
     <Button
@@ -150,14 +151,13 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         app:barrierDirection="start"
-        app:barrierAllowsGoneWidgets="false"
+        app:barrierAllowsGoneWidgets="true"
         app:constraint_referenced_ids="primary_action_borderless,primary_action" />
 
     <Button
         android:id="@+id/primary_action_borderless"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/car_keyline_1"
         android:ellipsize="end"
         android:maxLength="@integer/car_borderless_button_text_length_limit"
         android:maxLines="1"
@@ -169,7 +169,6 @@
         android:id="@+id/primary_action"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginEnd="@dimen/car_keyline_1"
         android:ellipsize="end"
         android:maxLength="@integer/car_borderless_button_text_length_limit"
         android:maxLines="1"
diff --git a/car/core/res/values-bn/strings.xml b/car/core/res/values-bn/strings.xml
new file mode 100644
index 0000000..3ad0ed9
--- /dev/null
+++ b/car/core/res/values-bn/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="444412252084688703">"মনোযোগ দিয়ে গাড়ি চালান"</string>
+    <string name="action_bar_expand_collapse_button" msgid="1874508980662961036">"সঙ্কোচন/প্রসারণের বোতাম"</string>
+    <string name="scroll_bar_page_up_button" msgid="465102831431294180">"উপরে স্ক্রল করুন"</string>
+    <string name="scroll_bar_page_down_button" msgid="635940284003824276">"নিচে স্ক্রল করুন"</string>
+</resources>
diff --git a/car/core/res/values-gu/strings.xml b/car/core/res/values-gu/strings.xml
new file mode 100644
index 0000000..580e752
--- /dev/null
+++ b/car/core/res/values-gu/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="444412252084688703">"રસ્તા પર ફોકસ કરો"</string>
+    <string name="action_bar_expand_collapse_button" msgid="1874508980662961036">"વિસ્તાર કરો/સંકુચિત કરો બટન"</string>
+    <string name="scroll_bar_page_up_button" msgid="465102831431294180">"ઉપર સ્ક્રોલ કરો"</string>
+    <string name="scroll_bar_page_down_button" msgid="635940284003824276">"નીચે સ્ક્રોલ કરો"</string>
+</resources>
diff --git a/car/core/res/values-hi/strings.xml b/car/core/res/values-hi/strings.xml
index 6b7cbfc..1158ed7 100644
--- a/car/core/res/values-hi/strings.xml
+++ b/car/core/res/values-hi/strings.xml
@@ -18,6 +18,6 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="444412252084688703">"सड़क पर ध्यान दें"</string>
     <string name="action_bar_expand_collapse_button" msgid="1874508980662961036">"बड़ा/छोटा करने वाला बटन"</string>
-    <string name="scroll_bar_page_up_button" msgid="465102831431294180">"ऊपर स्क्रॉल करें"</string>
-    <string name="scroll_bar_page_down_button" msgid="635940284003824276">"स्क्रोल करके नीचे जाएं"</string>
+    <string name="scroll_bar_page_up_button" msgid="465102831431294180">"ऊपर स्क्रोल करें"</string>
+    <string name="scroll_bar_page_down_button" msgid="635940284003824276">"नीचे स्क्रोल करें"</string>
 </resources>
diff --git a/car/core/res/values-ne/strings.xml b/car/core/res/values-ne/strings.xml
new file mode 100644
index 0000000..4dd830c
--- /dev/null
+++ b/car/core/res/values-ne/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="444412252084688703">"सडकमा ध्यान केन्द्रित गर्नु…"</string>
+    <string name="action_bar_expand_collapse_button" msgid="1874508980662961036">"विस्तृत/संक्षिप्त गर्ने बटन"</string>
+    <string name="scroll_bar_page_up_button" msgid="465102831431294180">"माथि स्क्रोल गर्नु…"</string>
+    <string name="scroll_bar_page_down_button" msgid="635940284003824276">"तल स्क्रोल गर्नुहोस्"</string>
+</resources>
diff --git a/car/core/res/values-pa/strings.xml b/car/core/res/values-pa/strings.xml
new file mode 100644
index 0000000..0922ce0
--- /dev/null
+++ b/car/core/res/values-pa/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="444412252084688703">"ਸੜਕ \'ਤੇ ਧਿਆਨ ਦਿਓ"</string>
+    <string name="action_bar_expand_collapse_button" msgid="1874508980662961036">"ਵਿਸਤਾਰ ਕਰੋ ਜਾਂ ਸਮੇਟੋ ਬਟਨ"</string>
+    <string name="scroll_bar_page_up_button" msgid="465102831431294180">"ਉੱਪਰ ਵੱਲ ਸਕ੍ਰੋਲ ਕਰੋ"</string>
+    <string name="scroll_bar_page_down_button" msgid="635940284003824276">"ਹੇਠਾਂ ਵੱਲ ਸਕ੍ਰੋਲ ਕਰੋ"</string>
+</resources>
diff --git a/car/core/res/values-ta/strings.xml b/car/core/res/values-ta/strings.xml
new file mode 100644
index 0000000..ccbab92
--- /dev/null
+++ b/car/core/res/values-ta/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="444412252084688703">"வாகனம் ஓட்டும்போது கவனம் தேவை"</string>
+    <string name="action_bar_expand_collapse_button" msgid="1874508980662961036">"விரிவாக்குவதற்கான/சுருக்குவதற்கான பட்டன்"</string>
+    <string name="scroll_bar_page_up_button" msgid="465102831431294180">"மேலே உருட்டும்"</string>
+    <string name="scroll_bar_page_down_button" msgid="635940284003824276">"கீழே உருட்டும்"</string>
+</resources>
diff --git a/car/core/res/values-te/strings.xml b/car/core/res/values-te/strings.xml
new file mode 100644
index 0000000..fbaf5db
--- /dev/null
+++ b/car/core/res/values-te/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="speed_bump_lockout_message" msgid="444412252084688703">"రహదారిపై దృష్టి ఉంచండి"</string>
+    <string name="action_bar_expand_collapse_button" msgid="1874508980662961036">"విస్తరింపజేయి/కుదించు బటన్"</string>
+    <string name="scroll_bar_page_up_button" msgid="465102831431294180">"పైకి స్క్రోల్ చేస్తుంది"</string>
+    <string name="scroll_bar_page_down_button" msgid="635940284003824276">"కిందికి స్క్రోల్ చేస్తుంది"</string>
+</resources>
diff --git a/car/core/res/values/attrs.xml b/car/core/res/values/attrs.xml
index 816f5d0..4f353ab 100644
--- a/car/core/res/values/attrs.xml
+++ b/car/core/res/values/attrs.xml
@@ -110,6 +110,8 @@
         <!-- The background for the buttons in the PagedListView. This background should provide
              the ripple. -->
         <attr name="buttonRippleBackground" format="reference" />
+        <!-- Whether to display the scrollthumb or not. Defaults to true. -->
+        <attr name="showScrollBarThumb" format="boolean" />
     </declare-styleable>
 
     <!-- The configuration for modifying the ListItem. These ListItems are only intended to be used
diff --git a/car/core/src/androidTest/java/androidx/car/widget/ActionListItemTest.java b/car/core/src/androidTest/java/androidx/car/widget/ActionListItemTest.java
index bad3b1c..06a752b 100644
--- a/car/core/src/androidTest/java/androidx/car/widget/ActionListItemTest.java
+++ b/car/core/src/androidTest/java/androidx/car/widget/ActionListItemTest.java
@@ -168,9 +168,9 @@
     }
 
     @Test
-    public void testSingleActionButtonVisibility_withDividers_Borderless() {
+    public void testPrimaryActionButtonVisibility_withDividers_Borderless() {
         ActionListItem item = new ActionListItem(mActivity);
-        item.setAction("text", /* showDivider= */ true, v -> { /* Do nothing. */ });
+        item.setPrimaryAction("text", /* showDivider= */ true, v -> { /* Do nothing. */ });
 
         List<ActionListItem> items = Arrays.asList(item);
         setupPagedListView(items);
@@ -184,9 +184,9 @@
     }
 
     @Test
-    public void testSingleActionButtonVisibility_withDividers() {
+    public void testPrimaryActionButtonVisibility_withDividers() {
         ActionListItem item = new ActionListItem(mActivity);
-        item.setAction("text", /* showDivider= */ true, v -> { /* Do nothing. */ });
+        item.setPrimaryAction("text", /* showDivider= */ true, v -> { /* Do nothing. */ });
         item.setActionBorderless(false);
 
         List<ActionListItem> items = Arrays.asList(item);
@@ -202,10 +202,44 @@
     }
 
     @Test
+    public void testSecondaryActionButtonVisibility_withDividers_Borderless() {
+        ActionListItem item = new ActionListItem(mActivity);
+        item.setSecondaryAction("text", /* showDivider= */ true, v -> { /* Do nothing. */ });
+
+        List<ActionListItem> items = Arrays.asList(item);
+        setupPagedListView(items);
+
+        ActionListItem.ViewHolder viewHolder = getViewHolderAtPosition(0);
+        assertThat(viewHolder.getBorderlessSecondaryAction().getVisibility(),
+                is(equalTo(View.VISIBLE)));
+        assertThat(viewHolder.getBorderedSecondaryAction().getVisibility(), is(equalTo(View.GONE)));
+        assertThat(viewHolder.getSecondaryAction().getVisibility(), is(equalTo(View.VISIBLE)));
+        assertThat(viewHolder.getSecondaryAction().getVisibility(), is(equalTo(View.VISIBLE)));
+    }
+
+    @Test
+    public void testSecondaryActionButtonVisibility_withDividers() {
+        ActionListItem item = new ActionListItem(mActivity);
+        item.setSecondaryAction("text", /* showDivider= */ true, v -> { /* Do nothing. */ });
+        item.setActionBorderless(false);
+
+        List<ActionListItem> items = Arrays.asList(item);
+        setupPagedListView(items);
+
+        ActionListItem.ViewHolder viewHolder = getViewHolderAtPosition(0);
+        assertThat(viewHolder.getBorderlessSecondaryAction().getVisibility(),
+                is(equalTo(View.GONE)));
+        assertThat(viewHolder.getBorderedSecondaryAction().getVisibility(),
+                is(equalTo(View.VISIBLE)));
+        assertThat(viewHolder.getSecondaryAction().getVisibility(), is(equalTo(View.VISIBLE)));
+        assertThat(viewHolder.getSecondaryAction().getVisibility(), is(equalTo(View.VISIBLE)));
+    }
+
+    @Test
     public void testTwoActionButtonsVisibility_withDividers_Borderless() {
         ActionListItem item = new ActionListItem(mActivity);
-        item.setActions("text", /* showDivider= */ true, v -> { /* Do nothing. */ },
-                "text", /* showDivider= */ true, v -> { /* Do nothing. */ });
+        item.setPrimaryAction("text", /* showDivider= */ true, v -> { /* Do nothing. */ });
+        item.setSecondaryAction("text", /* showDivider= */ true, v -> { /* Do nothing. */ });
 
         List<ActionListItem> items = Arrays.asList(item);
         setupPagedListView(items);
@@ -228,8 +262,8 @@
     @Test
     public void testTwoActionButtonsVisibility_withDividers() {
         ActionListItem item = new ActionListItem(mActivity);
-        item.setActions("text", /* showDivider= */ true, v -> { /* Do nothing. */ },
-                "text", /* showDivider= */ true, v -> { /* Do nothing. */ });
+        item.setPrimaryAction("text", /* showDivider= */ true, v -> { /* Do nothing. */ });
+        item.setSecondaryAction("text", /* showDivider= */ true, v -> { /* Do nothing. */ });
         item.setActionBorderless(false);
 
         List<ActionListItem> items = Arrays.asList(item);
@@ -254,7 +288,7 @@
     @Test
     public void testSingleActionButtonVisibility_noDividers_Borderless() {
         ActionListItem item = new ActionListItem(mActivity);
-        item.setAction("text", /* showDivider= */ false, v -> { /* Do nothing. */ });
+        item.setPrimaryAction("text", /* showDivider= */ false, v -> { /* Do nothing. */ });
 
         List<ActionListItem> items = Arrays.asList(item);
         setupPagedListView(items);
@@ -271,7 +305,7 @@
     @Test
     public void testSingleActionButtonVisibility_noDividers() {
         ActionListItem item = new ActionListItem(mActivity);
-        item.setAction("text", /* showDivider= */ false, v -> { /* Do nothing. */ });
+        item.setPrimaryAction("text", /* showDivider= */ false, v -> { /* Do nothing. */ });
         item.setActionBorderless(false);
 
         List<ActionListItem> items = Arrays.asList(item);
@@ -289,8 +323,8 @@
     @Test
     public void testTwoActionButtonsVisibility_noDividers_Borderless() {
         ActionListItem item = new ActionListItem(mActivity);
-        item.setActions("text", /* showDivider= */ false, v -> { /* Do nothing. */ },
-                "text", /* showDivider= */ false, v -> { /* Do nothing. */ });
+        item.setPrimaryAction("text", /* showDivider= */ false, v -> { /* Do nothing. */ });
+        item.setSecondaryAction("text", /* showDivider= */ false, v -> { /* Do nothing. */ });
 
         List<ActionListItem> items = Arrays.asList(item);
         setupPagedListView(items);
@@ -313,8 +347,8 @@
     @Test
     public void testTwoActionButtonsVisibility_noDividers() {
         ActionListItem item = new ActionListItem(mActivity);
-        item.setActions("text", /* showDivider= */ false, v -> { /* Do nothing. */ },
-                "text", /* showDivider= */ false, v -> { /* Do nothing. */ });
+        item.setPrimaryAction("text", /* showDivider= */ false, v -> { /* Do nothing. */ });
+        item.setSecondaryAction("text", /* showDivider= */ false, v -> { /* Do nothing. */ });
         item.setActionBorderless(false);
 
         List<ActionListItem> items = Arrays.asList(item);
@@ -339,7 +373,7 @@
     public void testClickInterceptor_ClickableIfOneActionSet() {
         ActionListItem item = new ActionListItem(mActivity);
         item.setEnabled(true);
-        item.setAction("text", /* showDivider= */ true, v -> { });
+        item.setPrimaryAction("text", /* showDivider= */ true, v -> { });
 
         setupPagedListView(Arrays.asList(item));
 
@@ -351,7 +385,7 @@
     public void testClickInterceptor_VisibleIfOneActionSet() {
         ActionListItem item = new ActionListItem(mActivity);
         item.setEnabled(true);
-        item.setAction("text", /* showDivider= */ true, v -> { });
+        item.setPrimaryAction("text", /* showDivider= */ true, v -> { });
 
         setupPagedListView(Arrays.asList(item));
 
@@ -363,8 +397,8 @@
     public void testClickInterceptor_ClickableIfTwoActionsSet() {
         ActionListItem item = new ActionListItem(mActivity);
         item.setEnabled(true);
-        item.setActions("text", /* showDivider= */ true, v -> { },
-                "text", /* showDivider= */ true, v -> { });
+        item.setPrimaryAction("text", /* showDivider= */ true, v -> { });
+        item.setSecondaryAction("text", /* showDivider= */ true, v -> { });
 
         setupPagedListView(Arrays.asList(item));
 
@@ -376,8 +410,8 @@
     public void testClickInterceptor_VisibleIfTwoActionsSet() {
         ActionListItem item = new ActionListItem(mActivity);
         item.setEnabled(true);
-        item.setActions("text", /* showDivider= */ true, v -> { },
-                "text", /* showDivider= */ true, v -> { });
+        item.setPrimaryAction("text", /* showDivider= */ true, v -> { });
+        item.setSecondaryAction("text", /* showDivider= */ true, v -> { });
 
         setupPagedListView(Arrays.asList(item));
 
@@ -596,7 +630,7 @@
         final boolean[] clicked = {false};
 
         ActionListItem item0 = new ActionListItem(mActivity);
-        item0.setAction("action", /* showDivider= */ true, v -> clicked[0] = true);
+        item0.setPrimaryAction("action", /* showDivider= */ true, v -> clicked[0] = true);
 
         List<ActionListItem> items = Arrays.asList(item0);
         setupPagedListView(items);
@@ -611,7 +645,7 @@
         final boolean[] clicked = {false};
 
         ActionListItem item0 = new ActionListItem(mActivity);
-        item0.setAction("action", /* showDivider= */ true, v -> clicked[0] = true);
+        item0.setPrimaryAction("action", /* showDivider= */ true, v -> clicked[0] = true);
         item0.setActionBorderless(false);
 
         List<ActionListItem> items = Arrays.asList(item0);
@@ -627,8 +661,8 @@
         final boolean[] clicked = {false, false};
 
         ActionListItem item0 = new ActionListItem(mActivity);
-        item0.setActions("action 1", /* showDivider= */ true, v -> clicked[0] = true,
-                "action 2", /* showDivider= */ true, v -> clicked[1] = true);
+        item0.setPrimaryAction("action 1", /* showDivider= */ true, v -> clicked[0] = true);
+        item0.setSecondaryAction("action 2", /* showDivider= */ true, v -> clicked[1] = true);
 
         List<ActionListItem> items = Arrays.asList(item0);
         setupPagedListView(items);
@@ -648,8 +682,8 @@
         final boolean[] clicked = {false, false};
 
         ActionListItem item0 = new ActionListItem(mActivity);
-        item0.setActions("action 1", /* showDivider= */ true, v -> clicked[0] = true,
-                "action 2", /* showDivider= */ true, v -> clicked[1] = true);
+        item0.setPrimaryAction("action 1", /* showDivider= */ true, v -> clicked[0] = true);
+        item0.setSecondaryAction("action 2", /* showDivider= */ true, v -> clicked[1] = true);
         item0.setActionBorderless(false);
 
         List<ActionListItem> items = Arrays.asList(item0);
@@ -822,7 +856,7 @@
         item.setOnClickListener(v -> { });
         item.setTitle("title");
         item.setBody("body");
-        item.setAction("action", false, v -> { });
+        item.setPrimaryAction("action", false, v -> { });
         item.setEnabled(false);
 
         setupPagedListView(Arrays.asList(item));
diff --git a/car/core/src/androidTest/java/androidx/car/widget/PagedListViewTest.java b/car/core/src/androidTest/java/androidx/car/widget/PagedListViewTest.java
index a16ade9..88027d8 100644
--- a/car/core/src/androidTest/java/androidx/car/widget/PagedListViewTest.java
+++ b/car/core/src/androidTest/java/androidx/car/widget/PagedListViewTest.java
@@ -349,6 +349,21 @@
     }
 
     @Test
+    public void testScrollBarThumbShowByDefault() {
+        // Just need enough items to ensure the scroll bar is showing.
+        setUpPagedListView(ITEMS_PER_PAGE * 10);
+        onView(withId(R.id.scrollbar_thumb)).check(matches(isDisplayed()));
+    }
+
+    @Test
+    public void testScrollBarThumbIsHidden() {
+        // Just need enough items to ensure the scroll bar is showing.
+        setUpPagedListView(ITEMS_PER_PAGE * 10);
+        mPagedListView.setShowScrollBarThumb(false);
+        onView(withId(R.id.scrollbar_thumb)).check(matches(not(isDisplayed())));
+    }
+
+    @Test
     public void testSetGutterNone() {
         // Just need enough items to ensure the scroll bar is showing.
         setUpPagedListView(ITEMS_PER_PAGE * 10);
diff --git a/car/core/src/main/java/androidx/car/widget/ActionListItem.java b/car/core/src/main/java/androidx/car/widget/ActionListItem.java
index 9105ea4..58cbab5 100644
--- a/car/core/src/main/java/androidx/car/widget/ActionListItem.java
+++ b/car/core/src/main/java/androidx/car/widget/ActionListItem.java
@@ -100,13 +100,6 @@
     private static final int PRIMARY_ACTION_TYPE_EMPTY_ICON = 1;
     private static final int PRIMARY_ACTION_TYPE_ICON = 2;
 
-    @Retention(SOURCE)
-    @IntDef({ SUPPLEMENTAL_ACTION_ONE_ACTION, SUPPLEMENTAL_ACTION_TWO_ACTIONS })
-    private @interface SupplementalActionType {}
-
-    private static final int SUPPLEMENTAL_ACTION_ONE_ACTION = 0;
-    private static final int SUPPLEMENTAL_ACTION_TWO_ACTIONS = 1;
-
     @PrimaryActionType private int mPrimaryActionType = PRIMARY_ACTION_TYPE_NO_ICON;
     private Drawable mPrimaryActionIconDrawable;
     @PrimaryActionIconSize private int mPrimaryActionIconSize = PRIMARY_ACTION_ICON_SIZE_SMALL;
@@ -118,8 +111,6 @@
     private CharSequence mTitle;
     private CharSequence mBody;
 
-    @SupplementalActionType private int mSupplementalActionType = SUPPLEMENTAL_ACTION_ONE_ACTION;
-
     @Dimension
     private final int mSupplementalGuidelineBegin;
 
@@ -157,21 +148,22 @@
     }
 
     /**
-     * Hides all views in {@link ActionListItem.ViewHolder} then applies ViewBinders to
+     * Resets all views in {@link ActionListItem.ViewHolder} then applies ViewBinders to
      * adjust view layout params.
      */
     @Override
     public void onBind(ActionListItem.ViewHolder viewHolder) {
-        hideSubViews(viewHolder);
+        for (View v : viewHolder.getWidgetViews()) {
+            v.setEnabled(mIsEnabled);
+            v.setVisibility(View.GONE);
+        }
+
+        // ActionListItem supports clicking on the item so we also update the entire itemView.
+        viewHolder.itemView.setEnabled(mIsEnabled);
+
         for (ViewBinder<ViewHolder> binder : mBinders) {
             binder.bind(viewHolder);
         }
-
-        for (View v : viewHolder.getWidgetViews()) {
-            v.setEnabled(mIsEnabled);
-        }
-        // ActionListItem supports clicking on the item so we also update the entire itemView.
-        viewHolder.itemView.setEnabled(mIsEnabled);
     }
 
     @Override
@@ -424,50 +416,50 @@
      * Sets up view(s) for supplemental action.
      */
     private void setSupplementalActions() {
-        switch (mSupplementalActionType) {
-            case SUPPLEMENTAL_ACTION_TWO_ACTIONS:
-                mBinders.add(vh -> {
-                    vh.setActionBorderless(mIsActionBorderless);
+        boolean hasPrimaryAction = !TextUtils.isEmpty(mPrimaryActionText);
+        boolean hasSecondaryAction = !TextUtils.isEmpty(mSecondaryActionText);
 
-                    Button secondaryAction = vh.getSecondaryAction();
-
-                    secondaryAction.setVisibility(View.VISIBLE);
-                    if (mShowSecondaryActionDivider) {
-                        vh.getSecondaryActionDivider().setVisibility(View.VISIBLE);
-                    }
-
-                    secondaryAction.setText(mSecondaryActionText);
-                    secondaryAction.setOnClickListener(mSecondaryActionOnClickListener);
-
-                    Button primaryAction = vh.getPrimaryAction();
-
-                    primaryAction.setVisibility(View.VISIBLE);
-                    if (mShowPrimaryActionDivider) {
-                        vh.getPrimaryActionDivider().setVisibility(View.VISIBLE);
-                    }
-
-                    primaryAction.setText(mPrimaryActionText);
-                    primaryAction.setOnClickListener(mPrimaryActionOnClickListener);
-                });
-                break;
-            case SUPPLEMENTAL_ACTION_ONE_ACTION:
-                mBinders.add(vh -> {
-                    vh.setActionBorderless(mIsActionBorderless);
-
-                    Button primaryAction = vh.getPrimaryAction();
-
-                    primaryAction.setVisibility(View.VISIBLE);
-                    if (mShowPrimaryActionDivider) {
-                        vh.getPrimaryActionDivider().setVisibility(View.VISIBLE);
-                    }
-
-                    primaryAction.setText(mPrimaryActionText);
-                    primaryAction.setOnClickListener(mPrimaryActionOnClickListener);
-                });
-                break;
-            default:
-                throw new IllegalStateException("Unknown supplemental action type.");
+        if (!hasPrimaryAction && !hasSecondaryAction) {
+            return;
         }
+
+        mBinders.add(vh -> {
+            vh.setActionBorderless(mIsActionBorderless);
+
+            if (hasSecondaryAction) {
+                Button secondaryAction = vh.getSecondaryAction();
+
+                secondaryAction.setVisibility(View.VISIBLE);
+                if (mShowSecondaryActionDivider) {
+                    vh.getSecondaryActionDivider().setVisibility(View.VISIBLE);
+                }
+
+                secondaryAction.setText(mSecondaryActionText);
+                secondaryAction.setOnClickListener(mSecondaryActionOnClickListener);
+
+                // Add spacing between the buttons if there is a primary action.
+                int endMargin = hasPrimaryAction
+                        ? mContext.getResources().getDimensionPixelSize(R.dimen.car_padding_4)
+                        : 0;
+
+                ViewGroup.MarginLayoutParams layoutParams =
+                        (ViewGroup.MarginLayoutParams) secondaryAction.getLayoutParams();
+                layoutParams.setMarginEnd(endMargin);
+                secondaryAction.requestLayout();
+            }
+
+            if (hasPrimaryAction) {
+                Button primaryAction = vh.getPrimaryAction();
+
+                primaryAction.setVisibility(View.VISIBLE);
+                if (mShowPrimaryActionDivider) {
+                    vh.getPrimaryActionDivider().setVisibility(View.VISIBLE);
+                }
+
+                primaryAction.setText(mPrimaryActionText);
+                primaryAction.setOnClickListener(mPrimaryActionOnClickListener);
+            }
+        });
     }
 
     /**
@@ -555,22 +547,14 @@
      * @param showDivider whether to display a vertical bar that separates {@code Text} and
      *                    {@code Action Button}.
      * @param listener the callback that will run when action button is clicked.
+     * @deprecated Use {@link #setPrimaryAction(String, boolean, View.OnClickListener)} or
+     * {@link #setSecondaryAction(String, boolean, View.OnClickListener)} instead to individually
+     * set the actions.
      */
+    @Deprecated
     public void setAction(@NonNull String text, boolean showDivider,
             @NonNull View.OnClickListener listener) {
-        if (TextUtils.isEmpty(text)) {
-            throw new IllegalArgumentException("Action text cannot be empty.");
-        }
-        if (listener == null) {
-            throw new IllegalArgumentException("Action OnClickListener cannot be null.");
-        }
-        mSupplementalActionType = SUPPLEMENTAL_ACTION_ONE_ACTION;
-
-        mPrimaryActionText = text;
-        mPrimaryActionOnClickListener = listener;
-        mShowPrimaryActionDivider = showDivider;
-
-        markDirty();
+        setPrimaryAction(text, showDivider, listener);
     }
 
     /**
@@ -585,22 +569,70 @@
      *                                   action.
      * @param secondaryActionOnClickListener The listener to be invoked when the secondary action is
      *                                       triggered.
+     * @deprecated Use {@link #setPrimaryAction(String, boolean, View.OnClickListener)} and
+     * {@link #setSecondaryAction(String, boolean, View.OnClickListener)} to set both actions.
      */
+    @Deprecated
     public void setActions(@NonNull String primaryActionText, boolean showPrimaryActionDivider,
             @NonNull View.OnClickListener primaryActionOnClickListener,
             @NonNull String secondaryActionText, boolean showSecondaryActionDivider,
             @NonNull View.OnClickListener secondaryActionOnClickListener) {
-        if (TextUtils.isEmpty(primaryActionText) || TextUtils.isEmpty(secondaryActionText)) {
+        setPrimaryAction(primaryActionText, showPrimaryActionDivider, primaryActionOnClickListener);
+        setSecondaryAction(secondaryActionText, showSecondaryActionDivider,
+                secondaryActionOnClickListener);
+    }
+
+    /**
+     * Sets the primary action of this {@code ListItem}.
+     *
+     * @param primaryActionText Action text to display.
+     * @param showPrimaryActionDivider Whether or not to display a vertical bar before the primary
+     *                                 action.
+     * @param primaryActionOnClickListener The callback that will run when the action is clicked.
+     *
+     * @throws IllegalArgumentException If {@code primaryActionText} is {@code null} or empty.
+     * @throws IllegalArgumentException If {@code primaryActionOnClickListener} is {@code null}.
+     */
+    public void setPrimaryAction(@NonNull String primaryActionText,
+            boolean showPrimaryActionDivider,
+            @NonNull View.OnClickListener primaryActionOnClickListener) {
+        if (TextUtils.isEmpty(primaryActionText)) {
             throw new IllegalArgumentException("Action text cannot be empty.");
         }
-        if (primaryActionOnClickListener == null || secondaryActionOnClickListener == null) {
+        if (primaryActionOnClickListener == null) {
             throw new IllegalArgumentException("Action OnClickListener cannot be null.");
         }
-        mSupplementalActionType = SUPPLEMENTAL_ACTION_TWO_ACTIONS;
 
         mPrimaryActionText = primaryActionText;
         mPrimaryActionOnClickListener = primaryActionOnClickListener;
         mShowPrimaryActionDivider = showPrimaryActionDivider;
+
+        markDirty();
+    }
+
+    /**
+     * Sets the secondary action of this {@code ListItem}.
+     *
+     * <p>The secondary action will appear before the primary action if both are set.
+     *
+     * @param secondaryActionText Action text to display.
+     * @param showSecondaryActionDivider Whether or not to display a vertical bar before the
+     *                                   secondary action.
+     * @param secondaryActionOnClickListener The callback that will run when the action is clicked.
+     *
+     * @throws IllegalArgumentException If {@code secondaryActionText} is {@code null} or empty.
+     * @throws IllegalArgumentException If {@code secondaryActionOnClickListener} is {@code null}.
+     */
+    public void setSecondaryAction(@NonNull String secondaryActionText,
+            boolean showSecondaryActionDivider,
+            @NonNull View.OnClickListener secondaryActionOnClickListener) {
+        if (TextUtils.isEmpty(secondaryActionText)) {
+            throw new IllegalArgumentException("Action text cannot be empty.");
+        }
+        if (secondaryActionOnClickListener == null) {
+            throw new IllegalArgumentException("Action OnClickListener cannot be null.");
+        }
+
         mSecondaryActionText = secondaryActionText;
         mSecondaryActionOnClickListener = secondaryActionOnClickListener;
         mShowSecondaryActionDivider = showSecondaryActionDivider;
@@ -620,12 +652,6 @@
         mIsActionBorderless = isActionBorderless;
     }
 
-    private void hideSubViews(ViewHolder vh) {
-        for (View v : vh.getWidgetViews()) {
-            v.setVisibility(View.GONE);
-        }
-    }
-
     /**
      * Holds the children views of {@link ActionListItem}.
      */
diff --git a/car/core/src/main/java/androidx/car/widget/PagedListView.java b/car/core/src/main/java/androidx/car/widget/PagedListView.java
index 04cafda..4cf9ab43 100644
--- a/car/core/src/main/java/androidx/car/widget/PagedListView.java
+++ b/car/core/src/main/java/androidx/car/widget/PagedListView.java
@@ -464,6 +464,22 @@
     }
 
     /**
+     * Set the visibility of scroll bar thumb in the scroll bar, the default visibility is true.
+     *
+     * @param show Whether to show the scrollbar thumb or not.
+     */
+    public void setShowScrollBarThumb(boolean show) {
+        mScrollBarView.setShowScrollBarThumb(show);
+    }
+
+    /**
+     * Returns {@code true} if the scroll bar thumb is visible
+     */
+    public boolean getShowScrollBarThumb() {
+        return mScrollBarView.getShowScrollBarThumb();
+    }
+
+    /**
      * Sets an offset above the first item in the {@code PagedListView}. This offset is scrollable
      * with the contents of the list.
      *
diff --git a/car/core/src/main/java/androidx/car/widget/PagedScrollBarView.java b/car/core/src/main/java/androidx/car/widget/PagedScrollBarView.java
index ec4d48a..60c8275 100644
--- a/car/core/src/main/java/androidx/car/widget/PagedScrollBarView.java
+++ b/car/core/src/main/java/androidx/car/widget/PagedScrollBarView.java
@@ -70,6 +70,7 @@
     private final int mSeparatingMargin;
     private final int mScrollBarThumbWidth;
 
+    private boolean mShowScrollBarThumb;
     /** The amount of space that the scroll thumb is allowed to roam over. */
     private int mScrollThumbTrackHeight;
 
@@ -109,12 +110,13 @@
         mDownButton.setOnClickListener(mDownButtonClickListener);
         mAlphaJumpButton = findViewById(R.id.alpha_jump);
         mAlphaJumpButton.setOnClickListener(mAlphaJumpButtonClickListener);
-
         mScrollThumb = findViewById(R.id.scrollbar_thumb);
 
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PagedScrollBarView,
                 defStyleAttrs, defStyleRes);
 
+        mShowScrollBarThumb = a.getBoolean(R.styleable.PagedScrollBarView_showScrollBarThumb, true);
+        setShowScrollBarThumb(mShowScrollBarThumb);
         Drawable upButtonIcon = a.getDrawable(R.styleable.PagedScrollBarView_upButtonIcon);
         if (upButtonIcon != null) {
             setUpButtonIcon(upButtonIcon);
@@ -179,6 +181,20 @@
         mAlphaJumpButton.setVisibility(show ? View.VISIBLE : View.GONE);
     }
 
+    /** Returns {@code true} if the scroll bar thumb is visible */
+    public boolean getShowScrollBarThumb() {
+        return mShowScrollBarThumb;
+    }
+    /**
+     * Sets whether or not the scroll bar thumb is visible, the default value is true.
+     *
+     * @param show {@code true} if the scroll bar thumb is visible.
+     */
+    public void setShowScrollBarThumb(boolean show) {
+        mShowScrollBarThumb = show;
+        mScrollThumb.setVisibility(mShowScrollBarThumb ? View.VISIBLE : View.GONE);
+    }
+
     /**
      * Sets the range, offset and extent of the scroll bar. The range represents the size of a
      * container for the scrollbar thumb; offset is the distance from the start of the container
diff --git a/core/ktx/src/androidTest/java/androidx/core/os/HandlerTest.kt b/core/ktx/src/androidTest/java/androidx/core/os/HandlerTest.kt
index 3bc4389..a475418 100644
--- a/core/ktx/src/androidTest/java/androidx/core/os/HandlerTest.kt
+++ b/core/ktx/src/androidTest/java/androidx/core/os/HandlerTest.kt
@@ -18,10 +18,16 @@
 
 import android.os.Handler
 import android.os.HandlerThread
+import android.os.Looper
 import android.os.SystemClock
+import android.os.TestLooperManager
+import androidx.annotation.RequiresApi
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.SdkSuppress
 import androidx.test.filters.SmallTest
 import org.junit.After
 import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
@@ -31,13 +37,16 @@
 import java.util.concurrent.TimeUnit.SECONDS
 
 @SmallTest
+@SdkSuppress(minSdkVersion = 26)
 class HandlerTest {
     private val handlerThread = HandlerThread("handler-test")
+    private lateinit var looper: Looper
     private lateinit var handler: Handler
 
     @Before fun before() {
         handlerThread.start()
-        handler = Handler(handlerThread.looper)
+        looper = handlerThread.looper
+        handler = Handler(looper)
     }
 
     @After fun after() {
@@ -55,14 +64,14 @@
     }
 
     @Test fun postDelayedLambdaMillisRemoved() {
-        var called = 0
-        val runnable = handler.postDelayed(10) {
-            called++
-        }
-        handler.removeCallbacks(runnable)
+        looper.manage { manager ->
+            val runnable = handler.postDelayed(1000) {
+                throw AssertionError()
+            }
+            handler.removeCallbacks(runnable)
 
-        handler.await(20, MILLISECONDS)
-        assertEquals(0, called)
+            assertFalse(manager.hasMessages(handler))
+        }
     }
 
     @Test fun postAtTimeLambda() {
@@ -76,14 +85,14 @@
     }
 
     @Test fun postAtTimeLambdaRemoved() {
-        var called = 0
-        val runnable = handler.postAtTime(SystemClock.uptimeMillis() + 10) {
-            called++
-        }
-        handler.removeCallbacks(runnable)
+        looper.manage { manager ->
+            val runnable = handler.postAtTime(SystemClock.uptimeMillis() + 1000) {
+                throw AssertionError()
+            }
+            handler.removeCallbacks(runnable)
 
-        handler.await(20, MILLISECONDS)
-        assertEquals(0, called)
+            assertFalse(manager.hasMessages(handler))
+        }
     }
 
     @Test fun postAtTimeLambdaWithTokenRuns() {
@@ -101,15 +110,15 @@
         // This test uses the token to cancel the runnable as it's the only way we have to verify
         // that the Runnable was actually posted with the token.
 
-        val token = Any()
-        var called = 0
-        handler.postAtTime(SystemClock.uptimeMillis() + 10, token) {
-            called++
-        }
-        handler.removeCallbacksAndMessages(token)
+        looper.manage { manager ->
+            val token = Any()
+            handler.postAtTime(SystemClock.uptimeMillis() + 1000, token) {
+                throw AssertionError()
+            }
+            handler.removeCallbacksAndMessages(token)
 
-        handler.await(20, MILLISECONDS)
-        assertEquals(0, called)
+            assertFalse(manager.hasMessages(handler))
+        }
     }
 
     private fun Handler.await(amount: Long, unit: TimeUnit) {
@@ -120,4 +129,18 @@
         val wait = unit.toMillis(amount) + SECONDS.toMillis(1)
         assertTrue(latch.await(wait, MILLISECONDS))
     }
+
+    @RequiresApi(26)
+    private inline fun Looper.manage(block: (TestLooperManager) -> Unit) {
+        val instrumentation = InstrumentationRegistry.getInstrumentation()
+        val looperManager = instrumentation.acquireLooperManager(this)
+        try {
+            block(looperManager)
+        } finally {
+            looperManager.release()
+        }
+    }
+
+    @RequiresApi(26)
+    private fun TestLooperManager.hasMessages(handler: Handler) = hasMessages(handler, null, null)
 }
diff --git a/core/ktx/src/main/java/androidx/core/content/res/TypedArray.kt b/core/ktx/src/main/java/androidx/core/content/res/TypedArray.kt
index a4f6fef..5c3d1a0 100644
--- a/core/ktx/src/main/java/androidx/core/content/res/TypedArray.kt
+++ b/core/ktx/src/main/java/androidx/core/content/res/TypedArray.kt
@@ -118,7 +118,7 @@
  */
 fun TypedArray.getDrawableOrThrow(@StyleableRes index: Int): Drawable {
     checkAttribute(index)
-    return getDrawable(index)
+    return getDrawable(index)!!
 }
 
 /**
@@ -143,7 +143,7 @@
 @RequiresApi(26)
 fun TypedArray.getFontOrThrow(@StyleableRes index: Int): Typeface {
     checkAttribute(index)
-    return getFont(index)
+    return getFont(index)!!
 }
 
 /**
diff --git a/core/ktx/src/main/java/androidx/core/os/Bundle.kt b/core/ktx/src/main/java/androidx/core/os/Bundle.kt
index 53da45d..aa1f15d 100644
--- a/core/ktx/src/main/java/androidx/core/os/Bundle.kt
+++ b/core/ktx/src/main/java/androidx/core/os/Bundle.kt
@@ -61,7 +61,7 @@
 
             // Reference arrays
             is Array<*> -> {
-                val componentType = value::class.java.componentType
+                val componentType = value::class.java.componentType!!
                 @Suppress("UNCHECKED_CAST") // Checked by reflection.
                 when {
                     Parcelable::class.java.isAssignableFrom(componentType) -> {
diff --git a/core/ktx/src/main/java/androidx/core/os/PersistableBundle.kt b/core/ktx/src/main/java/androidx/core/os/PersistableBundle.kt
index 261e72b..720c6be 100644
--- a/core/ktx/src/main/java/androidx/core/os/PersistableBundle.kt
+++ b/core/ktx/src/main/java/androidx/core/os/PersistableBundle.kt
@@ -60,7 +60,7 @@
 
             // Reference arrays
             is Array<*> -> {
-                val componentType = value::class.java.componentType
+                val componentType = value::class.java.componentType!!
                 @Suppress("UNCHECKED_CAST") // Checked by reflection.
                 when {
                     String::class.java.isAssignableFrom(componentType) -> {
diff --git a/development/importMaven/build.gradle.kts b/development/importMaven/build.gradle.kts
index fb6d0759..0603314 100644
--- a/development/importMaven/build.gradle.kts
+++ b/development/importMaven/build.gradle.kts
@@ -14,15 +14,18 @@
  * limitations under the License.
  */
 
-import org.gradle.api.internal.artifacts.result.DefaultResolvedArtifactResult
+import org.gradle.api.artifacts.result.ResolvedArtifactResult
 
 // The output folder inside prebuilts
 val prebuiltsLocation = file("../../../../prebuilts/androidx")
 val internalFolder = "internal"
 val externalFolder = "external"
-
+val configurationName = "fetchArtifacts"
+val fetchArtifacts = configurations.create(configurationName)
+val fetchArtifactsContainer = configurations.getByName(configurationName)
 // Passed in as a project property
-val artifactName: String by project
+// Set a default here, so we can open this gradle script in an IDE without errors.
+val artifactName = project.findProperty("artifactName")
 
 val internalArtifacts = listOf(
         "android.arch(.*)?".toRegex(),
@@ -38,13 +41,6 @@
         ".databinding"
 )
 
-buildscript {
-    repositories {
-        mavenCentral()
-        google()
-    }
-}
-
 plugins {
     java
 }
@@ -56,7 +52,9 @@
 }
 
 dependencies {
-    compile(artifactName)
+    // This is the configuration container that we use to lookup the
+    // transitive closure of all dependencies.
+    fetchArtifacts(artifactName!!)
 }
 
 /**
@@ -91,25 +89,28 @@
 /**
  * Returns the supporting files (POM, Source files) for a given artifact.
  */
-fun supportingArtifacts(artifact: ResolvedArtifact): List<DefaultResolvedArtifactResult> {
-    val supportingArtifacts = mutableListOf<DefaultResolvedArtifactResult>()
+fun supportingArtifacts(artifact: ResolvedArtifact): List<ResolvedArtifactResult> {
+    val supportingArtifacts = mutableListOf<ResolvedArtifactResult>()
     val pomQuery = project.dependencies.createArtifactResolutionQuery()
     val pomQueryResult = pomQuery.forComponents(artifact.id.componentIdentifier)
             .withArtifacts(
                     MavenModule::class.java,
                     MavenPomArtifact::class.java)
             .execute()
-    val pomResult = pomQueryResult.resolvedComponents.firstOrNull()
-    // DefaultResolvedArtifactResult is an internal Gradle class.
-    // However, it's being widely used anyway.
-    val pomFile = pomResult?.getArtifacts(MavenPomArtifact::class.java)
-            ?.firstOrNull()
-            as? DefaultResolvedArtifactResult
-    if (pomFile != null) {
-        supportingArtifacts.add(pomFile)
+
+    for (component in pomQueryResult.resolvedComponents) {
+        // DefaultResolvedArtifactResult is an internal Gradle class.
+        // However, it's being widely used anyway.
+        val pomArtifacts = component.getArtifacts(MavenPomArtifact::class.java)
+        for (pomArtifact in pomArtifacts) {
+            val pomFile = pomArtifact as? ResolvedArtifactResult
+            if (pomFile != null) {
+                supportingArtifacts.add(pomFile)
+            }
+        }
     }
 
-    // Create a seperate query for a sources. This is because, withArtifacts seems to be an AND.
+    // Create a separate query for a sources. This is because, withArtifacts seems to be an AND.
     // So if artifacts only have a distributable without a source, we still want to copy the POM file.
     val sourcesQuery = project.dependencies.createArtifactResolutionQuery()
     val sourcesQueryResult = sourcesQuery.forComponents(artifact.id.componentIdentifier)
@@ -117,12 +118,15 @@
                     MavenModule::class.java,
                     SourcesArtifact::class.java)
             .execute()
-    val sourcesResult = sourcesQueryResult.resolvedComponents.firstOrNull()
-    val sourcesFile = sourcesResult?.getArtifacts(SourcesArtifact::class.java)
-            ?.firstOrNull()
-            as? DefaultResolvedArtifactResult
-    if (sourcesFile != null) {
-        supportingArtifacts.add(sourcesFile)
+
+    for (component in sourcesQueryResult.resolvedComponents) {
+        val sourcesArtifacts = component.getArtifacts(SourcesArtifact::class.java)
+        for (sourcesArtifact in sourcesArtifacts) {
+            val sourcesFile = sourcesArtifact as? ResolvedArtifactResult
+            if (sourcesFile != null) {
+                supportingArtifacts.add(sourcesFile)
+            }
+        }
     }
     return supportingArtifacts
 }
@@ -165,13 +169,13 @@
             // Copy the jar/aar's and their respective POM files.
             val internalLibraries =
                     filterInternalLibraries(
-                            configurations
-                                    .compile
+                        fetchArtifactsContainer
                                     .resolvedConfiguration
                                     .resolvedArtifacts)
 
             val externalLibraries =
-                    configurations.compile.resolvedConfiguration
+                    fetchArtifactsContainer
+                            .resolvedConfiguration
                             .resolvedArtifacts.filter {
                         val isInternal = internalLibraries.contains(it)
                         !isInternal
diff --git a/fragment/api/current.txt b/fragment/api/current.txt
index 736dccf..a2da2f6 100644
--- a/fragment/api/current.txt
+++ b/fragment/api/current.txt
@@ -155,6 +155,7 @@
     method public java.lang.Object getLastCustomNonConfigurationInstance();
     method public androidx.fragment.app.FragmentManager getSupportFragmentManager();
     method public deprecated androidx.loader.app.LoaderManager getSupportLoaderManager();
+    method public android.content.Context getThemedContext();
     method public androidx.lifecycle.ViewModelStore getViewModelStore();
     method public void onAttachFragment(androidx.fragment.app.Fragment);
     method public void onMultiWindowModeChanged(boolean);
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/FragmentTest.java b/fragment/src/androidTest/java/androidx/fragment/app/FragmentTest.java
index 2e9c9bc..08b6da7 100644
--- a/fragment/src/androidTest/java/androidx/fragment/app/FragmentTest.java
+++ b/fragment/src/androidTest/java/androidx/fragment/app/FragmentTest.java
@@ -17,10 +17,12 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.fail;
 
 import android.app.Instrumentation;
 import android.os.Bundle;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -53,7 +55,7 @@
 public class FragmentTest {
     @Rule
     public ActivityTestRule<FragmentTestActivity> mActivityRule =
-            new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
+            new ActivityTestRule<>(FragmentTestActivity.class);
 
     private FragmentTestActivity mActivity;
     private Instrumentation mInstrumentation;
@@ -184,6 +186,40 @@
     }
 
     @SmallTest
+    @UiThreadTest
+    @Test
+    public void testInflatedViewContext() {
+        final FragmentA fragment = new FragmentA();
+
+        mActivity.getSupportFragmentManager()
+                .beginTransaction()
+                .add(R.id.content, fragment)
+                .commitNow();
+
+        // Assert that the view has the Activity's context
+        assertSame(mActivity, fragment.getView().getContext());
+    }
+
+    @SmallTest
+    @UiThreadTest
+    @Test
+    public void testInflatedViewContext_withThemedContext() {
+        // Set the FragmentActivity to use a 'themed context'
+        ContextThemeWrapper themedContext = new ContextThemeWrapper(mActivity,
+                android.R.style.Theme_Black);
+        mActivity.setTestThemedContext(themedContext);
+
+        final FragmentA fragment = new FragmentA();
+        mActivity.getSupportFragmentManager()
+                .beginTransaction()
+                .replace(R.id.content, fragment)
+                .commitNow();
+
+        // Assert that the view uses the themed context
+        assertSame(themedContext, fragment.getView().getContext());
+    }
+
+    @SmallTest
     @Test
     public void requireMethodsThrowsWhenNotAttached() {
         Fragment fragment = new Fragment();
diff --git a/fragment/src/androidTest/java/androidx/fragment/app/test/FragmentTestActivity.java b/fragment/src/androidTest/java/androidx/fragment/app/test/FragmentTestActivity.java
index a4c8e68..8bdb54d 100644
--- a/fragment/src/androidTest/java/androidx/fragment/app/test/FragmentTestActivity.java
+++ b/fragment/src/androidTest/java/androidx/fragment/app/test/FragmentTestActivity.java
@@ -30,6 +30,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.fragment.app.Fragment;
 import androidx.fragment.app.FragmentActivity;
@@ -42,6 +43,7 @@
  * A simple activity used for Fragment Transitions and lifecycle event ordering
  */
 public class FragmentTestActivity extends FragmentActivity {
+    private Context mTestThemedContext;
     public final CountDownLatch onDestroyLatch = new CountDownLatch(1);
 
     @Override
@@ -63,6 +65,19 @@
         onDestroyLatch.countDown();
     }
 
+    @NonNull
+    @Override
+    public Context getThemedContext() {
+        if (mTestThemedContext != null) {
+            return mTestThemedContext;
+        }
+        return super.getThemedContext();
+    }
+
+    public void setTestThemedContext(Context testThemedContext) {
+        mTestThemedContext = testThemedContext;
+    }
+
     public static class TestFragment extends Fragment {
         public static final int ENTER = 0;
         public static final int RETURN = 1;
diff --git a/fragment/src/main/java/androidx/fragment/app/FragmentActivity.java b/fragment/src/main/java/androidx/fragment/app/FragmentActivity.java
index dc8769a..8fd6bbf 100644
--- a/fragment/src/main/java/androidx/fragment/app/FragmentActivity.java
+++ b/fragment/src/main/java/androidx/fragment/app/FragmentActivity.java
@@ -298,6 +298,14 @@
     }
 
     /**
+     * Returns the context to be used for inflating any fragment view hierarchies.
+     */
+    @NonNull
+    public Context getThemedContext() {
+        return this;
+    }
+
+    /**
      * Perform initialization of all fragments.
      */
     @SuppressWarnings("deprecation")
@@ -952,7 +960,7 @@
         @Override
         @NonNull
         public LayoutInflater onGetLayoutInflater() {
-            return FragmentActivity.this.getLayoutInflater().cloneInContext(FragmentActivity.this);
+            return FragmentActivity.this.getLayoutInflater().cloneInContext(getThemedContext());
         }
 
         @Override
diff --git a/legacy/preference-v14/OWNERS b/legacy/preference-v14/OWNERS
deleted file mode 100644
index ddaac03..0000000
--- a/legacy/preference-v14/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
[email protected]
\ No newline at end of file
diff --git a/legacy/preference-v14/api/1.0.0.txt b/legacy/preference-v14/api/1.0.0.txt
deleted file mode 100644
index e69de29..0000000
--- a/legacy/preference-v14/api/1.0.0.txt
+++ /dev/null
diff --git a/legacy/preference-v14/api_legacy/26.0.0.txt b/legacy/preference-v14/api_legacy/26.0.0.txt
deleted file mode 100644
index b92ccf9..0000000
--- a/legacy/preference-v14/api_legacy/26.0.0.txt
+++ /dev/null
@@ -1,98 +0,0 @@
-package android.support.v14.preference {
-
-  public class EditTextPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
-    ctor public EditTextPreferenceDialogFragment();
-    method public static android.support.v14.preference.EditTextPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public class ListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
-    ctor public ListPreferenceDialogFragment();
-    method public static android.support.v14.preference.ListPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public class MultiSelectListPreference extends android.support.v7.preference.internal.AbstractMultiSelectListPreference {
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet);
-    ctor public MultiSelectListPreference(android.content.Context);
-    method public int findIndexOfValue(java.lang.String);
-    method public java.lang.CharSequence[] getEntries();
-    method public java.lang.CharSequence[] getEntryValues();
-    method protected boolean[] getSelectedItems();
-    method public java.util.Set<java.lang.String> getValues();
-    method public void setEntries(java.lang.CharSequence[]);
-    method public void setEntries(int);
-    method public void setEntryValues(java.lang.CharSequence[]);
-    method public void setEntryValues(int);
-    method public void setValues(java.util.Set<java.lang.String>);
-  }
-
-  public class MultiSelectListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
-    ctor public MultiSelectListPreferenceDialogFragment();
-    method public static android.support.v14.preference.MultiSelectListPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public abstract class PreferenceDialogFragment extends android.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
-    ctor public PreferenceDialogFragment();
-    method public android.support.v7.preference.DialogPreference getPreference();
-    method protected void onBindDialogView(android.view.View);
-    method public void onClick(android.content.DialogInterface, int);
-    method protected android.view.View onCreateDialogView(android.content.Context);
-    method public abstract void onDialogClosed(boolean);
-    method protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder);
-    field protected static final java.lang.String ARG_KEY = "key";
-  }
-
-  public abstract class PreferenceFragment extends android.app.Fragment implements android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
-    ctor public PreferenceFragment();
-    method public void addPreferencesFromResource(int);
-    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
-    method public final android.support.v7.widget.RecyclerView getListView();
-    method public android.support.v7.preference.PreferenceManager getPreferenceManager();
-    method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
-    method protected android.support.v7.widget.RecyclerView.Adapter onCreateAdapter(android.support.v7.preference.PreferenceScreen);
-    method public android.support.v7.widget.RecyclerView.LayoutManager onCreateLayoutManager();
-    method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
-    method public android.support.v7.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
-    method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
-    method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
-    method public void scrollToPreference(java.lang.String);
-    method public void scrollToPreference(android.support.v7.preference.Preference);
-    method public void setDivider(android.graphics.drawable.Drawable);
-    method public void setDividerHeight(int);
-    method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
-    method public void setPreferencesFromResource(int, java.lang.String);
-    field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceDisplayDialogCallback {
-    method public abstract boolean onPreferenceDisplayDialog(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceStartFragmentCallback {
-    method public abstract boolean onPreferenceStartFragment(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceStartScreenCallback {
-    method public abstract boolean onPreferenceStartScreen(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.PreferenceScreen);
-  }
-
-  public class SwitchPreference extends android.support.v7.preference.TwoStatePreference {
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet);
-    ctor public SwitchPreference(android.content.Context);
-    method public java.lang.CharSequence getSwitchTextOff();
-    method public java.lang.CharSequence getSwitchTextOn();
-    method public void setSwitchTextOff(java.lang.CharSequence);
-    method public void setSwitchTextOff(int);
-    method public void setSwitchTextOn(java.lang.CharSequence);
-    method public void setSwitchTextOn(int);
-  }
-
-}
-
diff --git a/legacy/preference-v14/api_legacy/26.1.0.txt b/legacy/preference-v14/api_legacy/26.1.0.txt
deleted file mode 100644
index b92ccf9..0000000
--- a/legacy/preference-v14/api_legacy/26.1.0.txt
+++ /dev/null
@@ -1,98 +0,0 @@
-package android.support.v14.preference {
-
-  public class EditTextPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
-    ctor public EditTextPreferenceDialogFragment();
-    method public static android.support.v14.preference.EditTextPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public class ListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
-    ctor public ListPreferenceDialogFragment();
-    method public static android.support.v14.preference.ListPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public class MultiSelectListPreference extends android.support.v7.preference.internal.AbstractMultiSelectListPreference {
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet);
-    ctor public MultiSelectListPreference(android.content.Context);
-    method public int findIndexOfValue(java.lang.String);
-    method public java.lang.CharSequence[] getEntries();
-    method public java.lang.CharSequence[] getEntryValues();
-    method protected boolean[] getSelectedItems();
-    method public java.util.Set<java.lang.String> getValues();
-    method public void setEntries(java.lang.CharSequence[]);
-    method public void setEntries(int);
-    method public void setEntryValues(java.lang.CharSequence[]);
-    method public void setEntryValues(int);
-    method public void setValues(java.util.Set<java.lang.String>);
-  }
-
-  public class MultiSelectListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
-    ctor public MultiSelectListPreferenceDialogFragment();
-    method public static android.support.v14.preference.MultiSelectListPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public abstract class PreferenceDialogFragment extends android.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
-    ctor public PreferenceDialogFragment();
-    method public android.support.v7.preference.DialogPreference getPreference();
-    method protected void onBindDialogView(android.view.View);
-    method public void onClick(android.content.DialogInterface, int);
-    method protected android.view.View onCreateDialogView(android.content.Context);
-    method public abstract void onDialogClosed(boolean);
-    method protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder);
-    field protected static final java.lang.String ARG_KEY = "key";
-  }
-
-  public abstract class PreferenceFragment extends android.app.Fragment implements android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
-    ctor public PreferenceFragment();
-    method public void addPreferencesFromResource(int);
-    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
-    method public final android.support.v7.widget.RecyclerView getListView();
-    method public android.support.v7.preference.PreferenceManager getPreferenceManager();
-    method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
-    method protected android.support.v7.widget.RecyclerView.Adapter onCreateAdapter(android.support.v7.preference.PreferenceScreen);
-    method public android.support.v7.widget.RecyclerView.LayoutManager onCreateLayoutManager();
-    method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
-    method public android.support.v7.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
-    method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
-    method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
-    method public void scrollToPreference(java.lang.String);
-    method public void scrollToPreference(android.support.v7.preference.Preference);
-    method public void setDivider(android.graphics.drawable.Drawable);
-    method public void setDividerHeight(int);
-    method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
-    method public void setPreferencesFromResource(int, java.lang.String);
-    field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceDisplayDialogCallback {
-    method public abstract boolean onPreferenceDisplayDialog(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceStartFragmentCallback {
-    method public abstract boolean onPreferenceStartFragment(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceStartScreenCallback {
-    method public abstract boolean onPreferenceStartScreen(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.PreferenceScreen);
-  }
-
-  public class SwitchPreference extends android.support.v7.preference.TwoStatePreference {
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet);
-    ctor public SwitchPreference(android.content.Context);
-    method public java.lang.CharSequence getSwitchTextOff();
-    method public java.lang.CharSequence getSwitchTextOn();
-    method public void setSwitchTextOff(java.lang.CharSequence);
-    method public void setSwitchTextOff(int);
-    method public void setSwitchTextOn(java.lang.CharSequence);
-    method public void setSwitchTextOn(int);
-  }
-
-}
-
diff --git a/legacy/preference-v14/api_legacy/27.0.0.txt b/legacy/preference-v14/api_legacy/27.0.0.txt
deleted file mode 100644
index b92ccf9..0000000
--- a/legacy/preference-v14/api_legacy/27.0.0.txt
+++ /dev/null
@@ -1,98 +0,0 @@
-package android.support.v14.preference {
-
-  public class EditTextPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
-    ctor public EditTextPreferenceDialogFragment();
-    method public static android.support.v14.preference.EditTextPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public class ListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
-    ctor public ListPreferenceDialogFragment();
-    method public static android.support.v14.preference.ListPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public class MultiSelectListPreference extends android.support.v7.preference.internal.AbstractMultiSelectListPreference {
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet);
-    ctor public MultiSelectListPreference(android.content.Context);
-    method public int findIndexOfValue(java.lang.String);
-    method public java.lang.CharSequence[] getEntries();
-    method public java.lang.CharSequence[] getEntryValues();
-    method protected boolean[] getSelectedItems();
-    method public java.util.Set<java.lang.String> getValues();
-    method public void setEntries(java.lang.CharSequence[]);
-    method public void setEntries(int);
-    method public void setEntryValues(java.lang.CharSequence[]);
-    method public void setEntryValues(int);
-    method public void setValues(java.util.Set<java.lang.String>);
-  }
-
-  public class MultiSelectListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
-    ctor public MultiSelectListPreferenceDialogFragment();
-    method public static android.support.v14.preference.MultiSelectListPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public abstract class PreferenceDialogFragment extends android.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
-    ctor public PreferenceDialogFragment();
-    method public android.support.v7.preference.DialogPreference getPreference();
-    method protected void onBindDialogView(android.view.View);
-    method public void onClick(android.content.DialogInterface, int);
-    method protected android.view.View onCreateDialogView(android.content.Context);
-    method public abstract void onDialogClosed(boolean);
-    method protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder);
-    field protected static final java.lang.String ARG_KEY = "key";
-  }
-
-  public abstract class PreferenceFragment extends android.app.Fragment implements android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
-    ctor public PreferenceFragment();
-    method public void addPreferencesFromResource(int);
-    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
-    method public final android.support.v7.widget.RecyclerView getListView();
-    method public android.support.v7.preference.PreferenceManager getPreferenceManager();
-    method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
-    method protected android.support.v7.widget.RecyclerView.Adapter onCreateAdapter(android.support.v7.preference.PreferenceScreen);
-    method public android.support.v7.widget.RecyclerView.LayoutManager onCreateLayoutManager();
-    method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
-    method public android.support.v7.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
-    method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
-    method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
-    method public void scrollToPreference(java.lang.String);
-    method public void scrollToPreference(android.support.v7.preference.Preference);
-    method public void setDivider(android.graphics.drawable.Drawable);
-    method public void setDividerHeight(int);
-    method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
-    method public void setPreferencesFromResource(int, java.lang.String);
-    field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceDisplayDialogCallback {
-    method public abstract boolean onPreferenceDisplayDialog(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceStartFragmentCallback {
-    method public abstract boolean onPreferenceStartFragment(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceStartScreenCallback {
-    method public abstract boolean onPreferenceStartScreen(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.PreferenceScreen);
-  }
-
-  public class SwitchPreference extends android.support.v7.preference.TwoStatePreference {
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet);
-    ctor public SwitchPreference(android.content.Context);
-    method public java.lang.CharSequence getSwitchTextOff();
-    method public java.lang.CharSequence getSwitchTextOn();
-    method public void setSwitchTextOff(java.lang.CharSequence);
-    method public void setSwitchTextOff(int);
-    method public void setSwitchTextOn(java.lang.CharSequence);
-    method public void setSwitchTextOn(int);
-  }
-
-}
-
diff --git a/legacy/preference-v14/api_legacy/28.0.0-alpha1.txt b/legacy/preference-v14/api_legacy/28.0.0-alpha1.txt
deleted file mode 100644
index af3db09..0000000
--- a/legacy/preference-v14/api_legacy/28.0.0-alpha1.txt
+++ /dev/null
@@ -1,98 +0,0 @@
-package android.support.v14.preference {
-
-  public class EditTextPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
-    ctor public EditTextPreferenceDialogFragment();
-    method public static android.support.v14.preference.EditTextPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public class ListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
-    ctor public ListPreferenceDialogFragment();
-    method public static android.support.v14.preference.ListPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public class MultiSelectListPreference extends android.support.v7.preference.internal.AbstractMultiSelectListPreference {
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet);
-    ctor public MultiSelectListPreference(android.content.Context);
-    method public int findIndexOfValue(java.lang.String);
-    method public java.lang.CharSequence[] getEntries();
-    method public java.lang.CharSequence[] getEntryValues();
-    method protected boolean[] getSelectedItems();
-    method public java.util.Set<java.lang.String> getValues();
-    method public void setEntries(java.lang.CharSequence[]);
-    method public void setEntries(int);
-    method public void setEntryValues(java.lang.CharSequence[]);
-    method public void setEntryValues(int);
-    method public void setValues(java.util.Set<java.lang.String>);
-  }
-
-  public class MultiSelectListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
-    ctor public MultiSelectListPreferenceDialogFragment();
-    method public static android.support.v14.preference.MultiSelectListPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public abstract class PreferenceDialogFragment extends android.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
-    ctor public PreferenceDialogFragment();
-    method public android.support.v7.preference.DialogPreference getPreference();
-    method protected void onBindDialogView(android.view.View);
-    method public void onClick(android.content.DialogInterface, int);
-    method protected android.view.View onCreateDialogView(android.content.Context);
-    method public abstract void onDialogClosed(boolean);
-    method protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder);
-    field protected static final java.lang.String ARG_KEY = "key";
-  }
-
-  public abstract class PreferenceFragment extends android.app.Fragment implements android.support.v7.preference.DialogPreference.TargetFragment android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
-    ctor public PreferenceFragment();
-    method public void addPreferencesFromResource(int);
-    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
-    method public final android.support.v7.widget.RecyclerView getListView();
-    method public android.support.v7.preference.PreferenceManager getPreferenceManager();
-    method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
-    method protected android.support.v7.widget.RecyclerView.Adapter onCreateAdapter(android.support.v7.preference.PreferenceScreen);
-    method public android.support.v7.widget.RecyclerView.LayoutManager onCreateLayoutManager();
-    method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
-    method public android.support.v7.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
-    method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
-    method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
-    method public void scrollToPreference(java.lang.String);
-    method public void scrollToPreference(android.support.v7.preference.Preference);
-    method public void setDivider(android.graphics.drawable.Drawable);
-    method public void setDividerHeight(int);
-    method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
-    method public void setPreferencesFromResource(int, java.lang.String);
-    field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceDisplayDialogCallback {
-    method public abstract boolean onPreferenceDisplayDialog(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceStartFragmentCallback {
-    method public abstract boolean onPreferenceStartFragment(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceStartScreenCallback {
-    method public abstract boolean onPreferenceStartScreen(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.PreferenceScreen);
-  }
-
-  public class SwitchPreference extends android.support.v7.preference.TwoStatePreference {
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet);
-    ctor public SwitchPreference(android.content.Context);
-    method public java.lang.CharSequence getSwitchTextOff();
-    method public java.lang.CharSequence getSwitchTextOn();
-    method public void setSwitchTextOff(java.lang.CharSequence);
-    method public void setSwitchTextOff(int);
-    method public void setSwitchTextOn(java.lang.CharSequence);
-    method public void setSwitchTextOn(int);
-  }
-
-}
-
diff --git a/legacy/preference-v14/api_legacy/current.txt b/legacy/preference-v14/api_legacy/current.txt
deleted file mode 100644
index af3db09..0000000
--- a/legacy/preference-v14/api_legacy/current.txt
+++ /dev/null
@@ -1,98 +0,0 @@
-package android.support.v14.preference {
-
-  public class EditTextPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
-    ctor public EditTextPreferenceDialogFragment();
-    method public static android.support.v14.preference.EditTextPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public class ListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
-    ctor public ListPreferenceDialogFragment();
-    method public static android.support.v14.preference.ListPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public class MultiSelectListPreference extends android.support.v7.preference.internal.AbstractMultiSelectListPreference {
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public MultiSelectListPreference(android.content.Context, android.util.AttributeSet);
-    ctor public MultiSelectListPreference(android.content.Context);
-    method public int findIndexOfValue(java.lang.String);
-    method public java.lang.CharSequence[] getEntries();
-    method public java.lang.CharSequence[] getEntryValues();
-    method protected boolean[] getSelectedItems();
-    method public java.util.Set<java.lang.String> getValues();
-    method public void setEntries(java.lang.CharSequence[]);
-    method public void setEntries(int);
-    method public void setEntryValues(java.lang.CharSequence[]);
-    method public void setEntryValues(int);
-    method public void setValues(java.util.Set<java.lang.String>);
-  }
-
-  public class MultiSelectListPreferenceDialogFragment extends android.support.v14.preference.PreferenceDialogFragment {
-    ctor public MultiSelectListPreferenceDialogFragment();
-    method public static android.support.v14.preference.MultiSelectListPreferenceDialogFragment newInstance(java.lang.String);
-    method public void onDialogClosed(boolean);
-  }
-
-  public abstract class PreferenceDialogFragment extends android.app.DialogFragment implements android.content.DialogInterface.OnClickListener {
-    ctor public PreferenceDialogFragment();
-    method public android.support.v7.preference.DialogPreference getPreference();
-    method protected void onBindDialogView(android.view.View);
-    method public void onClick(android.content.DialogInterface, int);
-    method protected android.view.View onCreateDialogView(android.content.Context);
-    method public abstract void onDialogClosed(boolean);
-    method protected void onPrepareDialogBuilder(android.app.AlertDialog.Builder);
-    field protected static final java.lang.String ARG_KEY = "key";
-  }
-
-  public abstract class PreferenceFragment extends android.app.Fragment implements android.support.v7.preference.DialogPreference.TargetFragment android.support.v7.preference.PreferenceManager.OnDisplayPreferenceDialogListener android.support.v7.preference.PreferenceManager.OnNavigateToScreenListener android.support.v7.preference.PreferenceManager.OnPreferenceTreeClickListener {
-    ctor public PreferenceFragment();
-    method public void addPreferencesFromResource(int);
-    method public android.support.v7.preference.Preference findPreference(java.lang.CharSequence);
-    method public final android.support.v7.widget.RecyclerView getListView();
-    method public android.support.v7.preference.PreferenceManager getPreferenceManager();
-    method public android.support.v7.preference.PreferenceScreen getPreferenceScreen();
-    method protected android.support.v7.widget.RecyclerView.Adapter onCreateAdapter(android.support.v7.preference.PreferenceScreen);
-    method public android.support.v7.widget.RecyclerView.LayoutManager onCreateLayoutManager();
-    method public abstract void onCreatePreferences(android.os.Bundle, java.lang.String);
-    method public android.support.v7.widget.RecyclerView onCreateRecyclerView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
-    method public void onDisplayPreferenceDialog(android.support.v7.preference.Preference);
-    method public void onNavigateToScreen(android.support.v7.preference.PreferenceScreen);
-    method public boolean onPreferenceTreeClick(android.support.v7.preference.Preference);
-    method public void scrollToPreference(java.lang.String);
-    method public void scrollToPreference(android.support.v7.preference.Preference);
-    method public void setDivider(android.graphics.drawable.Drawable);
-    method public void setDividerHeight(int);
-    method public void setPreferenceScreen(android.support.v7.preference.PreferenceScreen);
-    method public void setPreferencesFromResource(int, java.lang.String);
-    field public static final java.lang.String ARG_PREFERENCE_ROOT = "android.support.v7.preference.PreferenceFragmentCompat.PREFERENCE_ROOT";
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceDisplayDialogCallback {
-    method public abstract boolean onPreferenceDisplayDialog(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceStartFragmentCallback {
-    method public abstract boolean onPreferenceStartFragment(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.Preference);
-  }
-
-  public static abstract interface PreferenceFragment.OnPreferenceStartScreenCallback {
-    method public abstract boolean onPreferenceStartScreen(android.support.v14.preference.PreferenceFragment, android.support.v7.preference.PreferenceScreen);
-  }
-
-  public class SwitchPreference extends android.support.v7.preference.TwoStatePreference {
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int, int);
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet, int);
-    ctor public SwitchPreference(android.content.Context, android.util.AttributeSet);
-    ctor public SwitchPreference(android.content.Context);
-    method public java.lang.CharSequence getSwitchTextOff();
-    method public java.lang.CharSequence getSwitchTextOn();
-    method public void setSwitchTextOff(java.lang.CharSequence);
-    method public void setSwitchTextOff(int);
-    method public void setSwitchTextOn(java.lang.CharSequence);
-    method public void setSwitchTextOn(int);
-  }
-
-}
-
diff --git a/legacy/preference-v14/build.gradle b/legacy/preference-v14/build.gradle
deleted file mode 100644
index 79e3ffd..0000000
--- a/legacy/preference-v14/build.gradle
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-import androidx.build.LibraryGroups
-import androidx.build.LibraryVersions
-
-plugins {
-    id("SupportAndroidLibraryPlugin")
-}
-
-dependencies {
-    api(project(":preference"))
-}
-
-supportLibrary {
-    name = "Android Support Preference v14"
-    publish = true
-    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
-    mavenGroup = LibraryGroups.LEGACY
-    inceptionYear = "2015"
-    description = "Android Support Preference v14"
-    useMetalava = false
-}
diff --git a/legacy/preference-v14/src/main/AndroidManifest.xml b/legacy/preference-v14/src/main/AndroidManifest.xml
deleted file mode 100644
index 60b2d0b..0000000
--- a/legacy/preference-v14/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest package="androidx.legacy.preference"/>
diff --git a/lifecycle/common/api/current.txt b/lifecycle/common/api/current.txt
index 370089b..6b90ad3 100644
--- a/lifecycle/common/api/current.txt
+++ b/lifecycle/common/api/current.txt
@@ -1,5 +1,9 @@
 package androidx.lifecycle {
 
+  public abstract interface GenericLifecycleObserver implements androidx.lifecycle.LifecycleObserver {
+    method public abstract void onStateChanged(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Lifecycle.Event);
+  }
+
   public abstract class Lifecycle {
     ctor public Lifecycle();
     method public abstract void addObserver(androidx.lifecycle.LifecycleObserver);
diff --git a/lifecycle/common/src/main/java/androidx/lifecycle/GenericLifecycleObserver.java b/lifecycle/common/src/main/java/androidx/lifecycle/GenericLifecycleObserver.java
index ffdd2c0..2a201d5 100644
--- a/lifecycle/common/src/main/java/androidx/lifecycle/GenericLifecycleObserver.java
+++ b/lifecycle/common/src/main/java/androidx/lifecycle/GenericLifecycleObserver.java
@@ -16,14 +16,9 @@
 
 package androidx.lifecycle;
 
-import androidx.annotation.RestrictTo;
-
 /**
- * Internal class that can receive any lifecycle change and dispatch it to the receiver.
- * @hide
+ * Class that can receive any lifecycle change and dispatch it to the receiver.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-@SuppressWarnings({"WeakerAccess", "unused"})
 public interface GenericLifecycleObserver extends LifecycleObserver {
     /**
      * Called when a state transition event happens.
diff --git a/navigation/ui/build.gradle b/navigation/ui/build.gradle
index c4a5c17..bae2af1 100644
--- a/navigation/ui/build.gradle
+++ b/navigation/ui/build.gradle
@@ -21,6 +21,7 @@
 
 plugins {
     id("SupportAndroidLibraryPlugin")
+    id("kotlin-android")
 }
 
 android {
@@ -37,8 +38,12 @@
     testImplementation(MOCKITO_CORE)
     testImplementation(TEST_RUNNER)
 
+    androidTestImplementation(KOTLIN_STDLIB)
     androidTestImplementation(TEST_RUNNER)
-    androidTestImplementation(ESPRESSO_CORE)
+    androidTestImplementation(TRUTH)
+    androidTestImplementation(ESPRESSO_CORE, libs.exclude_for_espresso)
+    androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+    androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
 }
 
 supportLibrary {
diff --git a/navigation/ui/ktx/src/main/java/androidx/navigation/ui/Activity.kt b/navigation/ui/ktx/src/main/java/androidx/navigation/ui/Activity.kt
index 6e530c6..dc655b8 100644
--- a/navigation/ui/ktx/src/main/java/androidx/navigation/ui/Activity.kt
+++ b/navigation/ui/ktx/src/main/java/androidx/navigation/ui/Activity.kt
@@ -37,8 +37,9 @@
  * @param drawerLayout The DrawerLayout that should be toggled from the home button
  */
 fun AppCompatActivity.setupActionBarWithNavController(
-        navController: NavController,
-        drawerLayout: DrawerLayout? = null
+    navController: NavController,
+    drawerLayout: DrawerLayout? = null
 ) {
-    NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)
+    NavigationUI.setupActionBarWithNavController(this, navController,
+            AppBarConfiguration.Builder().setDrawerLayout(drawerLayout).build())
 }
diff --git a/navigation/ui/ktx/src/main/java/androidx/navigation/ui/CollapsingToolbarLayout.kt b/navigation/ui/ktx/src/main/java/androidx/navigation/ui/CollapsingToolbarLayout.kt
index a80a872..d099d98 100644
--- a/navigation/ui/ktx/src/main/java/androidx/navigation/ui/CollapsingToolbarLayout.kt
+++ b/navigation/ui/ktx/src/main/java/androidx/navigation/ui/CollapsingToolbarLayout.kt
@@ -43,5 +43,6 @@
     navController: NavController,
     drawerLayout: DrawerLayout? = null
 ) {
-    NavigationUI.setupWithNavController(this, toolbar, navController, drawerLayout)
+    NavigationUI.setupWithNavController(this, toolbar, navController,
+            AppBarConfiguration.Builder().setDrawerLayout(drawerLayout).build())
 }
diff --git a/navigation/ui/ktx/src/main/java/androidx/navigation/ui/Toolbar.kt b/navigation/ui/ktx/src/main/java/androidx/navigation/ui/Toolbar.kt
index 1a150ec..9b905e1 100644
--- a/navigation/ui/ktx/src/main/java/androidx/navigation/ui/Toolbar.kt
+++ b/navigation/ui/ktx/src/main/java/androidx/navigation/ui/Toolbar.kt
@@ -40,5 +40,6 @@
     navController: NavController,
     drawerLayout: DrawerLayout? = null
 ) {
-    NavigationUI.setupWithNavController(this, navController, drawerLayout)
+    NavigationUI.setupWithNavController(this, navController,
+            AppBarConfiguration.Builder().setDrawerLayout(drawerLayout).build())
 }
diff --git a/navigation/ui/src/androidTest/AndroidManifest.xml b/navigation/ui/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..d057989
--- /dev/null
+++ b/navigation/ui/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="androidx.navigation.ui.test">
+    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
+
+</manifest>
diff --git a/navigation/ui/src/androidTest/java/androidx/navigation/ui/AppBarConfigurationTest.kt b/navigation/ui/src/androidTest/java/androidx/navigation/ui/AppBarConfigurationTest.kt
new file mode 100644
index 0000000..d7934d8
--- /dev/null
+++ b/navigation/ui/src/androidTest/java/androidx/navigation/ui/AppBarConfigurationTest.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.navigation.ui
+
+import android.support.v4.widget.DrawerLayout
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AppBarConfigurationTest {
+
+    @Test
+    fun testSetDrawerLayout() {
+        val builder = AppBarConfiguration.Builder()
+        val drawerLayout: DrawerLayout = mock(DrawerLayout::class.java)
+        builder.setDrawerLayout(drawerLayout)
+        val appBarConfiguration = builder.build()
+        assertThat(appBarConfiguration.drawerLayout).isEqualTo(drawerLayout)
+    }
+}
diff --git a/navigation/ui/src/main/java/androidx/navigation/ui/AbstractAppBarOnNavigatedListener.java b/navigation/ui/src/main/java/androidx/navigation/ui/AbstractAppBarOnNavigatedListener.java
index 0d0ea75..662cd013 100644
--- a/navigation/ui/src/main/java/androidx/navigation/ui/AbstractAppBarOnNavigatedListener.java
+++ b/navigation/ui/src/main/java/androidx/navigation/ui/AbstractAppBarOnNavigatedListener.java
@@ -48,8 +48,9 @@
     private ValueAnimator mAnimator;
 
     AbstractAppBarOnNavigatedListener(@NonNull Context context,
-            @Nullable DrawerLayout drawerLayout) {
+            @NonNull AppBarConfiguration configuration) {
         mContext = context;
+        DrawerLayout drawerLayout = configuration.getDrawerLayout();
         if (drawerLayout != null) {
             mDrawerLayoutWeakReference = new WeakReference<>(drawerLayout);
         } else {
diff --git a/navigation/ui/src/main/java/androidx/navigation/ui/ActionBarOnNavigatedListener.java b/navigation/ui/src/main/java/androidx/navigation/ui/ActionBarOnNavigatedListener.java
index bc50a5c..69d2842 100644
--- a/navigation/ui/src/main/java/androidx/navigation/ui/ActionBarOnNavigatedListener.java
+++ b/navigation/ui/src/main/java/androidx/navigation/ui/ActionBarOnNavigatedListener.java
@@ -18,9 +18,7 @@
 
 import android.graphics.drawable.Drawable;
 import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
-import android.support.v4.widget.DrawerLayout;
 import android.support.v7.app.ActionBar;
 import android.support.v7.app.ActionBarDrawerToggle;
 import android.support.v7.app.AppCompatActivity;
@@ -35,9 +33,9 @@
 class ActionBarOnNavigatedListener extends AbstractAppBarOnNavigatedListener {
     private final AppCompatActivity mActivity;
 
-    ActionBarOnNavigatedListener(
-            @NonNull AppCompatActivity activity, @Nullable DrawerLayout drawerLayout) {
-        super(activity.getDrawerToggleDelegate().getActionBarThemedContext(), drawerLayout);
+    ActionBarOnNavigatedListener(@NonNull AppCompatActivity activity,
+            @NonNull AppBarConfiguration configuration) {
+        super(activity.getDrawerToggleDelegate().getActionBarThemedContext(), configuration);
         mActivity = activity;
     }
 
diff --git a/navigation/ui/src/main/java/androidx/navigation/ui/AppBarConfiguration.java b/navigation/ui/src/main/java/androidx/navigation/ui/AppBarConfiguration.java
new file mode 100644
index 0000000..dc09a762
--- /dev/null
+++ b/navigation/ui/src/main/java/androidx/navigation/ui/AppBarConfiguration.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.navigation.ui;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.widget.DrawerLayout;
+
+/**
+ * Configuration options for {@link NavigationUI} methods that interact with implementations of the
+ * app bar pattern such as {@link android.support.v7.widget.Toolbar},
+ * {@link android.support.design.widget.CollapsingToolbarLayout}, and
+ * {@link android.support.v7.app.ActionBar}.
+ */
+public class AppBarConfiguration {
+
+    @Nullable
+    private final DrawerLayout mDrawerLayout;
+
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    AppBarConfiguration(@Nullable DrawerLayout drawerLayout) {
+        mDrawerLayout = drawerLayout;
+    }
+
+    /**
+     * The {@link DrawerLayout} indicating that the Navigation button should be displayed as
+     * a drawer symbol when it is not being shown as an Up button.
+     * @return The DrawerLayout that should be toggled from the Navigation button
+     */
+    @Nullable
+    public DrawerLayout getDrawerLayout() {
+        return mDrawerLayout;
+    }
+
+    /**
+     * The Builder class for constructing new {@link AppBarConfiguration} instances.
+     */
+    public static class Builder {
+        @Nullable
+        private DrawerLayout mDrawerLayout;
+
+        /**
+         * Display the Navigation button as a drawer symbol when it is not being shown as an
+         * Up button.
+         * @param drawerLayout The DrawerLayout that should be toggled from the Navigation button
+         * @return this {@link Builder}
+         */
+        @NonNull
+        public Builder setDrawerLayout(@Nullable DrawerLayout drawerLayout) {
+            mDrawerLayout = drawerLayout;
+            return this;
+        }
+
+        /**
+         * Construct the {@link AppBarConfiguration} instance.
+         *
+         * @return a valid {@link AppBarConfiguration}
+         */
+        @NonNull
+        public AppBarConfiguration build() {
+            return new AppBarConfiguration(mDrawerLayout);
+        }
+    }
+}
diff --git a/navigation/ui/src/main/java/androidx/navigation/ui/CollapsingToolbarOnNavigatedListener.java b/navigation/ui/src/main/java/androidx/navigation/ui/CollapsingToolbarOnNavigatedListener.java
index 20e242b..efc560c 100644
--- a/navigation/ui/src/main/java/androidx/navigation/ui/CollapsingToolbarOnNavigatedListener.java
+++ b/navigation/ui/src/main/java/androidx/navigation/ui/CollapsingToolbarOnNavigatedListener.java
@@ -18,10 +18,8 @@
 
 import android.graphics.drawable.Drawable;
 import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
 import android.support.design.widget.CollapsingToolbarLayout;
-import android.support.v4.widget.DrawerLayout;
 import android.support.v7.widget.Toolbar;
 
 import androidx.navigation.NavController;
@@ -43,8 +41,8 @@
 
     CollapsingToolbarOnNavigatedListener(
             @NonNull CollapsingToolbarLayout collapsingToolbarLayout,
-            @NonNull Toolbar toolbar, @Nullable DrawerLayout drawerLayout) {
-        super(collapsingToolbarLayout.getContext(), drawerLayout);
+            @NonNull Toolbar toolbar, @NonNull AppBarConfiguration configuration) {
+        super(collapsingToolbarLayout.getContext(), configuration);
         mCollapsingToolbarLayoutWeakReference = new WeakReference<>(collapsingToolbarLayout);
         mToolbarWeakReference = new WeakReference<>(toolbar);
     }
diff --git a/navigation/ui/src/main/java/androidx/navigation/ui/NavigationUI.java b/navigation/ui/src/main/java/androidx/navigation/ui/NavigationUI.java
index 4738994..f372359 100644
--- a/navigation/ui/src/main/java/androidx/navigation/ui/NavigationUI.java
+++ b/navigation/ui/src/main/java/androidx/navigation/ui/NavigationUI.java
@@ -126,11 +126,12 @@
      * @param activity The activity hosting the action bar that should be kept in sync with changes
      *                 to the NavController.
      * @param navController The NavController that supplies the secondary menu. Navigation actions
- *                      on this NavController will be reflected in the title of the action bar.
+     *                      on this NavController will be reflected in the title of the action bar.
      */
     public static void setupActionBarWithNavController(@NonNull AppCompatActivity activity,
             @NonNull NavController navController) {
-        setupActionBarWithNavController(activity, navController, null);
+        setupActionBarWithNavController(activity, navController,
+                new AppBarConfiguration.Builder().build());
     }
 
     /**
@@ -153,7 +154,30 @@
             @NonNull NavController navController,
             @Nullable DrawerLayout drawerLayout) {
         navController.addOnNavigatedListener(
-                new ActionBarOnNavigatedListener(activity, drawerLayout));
+                new ActionBarOnNavigatedListener(activity,
+                        new AppBarConfiguration.Builder().setDrawerLayout(drawerLayout).build()));
+    }
+
+    /**
+     * Sets up the ActionBar returned by {@link AppCompatActivity#getSupportActionBar()} for use
+     * with a {@link NavController}.
+     *
+     * <p>By calling this method, the title in the action bar will automatically be updated when
+     * the destination changes (assuming there is a valid {@link NavDestination#getLabel label}).
+     *
+     * <p>The {@link AppBarConfiguration} you provide controls how the Up button is displayed.
+     *  @param activity The activity hosting the action bar that should be kept in sync with changes
+     *                 to the NavController.
+     * @param navController The NavController whose navigation actions will be reflected
+     *                      in the title of the action bar.
+     * @param configuration Additional configuration options for customizing the behavior of the
+     *                      ActionBar
+     */
+    public static void setupActionBarWithNavController(@NonNull AppCompatActivity activity,
+            @NonNull NavController navController,
+            @NonNull AppBarConfiguration configuration) {
+        navController.addOnNavigatedListener(
+                new ActionBarOnNavigatedListener(activity, configuration));
     }
 
     /**
@@ -172,7 +196,7 @@
      */
     public static void setupWithNavController(@NonNull Toolbar toolbar,
             @NonNull NavController navController) {
-        setupWithNavController(toolbar, navController, null);
+        setupWithNavController(toolbar, navController, new AppBarConfiguration.Builder().build());
     }
 
     /**
@@ -194,12 +218,34 @@
     public static void setupWithNavController(@NonNull Toolbar toolbar,
             @NonNull final NavController navController,
             @Nullable final DrawerLayout drawerLayout) {
+        setupWithNavController(toolbar, navController,
+                new AppBarConfiguration.Builder().setDrawerLayout(drawerLayout).build());
+    }
+
+    /**
+     * Sets up a {@link Toolbar} for use with a {@link NavController}.
+     *
+     * <p>By calling this method, the title in the Toolbar will automatically be updated when
+     * the destination changes (assuming there is a valid {@link NavDestination#getLabel label}).
+     *
+     * <p>The {@link AppBarConfiguration} you provide controls how the Up button is displayed and
+     * what action is triggered when the Up button is tapped.
+     *
+     * @param toolbar The Toolbar that should be kept in sync with changes to the NavController.
+     * @param navController The NavController whose navigation actions will be reflected
+     *                      in the title of the Toolbar.
+     * @param configuration Additional configuration options for customizing the behavior of the
+     *                      Toolbar
+     */
+    public static void setupWithNavController(@NonNull Toolbar toolbar,
+            @NonNull final NavController navController,
+            @NonNull final AppBarConfiguration configuration) {
         navController.addOnNavigatedListener(
-                new ToolbarOnNavigatedListener(toolbar, drawerLayout));
+                new ToolbarOnNavigatedListener(toolbar, configuration));
         toolbar.setNavigationOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                navigateUp(drawerLayout, navController);
+                navigateUp(configuration.getDrawerLayout(), navController);
             }
         });
     }
@@ -226,7 +272,8 @@
             @NonNull CollapsingToolbarLayout collapsingToolbarLayout,
             @NonNull Toolbar toolbar,
             @NonNull NavController navController) {
-        setupWithNavController(collapsingToolbarLayout, toolbar, navController, null);
+        setupWithNavController(collapsingToolbarLayout, toolbar, navController,
+                new AppBarConfiguration.Builder().build());
     }
 
     /**
@@ -254,12 +301,40 @@
             @NonNull Toolbar toolbar,
             @NonNull final NavController navController,
             @Nullable final DrawerLayout drawerLayout) {
+        setupWithNavController(collapsingToolbarLayout, toolbar, navController,
+                new AppBarConfiguration.Builder().setDrawerLayout(drawerLayout).build());
+    }
+
+    /**
+     * Sets up a {@link CollapsingToolbarLayout} and {@link Toolbar} for use with a
+     * {@link NavController}.
+     *
+     * <p>By calling this method, the title in the CollapsingToolbarLayout will automatically be
+     * updated when the destination changes (assuming there is a valid
+     * {@link NavDestination#getLabel label}).
+     *
+     * <p>The {@link AppBarConfiguration} you provide controls how the Up button is displayed and
+     * what action is triggered when the Up button is tapped.
+     *
+     * @param collapsingToolbarLayout The CollapsingToolbarLayout that should be kept in sync with
+     *                                changes to the NavController.
+     * @param toolbar The Toolbar that should be kept in sync with changes to the NavController.
+     * @param navController The NavController whose navigation actions will be reflected
+     *                      in the title of the Toolbar.
+     * @param configuration Additional configuration options for customizing the behavior of the
+     *                      Toolbar
+     */
+    public static void setupWithNavController(
+            @NonNull CollapsingToolbarLayout collapsingToolbarLayout,
+            @NonNull Toolbar toolbar,
+            @NonNull final NavController navController,
+            @NonNull final AppBarConfiguration configuration) {
         navController.addOnNavigatedListener(new CollapsingToolbarOnNavigatedListener(
-                collapsingToolbarLayout, toolbar, drawerLayout));
+                collapsingToolbarLayout, toolbar, configuration));
         toolbar.setNavigationOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
-                navigateUp(drawerLayout, navController);
+                navigateUp(configuration.getDrawerLayout(), navController);
             }
         });
     }
diff --git a/navigation/ui/src/main/java/androidx/navigation/ui/ToolbarOnNavigatedListener.java b/navigation/ui/src/main/java/androidx/navigation/ui/ToolbarOnNavigatedListener.java
index 9341e16..88c12a9 100644
--- a/navigation/ui/src/main/java/androidx/navigation/ui/ToolbarOnNavigatedListener.java
+++ b/navigation/ui/src/main/java/androidx/navigation/ui/ToolbarOnNavigatedListener.java
@@ -18,9 +18,7 @@
 
 import android.graphics.drawable.Drawable;
 import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
-import android.support.v4.widget.DrawerLayout;
 import android.support.v7.widget.Toolbar;
 
 import androidx.navigation.NavController;
@@ -39,8 +37,8 @@
     private final WeakReference<Toolbar> mToolbarWeakReference;
 
     ToolbarOnNavigatedListener(
-            @NonNull Toolbar toolbar, @Nullable DrawerLayout drawerLayout) {
-        super(toolbar.getContext(), drawerLayout);
+            @NonNull Toolbar toolbar, @NonNull AppBarConfiguration configuration) {
+        super(toolbar.getContext(), configuration);
         mToolbarWeakReference = new WeakReference<>(toolbar);
     }
 
diff --git a/samples/Support7Demos/src/main/AndroidManifest.xml b/samples/Support7Demos/src/main/AndroidManifest.xml
index dbb3225..075a9e9 100644
--- a/samples/Support7Demos/src/main/AndroidManifest.xml
+++ b/samples/Support7Demos/src/main/AndroidManifest.xml
@@ -354,6 +354,16 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".app.AppCompatNightModeActivityConfigChanges"
+                  android:label="@string/mode_night_activity_config_changes_title"
+                  android:theme="@style/Theme.AppCompat.DayNight"
+                  android:configChanges="uiMode">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="com.example.android.supportv7.SAMPLE_CODE"/>
+            </intent-filter>
+        </activity>
+
         <activity android:name=".app.AppCompatNightModeDialog"
                   android:label="@string/mode_night_dialog_title"
                   android:theme="@style/Theme.AppCompat">
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeActivity.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeActivity.java
index 87707bd..ba25c0f 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeActivity.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeActivity.java
@@ -18,7 +18,10 @@
 
 
 import android.os.Bundle;
+import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
+import android.webkit.WebView;
 
 import androidx.annotation.Nullable;
 import androidx.appcompat.app.AppCompatActivity;
@@ -34,18 +37,35 @@
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.appcompat_night_mode);
+        setContentView(R.layout.appcompat_night_mode_activity);
+        refreshIndicator();
     }
 
     public void setModeNightNo(View view) {
         getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_NO);
+        refreshIndicator();
     }
 
     public void setModeNightYes(View view) {
         getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
+        refreshIndicator();
     }
 
     public void setModeNightAuto(View view) {
         getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_AUTO);
+        refreshIndicator();
+    }
+
+    public void loadWebView(View view) {
+        // Create a WebView, which will reset the Activity resources
+        WebView webView = new WebView(this);
+        refreshIndicator();
+    }
+
+    private void refreshIndicator() {
+        final ViewGroup indicatorParent = findViewById(R.id.night_mode_indicator_parent);
+        indicatorParent.removeAllViews();
+        LayoutInflater.from(getThemedContext())
+                .inflate(R.layout.appcompat_night_mode_indicator, indicatorParent);
     }
 }
\ No newline at end of file
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeActivityConfigChanges.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeActivityConfigChanges.java
new file mode 100644
index 0000000..6ab97fc
--- /dev/null
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeActivityConfigChanges.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.supportv7.app;
+
+
+/**
+ * This demonstrates idiomatic usage of AppCompatActivity with Theme.AppCompat.DayNight.
+ * The difference to AppCompatNightModeActivity is that this Activity is set to handle uiMode
+ * config changes in the manifest.
+ */
+public class AppCompatNightModeActivityConfigChanges extends AppCompatNightModeActivity {
+}
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java
index efbd1ea..72f68be 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeAlertDialog.java
@@ -33,7 +33,7 @@
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.appcompat_night_mode);
+        setContentView(R.layout.appcompat_night_mode_dialog);
     }
 
     public void setModeNightNo(View view) {
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeDialog.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeDialog.java
index 8d1fe32..62f3427 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeDialog.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/app/AppCompatNightModeDialog.java
@@ -33,7 +33,7 @@
     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        setContentView(R.layout.appcompat_night_mode);
+        setContentView(R.layout.appcompat_night_mode_dialog);
     }
 
     public void setModeNightNo(View view) {
diff --git a/samples/Support7Demos/src/main/res/layout/appcompat_night_mode.xml b/samples/Support7Demos/src/main/res/layout/appcompat_night_mode_activity.xml
similarity index 72%
rename from samples/Support7Demos/src/main/res/layout/appcompat_night_mode.xml
rename to samples/Support7Demos/src/main/res/layout/appcompat_night_mode_activity.xml
index 6039f60..53a0cd8 100644
--- a/samples/Support7Demos/src/main/res/layout/appcompat_night_mode.xml
+++ b/samples/Support7Demos/src/main/res/layout/appcompat_night_mode_activity.xml
@@ -40,21 +40,24 @@
                 android:text="@string/mode_night_auto"
                 android:onClick="setModeNightAuto"/>
 
-        <View
-            android:layout_width="match_parent"
-            android:layout_height="100dp" />
-
-        <TextView
-            android:id="@+id/text_night_mode"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/night_mode" />
+        <Button android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/mode_night_load_webview"
+                android:onClick="loadWebView"/>
 
         <View
-            android:id="@+id/view_background"
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:background="@drawable/test_night_color_conversion_background" />
+                android:layout_width="match_parent"
+                android:layout_height="100dp"/>
+
+        <FrameLayout
+                android:id="@+id/night_mode_indicator_parent"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+
+            <include layout="@layout/appcompat_night_mode_indicator"/>
+            <include layout="@layout/appcompat_night_mode_indicator"/>
+
+        </FrameLayout>
 
     </LinearLayout>
 
diff --git a/samples/Support7Demos/src/main/res/layout/appcompat_night_mode_dialog.xml b/samples/Support7Demos/src/main/res/layout/appcompat_night_mode_dialog.xml
new file mode 100644
index 0000000..185e345
--- /dev/null
+++ b/samples/Support7Demos/src/main/res/layout/appcompat_night_mode_dialog.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:orientation="vertical"
+                  android:padding="16dp">
+
+        <Button android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/mode_night_no"
+                android:onClick="setModeNightNo"/>
+
+        <Button android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/mode_night_yes"
+                android:onClick="setModeNightYes"/>
+
+        <Button android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/mode_night_auto"
+                android:onClick="setModeNightAuto"/>
+
+    </LinearLayout>
+
+</ScrollView>
\ No newline at end of file
diff --git a/samples/Support7Demos/src/main/res/layout/appcompat_night_mode_indicator.xml b/samples/Support7Demos/src/main/res/layout/appcompat_night_mode_indicator.xml
new file mode 100644
index 0000000..05c0d4c0
--- /dev/null
+++ b/samples/Support7Demos/src/main/res/layout/appcompat_night_mode_indicator.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="?android:attr/colorBackground"
+        android:padding="16dp"
+        android:orientation="vertical">
+
+    <TextView
+            android:id="@+id/text_night_mode"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/night_mode"/>
+
+    <View
+            android:id="@+id/view_background"
+            android:layout_width="100dp"
+            android:layout_height="100dp"
+            android:background="@drawable/test_night_color_conversion_background"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/samples/Support7Demos/src/main/res/values-notnight/strings.xml b/samples/Support7Demos/src/main/res/values-notnight/strings.xml
new file mode 100644
index 0000000..44e4b63
--- /dev/null
+++ b/samples/Support7Demos/src/main/res/values-notnight/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <string name="night_mode">NOT NIGHT</string>
+</resources>
diff --git a/samples/Support7Demos/src/main/res/values/strings.xml b/samples/Support7Demos/src/main/res/values/strings.xml
index d11e06b..ac3c2c5 100644
--- a/samples/Support7Demos/src/main/res/values/strings.xml
+++ b/samples/Support7Demos/src/main/res/values/strings.xml
@@ -217,7 +217,9 @@
     <string name="mode_night_yes">MODE_NIGHT_YES</string>
     <string name="mode_night_no">MODE_NIGHT_NO</string>
     <string name="mode_night_auto">MODE_NIGHT_AUTO</string>
+    <string name="mode_night_load_webview">Load WebView</string>
     <string name="mode_night_activity_title">AppCompat/DayNight/Activity Usage</string>
+    <string name="mode_night_activity_config_changes_title">AppCompat/DayNight/Activity Usage (handling configChanges)</string>
     <string name="mode_night_dialog_title">AppCompat/DayNight/Dialog Usage</string>
     <string name="mode_night_alertdialog_title">AppCompat/DayNight/AlertDialog Usage</string>
 
@@ -251,7 +253,7 @@
     <string name="simple_selection_demo_activity">RecyclerView Selection: Gesture Only</string>
     <string name="fancy_selection_demo_activity">RecyclerView Selection: Gesture and Pointer</string>
 
-    <string name="night_mode">DAY</string>
+    <string name="night_mode">DEFAULT</string>
 
     <string name="text_plain_enabled">Plain enabled</string>
     <string name="text_plain_disabled">Plain disabled</string>
diff --git a/samples/SupportCarDemos/src/main/java/com/example/androidx/car/TextListItemActivity.java b/samples/SupportCarDemos/src/main/java/com/example/androidx/car/TextListItemActivity.java
index 1bf52e4..b7b14f0 100644
--- a/samples/SupportCarDemos/src/main/java/com/example/androidx/car/TextListItemActivity.java
+++ b/samples/SupportCarDemos/src/main/java/com/example/androidx/car/TextListItemActivity.java
@@ -134,21 +134,37 @@
             actionItem.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon,
                     ActionListItem.PRIMARY_ACTION_ICON_SIZE_LARGE);
             actionItem.setTitle("single line with large icon and one action");
-            actionItem.setAction("Card Height", true, mGetParentHeight);
+            actionItem.setPrimaryAction("Card Height", false, mGetParentHeight);
             mItems.add(actionItem);
-            actionItem = new ActionListItem(mContext);
 
+            actionItem = new ActionListItem(mContext);
+            actionItem.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon,
+                    ActionListItem.PRIMARY_ACTION_ICON_SIZE_LARGE);
+            actionItem.setTitle("single line with large icon and one secondary action");
+            actionItem.setSecondaryAction("Card Height", true, mGetParentHeight);
+            mItems.add(actionItem);
+
+            actionItem = new ActionListItem(mContext);
             actionItem.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon,
                     ActionListItem.PRIMARY_ACTION_ICON_SIZE_LARGE);
             actionItem.setTitle("single line with large icon and one raised action");
-            actionItem.setAction("Card Height", false, mGetParentHeight);
+            actionItem.setPrimaryAction("Card Height", false, mGetParentHeight);
             actionItem.setActionBorderless(false);
             mItems.add(actionItem);
 
+            actionItem = new ActionListItem(mContext);
             actionItem.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon,
                     ActionListItem.PRIMARY_ACTION_ICON_SIZE_LARGE);
-            actionItem.setTitle("single line with large icon and one raised action with divider");
-            actionItem.setAction("Card Height", true, mGetParentHeight);
+            actionItem.setTitle("single line with large icon, divider, one raised action");
+            actionItem.setPrimaryAction("Card Height", true, mGetParentHeight);
+            actionItem.setActionBorderless(false);
+            mItems.add(actionItem);
+
+            actionItem = new ActionListItem(mContext);
+            actionItem.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon,
+                    ActionListItem.PRIMARY_ACTION_ICON_SIZE_LARGE);
+            actionItem.setTitle("single line with large icon, and one raised secondary action");
+            actionItem.setSecondaryAction("Card Height", false, mGetParentHeight);
             actionItem.setActionBorderless(false);
             mItems.add(actionItem);
 
@@ -190,7 +206,7 @@
 
             item = new TextListItem(mContext);
             item.setTitle("title is single line and ellipsizes. "
-                            + mContext.getString(R.string.long_text));
+                    + mContext.getString(R.string.long_text));
             item.setSupplementalIcon(android.R.drawable.sym_def_app_icon, true);
             mItems.add(item);
 
@@ -204,46 +220,38 @@
             actionItem = new ActionListItem(mContext);
             actionItem.setPrimaryActionNoIcon();
             actionItem.setTitle("single line with two actions and no divider");
-            actionItem.setActions("Action 1", false,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 1", Toast.LENGTH_SHORT).show(),
-                    "Action 2", false,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
+            actionItem.setPrimaryAction("Action 1", false,
+                    v -> Toast.makeText(v.getContext(), "Action 1", Toast.LENGTH_SHORT).show());
+            actionItem.setSecondaryAction("Action 2", false,
+                    v -> Toast.makeText(v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
             mItems.add(actionItem);
 
             actionItem = new ActionListItem(mContext);
             actionItem.setPrimaryActionNoIcon();
             actionItem.setTitle("single line with two raised actions and no divider");
-            actionItem.setActions("Action 1", false,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 1", Toast.LENGTH_SHORT).show(),
-                    "Action 2", false,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
+            actionItem.setPrimaryAction("Action 1", false,
+                    v -> Toast.makeText(v.getContext(), "Action 1", Toast.LENGTH_SHORT).show());
+            actionItem.setSecondaryAction("Action 2", false,
+                    v -> Toast.makeText(v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
             actionItem.setActionBorderless(false);
             mItems.add(actionItem);
 
             actionItem = new ActionListItem(mContext);
             actionItem.setPrimaryActionNoIcon();
             actionItem.setTitle("single line with two actions and Action 2 divider");
-            actionItem.setActions("Action 1", false,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 1", Toast.LENGTH_SHORT).show(),
-                    "Action 2", true,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
+            actionItem.setPrimaryAction("Action 1", false,
+                    v -> Toast.makeText(v.getContext(), "Action 1", Toast.LENGTH_SHORT).show());
+            actionItem.setSecondaryAction("Action 2", true,
+                    v -> Toast.makeText(v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
             mItems.add(actionItem);
 
             actionItem = new ActionListItem(mContext);
             actionItem.setPrimaryActionNoIcon();
             actionItem.setTitle("single line with two raised actions and Action 2 divider");
-            actionItem.setActions("Action 1", false,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 1", Toast.LENGTH_SHORT).show(),
-                    "Action 2", true,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
+            actionItem.setPrimaryAction("Action 1", false,
+                    v -> Toast.makeText(v.getContext(), "Action 1", Toast.LENGTH_SHORT).show());
+            actionItem.setSecondaryAction("Action 2", true,
+                    v -> Toast.makeText(v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
             actionItem.setActionBorderless(false);
             mItems.add(actionItem);
 
@@ -251,24 +259,20 @@
             actionItem.setPrimaryActionNoIcon();
             actionItem.setTitle("single line with divider between actions. "
                     + mContext.getString(R.string.long_text));
-            actionItem.setActions("Action 1", true,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 1", Toast.LENGTH_SHORT).show(),
-                    "Action 2", false,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
+            actionItem.setPrimaryAction("Action 1", true,
+                    v -> Toast.makeText(v.getContext(), "Action 1", Toast.LENGTH_SHORT).show());
+            actionItem.setSecondaryAction("Action 2", false,
+                    v -> Toast.makeText(v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
             mItems.add(actionItem);
 
             actionItem = new ActionListItem(mContext);
             actionItem.setPrimaryActionNoIcon();
             actionItem.setTitle("single line with divider between raised actions. "
                     + mContext.getString(R.string.long_text));
-            actionItem.setActions("Action 1", true,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 1", Toast.LENGTH_SHORT).show(),
-                    "Action 2", false,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
+            actionItem.setPrimaryAction("Action 1", true,
+                    v -> Toast.makeText(v.getContext(), "Action 1", Toast.LENGTH_SHORT).show());
+            actionItem.setSecondaryAction("Action 2", false,
+                    v -> Toast.makeText(v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
             actionItem.setActionBorderless(false);
             mItems.add(actionItem);
 
@@ -276,24 +280,20 @@
             actionItem.setPrimaryActionNoIcon();
             actionItem.setTitle("single line with both dividers for actions. "
                     + mContext.getString(R.string.long_text));
-            actionItem.setActions("Action 1", true,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 1", Toast.LENGTH_SHORT).show(),
-                    "Action 2", true,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
+            actionItem.setPrimaryAction("Action 1", true,
+                    v -> Toast.makeText(v.getContext(), "Action 1", Toast.LENGTH_SHORT).show());
+            actionItem.setSecondaryAction("Action 2", true,
+                    v -> Toast.makeText(v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
             mItems.add(actionItem);
 
             actionItem = new ActionListItem(mContext);
             actionItem.setPrimaryActionNoIcon();
             actionItem.setTitle("single line with both dividers for raised actions. "
                     + mContext.getString(R.string.long_text));
-            actionItem.setActions("Action 1", true,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 1", Toast.LENGTH_SHORT).show(),
-                    "Action 2", true,
-                    v -> Toast.makeText(
-                            v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
+            actionItem.setPrimaryAction("Action 1", true,
+                    v -> Toast.makeText(v.getContext(), "Action 1", Toast.LENGTH_SHORT).show());
+            actionItem.setSecondaryAction("Action 2", true,
+                    v -> Toast.makeText(v.getContext(), "Action 2", Toast.LENGTH_SHORT).show());
             actionItem.setActionBorderless(false);
             mItems.add(actionItem);
 
@@ -315,7 +315,7 @@
                     TextListItem.PRIMARY_ACTION_ICON_SIZE_SMALL);
             actionItem.setTitle("double line with small icon and one action");
             actionItem.setBody(mContext.getString(R.string.long_text));
-            actionItem.setAction("Card Height", true, mGetParentHeight);
+            actionItem.setPrimaryAction("Card Height", true, mGetParentHeight);
             mItems.add(actionItem);
 
             String tenChars = "Ten Chars.";
@@ -331,7 +331,7 @@
             actionItem.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon,
                     ActionListItem.PRIMARY_ACTION_ICON_SIZE_LARGE);
             actionItem.setBody("Only body - no title is set");
-            actionItem.setAction("Card Height", true, mGetParentHeight);
+            actionItem.setPrimaryAction("Card Height", true, mGetParentHeight);
             mItems.add(actionItem);
 
             item = new TextListItem(mContext);
@@ -344,10 +344,8 @@
             item.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon,
                     TextListItem.PRIMARY_ACTION_ICON_SIZE_SMALL);
             item.setTitle("Switch - initially unchecked");
-            item.setSwitch(false, true, (button, isChecked) -> {
-                Toast.makeText(mContext,
-                        isChecked ? "checked" : "unchecked", Toast.LENGTH_SHORT).show();
-            });
+            item.setSwitch(false, true, (button, isChecked) -> Toast.makeText(mContext,
+                    isChecked ? "checked" : "unchecked", Toast.LENGTH_SHORT).show());
             mItems.add(item);
 
             item = new TextListItem(mContext);
@@ -391,7 +389,7 @@
                 throw new RuntimeException("This item should not be clickable");
             });
             actionItem.setTitle("Disabled item");
-            actionItem.setAction("action", false, v -> {
+            actionItem.setPrimaryAction("action", false, v -> {
                 throw new RuntimeException("This button should not be clickable");
             });
             actionItem.setEnabled(false);
diff --git a/settings.gradle b/settings.gradle
index b169e0b..ec8c148 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -185,7 +185,6 @@
 
 includeProject(":legacy-support-core-ui", "legacy/core-ui")
 includeProject(":legacy-support-core-utils", "legacy/core-utils")
-includeProject(":legacy-preference-v14", "legacy/preference-v14")
 
 /////////////////////////////
 //
diff --git a/textclassifier/api/current.txt b/textclassifier/api/current.txt
index 2e6c474..11932f6 100644
--- a/textclassifier/api/current.txt
+++ b/textclassifier/api/current.txt
@@ -52,6 +52,7 @@
   }
 
   public final class TextClassificationManager {
+    method public androidx.textclassifier.TextClassifier getDefaultTextClassifier();
     method public androidx.textclassifier.TextClassifier getTextClassifier();
     method public static androidx.textclassifier.TextClassificationManager of(android.content.Context);
     method public void setTextClassifier(androidx.textclassifier.TextClassifier);
diff --git a/textclassifier/src/androidTest/java/androidx/textclassifier/TextClassificationManagerTest.java b/textclassifier/src/androidTest/java/androidx/textclassifier/TextClassificationManagerTest.java
index 629c4d7..7d8607d 100644
--- a/textclassifier/src/androidTest/java/androidx/textclassifier/TextClassificationManagerTest.java
+++ b/textclassifier/src/androidTest/java/androidx/textclassifier/TextClassificationManagerTest.java
@@ -100,6 +100,22 @@
                 .isInstanceOf(PlatformTextClassifier.class);
     }
 
+    @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.N_MR1)
+    @Test
+    public void testGetDefaultTextClassifier_preO() {
+        TextClassifier textClassifier = mTextClassificationManager.getDefaultTextClassifier();
+
+        assertThat(textClassifier).isInstanceOf(LegacyTextClassifier.class);
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    public void testGetDefaultTextClassifier_postO() {
+        TextClassifier textClassifier = mTextClassificationManager.getDefaultTextClassifier();
+
+        assertThat(textClassifier).isInstanceOf(PlatformTextClassifierWrapper.class);
+    }
+
     private static class DummyTextClassifier extends TextClassifier {
         DummyTextClassifier() {
             super();
diff --git a/textclassifier/src/main/java/androidx/textclassifier/TextClassificationManager.java b/textclassifier/src/main/java/androidx/textclassifier/TextClassificationManager.java
index 556c83e..afe155e 100644
--- a/textclassifier/src/main/java/androidx/textclassifier/TextClassificationManager.java
+++ b/textclassifier/src/main/java/androidx/textclassifier/TextClassificationManager.java
@@ -71,6 +71,12 @@
     /**
      * Returns the text classifier set through {@link #setTextClassifier(TextClassifier)},
      * a default text classifier is returned if it is not ever set, or a {@code null} is set.
+     * <p>
+     * If you are implementing a text classifier, and want to delegate requests to the default
+     * text classifier provided by this library, you may want to use
+     * {@link #getDefaultTextClassifier()} instead.
+     *
+     * @see #getDefaultTextClassifier()
      */
     @NonNull
     public TextClassifier getTextClassifier() {
@@ -124,4 +130,21 @@
         }
         return LegacyTextClassifier.of(context);
     }
+
+    /**
+     * Returns the default text classifier provided by this library.
+     * <p>
+     * This is mainly for text classifier implementation to delegate the request to the default
+     * text classifier. Otherwise, in most cases, you shuold consider
+     * {@link #getTextClassifier()} instead.
+     * <p>
+     * Note that the returned text classifier should be only used within the same context that is
+     * passed to {@link TextClassificationManager#of(Context)}.
+     *
+     * @see #getTextClassifier()
+     */
+    @NonNull
+    public TextClassifier getDefaultTextClassifier() {
+        return mDefaultTextClassifier;
+    }
 }
diff --git a/work/workmanager/proguard-rules.pro b/work/workmanager/proguard-rules.pro
index a861086..440b1f6 100644
--- a/work/workmanager/proguard-rules.pro
+++ b/work/workmanager/proguard-rules.pro
@@ -1,11 +1,11 @@
 -keep class * extends androidx.work.Worker
 -keep class * extends androidx.work.InputMerger
-# Keep all constructors on NonBlockingWorker, Worker (also marked with @Keep)
--keep public class * extends androidx.work.NonBlockingWorker {
+# Keep all constructors on ListenableWorker, Worker (also marked with @Keep)
+-keep public class * extends androidx.work.ListenableWorker {
     public <init>(...);
 }
-# We need to keep WorkParameters for the method descriptor of internalInit.
--keep class androidx.work.WorkParameters
+# We need to keep WorkerParameters for the ListenableWorker constructor
+-keep class androidx.work.WorkerParameters
 # We reflectively try and instantiate FirebaseJobScheduler when we find a Firebase dependency
 # on the classpath.
 -keep class androidx.work.impl.background.firebase.FirebaseJobScheduler
diff --git a/work/workmanager/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobServiceTest.java b/work/workmanager/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobServiceTest.java
index c3a1ee5..6d0a90c 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobServiceTest.java
+++ b/work/workmanager/src/androidTest/java/androidx/work/impl/background/systemjob/SystemJobServiceTest.java
@@ -19,8 +19,10 @@
 import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
 
 import static org.hamcrest.CoreMatchers.is;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doCallRealMethod;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
@@ -48,6 +50,8 @@
 import androidx.work.WorkRequest;
 import androidx.work.Worker;
 import androidx.work.WorkerParameters;
+import androidx.work.impl.Processor;
+import androidx.work.impl.Scheduler;
 import androidx.work.impl.WorkDatabase;
 import androidx.work.impl.WorkManagerImpl;
 import androidx.work.impl.model.WorkSpecDao;
@@ -59,6 +63,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Collections;
+import java.util.UUID;
 import java.util.concurrent.Executors;
 
 @RunWith(AndroidJUnit4.class)
@@ -66,8 +72,10 @@
 public class SystemJobServiceTest extends WorkManagerTest {
 
     private WorkManagerImpl mWorkManagerImpl;
+    private Processor mProcessor;
     private WorkDatabase mDatabase;
     private SystemJobService mSystemJobServiceSpy;
+    private Scheduler mScheduler;
 
     @Before
     public void setUp() {
@@ -94,13 +102,32 @@
         });
 
         Context context = InstrumentationRegistry.getTargetContext();
+        mDatabase = WorkDatabase.create(context, true);
+        InstantWorkTaskExecutor taskExecutor = new InstantWorkTaskExecutor();
         Configuration configuration = new Configuration.Builder()
                 .setExecutor(Executors.newSingleThreadExecutor())
                 .build();
-        mWorkManagerImpl =
-                new WorkManagerImpl(context, configuration, new InstantWorkTaskExecutor());
+        mScheduler = mock(Scheduler.class);
+        mProcessor = new Processor(
+                context,
+                configuration,
+                taskExecutor,
+                mDatabase,
+                Collections.singletonList(mScheduler));
+        mWorkManagerImpl = mock(WorkManagerImpl.class);
+        when(mWorkManagerImpl.getApplicationContext()).thenReturn(context);
+        when(mWorkManagerImpl.getConfiguration()).thenReturn(configuration);
+        when(mWorkManagerImpl.getProcessor()).thenReturn(mProcessor);
+        when(mWorkManagerImpl.getWorkDatabase()).thenReturn(mDatabase);
+        when(mWorkManagerImpl.getSchedulers()).thenReturn(Collections.singletonList(mScheduler));
+        when(mWorkManagerImpl.getWorkTaskExecutor()).thenReturn(taskExecutor);
+        // Delegate to the underlying implementations of methods used in tests.
+        doCallRealMethod().when(mWorkManagerImpl).cancelWorkById(any(UUID.class));
+        doCallRealMethod().when(mWorkManagerImpl).startWork(anyString());
+        doCallRealMethod().when(mWorkManagerImpl).startWork(anyString(),
+                any(WorkerParameters.RuntimeExtras.class));
+        doCallRealMethod().when(mWorkManagerImpl).stopWork(anyString());
         WorkManagerImpl.setDelegate(mWorkManagerImpl);
-        mDatabase = mWorkManagerImpl.getWorkDatabase();
         mSystemJobServiceSpy = spy(new SystemJobService());
         doNothing().when(mSystemJobServiceSpy).onExecuted(anyString(), anyBoolean());
         mSystemJobServiceSpy.onCreate();
diff --git a/work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java b/work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java
index 4f64d07..44b9f73 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/WorkManagerImpl.java
@@ -76,6 +76,8 @@
     private Context mContext;
     private Configuration mConfiguration;
     private WorkDatabase mWorkDatabase;
+    // Always use getWorkTaskExecutor() so they can be mocked in tests.
+    // TODO(rahulrav@) - Revisit constructors for WorkManagerImpl to clean this part up.
     private TaskExecutor mWorkTaskExecutor;
     private List<Scheduler> mSchedulers;
     private Processor mProcessor;
@@ -334,28 +336,28 @@
     @Override
     public ListenableFuture<Void> cancelWorkById(@NonNull UUID id) {
         CancelWorkRunnable runnable = CancelWorkRunnable.forId(id, this);
-        mWorkTaskExecutor.executeOnBackgroundThread(runnable);
+        getWorkTaskExecutor().executeOnBackgroundThread(runnable);
         return runnable.getFuture();
     }
 
     @Override
     public ListenableFuture<Void> cancelAllWorkByTag(@NonNull final String tag) {
         CancelWorkRunnable runnable = CancelWorkRunnable.forTag(tag, this);
-        mWorkTaskExecutor.executeOnBackgroundThread(runnable);
+        getWorkTaskExecutor().executeOnBackgroundThread(runnable);
         return runnable.getFuture();
     }
 
     @Override
     public ListenableFuture<Void> cancelUniqueWork(@NonNull String uniqueWorkName) {
         CancelWorkRunnable runnable = CancelWorkRunnable.forName(uniqueWorkName, this, true);
-        mWorkTaskExecutor.executeOnBackgroundThread(runnable);
+        getWorkTaskExecutor().executeOnBackgroundThread(runnable);
         return runnable.getFuture();
     }
 
     @Override
     public ListenableFuture<Void> cancelAllWork() {
         CancelWorkRunnable runnable = CancelWorkRunnable.forAll(this);
-        mWorkTaskExecutor.executeOnBackgroundThread(runnable);
+        getWorkTaskExecutor().executeOnBackgroundThread(runnable);
         return runnable.getFuture();
     }
 
@@ -370,7 +372,7 @@
         final SettableFuture<Long> future = SettableFuture.create();
         // Avoiding synthetic accessors.
         final Preferences preferences = mPreferences;
-        mWorkTaskExecutor.executeOnBackgroundThread(new Runnable() {
+        getWorkTaskExecutor().executeOnBackgroundThread(new Runnable() {
             @Override
             public void run() {
                 try {
@@ -386,7 +388,7 @@
     @Override
     public ListenableFuture<Void> pruneWork() {
         PruneWorkRunnable runnable = new PruneWorkRunnable(this);
-        mWorkTaskExecutor.executeOnBackgroundThread(runnable);
+        getWorkTaskExecutor().executeOnBackgroundThread(runnable);
         return runnable.getFuture();
     }
 
@@ -406,13 +408,13 @@
                         return workStatus;
                     }
                 },
-                mWorkTaskExecutor);
+                getWorkTaskExecutor());
     }
 
     @Override
     public @NonNull ListenableFuture<WorkStatus> getStatusById(@NonNull UUID id) {
         StatusRunnable<WorkStatus> runnable = StatusRunnable.forUUID(this, id);
-        mWorkTaskExecutor.getBackgroundExecutor().execute(runnable);
+        getWorkTaskExecutor().getBackgroundExecutor().execute(runnable);
         return runnable.getFuture();
     }
 
@@ -424,13 +426,13 @@
         return LiveDataUtils.dedupedMappedLiveDataFor(
                 inputLiveData,
                 WorkSpec.WORK_STATUS_MAPPER,
-                mWorkTaskExecutor);
+                getWorkTaskExecutor());
     }
 
     @Override
     public @NonNull ListenableFuture<List<WorkStatus>> getStatusesByTag(@NonNull String tag) {
         StatusRunnable<List<WorkStatus>> runnable = StatusRunnable.forTag(this, tag);
-        mWorkTaskExecutor.getBackgroundExecutor().execute(runnable);
+        getWorkTaskExecutor().getBackgroundExecutor().execute(runnable);
         return runnable.getFuture();
     }
 
@@ -443,7 +445,7 @@
         return LiveDataUtils.dedupedMappedLiveDataFor(
                 inputLiveData,
                 WorkSpec.WORK_STATUS_MAPPER,
-                mWorkTaskExecutor);
+                getWorkTaskExecutor());
     }
 
     @Override
@@ -451,7 +453,7 @@
     public ListenableFuture<List<WorkStatus>> getStatusesForUniqueWork(@NonNull String name) {
         StatusRunnable<List<WorkStatus>> runnable =
                 StatusRunnable.forUniqueWork(this, name);
-        mWorkTaskExecutor.getBackgroundExecutor().execute(runnable);
+        getWorkTaskExecutor().getBackgroundExecutor().execute(runnable);
         return runnable.getFuture();
     }
 
@@ -462,7 +464,7 @@
         return LiveDataUtils.dedupedMappedLiveDataFor(
                 inputLiveData,
                 WorkSpec.WORK_STATUS_MAPPER,
-                mWorkTaskExecutor);
+                getWorkTaskExecutor());
     }
 
     /**
@@ -481,8 +483,9 @@
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public void startWork(String workSpecId, WorkerParameters.RuntimeExtras runtimeExtras) {
-        mWorkTaskExecutor.executeOnBackgroundThread(
-                new StartWorkRunnable(this, workSpecId, runtimeExtras));
+        getWorkTaskExecutor()
+                .executeOnBackgroundThread(
+                        new StartWorkRunnable(this, workSpecId, runtimeExtras));
     }
 
     /**
@@ -491,7 +494,7 @@
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public void stopWork(String workSpecId) {
-        mWorkTaskExecutor.executeOnBackgroundThread(new StopWorkRunnable(this, workSpecId));
+        getWorkTaskExecutor().executeOnBackgroundThread(new StopWorkRunnable(this, workSpecId));
     }
 
     /**
diff --git a/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java b/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java
index 149b54c..a6f12b1 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/WorkerWrapper.java
@@ -54,6 +54,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
+import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
 
 /**
@@ -89,6 +90,10 @@
 
     private @NonNull SettableFuture<Boolean> mFuture = SettableFuture.create();
 
+    // Package-private for synthetic accessor.
+    @Nullable ListenableFuture<ListenableWorker.Payload> mInnerFuture = null;
+
+
     private volatile boolean mInterrupted;
 
     // Package-private for synthetic accessor.
@@ -217,9 +222,8 @@
                         @Override
                         public void run() {
                             try {
-                                final ListenableFuture<ListenableWorker.Payload> innerFuture =
-                                        mWorker.onStartWork();
-                                future.setFuture(innerFuture);
+                                mInnerFuture = mWorker.onStartWork();
+                                future.setFuture(mInnerFuture);
                             } catch (Throwable e) {
                                 future.setException(e);
                             }
@@ -234,7 +238,10 @@
                 public void run() {
                     try {
                         mPayload = future.get();
-                    } catch (InterruptedException | ExecutionException exception) {
+                    } catch (CancellationException | InterruptedException | ExecutionException
+                            exception) {
+                        // We need to handle CancellationExceptions here because innerFuture
+                        // cancellations will bubble up, and we need to gracefully handle that.
                         Logger.error(TAG,
                                 String.format("%s failed because it threw an exception/error",
                                         workDescription),
@@ -301,6 +308,14 @@
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     public void interrupt(boolean cancelled) {
         mInterrupted = true;
+        // Resolve WorkerWrapper's future so we do the right thing and setup a reschedule
+        // if necessary. mInterrupted is always true here, we don't really care about the return
+        // value.
+        tryCheckForInterruptionAndResolve();
+        if (mInnerFuture != null) {
+            // Propagate the cancellations to the inner future.
+            mInnerFuture.cancel(true);
+        }
         // Worker can be null if run() hasn't been called yet.
         if (mWorker != null) {
             mWorker.stop(cancelled);