1 package com.android.systemui.qs;
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 import com.android.systemui.R;
14 import com.android.systemui.qs.QSPanel.QSTileLayout;
15 import com.android.systemui.qs.QSPanel.TileRecord;
17 import java.util.ArrayList;
19 public class PagedTileLayout extends ViewPager implements QSTileLayout {
21 private static final boolean DEBUG = false;
23 private static final String TAG = "PagedTileLayout";
25 private final ArrayList<TileRecord> mTiles = new ArrayList<TileRecord>();
26 private final ArrayList<TilePage> mPages = new ArrayList<TilePage>();
28 private PageIndicator mPageIndicator;
30 private int mNumPages;
31 private View mDecorGroup;
32 private PageListener mPageListener;
34 private int mPosition;
35 private boolean mOffPage;
36 private boolean mListening;
38 public PagedTileLayout(Context context, AttributeSet attrs) {
39 super(context, attrs);
41 setOnPageChangeListener(new OnPageChangeListener() {
43 public void onPageSelected(int position) {
44 if (mPageIndicator == null) return;
45 if (mPageListener != null) {
46 mPageListener.onPageChanged(isLayoutRtl() ? position == mPages.size() - 1
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));
64 public void onPageScrollStateChanged(int state) {
71 public void onRtlPropertiesChanged(int layoutDirection) {
72 super.onRtlPropertiesChanged(layoutDirection);
74 setCurrentItem(0, false);
78 public void setCurrentItem(int item, boolean smoothScroll) {
80 item = mPages.size() - 1 - item;
82 super.setCurrentItem(item, smoothScroll);
86 public void setListening(boolean listening) {
87 if (mListening == listening) return;
88 mListening = listening;
90 mPages.get(mPosition).setListening(listening);
92 mPages.get(mPosition + 1).setListening(listening);
95 // Make sure no pages are listening.
96 for (int i = 0; i < mPages.size(); i++) {
97 mPages.get(i).setListening(false);
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
107 private void setCurrentPage(int position, boolean offPage) {
108 if (mPosition == position && mOffPage == offPage) return;
110 if (mPosition != position) {
111 // Clear out the last pages from listening.
112 setPageListening(mPosition, false);
114 setPageListening(mPosition + 1, false);
116 // Set the new pages to listening
117 setPageListening(position, true);
119 setPageListening(position + 1, true);
121 } else if (mOffPage != offPage) {
122 // Whether we are showing position + 1 has changed.
123 setPageListening(mPosition + 1, offPage);
126 // Save the current state.
127 mPosition = position;
131 private void setPageListening(int position, boolean listening) {
132 if (position >= mPages.size()) return;
133 mPages.get(position).setListening(listening);
137 public boolean hasOverlappingRendering() {
142 protected void onFinishInflate() {
143 super.onFinishInflate();
144 mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator);
145 mDecorGroup = findViewById(R.id.page_decor);
146 ((LayoutParams) mDecorGroup.getLayoutParams()).isDecor = true;
148 mPages.add((TilePage) LayoutInflater.from(mContext)
149 .inflate(R.layout.qs_paged_page, this, false));
153 public int getOffsetTop(TileRecord tile) {
154 final ViewGroup parent = (ViewGroup) tile.tileView.getParent();
155 if (parent == null) return 0;
156 return parent.getTop() + getTop();
160 public void addTile(TileRecord tile) {
162 postDistributeTiles();
166 public void removeTile(TileRecord tile) {
167 if (mTiles.remove(tile)) {
168 postDistributeTiles();
172 public void setPageListener(PageListener listener) {
173 mPageListener = listener;
176 private void postDistributeTiles() {
177 removeCallbacks(mDistribute);
181 private void distributeTiles() {
182 if (DEBUG) Log.d(TAG, "Distributing tiles");
183 final int NP = mPages.size();
184 for (int i = 0; i < NP; i++) {
185 mPages.get(i).removeAllViews();
188 final int NT = mTiles.size();
189 for (int i = 0; i < NT; i++) {
190 TileRecord tile = mTiles.get(i);
191 if (mPages.get(index).isFull()) {
192 if (++index == mPages.size()) {
193 if (DEBUG) Log.d(TAG, "Adding page for "
194 + tile.tile.getClass().getSimpleName());
195 mPages.add((TilePage) LayoutInflater.from(mContext)
196 .inflate(R.layout.qs_paged_page, this, false));
199 if (DEBUG) Log.d(TAG, "Adding " + tile.tile.getClass().getSimpleName() + " to "
201 mPages.get(index).addTile(tile);
203 if (mNumPages != index + 1) {
204 mNumPages = index + 1;
205 while (mPages.size() > mNumPages) {
206 mPages.remove(mPages.size() - 1);
208 if (DEBUG) Log.d(TAG, "Size: " + mNumPages);
209 mPageIndicator.setNumPages(mNumPages);
210 setAdapter(mAdapter);
211 mAdapter.notifyDataSetChanged();
212 setCurrentItem(0, false);
217 public boolean updateResources() {
218 boolean changed = false;
219 for (int i = 0; i < mPages.size(); i++) {
220 changed |= mPages.get(i).updateResources();
229 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
230 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
231 // The ViewPager likes to eat all of the space, instead force it to wrap to the max height
234 final int N = getChildCount();
235 for (int i = 0; i < N; i++) {
236 int height = getChildAt(i).getMeasuredHeight();
237 if (height > maxHeight) {
241 setMeasuredDimension(getMeasuredWidth(), maxHeight + mDecorGroup.getMeasuredHeight());
244 private final Runnable mDistribute = new Runnable() {
251 public int getColumnCount() {
252 if (mPages.size() == 0) return 0;
253 return mPages.get(0).mColumns;
256 public static class TilePage extends TileLayout {
257 private int mMaxRows = 3;
259 public TilePage(Context context, AttributeSet attrs) {
260 super(context, attrs);
262 setContentDescription(mContext.getString(R.string.accessibility_desc_quick_settings));
266 public boolean updateResources() {
267 final int rows = getRows();
268 boolean changed = rows != mMaxRows;
273 return super.updateResources() || changed;
276 private int getRows() {
277 final Resources res = getContext().getResources();
278 if (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
279 // Always have 3 rows in portrait.
282 return Math.max(1, res.getInteger(R.integer.quick_settings_num_rows));
285 public void setMaxRows(int maxRows) {
289 public boolean isFull() {
290 return mRecords.size() >= mColumns * mMaxRows;
294 private final PagerAdapter mAdapter = new PagerAdapter() {
295 public void destroyItem(ViewGroup container, int position, Object object) {
296 if (DEBUG) Log.d(TAG, "Destantiating " + position);
297 container.removeView((View) object);
300 public Object instantiateItem(ViewGroup container, int position) {
301 if (DEBUG) Log.d(TAG, "Instantiating " + position);
303 position = mPages.size() - 1 - position;
305 ViewGroup view = mPages.get(position);
306 container.addView(view);
311 public int getCount() {
316 public boolean isViewFromObject(View view, Object object) {
317 return view == object;
321 public interface PageListener {
322 void onPageChanged(boolean isFirst);