blob: 115c9d0e06fb5dcf7927304e847079cb204abacb [file] [log] [blame]
Jason Monkcaf37622015-08-18 12:33:50 -04001package com.android.systemui.qs;
2
3import android.content.Context;
Jason Monk51fb85a2016-03-28 14:06:04 -04004import android.support.v4.view.PagerAdapter;
5import android.support.v4.view.ViewPager;
Jason Monkcaf37622015-08-18 12:33:50 -04006import android.util.AttributeSet;
7import android.util.Log;
8import android.view.LayoutInflater;
9import android.view.View;
10import android.view.ViewGroup;
Jason Monkcaf37622015-08-18 12:33:50 -040011import com.android.systemui.R;
12import com.android.systemui.qs.QSPanel.QSTileLayout;
13import com.android.systemui.qs.QSPanel.TileRecord;
14
15import java.util.ArrayList;
16
17public class PagedTileLayout extends ViewPager implements QSTileLayout {
18
19 private static final boolean DEBUG = false;
20
21 private static final String TAG = "PagedTileLayout";
22
23 private final ArrayList<TileRecord> mTiles = new ArrayList<TileRecord>();
24 private final ArrayList<TilePage> mPages = new ArrayList<TilePage>();
25
Jason Monkcaf37622015-08-18 12:33:50 -040026 private PageIndicator mPageIndicator;
27
28 private int mNumPages;
Jason Monk21428432016-02-10 16:42:38 -050029 private View mDecorGroup;
Jason Monk162011e2016-02-19 08:11:55 -050030 private PageListener mPageListener;
Jason Monkcaf37622015-08-18 12:33:50 -040031
32 public PagedTileLayout(Context context, AttributeSet attrs) {
33 super(context, attrs);
34 setAdapter(mAdapter);
35 setOnPageChangeListener(new OnPageChangeListener() {
36 @Override
37 public void onPageSelected(int position) {
38 if (mPageIndicator == null) return;
Jason Monk162011e2016-02-19 08:11:55 -050039 if (mPageListener != null) {
Jason Monk51fb85a2016-03-28 14:06:04 -040040 mPageListener.onPageChanged(isLayoutRtl() ? position == mPages.size() - 1
41 : position == 0);
Jason Monk162011e2016-02-19 08:11:55 -050042 }
Jason Monkcaf37622015-08-18 12:33:50 -040043 }
44
45 @Override
Jason Monk162011e2016-02-19 08:11:55 -050046 public void onPageScrolled(int position, float positionOffset,
47 int positionOffsetPixels) {
Jason Monkcaf37622015-08-18 12:33:50 -040048 if (mPageIndicator == null) return;
49 mPageIndicator.setLocation(position + positionOffset);
Jason Monk66eaf312016-02-25 12:29:29 -050050 if (mPageListener != null) {
Jason Monk51fb85a2016-03-28 14:06:04 -040051 mPageListener.onPageChanged(positionOffsetPixels == 0 &&
52 (isLayoutRtl() ? position == mPages.size() - 1 : position == 0));
Jason Monk66eaf312016-02-25 12:29:29 -050053 }
Jason Monkcaf37622015-08-18 12:33:50 -040054 }
55
56 @Override
57 public void onPageScrollStateChanged(int state) {
58 }
59 });
60 setCurrentItem(0);
61 }
62
63 @Override
Jason Monk51fb85a2016-03-28 14:06:04 -040064 public void onRtlPropertiesChanged(int layoutDirection) {
65 super.onRtlPropertiesChanged(layoutDirection);
66 setAdapter(mAdapter);
67 setCurrentItem(0, false);
68 }
69
70 @Override
71 public void setCurrentItem(int item, boolean smoothScroll) {
72 if (isLayoutRtl()) {
73 item = mPages.size() - 1 - item;
74 }
75 super.setCurrentItem(item, smoothScroll);
76 }
77
78 @Override
Jason Monkc5bdafb2016-02-25 16:24:21 -050079 public boolean hasOverlappingRendering() {
80 return false;
81 }
82
83 @Override
Jason Monkcaf37622015-08-18 12:33:50 -040084 protected void onFinishInflate() {
85 super.onFinishInflate();
86 mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator);
Jason Monk21428432016-02-10 16:42:38 -050087 mDecorGroup = findViewById(R.id.page_decor);
88 ((LayoutParams) mDecorGroup.getLayoutParams()).isDecor = true;
Jason Monkcaf37622015-08-18 12:33:50 -040089
Jason Monke4e69302016-01-20 11:27:15 -050090 mPages.add((TilePage) LayoutInflater.from(mContext)
91 .inflate(R.layout.qs_paged_page, this, false));
Jason Monkcaf37622015-08-18 12:33:50 -040092 }
93
94 @Override
95 public int getOffsetTop(TileRecord tile) {
Jason Monkae5bd032016-03-02 14:38:31 -050096 final ViewGroup parent = (ViewGroup) tile.tileView.getParent();
97 if (parent == null) return 0;
98 return parent.getTop() + getTop();
Jason Monkcaf37622015-08-18 12:33:50 -040099 }
100
101 @Override
Jason Monkcaf37622015-08-18 12:33:50 -0400102 public void addTile(TileRecord tile) {
103 mTiles.add(tile);
Jason Monk9d02a432016-01-20 16:33:46 -0500104 postDistributeTiles();
Jason Monkcaf37622015-08-18 12:33:50 -0400105 }
106
107 @Override
108 public void removeTile(TileRecord tile) {
109 if (mTiles.remove(tile)) {
Jason Monk9d02a432016-01-20 16:33:46 -0500110 postDistributeTiles();
Jason Monkcaf37622015-08-18 12:33:50 -0400111 }
112 }
113
Jason Monk162011e2016-02-19 08:11:55 -0500114 public void setPageListener(PageListener listener) {
115 mPageListener = listener;
116 }
117
Jason Monk9d02a432016-01-20 16:33:46 -0500118 private void postDistributeTiles() {
119 removeCallbacks(mDistribute);
120 post(mDistribute);
121 }
122
Jason Monkcaf37622015-08-18 12:33:50 -0400123 private void distributeTiles() {
124 if (DEBUG) Log.d(TAG, "Distributing tiles");
Jason Monkcaf37622015-08-18 12:33:50 -0400125 final int NP = mPages.size();
126 for (int i = 0; i < NP; i++) {
Jason Monk9d02a432016-01-20 16:33:46 -0500127 mPages.get(i).removeAllViews();
Jason Monkcaf37622015-08-18 12:33:50 -0400128 }
129 int index = 0;
130 final int NT = mTiles.size();
131 for (int i = 0; i < NT; i++) {
132 TileRecord tile = mTiles.get(i);
Jason Monkcaf37622015-08-18 12:33:50 -0400133 if (mPages.get(index).isFull()) {
134 if (++index == mPages.size()) {
135 if (DEBUG) Log.d(TAG, "Adding page for " + tile.tile.getClass().getSimpleName());
136 mPages.add((TilePage) LayoutInflater.from(mContext)
137 .inflate(R.layout.qs_paged_page, this, false));
138 }
139 }
140 if (DEBUG) Log.d(TAG, "Adding " + tile.tile.getClass().getSimpleName() + " to "
141 + index);
142 mPages.get(index).addTile(tile);
143 }
144 if (mNumPages != index + 1) {
145 mNumPages = index + 1;
146 mPageIndicator.setNumPages(mNumPages);
147 mAdapter.notifyDataSetChanged();
Jason Monk51fb85a2016-03-28 14:06:04 -0400148 setCurrentItem(0, false);
Jason Monkcaf37622015-08-18 12:33:50 -0400149 }
150 }
151
152 @Override
Jason Monk9d02a432016-01-20 16:33:46 -0500153 public boolean updateResources() {
154 boolean changed = false;
Jason Monkcaf37622015-08-18 12:33:50 -0400155 for (int i = 0; i < mPages.size(); i++) {
Jason Monk9d02a432016-01-20 16:33:46 -0500156 changed |= mPages.get(i).updateResources();
Jason Monkcaf37622015-08-18 12:33:50 -0400157 }
Jason Monk9d02a432016-01-20 16:33:46 -0500158 if (changed) {
159 distributeTiles();
160 }
161 return changed;
Jason Monkcaf37622015-08-18 12:33:50 -0400162 }
163
164 @Override
165 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
166 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
167 // The ViewPager likes to eat all of the space, instead force it to wrap to the max height
168 // of the pages.
169 int maxHeight = 0;
170 final int N = getChildCount();
171 for (int i = 0; i < N; i++) {
172 int height = getChildAt(i).getMeasuredHeight();
173 if (height > maxHeight) {
174 maxHeight = height;
175 }
176 }
Jason Monk21428432016-02-10 16:42:38 -0500177 setMeasuredDimension(getMeasuredWidth(), maxHeight + mDecorGroup.getMeasuredHeight());
Jason Monkcaf37622015-08-18 12:33:50 -0400178 }
179
Jason Monk9d02a432016-01-20 16:33:46 -0500180 private final Runnable mDistribute = new Runnable() {
181 @Override
182 public void run() {
183 distributeTiles();
184 }
185 };
186
Jason Monk8fb77872016-03-03 16:39:42 -0500187 public int getColumnCount() {
188 if (mPages.size() == 0) return 0;
189 return mPages.get(0).mColumns;
190 }
191
Jason Monkcaf37622015-08-18 12:33:50 -0400192 public static class TilePage extends TileLayout {
Jason Monk94a1bf62015-10-20 08:43:36 -0700193 private int mMaxRows = 3;
Jason Monkcaf37622015-08-18 12:33:50 -0400194
195 public TilePage(Context context, AttributeSet attrs) {
196 super(context, attrs);
Jason Monkb9c00192015-10-07 11:45:33 -0400197 updateResources();
Jason Monkcaf37622015-08-18 12:33:50 -0400198 }
199
Jason Monk9d02a432016-01-20 16:33:46 -0500200 @Override
201 public boolean updateResources() {
202 if (super.updateResources()) {
203 mMaxRows = mColumns != 3 ? 2 : 3;
204 return true;
205 }
206 return false;
207 }
208
Jason Monkbd6dbb02015-09-03 15:46:25 -0400209 public void setMaxRows(int maxRows) {
210 mMaxRows = maxRows;
211 }
212
Jason Monkbd6dbb02015-09-03 15:46:25 -0400213 public boolean isFull() {
Jason Monkcaf37622015-08-18 12:33:50 -0400214 return mRecords.size() >= mColumns * mMaxRows;
215 }
216 }
217
218 private final PagerAdapter mAdapter = new PagerAdapter() {
219 public void destroyItem(ViewGroup container, int position, Object object) {
220 if (DEBUG) Log.d(TAG, "Destantiating " + position);
221 // TODO: Find way to clean up the extra pages.
222 container.removeView((View) object);
223 }
224
225 public Object instantiateItem(ViewGroup container, int position) {
226 if (DEBUG) Log.d(TAG, "Instantiating " + position);
Jason Monk51fb85a2016-03-28 14:06:04 -0400227 if (isLayoutRtl()) {
228 position = mPages.size() - 1 - position;
229 }
Jason Monke4e69302016-01-20 11:27:15 -0500230 ViewGroup view = mPages.get(position);
Jason Monkcaf37622015-08-18 12:33:50 -0400231 container.addView(view);
232 return view;
233 }
234
235 @Override
236 public int getCount() {
237 return mNumPages;
238 }
239
240 @Override
241 public boolean isViewFromObject(View view, Object object) {
242 return view == object;
243 }
244 };
Jason Monk162011e2016-02-19 08:11:55 -0500245
246 public interface PageListener {
Jason Monk66eaf312016-02-25 12:29:29 -0500247 void onPageChanged(boolean isFirst);
Jason Monk162011e2016-02-19 08:11:55 -0500248 }
Jason Monkcaf37622015-08-18 12:33:50 -0400249}