Allow Toolbar's search icon to be changed, and remove custom menu items

To go along with removing custom MenuItems, added setShowIconAndTitle()
and setTinted() to support the user button in CarSettings.

Also allow setting the logo to a Drawable or Bitmap

Fixes: 141570775
Test: Manually
Change-Id: Ic01ab4390f9154a1dedb9a020c5f172e975ffe65
diff --git a/car-ui-lib/res/drawable/car_ui_icon_search.xml b/car-ui-lib/res/drawable/car_ui_icon_search.xml
index e0e977a..52fbad9 100644
--- a/car-ui-lib/res/drawable/car_ui_icon_search.xml
+++ b/car-ui-lib/res/drawable/car_ui_icon_search.xml
@@ -20,7 +20,7 @@
     android:viewportHeight="48">
 
     <path
-        android:fillColor="@color/car_ui_toolbar_search_icon_color"
+        android:fillColor="@color/car_ui_toolbar_menu_item_icon_color"
         android:pathData="M31 28h-1.59l-.55-.55C30.82 25.18 32 22.23 32 19c0-7.18-5.82-13-13-13S6 11.82 6
 19s5.82 13 13 13c3.23 0 6.18-1.18 8.45-3.13l.55 .55 V31l10 9.98L40.98 38 31
 28zm-12 0c-4.97 0-9-4.03-9-9s4.03-9 9-9 9 4.03 9 9-4.03 9-9 9z" />
diff --git a/car-ui-lib/res/layout/car_ui_toolbar_menu_item_icon_and_text.xml b/car-ui-lib/res/layout/car_ui_toolbar_menu_item_icon_and_text.xml
new file mode 100644
index 0000000..282d823
--- /dev/null
+++ b/car-ui-lib/res/layout/car_ui_toolbar_menu_item_icon_and_text.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+<com.android.car.ui.uxr.DrawableStateButton
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/car_ui_toolbar_menu_item_text"
+    style="@style/Widget.CarUi.Toolbar.TextButton.WithIcon"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent"
+    android:layout_gravity="center_vertical"/>
diff --git a/car-ui-lib/res/values/colors.xml b/car-ui-lib/res/values/colors.xml
index 61cb0e4..ae35ba5 100644
--- a/car-ui-lib/res/values/colors.xml
+++ b/car-ui-lib/res/values/colors.xml
@@ -23,8 +23,6 @@
 
     <!-- Toolbar -->
 
-    <!-- Color used on the search icon -->
-    <color name="car_ui_toolbar_search_icon_color">@color/car_ui_primary_text_color</color>
     <!-- Color used on the navigation icon -->
     <color name="car_ui_toolbar_nav_icon_color">@color/car_ui_primary_text_color</color>
     <!-- Text color applied to the hint displayed inside the search box -->
diff --git a/car-ui-lib/res/values/styles.xml b/car-ui-lib/res/values/styles.xml
index 4b96e3e..25a9cb2 100644
--- a/car-ui-lib/res/values/styles.xml
+++ b/car-ui-lib/res/values/styles.xml
@@ -29,7 +29,14 @@
         <item name="android:src">@drawable/car_ui_icon_arrow_back</item>
     </style>
 
-    <style name="Widget.CarUi.Toolbar.TextButton" parent="Widget.CarUi.Button.Borderless.Colored"/>
+    <style name="Widget.CarUi.Toolbar.TextButton" parent="Widget.CarUi.Button.Borderless.Colored">
+        <item name="android:drawableTint">@color/car_ui_toolbar_menu_item_icon_color</item>
+        <item name="android:drawablePadding">10dp</item>
+    </style>
+
+    <style name="Widget.CarUi.Toolbar.TextButton.WithIcon">
+        <item name="android:textColor">@color/car_ui_toolbar_menu_item_icon_color</item>
+    </style>
 
     <!-- Style applied to the decoration view between toolbar rows -->
     <style name="Widget.CarUi.Toolbar.SeparatorView">
diff --git a/car-ui-lib/src/com/android/car/ui/toolbar/MenuItem.java b/car-ui-lib/src/com/android/car/ui/toolbar/MenuItem.java
index bf291b4..054dc97 100644
--- a/car-ui-lib/src/com/android/car/ui/toolbar/MenuItem.java
+++ b/car-ui-lib/src/com/android/car/ui/toolbar/MenuItem.java
@@ -45,8 +45,9 @@
     private final Context mContext;
     private final boolean mIsCheckable;
     private final boolean mIsActivatable;
-    final int mCustomLayoutId;
     private final boolean mIsSearch;
+    private final boolean mShowIconAndTitle;
+    private final boolean mIsTinted;
     @CarUxRestrictions.CarUxRestrictionsInfo
     private final int mUxRestrictions;
 
@@ -64,7 +65,6 @@
         mContext = builder.mContext;
         mIsCheckable = builder.mIsCheckable;
         mIsActivatable = builder.mIsActivatable;
-        mCustomLayoutId = builder.mCustomLayoutId;
         mTitle = builder.mTitle;
         mIcon = builder.mIcon;
         mOnClickListener = builder.mOnClickListener;
@@ -74,6 +74,8 @@
         mIsVisible = builder.mIsVisible;
         mIsActivated = builder.mIsActivated;
         mIsSearch = builder.mIsSearch;
+        mShowIconAndTitle = builder.mShowIconAndTitle;
+        mIsTinted = builder.mIsTinted;
         mUxRestrictions = builder.mUxRestrictions;
     }
 
@@ -122,6 +124,10 @@
         update();
     }
 
+    public boolean isTinted() {
+        return mIsTinted;
+    }
+
     /** Returns whether or not the MenuItem is visible */
     public boolean isVisible() {
         return mIsVisible;
@@ -186,6 +192,10 @@
         return mOnClickListener;
     }
 
+    public boolean isShowingIconAndTitle() {
+        return mShowIconAndTitle;
+    }
+
     /** Sets the {@link OnClickListener} */
     public void setOnClickListener(OnClickListener listener) {
         mOnClickListener = listener;
@@ -210,19 +220,6 @@
         return mIcon;
     }
 
-    /**
-     * Gets the custom view specified by {@link Builder#setCustomLayout(int)}
-     *
-     * @return null if {@link Builder#setCustomLayout(int)} was not used when
-     * building this MenuItem.
-     */
-    public View getView() {
-        if (mListener != null) {
-            return mListener.getView();
-        }
-        return null;
-    }
-
     /** Returns if this is the search MenuItem, which has special behavior when searching */
     boolean isSearch() {
         return mIsSearch;
@@ -242,13 +239,14 @@
         private Drawable mIcon;
         private OnClickListener mOnClickListener;
         private DisplayBehavior mDisplayBehavior = DisplayBehavior.ALWAYS;
+        private boolean mIsTinted = true;
+        private boolean mShowIconAndTitle = false;
         private boolean mIsEnabled = true;
         private boolean mIsCheckable = false;
         private boolean mIsChecked = false;
         private boolean mIsVisible = true;
         private boolean mIsActivatable = false;
         private boolean mIsActivated = false;
-        private int mCustomLayoutId;
         private boolean mIsSearch = false;
         @CarUxRestrictions.CarUxRestrictionsInfo
         private int mUxRestrictions = CarUxRestrictions.UX_RESTRICTIONS_BASELINE;
@@ -259,6 +257,16 @@
 
         /** Builds a {@link MenuItem} from the current state of the Builder */
         public MenuItem build() {
+            if (mIsActivatable && (mShowIconAndTitle || mIcon == null)) {
+                throw new IllegalStateException("Only simple icons can be activatable");
+            }
+            if (mIsCheckable
+                    && (mDisplayBehavior == DisplayBehavior.NEVER
+                    || mShowIconAndTitle
+                    || mIsActivatable)) {
+                throw new IllegalStateException("Unsupported options for a checkable MenuItem");
+            }
+
             return new MenuItem(this);
         }
 
@@ -284,6 +292,17 @@
             return this;
         }
 
+        /**
+         * Sets whether to tint the icon, true by default.
+         *
+         * <p>Try not to use this, it should only be used if the MenuItem is displaying some
+         * kind of logo or avatar and should be colored.
+         */
+        public Builder setTinted(boolean tinted) {
+            mIsTinted = tinted;
+            return this;
+        }
+
         /** Sets whether the MenuItem is visible or not. Default true. */
         public Builder setVisible(boolean visible) {
             mIsVisible = visible;
@@ -292,7 +311,7 @@
 
         /**
          * Makes the MenuItem activatable, which means it will toggle it's visual state after
-         *  every click.
+         * every click.
          */
         public Builder setActivatable() {
             mIsActivatable = true;
@@ -309,21 +328,6 @@
             return this;
         }
 
-        /**
-         * Sets a custom layout to use for this MenuItem.
-         *
-         * <p>Should not be used in non-system (GAS) apps, as the OEM will not be able to
-         * customize the layout.
-         */
-        public Builder setCustomLayout(int resId) {
-            if (mIsCheckable) {
-                throw new IllegalStateException("Cannot have a checkable custom layout MenuItem");
-            }
-
-            mCustomLayoutId = resId;
-            return this;
-        }
-
         /** Sets the {@link OnClickListener} */
         public Builder setOnClickListener(OnClickListener listener) {
             mOnClickListener = listener;
@@ -331,16 +335,24 @@
         }
 
         /**
+         * Used to show both the icon and title when displayed on the toolbar. If this
+         * is false, only the icon while be displayed when the MenuItem is in the toolbar
+         * and only the title will be displayed when the MenuItem is in the overflow menu.
+         *
+         * <p>Defaults to false.
+         */
+        public Builder setShowIconAndTitle(boolean showIconAndTitle) {
+            mShowIconAndTitle = showIconAndTitle;
+            return this;
+        }
+
+        /**
          * Sets the {@link DisplayBehavior}.
          *
          * <p>If the DisplayBehavior is {@link DisplayBehavior#NEVER}, the MenuItem must not be
          * {@link #setCheckable() checkable}.
          */
         public Builder setDisplayBehavior(DisplayBehavior behavior) {
-            if (behavior == DisplayBehavior.NEVER && mIsCheckable) {
-                throw new IllegalStateException(
-                        "Currently we don't support a checkable overflow item");
-            }
             mDisplayBehavior = behavior;
             return this;
         }
@@ -358,15 +370,6 @@
          * <p>The MenuItem is not checkable by default.
          */
         public Builder setCheckable() {
-            if (mDisplayBehavior == DisplayBehavior.NEVER) {
-                throw new IllegalStateException(
-                        "Currently we don't support a checkable overflow item");
-            }
-
-            if (mCustomLayoutId != 0) {
-                throw new IllegalStateException("Cannot have a checkable custom layout MenuItem");
-            }
-
             mIsCheckable = true;
             return this;
         }
@@ -454,9 +457,6 @@
 
         /** Called when {@link MenuItem#performClick()} is called */
         void performClick();
-
-        /** Used to get the custom view, if there is one */
-        View getView();
     }
 
     void setListener(Listener listener) {
diff --git a/car-ui-lib/src/com/android/car/ui/toolbar/MenuItemRenderer.java b/car-ui-lib/src/com/android/car/ui/toolbar/MenuItemRenderer.java
index 47812ce..3cda47a 100644
--- a/car-ui-lib/src/com/android/car/ui/toolbar/MenuItemRenderer.java
+++ b/car-ui-lib/src/com/android/car/ui/toolbar/MenuItemRenderer.java
@@ -77,23 +77,16 @@
         updateView();
     }
 
-    @Override
-    public View getView() {
-        if (mMenuItem.mCustomLayoutId != 0) {
-            return mView;
-        }
-        return null;
-    }
-
     View createView() {
         LayoutInflater inflater = (LayoutInflater) mParentView.getContext().getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
 
-        if (mMenuItem.mCustomLayoutId != 0) {
-            mView = inflater.inflate(mMenuItem.mCustomLayoutId, mParentView, false);
-        } else if (mMenuItem.isCheckable()) {
+        if (mMenuItem.isCheckable()) {
             mView = inflater.inflate(
                     R.layout.car_ui_toolbar_menu_item_switch, mParentView, false);
+        } else if (mMenuItem.isShowingIconAndTitle()) {
+            mView = inflater.inflate(
+                    R.layout.car_ui_toolbar_menu_item_icon_and_text, mParentView, false);
         } else if (mMenuItem.getIcon() != null) {
             mView = inflater.inflate(
                     R.layout.car_ui_toolbar_menu_item_icon, mParentView, false);
@@ -127,6 +120,15 @@
         TextView textView = mView.findViewById(R.id.car_ui_toolbar_menu_item_text);
         if (textView != null) {
             textView.setText(mMenuItem.getTitle());
+
+            if (mMenuItem.isShowingIconAndTitle() && imageView == null) {
+                int menuItemIconSize = mView.getContext().getResources()
+                        .getDimensionPixelSize(R.dimen.car_ui_toolbar_menu_item_icon_size);
+
+                mMenuItem.getIcon().setBounds(0, 0, menuItemIconSize, menuItemIconSize);
+
+                textView.setCompoundDrawables(mMenuItem.getIcon(), null, null, null);
+            }
         }
 
         Switch s = mView.findViewById(R.id.car_ui_toolbar_menu_item_switch);
@@ -134,6 +136,10 @@
             s.setChecked(mMenuItem.isChecked());
         }
 
+        if (!mMenuItem.isTinted()) {
+            mMenuItem.getIcon().setTintList(null);
+        }
+
         recursiveSetEnabledAndDrawableState(mView);
         mView.setActivated(mMenuItem.isActivated());
 
diff --git a/car-ui-lib/src/com/android/car/ui/toolbar/SearchView.java b/car-ui-lib/src/com/android/car/ui/toolbar/SearchView.java
index a62c0df..5ae6589 100644
--- a/car-ui-lib/src/com/android/car/ui/toolbar/SearchView.java
+++ b/car-ui-lib/src/com/android/car/ui/toolbar/SearchView.java
@@ -16,7 +16,6 @@
 package com.android.car.ui.toolbar;
 
 import android.content.Context;
-import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.text.Editable;
 import android.text.TextUtils;
@@ -158,22 +157,23 @@
     /**
      * Sets a custom icon to display in the search box.
      */
-    public void setIcon(Bitmap b) {
-        mIcon.setImageBitmap(b);
-    }
-
-    /**
-     * Sets a custom icon to display in the search box.
-     */
     public void setIcon(Drawable d) {
-        mIcon.setImageDrawable(d);
+        if (d == null) {
+            mIcon.setImageResource(R.drawable.car_ui_icon_search);
+        } else {
+            mIcon.setImageDrawable(d);
+        }
     }
 
     /**
      * Sets a custom icon to display in the search box.
      */
     public void setIcon(int resId) {
-        mIcon.setImageResource(resId);
+        if (resId == 0) {
+            mIcon.setImageResource(R.drawable.car_ui_icon_search);
+        } else {
+            mIcon.setImageResource(resId);
+        }
     }
 
     private void onSearch(String query) {
diff --git a/car-ui-lib/src/com/android/car/ui/toolbar/Toolbar.java b/car-ui-lib/src/com/android/car/ui/toolbar/Toolbar.java
index b396fed..892aead 100644
--- a/car-ui-lib/src/com/android/car/ui/toolbar/Toolbar.java
+++ b/car-ui-lib/src/com/android/car/ui/toolbar/Toolbar.java
@@ -476,6 +476,26 @@
     }
 
     /**
+     * Sets the icon to display in the search box.
+     *
+     * @note The icon will be lost on configuration change, make sure to set it in onCreate() or
+     * a similar place.
+     */
+    public void setSearchIcon(int resId) {
+        mSearchView.setIcon(resId);
+    }
+
+    /**
+     * Sets the icon to display in the search box.
+     *
+     * @note The icon will be lost on configuration change, make sure to set it in onCreate() or
+     * a similar place.
+     */
+    public void setSearchIcon(Drawable d) {
+        mSearchView.setIcon(d);
+    }
+
+    /**
      * An enum of possible styles the nav button could be in. All styles will still call
      * {@link OnBackListener#onBack()}.
      */
@@ -559,11 +579,6 @@
                     public void performClick() {
                         Log.w(TAG, "performClick on overflow MenuItems not yet implemented");
                     }
-
-                    @Override
-                    public View getView() {
-                        return null;
-                    }
                 });
             } else {
                 MenuItemRenderer renderer = new MenuItemRenderer(item, mMenuItemsContainer);
diff --git a/car-ui-lib/tests/paintbooth/res/drawable/ic_tracklist.xml b/car-ui-lib/tests/paintbooth/res/drawable/ic_tracklist.xml
index 1904745..69b5a3e 100644
--- a/car-ui-lib/tests/paintbooth/res/drawable/ic_tracklist.xml
+++ b/car-ui-lib/tests/paintbooth/res/drawable/ic_tracklist.xml
@@ -18,12 +18,11 @@
         android:width="500dp"
         android:height="500dp"
         android:viewportWidth="48"
-        android:viewportHeight="48"
-        android:tint="#FF0000">
+        android:viewportHeight="48">
     <path
         android:pathData="M0 0h48v48H0z"/>
     <path
-        android:fillColor="#000000"
+        android:fillColor="#FF0000"
         android:pathData="M30 12H6v4h24v-4zm0 8H6v4h24v-4zM6
 32h16v-4H6v4zm28-20v16.37c-.63-.23-1.29-.37-2-.37-3.31 0-6 2.69-6 6s2.69 6 6 6
 6-2.69 6-6V16h6v-4H34z"/>
diff --git a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/toolbar/ToolbarActivity.java b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/toolbar/ToolbarActivity.java
index a231ec7..096c424 100644
--- a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/toolbar/ToolbarActivity.java
+++ b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/toolbar/ToolbarActivity.java
@@ -74,6 +74,16 @@
             toolbar.setMenuItems(mMenuItems);
         }));
 
+        mButtons.add(Pair.create("MenuItem: Add untinted icon", v -> {
+            mMenuItems.add(new MenuItem.Builder(this)
+                    .setIcon(R.drawable.ic_tracklist)
+                    .setTinted(false)
+                    .setOnClickListener(i ->
+                            Toast.makeText(this, "Clicked", Toast.LENGTH_SHORT).show())
+                    .build());
+            toolbar.setMenuItems(mMenuItems);
+        }));
+
         Mutable<Integer> overflowCounter = new Mutable<>(1);
         mButtons.add(Pair.create("MenuItem: Add Overflow", v -> {
             mMenuItems.add(new MenuItem.Builder(this)
@@ -105,6 +115,29 @@
             toolbar.setMenuItems(mMenuItems);
         }));
 
+        mButtons.add(Pair.create("MenuItem: Add icon and text", v -> {
+            mMenuItems.add(new MenuItem.Builder(this)
+                    .setIcon(R.drawable.ic_tracklist)
+                    .setTitle("Bar")
+                    .setShowIconAndTitle(true)
+                    .setOnClickListener(i ->
+                            Toast.makeText(this, "Clicked", Toast.LENGTH_SHORT).show())
+                    .build());
+            toolbar.setMenuItems(mMenuItems);
+        }));
+
+        mButtons.add(Pair.create("MenuItem: Add untinted icon and text", v -> {
+            mMenuItems.add(new MenuItem.Builder(this)
+                    .setIcon(R.drawable.ic_tracklist)
+                    .setTitle("Bar")
+                    .setShowIconAndTitle(true)
+                    .setTinted(false)
+                    .setOnClickListener(i ->
+                            Toast.makeText(this, "Clicked", Toast.LENGTH_SHORT).show())
+                    .build());
+            toolbar.setMenuItems(mMenuItems);
+        }));
+
         mButtons.add(Pair.create("MenuItem: Add activatable", v -> {
             mMenuItems.add(new MenuItem.Builder(this)
                     .setIcon(R.drawable.ic_tracklist)
@@ -182,11 +215,21 @@
                     .setEditBox(null, textWatcher, null)
                     .setTitle("Enter the text for the title")
                     .setPositiveButton("Ok", (dialog, which) ->
-                        toolbar.addTab(new TabLayout.Tab(getDrawable(R.drawable.ic_launcher),
-                                textWatcher.getText())))
+                            toolbar.addTab(new TabLayout.Tab(getDrawable(R.drawable.ic_launcher),
+                                    textWatcher.getText())))
                     .show();
         }));
 
+        Mutable<Boolean> showingLauncherIcon = new Mutable<>(false);
+        mButtons.add(Pair.create("Toggle search icon", v -> {
+            if (showingLauncherIcon.value) {
+                toolbar.setSearchIcon(0);
+            } else {
+                toolbar.setSearchIcon(R.drawable.ic_launcher);
+            }
+            showingLauncherIcon.value = !showingLauncherIcon.value;
+        }));
+
         CarUiRecyclerView prv = requireViewById(R.id.list);
         prv.setAdapter(mAdapter);
     }