Merge "Add a utility method to hide the focus" into sc-dev
diff --git a/car-assist-lib/src/com/android/car/assist/CarVoiceInteractionSession.java b/car-assist-lib/src/com/android/car/assist/CarVoiceInteractionSession.java
index b66f5eb..8e5fef2 100644
--- a/car-assist-lib/src/com/android/car/assist/CarVoiceInteractionSession.java
+++ b/car-assist-lib/src/com/android/car/assist/CarVoiceInteractionSession.java
@@ -23,6 +23,7 @@
 import android.service.voice.VoiceInteractionSession;
 
 import androidx.annotation.StringDef;
+import androidx.core.app.NotificationManagerCompat;
 
 import com.android.car.assist.payloadhandlers.NotificationPayloadHandler;
 import com.android.car.messenger.common.Conversation;
@@ -43,18 +44,25 @@
     public static final String KEY_EXCEPTION = "KEY_EXCEPTION";
 
     /**
-     * The key used for the {@link CarVoiceInteractionSession#VOICE_ACTION_HANDLE_EXCEPTION}
-     * payload
+     * The key used for the {@link CarVoiceInteractionSession#VOICE_ACTION_HANDLE_EXCEPTION} payload
      * {@link Bundle}. Must map to a boolean. If value is true, the Fallback Assistant that can
-     * handle
-     * the user's request has been disabled.
+     * handle the user's request has been disabled.
      */
     public static final String KEY_FALLBACK_ASSISTANT_ENABLED = "KEY_FALLBACK_ASSISTANT_ENABLED";
 
     /**
+     * The key used for a substitute package name the Digital Assistant should read out in lieu of
+     * package name associated with the {@link StatusBarNotification}.
+     *
+     * <p>Only system packages which lump together a bunch of unrelated stuff may substitute a
+     * different name to make the purpose of the notification more clear. The correct package label
+     * should always be accessible via SystemUI.
+     */
+    public static final String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
+
+    /**
      * The key used for the payload {@link Bundle}, if a {@link StatusBarNotification} is used as
-     * the
-     * payload.
+     * the payload.
      */
     public static final String KEY_NOTIFICATION = "KEY_NOTIFICATION";
 
@@ -68,39 +76,36 @@
     public static final String VOICE_ACTION_NO_ACTION = "VOICE_ACTION_NO_ACTION";
 
     /**
-     * Indicates to assistant that a read action is being requested for a given payload.
-     * A {@link StatusBarNotification} object will be provided in the payload
+     * Indicates to assistant that a read action is being requested for a given payload. A {@link
+     * StatusBarNotification} object will be provided in the payload
      */
     public static final String VOICE_ACTION_READ_NOTIFICATION = "VOICE_ACTION_READ_NOTIFICATION";
 
     /**
-     * Indicates to assistant that a reply action is being requested for a given payload.
-     * A {@link StatusBarNotification} object will be provided in the payload
+     * Indicates to assistant that a reply action is being requested for a given payload. A {@link
+     * StatusBarNotification} object will be provided in the payload
      */
     public static final String VOICE_ACTION_REPLY_NOTIFICATION = "VOICE_ACTION_REPLY_NOTIFICATION";
 
     /**
-     * Indicates to assistant that a read conversation action is being requested.
-     * A {@link Conversation} object will be provided in the payload.
+     * Indicates to assistant that a read conversation action is being requested. A {@link
+     * Conversation} object will be provided in the payload.
      */
     public static final String VOICE_ACTION_READ_CONVERSATION = "VOICE_ACTION_READ_CONVERSATION";
 
     /**
-     * Indicates to assistant that a reply conversation action is being requested.
-     * A {@link Conversation} object will be provided in the payload.
+     * Indicates to assistant that a reply conversation action is being requested. A {@link
+     * Conversation} object will be provided in the payload.
      */
     public static final String VOICE_ACTION_REPLY_CONVERSATION = "VOICE_ACTION_REPLY_CONVERSATION";
 
     /**
      * Indicates to digital assistant that it should capture a SMS message from the user,
-     * potentially
-     * finding which contact to send the message to and which device to send the message from
-     * (only if the application does not send the digital assistant this information in the
-     * bundle).
-     * Once the digital assistant has gathered the information from the user, it should send back
-     * the PendingIntent (provided in the bundle) with the information so the application can
-     * actually
-     * send the SMS.
+     * potentially finding which contact to send the message to and which device to send the message
+     * from (only if the application does not send the digital assistant this information in the
+     * bundle). Once the digital assistant has gathered the information from the user, it should
+     * send back the PendingIntent (provided in the bundle) with the information so the application
+     * can actually send the SMS.
      */
     public static final String VOICE_ACTION_SEND_SMS = "VOICE_ACTION_SEND_SMS";
 
@@ -112,8 +117,8 @@
 
     /**
      * Recipient's name. If this and the recipient phone number are not provided by the application,
-     * digital assistant must do contact disambiguation but is not required to add the name
-     * to the PendingIntent.
+     * digital assistant must do contact disambiguation but is not required to add the name to the
+     * PendingIntent.
      */
     public static final String KEY_RECIPIENT_NAME = "KEY RECIPIENT NAME";
 
@@ -151,8 +156,7 @@
 
     /** The list of exceptions the active voice service must handle. */
     @StringDef({EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING})
-    public @interface ExceptionValue {
-    }
+    public @interface ExceptionValue {}
 
     /**
      * Indicates to assistant that it is missing the Notification Listener permission, and should
@@ -184,7 +188,8 @@
     @Override
     public final void onShow(Bundle args, int showFlags) {
         super.onShow(args, showFlags);
-        if (args != null && isCarNotificationSource(showFlags)) {
+        addNotificationAccessExceptionIfNeeded(args);
+        if (args != null) {
             String action = getRequestedVoiceAction(args);
             if (!VOICE_ACTION_NO_ACTION.equals(action)) {
                 onShow(action, args, showFlags);
@@ -197,25 +202,53 @@
     /**
      * Called when the session UI is going to be shown. This is called after {@link
      * #onCreateContentView} (if the session's content UI needed to be created) and immediately
-     * prior
-     * to the window being shown. This may be called while the window is already shown, if a show
-     * request has come in while it is shown, to allow you to update the UI to match the new show
-     * arguments.
+     * prior to the window being shown. This may be called while the window is already shown, if a
+     * show request has come in while it is shown, to allow you to update the UI to match the new
+     * show arguments.
      *
      * @param action The action that is being requested for this session (e.g. {@link
-     *               CarVoiceInteractionSession#VOICE_ACTION_READ_NOTIFICATION}, {@link
-     *               CarVoiceInteractionSession#VOICE_ACTION_REPLY_NOTIFICATION}).
-     * @param args   The arguments that were supplied to {@link VoiceInteractionService#showSession
-     *               VoiceInteractionService.showSession}.
-     * @param flags  The show flags originally provided to
-     * {@link VoiceInteractionService#showSession
-     *               VoiceInteractionService.showSession}.
+     *     CarVoiceInteractionSession#VOICE_ACTION_READ_NOTIFICATION}, {@link
+     *     CarVoiceInteractionSession#VOICE_ACTION_REPLY_NOTIFICATION}).
+     * @param args The arguments that were supplied to {@link VoiceInteractionService#showSession
+     *     VoiceInteractionService.showSession}.
+     * @param flags The show flags originally provided to {@link VoiceInteractionService#showSession
+     *     VoiceInteractionService.showSession}.
      */
     protected abstract void onShow(String action, Bundle args, int flags);
 
-    /** Returns true if the request was initiated for a car notification. */
-    private static boolean isCarNotificationSource(int flags) {
-        return (flags & SHOW_SOURCE_NOTIFICATION) != 0;
+    /**
+     * Transforms bundle to {@link KEY_EXCEPTION} with
+     * value {@link EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING} if
+     * Notification Listener permissions are missing.
+     */
+    private void addNotificationAccessExceptionIfNeeded(Bundle args) {
+      if (needsNotificationAccess(args)) {
+              args.putString(KEY_ACTION, VOICE_ACTION_HANDLE_EXCEPTION);
+              args.putString(KEY_EXCEPTION, EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING);
+              args.putBoolean(KEY_FALLBACK_ASSISTANT_ENABLED, false);
+      }
+    }
+
+    private boolean needsNotificationAccess(Bundle args) {
+      return isNotificationAction(args) && !hasNotificationAccess(getContext());
+    }
+
+    /**
+     * Returns {@code true} if the given {@code args} is a notification action, {@code false}
+     * otherwise
+     */
+    private static boolean isNotificationAction(Bundle args) {
+        if (args == null) {
+          return false;
+        }
+        String action = args.getString(KEY_ACTION);
+        return VOICE_ACTION_REPLY_NOTIFICATION.equals(action)
+            || VOICE_ACTION_READ_NOTIFICATION.equals(action);
+    }
+
+    private boolean hasNotificationAccess(Context context) {
+        return NotificationManagerCompat
+            .getEnabledListenerPackages(context).contains(context.getPackageName());
     }
 
     /**
diff --git a/car-media-common/src/com/android/car/media/common/MediaButtonController.java b/car-media-common/src/com/android/car/media/common/MediaButtonController.java
index 1341507..1db7a31 100644
--- a/car-media-common/src/com/android/car/media/common/MediaButtonController.java
+++ b/car-media-common/src/com/android/car/media/common/MediaButtonController.java
@@ -88,6 +88,9 @@
                 R.id.circular_progress_bar);
         mPlayPauseStopImageView.setAction(PlayPauseStopImageView.ACTION_DISABLED);
         mPlayPauseStopImageView.setOnClickListener(this::onPlayPauseStopClicked);
+        // In non-touch mode, a browse list will request focus explicitly and its first element
+        // will get focused instead of this button
+        mPlayPauseStopImageView.setFocusedByDefault(true);
 
         mShowCircularProgressBar = context.getResources().getBoolean(
                 R.bool.show_circular_progress_bar);
diff --git a/car-telephony-common/src/com/android/car/telephony/common/Contact.java b/car-telephony-common/src/com/android/car/telephony/common/Contact.java
index 180ae6b..f40a566 100644
--- a/car-telephony-common/src/com/android/car/telephony/common/Contact.java
+++ b/car-telephony-common/src/com/android/car/telephony/common/Contact.java
@@ -688,7 +688,7 @@
             return Integer.compare(type, otherType);
         }
         Locale currentLocale = Locale.getDefault();
-        if (mCollator == null || mLocale.equals(currentLocale)) {
+        if (mCollator == null || mLocale == null || !mLocale.equals(currentLocale)) {
             mCollator = Collator.getInstance(currentLocale);
             mLocale = currentLocale;
         }
diff --git a/car-telephony-common/tests/robotests/src/com/android/car/telephony/common/ContactTest.java b/car-telephony-common/tests/robotests/src/com/android/car/telephony/common/ContactTest.java
index 8091f42..4825895 100644
--- a/car-telephony-common/tests/robotests/src/com/android/car/telephony/common/ContactTest.java
+++ b/car-telephony-common/tests/robotests/src/com/android/car/telephony/common/ContactTest.java
@@ -38,7 +38,6 @@
 import java.util.Collections;
 import java.util.List;
 
-
 @RunWith(RobolectricTestRunner.class)
 public class ContactTest {
 
diff --git a/car-ui-lib/car-rotary-lib/OWNERS b/car-ui-lib/car-rotary-lib/OWNERS
index 2d2eaee..0439586 100644
--- a/car-ui-lib/car-rotary-lib/OWNERS
+++ b/car-ui-lib/car-rotary-lib/OWNERS
@@ -1 +1 @@
-include platform/packages/apps/Car/RotaryController/OWNERS
\ No newline at end of file
+include platform/packages/apps/Car/RotaryController:/OWNERS
\ No newline at end of file
diff --git a/car-ui-lib/car-ui-lib/build.gradle b/car-ui-lib/car-ui-lib/build.gradle
index b7368d8..478a739 100644
--- a/car-ui-lib/car-ui-lib/build.gradle
+++ b/car-ui-lib/car-ui-lib/build.gradle
@@ -83,14 +83,6 @@
     api "androidx.asynclayoutinflater:asynclayoutinflater:1.0.0"
     implementation 'com.android.support:support-annotations:28.0.0'
 
-    testImplementation "androidx.test.ext:junit:1.1.2"
-    testImplementation 'org.robolectric:robolectric:4.3.1'
-    testImplementation "org.mockito:mockito-core:2.19.0"
-    testImplementation "com.google.truth:truth:1.1.2"
-    testImplementation "org.testng:testng:6.9.9"
-    // Required for local unit tests (JUnit 4 framework)
-    testImplementation 'junit:junit:4.13.2'
-
     androidTestImplementation 'org.hamcrest:hamcrest-library:1.3'
     androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
     androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.3.0'
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/AndroidManifest.xml b/car-ui-lib/car-ui-lib/src/androidTest/AndroidManifest.xml
index 675f5bc..21c8813 100644
--- a/car-ui-lib/car-ui-lib/src/androidTest/AndroidManifest.xml
+++ b/car-ui-lib/car-ui-lib/src/androidTest/AndroidManifest.xml
@@ -18,6 +18,8 @@
           package="com.android.car.ui.test">
     <application android:debuggable="true" android:theme="@style/Theme.CarUi.NoToolbar">
         <uses-library android:name="android.test.runner" />
+        <activity android:name="com.android.car.ui.TrulyEmptyActivity"
+            android:theme="@android:style/Theme.Material.NoActionBar"/>
         <activity android:name="com.android.car.ui.TestActivity" />
         <activity android:name="com.android.car.ui.recyclerview.CarUiRecyclerViewTestActivity" />
         <activity android:name="com.android.car.ui.imewidescreen.CarUiImeWideScreenTestActivity" />
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/TrulyEmptyActivity.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/TrulyEmptyActivity.java
new file mode 100644
index 0000000..6085f6c
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/TrulyEmptyActivity.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.ui;
+
+import android.app.Activity;
+
+/**
+ * An empty activity used for testing
+ */
+public class TrulyEmptyActivity extends Activity {
+}
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/core/CarUiTest.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/core/CarUiTest.java
new file mode 100644
index 0000000..34b082a
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/core/CarUiTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.ui.core;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+
+import com.android.car.ui.test.R;
+
+import org.junit.Test;
+
+/** A test for {@link com.android.car.ui.core.CarUi} */
+public class CarUiTest {
+
+    @Test
+    public void test_findCarUiComponentById_returnsNullWithNullInput() {
+        assertNull(CarUi.findCarUiComponentById(null, R.id.car_ui_recycler_view));
+    }
+
+    @Test
+    public void test_requireCarUiComponentById_throwsWithNullInput() {
+        assertThrows(NullPointerException.class,
+                () -> CarUi.requireCarUiComponentById(null, R.id.car_ui_recycler_view));
+    }
+}
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/preference/PreferenceTest.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/preference/PreferenceTest.java
index 1a3d1cd..0866334 100644
--- a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/preference/PreferenceTest.java
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/preference/PreferenceTest.java
@@ -19,6 +19,7 @@
 import static androidx.test.espresso.Espresso.onView;
 import static androidx.test.espresso.action.ViewActions.click;
 import static androidx.test.espresso.action.ViewActions.typeText;
+import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
 import static androidx.test.espresso.assertion.ViewAssertions.matches;
 import static androidx.test.espresso.matcher.ViewMatchers.isChecked;
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
@@ -43,7 +44,10 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.AlertDialog;
+import android.content.DialogInterface;
 import android.content.res.Resources;
+import android.view.View;
 
 import androidx.preference.CheckBoxPreference;
 import androidx.preference.DropDownPreference;
@@ -790,7 +794,7 @@
         preference.setKey("editText");
         preference.setTitle(R.string.title_edit_text_preference);
         preference.setOrder(0);
-        CharSequence positiveButtonText = "Ok";
+        String positiveButtonText = "Ok";
         preference.setPositiveButtonText(positiveButtonText);
         preference.setDialogTitle(R.string.dialog_title_edit_text_preference);
         preference.setSummaryProvider(EditTextPreference.SimpleSummaryProvider.getInstance());
@@ -805,12 +809,12 @@
         onView(withText(R.string.dialog_title_edit_text_preference)).check(matches(isDisplayed()));
 
         // Enter value
-        CharSequence value = "test value";
-        onView(withId(android.R.id.edit)).perform(typeText(value.toString()));
-        onView(withText(positiveButtonText.toString())).perform(click());
+        String value = "test value";
+        onView(withId(android.R.id.edit)).perform(typeText(value));
+        onView(withText(positiveButtonText)).perform(click());
 
         // Confirm value updated by simple summary provider
-        onView(withText(value.toString())).check(matches(isDisplayed()));
+        onView(withText(value)).check(matches(isDisplayed()));
     }
 
     @Test
@@ -849,9 +853,9 @@
         preference.setKey("seek_bar");
         preference.setTitle(R.string.title_seek_bar_preference);
         preference.setOrder(0);
-        CharSequence positiveButtonText = "Ok";
+        String positiveButtonText = "Ok";
         preference.setPositiveButtonText(positiveButtonText);
-        CharSequence negativeButtonText = "Cancel";
+        String negativeButtonText = "Cancel";
         preference.setNegativeButtonText(negativeButtonText);
         preference.setDialogTitle(R.string.dialog_title_seek_bar_preference);
         preference.setMaxProgress(20);
@@ -863,8 +867,8 @@
         // Click on preference
         onView(withText(R.string.title_seek_bar_preference)).perform(click());
         onView(withText(R.string.dialog_title_seek_bar_preference)).check(matches(isDisplayed()));
-        onView(withText(positiveButtonText.toString())).check(matches(isDisplayed()));
-        onView(withText(negativeButtonText.toString())).check(matches(isDisplayed()));
+        onView(withText(positiveButtonText)).check(matches(isDisplayed()));
+        onView(withText(negativeButtonText)).check(matches(isDisplayed()));
 
         // Confirm progress is set to 0
         assertEquals(0, preference.getProgress());
@@ -877,16 +881,91 @@
     }
 
     @Test
+    public void testSeekBarPreference_clickOk_valueSaved() {
+        // Create CarUiSeekBarDialogPreference preference and add it to screen.
+        CarUiSeekBarDialogPreference preference = new CarUiSeekBarDialogPreference(mActivity);
+        preference.setKey("seek_bar");
+        preference.setTitle(R.string.title_seek_bar_preference);
+        preference.setOrder(0);
+        String positiveButtonText = "Ok";
+        preference.setPositiveButtonText(positiveButtonText);
+        String negativeButtonText = "Cancel";
+        preference.setNegativeButtonText(negativeButtonText);
+        preference.setDialogTitle(R.string.dialog_title_seek_bar_preference);
+        preference.setMaxProgress(20);
+        mActivity.addPreference(preference);
+
+        // Check title is displayed as expected.
+        onView(withText(R.string.title_seek_bar_preference)).check(matches(isDisplayed()));
+
+        // Click on preference, set progress, then hit ok
+        onView(withText(R.string.title_seek_bar_preference)).perform(click());
+        onView(withId(R.id.seek_bar)).perform(setProgress(10));
+        onView(withText(positiveButtonText)).perform(click());
+        onView(withText(R.string.dialog_title_seek_bar_preference)).check(doesNotExist());
+
+        // Confirm progress is set to 0
+        assertEquals(10, preference.getProgress());
+        assertEquals(20, preference.getMaxProgress());
+    }
+
+    @Test
+    public void testSeekBarPreference_clickCancel_valueNotSaved() {
+        // Create CarUiSeekBarDialogPreference preference and add it to screen.
+        CarUiSeekBarDialogPreference preference = new CarUiSeekBarDialogPreference(mActivity);
+        preference.setKey("seek_bar");
+        preference.setTitle(R.string.title_seek_bar_preference);
+        preference.setOrder(0);
+        String positiveButtonText = "Ok";
+        preference.setPositiveButtonText(positiveButtonText);
+        String negativeButtonText = "Cancel";
+        preference.setNegativeButtonText(negativeButtonText);
+        preference.setDialogTitle(R.string.dialog_title_seek_bar_preference);
+        preference.setMaxProgress(20);
+        mActivity.addPreference(preference);
+
+        // Check title is displayed as expected.
+        onView(withText(R.string.title_seek_bar_preference)).check(matches(isDisplayed()));
+
+        // Click on preference, set progress, then hit cancel
+        onView(withText(R.string.title_seek_bar_preference)).perform(click());
+        onView(withId(R.id.seek_bar)).perform(setProgress(10));
+        onView(withText(negativeButtonText)).perform(click());
+        onView(withText(R.string.dialog_title_seek_bar_preference)).check(doesNotExist());
+
+        // Confirm progress is set to 0
+        assertEquals(0, preference.getProgress());
+        assertEquals(20, preference.getMaxProgress());
+    }
+
+    @Test
+    public void test_defaultDialogFragmentCallbacks_doNothing() {
+        DialogFragmentCallbacks callbacks = new DialogFragmentCallbacks() {
+        };
+
+        callbacks.onBindDialogView(new View(mActivity));
+        callbacks.onClick(new DialogInterface() {
+            @Override
+            public void cancel() {
+            }
+
+            @Override
+            public void dismiss() {
+            }
+        }, 0);
+        callbacks.onDialogClosed(true);
+        callbacks.onPrepareDialogBuilder(new AlertDialog.Builder(mActivity));
+    }
+
+    @Test
     public void testSeekBarPreference_uxRestricted() {
         // Create CarUiSeekBarDialogPreference preference and add it to screen.
         CarUiSeekBarDialogPreference preference = new CarUiSeekBarDialogPreference(mActivity);
         preference.setKey("seek_bar");
         preference.setTitle(R.string.title_seek_bar_preference);
         preference.setOrder(0);
-        CharSequence positiveButtonText = "Ok";
-        preference.setPositiveButtonText(positiveButtonText);
-        CharSequence negativeButtonText = "Cancel";
-        preference.setNegativeButtonText(negativeButtonText);
+        preference.setPositiveButtonText("Ok");
+        preference.setNegativeButtonText("Cancel");
         preference.setDialogTitle(R.string.dialog_title_seek_bar_preference);
         preference.setMaxProgress(20);
         preference.setUxRestricted(true);
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/preference/PreferenceTestFragment.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/preference/PreferenceTestFragment.java
index 3797913..631911d 100644
--- a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/preference/PreferenceTestFragment.java
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/preference/PreferenceTestFragment.java
@@ -56,6 +56,7 @@
      */
     public static class TestDataStore extends PreferenceDataStore {
 
+        private final Map<String, Integer> mIntStore = new HashMap<>();
         private final Map<String, String> mStringStore = new HashMap<>();
         private final Map<String, Boolean> mBooleanStore = new HashMap<>();
         private final Map<String, Set<String>> mStringSetStore = new HashMap<>();
@@ -95,5 +96,15 @@
         public boolean getBoolean(String key, boolean defValue) {
             return mBooleanStore.getOrDefault(key, defValue);
         }
+
+        @Override
+        public void putInt(String key, int value) {
+            mIntStore.put(key, value);
+        }
+
+        @Override
+        public int getInt(String key, int defValue) {
+            return mIntStore.getOrDefault(key, defValue);
+        }
     }
 }
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/recyclerview/DelegatingContentLimitingAdapterTest.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/recyclerview/DelegatingContentLimitingAdapterTest.java
index 3908df8..b3ad0c1 100644
--- a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/recyclerview/DelegatingContentLimitingAdapterTest.java
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/recyclerview/DelegatingContentLimitingAdapterTest.java
@@ -21,12 +21,16 @@
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.matcher.ViewMatchers.withText;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 import android.view.View;
 
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.OrientationHelper;
+import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
 import androidx.test.core.app.ActivityScenario;
 import androidx.test.ext.junit.rules.ActivityScenarioRule;
 
@@ -36,6 +40,7 @@
 import org.junit.Rule;
 import org.junit.Test;
 
+import java.util.ArrayList;
 import java.util.Objects;
 
 public class DelegatingContentLimitingAdapterTest {
@@ -127,4 +132,150 @@
 
         onView(withText(mDelegateAdapter.getItemText(15))).check(matches(isDisplayed()));
     }
+
+    @Test
+    public void testChangeItem_callsObservers() {
+        mDelegateAdapter = new TestDelegatingContentLimitingAdapter(50);
+        mContentLimitingAdapter = new DelegatingContentLimitingAdapter<>(mDelegateAdapter, 1);
+
+        AdapterDataObserver observer = mock(AdapterDataObserver.class);
+        mContentLimitingAdapter.registerAdapterDataObserver(observer);
+
+        onView(withId(R.id.list)).check(matches(isDisplayed()));
+
+        CarUiRecyclerView carUiRecyclerView = mActivity.requireViewById(R.id.list);
+        mActivity.runOnUiThread(() -> {
+            carUiRecyclerView.setAdapter(mContentLimitingAdapter);
+            carUiRecyclerView.setVisibility(View.VISIBLE);
+            mContentLimitingAdapter.setMaxItems(10);
+            mDelegateAdapter.changeItemRange(5, 3);
+        });
+
+        onView(withText(mDelegateAdapter.getItemText(0))).check(matches(isDisplayed()));
+
+        verify(observer).onItemRangeChanged(5, 3, null);
+    }
+
+    @Test
+    public void testInsertItem_callsObservers() {
+        mDelegateAdapter = new TestDelegatingContentLimitingAdapter(50);
+        mContentLimitingAdapter = new DelegatingContentLimitingAdapter<>(mDelegateAdapter, 1);
+
+        AdapterDataObserver observer = mock(AdapterDataObserver.class);
+        mContentLimitingAdapter.registerAdapterDataObserver(observer);
+
+        onView(withId(R.id.list)).check(matches(isDisplayed()));
+
+        CarUiRecyclerView carUiRecyclerView = mActivity.requireViewById(R.id.list);
+        mActivity.runOnUiThread(() -> {
+            carUiRecyclerView.setAdapter(mContentLimitingAdapter);
+            carUiRecyclerView.setVisibility(View.VISIBLE);
+            mContentLimitingAdapter.setMaxItems(10);
+            mDelegateAdapter.insertItemRange(5, "new item 1", "new item 2");
+        });
+
+        onView(withText(mDelegateAdapter.getItemText(0))).check(matches(isDisplayed()));
+
+        verify(observer).onItemRangeInserted(5, 2);
+    }
+
+    @Test
+    public void testRemoveItem_callsObservers() {
+        mDelegateAdapter = new TestDelegatingContentLimitingAdapter(50);
+        mContentLimitingAdapter = new DelegatingContentLimitingAdapter<>(mDelegateAdapter, 1);
+
+        AdapterDataObserver observer = mock(AdapterDataObserver.class);
+        mContentLimitingAdapter.registerAdapterDataObserver(observer);
+
+        onView(withId(R.id.list)).check(matches(isDisplayed()));
+
+        CarUiRecyclerView carUiRecyclerView = mActivity.requireViewById(R.id.list);
+        mActivity.runOnUiThread(() -> {
+            carUiRecyclerView.setAdapter(mContentLimitingAdapter);
+            carUiRecyclerView.setVisibility(View.VISIBLE);
+            mContentLimitingAdapter.setMaxItems(10);
+            mDelegateAdapter.removeItemRange(5, 2);
+        });
+
+        onView(withText(mDelegateAdapter.getItemText(0))).check(matches(isDisplayed()));
+
+        verify(observer).onItemRangeRemoved(5, 2);
+    }
+
+    @Test
+    public void testMoveItem_callsObservers() {
+        mDelegateAdapter = new TestDelegatingContentLimitingAdapter(50);
+        mContentLimitingAdapter = new DelegatingContentLimitingAdapter<>(mDelegateAdapter, 1);
+
+        AdapterDataObserver observer = mock(AdapterDataObserver.class);
+        mContentLimitingAdapter.registerAdapterDataObserver(observer);
+
+        onView(withId(R.id.list)).check(matches(isDisplayed()));
+
+        CarUiRecyclerView carUiRecyclerView = mActivity.requireViewById(R.id.list);
+        mActivity.runOnUiThread(() -> {
+            carUiRecyclerView.setAdapter(mContentLimitingAdapter);
+            carUiRecyclerView.setVisibility(View.VISIBLE);
+            mContentLimitingAdapter.setMaxItems(10);
+            mDelegateAdapter.moveItem(5, 2);
+        });
+
+        onView(withText(mDelegateAdapter.getItemText(0))).check(matches(isDisplayed()));
+
+        verify(observer).onChanged();
+    }
+
+    @Test
+    public void testChangeDataSet_callsObservers() {
+        mDelegateAdapter = new TestDelegatingContentLimitingAdapter(50);
+        mContentLimitingAdapter = new DelegatingContentLimitingAdapter<>(mDelegateAdapter, 1);
+
+        AdapterDataObserver observer = mock(AdapterDataObserver.class);
+        mContentLimitingAdapter.registerAdapterDataObserver(observer);
+
+        onView(withId(R.id.list)).check(matches(isDisplayed()));
+
+        CarUiRecyclerView carUiRecyclerView = mActivity.requireViewById(R.id.list);
+        mActivity.runOnUiThread(() -> {
+            carUiRecyclerView.setAdapter(mContentLimitingAdapter);
+            carUiRecyclerView.setVisibility(View.VISIBLE);
+            mContentLimitingAdapter.setMaxItems(10);
+        });
+
+        onView(withText(mDelegateAdapter.getItemText(0))).check(matches(isDisplayed()));
+
+        mActivity.runOnUiThread(() -> {
+            ArrayList<String> newItems = new ArrayList<>();
+            for (int i = 0; i < 40; i++) {
+                newItems.add("New Item " + i);
+            }
+            mDelegateAdapter.changeList(newItems);
+        });
+
+        onView(withText("New Item 0")).check(matches(isDisplayed()));
+
+        verify(observer).onChanged();
+    }
+
+    @Test
+    public void testSetHasStableId_setsDelegateToo() {
+        mDelegateAdapter = new TestDelegatingContentLimitingAdapter(50);
+        mDelegateAdapter.setHasStableIds(false);
+
+        mContentLimitingAdapter = new DelegatingContentLimitingAdapter<>(mDelegateAdapter, 1);
+
+        mContentLimitingAdapter.setHasStableIds(true);
+
+        assertTrue(mDelegateAdapter.hasStableIds());
+    }
+
+    @Test
+    public void testGetIds_callsDelegate() {
+        mDelegateAdapter = new TestDelegatingContentLimitingAdapter(50);
+        mContentLimitingAdapter = new DelegatingContentLimitingAdapter<>(mDelegateAdapter, 1);
+
+        for (int i = 0; i < 50; i++) {
+            assertEquals(mDelegateAdapter.getItemId(i), mContentLimitingAdapter.getItemId(i));
+        }
+    }
 }
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/recyclerview/TestDelegatingContentLimitingAdapter.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/recyclerview/TestDelegatingContentLimitingAdapter.java
index d3e9791..4a59c04 100644
--- a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/recyclerview/TestDelegatingContentLimitingAdapter.java
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/recyclerview/TestDelegatingContentLimitingAdapter.java
@@ -62,6 +62,45 @@
         return "Item " + i;
     }
 
+    public void changeItemRange(int positionStart, int itemCount) {
+        for (int i = 0; i < itemCount; i++) {
+            mItems.set(i + positionStart, mItems.get(i + positionStart) + "-changed");
+        }
+        notifyItemRangeChanged(positionStart, itemCount);
+    }
+
+    public void insertItemRange(int position, String... items) {
+        for (int i = 0; i < items.length; i++) {
+            mItems.add(position, items[i]);
+        }
+        notifyItemRangeInserted(position, items.length);
+    }
+
+    public void removeItemRange(int positionStart, int itemCount) {
+        for (int i = 0; i < itemCount; i++) {
+            mItems.remove(positionStart + i);
+        }
+        notifyItemRangeRemoved(positionStart, itemCount);
+    }
+
+    public void moveItem(int fromPosition, int toPosition) {
+        String item = mItems.get(fromPosition);
+        if (fromPosition > toPosition) {
+            mItems.remove(fromPosition);
+            mItems.add(toPosition, item);
+        } else {
+            mItems.add(toPosition, item);
+            mItems.remove(fromPosition);
+        }
+        notifyItemMoved(fromPosition, toPosition);
+    }
+
+    public void changeList(List<String> newItems) {
+        mItems.clear();
+        mItems.addAll(newItems);
+        notifyDataSetChanged();
+    }
+
     static class WithContentLimiting extends TestDelegatingContentLimitingAdapter
             implements DelegatingContentLimitingAdapter.ContentLimiting {
 
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/toolbar/EmptyToolbarController.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/toolbar/EmptyToolbarController.java
new file mode 100644
index 0000000..a984e14
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/toolbar/EmptyToolbarController.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.ui.toolbar;
+
+import android.graphics.drawable.Drawable;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.car.ui.imewidescreen.CarUiImeSearchListItem;
+
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * A class that implements ToolbarController but does nothing, just to easily get a non-null
+ * ToolbarController
+ */
+public class EmptyToolbarController implements ToolbarController {
+    @Override
+    public void setTitle(int title) {
+
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+
+    }
+
+    @Override
+    public CharSequence getTitle() {
+        return null;
+    }
+
+    @Override
+    public void setSubtitle(int title) {
+
+    }
+
+    @Override
+    public void setSubtitle(CharSequence title) {
+
+    }
+
+    @Override
+    public CharSequence getSubtitle() {
+        return null;
+    }
+
+    @Override
+    public void setTabs(@Nullable List<Tab> tabs) {
+
+    }
+
+    @Override
+    public void setTabs(@Nullable List<Tab> tabs,
+            int selectedTab) {
+
+    }
+
+    @Override
+    public List<Tab> getTabs() {
+        return null;
+    }
+
+    @Override
+    public int getTabCount() {
+        return 0;
+    }
+
+    @Override
+    public int getTabPosition(TabLayout.Tab tab) {
+        return 0;
+    }
+
+    @Override
+    public void addTab(TabLayout.Tab tab) {
+
+    }
+
+    @Override
+    public void clearAllTabs() {
+
+    }
+
+    @Override
+    public TabLayout.Tab getTab(int position) {
+        return null;
+    }
+
+    @Override
+    public void selectTab(int position) {
+
+    }
+
+    @Override
+    public int getSelectedTab() {
+        return 0;
+    }
+
+    @Override
+    public void setShowTabsInSubpage(boolean showTabs) {
+
+    }
+
+    @Override
+    public boolean getShowTabsInSubpage() {
+        return false;
+    }
+
+    @Override
+    public void setLogo(int resId) {
+
+    }
+
+    @Override
+    public void setLogo(Drawable drawable) {
+
+    }
+
+    @Override
+    public void setSearchHint(int resId) {
+
+    }
+
+    @Override
+    public void setSearchHint(CharSequence hint) {
+
+    }
+
+    @Override
+    public CharSequence getSearchHint() {
+        return null;
+    }
+
+    @Override
+    public void setSearchIcon(int resId) {
+
+    }
+
+    @Override
+    public void setSearchIcon(Drawable d) {
+
+    }
+
+    @Override
+    public void setSearchMode(SearchMode mode) {
+
+    }
+
+    @Override
+    public void setNavButtonMode(Toolbar.NavButtonMode style) {
+
+    }
+
+    @Override
+    public void setNavButtonMode(NavButtonMode mode) {
+
+    }
+
+    @Override
+    public Toolbar.NavButtonMode getNavButtonMode() {
+        return null;
+    }
+
+    @Override
+    public void setBackgroundShown(boolean shown) {
+
+    }
+
+    @Override
+    public boolean getBackgroundShown() {
+        return false;
+    }
+
+    @Override
+    public void setMenuItems(@Nullable List<MenuItem> items) {
+
+    }
+
+    @Override
+    public List<MenuItem> setMenuItems(int resId) {
+        return null;
+    }
+
+    @NonNull
+    @Override
+    public List<MenuItem> getMenuItems() {
+        return null;
+    }
+
+    @Nullable
+    @Override
+    public MenuItem findMenuItemById(int id) {
+        return null;
+    }
+
+    @NonNull
+    @Override
+    public MenuItem requireMenuItemById(int id) {
+        return null;
+    }
+
+    @Override
+    public void setShowMenuItemsWhileSearching(boolean showMenuItems) {
+
+    }
+
+    @Override
+    public boolean getShowMenuItemsWhileSearching() {
+        return false;
+    }
+
+    @Override
+    public void setSearchQuery(String query) {
+
+    }
+
+    @Override
+    public void setState(Toolbar.State state) {
+
+    }
+
+    @Override
+    public Toolbar.State getState() {
+        return null;
+    }
+
+    @Override
+    public boolean isStateSet() {
+        return false;
+    }
+
+    @Override
+    public void registerOnTabSelectedListener(Toolbar.OnTabSelectedListener listener) {
+
+    }
+
+    @Override
+    public boolean unregisterOnTabSelectedListener(Toolbar.OnTabSelectedListener listener) {
+        return false;
+    }
+
+    @Override
+    public void registerOnSearchListener(Toolbar.OnSearchListener listener) {
+
+    }
+
+    @Override
+    public boolean unregisterOnSearchListener(Toolbar.OnSearchListener listener) {
+        return false;
+    }
+
+    @Override
+    public void registerSearchListener(Consumer<String> listener) {
+
+    }
+
+    @Override
+    public boolean unregisterSearchListener(Consumer<String> listener) {
+        return false;
+    }
+
+    @Override
+    public void setSearchConfig(@Nullable SearchConfig searchConfig) {
+
+    }
+
+    @Override
+    public SearchCapabilities getSearchCapabilities() {
+        return null;
+    }
+
+    @Override
+    public boolean canShowSearchResultItems() {
+        return false;
+    }
+
+    @Override
+    public boolean canShowSearchResultsView() {
+        return false;
+    }
+
+    @Override
+    public void setSearchResultsView(@Nullable View view) {
+
+    }
+
+    @Override
+    public void setSearchResultsInputViewIcon(@NonNull Drawable drawable) {
+
+    }
+
+    @Override
+    public void setSearchResultItems(List<? extends CarUiImeSearchListItem> searchItems) {
+
+    }
+
+    @Override
+    public void registerOnSearchCompletedListener(Toolbar.OnSearchCompletedListener listener) {
+
+    }
+
+    @Override
+    public boolean unregisterOnSearchCompletedListener(Toolbar.OnSearchCompletedListener listener) {
+        return false;
+    }
+
+    @Override
+    public void registerSearchCompletedListener(Runnable listener) {
+
+    }
+
+    @Override
+    public boolean unregisterSearchCompletedListener(Runnable listener) {
+        return false;
+    }
+
+    @Override
+    public void registerOnBackListener(Toolbar.OnBackListener listener) {
+
+    }
+
+    @Override
+    public boolean unregisterOnBackListener(Toolbar.OnBackListener listener) {
+        return false;
+    }
+
+    @Override
+    public void registerBackListener(Supplier<Boolean> listener) {
+
+    }
+
+    @Override
+    public boolean unregisterBackListener(Supplier<Boolean> listener) {
+        return false;
+    }
+
+    @Override
+    public ProgressBarController getProgressBar() {
+        return null;
+    }
+}
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/toolbar/InstallBaseLayoutAroundTest.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/toolbar/InstallBaseLayoutAroundTest.java
new file mode 100644
index 0000000..a09357e
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/toolbar/InstallBaseLayoutAroundTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.ui.toolbar;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+
+import com.android.car.ui.FocusParkingView;
+import com.android.car.ui.TrulyEmptyActivity;
+import com.android.car.ui.baselayout.Insets;
+import com.android.car.ui.core.CarUi;
+import com.android.car.ui.sharedlibrarysupport.SharedLibraryFactorySingleton;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+/** A test of {@link com.android.car.ui.core.CarUi#installBaseLayoutAround} */
+@RunWith(Parameterized.class)
+public class InstallBaseLayoutAroundTest {
+
+    @Parameterized.Parameters
+    public static Object[] data() {
+        // It's important to do no shared library first, so that the shared library will
+        // still be enabled when this test finishes
+        return new Object[] { false, true };
+    }
+
+    private final boolean mSharedLibEnabled;
+
+    public InstallBaseLayoutAroundTest(boolean sharedLibEnabled) {
+        mSharedLibEnabled = sharedLibEnabled;
+        SharedLibraryFactorySingleton.setSharedLibEnabled(sharedLibEnabled);
+    }
+
+    @Rule
+    public final ActivityScenarioRule<TrulyEmptyActivity> mScenarioRule =
+            new ActivityScenarioRule<>(TrulyEmptyActivity.class);
+
+    @Test
+    public void test_installBaseLayoutAround_createsToolbar() {
+        onView(isAssignableFrom(FocusParkingView.class)).check(doesNotExist());
+
+        ToolbarController[] toolbar = new ToolbarController[] { null };
+        Insets[] insets = new Insets[] { null };
+        mScenarioRule.getScenario().onActivity(activity -> {
+            toolbar[0] = CarUi.installBaseLayoutAround(
+                    activity.requireViewById(android.R.id.content),
+                    i -> insets[0] = i,
+                    true);
+            if (toolbar[0] != null) {
+                toolbar[0].setTitle("Hello, world!");
+            }
+        });
+
+        assertNotNull(toolbar[0]);
+        onView(withText("Hello, world!")).check(matches(isDisplayed()));
+
+        assertNotNull(insets[0]);
+        // Technically this doesn't have to be true depending on the OEM's customizations
+        assertTrue(insets[0].getTop() > 0);
+        onView(isAssignableFrom(FocusParkingView.class)).check(matches(isDisplayed()));
+    }
+
+    @Test
+    public void test_installBaseLayoutAround_doesntCreateToolbar() {
+        onView(isAssignableFrom(FocusParkingView.class)).check(doesNotExist());
+
+        ToolbarController[] toolbar = new ToolbarController[] { null };
+        mScenarioRule.getScenario().onActivity(activity ->
+                toolbar[0] = CarUi.installBaseLayoutAround(
+                        activity.requireViewById(android.R.id.content),
+                        i -> {},
+                        false));
+
+        assertNull(toolbar[0]);
+        onView(isAssignableFrom(FocusParkingView.class)).check(matches(isDisplayed()));
+    }
+
+    @Test
+    public void test_emptyactivity_doesnthaveinsetsortoolbar() {
+        Insets[] insets = new Insets[] { new Insets() };
+        mScenarioRule.getScenario().onActivity(activity -> insets[0] = CarUi.getInsets(activity));
+        assertNull(insets[0]);
+
+        ToolbarController[] toolbar = new ToolbarController[] { new EmptyToolbarController() };
+        mScenarioRule.getScenario().onActivity(activity -> toolbar[0] = CarUi.getToolbar(activity));
+        assertNull(toolbar[0]);
+    }
+}
diff --git a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/toolbar/ToolbarTest.java b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/toolbar/ToolbarTest.java
index abd5c15..0971722 100644
--- a/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/toolbar/ToolbarTest.java
+++ b/car-ui-lib/car-ui-lib/src/androidTest/java/com/android/car/ui/toolbar/ToolbarTest.java
@@ -28,6 +28,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static junit.framework.Assert.assertNotNull;
 import static junit.framework.TestCase.assertEquals;
 
 import android.content.Context;
@@ -36,6 +37,7 @@
 import androidx.test.ext.junit.rules.ActivityScenarioRule;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.car.ui.baselayout.Insets;
 import com.android.car.ui.core.CarUi;
 import com.android.car.ui.sharedlibrarysupport.SharedLibraryFactorySingleton;
 import com.android.car.ui.test.R;
@@ -244,6 +246,13 @@
         }
     }
 
+    @Test
+    public void test_requireInsets_returnsInsets() {
+        Insets[] insets = new Insets[] { null };
+        mScenarioRule.getScenario().onActivity(activity ->
+                insets[0] = CarUi.requireInsets(activity));
+        assertNotNull(insets[0]);
+    }
 
     private void runWithToolbar(Consumer<ToolbarController> toRun) {
         mScenarioRule.getScenario().onActivity(activity -> {
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledViewControllerImpl.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledViewControllerImpl.java
index 41b6a40..50ded45 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledViewControllerImpl.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/appstyledview/AppStyledViewControllerImpl.java
@@ -25,6 +25,7 @@
 import android.view.View;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 
 import androidx.recyclerview.widget.LinearLayoutManager;
@@ -132,8 +133,10 @@
             close.setImageResource(R.drawable.car_ui_icon_close);
         }
 
-        if (mAppStyledVCloseClickListener != null) {
-            close.setOnClickListener((v) -> {
+        FrameLayout navContainer =
+                appStyleView.findViewById(R.id.car_ui_app_styled_view_nav_icon_container);
+        if (mAppStyledVCloseClickListener != null && navContainer != null) {
+            navContainer.setOnClickListener((v) -> {
                 mAppStyledVCloseClickListener.onClick();
             });
         }
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/recyclerview/DelegatingContentLimitingAdapter.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/recyclerview/DelegatingContentLimitingAdapter.java
index c865b75..62d9feb 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/recyclerview/DelegatingContentLimitingAdapter.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/recyclerview/DelegatingContentLimitingAdapter.java
@@ -41,6 +41,8 @@
     private final int mScrollingLimitedMessagePositionOffset;
     @IdRes
     private final int mConfigId;
+    @NonNull
+    private final Observer mAdapterDataObserver;
 
     /**
      * Provides the abilities to delegate {@link ContentLimitingAdapter} callback functions.
@@ -102,7 +104,24 @@
         mConfigId = configId;
         mScrollingLimitedMessageViewType = viewType;
         mScrollingLimitedMessagePositionOffset = offset;
-        mDelegate.registerAdapterDataObserver(new Observer());
+        mAdapterDataObserver = new Observer();
+    }
+
+    @Override
+    public void registerAdapterDataObserver(@NonNull RecyclerView.AdapterDataObserver observer) {
+        if (!hasObservers()) {
+            mDelegate.registerAdapterDataObserver(mAdapterDataObserver);
+        }
+        super.registerAdapterDataObserver(observer);
+    }
+
+    @Override
+    public void unregisterAdapterDataObserver(@NonNull RecyclerView.AdapterDataObserver observer) {
+        super.unregisterAdapterDataObserver(observer);
+
+        if (!hasObservers()) {
+            mDelegate.unregisterAdapterDataObserver(mAdapterDataObserver);
+        }
     }
 
     private class Observer extends RecyclerView.AdapterDataObserver {
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/sharedlibrarysupport/SharedLibraryFactoryAdapterV1.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/sharedlibrarysupport/SharedLibraryFactoryAdapterV1.java
index 9dfd214..730d2d8 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/sharedlibrarysupport/SharedLibraryFactoryAdapterV1.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/sharedlibrarysupport/SharedLibraryFactoryAdapterV1.java
@@ -71,15 +71,11 @@
  * SharedLibraryFactory.
  */
 public final class SharedLibraryFactoryAdapterV1 implements SharedLibraryFactory {
-
-    private final Context mSharedLibContext;
-
     SharedLibraryFactoryOEMV1 mOem;
     SharedLibraryFactoryStub mFactoryStub;
 
     public SharedLibraryFactoryAdapterV1(SharedLibraryFactoryOEMV1 oem, Context sharedLibContext) {
         mOem = oem;
-        mSharedLibContext = sharedLibContext;
         mFactoryStub = new SharedLibraryFactoryStub(sharedLibContext);
 
         mOem.setRotaryFactories(
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/sharedlibrarysupport/SharedLibraryFactorySingleton.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/sharedlibrarysupport/SharedLibraryFactorySingleton.java
index 0abc95c..a59b187 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/sharedlibrarysupport/SharedLibraryFactorySingleton.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/sharedlibrarysupport/SharedLibraryFactorySingleton.java
@@ -48,6 +48,20 @@
 
     private static final String TAG = "carui";
     private static SharedLibraryFactory sInstance;
+
+    /*
+     ********************************************
+     *               WARNING                    *
+     ********************************************
+     * The OEM APIs as they appear on this      *
+     * branch of android are not finalized!     *
+     * If a shared library is built using them, *
+     * it will cause apps to crash!             *
+     *                                          *
+     * Please only use a shared library with    *
+     * a later version of car-ui-lib.           *
+     ********************************************
+     */
     private static boolean sSharedLibEnabled = false;
 
     /**
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/TabAdapterV1.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/TabAdapterV1.java
index 8cee728..543a10d 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/TabAdapterV1.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/TabAdapterV1.java
@@ -16,48 +16,33 @@
 
 package com.android.car.ui.toolbar;
 
-import android.graphics.drawable.Drawable;
-
 import com.android.car.ui.sharedlibrary.oemapis.toolbar.TabOEMV1;
 
 import java.util.function.Consumer;
 
 @SuppressWarnings("AndroidJdkLibsChecker")
-class TabAdapterV1 implements TabOEMV1 {
+class TabAdapterV1 {
 
     private final Tab mClientTab;
+    private final TabOEMV1 mSharedLibraryTab;
 
     TabAdapterV1(Tab clientTab) {
         mClientTab = clientTab;
+        Consumer<Tab> selectedListener = mClientTab.getSelectedListener();
+        mSharedLibraryTab = TabOEMV1.builder()
+                .setIcon(mClientTab.getIcon())
+                .setTitle(mClientTab.getText())
+                .setOnSelectedListener(selectedListener == null
+                        ? null
+                        : () -> selectedListener.accept(mClientTab))
+                .build();
     }
 
     public Tab getClientTab() {
         return mClientTab;
     }
 
-    @Override
-    public String getTitle() {
-        return mClientTab.getText();
-    }
-
-    @Override
-    public Drawable getIcon() {
-        return mClientTab.getIcon();
-    }
-
-
-    @Override
-    public Runnable getOnClickListener() {
-        Consumer<Tab> selectedListener = mClientTab.getSelectedListener();
-        if (selectedListener == null) {
-            return null;
-        } else {
-            return () -> selectedListener.accept(mClientTab);
-        }
-    }
-
-    @Override
-    public boolean shouldTint() {
-        return true;
+    public TabOEMV1 getSharedLibraryTab() {
+        return mSharedLibraryTab;
     }
 }
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/ToolbarControllerAdapterV1.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/ToolbarControllerAdapterV1.java
index 981cf71..8742961 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/ToolbarControllerAdapterV1.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/ToolbarControllerAdapterV1.java
@@ -475,11 +475,19 @@
         boolean gainingTabs = newAdapterState.hasTabs() && !oldAdapterState.hasTabs();
         boolean losingTabs = !newAdapterState.hasTabs() && oldAdapterState.hasTabs();
         if (gainingTabs) {
-            mOemToolbar.setTabs(newAdapterState.getTabs(), newAdapterState.getSelectedTab());
+            mOemToolbar.setTabs(newAdapterState.getTabs()
+                    .stream()
+                    .map(TabAdapterV1::getSharedLibraryTab)
+                    .collect(toList()),
+                    newAdapterState.getSelectedTab());
         } else if (losingTabs) {
             mOemToolbar.setTabs(Collections.emptyList(), -1);
         } else if (newAdapterState.hasTabs() && newAdapterState.getTabsDirty()) {
-            mOemToolbar.setTabs(newAdapterState.getTabs(), newAdapterState.getSelectedTab());
+            mOemToolbar.setTabs(newAdapterState.getTabs()
+                            .stream()
+                            .map(TabAdapterV1::getSharedLibraryTab)
+                            .collect(toList()),
+                    newAdapterState.getSelectedTab());
         } else if (newAdapterState.hasTabs()
                 && newAdapterState.getSelectedTab() != oldAdapterState.getSelectedTab()) {
             mOemToolbar.selectTab(newAdapterState.getSelectedTab(), true);
diff --git a/car-ui-lib/car-ui-lib/src/main/res-private/drawable/car_ui_app_styled_view_ripple.xml b/car-ui-lib/car-ui-lib/src/main/res-private/drawable/car_ui_app_styled_view_ripple.xml
new file mode 100644
index 0000000..fadd180
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/main/res-private/drawable/car_ui_app_styled_view_ripple.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~
+  ~ Copyright (C) 2021 Google Inc.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:state_focused="true" android:state_pressed="true">
+    <shape android:shape="oval">
+      <solid android:color="#8A94CBFF"/>
+      <stroke android:width="4dp"
+          android:color="#94CBFF"/>
+      <size android:width="48dp"
+          android:height="48dp"/>
+    </shape>
+  </item>
+  <item android:state_focused="true">
+    <shape android:shape="oval">
+      <solid android:color="#3D94CBFF"/>
+      <stroke android:width="8dp"
+          android:color="#94CBFF"/>
+      <size android:width="48dp"
+          android:height="48dp"/>
+    </shape>
+  </item>
+  <item>
+    <ripple android:color="#27ffffff">
+      <item android:id="@android:id/mask">
+        <shape android:shape="oval">
+          <solid android:color="#FFFFFF"/>
+        </shape>
+      </item>
+    </ripple>
+  </item>
+</selector>
diff --git a/car-ui-lib/car-ui-lib/src/main/res-private/layout-land/car_ui_app_styled_view.xml b/car-ui-lib/car-ui-lib/src/main/res-private/layout-land/car_ui_app_styled_view.xml
index 880c996..47daee0 100644
--- a/car-ui-lib/car-ui-lib/src/main/res-private/layout-land/car_ui_app_styled_view.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res-private/layout-land/car_ui_app_styled_view.xml
@@ -32,23 +32,23 @@
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintRight_toLeftOf="@+id/car_ui_app_styled_content"
-        style="@style/Widget.CarUi.Toolbar.Container">
+        app:layout_constraintRight_toLeftOf="@+id/car_ui_app_styled_content">
         <FrameLayout
             android:id="@+id/car_ui_app_styled_view_nav_icon_container"
+            android:layout_marginVertical="10dp"
+            android:layout_marginHorizontal="18dp"
             android:layout_width="76dp"
             android:layout_height="76dp"
             android:layout_gravity="center"
             app:layout_constraintHorizontal_bias="0.0"
-            style="@style/Widget.CarUi.Toolbar.NavIconContainer">
+            android:background="@drawable/car_ui_app_styled_view_ripple">
             <ImageView
                 android:id="@+id/car_ui_app_styled_view_icon_close"
                 android:layout_width="@dimen/car_ui_toolbar_nav_icon_size"
                 android:layout_height="@dimen/car_ui_toolbar_nav_icon_size"
                 android:tint="@color/car_ui_toolbar_nav_icon_color"
                 android:layout_gravity="center"
-                android:scaleType="fitXY"
-                style="@style/Widget.CarUi.Toolbar.NavIcon"/>
+                android:scaleType="fitXY"/>
         </FrameLayout>
     </com.android.car.ui.FocusArea>
     <com.android.car.ui.recyclerview.CarUiRecyclerView
diff --git a/car-ui-lib/car-ui-lib/src/main/res-private/layout/car_ui_app_styled_view.xml b/car-ui-lib/car-ui-lib/src/main/res-private/layout/car_ui_app_styled_view.xml
index d26b8e2..f544e1d 100644
--- a/car-ui-lib/car-ui-lib/src/main/res-private/layout/car_ui_app_styled_view.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res-private/layout/car_ui_app_styled_view.xml
@@ -34,22 +34,22 @@
         android:layout_width="match_parent"
         android:layout_height="@dimen/car_ui_toolbar_first_row_height"
         app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        style="@style/Widget.CarUi.Toolbar.Container">
+        app:layout_constraintStart_toStartOf="parent">
         <FrameLayout
             android:id="@+id/car_ui_app_styled_view_nav_icon_container"
+            android:layout_marginVertical="10dp"
+            android:layout_marginHorizontal="18dp"
+            android:background="@drawable/car_ui_app_styled_view_ripple"
             android:layout_width="@dimen/car_ui_toolbar_margin"
             android:layout_height="match_parent"
-            app:layout_constraintHorizontal_bias="0.0"
-            style="@style/Widget.CarUi.Toolbar.NavIconContainer">
+            app:layout_constraintHorizontal_bias="0.0">
             <ImageView
                 android:id="@+id/car_ui_app_styled_view_icon_close"
                 android:layout_width="@dimen/car_ui_toolbar_nav_icon_size"
                 android:layout_height="@dimen/car_ui_toolbar_nav_icon_size"
                 android:tint="@color/car_ui_toolbar_nav_icon_color"
                 android:layout_gravity="center"
-                android:scaleType="fitXY"
-                style="@style/Widget.CarUi.Toolbar.NavIcon"/>
+                android:scaleType="fitXY"/>
         </FrameLayout>
     </com.android.car.ui.FocusArea>
     <com.android.car.ui.recyclerview.CarUiRecyclerView
diff --git a/car-ui-lib/car-ui-lib/src/test/Android.bp b/car-ui-lib/car-ui-lib/src/test/Android.bp
deleted file mode 100644
index 2d1827c..0000000
--- a/car-ui-lib/car-ui-lib/src/test/Android.bp
+++ /dev/null
@@ -1,30 +0,0 @@
-//
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//###########################################################
-// CarUi lib just for Robolectric test target.     #
-//###########################################################
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-android_app {
-    name: "CarUiRobolectricTestApp",
-    resource_dirs: ["res"],
-    platform_apis: true,
-    privileged: true,
-    libs: ["android.car"],
-    static_libs: ["car-ui-lib"],
-}
diff --git a/car-ui-lib/car-ui-lib/src/test/AndroidManifest.xml b/car-ui-lib/car-ui-lib/src/test/AndroidManifest.xml
deleted file mode 100644
index eb83765..0000000
--- a/car-ui-lib/car-ui-lib/src/test/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    Copyright (C) 2020 Google Inc.
-
-    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="com.android.car.ui">
-</manifest>
diff --git a/car-ui-lib/car-ui-lib/src/test/java/Android.bp b/car-ui-lib/car-ui-lib/src/test/java/Android.bp
deleted file mode 100644
index a418f14..0000000
--- a/car-ui-lib/car-ui-lib/src/test/java/Android.bp
+++ /dev/null
@@ -1,31 +0,0 @@
-//
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//###############################################
-// Car Ui Robolectric test target. #
-//###############################################
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-android_robolectric_test {
-    name: "CarUiRoboTests",
-    srcs: ["**/*.java"],
-    libs: [
-        "android.car",
-        "testng",
-    ],
-    instrumentation_for: "CarUiRobolectricTestApp",
-}
diff --git a/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/CarUiListItemTest.java b/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/CarUiListItemTest.java
deleted file mode 100644
index 344180a..0000000
--- a/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/CarUiListItemTest.java
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.ui.recyclerview;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.view.View;
-import android.widget.CheckBox;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import com.android.car.ui.R;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-public class CarUiListItemTest {
-
-    private CarUiRecyclerView mListView;
-    private Context mContext;
-
-    @Mock
-    CarUiContentListItem.OnCheckedChangeListener mOnCheckedChangeListener;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-        mListView = new CarUiRecyclerViewImpl(mContext);
-    }
-
-    private CarUiListItemAdapter.ListItemViewHolder getListItemViewHolderAtPosition(int position) {
-        return (CarUiListItemAdapter.ListItemViewHolder) mListView.findViewHolderForAdapterPosition(
-                position);
-    }
-
-    private View getListItemTitleAtPosition(int position) {
-        return getListItemViewHolderAtPosition(position).itemView
-                .findViewById(R.id.car_ui_list_item_title);
-    }
-
-    private View getListItemBodyAtPosition(int position) {
-        return getListItemViewHolderAtPosition(position).itemView
-                .findViewById(R.id.car_ui_list_item_body);
-    }
-
-    private View getListItemIconContainerAtPosition(int position) {
-        return getListItemViewHolderAtPosition(position).itemView
-                .findViewById(R.id.car_ui_list_item_icon_container);
-    }
-
-    private View getListItemActionContainerAtPosition(int position) {
-        return getListItemViewHolderAtPosition(position)
-                .itemView.findViewById(R.id.action_container);
-    }
-
-    private Switch getListItemSwitchAtPosition(int position) {
-        return getListItemViewHolderAtPosition(position).itemView
-                .findViewById(R.id.car_ui_list_item_switch_widget);
-    }
-
-    private CheckBox getListItemCheckBoxAtPosition(int position) {
-        return getListItemViewHolderAtPosition(position)
-                .itemView.findViewById(R.id.car_ui_list_item_checkbox_widget);
-    }
-
-    private View getListItemIconAtPosition(int position) {
-        return getListItemViewHolderAtPosition(position).itemView.findViewById(R.id.icon);
-    }
-
-    private CarUiListItemAdapter.HeaderViewHolder getHeaderViewHolderAtPosition(int position) {
-        return (CarUiListItemAdapter.HeaderViewHolder) mListView.findViewHolderForAdapterPosition(
-                position);
-    }
-
-    private TextView getHeaderViewHolderTitleAtPosition(int position) {
-        return getHeaderViewHolderAtPosition(position).itemView
-                .findViewById(R.id.car_ui_list_item_title);
-    }
-
-    private TextView getHeaderViewHolderBodyAtPosition(int position) {
-        return getHeaderViewHolderAtPosition(position).itemView
-                .findViewById(R.id.car_ui_list_item_body);
-    }
-
-    private void updateRecyclerViewAdapter(CarUiListItemAdapter adapter) {
-        mListView.setAdapter(adapter);
-
-        // Force CarUiRecyclerView and the nested RecyclerView to be laid out.
-        mListView.measure(0, 0);
-        mListView.layout(0, 0, 100, 10000);
-
-        if (mListView != null) {
-            mListView.measure(0, 0);
-            mListView.layout(0, 0, 100, 10000);
-        }
-
-        // Required to init nested RecyclerView
-        mListView.getViewTreeObserver().dispatchOnGlobalLayout();
-    }
-
-    @Test
-    public void testItemVisibility_withTitle() {
-        List<CarUiListItem> items = new ArrayList<>();
-
-        CarUiContentListItem item = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
-        item.setTitle("Test title");
-        items.add(item);
-
-        updateRecyclerViewAdapter(new CarUiListItemAdapter(items));
-
-        assertThat(getListItemTitleAtPosition(0).getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(getListItemBodyAtPosition(0).getVisibility()).isNotEqualTo(View.VISIBLE);
-        assertThat(getListItemIconContainerAtPosition(0).getVisibility())
-                .isNotEqualTo(View.VISIBLE);
-        assertThat(getListItemActionContainerAtPosition(0).getVisibility())
-                .isNotEqualTo(View.VISIBLE);
-    }
-
-    @Test
-    public void testItemVisibility_withTitle_withBody() {
-        List<CarUiListItem> items = new ArrayList<>();
-
-        CarUiContentListItem item = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
-        item.setTitle("Test title");
-        item.setBody("Test body");
-        items.add(item);
-
-        updateRecyclerViewAdapter(new CarUiListItemAdapter(items));
-
-        assertThat(getListItemTitleAtPosition(0).getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(getListItemBodyAtPosition(0).getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(getListItemIconContainerAtPosition(0).getVisibility())
-                .isNotEqualTo(View.VISIBLE);
-        assertThat(getListItemActionContainerAtPosition(0).getVisibility())
-                .isNotEqualTo(View.VISIBLE);
-    }
-
-    @Test
-    public void testItemVisibility_withTitle_withIcon() {
-        List<CarUiListItem> items = new ArrayList<>();
-
-        CarUiContentListItem item = new CarUiContentListItem(CarUiContentListItem.Action.NONE);
-        item.setTitle("Test title");
-        item.setIcon(mContext.getDrawable(R.drawable.car_ui_icon_close));
-        items.add(item);
-
-        updateRecyclerViewAdapter(new CarUiListItemAdapter(items));
-
-        assertThat(getListItemTitleAtPosition(0).getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(getListItemBodyAtPosition(0).getVisibility()).isNotEqualTo(View.VISIBLE);
-        assertThat(getListItemIconContainerAtPosition(0).getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(getListItemIconAtPosition(0).getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(getListItemActionContainerAtPosition(0).getVisibility())
-                .isNotEqualTo(View.VISIBLE);
-    }
-
-    @Test
-    public void testItemVisibility_withTitle_withCheckbox() {
-        List<CarUiListItem> items = new ArrayList<>();
-
-        CarUiContentListItem item = new CarUiContentListItem(CarUiContentListItem.Action.CHECK_BOX);
-        item.setTitle("Test title");
-        items.add(item);
-
-        updateRecyclerViewAdapter(new CarUiListItemAdapter(items));
-
-        assertThat(getListItemTitleAtPosition(0).getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(getListItemBodyAtPosition(0).getVisibility()).isNotEqualTo(View.VISIBLE);
-        assertThat(getListItemIconContainerAtPosition(0).getVisibility())
-                .isNotEqualTo(View.VISIBLE);
-        assertThat(getListItemActionContainerAtPosition(0).getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(getListItemSwitchAtPosition(0).getVisibility()).isNotEqualTo(View.VISIBLE);
-        assertThat(getListItemCheckBoxAtPosition(0).getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(getListItemCheckBoxAtPosition(0).isChecked()).isEqualTo(false);
-    }
-
-    @Test
-    public void testItemVisibility_withTitle_withBody_withSwitch() {
-        List<CarUiListItem> items = new ArrayList<>();
-
-        CarUiContentListItem item = new CarUiContentListItem(CarUiContentListItem.Action.SWITCH);
-        item.setTitle("Test title");
-        item.setBody("Body text");
-        items.add(item);
-
-        updateRecyclerViewAdapter(new CarUiListItemAdapter(items));
-
-        assertThat(getListItemTitleAtPosition(0).getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(getListItemBodyAtPosition(0).getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(getListItemIconContainerAtPosition(0).getVisibility())
-                .isNotEqualTo(View.VISIBLE);
-        assertThat(getListItemActionContainerAtPosition(0).getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(getListItemSwitchAtPosition(0).getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(getListItemSwitchAtPosition(0).isChecked()).isEqualTo(false);
-        assertThat(getListItemCheckBoxAtPosition(0).getVisibility()).isNotEqualTo(View.VISIBLE);
-    }
-
-    @Test
-    public void testCheckedState_switch() {
-        List<CarUiListItem> items = new ArrayList<>();
-
-        CarUiContentListItem item = new CarUiContentListItem(CarUiContentListItem.Action.SWITCH);
-        item.setTitle("Test title");
-        item.setOnCheckedChangeListener(mOnCheckedChangeListener);
-        item.setChecked(true);
-        items.add(item);
-
-        updateRecyclerViewAdapter(new CarUiListItemAdapter(items));
-
-        Switch switchWidget = getListItemSwitchAtPosition(0);
-
-        assertThat(switchWidget.isChecked()).isEqualTo(true);
-        switchWidget.performClick();
-        assertThat(switchWidget.isChecked()).isEqualTo(false);
-        verify(mOnCheckedChangeListener, times(1))
-                .onCheckedChanged(item, false);
-    }
-
-    @Test
-    public void testCheckedState_checkbox() {
-        List<CarUiListItem> items = new ArrayList<>();
-
-        CarUiContentListItem item = new CarUiContentListItem(CarUiContentListItem.Action.CHECK_BOX);
-        item.setTitle("Test title");
-        item.setOnCheckedChangeListener(mOnCheckedChangeListener);
-        items.add(item);
-
-        updateRecyclerViewAdapter(new CarUiListItemAdapter(items));
-
-        CheckBox checkBox = getListItemCheckBoxAtPosition(0);
-
-        assertThat(checkBox.isChecked()).isEqualTo(false);
-        checkBox.performClick();
-        assertThat(checkBox.isChecked()).isEqualTo(true);
-        verify(mOnCheckedChangeListener, times(1))
-                .onCheckedChanged(item, true);
-    }
-
-    @Test
-    public void testHeader_onlyTitle() {
-        List<CarUiListItem> items = new ArrayList<>();
-
-        CharSequence title = "Test header";
-        CarUiHeaderListItem header = new CarUiHeaderListItem(title);
-        items.add(header);
-
-        updateRecyclerViewAdapter(new CarUiListItemAdapter(items));
-
-        assertThat(getHeaderViewHolderTitleAtPosition(0).getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(getHeaderViewHolderTitleAtPosition(0).getText()).isEqualTo(title);
-        assertThat(getHeaderViewHolderBodyAtPosition(0).getVisibility()).isNotEqualTo(View.VISIBLE);
-    }
-
-    @Test
-    public void testHeader_titleAndBody() {
-        List<CarUiListItem> items = new ArrayList<>();
-
-        CharSequence title = "Test header";
-        CharSequence body = "With body text";
-
-        CarUiHeaderListItem header = new CarUiHeaderListItem(title, body);
-        items.add(header);
-
-        updateRecyclerViewAdapter(new CarUiListItemAdapter(items));
-
-        TextView titleView = getHeaderViewHolderTitleAtPosition(0);
-        TextView bodyView = getHeaderViewHolderBodyAtPosition(0);
-
-        assertThat(titleView.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(titleView.getText()).isEqualTo(title);
-        assertThat(bodyView.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(bodyView.getText()).isEqualTo(body);
-    }
-}
diff --git a/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/CarUiRecyclerViewAdapterTest.java b/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/CarUiRecyclerViewAdapterTest.java
deleted file mode 100644
index 4d21851..0000000
--- a/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/CarUiRecyclerViewAdapterTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.ui.recyclerview;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.view.ViewGroup;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class CarUiRecyclerViewAdapterTest {
-
-    private Context mContext;
-    private CarUiRecyclerViewAdapter mCarUiRecyclerViewAdapter;
-
-    @Mock
-    private ViewGroup mParent;
-    @Mock
-    private ViewGroup.LayoutParams mLayoutParams;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-
-        mContext = RuntimeEnvironment.application;
-        mCarUiRecyclerViewAdapter = new CarUiRecyclerViewAdapter();
-    }
-
-    @Test
-    public void getItemCount_shouldAlwaysBeOne() {
-        assertThat(mCarUiRecyclerViewAdapter.getItemCount()).isEqualTo(1);
-    }
-
-    @Test
-    public void onCreateViewHolder_frameLayoutNotNull() {
-
-        when(mParent.getContext()).thenReturn(mContext);
-        when(mParent.generateLayoutParams(any())).thenReturn(mLayoutParams);
-
-        CarUiRecyclerViewAdapter.NestedRowViewHolder nestedRowViewHolder =
-                mCarUiRecyclerViewAdapter.onCreateViewHolder(mParent, 0);
-
-        assertThat(nestedRowViewHolder.frameLayout).isNotNull();
-    }
-}
diff --git a/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/CarUiRecyclerViewTest.java b/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/CarUiRecyclerViewTest.java
deleted file mode 100644
index 1c8cc68..0000000
--- a/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/CarUiRecyclerViewTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.ui.recyclerview;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import androidx.recyclerview.widget.GridLayoutManager;
-import androidx.recyclerview.widget.LinearLayoutManager;
-
-import com.android.car.ui.R;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class CarUiRecyclerViewTest {
-
-    private Context mContext;
-    private View mView;
-    private CarUiRecyclerView mCarUiRecyclerView;
-    private Resources mResources;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-        mResources = mContext.getResources();
-    }
-
-    @Test
-    public void setAdapter_shouldInitializeLinearLayoutManager() {
-        mView = LayoutInflater.from(mContext)
-                .inflate(mResources.getIdentifier("test_linear_car_ui_recycler_view", "layout",
-                        mContext.getPackageName()), null);
-
-        mCarUiRecyclerView = mView.findViewById(
-                mResources.getIdentifier("test_prv", "id", mContext.getPackageName()));
-
-        assertThat(mCarUiRecyclerView.getLayoutManager()).isInstanceOf(
-                LinearLayoutManager.class);
-    }
-
-    @Test
-    public void setAdapter_shouldInitializeGridLayoutManager() {
-        mView = LayoutInflater.from(mContext)
-                .inflate(mResources.getIdentifier("test_grid_car_ui_recycler_view", "layout",
-                        mContext.getPackageName()), null);
-
-        mCarUiRecyclerView = mView.findViewById(
-                mResources.getIdentifier("test_prv", "id", mContext.getPackageName()));
-
-        assertThat(mCarUiRecyclerView.getLayoutManager()).isInstanceOf(
-                GridLayoutManager.class);
-    }
-
-    @Test
-    public void init_shouldContainRecyclerView() {
-        mView = LayoutInflater.from(mContext)
-                .inflate(mResources.getIdentifier("test_linear_car_ui_recycler_view", "layout",
-                        mContext.getPackageName()), null);
-
-        mCarUiRecyclerView = mView.findViewById(
-                mResources.getIdentifier("test_prv", "id", mContext.getPackageName()));
-
-        assertThat(mCarUiRecyclerView).isNotNull();
-    }
-
-    @Test
-    public void init_shouldHaveGridLayout() {
-        mCarUiRecyclerView = new CarUiRecyclerViewImpl(mContext,
-                        Robolectric.buildAttributeSet()
-                                        .addAttribute(R.attr.layoutStyle, "grid").build());
-        assertThat(mCarUiRecyclerView.getLayoutManager()).isInstanceOf(
-                GridLayoutManager.class);
-    }
-}
diff --git a/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/CarUiSmoothScrollerTest.java b/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/CarUiSmoothScrollerTest.java
deleted file mode 100644
index c5dc78b..0000000
--- a/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/CarUiSmoothScrollerTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.ui.recyclerview;
-
-import static androidx.recyclerview.widget.LinearSmoothScroller.SNAP_TO_START;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class CarUiSmoothScrollerTest {
-
-    private Context mContext;
-    private CarUiSmoothScroller mCarUiSmoothScroller;
-
-    @Before
-    public void setUp() {
-        mContext = RuntimeEnvironment.application;
-        mCarUiSmoothScroller = new CarUiSmoothScroller(mContext);
-    }
-
-    @Test
-    public void calculateTimeForScrolling_shouldInitializeAllValues() {
-        assertThat(mCarUiSmoothScroller.mMillisecondsPerInch).isNotEqualTo(0);
-        assertThat(mCarUiSmoothScroller.mDecelerationTimeDivisor).isNotEqualTo(0);
-        assertThat(mCarUiSmoothScroller.mMillisecondsPerPixel).isNotEqualTo(0);
-        assertThat(mCarUiSmoothScroller.mInterpolator).isNotNull();
-        assertThat(mCarUiSmoothScroller.mDensityDpi).isNotEqualTo(0);
-    }
-
-    @Test
-    public void getVerticalSnapPreference_shouldReturnSnapToStart() {
-        assertThat(mCarUiSmoothScroller.getVerticalSnapPreference()).isEqualTo(SNAP_TO_START);
-    }
-
-    @Test
-    public void calculateTimeForScrolling_shouldReturnMultiplierOfMillisecondsPerPixel() {
-        assertThat(mCarUiSmoothScroller.calculateTimeForScrolling(20)).isEqualTo(
-                (int) Math.ceil(Math.abs(20) * mCarUiSmoothScroller.mMillisecondsPerPixel));
-    }
-
-    @Test
-    public void calculateTimeForDeceleration_shouldReturnNotBeZero() {
-        assertThat(mCarUiSmoothScroller.calculateTimeForDeceleration(20)).isNotEqualTo(0);
-    }
-}
diff --git a/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/CarUiSnapHelperTest.java b/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/CarUiSnapHelperTest.java
deleted file mode 100644
index 62edd3d..0000000
--- a/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/CarUiSnapHelperTest.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.ui.recyclerview;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.view.View;
-
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class CarUiSnapHelperTest {
-
-    private Context mContext;
-    private CarUiSnapHelper mCarUiSnapHelper;
-
-    @Mock
-    private RecyclerView mRecyclerView;
-    @Mock
-    private LinearLayoutManager mLayoutManager;
-    @Mock
-    private RecyclerView.Adapter mAdapter;
-    @Mock
-    private View mChild;
-    @Mock
-    private RecyclerView.LayoutParams mLayoutParams;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-
-        mCarUiSnapHelper = new CarUiSnapHelper(mContext);
-
-        when(mRecyclerView.getContext()).thenReturn(mContext);
-        mCarUiSnapHelper.attachToRecyclerView(mRecyclerView);
-    }
-
-    @Test
-    public void calculateDistanceToFinalSnap_shouldReturnTopMarginDifference() {
-        when(mRecyclerView.getLayoutManager()).thenReturn(mLayoutManager);
-        when(mRecyclerView.isInTouchMode()).thenReturn(true);
-        when(mLayoutManager.getItemCount()).thenReturn(1);
-        when(mLayoutManager.canScrollVertically()).thenReturn(true);
-        when(mLayoutManager.getChildCount()).thenReturn(1);
-        // some delta
-        when(mLayoutManager.getDecoratedTop(any())).thenReturn(10);
-        when(mChild.getLayoutParams()).thenReturn(mLayoutParams);
-
-        int[] distance = mCarUiSnapHelper.calculateDistanceToFinalSnap(mLayoutManager, mChild);
-
-        assertThat(distance[1]).isEqualTo(10);
-    }
-
-    @Test
-    public void calculateScrollDistance_shouldScrollHeightOfView() {
-        when(mRecyclerView.getLayoutManager()).thenReturn(mLayoutManager);
-        when(mLayoutManager.getItemCount()).thenReturn(1);
-        when(mLayoutManager.canScrollVertically()).thenReturn(true);
-        when(mLayoutManager.getChildCount()).thenReturn(1);
-        // some delta
-        when(mLayoutManager.getDecoratedTop(any())).thenReturn(10);
-        when(mChild.getLayoutParams()).thenReturn(mLayoutParams);
-        when(mLayoutManager.getChildAt(0)).thenReturn(mChild);
-        when(mLayoutManager.getHeight()).thenReturn(-50);
-
-        int[] distance = mCarUiSnapHelper.calculateScrollDistance(0, 10);
-
-        assertThat(distance[1]).isEqualTo(50);
-    }
-}
diff --git a/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/DefaultScrollBarTest.java b/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/DefaultScrollBarTest.java
deleted file mode 100644
index 1cd59df..0000000
--- a/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/recyclerview/DefaultScrollBarTest.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.ui.recyclerview;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-import static org.testng.Assert.assertThrows;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.car.ui.R;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class DefaultScrollBarTest {
-
-    private Context mContext;
-    private ScrollBar mScrollBar;
-
-    @Mock
-    private RecyclerView mRecyclerView;
-    @Mock
-    private FrameLayout mParent;
-    @Mock
-    private FrameLayout.LayoutParams mLayoutParams;
-    @Mock
-    private RecyclerView.RecycledViewPool mRecycledViewPool;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-
-        mScrollBar = new DefaultScrollBar();
-    }
-
-    @Test
-    public void initialize_shouldInitializeScrollListener() {
-        when(mRecyclerView.getContext()).thenReturn(mContext);
-        when(mRecyclerView.getParent()).thenReturn(mParent);
-        when(mRecyclerView.getRecycledViewPool()).thenReturn(mRecycledViewPool);
-        when(mParent.generateLayoutParams(any())).thenReturn(mLayoutParams);
-
-        View scrollView = LayoutInflater.from(mContext).inflate(
-                R.layout.car_ui_recyclerview_scrollbar, null);
-        mScrollBar.initialize(mRecyclerView, scrollView);
-
-        // called once in DefaultScrollBar and once in SnapHelper while setting up the call backs
-        // when we use attachToRecyclerView(recyclerview)
-        verify(mRecyclerView, times(2)).addOnScrollListener(
-                any(RecyclerView.OnScrollListener.class));
-    }
-
-    @Test
-    public void initialize_shouldSetMaxRecyclerViews() {
-        when(mRecyclerView.getContext()).thenReturn(mContext);
-        when(mRecyclerView.getParent()).thenReturn(mParent);
-        when(mRecyclerView.getRecycledViewPool()).thenReturn(mRecycledViewPool);
-        when(mParent.generateLayoutParams(any())).thenReturn(mLayoutParams);
-
-        View scrollView = LayoutInflater.from(mContext).inflate(
-                R.layout.car_ui_recyclerview_scrollbar, null);
-        mScrollBar.initialize(mRecyclerView, scrollView);
-
-        verify(mRecycledViewPool).setMaxRecycledViews(0, 12);
-    }
-
-    @Test
-    public void initialize_shouldNotHaveFlingListener() {
-        when(mRecyclerView.getContext()).thenReturn(mContext);
-        when(mRecyclerView.getParent()).thenReturn(mParent);
-        when(mRecyclerView.getRecycledViewPool()).thenReturn(mRecycledViewPool);
-        when(mParent.generateLayoutParams(any())).thenReturn(mLayoutParams);
-
-        View scrollView = LayoutInflater.from(mContext).inflate(
-                R.layout.car_ui_recyclerview_scrollbar, null);
-        mScrollBar.initialize(mRecyclerView, scrollView);
-
-        verify(mRecyclerView).setOnFlingListener(null);
-    }
-
-    @Test
-    public void setPadding_shouldSetStartAndEndPadding() {
-        when(mRecyclerView.getContext()).thenReturn(mContext);
-        when(mRecyclerView.getParent()).thenReturn(mParent);
-        when(mRecyclerView.getRecycledViewPool()).thenReturn(mRecycledViewPool);
-        when(mParent.generateLayoutParams(any())).thenReturn(mLayoutParams);
-
-        View scrollView = LayoutInflater.from(mContext).inflate(
-                R.layout.car_ui_recyclerview_scrollbar, null);
-        mScrollBar.initialize(mRecyclerView, scrollView);
-        mScrollBar.setPadding(10, 20);
-
-        assertThat(scrollView.getPaddingTop()).isEqualTo(10);
-        assertThat(scrollView.getPaddingBottom()).isEqualTo(20);
-    }
-
-    @Test
-    public void setPadding_shouldThrowErrorWithoutInitialization() {
-        assertThrows(NullPointerException.class, () -> mScrollBar.setPadding(10, 20));
-    }
-
-    @Test
-    public void requestLayout_shouldThrowErrorWithoutInitialization() {
-        assertThrows(NullPointerException.class, () -> mScrollBar.requestLayout());
-    }
-}
diff --git a/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/utils/CarUxRestrictionsUtilTest.java b/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/utils/CarUxRestrictionsUtilTest.java
deleted file mode 100644
index ea62ee5..0000000
--- a/car-ui-lib/car-ui-lib/src/test/java/com/android/car/ui/utils/CarUxRestrictionsUtilTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.car.ui.utils;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.car.drivingstate.CarUxRestrictions;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-
-@RunWith(RobolectricTestRunner.class)
-public class CarUxRestrictionsUtilTest {
-    private int[] mRestrictionsArray;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mRestrictionsArray = new int[]{
-                CarUxRestrictions.UX_RESTRICTIONS_NO_DIALPAD,
-                CarUxRestrictions.UX_RESTRICTIONS_NO_KEYBOARD,
-                CarUxRestrictions.UX_RESTRICTIONS_NO_DIALPAD
-                        | CarUxRestrictions.UX_RESTRICTIONS_NO_KEYBOARD,
-                CarUxRestrictions.UX_RESTRICTIONS_FULLY_RESTRICTED
-        };
-    }
-
-    @Test
-    public void testNullActiveRestriction() {
-        CarUxRestrictions activeRestrictions = null;
-        boolean[] expectedResults = {true, true, true, true};
-        for (int i = 0; i < mRestrictionsArray.length; i++) {
-            boolean actualResult = CarUxRestrictionsUtil.isRestricted(mRestrictionsArray[i],
-                    activeRestrictions);
-            assertThat(actualResult == expectedResults[i]).isTrue();
-        }
-    }
-
-    @Test
-    public void testOneActiveRestriction() {
-        CarUxRestrictions activeRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */true,
-                CarUxRestrictions.UX_RESTRICTIONS_NO_DIALPAD, /* timestamp= */0).build();
-        boolean[] expectedResults = {true, false, true, true};
-        for (int i = 0; i < mRestrictionsArray.length; i++) {
-            boolean actualResult = CarUxRestrictionsUtil.isRestricted(mRestrictionsArray[i],
-                    activeRestrictions);
-            assertThat(actualResult == expectedResults[i]).isTrue();
-        }
-    }
-
-    @Test
-    public void testMultipleActiveRestrictions() {
-        CarUxRestrictions activeRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */true,
-                CarUxRestrictions.UX_RESTRICTIONS_NO_DIALPAD
-                        | CarUxRestrictions.UX_RESTRICTIONS_NO_TEXT_MESSAGE, /* timestamp= */
-                0).build();
-        boolean[] expectedResults = {true, false, true, true};
-        for (int i = 0; i < mRestrictionsArray.length; i++) {
-            boolean actualResult = CarUxRestrictionsUtil.isRestricted(mRestrictionsArray[i],
-                    activeRestrictions);
-            assertThat(actualResult == expectedResults[i]).isTrue();
-        }
-    }
-}
diff --git a/car-ui-lib/car-ui-lib/src/test/res/drawable/test_ic_launcher.png b/car-ui-lib/car-ui-lib/src/test/res/drawable/test_ic_launcher.png
deleted file mode 100644
index 2af53a4..0000000
--- a/car-ui-lib/car-ui-lib/src/test/res/drawable/test_ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/car-ui-lib/car-ui-lib/src/test/res/layout/test_custom_view.xml b/car-ui-lib/car-ui-lib/src/test/res/layout/test_custom_view.xml
deleted file mode 100644
index 7a52259..0000000
--- a/car-ui-lib/car-ui-lib/src/test/res/layout/test_custom_view.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright 2019 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<androidx.constraintlayout.widget.ConstraintLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <TextView
-        android:id="@+id/text_box_1"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="Text Box 1"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toStartOf="@id/text_box_2"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent"/>
-
-    <TextView
-        android:id="@+id/text_box_2"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="Text Box 2"
-        app:layout_constraintStart_toEndOf="@id/text_box_1"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintBottom_toBottomOf="parent"/>
-
-
-</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/car-ui-lib/car-ui-lib/src/test/res/layout/test_grid_car_ui_recycler_view.xml b/car-ui-lib/car-ui-lib/src/test/res/layout/test_grid_car_ui_recycler_view.xml
deleted file mode 100644
index e5bf7a3..0000000
--- a/car-ui-lib/car-ui-lib/src/test/res/layout/test_grid_car_ui_recycler_view.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2019 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <com.android.car.ui.recyclerview.CarUiRecyclerView
-        android:id="@+id/test_prv"
-        app:layoutStyle="grid"
-        app:numOfColumns="4"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"/>
-</FrameLayout>
diff --git a/car-ui-lib/lint-baseline.xml b/car-ui-lib/lint-baseline.xml
deleted file mode 100644
index 1689f30..0000000
--- a/car-ui-lib/lint-baseline.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 28): `android.view.SurfaceControlViewHost#relayout`"
-        errorLine1="                mSurfaceControlViewHost.relayout(width, height);"
-        errorLine2="                                        ~~~~~~~~">
-        <location
-            file="packages/apps/Car/libs/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/toolbar/SearchView.java"
-            line="561"
-            column="41"/>
-    </issue>
-
-</issues>
diff --git a/car-ui-lib/oem-apis/README.md b/car-ui-lib/oem-apis/README.md
new file mode 100644
index 0000000..40d4b42
--- /dev/null
+++ b/car-ui-lib/oem-apis/README.md
@@ -0,0 +1,21 @@
+# Car-ui-lib OEM APIs
+
+```
+#############################################
+#                  WARNING                  #
+#############################################
+# The OEM APIs as they appear on this       #
+# branch of android are not finalized!      #
+# If a shared library is built using them,  #
+# it will cause apps to crash!              #
+#                                           #
+# Please get the OEM APIs from a later      #
+# branch of android instead.                #
+#############################################
+```
+
+These APIs allow OEMs to build a shared library for
+car-ui-lib that can supply custom implementations
+of car-ui-lib components. See
+SharedLibraryFactorySingleton for information
+on the entrypoint to the shared library.
diff --git a/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/sharedlibrary/oemapis/InsetsOEMV1.java b/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/sharedlibrary/oemapis/InsetsOEMV1.java
index 11421a8..0e501d6 100644
--- a/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/sharedlibrary/oemapis/InsetsOEMV1.java
+++ b/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/sharedlibrary/oemapis/InsetsOEMV1.java
@@ -15,17 +15,64 @@
  */
 package com.android.car.ui.sharedlibrary.oemapis;
 
+import java.util.Objects;
+
 /**
  * Represents insets in the base layout. {@link com.android.car.ui.baselayout.Insets} for more
  * information.
  */
-public interface InsetsOEMV1 {
-    /** Gets the left inset */
-    int getLeft();
-    /** Gets the right inset */
-    int getRight();
-    /** Gets the top inset */
-    int getTop();
-    /** Gets the bottom inset */
-    int getBottom();
+public final class InsetsOEMV1 {
+    private final int mLeft;
+    private final int mRight;
+    private final int mTop;
+    private final int mBottom;
+
+    public InsetsOEMV1() {
+        mLeft = mRight = mTop = mBottom = 0;
+    }
+
+    public InsetsOEMV1(int left, int top, int right, int bottom) {
+        mLeft = left;
+        mRight = right;
+        mTop = top;
+        mBottom = bottom;
+    }
+
+    public int getLeft() {
+        return mLeft;
+    }
+
+    public int getRight() {
+        return mRight;
+    }
+
+    public int getTop() {
+        return mTop;
+    }
+
+    public int getBottom() {
+        return mBottom;
+    }
+
+    @Override
+    public String toString() {
+        return "{ left: " + mLeft + ", right: " + mRight
+                + ", top: " + mTop + ", bottom: " + mBottom + " }";
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        InsetsOEMV1 insets = (InsetsOEMV1) o;
+        return mLeft == insets.mLeft
+                && mRight == insets.mRight
+                && mTop == insets.mTop
+                && mBottom == insets.mBottom;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mLeft, mRight, mTop, mBottom);
+    }
 }
diff --git a/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/sharedlibrary/oemapis/toolbar/TabOEMV1.java b/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/sharedlibrary/oemapis/toolbar/TabOEMV1.java
index 9db4423..d175aca 100644
--- a/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/sharedlibrary/oemapis/toolbar/TabOEMV1.java
+++ b/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/sharedlibrary/oemapis/toolbar/TabOEMV1.java
@@ -19,17 +19,85 @@
 import android.graphics.drawable.Drawable;
 
 /** Interface representing a toolbar tab */
-public interface TabOEMV1 {
+public final class TabOEMV1 {
+    private final String mTitle;
+    private final Drawable mIcon;
+    private final Runnable mOnSelectedListener;
+    private final boolean mTinted;
+
+    private TabOEMV1(Builder builder) {
+        mTitle = builder.mTitle;
+        mIcon = builder.mIcon;
+        mOnSelectedListener = builder.mOnSelectedListener;
+        mTinted = builder.mTinted;
+    }
+
+    /** Constructs a new {@link Builder} to build a tab with */
+    public static Builder builder() {
+        return new Builder();
+    }
+
     /** Gets the title of the tab */
-    String getTitle();
+    public String getTitle() {
+        return mTitle;
+    }
+
     /** Gets the icon of the tab. The icon may be tinted to match the theme of the toolbar */
-    Drawable getIcon();
+    public Drawable getIcon() {
+        return mIcon;
+    }
+
     /** Gets the function to call when the tab is selected */
-    Runnable getOnClickListener();
+    public Runnable getOnSelectedListener() {
+        return mOnSelectedListener;
+    }
+
     /**
      * Returns if the icon should be tinted to match the style of the toolbar.
      * Most of the time this will be true. If not, then the original colors of the drawable
      * should be shown.
      */
-    boolean shouldTint();
+    public boolean isTinted() {
+        return mTinted;
+    }
+
+    /** Builder for {@link TabOEMV1} */
+    public static class Builder {
+        private String mTitle = null;
+        private Drawable mIcon = null;
+        private Runnable mOnSelectedListener = null;
+        private boolean mTinted = true;
+
+        private Builder() {
+        }
+
+        /** Sets the tab's text */
+        public Builder setTitle(String title) {
+            mTitle = title;
+            return this;
+        }
+
+        /** Sets the tab's icon */
+        public Builder setIcon(Drawable icon) {
+            mIcon = icon;
+            return this;
+        }
+
+        /** Sets a listener that is called when the tab is selected */
+        public Builder setOnSelectedListener(Runnable callback) {
+            mOnSelectedListener = callback;
+            return this;
+        }
+
+        /** See {@link TabOEMV1#isTinted} */
+        public Builder setTinted(boolean tinted) {
+            mTinted = tinted;
+            return this;
+        }
+
+        /** Builds the final {@link TabOEMV1} */
+        public TabOEMV1 build() {
+            return new TabOEMV1(this);
+        }
+    }
 }
diff --git a/car-ui-lib/referencedesign/product.mk b/car-ui-lib/referencedesign/product.mk
index 7cf8e7c..a68e882 100644
--- a/car-ui-lib/referencedesign/product.mk
+++ b/car-ui-lib/referencedesign/product.mk
@@ -1,7 +1,18 @@
 # Inherit from this product to include the "Reference Design" RROs for CarUi
 
-PRODUCT_PACKAGES += \
-   car-ui-lib-sharedlibrary \
+#############################################
+#                  WARNING                  #
+#############################################
+# The OEM APIs as they appear on this       #
+# branch of android are not finalized!      #
+# If a shared library is built using them,  #
+# it will cause apps to crash!              #
+#                                           #
+# Please only use a shared library with     #
+# a later version of car-ui-lib.            #
+#############################################
+#PRODUCT_PACKAGES += \
+#   car-ui-lib-sharedlibrary \
 
 PRODUCT_PRODUCT_PROPERTIES += ro.build.automotive.car.ui.shared.library.package.name=com.chassis.car.ui.sharedlibrary
 
diff --git a/car-ui-lib/referencedesign/sharedlibrary/Android.bp b/car-ui-lib/referencedesign/sharedlibrary/Android.bp
index 25b8276..384b741 100644
--- a/car-ui-lib/referencedesign/sharedlibrary/Android.bp
+++ b/car-ui-lib/referencedesign/sharedlibrary/Android.bp
@@ -2,6 +2,11 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
+android_app_certificate {
+    name: "car-ui-lib-sharedlibrary-certificate",
+    certificate: "chassis_upload_key"
+}
+
 android_app {
     name: "car-ui-lib-sharedlibrary",
 
@@ -27,4 +32,6 @@
     optimize: {
         enabled: false,
     },
+
+    certificate: ":car-ui-lib-sharedlibrary-certificate",
 }
diff --git a/car-ui-lib/referencedesign/sharedlibrary/build.gradle b/car-ui-lib/referencedesign/sharedlibrary/build.gradle
index 843f38a..99e0b1d 100644
--- a/car-ui-lib/referencedesign/sharedlibrary/build.gradle
+++ b/car-ui-lib/referencedesign/sharedlibrary/build.gradle
@@ -33,16 +33,15 @@
 
     // In order to adb install a new version of an app over it's preinstalled version, the new
     // version must be signed with the same key as the preinstalled version. If you don't specify
-    // a certificate in the Android.bp file (which we don't), the default certificate that will
+    // a certificate in the Android.bp file, the default certificate that will
     // be used is build/target/product/security/testkey.{pk8,x509.pem}. Android studio doesn't
     // support signing apps using individual pk8 and x509.pem files, it requires a keystore file.
-    // So the keystore in this project is just a repackaging of the testkey key.
     signingConfigs {
         debug {
-            storeFile file('keystore')
-            storePassword 'android'
-            keyAlias 'testkey'
-            keyPassword 'android'
+            storeFile file('chassis_upload_key.pepk')
+            storePassword 'chassis'
+            keyAlias 'chassis'
+            keyPassword 'chassis'
         }
     }
 }
diff --git a/car-ui-lib/referencedesign/sharedlibrary/chassis_upload_key.pepk b/car-ui-lib/referencedesign/sharedlibrary/chassis_upload_key.pepk
new file mode 100644
index 0000000..b765db1
--- /dev/null
+++ b/car-ui-lib/referencedesign/sharedlibrary/chassis_upload_key.pepk
Binary files differ
diff --git a/car-ui-lib/referencedesign/sharedlibrary/chassis_upload_key.pk8 b/car-ui-lib/referencedesign/sharedlibrary/chassis_upload_key.pk8
new file mode 100644
index 0000000..a867fdd
--- /dev/null
+++ b/car-ui-lib/referencedesign/sharedlibrary/chassis_upload_key.pk8
Binary files differ
diff --git a/car-ui-lib/referencedesign/sharedlibrary/chassis_upload_key.x509.pem b/car-ui-lib/referencedesign/sharedlibrary/chassis_upload_key.x509.pem
new file mode 100644
index 0000000..027a197
--- /dev/null
+++ b/car-ui-lib/referencedesign/sharedlibrary/chassis_upload_key.x509.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC9zCCAd+gAwIBAgIELMWXmDANBgkqhkiG9w0BAQsFADAsMQswCQYDVQQGEwJV
+UzELMAkGA1UECBMCQ0ExEDAOBgNVBAMTB0NoYXNzaXMwHhcNMjEwNTAzMTg1NDM5
+WhcNNDYwNDI3MTg1NDM5WjAsMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEDAO
+BgNVBAMTB0NoYXNzaXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCp
+JPZiygVOD1LEz+Hw3hS3SfCpqm5l57lje9K6hYqXN31l2xUsHaTBdz1w4AOTZgjm
+UQaY2m73HxMtOAli9OJUY6594orGYJS5dKqkuAnmMP4sCxvHRQvA413JERaKHXSz
+sg6AMkzOzPnTPqr+L2N013GaDj3knrz/7xKDvTJbHGVbPbogEDLZUs9hH7N8k03I
+jeU0ThDJpd2oJ/vzpv2bdV89gFmYAzu5hw+v1O2yPVf+OEsbL1kY+rJTmhTldtWJ
+/OPjHQQU/IV3TtQzy1xwEAsXC8M69VgoeGSBmQOo7tswuOMKngJ9OU8y0qFjbVUm
+xlwGix8nI6GxNlULrmSdAgMBAAGjITAfMB0GA1UdDgQWBBTkNQPmsZZ8KAjxOKXu
+u1fVHWWT7DANBgkqhkiG9w0BAQsFAAOCAQEAPQrN4tUM1lc40DsrMdAoSg7MZ0ji
+KOfGAjnPezJDqJY1fxoB4jRDd+ut13YiBFcnpH1LsJTekhkxLcL6mdCSOJO4f9UK
+YP/eMRS1tI5r/903qtdStzlYrBp+AKXicSV2q2Zr25AhZsFqDPR211xcKQNrmml1
+slCBK53Llk3wi795Disu1IlCsNN0CR4RmHAGOjZUU3QTNYyE6RhD3cdHZyzy0utt
+BkADfLvT7MCGHETDh1fvsNaieRzasV9dK30PTdQ8itj9+xel0cUnXTAXGs9YpudJ
+6ynTWXHZMU3N8Ay1Ip9d+J5pDSl//JXCSGFzVA3vO07AfUscQbtRoA/6lg==
+-----END CERTIFICATE-----
diff --git a/car-ui-lib/referencedesign/sharedlibrary/keystore b/car-ui-lib/referencedesign/sharedlibrary/keystore
deleted file mode 100644
index 49e4ecc..0000000
--- a/car-ui-lib/referencedesign/sharedlibrary/keystore
+++ /dev/null
Binary files differ
diff --git a/car-ui-lib/referencedesign/sharedlibrary/src/main/java/com/chassis/car/ui/sharedlibrary/toolbar/BaseLayoutInstaller.java b/car-ui-lib/referencedesign/sharedlibrary/src/main/java/com/chassis/car/ui/sharedlibrary/toolbar/BaseLayoutInstaller.java
index 9a7c13c..e5dcb80 100644
--- a/car-ui-lib/referencedesign/sharedlibrary/src/main/java/com/chassis/car/ui/sharedlibrary/toolbar/BaseLayoutInstaller.java
+++ b/car-ui-lib/referencedesign/sharedlibrary/src/main/java/com/chassis/car/ui/sharedlibrary/toolbar/BaseLayoutInstaller.java
@@ -23,6 +23,7 @@
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 
+import androidx.annotation.LayoutRes;
 import androidx.annotation.Nullable;
 
 import com.android.car.ui.sharedlibrary.oemapis.FocusAreaOEMV1;
@@ -54,11 +55,6 @@
             @Nullable Function<Context, FocusParkingViewOEMV1> focusParkingViewFactory,
             @Nullable Function<Context, FocusAreaOEMV1> focusAreaFactory) {
 
-        if (!toolbarEnabled) {
-            // We don't need a toolbar-less base layout in this design, so we're done.
-            return null;
-        }
-
         Context activityContext = contentView.getContext();
 
         // Add the configuration from the activity context to the shared library context,
@@ -67,8 +63,11 @@
         sharedLibraryContext = sharedLibraryContext.createConfigurationContext(
                 activityContext.getResources().getConfiguration());
 
+        @LayoutRes int layout = toolbarEnabled
+                ? R.layout.base_layout_toolbar
+                : R.layout.base_layout;
         FrameLayout baseLayout = (FrameLayout) LayoutInflater.from(sharedLibraryContext).inflate(
-                R.layout.base_layout_toolbar, null, false);
+                layout, null, false);
 
         // Replace the app's content view with a base layout
         ViewGroup contentViewParent = (ViewGroup) contentView.getParent();
@@ -103,7 +102,7 @@
         // the FocusArea using the app's context, so that it can access it's resources,
         // but we want children of the FocusArea to use the shared library context, so we can
         // access shared library resources.
-        if (focusAreaFactory != null) {
+        if (focusAreaFactory != null && toolbarEnabled) {
             LinearLayout focusArea = focusAreaFactory.apply(activityContext).getView();
             if (focusArea != null) {
                 View toolbar = baseLayout.requireViewById(R.id.toolbar_background);
@@ -116,8 +115,11 @@
         }
 
 
-        ToolbarControllerOEMV1 toolbarController = new ToolbarControllerImpl(
-                baseLayout, sharedLibraryContext, activityContext);
+        ToolbarControllerOEMV1 toolbarController = null;
+        if (toolbarEnabled) {
+            toolbarController = new ToolbarControllerImpl(
+                    baseLayout, sharedLibraryContext, activityContext);
+        }
 
         InsetsUpdater updater = new InsetsUpdater(baseLayout, contentView);
         updater.replaceInsetsChangedListenerWith(insetsChangedListener);
@@ -148,7 +150,7 @@
         private Consumer<InsetsOEMV1> mInsetsChangedListenerDelegate;
 
         private boolean mInsetsDirty = true;
-        private InsetsOEMV1 mInsets = new Insets();
+        private InsetsOEMV1 mInsets = new InsetsOEMV1();
 
         /**
          * Constructs an InsetsUpdater that calculates and dispatches insets to the method provided
@@ -251,7 +253,7 @@
                 right += Math.max(0,
                         getRightOfView(mContentViewContainer) - getLeftOfView(mRightInsetView));
             }
-            InsetsOEMV1 insets = new Insets(left, top, right, bottom);
+            InsetsOEMV1 insets = new InsetsOEMV1(left, top, right, bottom);
 
             mInsetsDirty = false;
             if (!insets.equals(mInsets)) {
diff --git a/car-ui-lib/referencedesign/sharedlibrary/src/main/java/com/chassis/car/ui/sharedlibrary/toolbar/Insets.java b/car-ui-lib/referencedesign/sharedlibrary/src/main/java/com/chassis/car/ui/sharedlibrary/toolbar/Insets.java
deleted file mode 100644
index 7b27a24..0000000
--- a/car-ui-lib/referencedesign/sharedlibrary/src/main/java/com/chassis/car/ui/sharedlibrary/toolbar/Insets.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.chassis.car.ui.sharedlibrary.toolbar;
-
-import com.android.car.ui.sharedlibrary.oemapis.InsetsOEMV1;
-
-import java.util.Objects;
-
-class Insets implements InsetsOEMV1 {
-    private final int mLeft;
-    private final int mRight;
-    private final int mTop;
-    private final int mBottom;
-
-    Insets() {
-        mLeft = mRight = mTop = mBottom = 0;
-    }
-
-    Insets(int left, int top, int right, int bottom) {
-        mLeft = left;
-        mRight = right;
-        mTop = top;
-        mBottom = bottom;
-    }
-
-    @Override
-    public int getLeft() {
-        return mLeft;
-    }
-
-    @Override
-    public int getRight() {
-        return mRight;
-    }
-
-    @Override
-    public int getTop() {
-        return mTop;
-    }
-
-    @Override
-    public int getBottom() {
-        return mBottom;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-        Insets insets = (Insets) o;
-        return mLeft == insets.mLeft
-                && mRight == insets.mRight
-                && mTop == insets.mTop
-                && mBottom == insets.mBottom;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mLeft, mRight, mTop, mBottom);
-    }
-}
diff --git a/car-ui-lib/referencedesign/sharedlibrary/src/main/java/com/chassis/car/ui/sharedlibrary/toolbar/TabLayout.java b/car-ui-lib/referencedesign/sharedlibrary/src/main/java/com/chassis/car/ui/sharedlibrary/toolbar/TabLayout.java
index 25168d7..868193d 100644
--- a/car-ui-lib/referencedesign/sharedlibrary/src/main/java/com/chassis/car/ui/sharedlibrary/toolbar/TabLayout.java
+++ b/car-ui-lib/referencedesign/sharedlibrary/src/main/java/com/chassis/car/ui/sharedlibrary/toolbar/TabLayout.java
@@ -112,9 +112,9 @@
         bindTab(oldSelectedTab);
         bindTab(mSelectedTab);
 
-        Runnable onClickListener = tab.getOnClickListener();
-        if (onClickListener != null && sendCallback) {
-            onClickListener.run();
+        Runnable onSelectedListener = tab.getOnSelectedListener();
+        if (onSelectedListener != null && sendCallback) {
+            onSelectedListener.run();
         }
     }
 
diff --git a/car-ui-lib/car-ui-lib/src/test/res/layout/test_linear_car_ui_recycler_view.xml b/car-ui-lib/referencedesign/sharedlibrary/src/main/res/layout/base_layout.xml
similarity index 77%
rename from car-ui-lib/car-ui-lib/src/test/res/layout/test_linear_car_ui_recycler_view.xml
rename to car-ui-lib/referencedesign/sharedlibrary/src/main/res/layout/base_layout.xml
index 8f7f2ad..fc2b830 100644
--- a/car-ui-lib/car-ui-lib/src/test/res/layout/test_linear_car_ui_recycler_view.xml
+++ b/car-ui-lib/referencedesign/sharedlibrary/src/main/res/layout/base_layout.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2019 The Android Open Source Project
+  ~ Copyright (C) 2021 The Android Open Source Project
   ~
   ~ Licensed under the Apache License, Version 2.0 (the "License");
   ~ you may not use this file except in compliance with the License.
@@ -14,12 +14,11 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-    <com.android.car.ui.recyclerview.CarUiRecyclerView
-        android:id="@+id/test_prv"
+    <FrameLayout
+        android:id="@+id/base_layout_content_container"
         android:layout_width="match_parent"
         android:layout_height="match_parent"/>
 </FrameLayout>