PagedTileLayout.java revision c5bdafb776ae8111da9da8f2b619181e136f1419
1package 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;
9import 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
26    private PageIndicator mPageIndicator;
27
28    private int mNumPages;
29    private View mDecorGroup;
30    private PageListener mPageListener;
31
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);
40                if (mPageListener != null) {
41                    mPageListener.onPageChanged(position == 0);
42                }
43            }
44
45            @Override
46            public void onPageScrolled(int position, float positionOffset,
47                    int positionOffsetPixels) {
48                if (mPageIndicator == null) return;
49                mPageIndicator.setLocation(position + positionOffset);
50                if (mPageListener != null) {
51                    mPageListener.onPageChanged(position == 0 && positionOffsetPixels == 0);
52                }
53            }
54
55            @Override
56            public void onPageScrollStateChanged(int state) {
57            }
58        });
59        setCurrentItem(0);
60    }
61
62    @Override
63    public boolean hasOverlappingRendering() {
64        return false;
65    }
66
67    @Override
68    protected void onFinishInflate() {
69        super.onFinishInflate();
70        mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator);
71        mDecorGroup = findViewById(R.id.page_decor);
72        ((LayoutParams) mDecorGroup.getLayoutParams()).isDecor = true;
73
74        mPages.add((TilePage) LayoutInflater.from(mContext)
75                .inflate(R.layout.qs_paged_page, this, false));
76    }
77
78    @Override
79    public int getOffsetTop(TileRecord tile) {
80        return ((ViewGroup) tile.tileView.getParent()).getTop() + getTop();
81    }
82
83    @Override
84    public void addTile(TileRecord tile) {
85        mTiles.add(tile);
86        postDistributeTiles();
87    }
88
89    @Override
90    public void removeTile(TileRecord tile) {
91        if (mTiles.remove(tile)) {
92            postDistributeTiles();
93        }
94    }
95
96    public void setPageListener(PageListener listener) {
97        mPageListener = listener;
98    }
99
100    private void postDistributeTiles() {
101        removeCallbacks(mDistribute);
102        post(mDistribute);
103    }
104
105    private void distributeTiles() {
106        if (DEBUG) Log.d(TAG, "Distributing tiles");
107        final int NP = mPages.size();
108        for (int i = 0; i < NP; i++) {
109            mPages.get(i).removeAllViews();
110        }
111        int index = 0;
112        final int NT = mTiles.size();
113        for (int i = 0; i < NT; i++) {
114            TileRecord tile = mTiles.get(i);
115            if (mPages.get(index).isFull()) {
116                if (++index == mPages.size()) {
117                    if (DEBUG) Log.d(TAG, "Adding page for " + tile.tile.getClass().getSimpleName());
118                    mPages.add((TilePage) LayoutInflater.from(mContext)
119                            .inflate(R.layout.qs_paged_page, this, false));
120                }
121            }
122            if (DEBUG) Log.d(TAG, "Adding " + tile.tile.getClass().getSimpleName() + " to "
123                    + index);
124            mPages.get(index).addTile(tile);
125        }
126        if (mNumPages != index + 1) {
127            mNumPages = index + 1;
128            mPageIndicator.setNumPages(mNumPages);
129            mAdapter.notifyDataSetChanged();
130        }
131    }
132
133    @Override
134    public boolean updateResources() {
135        boolean changed = false;
136        for (int i = 0; i < mPages.size(); i++) {
137            changed |= mPages.get(i).updateResources();
138        }
139        if (changed) {
140            distributeTiles();
141        }
142        return changed;
143    }
144
145    @Override
146    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
147        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
148        // The ViewPager likes to eat all of the space, instead force it to wrap to the max height
149        // of the pages.
150        int maxHeight = 0;
151        final int N = getChildCount();
152        for (int i = 0; i < N; i++) {
153            int height = getChildAt(i).getMeasuredHeight();
154            if (height > maxHeight) {
155                maxHeight = height;
156            }
157        }
158        setMeasuredDimension(getMeasuredWidth(), maxHeight + mDecorGroup.getMeasuredHeight());
159    }
160
161    private final Runnable mDistribute = new Runnable() {
162        @Override
163        public void run() {
164            distributeTiles();
165        }
166    };
167
168    public static class TilePage extends TileLayout {
169        private int mMaxRows = 3;
170
171        public TilePage(Context context, AttributeSet attrs) {
172            super(context, attrs);
173            updateResources();
174        }
175
176        @Override
177        public boolean updateResources() {
178            if (super.updateResources()) {
179                mMaxRows = mColumns != 3 ? 2 : 3;
180                return true;
181            }
182            return false;
183        }
184
185        public void setMaxRows(int maxRows) {
186            mMaxRows = maxRows;
187        }
188
189        public boolean isFull() {
190            return mRecords.size() >= mColumns * mMaxRows;
191        }
192    }
193
194    private final PagerAdapter mAdapter = new PagerAdapter() {
195        public void destroyItem(ViewGroup container, int position, Object object) {
196            if (DEBUG) Log.d(TAG, "Destantiating " + position);
197            // TODO: Find way to clean up the extra pages.
198            container.removeView((View) object);
199        }
200
201        public Object instantiateItem(ViewGroup container, int position) {
202            if (DEBUG) Log.d(TAG, "Instantiating " + position);
203            ViewGroup view = mPages.get(position);
204            container.addView(view);
205            return view;
206        }
207
208        @Override
209        public int getCount() {
210            return mNumPages;
211        }
212
213        @Override
214        public boolean isViewFromObject(View view, Object object) {
215            return view == object;
216        }
217    };
218
219    public interface PageListener {
220        void onPageChanged(boolean isFirst);
221    }
222}
223