Merge "Allow customizing Toolbar tabs" into pi-car-dev am: 4179a018ba
am: 5148aad9a9

Change-Id: I94d287edab7e719847155f11e6ebd60ec1fae785
diff --git a/car-ui-lib/res/color/car_ui_toolbar_tab_item_selector.xml b/car-ui-lib/res/color/car_ui_toolbar_tab_item_selector.xml
index b2ec68a..47d1a8e 100644
--- a/car-ui-lib/res/color/car_ui_toolbar_tab_item_selector.xml
+++ b/car-ui-lib/res/color/car_ui_toolbar_tab_item_selector.xml
@@ -16,6 +16,6 @@
   -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@color/car_ui_toolbar_tab_selected_color" android:state_selected="true"/>
+    <item android:color="@color/car_ui_toolbar_tab_selected_color" android:state_activated="true"/>
     <item android:color="@color/car_ui_toolbar_tab_unselected_color"/>
 </selector>
diff --git a/car-ui-lib/res/layout/car_ui_toolbar_tab_item.xml b/car-ui-lib/res/layout/car_ui_toolbar_tab_item.xml
index 91a010d..82faedc 100644
--- a/car-ui-lib/res/layout/car_ui_toolbar_tab_item.xml
+++ b/car-ui-lib/res/layout/car_ui_toolbar_tab_item.xml
@@ -15,20 +15,19 @@
   limitations under the License.
   -->
 
-<merge
-    xmlns:android="http://schemas.android.com/apk/res/android">
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    style="@style/Widget.CarUi.Toolbar.Tab.Container">
     <ImageView
         android:id="@+id/car_ui_toolbar_tab_item_icon"
         android:layout_width="@dimen/car_ui_toolbar_tab_icon_width"
         android:layout_height="@dimen/car_ui_toolbar_tab_icon_height"
-        android:scaleType="fitCenter"
-        android:tint="@color/car_ui_toolbar_tab_item_selector"
-        android:tintMode="src_in"/>
+        style="@style/Widget.CarUi.Toolbar.Tab.Icon"/>
     <TextView
         android:id="@+id/car_ui_toolbar_tab_item_text"
         android:layout_width="@dimen/car_ui_toolbar_tab_text_width"
         android:layout_height="wrap_content"
-        android:singleLine="true"
-        android:gravity="center"
-        android:textAppearance="@style/TextAppearance.CarUi.Widget.Toolbar.Tab"/>
-</merge>
+        style="@style/Widget.CarUi.Toolbar.Tab.Text"/>
+</LinearLayout>
diff --git a/car-ui-lib/res/values/styles.xml b/car-ui-lib/res/values/styles.xml
index 08ba96f..4b96e3e 100644
--- a/car-ui-lib/res/values/styles.xml
+++ b/car-ui-lib/res/values/styles.xml
@@ -47,6 +47,28 @@
     <style name="Widget.CarUi.Toolbar.Search.EditText"
         parent="android:Widget.DeviceDefault.EditText"/>
 
+    <style name="Widget.CarUi.Toolbar.Tab"/>
+
+    <style name="Widget.CarUi.Toolbar.Tab.Container">
+        <item name="android:orientation">vertical</item>
+        <item name="android:paddingStart">@dimen/car_ui_toolbar_tab_padding_x</item>
+        <item name="android:paddingEnd">@dimen/car_ui_toolbar_tab_padding_x</item>
+        <item name="android:gravity">center</item>
+        <item name="android:background">?android:attr/selectableItemBackground</item>
+    </style>
+
+    <style name="Widget.CarUi.Toolbar.Tab.Icon">
+        <item name="android:scaleType">fitCenter</item>
+        <item name="android:tint">@color/car_ui_toolbar_tab_item_selector</item>
+        <item name="android:tintMode">src_in</item>
+    </style>
+
+    <style name="Widget.CarUi.Toolbar.Tab.Text">
+        <item name="android:singleLine">true</item>
+        <item name="android:gravity">center</item>
+        <item name="android:textAppearance">@style/TextAppearance.CarUi.Widget.Toolbar.Tab</item>
+    </style>
+
     <style name="Widget.CarUi.CarUiRecyclerView">
         <item name="android:scrollbars">vertical</item>
     </style>
diff --git a/car-ui-lib/src/com/android/car/ui/AlertDialogBuilder.java b/car-ui-lib/src/com/android/car/ui/AlertDialogBuilder.java
index 623442f..78d8d87 100644
--- a/car-ui-lib/src/com/android/car/ui/AlertDialogBuilder.java
+++ b/car-ui-lib/src/com/android/car/ui/AlertDialogBuilder.java
@@ -504,17 +504,18 @@
      * @param textChangedListener textWatcher whose methods are called whenever this TextView's text
      * changes {@link null} otherwise.
      * @param inputFilters list of input filters, {@link null} if no filter is needed
-     * @return this Builder object to allow for chaining of calls to set
-     * methods
+     * @param inputType See {@link EditText#setInputType(int)}, except
+     *                  {@link android.text.InputType#TYPE_NULL} will not be set.
+     * @return this Builder object to allow for chaining of calls to set methods
      */
     public AlertDialogBuilder setEditBox(String prompt, TextWatcher textChangedListener,
-            InputFilter[] inputFilters) {
+            InputFilter[] inputFilters, int inputType) {
         LayoutInflater layoutInflater =
                 (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         View contentView = layoutInflater.inflate(R.layout.car_ui_alert_dialog_edit_text,
                 null);
 
-        EditText editText = contentView.findViewById(R.id.textbox);
+        EditText editText = contentView.requireViewById(R.id.textbox);
         editText.setText(prompt);
 
         if (textChangedListener != null) {
@@ -525,11 +526,29 @@
             editText.setFilters(inputFilters);
         }
 
+        if (inputType != 0) {
+            editText.setInputType(inputType);
+        }
+
         mBuilder.setView(contentView);
         return this;
     }
 
     /**
+     * Sets a custom edit text box within the alert dialog.
+     *
+     * @param prompt the string that will be set on the edit text view
+     * @param textChangedListener textWatcher whose methods are called whenever this TextView's text
+     * changes {@link null} otherwise.
+     * @param inputFilters list of input filters, {@link null} if no filter is needed
+     * @return this Builder object to allow for chaining of calls to set methods
+     */
+    public AlertDialogBuilder setEditBox(String prompt, TextWatcher textChangedListener,
+            InputFilter[] inputFilters) {
+        return setEditBox(prompt, textChangedListener, inputFilters, 0);
+    }
+
+    /**
      * Creates an {@link AlertDialog} with the arguments supplied to this
      * builder.
      * <p>
diff --git a/car-ui-lib/src/com/android/car/ui/toolbar/TabLayout.java b/car-ui-lib/src/com/android/car/ui/toolbar/TabLayout.java
index 9bcc763..798ff79 100644
--- a/car-ui-lib/src/com/android/car/ui/toolbar/TabLayout.java
+++ b/car-ui-lib/src/com/android/car/ui/toolbar/TabLayout.java
@@ -22,8 +22,6 @@
 import android.graphics.drawable.Drawable;
 import android.util.ArraySet;
 import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -187,18 +185,6 @@
         addView(tabView, position, layoutParams);
     }
 
-    private ViewGroup createTabItemView() {
-        LinearLayout tabItemView = new LinearLayout(getContext());
-        tabItemView.setOrientation(LinearLayout.VERTICAL);
-        tabItemView.setGravity(Gravity.CENTER);
-        tabItemView.setPadding(mTabPaddingX, 0, mTabPaddingX, 0);
-        TypedValue tv = new TypedValue();
-        getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground,
-                tv, /* resolveRefs= */ true);
-        tabItemView.setBackgroundResource(tv.resourceId);
-        return tabItemView;
-    }
-
     private static class TabAdapter extends BaseAdapter {
         private final Context mContext;
         private final TabLayout mTabLayout;
@@ -251,8 +237,8 @@
         @Override
         @NonNull
         public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
-            ViewGroup tabItemView = mTabLayout.createTabItemView();
-            LayoutInflater.from(mContext).inflate(mTabItemLayoutRes, tabItemView, true);
+            View tabItemView = LayoutInflater.from(mContext)
+                    .inflate(mTabItemLayoutRes, parent, false);
 
             presentTabItemView(position, tabItemView);
             return tabItemView;
@@ -304,10 +290,7 @@
             tabItemView.setOnClickListener(view -> selectTab(tab));
             tab.bindText(textView);
             tab.bindIcon(iconView);
-
-            tabItemView.setSelected(tab.mIsSelected);
-            iconView.setSelected(tab.mIsSelected);
-            textView.setSelected(tab.mIsSelected);
+            tabItemView.setActivated(tab.mIsSelected);
             textView.setTypeface(tab.mIsSelected ? mSelectedTypeface : mUnselectedTypeface);
         }
 
diff --git a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/overlays/OverlayActivity.java b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/overlays/OverlayActivity.java
index 419f21e..9a49b10 100644
--- a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/overlays/OverlayActivity.java
+++ b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/overlays/OverlayActivity.java
@@ -17,7 +17,6 @@
 package com.android.car.ui.paintbooth.overlays;
 
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.util.Log;
 import android.widget.Toast;
 
@@ -79,20 +78,20 @@
                         getPreferenceScreen().addPreference(switchPreference);
                     }
                 }
-            } catch (RemoteException e) {
-                Toast.makeText(getContext(), "Something went wrong internally.",
+            } catch (Exception e) {
+                Toast.makeText(getContext(), "Error: " + e.getMessage(),
                         Toast.LENGTH_LONG).show();
-                Log.e(TAG, "can't apply overlay: ", e);
+                Log.e(TAG, "Can't load overlays: ", e);
             }
         }
 
         private void applyOverlay(String overlayPackage, boolean enableOverlay) {
             try {
                 mOverlayManager.applyOverlay(overlayPackage, enableOverlay);
-            } catch (RemoteException e) {
-                Toast.makeText(getContext(), "Something went wrong internally.",
+            } catch (Exception e) {
+                Toast.makeText(getContext(), "Error: " + e.getMessage(),
                         Toast.LENGTH_LONG).show();
-                Log.w(TAG, "Can't change theme", e);
+                Log.e(TAG, "Can't apply overlay: ", e);
             }
         }
     }
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 9518d25..a231ec7 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
@@ -16,19 +16,20 @@
 package com.android.car.ui.paintbooth.toolbar;
 
 import android.app.Activity;
-import android.app.AlertDialog;
 import android.os.Bundle;
+import android.text.Editable;
 import android.text.InputType;
+import android.text.TextWatcher;
 import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
-import android.widget.EditText;
 import android.widget.Toast;
 
 import androidx.annotation.NonNull;
 
+import com.android.car.ui.AlertDialogBuilder;
 import com.android.car.ui.paintbooth.R;
 import com.android.car.ui.recyclerview.CarUiRecyclerView;
 import com.android.car.ui.toolbar.MenuItem;
@@ -115,19 +116,17 @@
         }));
 
         mButtons.add(Pair.create("MenuItem: Toggle Visibility", v -> {
-            EditText textBox = new EditText(this);
-            textBox.setInputType(InputType.TYPE_CLASS_NUMBER);
-            new AlertDialog.Builder(this)
-                    .setView(textBox)
+            SimpleTextWatcher textWatcher = new SimpleTextWatcher();
+            new AlertDialogBuilder(this)
+                    .setEditBox("", textWatcher, null, InputType.TYPE_CLASS_NUMBER)
                     .setTitle("Enter the index of the MenuItem to toggle")
                     .setPositiveButton("Ok", (dialog, which) -> {
                         try {
-                            MenuItem item = mMenuItems.get(
-                                    Integer.parseInt(textBox.getText().toString()));
+                            MenuItem item = mMenuItems.get(Integer.parseInt(textWatcher.getText()));
                             item.setVisible(!item.isVisible());
                         } catch (NumberFormatException | IndexOutOfBoundsException e) {
                             Toast.makeText(this, "Invalid index \""
-                                            + textBox.getText().toString()
+                                            + textWatcher.getText()
                                             + "\", valid range is 0 to " + (mMenuItems.size() - 1),
                                     Toast.LENGTH_LONG).show();
                         }
@@ -177,6 +176,17 @@
         mButtons.add(Pair.create("Add tab", v ->
                 toolbar.addTab(new TabLayout.Tab(getDrawable(R.drawable.ic_launcher), "Foo"))));
 
+        mButtons.add(Pair.create("Add tab with custom text", v -> {
+            SimpleTextWatcher textWatcher = new SimpleTextWatcher();
+            new AlertDialogBuilder(this)
+                    .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())))
+                    .show();
+        }));
+
         CarUiRecyclerView prv = requireViewById(R.id.list);
         prv.setAdapter(mAdapter);
     }
@@ -217,15 +227,38 @@
     };
 
     /** For changing values from lambdas */
-    public static final class Mutable<E> {
+    private static final class Mutable<E> {
         public E value;
 
-        public Mutable() {
+        Mutable() {
             value = null;
         }
 
-        public Mutable(E value) {
+        Mutable(E value) {
             this.value = value;
         }
     }
+
+    /** Used for getting text from a dialog. */
+    private static final class SimpleTextWatcher implements TextWatcher {
+
+        private String mValue;
+
+        @Override
+        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+        }
+
+        @Override
+        public void onTextChanged(CharSequence s, int start, int before, int count) {
+        }
+
+        @Override
+        public void afterTextChanged(Editable s) {
+            mValue = s.toString();
+        }
+
+        public String getText() {
+            return mValue;
+        }
+    }
 }