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);
+ }
+ }
+}