summaryrefslogtreecommitdiffstats
path: root/src/com/android/photos/views/GalleryThumbnailView.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/photos/views/GalleryThumbnailView.java')
-rw-r--r--src/com/android/photos/views/GalleryThumbnailView.java883
1 files changed, 0 insertions, 883 deletions
diff --git a/src/com/android/photos/views/GalleryThumbnailView.java b/src/com/android/photos/views/GalleryThumbnailView.java
deleted file mode 100644
index e5dd6f2ff..000000000
--- a/src/com/android/photos/views/GalleryThumbnailView.java
+++ /dev/null
@@ -1,883 +0,0 @@
-/*
- * Copyright (C) 2013 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.photos.views;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.database.DataSetObserver;
-import android.graphics.Canvas;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v4.view.VelocityTrackerCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.widget.EdgeEffectCompat;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.widget.ListAdapter;
-import android.widget.OverScroller;
-
-import java.util.ArrayList;
-
-public class GalleryThumbnailView extends ViewGroup {
-
- public interface GalleryThumbnailAdapter extends ListAdapter {
- /**
- * @param position Position to get the intrinsic aspect ratio for
- * @return width / height
- */
- float getIntrinsicAspectRatio(int position);
- }
-
- private static final String TAG = "GalleryThumbnailView";
- private static final float ASPECT_RATIO = (float) Math.sqrt(1.5f);
- private static final int LAND_UNITS = 2;
- private static final int PORT_UNITS = 3;
-
- private GalleryThumbnailAdapter mAdapter;
-
- private final RecycleBin mRecycler = new RecycleBin();
-
- private final AdapterDataSetObserver mObserver = new AdapterDataSetObserver();
-
- private boolean mDataChanged;
- private int mOldItemCount;
- private int mItemCount;
- private boolean mHasStableIds;
-
- private int mFirstPosition;
-
- private boolean mPopulating;
- private boolean mInLayout;
-
- private int mTouchSlop;
- private int mMaximumVelocity;
- private int mFlingVelocity;
- private float mLastTouchX;
- private float mTouchRemainderX;
- private int mActivePointerId;
-
- private static final int TOUCH_MODE_IDLE = 0;
- private static final int TOUCH_MODE_DRAGGING = 1;
- private static final int TOUCH_MODE_FLINGING = 2;
-
- private int mTouchMode;
- private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
- private final OverScroller mScroller;
-
- private final EdgeEffectCompat mLeftEdge;
- private final EdgeEffectCompat mRightEdge;
-
- private int mLargeColumnWidth;
- private int mSmallColumnWidth;
- private int mLargeColumnUnitCount = 8;
- private int mSmallColumnUnitCount = 10;
-
- public GalleryThumbnailView(Context context) {
- this(context, null);
- }
-
- public GalleryThumbnailView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public GalleryThumbnailView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- final ViewConfiguration vc = ViewConfiguration.get(context);
- mTouchSlop = vc.getScaledTouchSlop();
- mMaximumVelocity = vc.getScaledMaximumFlingVelocity();
- mFlingVelocity = vc.getScaledMinimumFlingVelocity();
- mScroller = new OverScroller(context);
-
- mLeftEdge = new EdgeEffectCompat(context);
- mRightEdge = new EdgeEffectCompat(context);
- setWillNotDraw(false);
- setClipToPadding(false);
- }
-
- @Override
- public void requestLayout() {
- if (!mPopulating) {
- super.requestLayout();
- }
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-
- if (widthMode != MeasureSpec.EXACTLY) {
- Log.e(TAG, "onMeasure: must have an exact width or match_parent! " +
- "Using fallback spec of EXACTLY " + widthSize);
- }
- if (heightMode != MeasureSpec.EXACTLY) {
- Log.e(TAG, "onMeasure: must have an exact height or match_parent! " +
- "Using fallback spec of EXACTLY " + heightSize);
- }
-
- setMeasuredDimension(widthSize, heightSize);
-
- float portSpaces = mLargeColumnUnitCount / PORT_UNITS;
- float height = getMeasuredHeight() / portSpaces;
- mLargeColumnWidth = (int) (height / ASPECT_RATIO);
- portSpaces++;
- height = getMeasuredHeight() / portSpaces;
- mSmallColumnWidth = (int) (height / ASPECT_RATIO);
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- mInLayout = true;
- populate();
- mInLayout = false;
-
- final int width = r - l;
- final int height = b - t;
- mLeftEdge.setSize(width, height);
- mRightEdge.setSize(width, height);
- }
-
- private void populate() {
- if (getWidth() == 0 || getHeight() == 0) {
- return;
- }
-
- // TODO: Handle size changing
-// final int colCount = mColCount;
-// if (mItemTops == null || mItemTops.length != colCount) {
-// mItemTops = new int[colCount];
-// mItemBottoms = new int[colCount];
-// final int top = getPaddingTop();
-// final int offset = top + Math.min(mRestoreOffset, 0);
-// Arrays.fill(mItemTops, offset);
-// Arrays.fill(mItemBottoms, offset);
-// mLayoutRecords.clear();
-// if (mInLayout) {
-// removeAllViewsInLayout();
-// } else {
-// removeAllViews();
-// }
-// mRestoreOffset = 0;
-// }
-
- mPopulating = true;
- layoutChildren(mDataChanged);
- fillRight(mFirstPosition + getChildCount(), 0);
- fillLeft(mFirstPosition - 1, 0);
- mPopulating = false;
- mDataChanged = false;
- }
-
- final void layoutChildren(boolean queryAdapter) {
-// TODO
-// final int childCount = getChildCount();
-// for (int i = 0; i < childCount; i++) {
-// View child = getChildAt(i);
-//
-// if (child.isLayoutRequested()) {
-// final int widthSpec = MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(), MeasureSpec.EXACTLY);
-// final int heightSpec = MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(), MeasureSpec.EXACTLY);
-// child.measure(widthSpec, heightSpec);
-// child.layout(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
-// }
-//
-// int childTop = mItemBottoms[col] > Integer.MIN_VALUE ?
-// mItemBottoms[col] + mItemMargin : child.getTop();
-// if (span > 1) {
-// int lowest = childTop;
-// for (int j = col + 1; j < col + span; j++) {
-// final int bottom = mItemBottoms[j] + mItemMargin;
-// if (bottom > lowest) {
-// lowest = bottom;
-// }
-// }
-// childTop = lowest;
-// }
-// final int childHeight = child.getMeasuredHeight();
-// final int childBottom = childTop + childHeight;
-// final int childLeft = paddingLeft + col * (colWidth + itemMargin);
-// final int childRight = childLeft + child.getMeasuredWidth();
-// child.layout(childLeft, childTop, childRight, childBottom);
-// }
- }
-
- /**
- * Obtain the view and add it to our list of children. The view can be made
- * fresh, converted from an unused view, or used as is if it was in the
- * recycle bin.
- *
- * @param startPosition Logical position in the list to start from
- * @param x Left or right edge of the view to add
- * @param forward If true, align left edge to x and increase position.
- * If false, align right edge to x and decrease position.
- * @return Number of views added
- */
- private int makeAndAddColumn(int startPosition, int x, boolean forward) {
- int columnWidth = mLargeColumnWidth;
- int addViews = 0;
- for (int remaining = mLargeColumnUnitCount, i = 0;
- remaining > 0 && startPosition + i >= 0 && startPosition + i < mItemCount;
- i += forward ? 1 : -1, addViews++) {
- if (mAdapter.getIntrinsicAspectRatio(startPosition + i) >= 1f) {
- // landscape
- remaining -= LAND_UNITS;
- } else {
- // portrait
- remaining -= PORT_UNITS;
- if (remaining < 0) {
- remaining += (mSmallColumnUnitCount - mLargeColumnUnitCount);
- columnWidth = mSmallColumnWidth;
- }
- }
- }
- int nextTop = 0;
- for (int i = 0; i < addViews; i++) {
- int position = startPosition + (forward ? i : -i);
- View child = obtainView(position, null);
- if (child.getParent() != this) {
- if (mInLayout) {
- addViewInLayout(child, forward ? -1 : 0, child.getLayoutParams());
- } else {
- addView(child, forward ? -1 : 0);
- }
- }
- int heightSize = (int) (.5f + (mAdapter.getIntrinsicAspectRatio(position) >= 1f
- ? columnWidth / ASPECT_RATIO
- : columnWidth * ASPECT_RATIO));
- int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
- int widthSpec = MeasureSpec.makeMeasureSpec(columnWidth, MeasureSpec.EXACTLY);
- child.measure(widthSpec, heightSpec);
- int childLeft = forward ? x : x - columnWidth;
- child.layout(childLeft, nextTop, childLeft + columnWidth, nextTop + heightSize);
- nextTop += heightSize;
- }
- return addViews;
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- mVelocityTracker.addMovement(ev);
- final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- mVelocityTracker.clear();
- mScroller.abortAnimation();
- mLastTouchX = ev.getX();
- mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
- mTouchRemainderX = 0;
- if (mTouchMode == TOUCH_MODE_FLINGING) {
- // Catch!
- mTouchMode = TOUCH_MODE_DRAGGING;
- return true;
- }
- break;
-
- case MotionEvent.ACTION_MOVE: {
- final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
- if (index < 0) {
- Log.e(TAG, "onInterceptTouchEvent could not find pointer with id " +
- mActivePointerId + " - did StaggeredGridView receive an inconsistent " +
- "event stream?");
- return false;
- }
- final float x = MotionEventCompat.getX(ev, index);
- final float dx = x - mLastTouchX + mTouchRemainderX;
- final int deltaY = (int) dx;
- mTouchRemainderX = dx - deltaY;
-
- if (Math.abs(dx) > mTouchSlop) {
- mTouchMode = TOUCH_MODE_DRAGGING;
- return true;
- }
- }
- }
-
- return false;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- mVelocityTracker.addMovement(ev);
- final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- mVelocityTracker.clear();
- mScroller.abortAnimation();
- mLastTouchX = ev.getX();
- mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
- mTouchRemainderX = 0;
- break;
-
- case MotionEvent.ACTION_MOVE: {
- final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
- if (index < 0) {
- Log.e(TAG, "onInterceptTouchEvent could not find pointer with id " +
- mActivePointerId + " - did StaggeredGridView receive an inconsistent " +
- "event stream?");
- return false;
- }
- final float x = MotionEventCompat.getX(ev, index);
- final float dx = x - mLastTouchX + mTouchRemainderX;
- final int deltaX = (int) dx;
- mTouchRemainderX = dx - deltaX;
-
- if (Math.abs(dx) > mTouchSlop) {
- mTouchMode = TOUCH_MODE_DRAGGING;
- }
-
- if (mTouchMode == TOUCH_MODE_DRAGGING) {
- mLastTouchX = x;
-
- if (!trackMotionScroll(deltaX, true)) {
- // Break fling velocity if we impacted an edge.
- mVelocityTracker.clear();
- }
- }
- } break;
-
- case MotionEvent.ACTION_CANCEL:
- mTouchMode = TOUCH_MODE_IDLE;
- break;
-
- case MotionEvent.ACTION_UP: {
- mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
- final float velocity = VelocityTrackerCompat.getXVelocity(mVelocityTracker,
- mActivePointerId);
- if (Math.abs(velocity) > mFlingVelocity) { // TODO
- mTouchMode = TOUCH_MODE_FLINGING;
- mScroller.fling(0, 0, (int) velocity, 0,
- Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0);
- mLastTouchX = 0;
- ViewCompat.postInvalidateOnAnimation(this);
- } else {
- mTouchMode = TOUCH_MODE_IDLE;
- }
-
- } break;
- }
- return true;
- }
-
- /**
- *
- * @param deltaX Pixels that content should move by
- * @return true if the movement completed, false if it was stopped prematurely.
- */
- private boolean trackMotionScroll(int deltaX, boolean allowOverScroll) {
- final boolean contentFits = contentFits();
- final int allowOverhang = Math.abs(deltaX);
-
- final int overScrolledBy;
- final int movedBy;
- if (!contentFits) {
- final int overhang;
- final boolean up;
- mPopulating = true;
- if (deltaX > 0) {
- overhang = fillLeft(mFirstPosition - 1, allowOverhang);
- up = true;
- } else {
- overhang = fillRight(mFirstPosition + getChildCount(), allowOverhang);
- up = false;
- }
- movedBy = Math.min(overhang, allowOverhang);
- offsetChildren(up ? movedBy : -movedBy);
- recycleOffscreenViews();
- mPopulating = false;
- overScrolledBy = allowOverhang - overhang;
- } else {
- overScrolledBy = allowOverhang;
- movedBy = 0;
- }
-
- if (allowOverScroll) {
- final int overScrollMode = ViewCompat.getOverScrollMode(this);
-
- if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS ||
- (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && !contentFits)) {
-
- if (overScrolledBy > 0) {
- EdgeEffectCompat edge = deltaX > 0 ? mLeftEdge : mRightEdge;
- edge.onPull((float) Math.abs(deltaX) / getWidth());
- ViewCompat.postInvalidateOnAnimation(this);
- }
- }
- }
-
- return deltaX == 0 || movedBy != 0;
- }
-
- /**
- * Important: this method will leave offscreen views attached if they
- * are required to maintain the invariant that child view with index i
- * is always the view corresponding to position mFirstPosition + i.
- */
- private void recycleOffscreenViews() {
- final int height = getHeight();
- final int clearAbove = 0;
- final int clearBelow = height;
- for (int i = getChildCount() - 1; i >= 0; i--) {
- final View child = getChildAt(i);
- if (child.getTop() <= clearBelow) {
- // There may be other offscreen views, but we need to maintain
- // the invariant documented above.
- break;
- }
-
- if (mInLayout) {
- removeViewsInLayout(i, 1);
- } else {
- removeViewAt(i);
- }
-
- mRecycler.addScrap(child);
- }
-
- while (getChildCount() > 0) {
- final View child = getChildAt(0);
- if (child.getBottom() >= clearAbove) {
- // There may be other offscreen views, but we need to maintain
- // the invariant documented above.
- break;
- }
-
- if (mInLayout) {
- removeViewsInLayout(0, 1);
- } else {
- removeViewAt(0);
- }
-
- mRecycler.addScrap(child);
- mFirstPosition++;
- }
- }
-
- final void offsetChildren(int offset) {
- final int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- final View child = getChildAt(i);
- child.layout(child.getLeft() + offset, child.getTop(),
- child.getRight() + offset, child.getBottom());
- }
- }
-
- private boolean contentFits() {
- final int childCount = getChildCount();
- if (childCount == 0) return true;
- if (childCount != mItemCount) return false;
-
- return getChildAt(0).getLeft() >= getPaddingLeft() &&
- getChildAt(childCount - 1).getRight() <= getWidth() - getPaddingRight();
- }
-
- private void recycleAllViews() {
- for (int i = 0; i < getChildCount(); i++) {
- mRecycler.addScrap(getChildAt(i));
- }
-
- if (mInLayout) {
- removeAllViewsInLayout();
- } else {
- removeAllViews();
- }
- }
-
- private int fillRight(int pos, int overhang) {
- int end = (getRight() - getLeft()) + overhang;
-
- int nextLeft = getChildCount() == 0 ? 0 : getChildAt(getChildCount() - 1).getRight();
- while (nextLeft < end && pos < mItemCount) {
- pos += makeAndAddColumn(pos, nextLeft, true);
- nextLeft = getChildAt(getChildCount() - 1).getRight();
- }
- final int gridRight = getWidth() - getPaddingRight();
- return getChildAt(getChildCount() - 1).getRight() - gridRight;
- }
-
- private int fillLeft(int pos, int overhang) {
- int end = getPaddingLeft() - overhang;
-
- int nextRight = getChildAt(0).getLeft();
- while (nextRight > end && pos >= 0) {
- pos -= makeAndAddColumn(pos, nextRight, false);
- nextRight = getChildAt(0).getLeft();
- }
-
- mFirstPosition = pos + 1;
- return getPaddingLeft() - getChildAt(0).getLeft();
- }
-
- @Override
- public void computeScroll() {
- if (mScroller.computeScrollOffset()) {
- final int x = mScroller.getCurrX();
- final int dx = (int) (x - mLastTouchX);
- mLastTouchX = x;
- final boolean stopped = !trackMotionScroll(dx, false);
-
- if (!stopped && !mScroller.isFinished()) {
- ViewCompat.postInvalidateOnAnimation(this);
- } else {
- if (stopped) {
- final int overScrollMode = ViewCompat.getOverScrollMode(this);
- if (overScrollMode != ViewCompat.OVER_SCROLL_NEVER) {
- final EdgeEffectCompat edge;
- if (dx > 0) {
- edge = mLeftEdge;
- } else {
- edge = mRightEdge;
- }
- edge.onAbsorb(Math.abs((int) mScroller.getCurrVelocity()));
- ViewCompat.postInvalidateOnAnimation(this);
- }
- mScroller.abortAnimation();
- }
- mTouchMode = TOUCH_MODE_IDLE;
- }
- }
- }
-
- @Override
- public void draw(Canvas canvas) {
- super.draw(canvas);
-
- if (!mLeftEdge.isFinished()) {
- final int restoreCount = canvas.save();
- final int height = getHeight() - getPaddingTop() - getPaddingBottom();
-
- canvas.rotate(270);
- canvas.translate(-height + getPaddingTop(), 0);
- mLeftEdge.setSize(height, getWidth());
- if (mLeftEdge.draw(canvas)) {
- postInvalidateOnAnimation();
- }
- canvas.restoreToCount(restoreCount);
- }
- if (!mRightEdge.isFinished()) {
- final int restoreCount = canvas.save();
- final int width = getWidth();
- final int height = getHeight() - getPaddingTop() - getPaddingBottom();
-
- canvas.rotate(90);
- canvas.translate(-getPaddingTop(), width);
- mRightEdge.setSize(height, width);
- if (mRightEdge.draw(canvas)) {
- postInvalidateOnAnimation();
- }
- canvas.restoreToCount(restoreCount);
- }
- }
-
- /**
- * Obtain a populated view from the adapter. If optScrap is non-null and is not
- * reused it will be placed in the recycle bin.
- *
- * @param position position to get view for
- * @param optScrap Optional scrap view; will be reused if possible
- * @return A new view, a recycled view from mRecycler, or optScrap
- */
- private final View obtainView(int position, View optScrap) {
- View view = mRecycler.getTransientStateView(position);
- if (view != null) {
- return view;
- }
-
- // Reuse optScrap if it's of the right type (and not null)
- final int optType = optScrap != null ?
- ((LayoutParams) optScrap.getLayoutParams()).viewType : -1;
- final int positionViewType = mAdapter.getItemViewType(position);
- final View scrap = optType == positionViewType ?
- optScrap : mRecycler.getScrapView(positionViewType);
-
- view = mAdapter.getView(position, scrap, this);
-
- if (view != scrap && scrap != null) {
- // The adapter didn't use it; put it back.
- mRecycler.addScrap(scrap);
- }
-
- ViewGroup.LayoutParams lp = view.getLayoutParams();
-
- if (view.getParent() != this) {
- if (lp == null) {
- lp = generateDefaultLayoutParams();
- } else if (!checkLayoutParams(lp)) {
- lp = generateLayoutParams(lp);
- }
- view.setLayoutParams(lp);
- }
-
- final LayoutParams sglp = (LayoutParams) lp;
- sglp.position = position;
- sglp.viewType = positionViewType;
-
- return view;
- }
-
- public GalleryThumbnailAdapter getAdapter() {
- return mAdapter;
- }
-
- public void setAdapter(GalleryThumbnailAdapter adapter) {
- if (mAdapter != null) {
- mAdapter.unregisterDataSetObserver(mObserver);
- }
- // TODO: If the new adapter says that there are stable IDs, remove certain layout records
- // and onscreen views if they have changed instead of removing all of the state here.
- clearAllState();
- mAdapter = adapter;
- mDataChanged = true;
- mOldItemCount = mItemCount = adapter != null ? adapter.getCount() : 0;
- if (adapter != null) {
- adapter.registerDataSetObserver(mObserver);
- mRecycler.setViewTypeCount(adapter.getViewTypeCount());
- mHasStableIds = adapter.hasStableIds();
- } else {
- mHasStableIds = false;
- }
- populate();
- }
-
- /**
- * Clear all state because the grid will be used for a completely different set of data.
- */
- private void clearAllState() {
- // Clear all layout records and views
- removeAllViews();
-
- // Reset to the top of the grid
- mFirstPosition = 0;
-
- // Clear recycler because there could be different view types now
- mRecycler.clear();
- }
-
- @Override
- protected LayoutParams generateDefaultLayoutParams() {
- return new LayoutParams(LayoutParams.WRAP_CONTENT);
- }
-
- @Override
- protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
- return new LayoutParams(lp);
- }
-
- @Override
- protected boolean checkLayoutParams(ViewGroup.LayoutParams lp) {
- return lp instanceof LayoutParams;
- }
-
- @Override
- public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
- return new LayoutParams(getContext(), attrs);
- }
-
- public static class LayoutParams extends ViewGroup.LayoutParams {
- private static final int[] LAYOUT_ATTRS = new int[] {
- android.R.attr.layout_span
- };
-
- private static final int SPAN_INDEX = 0;
-
- /**
- * The number of columns this item should span
- */
- public int span = 1;
-
- /**
- * Item position this view represents
- */
- int position;
-
- /**
- * Type of this view as reported by the adapter
- */
- int viewType;
-
- /**
- * The column this view is occupying
- */
- int column;
-
- /**
- * The stable ID of the item this view displays
- */
- long id = -1;
-
- public LayoutParams(int height) {
- super(MATCH_PARENT, height);
-
- if (this.height == MATCH_PARENT) {
- Log.w(TAG, "Constructing LayoutParams with height MATCH_PARENT - " +
- "impossible! Falling back to WRAP_CONTENT");
- this.height = WRAP_CONTENT;
- }
- }
-
- public LayoutParams(Context c, AttributeSet attrs) {
- super(c, attrs);
-
- if (this.width != MATCH_PARENT) {
- Log.w(TAG, "Inflation setting LayoutParams width to " + this.width +
- " - must be MATCH_PARENT");
- this.width = MATCH_PARENT;
- }
- if (this.height == MATCH_PARENT) {
- Log.w(TAG, "Inflation setting LayoutParams height to MATCH_PARENT - " +
- "impossible! Falling back to WRAP_CONTENT");
- this.height = WRAP_CONTENT;
- }
-
- TypedArray a = c.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
- span = a.getInteger(SPAN_INDEX, 1);
- a.recycle();
- }
-
- public LayoutParams(ViewGroup.LayoutParams other) {
- super(other);
-
- if (this.width != MATCH_PARENT) {
- Log.w(TAG, "Constructing LayoutParams with width " + this.width +
- " - must be MATCH_PARENT");
- this.width = MATCH_PARENT;
- }
- if (this.height == MATCH_PARENT) {
- Log.w(TAG, "Constructing LayoutParams with height MATCH_PARENT - " +
- "impossible! Falling back to WRAP_CONTENT");
- this.height = WRAP_CONTENT;
- }
- }
- }
-
- private class RecycleBin {
- private ArrayList<View>[] mScrapViews;
- private int mViewTypeCount;
- private int mMaxScrap;
-
- private SparseArray<View> mTransientStateViews;
-
- public void setViewTypeCount(int viewTypeCount) {
- if (viewTypeCount < 1) {
- throw new IllegalArgumentException("Must have at least one view type (" +
- viewTypeCount + " types reported)");
- }
- if (viewTypeCount == mViewTypeCount) {
- return;
- }
-
- ArrayList<View>[] scrapViews = new ArrayList[viewTypeCount];
- for (int i = 0; i < viewTypeCount; i++) {
- scrapViews[i] = new ArrayList<View>();
- }
- mViewTypeCount = viewTypeCount;
- mScrapViews = scrapViews;
- }
-
- public void clear() {
- final int typeCount = mViewTypeCount;
- for (int i = 0; i < typeCount; i++) {
- mScrapViews[i].clear();
- }
- if (mTransientStateViews != null) {
- mTransientStateViews.clear();
- }
- }
-
- public void clearTransientViews() {
- if (mTransientStateViews != null) {
- mTransientStateViews.clear();
- }
- }
-
- public void addScrap(View v) {
- final LayoutParams lp = (LayoutParams) v.getLayoutParams();
- if (ViewCompat.hasTransientState(v)) {
- if (mTransientStateViews == null) {
- mTransientStateViews = new SparseArray<View>();
- }
- mTransientStateViews.put(lp.position, v);
- return;
- }
-
- final int childCount = getChildCount();
- if (childCount > mMaxScrap) {
- mMaxScrap = childCount;
- }
-
- ArrayList<View> scrap = mScrapViews[lp.viewType];
- if (scrap.size() < mMaxScrap) {
- scrap.add(v);
- }
- }
-
- public View getTransientStateView(int position) {
- if (mTransientStateViews == null) {
- return null;
- }
-
- final View result = mTransientStateViews.get(position);
- if (result != null) {
- mTransientStateViews.remove(position);
- }
- return result;
- }
-
- public View getScrapView(int type) {
- ArrayList<View> scrap = mScrapViews[type];
- if (scrap.isEmpty()) {
- return null;
- }
-
- final int index = scrap.size() - 1;
- final View result = scrap.get(index);
- scrap.remove(index);
- return result;
- }
- }
-
- private class AdapterDataSetObserver extends DataSetObserver {
- @Override
- public void onChanged() {
- mDataChanged = true;
- mOldItemCount = mItemCount;
- mItemCount = mAdapter.getCount();
-
- // TODO: Consider matching these back up if we have stable IDs.
- mRecycler.clearTransientViews();
-
- if (!mHasStableIds) {
- recycleAllViews();
- }
-
- // TODO: consider repopulating in a deferred runnable instead
- // (so that successive changes may still be batched)
- requestLayout();
- }
-
- @Override
- public void onInvalidated() {
- }
- }
-}