Home | History | Annotate | Download | only in qs
      1 package com.android.systemui.qs;
      2 
      3 import android.content.Context;
      4 import android.content.res.Configuration;
      5 import android.content.res.Resources;
      6 import android.support.v4.view.PagerAdapter;
      7 import android.support.v4.view.ViewPager;
      8 import android.util.AttributeSet;
      9 import android.util.Log;
     10 import android.view.LayoutInflater;
     11 import android.view.View;
     12 import android.view.ViewGroup;
     13 
     14 import com.android.systemui.R;
     15 import com.android.systemui.qs.QSPanel.QSTileLayout;
     16 import com.android.systemui.qs.QSPanel.TileRecord;
     17 
     18 import java.util.ArrayList;
     19 
     20 public class PagedTileLayout extends ViewPager implements QSTileLayout {
     21 
     22     private static final boolean DEBUG = false;
     23 
     24     private static final String TAG = "PagedTileLayout";
     25 
     26     private final ArrayList<TileRecord> mTiles = new ArrayList<TileRecord>();
     27     private final ArrayList<TilePage> mPages = new ArrayList<TilePage>();
     28 
     29     private PageIndicator mPageIndicator;
     30 
     31     private int mNumPages;
     32     private PageListener mPageListener;
     33 
     34     private int mPosition;
     35     private boolean mOffPage;
     36     private boolean mListening;
     37 
     38     public PagedTileLayout(Context context, AttributeSet attrs) {
     39         super(context, attrs);
     40         setAdapter(mAdapter);
     41         setOnPageChangeListener(new OnPageChangeListener() {
     42             @Override
     43             public void onPageSelected(int position) {
     44                 if (mPageIndicator == null) return;
     45                 if (mPageListener != null) {
     46                     mPageListener.onPageChanged(isLayoutRtl() ? position == mPages.size() - 1
     47                             : position == 0);
     48                 }
     49             }
     50 
     51             @Override
     52             public void onPageScrolled(int position, float positionOffset,
     53                     int positionOffsetPixels) {
     54                 if (mPageIndicator == null) return;
     55                 setCurrentPage(position, positionOffset != 0);
     56                 mPageIndicator.setLocation(position + positionOffset);
     57                 if (mPageListener != null) {
     58                     mPageListener.onPageChanged(positionOffsetPixels == 0 &&
     59                             (isLayoutRtl() ? position == mPages.size() - 1 : position == 0));
     60                 }
     61             }
     62 
     63             @Override
     64             public void onPageScrollStateChanged(int state) {
     65             }
     66         });
     67         setCurrentItem(0);
     68     }
     69 
     70     @Override
     71     public void onRtlPropertiesChanged(int layoutDirection) {
     72         super.onRtlPropertiesChanged(layoutDirection);
     73         setAdapter(mAdapter);
     74         setCurrentItem(0, false);
     75     }
     76 
     77     @Override
     78     public void setCurrentItem(int item, boolean smoothScroll) {
     79         if (isLayoutRtl()) {
     80             item = mPages.size() - 1 - item;
     81         }
     82         super.setCurrentItem(item, smoothScroll);
     83     }
     84 
     85     @Override
     86     public void setListening(boolean listening) {
     87         if (mListening == listening) return;
     88         mListening = listening;
     89         if (mListening) {
     90             setPageListening(mPosition, true);
     91             if (mOffPage) {
     92                 setPageListening(mPosition + 1, true);
     93             }
     94         } else {
     95             // Make sure no pages are listening.
     96             for (int i = 0; i < mPages.size(); i++) {
     97                 mPages.get(i).setListening(false);
     98             }
     99         }
    100     }
    101 
    102     /**
    103      * Sets individual pages to listening or not.  If offPage it will set
    104      * the next page after position to listening as well since we are in between
    105      * pages.
    106      */
    107     private void setCurrentPage(int position, boolean offPage) {
    108         if (mPosition == position && mOffPage == offPage) return;
    109         if (mListening) {
    110             if (mPosition != position) {
    111                 // Clear out the last pages from listening.
    112                 setPageListening(mPosition, false);
    113                 if (mOffPage) {
    114                     setPageListening(mPosition + 1, false);
    115                 }
    116                 // Set the new pages to listening
    117                 setPageListening(position, true);
    118                 if (offPage) {
    119                     setPageListening(position + 1, true);
    120                 }
    121             } else if (mOffPage != offPage) {
    122                 // Whether we are showing position + 1 has changed.
    123                 setPageListening(mPosition + 1, offPage);
    124             }
    125         }
    126         // Save the current state.
    127         mPosition = position;
    128         mOffPage = offPage;
    129     }
    130 
    131     private void setPageListening(int position, boolean listening) {
    132         if (position >= mPages.size()) return;
    133         if (isLayoutRtl()) {
    134             position = mPages.size() - 1 - position;
    135         }
    136         mPages.get(position).setListening(listening);
    137     }
    138 
    139     @Override
    140     public boolean hasOverlappingRendering() {
    141         return false;
    142     }
    143 
    144     @Override
    145     protected void onFinishInflate() {
    146         super.onFinishInflate();
    147         mPages.add((TilePage) LayoutInflater.from(getContext())
    148                 .inflate(R.layout.qs_paged_page, this, false));
    149     }
    150 
    151     public void setPageIndicator(PageIndicator indicator) {
    152         mPageIndicator = indicator;
    153     }
    154 
    155     @Override
    156     public int getOffsetTop(TileRecord tile) {
    157         final ViewGroup parent = (ViewGroup) tile.tileView.getParent();
    158         if (parent == null) return 0;
    159         return parent.getTop() + getTop();
    160     }
    161 
    162     @Override
    163     public void addTile(TileRecord tile) {
    164         mTiles.add(tile);
    165         postDistributeTiles();
    166     }
    167 
    168     @Override
    169     public void removeTile(TileRecord tile) {
    170         if (mTiles.remove(tile)) {
    171             postDistributeTiles();
    172         }
    173     }
    174 
    175     public void setPageListener(PageListener listener) {
    176         mPageListener = listener;
    177     }
    178 
    179     private void postDistributeTiles() {
    180         removeCallbacks(mDistribute);
    181         post(mDistribute);
    182     }
    183 
    184     private void distributeTiles() {
    185         if (DEBUG) Log.d(TAG, "Distributing tiles");
    186         final int NP = mPages.size();
    187         for (int i = 0; i < NP; i++) {
    188             mPages.get(i).removeAllViews();
    189         }
    190         int index = 0;
    191         final int NT = mTiles.size();
    192         for (int i = 0; i < NT; i++) {
    193             TileRecord tile = mTiles.get(i);
    194             if (mPages.get(index).isFull()) {
    195                 if (++index == mPages.size()) {
    196                     if (DEBUG) Log.d(TAG, "Adding page for "
    197                             + tile.tile.getClass().getSimpleName());
    198                     mPages.add((TilePage) LayoutInflater.from(getContext())
    199                             .inflate(R.layout.qs_paged_page, this, false));
    200                 }
    201             }
    202             if (DEBUG) Log.d(TAG, "Adding " + tile.tile.getClass().getSimpleName() + " to "
    203                     + index);
    204             mPages.get(index).addTile(tile);
    205         }
    206         if (mNumPages != index + 1) {
    207             mNumPages = index + 1;
    208             while (mPages.size() > mNumPages) {
    209                 mPages.remove(mPages.size() - 1);
    210             }
    211             if (DEBUG) Log.d(TAG, "Size: " + mNumPages);
    212             mPageIndicator.setNumPages(mNumPages);
    213             mPageIndicator.setVisibility(mNumPages > 1 ? View.VISIBLE : View.GONE);
    214             setAdapter(mAdapter);
    215             mAdapter.notifyDataSetChanged();
    216             setCurrentItem(0, false);
    217         }
    218     }
    219 
    220     @Override
    221     public boolean updateResources() {
    222         boolean changed = false;
    223         for (int i = 0; i < mPages.size(); i++) {
    224             changed |= mPages.get(i).updateResources();
    225         }
    226         if (changed) {
    227             distributeTiles();
    228         }
    229         return changed;
    230     }
    231 
    232     @Override
    233     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    234         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    235         // The ViewPager likes to eat all of the space, instead force it to wrap to the max height
    236         // of the pages.
    237         int maxHeight = 0;
    238         final int N = getChildCount();
    239         for (int i = 0; i < N; i++) {
    240             int height = getChildAt(i).getMeasuredHeight();
    241             if (height > maxHeight) {
    242                 maxHeight = height;
    243             }
    244         }
    245         setMeasuredDimension(getMeasuredWidth(), maxHeight + getPaddingBottom());
    246     }
    247 
    248     private final Runnable mDistribute = new Runnable() {
    249         @Override
    250         public void run() {
    251             distributeTiles();
    252         }
    253     };
    254 
    255     public int getColumnCount() {
    256         if (mPages.size() == 0) return 0;
    257         return mPages.get(0).mColumns;
    258     }
    259 
    260     public static class TilePage extends TileLayout {
    261         private int mMaxRows = 3;
    262 
    263         public TilePage(Context context, AttributeSet attrs) {
    264             super(context, attrs);
    265             updateResources();
    266         }
    267 
    268         @Override
    269         public boolean updateResources() {
    270             final int rows = getRows();
    271             boolean changed = rows != mMaxRows;
    272             if (changed) {
    273                 mMaxRows = rows;
    274                 requestLayout();
    275             }
    276             return super.updateResources() || changed;
    277         }
    278 
    279         private int getRows() {
    280             final Resources res = getContext().getResources();
    281             if (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
    282                 return res.getInteger(R.integer.quick_settings_num_rows_portrait);
    283             }
    284             return Math.max(1, res.getInteger(R.integer.quick_settings_num_rows));
    285         }
    286 
    287         public void setMaxRows(int maxRows) {
    288             mMaxRows = maxRows;
    289         }
    290 
    291         public boolean isFull() {
    292             return mRecords.size() >= mColumns * mMaxRows;
    293         }
    294     }
    295 
    296     private final PagerAdapter mAdapter = new PagerAdapter() {
    297         public void destroyItem(ViewGroup container, int position, Object object) {
    298             if (DEBUG) Log.d(TAG, "Destantiating " + position);
    299             container.removeView((View) object);
    300         }
    301 
    302         public Object instantiateItem(ViewGroup container, int position) {
    303             if (DEBUG) Log.d(TAG, "Instantiating " + position);
    304             if (isLayoutRtl()) {
    305                 position = mPages.size() - 1 - position;
    306             }
    307             ViewGroup view = mPages.get(position);
    308             container.addView(view);
    309             return view;
    310         }
    311 
    312         @Override
    313         public int getCount() {
    314             return mNumPages;
    315         }
    316 
    317         @Override
    318         public boolean isViewFromObject(View view, Object object) {
    319             return view == object;
    320         }
    321     };
    322 
    323     public interface PageListener {
    324         void onPageChanged(boolean isFirst);
    325     }
    326 }
    327