diff options
Diffstat (limited to 'packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java')
-rw-r--r-- | packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java new file mode 100644 index 0000000..d58663d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.qs; + +import com.android.systemui.R; + +import android.content.Context; +import android.content.res.TypedArray; +import android.database.DataSetObserver; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + +import java.lang.ref.WeakReference; + +/** + * A view that arranges it's children in a grid with a fixed number of evenly spaced columns. + * + * {@see android.widget.GridView} + */ +public class PseudoGridView extends ViewGroup { + + private int mNumColumns = 3; + private int mVerticalSpacing; + private int mHorizontalSpacing; + + public PseudoGridView(Context context, AttributeSet attrs) { + super(context, attrs); + + final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PseudoGridView); + + final int N = a.getIndexCount(); + for (int i = 0; i < N; i++) { + int attr = a.getIndex(i); + switch (attr) { + case R.styleable.PseudoGridView_numColumns: + mNumColumns = a.getInt(attr, 3); + break; + case R.styleable.PseudoGridView_verticalSpacing: + mVerticalSpacing = a.getDimensionPixelSize(attr, 0); + break; + case R.styleable.PseudoGridView_horizontalSpacing: + mHorizontalSpacing = a.getDimensionPixelSize(attr, 0); + break; + } + } + + a.recycle(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + if (widthMode == MeasureSpec.UNSPECIFIED) { + throw new UnsupportedOperationException("Needs a maximum width"); + } + int width = MeasureSpec.getSize(widthMeasureSpec); + + int childWidth = (width - (mNumColumns - 1) * mHorizontalSpacing) / mNumColumns; + int childWidthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY); + int childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + int totalHeight = 0; + int children = getChildCount(); + int rows = (children + mNumColumns - 1) / mNumColumns; + for (int row = 0; row < rows; row++) { + int startOfRow = row * mNumColumns; + int endOfRow = Math.min(startOfRow + mNumColumns, children); + int maxHeight = 0; + for (int i = startOfRow; i < endOfRow; i++) { + View child = getChildAt(i); + child.measure(childWidthSpec, childHeightSpec); + maxHeight = Math.max(maxHeight, child.getMeasuredHeight()); + } + int maxHeightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY); + for (int i = startOfRow; i < endOfRow; i++) { + View child = getChildAt(i); + child.measure(childWidthSpec, maxHeightSpec); + } + totalHeight += maxHeight; + if (row > 0) { + totalHeight += mVerticalSpacing; + } + } + + setMeasuredDimension(width, getDefaultSize(totalHeight, heightMeasureSpec)); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + int children = getChildCount(); + int rows = (children + mNumColumns - 1) / mNumColumns; + int y = 0; + for (int row = 0; row < rows; row++) { + int x = 0; + int maxHeight = 0; + int startOfRow = row * mNumColumns; + int endOfRow = Math.min(startOfRow + mNumColumns, children); + for (int i = startOfRow; i < endOfRow; i++) { + View child = getChildAt(i); + int width = child.getMeasuredWidth(); + int height = child.getMeasuredHeight(); + child.layout(x, y, x + width, y + height); + maxHeight = Math.max(maxHeight, height); + x += width + mHorizontalSpacing; + } + y += maxHeight; + if (row > 0) { + y += mVerticalSpacing; + } + } + } + + /** + * Bridges between a ViewGroup and a BaseAdapter. + * <p> + * Usage: {@code ViewGroupAdapterBridge.link(viewGroup, adapter)} + * <br /> + * After this call, the ViewGroup's children will be provided by the adapter. + */ + public static class ViewGroupAdapterBridge extends DataSetObserver { + + private final WeakReference<ViewGroup> mViewGroup; + private final BaseAdapter mAdapter; + private boolean mReleased; + + public static void link(ViewGroup viewGroup, BaseAdapter adapter) { + new ViewGroupAdapterBridge(viewGroup, adapter); + } + + private ViewGroupAdapterBridge(ViewGroup viewGroup, BaseAdapter adapter) { + mViewGroup = new WeakReference<>(viewGroup); + mAdapter = adapter; + mReleased = false; + mAdapter.registerDataSetObserver(this); + refresh(); + } + + private void refresh() { + if (mReleased) { + return; + } + ViewGroup viewGroup = mViewGroup.get(); + if (viewGroup == null) { + release(); + return; + } + final int childCount = viewGroup.getChildCount(); + final int adapterCount = mAdapter.getCount(); + final int N = Math.max(childCount, adapterCount); + for (int i = 0; i < N; i++) { + if (i < adapterCount) { + View oldView = null; + if (i < childCount) { + oldView = viewGroup.getChildAt(i); + } + View newView = mAdapter.getView(i, oldView, viewGroup); + if (oldView == null) { + // We ran out of existing views. Add it at the end. + viewGroup.addView(newView); + } else if (oldView != newView) { + // We couldn't rebind the view. Replace it. + viewGroup.removeViewAt(i); + viewGroup.addView(newView, i); + } + } else { + int lastIndex = viewGroup.getChildCount() - 1; + viewGroup.removeViewAt(lastIndex); + } + } + } + + @Override + public void onChanged() { + refresh(); + } + + @Override + public void onInvalidated() { + release(); + } + + private void release() { + if (!mReleased) { + mReleased = true; + mAdapter.unregisterDataSetObserver(this); + } + } + } +} |