package com.android.systemui.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Adapter;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
/**
* Problems will arise if you change the carousel mode after setting an adapter
*/
public class PageView extends BounceSwipeView
{
private Adapter mAdapter;
private OnPageChangedListener mOnPageChangedListener; // as we are
// implementing our
// own
// OnPageChangedListener
// we need to keep the
// one set by a class
// implementing a
// CarouseView and
// then call it after
// we've done our
// bits.
private int mCurrentPage;
private int mOffset;
private boolean mCarouselMode = false;
public PageView(Context context)
{
super(context);
initView();
}
public PageView(Context context, AttributeSet attrs)
{
super(context, attrs);
initView();
}
public PageView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
initView();
}
private void initView()
{
setBounceEnabled(false);
}
/**
* The page being shown on the screen, rather than the underlying page in
* the SwipeView structure ( getCurrentPage() )
*
* @return
*/
public int getRealCurrentPage()
{
return mCurrentPage;
}
@Override
public int setPageWidth(int pageWidth)
{
mOffset = super.setPageWidth(pageWidth);
return mOffset;
}
public void setCarouselEnabled(boolean enabled)
{
mCarouselMode = enabled;
setBounceEnabled(!enabled);
}
public boolean getCarouselEnabled()
{
return mCarouselMode;
}
public void setAdapter(BaseAdapter adapter)
{
setAdapter(adapter, 0);
}
public void setAdapter(BaseAdapter adapter, final int startPosition)
{
mAdapter = adapter;
if (mAdapter != null)
{
mCurrentPage = startPosition;
fillCarousel(startPosition);
post(new Runnable()
{
public void run()
{
if (!mCarouselMode && startPosition == 0)
{
PageView.super.scrollToPage(0);
}
else if (!mCarouselMode && startPosition == mAdapter.getCount() - 1)
{
PageView.super.scrollToPage(2);
}
else
{
PageView.super.scrollToPage(1);
}
}
});
if (mAdapter.getCount() <= 1)
{
setBounceEnabled(true);
}
}
}
public Adapter getAdapter()
{
return mAdapter;
}
// we call this locally because we do a sneaky sneaky for 2 pages. we double
// it so it behave like it has four pages instead e.g. [1][2] becomes
// [1][2][1][2]. We then correct for this in the loadPage method
private int getAdapterPageCount()
{
if (mAdapter != null)
{
if (mAdapter.getCount() == 2 && mCarouselMode)
{
return 4;
}
else
{
return mAdapter.getCount();
}
}
else
{
return -1;
}
}
private void emptyCarousel()
{
getChildContainer().removeAllViews();
}
private void fillCarousel(int page)
{
emptyCarousel();
if (mAdapter.getCount() == 1)
{
loadPage(0, 0, null);// TODO make this actually support one page
// only.
}
else if (mAdapter.getCount() == 2)
{
if (!mCarouselMode)
{
loadPage(0, 0, null);
loadPage(1, 1, null);
}
else if (page == 0)
{
loadPage(1, 0, null);
loadPage(0, 1, null);
loadPage(1, 2, null);
}
else // page==1 (hopefully)
{
loadPage(0, 0, null);
loadPage(1, 1, null);
loadPage(0, 2, null);
}
}
else if (mAdapter.getCount() > 2)
{
if (page == 0 && mCarouselMode)// if first page, need to handle
// loading last page
{
loadPage(mAdapter.getCount() - 1, 0, null);
loadPage(0, 1, null);
loadPage(1, 2, null);
}
else if (page == 0 && !mCarouselMode)
{
loadPage(0, 0, null);
loadPage(1, 1, null);
loadPage(2, 2, null);
}
else if (page == mAdapter.getCount() - 1 && mCarouselMode)// if last
// page,
// need to
// handle
// loading
// first
// page
{
loadPage(page - 1, 0, null);
loadPage(mAdapter.getCount() - 1, 1, null);
loadPage(0, 2, null);
}
else if (page == mAdapter.getCount() - 1 && !mCarouselMode)
{
loadPage(mAdapter.getCount() - 3, 0, null);
loadPage(mAdapter.getCount() - 2, 1, null);
loadPage(mAdapter.getCount() - 1, 2, null);
}
else // get on with it
{
loadPage(page - 1, 0, null);
loadPage(page, 1, null);
loadPage(page + 1, 2, null);
}
resetMargins();
}
}
@Override
public void setOnPageChangedListener(OnPageChangedListener onPageChangedListener)
{
mOnPageChangedListener = onPageChangedListener;
}
@Override
public OnPageChangedListener getOnPageChangedListener()
{
return mOnPageChangedListener;
}
private void loadPage(int page, int position, View convertView)
{
if (mAdapter.getCount() == 2 && page > 1)
{
page = page - 2;
}
super.addView(mAdapter.getView(page, convertView, getChildContainer()), position);
}
@Override
public void smoothScrollToPage(int page)
{
scrollToPage(page, true);
}
@Override
public void scrollToPage(int page)
{
scrollToPage(page, false);
}
private void scrollToPage(int page, boolean smooth)
{
if (!mCarouselMode && getCurrentPage() == getPageCount() - 1 && page >= getCurrentPage() ||
!mCarouselMode && getCurrentPage() == 0 && page <= 0)
{
doAtEdgeAnimation();
}
else if (getCurrentPage() != page)
{
rearrangePages(getCurrentPage(), page, smooth);
notifiyAssignedOnPageChangedListener(page);
}
}
private void notifiyAssignedOnPageChangedListener(int newPage)
{
// call the OnPageChangedListener that might have been set by a class
// implementing a PageView
if (mOnPageChangedListener != null)
{
if (mCarouselMode && mCurrentPage == 0 && newPage == 2) // looping
// round to
// end from
// begining
{
mOnPageChangedListener.onPageChanged(mAdapter.getCount() - 1, mCurrentPage);
}
else if (mCarouselMode && mCurrentPage == mAdapter.getCount() - 1 && newPage == 0) // looping
// round
// from
// end
// back
// to
// begining
{
mOnPageChangedListener.onPageChanged(0, mCurrentPage);
}
else if (!mCarouselMode && mCurrentPage == 1 && newPage == 1) // going
// from
// first
// page
// into
// second,
// not
// using
// carousel
{
mOnPageChangedListener.onPageChanged(0, 1);
}
else if (!mCarouselMode && mCurrentPage == mAdapter.getCount() - 1
&& newPage == mAdapter.getCount() - 1)
{
mOnPageChangedListener.onPageChanged(mCurrentPage, mAdapter.getCount() - 2);
}
else if (newPage == 2) // going forwards
{
mOnPageChangedListener.onPageChanged(mCurrentPage - 1, mCurrentPage);
}
else // if(newPage==0) //going backwards
{
mOnPageChangedListener.onPageChanged(mCurrentPage + 1, mCurrentPage);
}
}
}
private void rearrangePages(int oldPage, int newPage, final boolean smooth)
{
// do the clever loading / moving pages thingy...
if (getAdapterPageCount() > 1)
{
final int pageToScrollTo;
if (newPage >= oldPage + 1)// going forwards
{
if (mCarouselMode || mCurrentPage < getAdapterPageCount() - 2 && mCurrentPage > 0)
{
mCallScrollToPageInOnLayout = false;
scrollTo(getScrollX() - getPageWidth(), 0);
forwardsMove();
pageToScrollTo = 1;
}
else if (mCurrentPage <= 0)
{
mCurrentPage = 1;
pageToScrollTo = 1;
}
else
{
mCurrentPage = getAdapterPageCount() - 1;
pageToScrollTo = 2;
}
}
else if (newPage <= oldPage - 1)// going backwards
{
if (mCarouselMode || mCurrentPage > 1 && mCurrentPage < getAdapterPageCount() - 1)
{
mCallScrollToPageInOnLayout = false;
scrollTo(getScrollX() + getPageWidth(), 0);
backwardsMove();
pageToScrollTo = 1;
}
else if (mCurrentPage >= getAdapterPageCount() - 1)
{
mCurrentPage = getAdapterPageCount() - 2;
pageToScrollTo = 1;
}
else
{
mCurrentPage = 0;
pageToScrollTo = 0;
}
}
else // doesn't do anything, needed to make it compile...
{
pageToScrollTo = 1;
}
post(new Runnable()
{
public void run()
{
if (smooth)
{
PageView.super.smoothScrollToPage(pageToScrollTo);
}
else
{
PageView.super.scrollToPage(pageToScrollTo);
}
}
});
}
}
private void forwardsMove()
{
if (mCurrentPage < getAdapterPageCount() - 1)
{
mCurrentPage++;
}
else
{
mCurrentPage = 0;
}
if (mCurrentPage < getAdapterPageCount() - 1)
{
forwardsRearrange(mCurrentPage + 1);
}
else
{
forwardsRearrange(0);
}
}
private void backwardsMove()
{
if (mCurrentPage > 0)
{
mCurrentPage--;
}
else
{
mCurrentPage = getAdapterPageCount() - 1;
}
if (mCurrentPage > 0)
{
backwardsRearrange(mCurrentPage - 1);
}
else
{
backwardsRearrange(getAdapterPageCount() - 1);
}
}
private void forwardsRearrange(int frontPageToLoad)
{
// Lose '0', move '1' into '0', move '2' into '1', and load in new '2'
View convertView = getChildContainer().getChildAt(0);
getChildContainer().removeViewAt(0);
loadPage(frontPageToLoad, 2, convertView);
resetMargins();
}
private void backwardsRearrange(int backPageToLoad)
{
View convertView = getChildContainer().getChildAt(2);
getChildContainer().removeViewAt(2);
loadPage(backPageToLoad, 0, convertView);
resetMargins();
}
private void resetMargins()
{
if (mOffset > 0)
{
((LinearLayout.LayoutParams) getChildContainer().getChildAt(0).getLayoutParams()).leftMargin = mOffset;
((LinearLayout.LayoutParams) getChildContainer().getChildAt(0).getLayoutParams()).rightMargin = 0;
((LinearLayout.LayoutParams) getChildContainer().getChildAt(1).getLayoutParams()).leftMargin = 0;
((LinearLayout.LayoutParams) getChildContainer().getChildAt(1).getLayoutParams()).rightMargin = 0;
((LinearLayout.LayoutParams) getChildContainer().getChildAt(2).getLayoutParams()).leftMargin = 0;
((LinearLayout.LayoutParams) getChildContainer().getChildAt(2).getLayoutParams()).rightMargin = mOffset;
}
}
public void itemAddedToAdapter(int position)
{
if (position <= mCurrentPage)
{
mCurrentPage++;
}
if (mAdapter.getCount() > 1)
{
setBounceEnabled(false);
}
refill(position);
}
public void itemRemovedFromAdapter(int position)
{
if (position <= mCurrentPage && mCurrentPage != 0)
{
mCurrentPage--;
}
refill(position);
}
private void refill(int position)
{
if (mCurrentPage == 0)// if it could be an edge case at start
{
if (position == getAdapterPageCount() - 1 || position <= mCurrentPage + 1)// if
// we
// need
// to
// refill
// carousel
{
fillCarousel(mCurrentPage);
}
}
else if (mCurrentPage == getAdapterPageCount() - 1)// if it could be an
// edge case at end
{
if (position >= mCurrentPage || position == 0)// if we need to
// refill carousel
{
fillCarousel(mCurrentPage);
}
}
else // not an edge case
{
if (position >= mCurrentPage - 1 && position <= mCurrentPage + 1)// if
// we
// need
// to
// refill
// carousel
{
fillCarousel(mCurrentPage);
}
}
}
}