diff --git a/android/res/values/attrs.xml b/android/res/values/attrs.xml
index ffd4f5d6c5..c101e936aa 100644
--- a/android/res/values/attrs.xml
+++ b/android/res/values/attrs.xml
@@ -93,4 +93,9 @@
+
+
+
+
+
diff --git a/android/src/com/mapswithme/maps/widget/ParallaxBackgroundPageListener.java b/android/src/com/mapswithme/maps/widget/ParallaxBackgroundPageListener.java
new file mode 100755
index 0000000000..558477a7ec
--- /dev/null
+++ b/android/src/com/mapswithme/maps/widget/ParallaxBackgroundPageListener.java
@@ -0,0 +1,174 @@
+package com.mapswithme.maps.widget;
+
+import android.support.annotation.NonNull;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.ImageView;
+
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+
+public class ParallaxBackgroundPageListener implements ViewPager.OnPageChangeListener
+{
+
+ private static final String ANDROID_SWITCHER_TAG_SEGMENT = "android:switcher:";
+ private static final String SEPARATOR_TAG_SEGMENT = ":";
+ private static final float POSITION_OFFSET_BASE = 0.5f;
+ private static final int POSITION_OFFSET_PIXELS_BASE = 1;
+ private static final float ALPHA_TRANSPARENT = 0.0F;
+ private static final float ALPHA_OPAQUE = 1.0f;
+ private static final int MINUS_INFINITY_EDGE = -1;
+ private static final int PLUS_INFINITY_EDGE = 1;
+ private static final float SETTLED_PAGE_POSITION = 0.0f;
+
+ @NonNull
+ private final ViewPager mPager;
+ @NonNull
+ private final FragmentPagerAdapter mAdapter;
+ @NonNull
+ private final AppCompatActivity mActivity;
+ @NonNull
+ private final List mItems;
+
+ private int mCurrentPagePosition;
+ private boolean mIsScrollToRight = true;
+ private boolean mIsScrollStarted;
+ private boolean mShouldCalculateScrollDirection;
+
+ public ParallaxBackgroundPageListener(@NonNull AppCompatActivity activity,
+ @NonNull ViewPager pager,
+ @NonNull FragmentPagerAdapter adapter,
+ @NonNull List items)
+ {
+ mPager = pager;
+ mAdapter = adapter;
+ mActivity = activity;
+ mItems = items;
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state)
+ {
+ if (state == ViewPager.SCROLL_STATE_IDLE)
+ {
+ mCurrentPagePosition = mPager.getCurrentItem();
+ mIsScrollToRight = true;
+ }
+
+ boolean isDragScroll = isDragScroll(state);
+
+ mIsScrollStarted = isDragScroll;
+ if (isDragScroll)
+ mShouldCalculateScrollDirection = true;
+ }
+
+ @Override
+ public void onPageSelected(int position)
+ {
+ if (position == 0)
+ onPageScrollStateChanged(ViewPager.SCROLL_STATE_IDLE);
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
+ {
+ recalculateScrollDirection(positionOffset, positionOffsetPixels);
+
+ int scrollX = mPager.getScrollX();
+ if (canScrollToLeft(scrollX) || isRightEdge(scrollX))
+ return;
+
+ int animatedItemIndex = mIsScrollToRight ? mCurrentPagePosition : mCurrentPagePosition - 1;
+ setAlpha(animatedItemIndex, scrollX);
+
+ if (isLeftEdge(scrollX))
+ restoreInitialAlphaValues();
+ }
+
+ private boolean isDragScroll(int state)
+ {
+ return !mIsScrollStarted && state == ViewPager.SCROLL_STATE_DRAGGING;
+ }
+
+ private boolean canScrollToLeft(int scrollX)
+ {
+ return isLeftEdge(scrollX) && !mIsScrollToRight;
+ }
+
+ private void setAlpha(int animatedItemIndex, int scrollX)
+ {
+ View child = findFragmentViewByIndex(animatedItemIndex);
+ ViewPager.LayoutParams lp = (ViewPager.LayoutParams) child.getLayoutParams();
+ if (lp.isDecor)
+ return;
+
+ float transformPos = (float) (child.getLeft() - scrollX) / (float) getClientWidth();
+ initCurrentAlpha(transformPos, animatedItemIndex);
+ }
+
+ @NonNull
+ private View findFragmentViewByIndex(int index)
+ {
+ String tag = makePagerFragmentTag(index, mPager.getId());
+ Fragment page = mActivity.getSupportFragmentManager().findFragmentByTag(tag);
+ if (page == null)
+ throw new NoSuchElementException("no such element for tag : " + tag);
+
+ return Objects.requireNonNull(page.getView());
+ }
+
+ private void initCurrentAlpha(float transformPos, int itemIndex)
+ {
+ ImageView currentImage = mActivity.findViewById(mItems.get(itemIndex));
+ if (transformPos <= MINUS_INFINITY_EDGE || transformPos >= PLUS_INFINITY_EDGE)
+ currentImage.setAlpha(ALPHA_TRANSPARENT);
+ else if (transformPos == SETTLED_PAGE_POSITION)
+ currentImage.setAlpha(ALPHA_OPAQUE);
+ else
+ currentImage.setAlpha(ALPHA_OPAQUE - Math.abs(transformPos));
+ }
+
+ private boolean isLeftEdge(int scrollX)
+ {
+ return scrollX == 0;
+ }
+
+ private boolean isRightEdge(int scrollX)
+ {
+ return scrollX == mPager.getWidth() * mAdapter.getCount();
+ }
+
+ private void restoreInitialAlphaValues()
+ {
+ for (int j = mItems.size() - 1; j >= 0; j--)
+ {
+ View view = mActivity.findViewById(mItems.get(j));
+ view.setAlpha(ALPHA_OPAQUE);
+ }
+ }
+
+ private void recalculateScrollDirection(float positionOffset, int positionOffsetPixels)
+ {
+ if (mShouldCalculateScrollDirection)
+ {
+ mIsScrollToRight =
+ POSITION_OFFSET_BASE > positionOffset && positionOffsetPixels > POSITION_OFFSET_PIXELS_BASE;
+ mShouldCalculateScrollDirection = false;
+ }
+ }
+
+ private int getClientWidth()
+ {
+ return mPager.getMeasuredWidth() - mPager.getPaddingLeft() - mPager.getPaddingRight();
+ }
+
+ @NonNull
+ private static String makePagerFragmentTag(int index, int pagerId)
+ {
+ return ANDROID_SWITCHER_TAG_SEGMENT + pagerId + SEPARATOR_TAG_SEGMENT + index;
+ }
+}
diff --git a/android/src/com/mapswithme/maps/widget/ParallaxBackgroundViewPager.java b/android/src/com/mapswithme/maps/widget/ParallaxBackgroundViewPager.java
new file mode 100755
index 0000000000..c66485b2d1
--- /dev/null
+++ b/android/src/com/mapswithme/maps/widget/ParallaxBackgroundViewPager.java
@@ -0,0 +1,132 @@
+package com.mapswithme.maps.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Handler;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.view.MotionEventCompat;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import com.mapswithme.maps.R;
+
+public class ParallaxBackgroundViewPager extends ViewPager
+{
+
+ private static final int DEFAULT_AUTO_SCROLL_PERIOD = 3000;
+ private static final int CAROUSEL_ITEMS_MIN_COUNT = 2;
+ private final int mAutoScrollPeriod;
+ private final boolean mHasAutoScroll;
+ @NonNull
+ private final Handler mAutoScrollHandler;
+ @NonNull
+ private final Runnable mAutoScrollMessage;
+ private int mCurrentPagePosition;
+
+ public ParallaxBackgroundViewPager(@NonNull Context context)
+ {
+ this(context, null);
+ }
+
+ public ParallaxBackgroundViewPager(@NonNull Context context, @Nullable AttributeSet attrs)
+ {
+ super(context, attrs);
+ TypedArray a = context.getTheme()
+ .obtainStyledAttributes(attrs, R.styleable.ParallaxBgViewPager, 0, 0);
+ try
+ {
+ mHasAutoScroll = a.getBoolean(R.styleable.ParallaxBgViewPager_autoScroll, false);
+ mAutoScrollPeriod = a.getInt(R.styleable.ParallaxBgViewPager_scrollPeriod,
+ DEFAULT_AUTO_SCROLL_PERIOD);
+ }
+ finally
+ {
+ a.recycle();
+ }
+ mAutoScrollHandler = new Handler();
+ mAutoScrollMessage = new AutoScrollMessage();
+ OnPageChangeListener autoScrollPageListener = new AutoScrollPageListener();
+ addOnPageChangeListener(autoScrollPageListener);
+ }
+
+ @Override
+ protected void onDetachedFromWindow()
+ {
+ super.onDetachedFromWindow();
+ stopAutoScroll();
+ clearOnPageChangeListeners();
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev)
+ {
+ int action = MotionEventCompat.getActionMasked(ev);
+
+ if (action == MotionEvent.ACTION_DOWN && mHasAutoScroll)
+ stopAutoScroll();
+ else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_OUTSIDE)
+ startAutoScroll();
+
+ return super.dispatchTouchEvent(ev);
+ }
+
+ public void startAutoScroll()
+ {
+ mAutoScrollHandler.postDelayed(mAutoScrollMessage, mAutoScrollPeriod);
+ }
+
+ public void stopAutoScroll()
+ {
+ mAutoScrollHandler.removeCallbacks(mAutoScrollMessage);
+ }
+
+ private boolean isLastAutoScrollPosition()
+ {
+ PagerAdapter adapter = getAdapter();
+ return adapter != null && adapter.getCount() - 1 == mCurrentPagePosition;
+ }
+
+ private class AutoScrollPageListener implements OnPageChangeListener
+ {
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
+ {
+ }
+
+ @Override
+ public void onPageSelected(int position)
+ {
+ mCurrentPagePosition = position;
+ mAutoScrollHandler.removeCallbacks(mAutoScrollMessage);
+ mAutoScrollHandler.postDelayed(mAutoScrollMessage, mAutoScrollPeriod);
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state)
+ {
+ }
+ }
+
+ private class AutoScrollMessage implements Runnable
+ {
+ @Override
+ public void run()
+ {
+ PagerAdapter adapter = getAdapter();
+ if (adapter == null
+ || adapter.getCount() < CAROUSEL_ITEMS_MIN_COUNT
+ || !mHasAutoScroll)
+ return;
+
+ if (isLastAutoScrollPosition())
+ mCurrentPagePosition = 0;
+ else
+ mCurrentPagePosition++;
+
+ setCurrentItem(mCurrentPagePosition, true);
+ }
+ }
+}