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