Merge "Remove overscroll from app styled view" into car-apps-dev
diff --git a/car-telephony-common/Android.bp b/car-telephony-common/Android.bp
index cb9c6c2..1222cd8 100644
--- a/car-telephony-common/Android.bp
+++ b/car-telephony-common/Android.bp
@@ -25,7 +25,6 @@
     "car-apps-common-prebuilt",
     "glide-prebuilt",
     "guava",
-    "libphonenumber",
 ]
 
 android_library {
diff --git a/car-telephony-common/build.gradle b/car-telephony-common/build.gradle
index 072bff2..1a5e785 100644
--- a/car-telephony-common/build.gradle
+++ b/car-telephony-common/build.gradle
@@ -53,7 +53,6 @@
 
     implementation 'com.github.bumptech.glide:glide:4.12.0'
     implementation 'com.google.guava:guava:30.1.1-android'
-    implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.31'
 
     implementation project(':car-apps-common')
 
diff --git a/car-telephony-common/src/com/android/car/telephony/common/InMemoryPhoneBook.java b/car-telephony-common/src/com/android/car/telephony/common/InMemoryPhoneBook.java
index 5e8bfb8..b33a718 100644
--- a/car-telephony-common/src/com/android/car/telephony/common/InMemoryPhoneBook.java
+++ b/car-telephony-common/src/com/android/car/telephony/common/InMemoryPhoneBook.java
@@ -26,8 +26,8 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.WorkerThread;
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.Observer;
 import androidx.lifecycle.Transformations;
@@ -36,7 +36,6 @@
 import com.android.car.telephony.common.QueryParam.QueryBuilder.Condition;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -173,7 +172,7 @@
      * Looks up a {@link Contact} by the given phone number. Returns null if can't find a Contact or
      * the {@link InMemoryPhoneBook} is still loading.
      *
-     * @deprecated Use {@link #lookupContactByKey(String, String)} instead.
+     * @deprecated Use {@link #lookupContactEntry(String, String)} instead.
      */
     @Deprecated
     @Nullable
@@ -198,7 +197,7 @@
     }
 
     /**
-     * Looks up a {@link Contact} by the given phone number and account name.
+     * Looks up the in memory cache for a {@link Contact} by the given phone number and account.
      */
     @Nullable
     public Contact lookupContactEntry(String phoneNumber, @Nullable String accountName) {
@@ -218,6 +217,20 @@
     }
 
     /**
+     * Looks up a {@link Contact} by the given phone number and account name. If it fails to hit the
+     * in memory cache, do a phone look up. This api should only be used for displaying caller info
+     * for HUN and ongoing calls before the in memory cache fully loads.
+     */
+    @WorkerThread
+    public Contact lookupContactEntryAsync(String phoneNumber, @Nullable String accountName) {
+        Contact contact = lookupContactEntry(phoneNumber, accountName);
+        if (contact == null) {
+            contact = TelecomUtils.lookupContactEntryAsync(mContext, phoneNumber, accountName);
+        }
+        return contact;
+    }
+
+    /**
      * Looks up a {@link Contact} by the given lookup key and account name. Account name could be
      * null for locally added contacts. Returns null if can't find the contact entry.
      */
@@ -237,32 +250,6 @@
         return null;
     }
 
-    /**
-     * Iterates all the accounts and returns a list of contacts that match the lookup key. This API
-     * is discouraged to use whenever the account name is available where {@link
-     * #lookupContactByKey(String, String)} should be used instead.
-     */
-    @NonNull
-    public List<Contact> lookupContactByKey(String lookupKey) {
-        if (!isLoaded()) {
-            L.w(TAG, "looking up a contact while loading.");
-        }
-
-        if (TextUtils.isEmpty(lookupKey)) {
-            L.w(TAG, "looking up an empty lookup key.");
-            return Collections.emptyList();
-        }
-        List<Contact> results = new ArrayList<>();
-        // Iterate all the accounts to get all the match contacts with given lookup key.
-        for (Map<String, Contact> subMap : mLookupKeyContactMap.values()) {
-            if (subMap.containsKey(lookupKey)) {
-                results.add(subMap.get(lookupKey));
-            }
-        }
-
-        return results;
-    }
-
     private List<Contact> onCursorLoaded(Cursor cursor) {
         Map<String, Map<String, Contact>> contactMap = new LinkedHashMap<>();
         List<Contact> contactList = new ArrayList<>();
diff --git a/car-telephony-common/src/com/android/car/telephony/common/TelecomUtils.java b/car-telephony-common/src/com/android/car/telephony/common/TelecomUtils.java
index 8949ff7..69791ea 100644
--- a/car-telephony-common/src/com/android/car/telephony/common/TelecomUtils.java
+++ b/car-telephony-common/src/com/android/car/telephony/common/TelecomUtils.java
@@ -52,9 +52,6 @@
 
 import com.bumptech.glide.Glide;
 import com.bumptech.glide.request.RequestOptions;
-import com.google.i18n.phonenumbers.NumberParseException;
-import com.google.i18n.phonenumbers.PhoneNumberUtil;
-import com.google.i18n.phonenumbers.Phonenumber;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -180,19 +177,6 @@
     }
 
     /**
-     * Creates a new instance of {@link Phonenumber.PhoneNumber} base on the given number and sim
-     * card country code. Returns {@code null} if the number in an invalid number.
-     */
-    @Nullable
-    public static Phonenumber.PhoneNumber createI18nPhoneNumber(Context context, String number) {
-        try {
-            return PhoneNumberUtil.getInstance().parse(number, getCurrentCountryIso(context));
-        } catch (NumberParseException e) {
-            return null;
-        }
-    }
-
-    /**
      * Contains all the info used to display a phone number on the screen. Returned by {@link
      * #getPhoneNumberInfo(Context, String)}
      */
@@ -258,10 +242,7 @@
      * Gets all the info needed to properly display a phone number to the UI. (e.g. if it's the
      * voicemail number, return a string and a uri that represents voicemail, if it's a contact, get
      * the contact's name, its avatar uri, the phone number's label, etc).
-     *
-     * @deprecated use {@link InMemoryPhoneBook#lookupContactEntry(String, String)} instead.
      */
-    @Deprecated
     public static CompletableFuture<PhoneNumberInfo> getPhoneNumberInfo(
             Context context, String number) {
         return CompletableFuture.supplyAsync(() -> lookupNumberInBackground(context, number));
@@ -270,7 +251,7 @@
     /**
      * Lookup phone number info in background.
      *
-     * @deprecated use {@link InMemoryPhoneBook#lookupContactEntry(String, String)} instead.
+     * @deprecated Use {@link InMemoryPhoneBook#lookupContactEntryAsync(String, String)} instead.
      */
     @Deprecated
     @WorkerThread
@@ -394,6 +375,53 @@
     }
 
     /**
+     * Lookup a contact for the given number and account in background.
+     */
+    static Contact lookupContactEntryAsync(
+            Context context, String number, String accountName) {
+        if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS)
+                != PackageManager.PERMISSION_GRANTED || TextUtils.isEmpty(number)) {
+            return null;
+        }
+
+        ContentResolver cr = context.getContentResolver();
+        Cursor lookupCursor = null;
+        Cursor loadCursor = null;
+        Contact contact = null;
+        try {
+            lookupCursor = cr.query(
+                    Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)),
+                    null, null, null, null);
+            if (lookupCursor == null) {
+                return null;
+            }
+
+            while (lookupCursor.moveToNext()) {
+                int lookupKeyColumn = lookupCursor.getColumnIndex(PhoneLookup.LOOKUP_KEY);
+                String lookupKey = lookupCursor.getString(lookupKeyColumn);
+                String selection = Phone.LOOKUP_KEY + " = ?"
+                        + " AND "
+                        + ContactsContract.RawContacts.ACCOUNT_NAME + " = ?";
+                String[] selectionArgs = new String[]{lookupKey, accountName};
+                loadCursor = cr.query(Phone.CONTENT_URI, null, selection, selectionArgs, null);
+                if (loadCursor.moveToFirst()) {
+                    contact = Contact.fromCursor(context, loadCursor);
+                    break;
+                }
+            }
+        } finally {
+            if (lookupCursor != null) {
+                lookupCursor.close();
+            }
+            if (loadCursor != null) {
+                loadCursor.close();
+            }
+        }
+
+        return contact;
+    }
+
+    /**
      * @return A string representation of the call state that can be presented to a user.
      */
     public static String callStateToUiString(Context context, int state) {
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 b55a0ec..9e0f36e 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
@@ -32,6 +32,7 @@
 
 import static com.android.car.ui.actions.ViewActions.setProgress;
 import static com.android.car.ui.core.CarUi.MIN_TARGET_API;
+import static com.android.car.ui.matchers.ViewMatchers.isActivated;
 import static com.android.car.ui.matchers.ViewMatchers.withIndex;
 
 import static junit.framework.Assert.assertFalse;
@@ -337,7 +338,6 @@
         // Scroll until list preference is visible
         mActivity.runOnUiThread(() -> mActivity.scrollToPreference("switch"));
 
-
         // Check title and summary are displayed as expected.
         onView(withIndex(withId(android.R.id.title), 0)).check(matches(
                 withText(mActivity.getString(R.string.title_switch_preference))));
@@ -372,6 +372,54 @@
     }
 
     @Test
+    public void testPrimarySwitchPreference() {
+        // Create switch preference and add it to screen.
+        CarUiPrimarySwitchPreference preference = new CarUiPrimarySwitchPreference(mActivity);
+        preference.setOrder(0);
+        preference.setKey("switch");
+        preference.setTitle(R.string.title_switch_preference);
+        preference.setSummary(R.string.summary_compound_button_preference);
+        mActivity.addPreference(preference);
+
+        // Scroll until list preference is visible
+        mActivity.runOnUiThread(() -> mActivity.scrollToPreference("switch"));
+
+        // Check title and summary are displayed as expected.
+        onView(withIndex(withId(android.R.id.title), 0)).check(matches(
+                withText(mActivity.getString(R.string.title_switch_preference))));
+        onView(withIndex(withId(android.R.id.summary), 0)).check(matches(
+                withText(mActivity.getString(R.string.summary_compound_button_preference))));
+
+        // Ensure switch preference is initially not selected.
+        onView(withId(android.R.id.switch_widget)).check(matches(isNotChecked()));
+
+        Preference.OnPreferenceChangeListener mockListener = mock(
+                Preference.OnPreferenceChangeListener.class);
+        when(mockListener.onPreferenceChange(any(), any())).thenReturn(true);
+        mActivity.setOnPreferenceChangeListener("switch", mockListener);
+
+        // Select switch preference.
+        onView(withText(R.string.title_switch_preference)).perform(click());
+
+        // Verify preference value was updated.
+        verify(mockListener, times(1)).onPreferenceChange(any(), eq(true));
+
+        // Verify switch preference correctly indicates preference is selected.
+        onView(withId(android.R.id.switch_widget)).check(matches(isChecked()));
+        onView(withText(R.string.title_switch_preference)).check(matches(isActivated()));
+
+        // Un-select switch preference.
+        onView(withText(R.string.title_switch_preference)).perform(click());
+
+        // Verify preference value was updated.
+        verify(mockListener, times(1)).onPreferenceChange(any(), eq(false));
+
+        // Verify switch preference correctly indicates preference is selected.
+        onView(withId(android.R.id.switch_widget)).check(matches(isNotChecked()));
+        onView(withText(R.string.title_switch_preference)).check(matches(not(isActivated())));
+    }
+
+    @Test
     public void testSwitchPreference_uxRestricted() {
         // Create switch preference and add it to screen.
         CarUiSwitchPreference preference = new CarUiSwitchPreference(mActivity);
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/preference/CarUiPrimarySwitchPreference.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/preference/CarUiPrimarySwitchPreference.java
new file mode 100644
index 0000000..6586464
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/preference/CarUiPrimarySwitchPreference.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2022 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.preference;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.car.ui.R;
+
+/**
+ * This class is the same as the base {@link CarUiSwitchPreference} class, except supports separate
+ * distinguishing styling.
+ */
+public class CarUiPrimarySwitchPreference extends CarUiSwitchPreference {
+    private View mItemView;
+
+    public CarUiPrimarySwitchPreference(Context context,
+            AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        init();
+    }
+
+    public CarUiPrimarySwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+    public CarUiPrimarySwitchPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init();
+    }
+
+    public CarUiPrimarySwitchPreference(Context context) {
+        super(context);
+        init();
+    }
+
+    private void init() {
+        setLayoutResource(R.layout.car_ui_preference_primary_switch);
+    }
+
+    @Override
+    public void onBindViewHolder(PreferenceViewHolder holder) {
+        super.onBindViewHolder(holder);
+        mItemView = holder.itemView;
+        mItemView.setActivated(isChecked());
+    }
+
+    @Override
+    public void setChecked(boolean checked) {
+        super.setChecked(checked);
+        if (mItemView != null) {
+            mItemView.setActivated(checked);
+        }
+    }
+}
diff --git a/car-ui-lib/car-ui-lib/src/main/res-overlayable/values/overlayable.xml b/car-ui-lib/car-ui-lib/src/main/res-overlayable/values/overlayable.xml
index 371c0b1..1ce20f8 100644
--- a/car-ui-lib/car-ui-lib/src/main/res-overlayable/values/overlayable.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res-overlayable/values/overlayable.xml
@@ -1,5 +1,5 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<!--Copyright (C) 2021 The Android Open Source Project
+<!--Copyright (C) 2022 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.
@@ -495,6 +495,7 @@
       <item type="layout" name="car_ui_preference_dropdown"/>
       <item type="layout" name="car_ui_preference_fragment"/>
       <item type="layout" name="car_ui_preference_fragment_with_toolbar"/>
+      <item type="layout" name="car_ui_preference_primary_switch"/>
       <item type="layout" name="car_ui_preference_two_action_icon"/>
       <item type="layout" name="car_ui_preference_two_action_switch"/>
       <item type="layout" name="car_ui_preference_two_action_text"/>
diff --git a/car-ui-lib/car-ui-lib/src/main/res-private/color/car_ui_preference_primary_switch_background_color.xml b/car-ui-lib/car-ui-lib/src/main/res-private/color/car_ui_preference_primary_switch_background_color.xml
new file mode 100644
index 0000000..3c93840
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/main/res-private/color/car_ui_preference_primary_switch_background_color.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_activated="false"
+        android:color="#202124"/>
+    <item android:color="?android:attr/colorAccent"
+        android:alpha="0.24"/>
+</selector>
diff --git a/car-ui-lib/car-ui-lib/src/main/res-private/drawable/car_ui_preference_primary_switch_background.xml b/car-ui-lib/car-ui-lib/src/main/res-private/drawable/car_ui_preference_primary_switch_background.xml
new file mode 100644
index 0000000..95f4e0c
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/main/res-private/drawable/car_ui_preference_primary_switch_background.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:gravity="center">
+        <shape android:shape="rectangle">
+            <corners android:radius="24dp" />
+            <solid android:color="@color/car_ui_preference_primary_switch_background_color" />
+        </shape>
+    </item>
+    <item android:drawable="@drawable/car_ui_preference_primary_switch_rotary_highlight" />
+</layer-list>
diff --git a/car-ui-lib/car-ui-lib/src/main/res-private/drawable/car_ui_preference_primary_switch_rotary_highlight.xml b/car-ui-lib/car-ui-lib/src/main/res-private/drawable/car_ui_preference_primary_switch_rotary_highlight.xml
new file mode 100644
index 0000000..af43b0e
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/main/res-private/drawable/car_ui_preference_primary_switch_rotary_highlight.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true" android:state_pressed="true">
+        <shape android:shape="rectangle">
+            <corners android:radius="24dp" />
+            <solid android:color="@color/car_ui_rotary_focus_pressed_fill_color" />
+            <stroke
+                android:width="@dimen/car_ui_rotary_focus_pressed_stroke_width"
+                android:color="@color/car_ui_rotary_focus_pressed_stroke_color" />
+        </shape>
+    </item>
+    <item android:state_focused="true">
+        <shape android:shape="rectangle">
+            <corners android:radius="24dp" />
+            <solid android:color="@color/car_ui_rotary_focus_fill_color" />
+            <stroke
+                android:width="@dimen/car_ui_rotary_focus_stroke_width"
+                android:color="@color/car_ui_rotary_focus_stroke_color" />
+        </shape>
+    </item>
+    <item>
+        <ripple android:color="?android:attr/colorControlHighlight" />
+    </item>
+</selector>
diff --git a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_primary_switch.xml b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_primary_switch.xml
new file mode 100644
index 0000000..a3b5f63
--- /dev/null
+++ b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_primary_switch.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 2022 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.
+-->
+
+<com.android.car.ui.uxr.DrawableStateRelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/car_ui_preference_primary_switch_background"
+    android:clipToPadding="false"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:tag="carUiPreference"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart">
+
+    <com.android.car.ui.uxr.DrawableStateImageView
+        android:id="@android:id/icon"
+        android:layout_width="@dimen/car_ui_preference_icon_size"
+        android:layout_height="@dimen/car_ui_preference_icon_size"
+        android:layout_alignParentStart="true"
+        android:layout_centerVertical="true"
+        android:layout_marginBottom="@dimen/car_ui_preference_content_margin_bottom"
+        android:layout_marginEnd="@dimen/car_ui_preference_icon_margin_end"
+        android:layout_marginTop="@dimen/car_ui_preference_content_margin_top"
+        android:scaleType="fitCenter"
+        style="@style/Preference.CarUi.Icon"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:layout_marginBottom="@dimen/car_ui_preference_content_margin_bottom"
+        android:layout_marginTop="@dimen/car_ui_preference_content_margin_top"
+        android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
+        android:layout_toEndOf="@android:id/icon"
+        android:layout_toStartOf="@android:id/widget_frame"
+        android:orientation="vertical">
+
+        <com.android.car.ui.uxr.DrawableStateTextView
+            android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="@style/TextAppearance.CarUi.PreferenceTitle"/>
+
+        <com.android.car.ui.uxr.DrawableStateTextView
+            android:id="@android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.CarUi.PreferenceSummary"/>
+
+    </LinearLayout>
+
+    <!-- Preference should place its actual preference widget here. -->
+    <FrameLayout
+        android:id="@android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_centerVertical="true"/>
+
+</com.android.car.ui.uxr.DrawableStateRelativeLayout>
diff --git a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_icon.xml b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_icon.xml
index c5c4fee..aba8279 100644
--- a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_icon.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_icon.xml
@@ -25,7 +25,7 @@
 
     <com.android.car.ui.uxr.DrawableStateConstraintLayout
         android:id="@+id/car_ui_first_action_container"
-        android:layout_height="0dp"
+        android:layout_height="wrap_content"
         android:layout_width="0dp"
         android:background="?android:attr/selectableItemBackground"
         android:paddingStart="?android:attr/listPreferredItemPaddingStart"
@@ -76,7 +76,7 @@
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/car_ui_second_action_container"
-        android:layout_height="0dp"
+        android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         app:layout_constraintStart_toEndOf="@id/car_ui_first_action_container"
         app:layout_constraintEnd_toEndOf="parent"
diff --git a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_switch.xml b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_switch.xml
index 3d7f6fa..82e1772 100644
--- a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_switch.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_switch.xml
@@ -25,7 +25,7 @@
 
     <com.android.car.ui.uxr.DrawableStateConstraintLayout
         android:id="@+id/car_ui_first_action_container"
-        android:layout_height="0dp"
+        android:layout_height="wrap_content"
         android:layout_width="0dp"
         android:background="?android:attr/selectableItemBackground"
         android:paddingStart="?android:attr/listPreferredItemPaddingStart"
@@ -76,7 +76,7 @@
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/car_ui_second_action_container"
-        android:layout_height="0dp"
+        android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         app:layout_constraintStart_toEndOf="@id/car_ui_first_action_container"
         app:layout_constraintEnd_toEndOf="parent"
diff --git a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_text.xml b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_text.xml
index 6f568c0..0aab5d2 100644
--- a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_text.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_text.xml
@@ -25,7 +25,7 @@
 
     <com.android.car.ui.uxr.DrawableStateConstraintLayout
         android:id="@+id/car_ui_first_action_container"
-        android:layout_height="0dp"
+        android:layout_height="wrap_content"
         android:layout_width="0dp"
         android:background="?android:attr/selectableItemBackground"
         android:paddingStart="?android:attr/listPreferredItemPaddingStart"
@@ -76,7 +76,7 @@
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/car_ui_second_action_container"
-        android:layout_height="0dp"
+        android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
         app:layout_constraintStart_toEndOf="@id/car_ui_first_action_container"
diff --git a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_text_borderless.xml b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_text_borderless.xml
index d329d98..0b00b1c 100644
--- a/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_text_borderless.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res/layout/car_ui_preference_two_action_text_borderless.xml
@@ -25,7 +25,7 @@
 
     <com.android.car.ui.uxr.DrawableStateConstraintLayout
         android:id="@+id/car_ui_first_action_container"
-        android:layout_height="0dp"
+        android:layout_height="wrap_content"
         android:layout_width="0dp"
         android:background="?android:attr/selectableItemBackground"
         android:paddingStart="?android:attr/listPreferredItemPaddingStart"
@@ -76,7 +76,7 @@
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/car_ui_second_action_container"
-        android:layout_height="0dp"
+        android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
         app:layout_constraintStart_toEndOf="@id/car_ui_first_action_container"
diff --git a/car-ui-lib/car-ui-lib/src/main/res/raw/car_ui_keep.xml b/car-ui-lib/car-ui-lib/src/main/res/raw/car_ui_keep.xml
index d3864e9..dae8e6e 100644
--- a/car-ui-lib/car-ui-lib/src/main/res/raw/car_ui_keep.xml
+++ b/car-ui-lib/car-ui-lib/src/main/res/raw/car_ui_keep.xml
@@ -15,20 +15,27 @@
 -->
 <resources xmlns:tools="http://schemas.android.com/tools"
     tools:keep="
+               @array/car_ui_*,
+               @attr/CarUi*,
+               @attr/actionEnabled,
+               @attr/actionShown,
+               @attr/activatable,
+               @attr/activated,
+               @attr/barrierAllowsGoneWidgets,
                @attr/barrierAllowsGoneWidgets,
                @attr/barrierDirection,
+               @attr/barrierDirection,
+               @attr/barrierMargin,
                @attr/barrierMargin,
                @attr/carUi*,
+               @attr/car_ui_*,
                @attr/chainUseRtl,
-               @attr/circularflow_angles,
-               @attr/circularflow_defaultAngle,
-               @attr/circularflow_defaultRadius,
-               @attr/circularflow_radiusInDP,
-               @attr/circularflow_viewCenter,
+               @attr/checkable,
+               @attr/checked,
                @attr/constraintSet,
                @attr/constraint_referenced_ids,
-               @attr/constraint_referenced_tags,
-               @attr/constraint_referenced_tags,
+               @attr/displayBehavior,
+               @attr/enableDivider,
                @attr/flow_firstHorizontalBias,
                @attr/flow_firstHorizontalStyle,
                @attr/flow_firstVerticalBias,
@@ -47,13 +54,14 @@
                @attr/flow_verticalGap,
                @attr/flow_verticalStyle,
                @attr/flow_wrapMode,
+               @attr/id,
                @attr/layoutDescription,
+               @attr/layoutManager,
+               @attr/layoutStyle,
                @attr/layout_constrainedHeight,
                @attr/layout_constrainedWidth,
                @attr/layout_constraintBaseline_creator,
                @attr/layout_constraintBaseline_toBaselineOf,
-               @attr/layout_constraintBaseline_toBottomOf,
-               @attr/layout_constraintBaseline_toTopOf,
                @attr/layout_constraintBottom_creator,
                @attr/layout_constraintBottom_toBottomOf,
                @attr/layout_constraintBottom_toTopOf,
@@ -66,7 +74,6 @@
                @attr/layout_constraintGuide_begin,
                @attr/layout_constraintGuide_end,
                @attr/layout_constraintGuide_percent,
-               @attr/layout_constraintHeight,
                @attr/layout_constraintHeight_default,
                @attr/layout_constraintHeight_max,
                @attr/layout_constraintHeight_min,
@@ -89,49 +96,55 @@
                @attr/layout_constraintVertical_bias,
                @attr/layout_constraintVertical_chainStyle,
                @attr/layout_constraintVertical_weight,
-               @attr/layout_constraintWidth,
                @attr/layout_constraintWidth_default,
                @attr/layout_constraintWidth_max,
                @attr/layout_constraintWidth_min,
                @attr/layout_constraintWidth_percent,
                @attr/layout_editor_absoluteX,
                @attr/layout_editor_absoluteY,
-               @attr/layout_goneMarginBaseline,
                @attr/layout_goneMarginBottom,
                @attr/layout_goneMarginEnd,
                @attr/layout_goneMarginLeft,
                @attr/layout_goneMarginRight,
                @attr/layout_goneMarginStart,
                @attr/layout_goneMarginTop,
-               @attr/layout_marginBaseline,
                @attr/layout_optimizationLevel,
-               @attr/layout_wrapBehaviorInParent,
+               @attr/logo,
+               @attr/menuItems,
+               @attr/numOfColumns,
+               @attr/onClick,
+               @attr/preferenceStyle,
+               @attr/reverseLayout,
+               @attr/rotaryScrollEnabled,
+               @attr/search,
+               @attr/searchHint,
+               @attr/secondaryActionIcon,
+               @attr/secondaryActionStyle,
+               @attr/secondaryActionText,
+               @attr/settings,
+               @attr/showBackground,
+               @attr/showIconAndTitle,
+               @attr/showMenuItemsWhileSearching,
+               @attr/showTabsInSubpage,
                @attr/state_ux_restricted,
+               @attr/tinted,
                @attr/title,
+               @attr/uxRestrictions,
+               @attr/visible,
+               @attr/widgetLayout,
                @bool/car_ui_*,
                @color/car_ui_*,
                @dimen/car_ui_*,
                @dimen/wrap_content,
                @drawable/car_ui_*,
                @font/car_ui_*,
-               @id/action_container,
-               @id/action_container_touch_interceptor,
-               @id/action_divider,
                @id/action_widget_container,
-               @id/avatar_icon,
-               @id/body,
                @id/car_ui_*,
-               @id/checkbox_widget,
                @id/container,
-               @id/content_icon,
-               @id/icon,
-               @id/icon_container,
                @id/list,
                @id/nested_recycler_view_layout,
                @id/radio_button,
-               @id/radio_button_widget,
                @id/recycler_view,
-               @id/reduced_touch_interceptor,
                @id/search,
                @id/seek_bar,
                @id/seek_bar_text_left,
@@ -140,18 +153,13 @@
                @id/seekbar,
                @id/seekbar_value,
                @id/spinner,
-               @id/supplemental_icon,
-               @id/switch_widget,
                @id/textbox,
-               @id/title,
                @id/title_template,
                @id/toolbar,
-               @id/touch_interceptor,
                @integer/car_ui_*,
                @layout/car_ui_*,
                @raw/car_ui_*,
                @string/car_ui_*,
                @style/*CarUi*,
-               @attr/CarUi*,
                "
   />
diff --git a/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/plugin/oemapis/recyclerview/ContentListItemOEMV1.java b/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/plugin/oemapis/recyclerview/ContentListItemOEMV1.java
index aaa4ef7..41ff5d9 100644
--- a/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/plugin/oemapis/recyclerview/ContentListItemOEMV1.java
+++ b/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/plugin/oemapis/recyclerview/ContentListItemOEMV1.java
@@ -321,7 +321,7 @@
          * @param type the icon type for the item.
          */
         @NonNull
-        public Builder setIcon(@NonNull Drawable icon, IconType type) {
+        public Builder setIcon(@NonNull Drawable icon, @NonNull IconType type) {
             mIcon = icon;
             mPrimaryIconType = type;
             return this;
@@ -377,6 +377,7 @@
          *
          * @param secure If the list item is secure or not.
          */
+        @NonNull
         public Builder setSecure(boolean secure) {
             mIsSecure = secure;
             return this;
diff --git a/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/plugin/oemapis/toolbar/TabOEMV1.java b/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/plugin/oemapis/toolbar/TabOEMV1.java
index 1ecff67..b90f087 100644
--- a/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/plugin/oemapis/toolbar/TabOEMV1.java
+++ b/car-ui-lib/oem-apis/src/main/java/com/android/car/ui/plugin/oemapis/toolbar/TabOEMV1.java
@@ -36,6 +36,7 @@
     }
 
     /** Constructs a new {@link Builder} to build a tab with */
+    @NonNull
     public static Builder builder() {
         return new Builder();
     }
diff --git a/car-ui-lib/paintbooth/src/main/res/values/strings.xml b/car-ui-lib/paintbooth/src/main/res/values/strings.xml
index 7a32240..287e7d6 100644
--- a/car-ui-lib/paintbooth/src/main/res/values/strings.xml
+++ b/car-ui-lib/paintbooth/src/main/res/values/strings.xml
@@ -77,6 +77,8 @@
 
   <!-- Title of a switch preference [CHAR_LIMIT=28]-->
   <string name="title_switch_preference">Switch preference</string>
+  <!-- Title of a primary switch preference [CHAR_LIMIT=28]-->
+  <string name="title_primary_switch_preference">Primary switch preference</string>
   <!-- Summary of a switch preference [CHAR_LIMIT=78]-->
   <string name="summary_switch_preference">Tap anywhere in this preference to toggle state</string>
 
diff --git a/car-ui-lib/paintbooth/src/main/res/xml/preference_samples.xml b/car-ui-lib/paintbooth/src/main/res/xml/preference_samples.xml
index 4cc4ada..25f217b 100644
--- a/car-ui-lib/paintbooth/src/main/res/xml/preference_samples.xml
+++ b/car-ui-lib/paintbooth/src/main/res/xml/preference_samples.xml
@@ -77,6 +77,11 @@
             android:summary="@string/summary_switch_preference"
             android:title="@string/title_switch_preference"/>
 
+        <com.android.car.ui.preference.CarUiPrimarySwitchPreference
+            android:key="primaryswitch"
+            android:summary="@string/summary_switch_preference"
+            android:title="@string/title_primary_switch_preference"/>
+
         <com.android.car.ui.preference.CarUiTwoActionPreference
             android:key="twoaction"
             android:summary="@string/summary_deprecated_twoaction_preference"
diff --git a/car-ui-lib/tests/apitest/current.xml b/car-ui-lib/tests/apitest/current.xml
index d1aef2b..cc3cc65 100644
--- a/car-ui-lib/tests/apitest/current.xml
+++ b/car-ui-lib/tests/apitest/current.xml
@@ -404,6 +404,7 @@
   <public type="layout" name="car_ui_preference_dropdown"/>
   <public type="layout" name="car_ui_preference_fragment"/>
   <public type="layout" name="car_ui_preference_fragment_with_toolbar"/>
+  <public type="layout" name="car_ui_preference_primary_switch"/>
   <public type="layout" name="car_ui_preference_two_action_icon"/>
   <public type="layout" name="car_ui_preference_two_action_switch"/>
   <public type="layout" name="car_ui_preference_two_action_text"/>