• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PagedTileLayout(Context context, AttributeSet attrs)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
onRtlPropertiesChanged(int layoutDirection)72     public void onRtlPropertiesChanged(int layoutDirection) {
73         super.onRtlPropertiesChanged(layoutDirection);
74         setAdapter(mAdapter);
75         setCurrentItem(0, false);
76     }
77 
78     @Override
setCurrentItem(int item, boolean smoothScroll)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
setListening(boolean listening)87     public void setListening(boolean listening) {
88         if (mListening == listening) return;
89         mListening = listening;
90         if (mListening) {
91             mPages.get(mPosition).setListening(listening);
92             if (mOffPage) {
93                 mPages.get(mPosition + 1).setListening(listening);
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      */
setCurrentPage(int position, boolean offPage)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 
setPageListening(int position, boolean listening)132     private void setPageListening(int position, boolean listening) {
133         if (position >= mPages.size()) return;
134         mPages.get(position).setListening(listening);
135     }
136 
137     @Override
hasOverlappingRendering()138     public boolean hasOverlappingRendering() {
139         return false;
140     }
141 
142     @Override
onFinishInflate()143     protected void onFinishInflate() {
144         super.onFinishInflate();
145         mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator);
146         mDecorGroup = findViewById(R.id.page_decor);
147         ((LayoutParams) mDecorGroup.getLayoutParams()).isDecor = true;
148 
149         mPages.add((TilePage) LayoutInflater.from(mContext)
150                 .inflate(R.layout.qs_paged_page, this, false));
151     }
152 
153     @Override
getOffsetTop(TileRecord tile)154     public int getOffsetTop(TileRecord tile) {
155         final ViewGroup parent = (ViewGroup) tile.tileView.getParent();
156         if (parent == null) return 0;
157         return parent.getTop() + getTop();
158     }
159 
160     @Override
addTile(TileRecord tile)161     public void addTile(TileRecord tile) {
162         mTiles.add(tile);
163         postDistributeTiles();
164     }
165 
166     @Override
removeTile(TileRecord tile)167     public void removeTile(TileRecord tile) {
168         if (mTiles.remove(tile)) {
169             postDistributeTiles();
170         }
171     }
172 
setPageListener(PageListener listener)173     public void setPageListener(PageListener listener) {
174         mPageListener = listener;
175     }
176 
postDistributeTiles()177     private void postDistributeTiles() {
178         removeCallbacks(mDistribute);
179         post(mDistribute);
180     }
181 
distributeTiles()182     private void distributeTiles() {
183         if (DEBUG) Log.d(TAG, "Distributing tiles");
184         final int NP = mPages.size();
185         for (int i = 0; i < NP; i++) {
186             mPages.get(i).removeAllViews();
187         }
188         int index = 0;
189         final int NT = mTiles.size();
190         for (int i = 0; i < NT; i++) {
191             TileRecord tile = mTiles.get(i);
192             if (mPages.get(index).isFull()) {
193                 if (++index == mPages.size()) {
194                     if (DEBUG) Log.d(TAG, "Adding page for "
195                             + tile.tile.getClass().getSimpleName());
196                     mPages.add((TilePage) LayoutInflater.from(mContext)
197                             .inflate(R.layout.qs_paged_page, this, false));
198                 }
199             }
200             if (DEBUG) Log.d(TAG, "Adding " + tile.tile.getClass().getSimpleName() + " to "
201                     + index);
202             mPages.get(index).addTile(tile);
203         }
204         if (mNumPages != index + 1) {
205             mNumPages = index + 1;
206             while (mPages.size() > mNumPages) {
207                 mPages.remove(mPages.size() - 1);
208             }
209             if (DEBUG) Log.d(TAG, "Size: " + mNumPages);
210             mPageIndicator.setNumPages(mNumPages);
211             mDecorGroup.setVisibility(mNumPages > 1 ? View.VISIBLE : View.GONE);
212             setAdapter(mAdapter);
213             mAdapter.notifyDataSetChanged();
214             setCurrentItem(0, false);
215         }
216     }
217 
218     @Override
updateResources()219     public boolean updateResources() {
220         boolean changed = false;
221         for (int i = 0; i < mPages.size(); i++) {
222             changed |= mPages.get(i).updateResources();
223         }
224         if (changed) {
225             distributeTiles();
226         }
227         return changed;
228     }
229 
230     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)231     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
232         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
233         // The ViewPager likes to eat all of the space, instead force it to wrap to the max height
234         // of the pages.
235         int maxHeight = 0;
236         final int N = getChildCount();
237         for (int i = 0; i < N; i++) {
238             int height = getChildAt(i).getMeasuredHeight();
239             if (height > maxHeight) {
240                 maxHeight = height;
241             }
242         }
243         setMeasuredDimension(getMeasuredWidth(), maxHeight
244                 + (mDecorGroup.getVisibility() != View.GONE ? mDecorGroup.getMeasuredHeight() : 0));
245     }
246 
247     private final Runnable mDistribute = new Runnable() {
248         @Override
249         public void run() {
250             distributeTiles();
251         }
252     };
253 
getColumnCount()254     public int getColumnCount() {
255         if (mPages.size() == 0) return 0;
256         return mPages.get(0).mColumns;
257     }
258 
259     public static class TilePage extends TileLayout {
260         private int mMaxRows = 3;
261 
TilePage(Context context, AttributeSet attrs)262         public TilePage(Context context, AttributeSet attrs) {
263             super(context, attrs);
264             updateResources();
265             setContentDescription(mContext.getString(R.string.accessibility_desc_quick_settings));
266         }
267 
268         @Override
updateResources()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 
getRows()279         private int getRows() {
280             final Resources res = getContext().getResources();
281             if (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
282                 // Always have 3 rows in portrait.
283                 return 3;
284             }
285             return Math.max(1, res.getInteger(R.integer.quick_settings_num_rows));
286         }
287 
setMaxRows(int maxRows)288         public void setMaxRows(int maxRows) {
289             mMaxRows = maxRows;
290         }
291 
isFull()292         public boolean isFull() {
293             return mRecords.size() >= mColumns * mMaxRows;
294         }
295     }
296 
297     private final PagerAdapter mAdapter = new PagerAdapter() {
298         public void destroyItem(ViewGroup container, int position, Object object) {
299             if (DEBUG) Log.d(TAG, "Destantiating " + position);
300             container.removeView((View) object);
301         }
302 
303         public Object instantiateItem(ViewGroup container, int position) {
304             if (DEBUG) Log.d(TAG, "Instantiating " + position);
305             if (isLayoutRtl()) {
306                 position = mPages.size() - 1 - position;
307             }
308             ViewGroup view = mPages.get(position);
309             container.addView(view);
310             return view;
311         }
312 
313         @Override
314         public int getCount() {
315             return mNumPages;
316         }
317 
318         @Override
319         public boolean isViewFromObject(View view, Object object) {
320             return view == object;
321         }
322     };
323 
324     public interface PageListener {
onPageChanged(boolean isFirst)325         void onPageChanged(boolean isFirst);
326     }
327 }
328