Snap for 7519874 from da02022f3364e2ae7924159a308566b000e458e9 to sc-release

Change-Id: If4e5a5ecbb46da655a2d501c1ec13b81af79e5ed
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 498e92b..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
@@ -32,6 +32,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 
 /**
  * Encapsulates data about a phone Contact entry. Typically loaded from the local Contact store.
@@ -200,11 +201,21 @@
 
     /**
      * All postal addresses of this contact mapping to the unique primary key for the raw data
-     * entry
+     * entry.
      */
     private final List<PostalAddress> mPostalAddresses = new ArrayList<>();
 
     /**
+     * Collator instance for proper comparison based on localized names.
+     */
+    private Collator mCollator;
+
+    /**
+     * Locale used for mCollator creation.
+     */
+    private Locale mLocale;
+
+    /**
      * Parses a contact entry for a Cursor loaded from the Contact Database. A new contact will be
      * created and returned.
      */
@@ -628,7 +639,7 @@
         for (int i = 0; i < phoneNumberListLength; i++) {
             PhoneNumber phoneNumber = source.readParcelable(PhoneNumber.class.getClassLoader());
             contact.mPhoneNumbers.add(phoneNumber);
-            if (phoneNumber.isPrimary()) {
+            if (phoneNumber != null && phoneNumber.isPrimary()) {
                 contact.mPrimaryPhoneNumber = phoneNumber;
             }
         }
@@ -676,8 +687,12 @@
         if (type != otherType) {
             return Integer.compare(type, otherType);
         }
-        Collator collator = Collator.getInstance();
-        return collator.compare(name == null ? "" : name, otherName == null ? "" : otherName);
+        Locale currentLocale = Locale.getDefault();
+        if (mCollator == null || mLocale == null || !mLocale.equals(currentLocale)) {
+            mCollator = Collator.getInstance(currentLocale);
+            mLocale = currentLocale;
+        }
+        return mCollator.compare(name == null ? "" : name, otherName == null ? "" : otherName);
     }
 
     /**
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 572dc8a..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,12 +38,18 @@
 import java.util.Collections;
 import java.util.List;
 
-
 @RunWith(RobolectricTestRunner.class)
 public class ContactTest {
 
     private static final int DISPLAY_NAME_COLUMN = 1;
+    private static final int MIMETYPE_COLUMN = 2;
+    private static final int LOOK_UP_KEY_COLUMN = 3;
+    private static final int PRIMARY_KEY_COLUMN = 4;
+    private static final String PHONEBOOK_LABEL = "phonebook_label";
+    private static final int PHONEBOOK_LABEL_COLUMN = 5;
 
+    private static final String EMPTY_MIME = "";
+    private static final String DEFAULT_LOOK_UP_KEY = "PRIMARY";
     private static final String NULL_NAME = null;
     private static final String EMPTY_NAME = "";
     private static final String LETTER_NAME_1 = "test";
@@ -79,94 +85,124 @@
 
         when(mMockCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)).thenReturn(
                 DISPLAY_NAME_COLUMN);
+        when(mMockCursor.getColumnIndex(ContactsContract.RawContacts.SORT_KEY_PRIMARY)).thenReturn(
+                PRIMARY_KEY_COLUMN);
+        when(mMockCursor.getColumnIndex(ContactsContract.Data.MIMETYPE)).thenReturn(
+                MIMETYPE_COLUMN);
+        when(mMockCursor.getString(MIMETYPE_COLUMN)).thenReturn(EMPTY_MIME);
+        when(mMockCursor.getColumnIndex(ContactsContract.Data.LOOKUP_KEY)).thenReturn(
+                LOOK_UP_KEY_COLUMN);
+        when(mMockCursor.getString(LOOK_UP_KEY_COLUMN)).thenReturn(DEFAULT_LOOK_UP_KEY);
+        when(mMockCursor.getColumnIndex(PHONEBOOK_LABEL)).thenReturn(
+                PHONEBOOK_LABEL_COLUMN);
+
         when(mMockContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(
                 mMockTelephonyManager);
         when(mMockTelephonyManager.getSimCountryIso()).thenReturn("");
 
-        when(mMockCursor.getString(DISPLAY_NAME_COLUMN)).thenReturn(NULL_NAME);
+        when(mMockCursor.getString(PHONEBOOK_LABEL_COLUMN)).thenReturn("");
+        when(mMockCursor.getString(PRIMARY_KEY_COLUMN)).thenReturn(NULL_NAME);
         mNullName = Contact.fromCursor(mMockContext, mMockCursor);
-        when(mMockCursor.getString(DISPLAY_NAME_COLUMN)).thenReturn(EMPTY_NAME);
+        when(mMockCursor.getString(PRIMARY_KEY_COLUMN)).thenReturn(EMPTY_NAME);
         mEmptyName = Contact.fromCursor(mMockContext, mMockCursor);
-        when(mMockCursor.getString(DISPLAY_NAME_COLUMN)).thenReturn(LETTER_NAME_1);
+
+        when(mMockCursor.getString(PHONEBOOK_LABEL_COLUMN)).thenReturn("T");
+        when(mMockCursor.getString(PRIMARY_KEY_COLUMN)).thenReturn(LETTER_NAME_1);
         mLetterName1 = Contact.fromCursor(mMockContext, mMockCursor);
-        when(mMockCursor.getString(DISPLAY_NAME_COLUMN)).thenReturn(LETTER_NAME_2);
+        when(mMockCursor.getString(PRIMARY_KEY_COLUMN)).thenReturn(LETTER_NAME_2);
         mLetterName2 = Contact.fromCursor(mMockContext, mMockCursor);
-        when(mMockCursor.getString(DISPLAY_NAME_COLUMN)).thenReturn(DIGIT_NAME_1);
+
+        when(mMockCursor.getString(PHONEBOOK_LABEL_COLUMN)).thenReturn("#");
+        when(mMockCursor.getString(PRIMARY_KEY_COLUMN)).thenReturn(DIGIT_NAME_1);
         mDigitName1 = Contact.fromCursor(mMockContext, mMockCursor);
-        when(mMockCursor.getString(DISPLAY_NAME_COLUMN)).thenReturn(DIGIT_NAME_2);
+        when(mMockCursor.getString(PRIMARY_KEY_COLUMN)).thenReturn(DIGIT_NAME_2);
         mDigitName2 = Contact.fromCursor(mMockContext, mMockCursor);
-        when(mMockCursor.getString(DISPLAY_NAME_COLUMN)).thenReturn(SPEC_CHAR_NAME);
+
+        when(mMockCursor.getString(PHONEBOOK_LABEL_COLUMN)).thenReturn("");
+        when(mMockCursor.getString(PRIMARY_KEY_COLUMN)).thenReturn(SPEC_CHAR_NAME);
         mSpecCharName = Contact.fromCursor(mMockContext, mMockCursor);
     }
 
     @Test
     public void compareTo_TwoNullStrings_Equal() {
+        // NULL == NULL
         int compareResult = mNullName.compareTo(mNullName);
         assertEquals(COMPARE_RESULT_EQUAL, compareResult);
     }
 
     @Test
     public void compareTo_TwoEmptyStrings_Equal() {
+        // "" == NULL
         int compareResult = mEmptyName.compareTo(mEmptyName);
         assertEquals(COMPARE_RESULT_EQUAL, compareResult);
     }
 
     @Test
     public void compareTo_TwoLetterStrings_Larger() {
+        // "test" > "ta"
         int compareResult = mLetterName1.compareTo(mLetterName2);
         assertEquals(COMPARE_RESULT_LARGER, compareResult);
     }
 
     @Test
     public void compareTo_TwoDigitStrings_Smaller() {
+        // "123" < "321"
         int compareResult = mDigitName1.compareTo(mDigitName2);
         assertEquals(COMPARE_RESULT_SMALLER, compareResult);
     }
 
     @Test
     public void compareTo_LetterAndDigitStrings_Smaller() {
+        // "test" < "123", because of Phonebook_label
         int compareResult = mLetterName1.compareTo(mDigitName1);
         assertEquals(COMPARE_RESULT_SMALLER, compareResult);
     }
 
     @Test
     public void compareTo_LetterAndSpecialCharStrings_Smaller() {
+        // "test" <"-", because of Phonebook_label
         int compareResult = mLetterName1.compareTo(mSpecCharName);
         assertEquals(COMPARE_RESULT_SMALLER, compareResult);
     }
 
     @Test
     public void compareTo_LetterAndEmptyStrings_Smaller() {
+        // "test" < "", because of Phonebook_label
         int compareResult = mLetterName1.compareTo(mEmptyName);
         assertEquals(COMPARE_RESULT_SMALLER, compareResult);
     }
 
     @Test
     public void compareTo_LetterAndNullStrings_Smaller() {
+        // "test < NULL, because of Phonebook_label
         int compareResult = mLetterName1.compareTo(mNullName);
         assertEquals(COMPARE_RESULT_SMALLER, compareResult);
     }
 
     @Test
     public void compareTo_DigitAndSpecialCharStrings_Smaller() {
+        // "123" < "-", because of Phonebook_label
         int compareResult = mDigitName1.compareTo(mSpecCharName);
         assertEquals(COMPARE_RESULT_SMALLER, compareResult);
     }
 
     @Test
     public void compareTo_DigitAndEmptyStrings_Smaller() {
+        // "123" > "", because of Phonebook_label
         int compareResult = mDigitName1.compareTo(mEmptyName);
         assertEquals(COMPARE_RESULT_SMALLER, compareResult);
     }
 
     @Test
     public void compareTo_DigitAndNullStrings_Smaller() {
+        // "123" < NULL, because of Phonebook_label
         int compareResult = mDigitName1.compareTo(mNullName);
         assertEquals(COMPARE_RESULT_SMALLER, compareResult);
     }
 
     @Test
     public void compareTo_SpecialCharAndEmptyStrings_Any() {
+        // "-" > ""
         int compareResult = mSpecCharName.compareTo(mEmptyName);
         assertThat(compareResult).isAnyOf(COMPARE_RESULT_SMALLER, COMPARE_RESULT_EQUAL,
                 COMPARE_RESULT_LARGER);
@@ -174,6 +210,7 @@
 
     @Test
     public void compareTo_SpecialCharAndNullStrings_Any() {
+        // "-" > NULL
         int compareResult = mSpecCharName.compareTo(mNullName);
         assertThat(compareResult).isAnyOf(COMPARE_RESULT_SMALLER, COMPARE_RESULT_EQUAL,
                 COMPARE_RESULT_LARGER);
@@ -181,24 +218,97 @@
 
     @Test
     public void compareTo_EmptyAndNullStrings_Equal() {
+        // "" == NULL
         int compareResult = mEmptyName.compareTo(mNullName);
         assertEquals(COMPARE_RESULT_EQUAL, compareResult);
     }
 
     @Test
     public void sortContactTest() {
-        List<Contact> sortResultList = new ArrayList<>();
-        sortResultList.add(mLetterName2);
-        sortResultList.add(mLetterName1);
-        sortResultList.add(mDigitName1);
-        sortResultList.add(mDigitName2);
-        sortResultList.add(mEmptyName);
-        sortResultList.add(mSpecCharName);
-        List<Contact> contactList = new ArrayList<>();
-        contactList.addAll(sortResultList);
+        List<Contact> expectedList = new ArrayList<>();
+        expectedList.add(mLetterName2);
+        expectedList.add(mLetterName1);
+        expectedList.add(mDigitName1);
+        expectedList.add(mDigitName2);
+        expectedList.add(mEmptyName);
+        expectedList.add(mSpecCharName);
 
-        Collections.shuffle(contactList);
+        List<Contact> contactList = new ArrayList<>();
+        contactList.add(mDigitName1);
+        contactList.add(mSpecCharName);
+        contactList.add(mLetterName1);
+        contactList.add(mEmptyName);
+        contactList.add(mLetterName2);
+        contactList.add(mDigitName2);
+
         Collections.sort(contactList);
-        assertArrayEquals(sortResultList.toArray(), contactList.toArray());
+        assertArrayEquals(expectedList.toArray(), contactList.toArray());
+    }
+
+    @Test
+    public void sortContactPrimaryTest() {
+        when(mMockCursor.getString(PRIMARY_KEY_COLUMN)).thenReturn("tä");
+        Contact letterName3 = Contact.fromCursor(mMockContext, mMockCursor);
+
+        when(mMockCursor.getString(PRIMARY_KEY_COLUMN)).thenReturn("tb");
+        Contact letterName4 = Contact.fromCursor(mMockContext, mMockCursor);
+
+        List<Contact> expectedList = new ArrayList<>();
+        expectedList.add(mLetterName2);
+        expectedList.add(letterName3);
+        expectedList.add(letterName4);
+        expectedList.add(mLetterName1);
+        expectedList.add(mDigitName1);
+        expectedList.add(mDigitName2);
+        expectedList.add(mEmptyName);
+        expectedList.add(mSpecCharName);
+
+        List<Contact> contactList = new ArrayList<>();
+        contactList.add(mDigitName1);
+        contactList.add(letterName4);
+        contactList.add(mSpecCharName);
+        contactList.add(mLetterName1);
+        contactList.add(mEmptyName);
+        contactList.add(mLetterName2);
+        contactList.add(letterName3);
+        contactList.add(mDigitName2);
+
+        Collections.sort(contactList, (o1, o2) -> o1.compareBySortKeyPrimary(o2));
+        assertArrayEquals(expectedList.toArray(), contactList.toArray());
+    }
+
+    @Test
+    public void sortContactAlternativeTest() {
+        int alternativeColumnIndex = 20;
+        when(mMockCursor.getColumnIndex(ContactsContract.RawContacts.SORT_KEY_ALTERNATIVE))
+                .thenReturn(alternativeColumnIndex);
+        when(mMockCursor.getString(alternativeColumnIndex)).thenReturn("tä");
+        Contact letterName3 = Contact.fromCursor(mMockContext, mMockCursor);
+
+        when(mMockCursor.getString(alternativeColumnIndex)).thenReturn("tb");
+        Contact letterName4 = Contact.fromCursor(mMockContext, mMockCursor);
+
+        List<Contact> expectedList = new ArrayList<>();
+        expectedList.add(mLetterName2);
+        expectedList.add(letterName3);
+        expectedList.add(letterName4);
+        expectedList.add(mLetterName1);
+        expectedList.add(mDigitName1);
+        expectedList.add(mDigitName2);
+        expectedList.add(mEmptyName);
+        expectedList.add(mSpecCharName);
+
+        List<Contact> contactList = new ArrayList<>();
+        contactList.add(mDigitName1);
+        contactList.add(letterName4);
+        contactList.add(mSpecCharName);
+        contactList.add(mLetterName1);
+        contactList.add(mEmptyName);
+        contactList.add(mLetterName2);
+        contactList.add(letterName3);
+        contactList.add(mDigitName2);
+
+        Collections.sort(contactList, (o1, o2) -> o1.compareBySortKeyAlt(o2));
+        assertArrayEquals(expectedList.toArray(), contactList.toArray());
     }
 }
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/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/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 602777a..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
@@ -150,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
@@ -253,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();
         }
     }