blob: 8ccf60d38650578b521186d3e04d13bbf586fc05 [file] [log] [blame]
Jason Monkcaf37622015-08-18 12:33:50 -04001package com.android.systemui.qs;
2
3import android.content.Context;
4import android.util.AttributeSet;
5import android.util.Log;
6import android.view.LayoutInflater;
7import android.view.View;
8import android.view.ViewGroup;
Jason Monkcaf37622015-08-18 12:33:50 -04009import com.android.internal.widget.PagerAdapter;
10import com.android.internal.widget.ViewPager;
11import 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;
39 mPageIndicator.setLocation(position);
Jason Monk162011e2016-02-19 08:11:55 -050040 if (mPageListener != null) {
Jason Monk66eaf312016-02-25 12:29:29 -050041 mPageListener.onPageChanged(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) {
51 mPageListener.onPageChanged(position == 0 && positionOffsetPixels == 0);
52 }
Jason Monkcaf37622015-08-18 12:33:50 -040053 }
54
55 @Override
56 public void onPageScrollStateChanged(int state) {
57 }
58 });
59 setCurrentItem(0);
60 }
61
62 @Override
Jason Monkc5bdafb2016-02-25 16:24:21 -050063 public boolean hasOverlappingRendering() {
64 return false;
65 }
66
67 @Override
Jason Monkcaf37622015-08-18 12:33:50 -040068 protected void onFinishInflate() {
69 super.onFinishInflate();
70 mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator);
Jason Monk21428432016-02-10 16:42:38 -050071 mDecorGroup = findViewById(R.id.page_decor);
72 ((LayoutParams) mDecorGroup.getLayoutParams()).isDecor = true;
Jason Monkcaf37622015-08-18 12:33:50 -040073
Jason Monke4e69302016-01-20 11:27:15 -050074 mPages.add((TilePage) LayoutInflater.from(mContext)
75 .inflate(R.layout.qs_paged_page, this, false));
Jason Monkcaf37622015-08-18 12:33:50 -040076 }
77
78 @Override
79 public int getOffsetTop(TileRecord tile) {
Jason Monkae5bd032016-03-02 14:38:31 -050080 final ViewGroup parent = (ViewGroup) tile.tileView.getParent();
81 if (parent == null) return 0;
82 return parent.getTop() + getTop();
Jason Monkcaf37622015-08-18 12:33:50 -040083 }
84
85 @Override
Jason Monkcaf37622015-08-18 12:33:50 -040086 public void addTile(TileRecord tile) {
87 mTiles.add(tile);
Jason Monk9d02a432016-01-20 16:33:46 -050088 postDistributeTiles();
Jason Monkcaf37622015-08-18 12:33:50 -040089 }
90
91 @Override
92 public void removeTile(TileRecord tile) {
93 if (mTiles.remove(tile)) {
Jason Monk9d02a432016-01-20 16:33:46 -050094 postDistributeTiles();
Jason Monkcaf37622015-08-18 12:33:50 -040095 }
96 }
97
Jason Monk162011e2016-02-19 08:11:55 -050098 public void setPageListener(PageListener listener) {
99 mPageListener = listener;
100 }
101
Jason Monk9d02a432016-01-20 16:33:46 -0500102 private void postDistributeTiles() {
103 removeCallbacks(mDistribute);
104 post(mDistribute);
105 }
106
Jason Monkcaf37622015-08-18 12:33:50 -0400107 private void distributeTiles() {
108 if (DEBUG) Log.d(TAG, "Distributing tiles");
Jason Monkcaf37622015-08-18 12:33:50 -0400109 final int NP = mPages.size();
110 for (int i = 0; i < NP; i++) {
Jason Monk9d02a432016-01-20 16:33:46 -0500111 mPages.get(i).removeAllViews();
Jason Monkcaf37622015-08-18 12:33:50 -0400112 }
113 int index = 0;
114 final int NT = mTiles.size();
115 for (int i = 0; i < NT; i++) {
116 TileRecord tile = mTiles.get(i);
Jason Monkcaf37622015-08-18 12:33:50 -0400117 if (mPages.get(index).isFull()) {
118 if (++index == mPages.size()) {
119 if (DEBUG) Log.d(TAG, "Adding page for " + tile.tile.getClass().getSimpleName());
120 mPages.add((TilePage) LayoutInflater.from(mContext)
121 .inflate(R.layout.qs_paged_page, this, false));
122 }
123 }
124 if (DEBUG) Log.d(TAG, "Adding " + tile.tile.getClass().getSimpleName() + " to "
125 + index);
126 mPages.get(index).addTile(tile);
127 }
128 if (mNumPages != index + 1) {
129 mNumPages = index + 1;
130 mPageIndicator.setNumPages(mNumPages);
131 mAdapter.notifyDataSetChanged();
132 }
133 }
134
135 @Override
Jason Monk9d02a432016-01-20 16:33:46 -0500136 public boolean updateResources() {
137 boolean changed = false;
Jason Monkcaf37622015-08-18 12:33:50 -0400138 for (int i = 0; i < mPages.size(); i++) {
Jason Monk9d02a432016-01-20 16:33:46 -0500139 changed |= mPages.get(i).updateResources();
Jason Monkcaf37622015-08-18 12:33:50 -0400140 }
Jason Monk9d02a432016-01-20 16:33:46 -0500141 if (changed) {
142 distributeTiles();
143 }
144 return changed;
Jason Monkcaf37622015-08-18 12:33:50 -0400145 }
146
147 @Override
148 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
149 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
150 // The ViewPager likes to eat all of the space, instead force it to wrap to the max height
151 // of the pages.
152 int maxHeight = 0;
153 final int N = getChildCount();
154 for (int i = 0; i < N; i++) {
155 int height = getChildAt(i).getMeasuredHeight();
156 if (height > maxHeight) {
157 maxHeight = height;
158 }
159 }
Jason Monk21428432016-02-10 16:42:38 -0500160 setMeasuredDimension(getMeasuredWidth(), maxHeight + mDecorGroup.getMeasuredHeight());
Jason Monkcaf37622015-08-18 12:33:50 -0400161 }
162
Jason Monk9d02a432016-01-20 16:33:46 -0500163 private final Runnable mDistribute = new Runnable() {
164 @Override
165 public void run() {
166 distributeTiles();
167 }
168 };
169
Jason Monkcaf37622015-08-18 12:33:50 -0400170 public static class TilePage extends TileLayout {
Jason Monk94a1bf62015-10-20 08:43:36 -0700171 private int mMaxRows = 3;
Jason Monkcaf37622015-08-18 12:33:50 -0400172
173 public TilePage(Context context, AttributeSet attrs) {
174 super(context, attrs);
Jason Monkb9c00192015-10-07 11:45:33 -0400175 updateResources();
Jason Monkcaf37622015-08-18 12:33:50 -0400176 }
177
Jason Monk9d02a432016-01-20 16:33:46 -0500178 @Override
179 public boolean updateResources() {
180 if (super.updateResources()) {
181 mMaxRows = mColumns != 3 ? 2 : 3;
182 return true;
183 }
184 return false;
185 }
186
Jason Monkbd6dbb02015-09-03 15:46:25 -0400187 public void setMaxRows(int maxRows) {
188 mMaxRows = maxRows;
189 }
190
Jason Monkbd6dbb02015-09-03 15:46:25 -0400191 public boolean isFull() {
Jason Monkcaf37622015-08-18 12:33:50 -0400192 return mRecords.size() >= mColumns * mMaxRows;
193 }
194 }
195
196 private final PagerAdapter mAdapter = new PagerAdapter() {
197 public void destroyItem(ViewGroup container, int position, Object object) {
198 if (DEBUG) Log.d(TAG, "Destantiating " + position);
199 // TODO: Find way to clean up the extra pages.
200 container.removeView((View) object);
201 }
202
203 public Object instantiateItem(ViewGroup container, int position) {
204 if (DEBUG) Log.d(TAG, "Instantiating " + position);
Jason Monke4e69302016-01-20 11:27:15 -0500205 ViewGroup view = mPages.get(position);
Jason Monkcaf37622015-08-18 12:33:50 -0400206 container.addView(view);
207 return view;
208 }
209
210 @Override
211 public int getCount() {
212 return mNumPages;
213 }
214
215 @Override
216 public boolean isViewFromObject(View view, Object object) {
217 return view == object;
218 }
219 };
Jason Monk162011e2016-02-19 08:11:55 -0500220
221 public interface PageListener {
Jason Monk66eaf312016-02-25 12:29:29 -0500222 void onPageChanged(boolean isFirst);
Jason Monk162011e2016-02-19 08:11:55 -0500223 }
Jason Monkcaf37622015-08-18 12:33:50 -0400224}