Merge "[ThemePicker 4/N] Add a PreviewPager widget" into ub-launcher3-master
diff --git a/res/drawable/ic_arrow_back_24px.xml b/res/drawable/ic_arrow_back_24px.xml
new file mode 100644
index 0000000..3eb00c7
--- /dev/null
+++ b/res/drawable/ic_arrow_back_24px.xml
@@ -0,0 +1,24 @@
+<!--
+     Copyright (C) 2018 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="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="?android:attr/colorForeground"
+        android:pathData="M16.41,5.41l-1.41,-1.41l-8,8l8,8l1.41,-1.41l-6.58,-6.59"/>
+</vector>
diff --git a/res/drawable/ic_arrow_forward_24px.xml b/res/drawable/ic_arrow_forward_24px.xml
new file mode 100644
index 0000000..a7284b2
--- /dev/null
+++ b/res/drawable/ic_arrow_forward_24px.xml
@@ -0,0 +1,24 @@
+<!--
+     Copyright (C) 2018 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="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="?android:attr/colorForeground"
+        android:pathData="M7.59,18.59l1.41,1.41l8,-8l-8,-8l-1.41,1.41l6.58,6.59"/>
+</vector>
diff --git a/res/layout/preview_pager.xml b/res/layout/preview_pager.xml
new file mode 100644
index 0000000..a165e56
--- /dev/null
+++ b/res/layout/preview_pager.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+     Copyright (C) 2018 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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <androidx.viewpager.widget.ViewPager
+        android:id="@+id/preview_viewpager"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"/>
+
+    <FrameLayout
+        android:id="@+id/indicator_container"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/indicator_container_height"
+        android:layout_gravity="bottom">
+
+        <com.android.customization.widget.PageIndicator
+            android:id="@+id/page_indicator"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center" />
+
+        <FrameLayout
+            android:id="@+id/arrow_previous"
+            android:layout_width="@dimen/indicator_arrow_touch_area_size"
+            android:layout_height="@dimen/indicator_arrow_touch_area_size"
+            android:layout_gravity="center_vertical|start"
+            android:layout_marginStart="@dimen/indicator_arrow_container_margin_horizontal"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:contentDescription="@string/previous_page_content_description"
+            android:visibility="gone">
+
+            <ImageView
+                android:layout_width="@dimen/indicator_arrow_size"
+                android:layout_height="@dimen/indicator_arrow_size"
+                android:layout_gravity="center"
+                android:contentDescription="@null"
+                android:src="@drawable/ic_arrow_back_24px" />
+        </FrameLayout>
+
+        <FrameLayout
+            android:id="@+id/arrow_next"
+            android:layout_width="@dimen/indicator_arrow_touch_area_size"
+            android:layout_height="@dimen/indicator_arrow_touch_area_size"
+            android:layout_gravity="center_vertical|end"
+            android:layout_marginEnd="@dimen/indicator_arrow_container_margin_horizontal"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:contentDescription="@string/next_page_content_description"
+            android:visibility="gone">
+
+            <ImageView
+                android:layout_width="@dimen/indicator_arrow_size"
+                android:layout_height="@dimen/indicator_arrow_size"
+                android:layout_gravity="center"
+                android:contentDescription="@null"
+                android:src="@drawable/ic_arrow_forward_24px" />
+        </FrameLayout>
+    </FrameLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index d2c466b..5576e4c 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -20,5 +20,15 @@
 
     <dimen name="preview_indicator_width">16dp</dimen>
     <dimen name="preview_indicator_height">8dp</dimen>
+    <dimen name="indicator_container_height">48dp</dimen>
+    <dimen name="indicator_container_divider_height">1dp</dimen>
+    <dimen name="indicator_arrow_size">24dp</dimen>
+    <dimen name="indicator_arrow_touch_area_size">48dp</dimen>
+
+    <dimen name="indicator_arrow_container_margin_horizontal">4dp</dimen>
+    <dimen name="preview_page_gap">16dp</dimen>
+    <dimen name="preview_page_horizontal_margin">56dp</dimen>
+    <dimen name="preview_page_top_margin">16dp</dimen>
+    <dimen name="preview_page_bottom_margin">2dp</dimen>
 
 </resources>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 735e781..613c481 100755
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -40,4 +40,9 @@
 
     <!-- Accessibility label for paging indicator in theme picker preview [CHAR LIMIT=NONE] -->
     <string name="accessibility_preview_pager">Page <xliff:g name="current_page" example="1">%1$d</xliff:g> of <xliff:g name="num_pages" example="2">%2$d</xliff:g></string>
+    <!-- Content description of the next button to bring user to the next preview page.[CHAR LIMIT=NONE] -->
+    <string name="next_page_content_description">Next</string>
+    <!-- Content description of the previous button to bring user to the previous preview page. [CHAR LIMIT=NONE] -->
+    <string name="previous_page_content_description">Previous</string>
+
 </resources>
diff --git a/src/com/android/customization/widget/PreviewPager.java b/src/com/android/customization/widget/PreviewPager.java
new file mode 100644
index 0000000..0ea43fc
--- /dev/null
+++ b/src/com/android/customization/widget/PreviewPager.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2018 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.customization.widget;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.DataSetObserver;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import androidx.annotation.Nullable;
+import androidx.viewpager.widget.PagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
+
+import com.android.wallpaper.R;
+
+/**
+ * A Widget consisting of a ViewPager linked to a PageIndicator and previous/next arrows that can be
+ * used to page over that ViewPager.
+ * To use it, set a {@link PagerAdapter} using {@link #setAdapter(PagerAdapter)}, and optionally use
+ * a {@link #setOnPageChangeListener(OnPageChangeListener)} to listen for page changes.
+ */
+public class PreviewPager extends LinearLayout {
+
+    private final ViewPager mViewPager;
+    private final PageIndicator mPageIndicator;
+    private final View mPreviousArrow;
+    private final View mNextArrow;
+    private final ViewPager.OnPageChangeListener mPageListener;
+
+    private PagerAdapter mAdapter;
+    private ViewPager.OnPageChangeListener mExternalPageListener;
+
+    public PreviewPager(Context context) {
+        this(context, null);
+    }
+
+    public PreviewPager(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public PreviewPager(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        LayoutInflater.from(context).inflate(R.layout.preview_pager, this);
+        Resources res = context.getResources();
+
+        mViewPager = findViewById(R.id.preview_viewpager);
+        mViewPager.setPageMargin(res.getDimensionPixelOffset(R.dimen.preview_page_gap));
+        mViewPager.setClipToPadding(false);
+        mViewPager.setPadding(res.getDimensionPixelOffset(R.dimen.preview_page_horizontal_margin),
+                res.getDimensionPixelOffset(R.dimen.preview_page_top_margin),
+                res.getDimensionPixelOffset(R.dimen.preview_page_horizontal_margin),
+                res.getDimensionPixelOffset(R.dimen.preview_page_bottom_margin));
+        mPageIndicator = findViewById(R.id.page_indicator);
+        mPreviousArrow = findViewById(R.id.arrow_previous);
+        mPreviousArrow.setOnClickListener(v -> {
+            final int previousPos = mViewPager.getCurrentItem() - 1;
+            mViewPager.setCurrentItem(previousPos, true);
+        });
+        mNextArrow = findViewById(R.id.arrow_next);
+        mNextArrow.setOnClickListener(v -> {
+            final int NextPos = mViewPager.getCurrentItem() + 1;
+            mViewPager.setCurrentItem(NextPos, true);
+        });
+        mPageListener = createPageListener();
+        mViewPager.addOnPageChangeListener(mPageListener);
+    }
+
+    /**
+     * Call this method to set the {@link PagerAdapter} backing the {@link ViewPager} in this
+     * widget.
+     */
+    public void setAdapter(PagerAdapter adapter) {
+        mAdapter = adapter;
+        mViewPager.setAdapter(adapter);
+
+        mAdapter.registerDataSetObserver(new DataSetObserver() {
+            @Override
+            public void onChanged() {
+                initIndicator();
+            }
+        });
+        initIndicator();
+        updateIndicator(mViewPager.getCurrentItem());
+    }
+
+    /**
+     * Set a {@link OnPageChangeListener} to be notified when the ViewPager's page state changes
+     */
+    public void setOnPageChangeListener(@Nullable ViewPager.OnPageChangeListener listener) {
+        mExternalPageListener = listener;
+    }
+
+    private void initIndicator() {
+        mPageIndicator.setNumPages(mAdapter.getCount());
+        mPageIndicator.setLocation(mViewPager.getCurrentItem());
+    }
+
+    private ViewPager.OnPageChangeListener createPageListener() {
+        return new ViewPager.OnPageChangeListener() {
+             @Override
+             public void onPageScrolled(
+                     int position, float positionOffset, int positionOffsetPixels) {
+                 mPageIndicator.setLocation(position + positionOffset);
+                 if (mExternalPageListener != null) {
+                     mExternalPageListener.onPageScrolled(position, positionOffset,
+                             positionOffsetPixels);
+                 }
+             }
+
+             @Override
+             public void onPageSelected(int position) {
+                 int adapterCount = mAdapter.getCount();
+                 if (position < 0 || position >= adapterCount) {
+                     return;
+                 }
+
+                 updateIndicator(position);
+                 if (mExternalPageListener != null) {
+                     mExternalPageListener.onPageSelected(position);
+                 }
+             }
+
+             @Override
+             public void onPageScrollStateChanged(int state) {
+                 if (mExternalPageListener != null) {
+                     mExternalPageListener.onPageScrollStateChanged(state);
+                 }
+             }
+        };
+    }
+
+    private void updateIndicator(int position) {
+        int adapterCount = mAdapter.getCount();
+        if (adapterCount > 0) {
+            mPreviousArrow.setVisibility(position == 0 ? View.GONE : View.VISIBLE);
+            mNextArrow.setVisibility(
+                    position == (adapterCount - 1) ? View.GONE : View.VISIBLE);
+        } else {
+            mPageIndicator.setVisibility(View.GONE);
+            mPreviousArrow.setVisibility(View.GONE);
+            mNextArrow.setVisibility(View.GONE);
+        }
+    }
+}