Merge "Add revert to left click to autoclick settings page" into main
diff --git a/res/drawable/keyboard_arrow_left.xml b/res/drawable/keyboard_arrow_left.xml
new file mode 100644
index 0000000..c2ffc1d
--- /dev/null
+++ b/res/drawable/keyboard_arrow_left.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2025 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" android:tint="?attr/colorControlNormal" android:autoMirrored="true">
+    <path android:fillColor="@color/settingslib_materialColorPrimary" android:pathData="M560,720L320,480L560,240L616,296L432,480L616,664L560,720Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/drawable/keyboard_arrow_right.xml b/res/drawable/keyboard_arrow_right.xml
new file mode 100644
index 0000000..ba76369
--- /dev/null
+++ b/res/drawable/keyboard_arrow_right.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2025 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" android:tint="?attr/colorControlNormal" android:autoMirrored="true">
+    <path android:fillColor="@color/settingslib_materialColorPrimary" android:pathData="M504,480L320,296L376,240L616,480L376,720L320,664L504,480Z" />
+</vector>
\ No newline at end of file
diff --git a/res/layout/accessibility_text_reading_preview.xml b/res/layout/accessibility_text_reading_preview.xml
index 830d9e6..2532a79 100644
--- a/res/layout/accessibility_text_reading_preview.xml
+++ b/res/layout/accessibility_text_reading_preview.xml
@@ -38,20 +38,47 @@
             android:text="@string/screen_zoom_preview_title"
             style="@style/AccessibilityTextReadingPreviewTitle" />
 
-        <com.android.settings.accessibility.TextReadingPreviewPager
-            android:id="@+id/preview_pager"
+        <LinearLayout
             android:layout_width="match_parent"
-            android:layout_height="217dp"
-            android:contentDescription="@string/preview_pager_content_description"
-            android:nestedScrollingEnabled="true" />
-
-        <com.android.settings.widget.DotsPageIndicator
-            android:id="@+id/page_indicator"
-            style="@style/PreviewPagerPageIndicator"
-            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal"
-            android:padding="6dp"
-            android:visibility="gone" />
+            android:orientation="vertical">
+            <com.android.settings.accessibility.TextReadingPreviewPager
+                android:id="@+id/preview_pager"
+                android:layout_width="wrap_content"
+                android:layout_height="217dp"
+                android:contentDescription="@string/preview_pager_content_description"
+                android:nestedScrollingEnabled="true" />
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                android:layout_gravity="center_horizontal"
+                android:gravity="center_horizontal">
+                <ImageButton
+                    android:id="@+id/preview_left_button"
+                    android:src="@drawable/keyboard_arrow_left"
+                    android:layout_width="48dp"
+                    android:layout_height="48dp"
+                    android:layout_gravity="center_vertical"
+                    android:contentDescription="@string/preview_pager_previous_button"
+                    style="?android:attr/borderlessButtonStyle" />
+                <com.android.settings.widget.DotsPageIndicator
+                    android:id="@+id/page_indicator"
+                    style="@style/PreviewPagerPageIndicator"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center_vertical"
+                    android:padding="6dp"
+                    android:visibility="gone" />
+                <ImageButton
+                    android:id="@+id/preview_right_button"
+                    android:src="@drawable/keyboard_arrow_right"
+                    android:layout_width="48dp"
+                    android:layout_height="48dp"
+                    android:layout_gravity="center_vertical"
+                    android:contentDescription="@string/preview_pager_next_button"
+                    style="?android:attr/borderlessButtonStyle" />
+            </LinearLayout>
+        </LinearLayout>
     </LinearLayout>
 </FrameLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 806011c..e103f1a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -80,6 +80,10 @@
     <string name="preview_pager_content_description">Preview</string>
     <!-- Content description for qrcode image. [CHAR LIMIT=none]-->
     <string name="qr_code_content_description">QR code</string>
+    <!-- Previous button for preview pager. [CHAR LIMIT=NONE] -->
+    <string name="preview_pager_previous_button">Previous preview</string>
+    <!-- Next button for preview pager. [CHAR LIMIT=NONE] -->
+    <string name="preview_pager_next_button">Next preview</string>
 
     <!-- Description for the button that makes interface elements smaller. [CHAR_LIMIT=NONE] -->
     <string name="font_size_make_smaller_desc">Make smaller</string>
@@ -3171,6 +3175,7 @@
     <string name="dark_ui_summary_on_auto_mode_modes">Will turn off when <xliff:g name="modeName" example="Bedtime">%1$s</xliff:g> ends</string>
     <!-- Dark theme screen, description of Dark theme feature. [CHAR LIMIT=NONE] -->
     <string name="dark_ui_text">Dark theme uses a black background to help keep battery alive longer on some screens. Dark theme schedules wait to turn on until your screen is off.</string>
+    <string name="dark_ui_text_force_invert">Use a dark background to make your screen more comfortable to view and reduce battery usage on some screens. Your theme will change if you have a schedule, when the screen is off.</string>
     <!-- Dark UI screen footer summary text shown when the when Dark theme turns on/off automatically according to a user bedtime schedule. [CHAR LIMIT=NONE] -->
     <string name="dark_ui_bedtime_footer_summary">Dark theme is currently following your Bedtime mode schedule</string>
     <!-- Dark UI screen footer action text shown when the when Dark theme turns on/off automatically according to a user bedtime schedule. [CHAR LIMIT=NONE] -->
@@ -5568,7 +5573,7 @@
     <!-- Title for the accessibility preference for forcing all apps to use dark theme. [CHAR LIMIT=35] -->
     <string name="accessibility_force_invert_title">Make more apps dark</string>
     <!-- Summary for the accessibility preference for forcing all apps to use dark theme. [CHAR LIMIT=100] -->
-    <string name="accessibility_force_invert_summary">Automatically convert light theme apps to dark theme</string>
+    <string name="accessibility_force_invert_summary">Expands dark theme to more apps. May not work with all apps.</string>
     <!-- Title for the accessibility preference for disabling animations. [CHAR LIMIT=35] -->
     <string name="accessibility_disable_animations">Remove animations</string>
     <!-- Summary for the accessibility preference for disabling animations. [CHAR LIMIT=60] -->
diff --git a/res/xml/dark_mode_settings.xml b/res/xml/dark_mode_settings.xml
index 44bd807..f886daf 100644
--- a/res/xml/dark_mode_settings.xml
+++ b/res/xml/dark_mode_settings.xml
@@ -22,8 +22,8 @@
 
     <com.android.settingslib.widget.TopIntroPreference
         android:key="dark_ui_top_intro"
-        android:title="@string/dark_ui_text"
-        settings:searchable="false"/>
+        settings:searchable="false"
+        settings:controller="com.android.settings.display.darkmode.DarkModeTopIntroPreferenceController"/>
 
     <com.android.settingslib.widget.MainSwitchPreference
         android:key="dark_ui_activated"
diff --git a/src/com/android/settings/accessibility/TextReadingPreviewPreference.java b/src/com/android/settings/accessibility/TextReadingPreviewPreference.java
index 9161171..99e7125 100644
--- a/src/com/android/settings/accessibility/TextReadingPreviewPreference.java
+++ b/src/com/android/settings/accessibility/TextReadingPreviewPreference.java
@@ -22,6 +22,7 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.FrameLayout;
+import android.widget.ImageButton;
 import android.widget.LinearLayout;
 
 import androidx.preference.Preference;
@@ -99,6 +100,28 @@
                 (DotsPageIndicator) holder.findViewById(R.id.page_indicator);
         updateAdapterIfNeeded(viewPager, pageIndicator, mPreviewAdapter);
         updatePagerAndIndicator(viewPager, pageIndicator);
+        viewPager.setClipToOutline(true);
+
+        int layoutDirection =
+                getContext().getResources().getConfiguration().getLayoutDirection();
+        int previousId = (layoutDirection == View.LAYOUT_DIRECTION_RTL)
+                ? R.id.preview_right_button : R.id.preview_left_button;
+        int nextId = (layoutDirection == View.LAYOUT_DIRECTION_RTL)
+                ? R.id.preview_left_button : R.id.preview_right_button;
+        final ImageButton previousButton = previewLayout.findViewById(previousId);
+        final ImageButton nextButton = previewLayout.findViewById(nextId);
+
+        // These call ViewPager#setCurrentItem directly
+        // because that doesn't force a refresh through notifyChanged().
+        // We found this avoids a crash in SUW (See b/386906497).
+        previousButton.setOnClickListener((view) ->
+                viewPager.setCurrentItem(getCurrentItem() - 1));
+        previousButton.setContentDescription(getContext().getString(
+                R.string.preview_pager_previous_button));
+        nextButton.setOnClickListener((view) ->
+                viewPager.setCurrentItem(getCurrentItem() + 1));
+        previousButton.setContentDescription(getContext().getString(
+                R.string.preview_pager_next_button));
     }
 
     @Override
diff --git a/src/com/android/settings/display/darkmode/DarkModeTopIntroPreferenceController.java b/src/com/android/settings/display/darkmode/DarkModeTopIntroPreferenceController.java
new file mode 100644
index 0000000..3688a05
--- /dev/null
+++ b/src/com/android/settings/display/darkmode/DarkModeTopIntroPreferenceController.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2025 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.settings.display.darkmode;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.widget.TopIntroPreference;
+
+/**
+ * Controller of the top info preference in the Dark Mode settings page.
+ *
+ * This should be removed after the flag android.view.accessibility.force_invert_color is launched.
+ */
+public class DarkModeTopIntroPreferenceController extends BasePreferenceController {
+    @Nullable private TopIntroPreference mPreference;
+
+    public DarkModeTopIntroPreferenceController(
+            @NonNull Context context,
+            @NonNull String preferenceKey) {
+        super(context, preferenceKey);
+
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return AVAILABLE_UNSEARCHABLE;
+    }
+
+    @Override
+    public void displayPreference(@NonNull PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreference = screen.findPreference(getPreferenceKey());
+        if (android.view.accessibility.Flags.forceInvertColor()) {
+            mPreference.setTitle(R.string.dark_ui_text_force_invert);
+        } else {
+            mPreference.setTitle(R.string.dark_ui_text);
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/display/darkmode/DarkModeTopIntroPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeTopIntroPreferenceControllerTest.java
new file mode 100644
index 0000000..f5f25d8
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/display/darkmode/DarkModeTopIntroPreferenceControllerTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2025 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.settings.display.darkmode;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.view.accessibility.Flags;
+
+import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settingslib.widget.TopIntroPreference;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+/**
+ * Tests for {@link DarkModeTopIntroPreferenceController}.
+ */
+@RunWith(RobolectricTestRunner.class)
+public class DarkModeTopIntroPreferenceControllerTest {
+    @Rule
+    public final MockitoRule mocks = MockitoJUnit.rule();
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+    private static final String PREFERENCE_KEY = "preference_key";
+
+    @Mock
+    private PreferenceScreen mScreen;
+    @Mock
+    private TopIntroPreference mPreference;
+    private DarkModeTopIntroPreferenceController mController;
+    private final Context mContext = ApplicationProvider.getApplicationContext();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mController = new DarkModeTopIntroPreferenceController(mContext, PREFERENCE_KEY);
+        when(mScreen.findPreference(PREFERENCE_KEY)).thenReturn(mPreference);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_FORCE_INVERT_COLOR)
+    public void enableForceInvert_newPreferenceTitle() {
+        mController.displayPreference(mScreen);
+
+        verify(mPreference).setTitle(eq(R.string.dark_ui_text_force_invert));
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_FORCE_INVERT_COLOR)
+    public void disableForceInvert_originalPreferenceTitle() {
+        mController.displayPreference(mScreen);
+
+        verify(mPreference).setTitle(eq(R.string.dark_ui_text));
+    }
+}