Merge "Support passing multiple res folders" into tm-qpr-dev am: 9f2c906504 am: 231ea90f79

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Car/systemlibs/+/20480634

Change-Id: I6d0086ef6f2a92316baeb291a72143acf25314e9
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/car-qc-lib/res/color/qc_seekbar_thumb_selector.xml b/car-qc-lib/res/color/qc_seekbar_thumb_selector.xml
new file mode 100644
index 0000000..bf94a61
--- /dev/null
+++ b/car-qc-lib/res/color/qc_seekbar_thumb_selector.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2023 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_enabled="false"
+        android:color="@color/qc_seekbar_thumb_disabled_on_dark"/>
+    <item android:color="@color/qc_seekbar_thumb"/>
+</selector>
diff --git a/car-qc-lib/res/color/qc_switch_thumb_selector.xml b/car-qc-lib/res/color/qc_switch_thumb_selector.xml
new file mode 100644
index 0000000..e0bfc22
--- /dev/null
+++ b/car-qc-lib/res/color/qc_switch_thumb_selector.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2023 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_enabled="false"
+        android:color="@color/qc_switch_thumb_color_disabled_on_dark"/>
+    <item android:color="@color/qc_switch_thumb_color"/>
+</selector>
diff --git a/car-qc-lib/res/drawable/qc_toggle_background.xml b/car-qc-lib/res/drawable/qc_toggle_background.xml
index 3688175..4e30cf4 100644
--- a/car-qc-lib/res/drawable/qc_toggle_background.xml
+++ b/car-qc-lib/res/drawable/qc_toggle_background.xml
@@ -16,8 +16,8 @@
   -->
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:id="@android:id/background"
-        android:width="@dimen/qc_toggle_size"
-        android:height="@dimen/qc_toggle_size"
+        android:width="@dimen/qc_toggle_background_size"
+        android:height="@dimen/qc_toggle_background_size"
         android:start="@dimen/qc_toggle_background_padding"
         android:top="@dimen/qc_toggle_background_padding"
         android:drawable="@drawable/qc_toggle_button_background">
diff --git a/car-qc-lib/res/drawable/qc_toggle_unavailable_background.xml b/car-qc-lib/res/drawable/qc_toggle_unavailable_background.xml
index e9f2e12..185b801 100644
--- a/car-qc-lib/res/drawable/qc_toggle_unavailable_background.xml
+++ b/car-qc-lib/res/drawable/qc_toggle_unavailable_background.xml
@@ -16,8 +16,8 @@
   -->
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:id="@android:id/background"
-        android:width="@dimen/qc_toggle_size"
-        android:height="@dimen/qc_toggle_size"
+        android:width="@dimen/qc_toggle_background_size"
+        android:height="@dimen/qc_toggle_background_size"
         android:start="@dimen/qc_toggle_background_padding"
         android:top="@dimen/qc_toggle_background_padding">
         <shape android:shape="rectangle">
diff --git a/car-qc-lib/res/layout/qc_row_view.xml b/car-qc-lib/res/layout/qc_row_view.xml
index 2d95888..a4af032 100644
--- a/car-qc-lib/res/layout/qc_row_view.xml
+++ b/car-qc-lib/res/layout/qc_row_view.xml
@@ -119,7 +119,7 @@
             app:layout_constraintTop_toBottomOf="@+id/barrier2"
             app:layout_constraintBottom_toBottomOf="parent">
             <com.android.car.qc.view.QCSeekBarView
-                android:id="@+id/seekbar"
+                android:id="@+id/qc_seekbar"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 style="@style/Widget.QC.SeekBar"/>
diff --git a/car-qc-lib/res/values/colors.xml b/car-qc-lib/res/values/colors.xml
index 62bcfdc..a2b85ff 100644
--- a/car-qc-lib/res/values/colors.xml
+++ b/car-qc-lib/res/values/colors.xml
@@ -20,4 +20,12 @@
     <color name="qc_toggle_unavailable_background_color">@android:color/transparent</color>
     <color name="qc_toggle_unavailable_color">#37FFFFFF</color>
     <color name="qc_toggle_rotary_shadow_color">#C7000000</color>
-</resources>
\ No newline at end of file
+    <!-- The SeekBar thumb color. -->
+    <color name="qc_seekbar_thumb">#FFFFFF</color>
+    <!-- The SeekBar thumb color when disabled. Use for the dark theme. -->
+    <color name="qc_seekbar_thumb_disabled_on_dark">#757575</color>
+    <!-- The Switch thumb color. -->
+    <color name="qc_switch_thumb_color">#FFFFFF</color>
+    <!-- The Switch thumb color when disabled. Use for the dark theme. -->
+    <color name="qc_switch_thumb_color_disabled_on_dark">#757575</color>
+</resources>
diff --git a/car-qc-lib/res/values/dimens.xml b/car-qc-lib/res/values/dimens.xml
index b973774..912891f 100644
--- a/car-qc-lib/res/values/dimens.xml
+++ b/car-qc-lib/res/values/dimens.xml
@@ -24,7 +24,8 @@
     <dimen name="qc_row_content_margin">16dp</dimen>
 
     <dimen name="qc_action_items_horizontal_margin">32dp</dimen>
-    <dimen name="qc_toggle_size">72dp</dimen>
+    <dimen name="qc_toggle_size">80dp</dimen>
+    <dimen name="qc_toggle_background_size">72dp</dimen>
     <dimen name="qc_toggle_margin">12dp</dimen>
     <dimen name="qc_row_horizontal_margin">16dp</dimen>
     <dimen name="qc_toggle_background_radius">16dp</dimen>
diff --git a/car-qc-lib/res/values/overlayable.xml b/car-qc-lib/res/values/overlayable.xml
new file mode 100644
index 0000000..d5b405a
--- /dev/null
+++ b/car-qc-lib/res/values/overlayable.xml
@@ -0,0 +1,87 @@
+<?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.
+  -->
+<!--
+THIS FILE WAS AUTO GENERATED, DO NOT EDIT MANUALLY.
+REGENERATE USING packages/apps/Car/tests/tools/rro/generate-overlayable.py
+-->
+<resources>
+    <overlayable name="car-qc-lib">
+        <policy type="system|product|signature">
+            <item type="attr" name="state_toggle_unavailable"/>
+            <item type="color" name="qc_start_icon_color"/>
+            <item type="color" name="qc_toggle_background_color"/>
+            <item type="color" name="qc_toggle_icon_fill_color"/>
+            <item type="color" name="qc_toggle_off_background_color"/>
+            <item type="color" name="qc_toggle_rotary_shadow_color"/>
+            <item type="color" name="qc_toggle_unavailable_background_color"/>
+            <item type="color" name="qc_toggle_unavailable_color"/>
+            <item type="dimen" name="qc_action_items_horizontal_margin"/>
+            <item type="dimen" name="qc_row_content_margin"/>
+            <item type="dimen" name="qc_row_horizontal_margin"/>
+            <item type="dimen" name="qc_row_icon_margin_end"/>
+            <item type="dimen" name="qc_row_icon_size"/>
+            <item type="dimen" name="qc_row_margin_vertical"/>
+            <item type="dimen" name="qc_row_min_height"/>
+            <item type="dimen" name="qc_row_padding_end"/>
+            <item type="dimen" name="qc_row_padding_start"/>
+            <item type="dimen" name="qc_seekbar_padding_top"/>
+            <item type="dimen" name="qc_toggle_background_padding"/>
+            <item type="dimen" name="qc_toggle_background_radius"/>
+            <item type="dimen" name="qc_toggle_foreground_icon_inset"/>
+            <item type="dimen" name="qc_toggle_margin"/>
+            <item type="dimen" name="qc_toggle_rotary_highlight_radius"/>
+            <item type="dimen" name="qc_toggle_rotary_highlight_size"/>
+            <item type="dimen" name="qc_toggle_rotary_shadow_padding"/>
+            <item type="dimen" name="qc_toggle_rotary_shadow_radius"/>
+            <item type="dimen" name="qc_toggle_rotary_shadow_size"/>
+            <item type="dimen" name="qc_toggle_rotary_shadow_width"/>
+            <item type="dimen" name="qc_toggle_background_size"/>
+            <item type="dimen" name="qc_toggle_size"/>
+            <item type="dimen" name="qc_toggle_unavailable_outline_width"/>
+            <item type="drawable" name="qc_row_action_divider"/>
+            <item type="drawable" name="qc_seekbar_wrapper_background"/>
+            <item type="drawable" name="qc_toggle_background"/>
+            <item type="drawable" name="qc_toggle_button_background"/>
+            <item type="drawable" name="qc_toggle_rotary_background"/>
+            <item type="drawable" name="qc_toggle_rotary_highlight"/>
+            <item type="drawable" name="qc_toggle_rotary_shadow"/>
+            <item type="drawable" name="qc_toggle_unavailable_background"/>
+            <item type="id" name="barrier1"/>
+            <item type="id" name="barrier2"/>
+            <item type="id" name="qc_icon"/>
+            <item type="id" name="qc_row_content"/>
+            <item type="id" name="qc_row_end_items"/>
+            <item type="id" name="qc_row_start_items"/>
+            <item type="id" name="qc_seekbar"/>
+            <item type="id" name="qc_seekbar_wrapper"/>
+            <item type="id" name="qc_summary"/>
+            <item type="id" name="qc_tile_toggle_button"/>
+            <item type="id" name="qc_tile_wrapper"/>
+            <item type="id" name="qc_title"/>
+            <item type="id" name="qc_toggle_button"/>
+            <item type="layout" name="qc_action_switch"/>
+            <item type="layout" name="qc_action_toggle"/>
+            <item type="layout" name="qc_row_view"/>
+            <item type="layout" name="qc_tile_view"/>
+            <item type="style" name="TextAppearance.QC"/>
+            <item type="style" name="TextAppearance.QC.Subtitle"/>
+            <item type="style" name="TextAppearance.QC.Title"/>
+            <item type="style" name="Widget.QC"/>
+            <item type="style" name="Widget.QC.SeekBar"/>
+        </policy>
+    </overlayable>
+</resources>
\ No newline at end of file
diff --git a/car-qc-lib/src/com/android/car/qc/provider/BaseQCProvider.java b/car-qc-lib/src/com/android/car/qc/provider/BaseQCProvider.java
index 61db361..8e9e550 100644
--- a/car-qc-lib/src/com/android/car/qc/provider/BaseQCProvider.java
+++ b/car-qc-lib/src/com/android/car/qc/provider/BaseQCProvider.java
@@ -172,7 +172,11 @@
         try {
             StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                     .detectAll()
-                    .penaltyDeath()
+
+                    // TODO(268275789): Revert back to penaltyDeath and ensure it works in
+                    //                  presubmit
+                    .penaltyLog()
+
                     .build());
             return onBind(uri);
         } finally {
diff --git a/car-qc-lib/src/com/android/car/qc/view/QCRowView.java b/car-qc-lib/src/com/android/car/qc/view/QCRowView.java
index 1e10e4b..c374602 100644
--- a/car-qc-lib/src/com/android/car/qc/view/QCRowView.java
+++ b/car-qc-lib/src/com/android/car/qc/view/QCRowView.java
@@ -193,7 +193,7 @@
         mStartItemsContainer = findViewById(R.id.qc_row_start_items);
         mEndItemsContainer = findViewById(R.id.qc_row_end_items);
         mSeekBarContainer = findViewById(R.id.qc_seekbar_wrapper);
-        mSeekBar = findViewById(R.id.seekbar);
+        mSeekBar = findViewById(R.id.qc_seekbar);
     }
 
     void setActionListener(QCActionListener listener) {
@@ -311,6 +311,8 @@
                 (action.isEnabled() || action.isClickableWhileDisabled()) && action.isAvailable();
         switchView.setOnCheckedChangeListener(null);
         switchView.setEnabled(shouldEnableView);
+        switchView.setThumbTintList(getContext().getColorStateList(
+                R.color.qc_switch_thumb_selector));
         switchView.setChecked(action.isChecked());
         switchView.setOnTouchListener((v, event) -> {
             if (!action.isEnabled()) {
@@ -397,13 +399,15 @@
             // remove current action view
             root.removeView(actionView);
         }
-        actionView = mLayoutInflater.inflate(resId, /* root= */ null);
+        actionView = mLayoutInflater.inflate(resId, root, /* attachToRoot= */ false);
         root.addView(actionView);
         return actionView;
     }
 
     private void initSlider(QCSlider slider) {
         mQCSlider = slider;
+        CarUiUtils.makeAllViewsEnabled(mSeekBar, slider.isEnabled());
+
         mSeekBar.setOnSeekBarChangeListener(null);
         mSeekBar.setMin(slider.getMin());
         mSeekBar.setMax(slider.getMax());
@@ -411,6 +415,8 @@
         mSeekBar.setEnabled(slider.isEnabled());
         mSeekBar.setClickableWhileDisabled(slider.isClickableWhileDisabled());
         mSeekBar.setDisabledClickListener(seekBar -> fireAction(slider, new Intent()));
+        mSeekBar.setThumbTintList(getContext().getColorStateList(
+                R.color.qc_seekbar_thumb_selector));
         if (!slider.isEnabled() && mInDirectManipulationMode) {
             setInDirectManipulationMode(mSeekBarContainer, mSeekBar, false);
         }
diff --git a/car-qc-lib/tests/unit/src/com/android/car/qc/view/QCRowViewTest.java b/car-qc-lib/tests/unit/src/com/android/car/qc/view/QCRowViewTest.java
index 647317a..9c1aa79 100644
--- a/car-qc-lib/tests/unit/src/com/android/car/qc/view/QCRowViewTest.java
+++ b/car-qc-lib/tests/unit/src/com/android/car/qc/view/QCRowViewTest.java
@@ -30,12 +30,14 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.ColorStateList;
 import android.graphics.drawable.Icon;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.SeekBar;
+import android.widget.Switch;
 import android.widget.TextView;
 
 import androidx.test.annotation.UiThreadTest;
@@ -203,11 +205,50 @@
                 .addSlider(new QCSlider.Builder().setInputAction(action).build())
                 .build();
         mView.setRow(row);
-        SeekBar seekBar = mView.findViewById(R.id.seekbar);
+        SeekBar seekBar = mView.findViewById(R.id.qc_seekbar);
         seekBar.setProgress(50);
         MotionEvent motionEvent = ExtendedMockito.mock(MotionEvent.class);
         ExtendedMockito.when(motionEvent.getAction()).thenReturn(MotionEvent.ACTION_UP);
         seekBar.onTouchEvent(motionEvent);
         verify(action).send(any(Context.class), anyInt(), any(Intent.class));
     }
+
+    @Test
+    @UiThreadTest
+    public void setRow_switchViewThumbTintList() {
+        PendingIntent action = mock(PendingIntent.class);
+        QCRow row = new QCRow.Builder()
+                .addEndItem(
+                        new QCActionItem.Builder(QC_TYPE_ACTION_SWITCH).setAction(action).build())
+                .build();
+        mView.setRow(row);
+        LinearLayout endContainer = mView.findViewById(R.id.qc_row_end_items);
+        assertThat(endContainer.getChildCount()).isEqualTo(1);
+        Switch switchView = (Switch) endContainer.getChildAt(0);
+        assertThat(switchView.getThumbTintList()).isNotNull();
+
+        ColorStateList switchColorStateList = switchView.getThumbTintList();
+        int[] enabledState = {android.R.attr.state_enabled};
+        int[] disabledState = {-android.R.attr.state_enabled};
+        assertThat(switchColorStateList.getColorForState(enabledState, 0)).isNotEqualTo(
+                switchColorStateList.getColorForState(disabledState, 0));
+    }
+
+    @Test
+    @UiThreadTest
+    public void setRow_sliderViewThumbTintList() {
+        PendingIntent action = mock(PendingIntent.class);
+        QCRow row = new QCRow.Builder()
+                .addSlider(new QCSlider.Builder().setInputAction(action).build())
+                .build();
+        mView.setRow(row);
+        SeekBar seekBar = mView.findViewById(R.id.qc_seekbar);
+        assertThat(seekBar.getThumbTintList()).isNotNull();
+
+        ColorStateList seekBarColorStateList = seekBar.getThumbTintList();
+        int[] enabledState = {android.R.attr.state_enabled};
+        int[] disabledState = {-android.R.attr.state_enabled};
+        assertThat(seekBarColorStateList.getColorForState(enabledState, 0)).isNotEqualTo(
+                seekBarColorStateList.getColorForState(disabledState, 0));
+    }
 }
diff --git a/tools/rro/resource_utils.py b/tools/rro/resource_utils.py
index 5f35e1a..fe4c52c 100644
--- a/tools/rro/resource_utils.py
+++ b/tools/rro/resource_utils.py
@@ -15,7 +15,11 @@
 
 import os
 import re
-import lxml.etree as etree
+try:
+    import lxml.etree as etree
+except ImportError:
+    print("Please install 'lxml' python package and retry.")
+    sys.exit(1)
 
 class ResourceLocation:
     def __init__(self, file, line=None):