Bug 1324034 - Remove TwoWayView. r?sebastian draft
authorTom Klein <twointofive@gmail.com>
Tue, 20 Dec 2016 00:54:12 -0600
changeset 451519 a8ffdb84cb7355da4abd440d3a768e59b48674f3
parent 451264 567894f026558e6dada617a3998f29aed06ac7d8
child 540059 09ef7790ba061a60c7754f6f4cdec11a5de8105b
push id39215
push userbmo:twointofive@gmail.com
push dateTue, 20 Dec 2016 15:35:20 +0000
reviewerssebastian
bugs1324034
milestone53.0a1
Bug 1324034 - Remove TwoWayView. r?sebastian MozReview-Commit-ID: GaqJEmi4dG7
mobile/android/base/java/org/mozilla/gecko/widget/TwoWayView.java
mobile/android/base/moz.build
mobile/android/base/resources/layout/search_engine_bar_item.xml
mobile/android/base/resources/layout/search_engine_bar_label.xml
mobile/android/base/resources/values/attrs.xml
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/widget/TwoWayView.java
+++ /dev/null
@@ -1,7191 +0,0 @@
-/*
- * Copyright (C) 2013 Lucas Rocha
- *
- * This code is based on bits and pieces of Android's AbsListView,
- * Listview, and StaggeredGridView.
- *
- * Copyright (C) 2012 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 org.mozilla.gecko.widget;
-
-import org.mozilla.gecko.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.database.DataSetObserver;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.TransitionDrawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.support.v4.util.LongSparseArray;
-import android.support.v4.util.SparseArrayCompat;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.KeyEventCompat;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v4.view.VelocityTrackerCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.widget.EdgeEffectCompat;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.SparseBooleanArray;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.FocusFinder;
-import android.view.HapticFeedbackConstants;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.SoundEffectConstants;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.ViewTreeObserver;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.AdapterView;
-import android.widget.Checkable;
-import android.widget.ListAdapter;
-import android.widget.Scroller;
-
-import static android.os.Build.VERSION_CODES.HONEYCOMB;
-
-/*
- * Implementation Notes:
- *
- * Some terminology:
- *
- *     index    - index of the items that are currently visible
- *     position - index of the items in the cursor
- *
- * Given the bi-directional nature of this view, the source code
- * usually names variables with 'start' to mean 'top' or 'left'; and
- * 'end' to mean 'bottom' or 'right', depending on the current
- * orientation of the widget.
- */
-
-/**
- * A view that shows items in a vertical or horizontal scrolling list.
- * The items come from the {@link ListAdapter} associated with this view.
- */
-public class TwoWayView extends AdapterView<ListAdapter> implements
-        ViewTreeObserver.OnTouchModeChangeListener {
-    private static final String LOGTAG = "TwoWayView";
-
-    private static final int NO_POSITION = -1;
-    private static final int INVALID_POINTER = -1;
-
-    public static final int[] STATE_NOTHING = new int[] { 0 };
-
-    private static final int TOUCH_MODE_REST = -1;
-    private static final int TOUCH_MODE_DOWN = 0;
-    private static final int TOUCH_MODE_TAP = 1;
-    private static final int TOUCH_MODE_DONE_WAITING = 2;
-    private static final int TOUCH_MODE_DRAGGING = 3;
-    private static final int TOUCH_MODE_FLINGING = 4;
-    private static final int TOUCH_MODE_OVERSCROLL = 5;
-
-    private static final int TOUCH_MODE_UNKNOWN = -1;
-    private static final int TOUCH_MODE_ON = 0;
-    private static final int TOUCH_MODE_OFF = 1;
-
-    private static final int LAYOUT_NORMAL = 0;
-    private static final int LAYOUT_FORCE_TOP = 1;
-    private static final int LAYOUT_SET_SELECTION = 2;
-    private static final int LAYOUT_FORCE_BOTTOM = 3;
-    private static final int LAYOUT_SPECIFIC = 4;
-    private static final int LAYOUT_SYNC = 5;
-    private static final int LAYOUT_MOVE_SELECTION = 6;
-
-    private static final int SYNC_SELECTED_POSITION = 0;
-    private static final int SYNC_FIRST_POSITION = 1;
-
-    private static final int SYNC_MAX_DURATION_MILLIS = 100;
-
-    private static final int CHECK_POSITION_SEARCH_DISTANCE = 20;
-
-    private static final float MAX_SCROLL_FACTOR = 0.33f;
-
-    private static final int MIN_SCROLL_PREVIEW_PIXELS = 10;
-
-    public static enum ChoiceMode {
-        NONE,
-        SINGLE,
-        MULTIPLE
-    }
-
-    public static enum Orientation {
-        HORIZONTAL,
-        VERTICAL
-    }
-
-    private final Context mContext;
-
-    private ListAdapter mAdapter;
-
-    private boolean mIsVertical;
-
-    private int mItemMargin;
-
-    private boolean mInLayout;
-    private boolean mBlockLayoutRequests;
-
-    private boolean mIsAttached;
-
-    private final RecycleBin mRecycler;
-    private AdapterDataSetObserver mDataSetObserver;
-
-    private boolean mItemsCanFocus;
-
-    final boolean[] mIsScrap = new boolean[1];
-
-    private boolean mDataChanged;
-    private int mItemCount;
-    private int mOldItemCount;
-    private boolean mHasStableIds;
-    private boolean mAreAllItemsSelectable;
-
-    private int mFirstPosition;
-    private int mSpecificStart;
-
-    private SavedState mPendingSync;
-
-    private PositionScroller mPositionScroller;
-    private Runnable mPositionScrollAfterLayout;
-
-    private final int mTouchSlop;
-    private final int mMaximumVelocity;
-    private final int mFlingVelocity;
-    private float mLastTouchPos;
-    private float mTouchRemainderPos;
-    private int mActivePointerId;
-
-    private final Rect mTempRect;
-
-    private final ArrowScrollFocusResult mArrowScrollFocusResult;
-
-    private Rect mTouchFrame;
-    private int mMotionPosition;
-    private CheckForTap mPendingCheckForTap;
-    private CheckForLongPress mPendingCheckForLongPress;
-    private CheckForKeyLongPress mPendingCheckForKeyLongPress;
-    private PerformClick mPerformClick;
-    private Runnable mTouchModeReset;
-    private int mResurrectToPosition;
-
-    private boolean mIsChildViewEnabled;
-
-    private boolean mDrawSelectorOnTop;
-    private Drawable mSelector;
-    private int mSelectorPosition;
-    private final Rect mSelectorRect;
-
-    private int mOverScroll;
-    private final int mOverscrollDistance;
-
-    private boolean mDesiredFocusableState;
-    private boolean mDesiredFocusableInTouchModeState;
-
-    private SelectionNotifier mSelectionNotifier;
-
-    private boolean mNeedSync;
-    private int mSyncMode;
-    private int mSyncPosition;
-    private long mSyncRowId;
-    private long mSyncSize;
-    private int mSelectedStart;
-
-    private int mNextSelectedPosition;
-    private long mNextSelectedRowId;
-    private int mSelectedPosition;
-    private long mSelectedRowId;
-    private int mOldSelectedPosition;
-    private long mOldSelectedRowId;
-
-    private ChoiceMode mChoiceMode;
-    private int mCheckedItemCount;
-    private SparseBooleanArray mCheckStates;
-    LongSparseArray<Integer> mCheckedIdStates;
-
-    private ContextMenuInfo mContextMenuInfo;
-
-    private int mLayoutMode;
-    private int mTouchMode;
-    private int mLastTouchMode;
-    private VelocityTracker mVelocityTracker;
-    private final Scroller mScroller;
-
-    private EdgeEffectCompat mStartEdge;
-    private EdgeEffectCompat mEndEdge;
-
-    private OnScrollListener mOnScrollListener;
-    private int mLastScrollState;
-
-    private View mEmptyView;
-
-    private ListItemAccessibilityDelegate mAccessibilityDelegate;
-
-    private int mLastAccessibilityScrollEventFromIndex;
-    private int mLastAccessibilityScrollEventToIndex;
-
-    public interface OnScrollListener {
-
-        /**
-         * The view is not scrolling. Note navigating the list using the trackball counts as
-         * being in the idle state since these transitions are not animated.
-         */
-        public static int SCROLL_STATE_IDLE = 0;
-
-        /**
-         * The user is scrolling using touch, and their finger is still on the screen
-         */
-        public static int SCROLL_STATE_TOUCH_SCROLL = 1;
-
-        /**
-         * The user had previously been scrolling using touch and had performed a fling. The
-         * animation is now coasting to a stop
-         */
-        public static int SCROLL_STATE_FLING = 2;
-
-        /**
-         * Callback method to be invoked while the list view or grid view is being scrolled. If the
-         * view is being scrolled, this method will be called before the next frame of the scroll is
-         * rendered. In particular, it will be called before any calls to
-         * {@link android.widget.Adapter#getView(int, View, ViewGroup)}.
-         *
-         * @param view The view whose scroll state is being reported
-         *
-         * @param scrollState The current scroll state. One of {@link #SCROLL_STATE_IDLE},
-         * {@link #SCROLL_STATE_TOUCH_SCROLL} or {@link #SCROLL_STATE_IDLE}.
-         */
-        public void onScrollStateChanged(TwoWayView view, int scrollState);
-
-        /**
-         * Callback method to be invoked when the list or grid has been scrolled. This will be
-         * called after the scroll has completed
-         * @param view The view whose scroll state is being reported
-         * @param firstVisibleItem the index of the first visible cell (ignore if
-         *        visibleItemCount == 0)
-         * @param visibleItemCount the number of visible cells
-         * @param totalItemCount the number of items in the list adaptor
-         */
-        public void onScroll(TwoWayView view, int firstVisibleItem, int visibleItemCount,
-                int totalItemCount);
-    }
-
-    /**
-     * A RecyclerListener is used to receive a notification whenever a View is placed
-     * inside the RecycleBin's scrap heap. This listener is used to free resources
-     * associated to Views placed in the RecycleBin.
-     *
-     * @see TwoWayView.RecycleBin
-     * @see TwoWayView#setRecyclerListener(TwoWayView.RecyclerListener)
-     */
-    public static interface RecyclerListener {
-        /**
-         * Indicates that the specified View was moved into the recycler's scrap heap.
-         * The view is not displayed on screen any more and any expensive resource
-         * associated with the view should be discarded.
-         *
-         * @param view
-         */
-        void onMovedToScrapHeap(View view);
-    }
-
-    public TwoWayView(Context context) {
-        this(context, null);
-    }
-
-    public TwoWayView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public TwoWayView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        mContext = context;
-
-        mLayoutMode = LAYOUT_NORMAL;
-        mTouchMode = TOUCH_MODE_REST;
-        mLastTouchMode = TOUCH_MODE_UNKNOWN;
-
-        mLastScrollState = OnScrollListener.SCROLL_STATE_IDLE;
-
-        final ViewConfiguration vc = ViewConfiguration.get(context);
-        mTouchSlop = vc.getScaledTouchSlop();
-        mMaximumVelocity = vc.getScaledMaximumFlingVelocity();
-        mFlingVelocity = vc.getScaledMinimumFlingVelocity();
-        mOverscrollDistance = getScaledOverscrollDistance(vc);
-
-        mScroller = new Scroller(context);
-
-        mIsVertical = true;
-
-        mTempRect = new Rect();
-
-        mArrowScrollFocusResult = new ArrowScrollFocusResult();
-
-        mSelectorPosition = INVALID_POSITION;
-
-        mSelectorRect = new Rect();
-
-        mResurrectToPosition = INVALID_POSITION;
-
-        mNextSelectedPosition = INVALID_POSITION;
-        mNextSelectedRowId = INVALID_ROW_ID;
-        mSelectedPosition = INVALID_POSITION;
-        mSelectedRowId = INVALID_ROW_ID;
-        mOldSelectedPosition = INVALID_POSITION;
-        mOldSelectedRowId = INVALID_ROW_ID;
-
-        mChoiceMode = ChoiceMode.NONE;
-
-        mRecycler = new RecycleBin();
-
-        mAreAllItemsSelectable = true;
-
-        setClickable(true);
-        setFocusableInTouchMode(true);
-        setWillNotDraw(false);
-        setAlwaysDrawnWithCacheEnabled(false);
-        setWillNotDraw(false);
-        setClipToPadding(false);
-
-        ViewCompat.setOverScrollMode(this, ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS);
-
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TwoWayView, defStyle, 0);
-
-        mDrawSelectorOnTop = a.getBoolean(
-                R.styleable.TwoWayView_android_drawSelectorOnTop, false);
-
-        Drawable d = a.getDrawable(R.styleable.TwoWayView_android_listSelector);
-        if (d != null) {
-            setSelector(d);
-        }
-
-        int orientation = a.getInt(R.styleable.TwoWayView_android_orientation, -1);
-        if (orientation >= 0) {
-            setOrientation(Orientation.values()[orientation]);
-        }
-
-        int choiceMode = a.getInt(R.styleable.TwoWayView_android_choiceMode, -1);
-        if (choiceMode >= 0) {
-            setChoiceMode(ChoiceMode.values()[choiceMode]);
-        }
-
-        a.recycle();
-    }
-
-    public void setOrientation(Orientation orientation) {
-        final boolean isVertical = (orientation == Orientation.VERTICAL);
-        if (mIsVertical == isVertical) {
-            return;
-        }
-
-        mIsVertical = isVertical;
-
-        resetState();
-        mRecycler.clear();
-
-        requestLayout();
-    }
-
-    public Orientation getOrientation() {
-        return (mIsVertical ? Orientation.VERTICAL : Orientation.HORIZONTAL);
-    }
-
-    public void setItemMargin(int itemMargin) {
-        if (mItemMargin == itemMargin) {
-            return;
-        }
-
-        mItemMargin = itemMargin;
-        requestLayout();
-    }
-
-    @SuppressWarnings("unused")
-    public int getItemMargin() {
-        return mItemMargin;
-    }
-
-    /**
-     * Indicates that the views created by the ListAdapter can contain focusable
-     * items.
-     *
-     * @param itemsCanFocus true if items can get focus, false otherwise
-     */
-    @SuppressWarnings("unused")
-    public void setItemsCanFocus(boolean itemsCanFocus) {
-        mItemsCanFocus = itemsCanFocus;
-        if (!itemsCanFocus) {
-            setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-        }
-    }
-
-    /**
-     * @return Whether the views created by the ListAdapter can contain focusable
-     * items.
-     */
-    @SuppressWarnings("unused")
-    public boolean getItemsCanFocus() {
-        return mItemsCanFocus;
-    }
-
-    /**
-     * Set the listener that will receive notifications every time the list scrolls.
-     *
-     * @param l the scroll listener
-     */
-    public void setOnScrollListener(OnScrollListener l) {
-        mOnScrollListener = l;
-        invokeOnItemScrollListener();
-    }
-
-    /**
-     * Sets the recycler listener to be notified whenever a View is set aside in
-     * the recycler for later reuse. This listener can be used to free resources
-     * associated to the View.
-     *
-     * @param l The recycler listener to be notified of views set aside
-     *        in the recycler.
-     *
-     * @see TwoWayView.RecycleBin
-     * @see TwoWayView.RecyclerListener
-     */
-    public void setRecyclerListener(RecyclerListener l) {
-        mRecycler.mRecyclerListener = l;
-    }
-
-    /**
-     * Controls whether the selection highlight drawable should be drawn on top of the item or
-     * behind it.
-     *
-     * @param drawSelectorOnTop If true, the selector will be drawn on the item it is highlighting.
-     *                          The default is false.
-     *
-     * @attr ref android.R.styleable#AbsListView_drawSelectorOnTop
-     */
-    @SuppressWarnings("unused")
-    public void setDrawSelectorOnTop(boolean drawSelectorOnTop) {
-        mDrawSelectorOnTop = drawSelectorOnTop;
-    }
-
-    /**
-     * Set a Drawable that should be used to highlight the currently selected item.
-     *
-     * @param resID A Drawable resource to use as the selection highlight.
-     *
-     * @attr ref android.R.styleable#AbsListView_listSelector
-     */
-    @SuppressWarnings("unused")
-    public void setSelector(int resID) {
-        setSelector(getResources().getDrawable(resID));
-    }
-
-    /**
-     * Set a Drawable that should be used to highlight the currently selected item.
-     *
-     * @param selector A Drawable to use as the selection highlight.
-     *
-     * @attr ref android.R.styleable#AbsListView_listSelector
-     */
-    public void setSelector(Drawable selector) {
-        if (mSelector != null) {
-            mSelector.setCallback(null);
-            unscheduleDrawable(mSelector);
-        }
-
-        mSelector = selector;
-        Rect padding = new Rect();
-        selector.getPadding(padding);
-
-        selector.setCallback(this);
-        updateSelectorState();
-    }
-
-    /**
-     * Returns the selector {@link android.graphics.drawable.Drawable} that is used to draw the
-     * selection in the list.
-     *
-     * @return the drawable used to display the selector
-     */
-    @SuppressWarnings("unused")
-    public Drawable getSelector() {
-        return mSelector;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int getSelectedItemPosition() {
-        return mNextSelectedPosition;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public long getSelectedItemId() {
-        return mNextSelectedRowId;
-    }
-
-    /**
-     * Returns the number of items currently selected. This will only be valid
-     * if the choice mode is not {@link ChoiceMode#NONE} (default).
-     *
-     * <p>To determine the specific items that are currently selected, use one of
-     * the <code>getChecked*</code> methods.
-     *
-     * @return The number of items currently selected
-     *
-     * @see #getCheckedItemPosition()
-     * @see #getCheckedItemPositions()
-     * @see #getCheckedItemIds()
-     */
-    @SuppressWarnings("unused")
-    public int getCheckedItemCount() {
-        return mCheckedItemCount;
-    }
-
-    /**
-     * Returns the checked state of the specified position. The result is only
-     * valid if the choice mode has been set to {@link ChoiceMode#SINGLE}
-     * or {@link ChoiceMode#MULTIPLE}.
-     *
-     * @param position The item whose checked state to return
-     * @return The item's checked state or <code>false</code> if choice mode
-     *         is invalid
-     *
-     * @see #setChoiceMode(ChoiceMode)
-     */
-    public boolean isItemChecked(int position) {
-        if (mChoiceMode == ChoiceMode.NONE && mCheckStates != null) {
-            return mCheckStates.get(position);
-        }
-
-        return false;
-    }
-
-    /**
-     * Returns the currently checked item. The result is only valid if the choice
-     * mode has been set to {@link ChoiceMode#SINGLE}.
-     *
-     * @return The position of the currently checked item or
-     *         {@link #INVALID_POSITION} if nothing is selected
-     *
-     * @see #setChoiceMode(ChoiceMode)
-     */
-    public int getCheckedItemPosition() {
-        if (mChoiceMode == ChoiceMode.SINGLE && mCheckStates != null && mCheckStates.size() == 1) {
-            return mCheckStates.keyAt(0);
-        }
-
-        return INVALID_POSITION;
-    }
-
-    /**
-     * Returns the set of checked items in the list. The result is only valid if
-     * the choice mode has not been set to {@link ChoiceMode#NONE}.
-     *
-     * @return  A SparseBooleanArray which will return true for each call to
-     *          get(int position) where position is a position in the list,
-     *          or <code>null</code> if the choice mode is set to
-     *          {@link ChoiceMode#NONE}.
-     */
-    public SparseBooleanArray getCheckedItemPositions() {
-        if (mChoiceMode != ChoiceMode.NONE) {
-            return mCheckStates;
-        }
-
-        return null;
-    }
-
-    /**
-     * Returns the set of checked items ids. The result is only valid if the
-     * choice mode has not been set to {@link ChoiceMode#NONE} and the adapter
-     * has stable IDs. ({@link ListAdapter#hasStableIds()} == {@code true})
-     *
-     * @return A new array which contains the id of each checked item in the
-     *         list.
-     */
-    public long[] getCheckedItemIds() {
-        if (mChoiceMode == ChoiceMode.NONE || mCheckedIdStates == null || mAdapter == null) {
-            return new long[0];
-        }
-
-        final LongSparseArray<Integer> idStates = mCheckedIdStates;
-        final int count = idStates.size();
-        final long[] ids = new long[count];
-
-        for (int i = 0; i < count; i++) {
-            ids[i] = idStates.keyAt(i);
-        }
-
-        return ids;
-    }
-
-    /**
-     * Sets the checked state of the specified position. The is only valid if
-     * the choice mode has been set to {@link ChoiceMode#SINGLE} or
-     * {@link ChoiceMode#MULTIPLE}.
-     *
-     * @param position The item whose checked state is to be checked
-     * @param value The new checked state for the item
-     */
-    @SuppressWarnings("unused")
-    public void setItemChecked(int position, boolean value) {
-        if (mChoiceMode == ChoiceMode.NONE) {
-            return;
-        }
-
-        if (mChoiceMode == ChoiceMode.MULTIPLE) {
-            boolean oldValue = mCheckStates.get(position);
-            mCheckStates.put(position, value);
-
-            if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
-                if (value) {
-                    mCheckedIdStates.put(mAdapter.getItemId(position), position);
-                } else {
-                    mCheckedIdStates.delete(mAdapter.getItemId(position));
-                }
-            }
-
-            if (oldValue != value) {
-                if (value) {
-                    mCheckedItemCount++;
-                } else {
-                    mCheckedItemCount--;
-                }
-            }
-        } else {
-            boolean updateIds = mCheckedIdStates != null && mAdapter.hasStableIds();
-
-            // Clear all values if we're checking something, or unchecking the currently
-            // selected item
-            if (value || isItemChecked(position)) {
-                mCheckStates.clear();
-
-                if (updateIds) {
-                    mCheckedIdStates.clear();
-                }
-            }
-
-            // This may end up selecting the value we just cleared but this way
-            // we ensure length of mCheckStates is 1, a fact getCheckedItemPosition relies on
-            if (value) {
-                mCheckStates.put(position, true);
-
-                if (updateIds) {
-                    mCheckedIdStates.put(mAdapter.getItemId(position), position);
-                }
-
-                mCheckedItemCount = 1;
-            } else if (mCheckStates.size() == 0 || !mCheckStates.valueAt(0)) {
-                mCheckedItemCount = 0;
-            }
-        }
-
-        // Do not generate a data change while we are in the layout phase
-        if (!mInLayout && !mBlockLayoutRequests) {
-            mDataChanged = true;
-            rememberSyncState();
-            requestLayout();
-        }
-    }
-
-    /**
-     * Clear any choices previously set
-     */
-    @SuppressWarnings("unused")
-    public void clearChoices() {
-        if (mCheckStates != null) {
-            mCheckStates.clear();
-        }
-
-        if (mCheckedIdStates != null) {
-            mCheckedIdStates.clear();
-        }
-
-        mCheckedItemCount = 0;
-    }
-
-    /**
-     * @see #setChoiceMode(ChoiceMode)
-     *
-     * @return The current choice mode
-     */
-    @SuppressWarnings("unused")
-    public ChoiceMode getChoiceMode() {
-        return mChoiceMode;
-    }
-
-    /**
-     * Defines the choice behavior for the List. By default, Lists do not have any choice behavior
-     * ({@link ChoiceMode#NONE}). By setting the choiceMode to {@link ChoiceMode#SINGLE}, the
-     * List allows up to one item to  be in a chosen state. By setting the choiceMode to
-     * {@link ChoiceMode#MULTIPLE}, the list allows any number of items to be chosen.
-     *
-     * @param choiceMode One of {@link ChoiceMode#NONE}, {@link ChoiceMode#SINGLE}, or
-     * {@link ChoiceMode#MULTIPLE}
-     */
-    public void setChoiceMode(ChoiceMode choiceMode) {
-        mChoiceMode = choiceMode;
-
-        if (mChoiceMode != ChoiceMode.NONE) {
-            if (mCheckStates == null) {
-                mCheckStates = new SparseBooleanArray();
-            }
-
-            if (mCheckedIdStates == null && mAdapter != null && mAdapter.hasStableIds()) {
-                mCheckedIdStates = new LongSparseArray<Integer>();
-            }
-        }
-    }
-
-    @Override
-    public ListAdapter getAdapter() {
-        return mAdapter;
-    }
-
-    @Override
-    public void setAdapter(ListAdapter adapter) {
-        if (mAdapter != null && mDataSetObserver != null) {
-            mAdapter.unregisterDataSetObserver(mDataSetObserver);
-        }
-
-        resetState();
-        mRecycler.clear();
-
-        mAdapter = adapter;
-        mDataChanged = true;
-
-        mOldSelectedPosition = INVALID_POSITION;
-        mOldSelectedRowId = INVALID_ROW_ID;
-
-        if (mCheckStates != null) {
-            mCheckStates.clear();
-        }
-
-        if (mCheckedIdStates != null) {
-            mCheckedIdStates.clear();
-        }
-
-        if (mAdapter != null) {
-            mOldItemCount = mItemCount;
-            mItemCount = adapter.getCount();
-
-            mDataSetObserver = new AdapterDataSetObserver();
-            mAdapter.registerDataSetObserver(mDataSetObserver);
-
-            mRecycler.setViewTypeCount(adapter.getViewTypeCount());
-
-            mHasStableIds = adapter.hasStableIds();
-            mAreAllItemsSelectable = adapter.areAllItemsEnabled();
-
-            if (mChoiceMode != ChoiceMode.NONE && mHasStableIds && mCheckedIdStates == null) {
-                mCheckedIdStates = new LongSparseArray<Integer>();
-            }
-
-            final int position = lookForSelectablePosition(0);
-            setSelectedPositionInt(position);
-            setNextSelectedPositionInt(position);
-
-            if (mItemCount == 0) {
-                checkSelectionChanged();
-            }
-        } else {
-            mItemCount = 0;
-            mHasStableIds = false;
-            mAreAllItemsSelectable = true;
-
-            checkSelectionChanged();
-        }
-
-        checkFocus();
-        requestLayout();
-    }
-
-    @Override
-    public int getFirstVisiblePosition() {
-        return mFirstPosition;
-    }
-
-    @Override
-    public int getLastVisiblePosition() {
-        return mFirstPosition + getChildCount() - 1;
-    }
-
-    @Override
-    public int getCount() {
-        return mItemCount;
-    }
-
-    @Override
-    public int getPositionForView(View view) {
-        View child = view;
-        try {
-            View v;
-            while (!(v = (View) child.getParent()).equals(this)) {
-                child = v;
-            }
-        } catch (ClassCastException e) {
-            // We made it up to the window without find this list view
-            return INVALID_POSITION;
-        }
-
-        // Search the children for the list item
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            if (getChildAt(i).equals(child)) {
-                return mFirstPosition + i;
-            }
-        }
-
-        // Child not found!
-        return INVALID_POSITION;
-    }
-
-    @Override
-    public void getFocusedRect(Rect r) {
-        View view = getSelectedView();
-
-        if (view != null && view.getParent() == this) {
-            // The focused rectangle of the selected view offset into the
-            // coordinate space of this view.
-            view.getFocusedRect(r);
-            offsetDescendantRectToMyCoords(view, r);
-        } else {
-            super.getFocusedRect(r);
-        }
-    }
-
-    @Override
-    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
-        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
-
-        if (gainFocus && mSelectedPosition < 0 && !isInTouchMode()) {
-            if (!mIsAttached && mAdapter != null) {
-                // Data may have changed while we were detached and it's valid
-                // to change focus while detached. Refresh so we don't die.
-                mDataChanged = true;
-                mOldItemCount = mItemCount;
-                mItemCount = mAdapter.getCount();
-            }
-
-            resurrectSelection();
-        }
-
-        final ListAdapter adapter = mAdapter;
-        int closetChildIndex = INVALID_POSITION;
-        int closestChildStart = 0;
-
-        if (adapter != null && gainFocus && previouslyFocusedRect != null) {
-            previouslyFocusedRect.offset(getScrollX(), getScrollY());
-
-            // Don't cache the result of getChildCount or mFirstPosition here,
-            // it could change in layoutChildren.
-            if (adapter.getCount() < getChildCount() + mFirstPosition) {
-                mLayoutMode = LAYOUT_NORMAL;
-                layoutChildren();
-            }
-
-            // Figure out which item should be selected based on previously
-            // focused rect.
-            Rect otherRect = mTempRect;
-            int minDistance = Integer.MAX_VALUE;
-            final int childCount = getChildCount();
-            final int firstPosition = mFirstPosition;
-
-            for (int i = 0; i < childCount; i++) {
-                // Only consider selectable views
-                if (!adapter.isEnabled(firstPosition + i)) {
-                    continue;
-                }
-
-                View other = getChildAt(i);
-                other.getDrawingRect(otherRect);
-                offsetDescendantRectToMyCoords(other, otherRect);
-                int distance = getDistance(previouslyFocusedRect, otherRect, direction);
-
-                if (distance < minDistance) {
-                    minDistance = distance;
-                    closetChildIndex = i;
-                    closestChildStart = getChildStartEdge(other);
-                }
-            }
-        }
-
-        if (closetChildIndex >= 0) {
-            setSelectionFromOffset(closetChildIndex + mFirstPosition, closestChildStart);
-        } else {
-            requestLayout();
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        final ViewTreeObserver treeObserver = getViewTreeObserver();
-        treeObserver.addOnTouchModeChangeListener(this);
-
-        if (mAdapter != null && mDataSetObserver == null) {
-            mDataSetObserver = new AdapterDataSetObserver();
-            mAdapter.registerDataSetObserver(mDataSetObserver);
-
-            // Data may have changed while we were detached. Refresh.
-            mDataChanged = true;
-            mOldItemCount = mItemCount;
-            mItemCount = mAdapter.getCount();
-        }
-
-        mIsAttached = true;
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        // Detach any view left in the scrap heap
-        mRecycler.clear();
-
-        final ViewTreeObserver treeObserver = getViewTreeObserver();
-        treeObserver.removeOnTouchModeChangeListener(this);
-
-        if (mAdapter != null) {
-            mAdapter.unregisterDataSetObserver(mDataSetObserver);
-            mDataSetObserver = null;
-        }
-
-        if (mPerformClick != null) {
-            removeCallbacks(mPerformClick);
-        }
-
-        if (mTouchModeReset != null) {
-            removeCallbacks(mTouchModeReset);
-            mTouchModeReset.run();
-        }
-
-        finishSmoothScrolling();
-
-        mIsAttached = false;
-    }
-
-    @Override
-    public void onWindowFocusChanged(boolean hasWindowFocus) {
-        super.onWindowFocusChanged(hasWindowFocus);
-
-        final int touchMode = isInTouchMode() ? TOUCH_MODE_ON : TOUCH_MODE_OFF;
-
-        if (!hasWindowFocus) {
-            if (!mScroller.isFinished()) {
-                finishSmoothScrolling();
-                if (mOverScroll != 0) {
-                    mOverScroll = 0;
-                    finishEdgeGlows();
-                    invalidate();
-                }
-            }
-
-            if (touchMode == TOUCH_MODE_OFF) {
-                // Remember the last selected element
-                mResurrectToPosition = mSelectedPosition;
-            }
-        } else {
-            // If we changed touch mode since the last time we had focus
-            if (touchMode != mLastTouchMode && mLastTouchMode != TOUCH_MODE_UNKNOWN) {
-                // If we come back in trackball mode, we bring the selection back
-                if (touchMode == TOUCH_MODE_OFF) {
-                    // This will trigger a layout
-                    resurrectSelection();
-
-                // If we come back in touch mode, then we want to hide the selector
-                } else {
-                    hideSelector();
-                    mLayoutMode = LAYOUT_NORMAL;
-                    layoutChildren();
-                }
-            }
-        }
-
-        mLastTouchMode = touchMode;
-    }
-
-    @Override
-    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
-        boolean needsInvalidate = false;
-
-        if (mIsVertical && mOverScroll != scrollY) {
-            onScrollChanged(getScrollX(), scrollY, getScrollX(), mOverScroll);
-            mOverScroll = scrollY;
-            needsInvalidate = true;
-        } else if (!mIsVertical && mOverScroll != scrollX) {
-            onScrollChanged(scrollX, getScrollY(), mOverScroll, getScrollY());
-            mOverScroll = scrollX;
-            needsInvalidate = true;
-        }
-
-        if (needsInvalidate) {
-            invalidate();
-            awakenScrollbarsInternal();
-        }
-    }
-
-    @TargetApi(9)
-    private boolean overScrollByInternal(int deltaX, int deltaY,
-            int scrollX, int scrollY,
-            int scrollRangeX, int scrollRangeY,
-            int maxOverScrollX, int maxOverScrollY,
-            boolean isTouchEvent) {
-        if (Build.VERSION.SDK_INT < 9) {
-            return false;
-        }
-
-        return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
-                scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
-    }
-
-    @Override
-    @TargetApi(9)
-    public void setOverScrollMode(int mode) {
-        if (Build.VERSION.SDK_INT < 9) {
-            return;
-        }
-
-        if (mode != ViewCompat.OVER_SCROLL_NEVER) {
-            if (mStartEdge == null) {
-                Context context = getContext();
-
-                mStartEdge = new EdgeEffectCompat(context);
-                mEndEdge = new EdgeEffectCompat(context);
-            }
-        } else {
-            mStartEdge = null;
-            mEndEdge = null;
-        }
-
-        super.setOverScrollMode(mode);
-    }
-
-    public int pointToPosition(int x, int y) {
-        Rect frame = mTouchFrame;
-        if (frame == null) {
-            mTouchFrame = new Rect();
-            frame = mTouchFrame;
-        }
-
-        final int count = getChildCount();
-        for (int i = count - 1; i >= 0; i--) {
-            final View child = getChildAt(i);
-
-            if (child.getVisibility() == View.VISIBLE) {
-                child.getHitRect(frame);
-
-                if (frame.contains(x, y)) {
-                    return mFirstPosition + i;
-                }
-            }
-        }
-        return INVALID_POSITION;
-    }
-
-    @Override
-    protected float getTopFadingEdgeStrength() {
-        if (!mIsVertical) {
-            return 0f;
-        }
-
-        final float fadingEdge = super.getTopFadingEdgeStrength();
-
-        final int childCount = getChildCount();
-        if (childCount == 0) {
-            return fadingEdge;
-        } else {
-            if (mFirstPosition > 0) {
-                return 1.0f;
-            }
-
-            final int top = getChildAt(0).getTop();
-            final int paddingTop = getPaddingTop();
-
-            final float length = (float) getVerticalFadingEdgeLength();
-
-            return (top < paddingTop ? (float) -(top - paddingTop) / length : fadingEdge);
-        }
-    }
-
-    @Override
-    protected float getBottomFadingEdgeStrength() {
-        if (!mIsVertical) {
-            return 0f;
-        }
-
-        final float fadingEdge = super.getBottomFadingEdgeStrength();
-
-        final int childCount = getChildCount();
-        if (childCount == 0) {
-            return fadingEdge;
-        } else {
-            if (mFirstPosition + childCount - 1 < mItemCount - 1) {
-                return 1.0f;
-            }
-
-            final int bottom = getChildAt(childCount - 1).getBottom();
-            final int paddingBottom = getPaddingBottom();
-
-            final int height = getHeight();
-            final float length = (float) getVerticalFadingEdgeLength();
-
-            return (bottom > height - paddingBottom ?
-                    (float) (bottom - height + paddingBottom) / length : fadingEdge);
-        }
-    }
-
-    @Override
-    protected float getLeftFadingEdgeStrength() {
-        if (mIsVertical) {
-            return 0f;
-        }
-
-        final float fadingEdge = super.getLeftFadingEdgeStrength();
-
-        final int childCount = getChildCount();
-        if (childCount == 0) {
-            return fadingEdge;
-        } else {
-            if (mFirstPosition > 0) {
-                return 1.0f;
-            }
-
-            final int left = getChildAt(0).getLeft();
-            final int paddingLeft = getPaddingLeft();
-
-            final float length = (float) getHorizontalFadingEdgeLength();
-
-            return (left < paddingLeft ? (float) -(left - paddingLeft) / length : fadingEdge);
-        }
-    }
-
-    @Override
-    protected float getRightFadingEdgeStrength() {
-        if (mIsVertical) {
-            return 0f;
-        }
-
-        final float fadingEdge = super.getRightFadingEdgeStrength();
-
-        final int childCount = getChildCount();
-        if (childCount == 0) {
-            return fadingEdge;
-        } else {
-            if (mFirstPosition + childCount - 1 < mItemCount - 1) {
-                return 1.0f;
-            }
-
-            final int right = getChildAt(childCount - 1).getRight();
-            final int paddingRight = getPaddingRight();
-
-            final int width = getWidth();
-            final float length = (float) getHorizontalFadingEdgeLength();
-
-            return (right > width - paddingRight ?
-                    (float) (right - width + paddingRight) / length : fadingEdge);
-        }
-    }
-
-    @Override
-    protected int computeVerticalScrollExtent() {
-        final int count = getChildCount();
-        if (count == 0) {
-            return 0;
-        }
-
-        int extent = count * 100;
-
-        View child = getChildAt(0);
-        final int childTop = child.getTop();
-
-        int childHeight = child.getHeight();
-        if (childHeight > 0) {
-            extent += (childTop * 100) / childHeight;
-        }
-
-        child = getChildAt(count - 1);
-        final int childBottom = child.getBottom();
-
-        childHeight = child.getHeight();
-        if (childHeight > 0) {
-            extent -= ((childBottom - getHeight()) * 100) / childHeight;
-        }
-
-        return extent;
-    }
-
-    @Override
-    protected int computeHorizontalScrollExtent() {
-        final int count = getChildCount();
-        if (count == 0) {
-            return 0;
-        }
-
-        int extent = count * 100;
-
-        View child = getChildAt(0);
-        final int childLeft = child.getLeft();
-
-        int childWidth = child.getWidth();
-        if (childWidth > 0) {
-            extent += (childLeft * 100) / childWidth;
-        }
-
-        child = getChildAt(count - 1);
-        final int childRight = child.getRight();
-
-        childWidth = child.getWidth();
-        if (childWidth > 0) {
-            extent -= ((childRight - getWidth()) * 100) / childWidth;
-        }
-
-        return extent;
-    }
-
-    @Override
-    protected int computeVerticalScrollOffset() {
-        final int firstPosition = mFirstPosition;
-        final int childCount = getChildCount();
-
-        if (firstPosition < 0 || childCount == 0) {
-            return 0;
-        }
-
-        final View child = getChildAt(0);
-        final int childTop = child.getTop();
-
-        int childHeight = child.getHeight();
-        if (childHeight > 0) {
-            return Math.max(firstPosition * 100 - (childTop * 100) / childHeight, 0);
-        }
-
-        return 0;
-    }
-
-    @Override
-    protected int computeHorizontalScrollOffset() {
-        final int firstPosition = mFirstPosition;
-        final int childCount = getChildCount();
-
-        if (firstPosition < 0 || childCount == 0) {
-            return 0;
-        }
-
-        final View child = getChildAt(0);
-        final int childLeft = child.getLeft();
-
-        int childWidth = child.getWidth();
-        if (childWidth > 0) {
-            return Math.max(firstPosition * 100 - (childLeft * 100) / childWidth, 0);
-        }
-
-        return 0;
-    }
-
-    @Override
-    protected int computeVerticalScrollRange() {
-        int result = Math.max(mItemCount * 100, 0);
-
-        if (mIsVertical && mOverScroll != 0) {
-            // Compensate for overscroll
-            result += Math.abs((int) ((float) mOverScroll / getHeight() * mItemCount * 100));
-        }
-
-        return result;
-    }
-
-    @Override
-    protected int computeHorizontalScrollRange() {
-        int result = Math.max(mItemCount * 100, 0);
-
-        if (!mIsVertical && mOverScroll != 0) {
-            // Compensate for overscroll
-            result += Math.abs((int) ((float) mOverScroll / getWidth() * mItemCount * 100));
-        }
-
-        return result;
-    }
-
-    @Override
-    public boolean showContextMenuForChild(View originalView) {
-        final int longPressPosition = getPositionForView(originalView);
-        if (longPressPosition >= 0) {
-            final long longPressId = mAdapter.getItemId(longPressPosition);
-            boolean handled = false;
-
-            OnItemLongClickListener listener = getOnItemLongClickListener();
-            if (listener != null) {
-                handled = listener.onItemLongClick(TwoWayView.this, originalView,
-                        longPressPosition, longPressId);
-            }
-
-            if (!handled) {
-                mContextMenuInfo = createContextMenuInfo(
-                        getChildAt(longPressPosition - mFirstPosition),
-                        longPressPosition, longPressId);
-
-                handled = super.showContextMenuForChild(originalView);
-            }
-
-            return handled;
-        }
-
-        return false;
-    }
-
-    @Override
-    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
-        if (disallowIntercept) {
-            recycleVelocityTracker();
-        }
-
-        super.requestDisallowInterceptTouchEvent(disallowIntercept);
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        if (!mIsAttached || mAdapter == null) {
-            return false;
-        }
-
-        final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
-        switch (action) {
-        case MotionEvent.ACTION_DOWN:
-            initOrResetVelocityTracker();
-            mVelocityTracker.addMovement(ev);
-
-            mScroller.abortAnimation();
-            if (mPositionScroller != null) {
-                mPositionScroller.stop();
-            }
-
-            final float x = ev.getX();
-            final float y = ev.getY();
-
-            mLastTouchPos = (mIsVertical ? y : x);
-
-            final int motionPosition = findMotionRowOrColumn((int) mLastTouchPos);
-
-            mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
-            mTouchRemainderPos = 0;
-
-            if (mTouchMode == TOUCH_MODE_FLINGING) {
-                return true;
-            } else if (motionPosition >= 0) {
-                mMotionPosition = motionPosition;
-                mTouchMode = TOUCH_MODE_DOWN;
-            }
-
-            break;
-
-        case MotionEvent.ACTION_MOVE: {
-            if (mTouchMode != TOUCH_MODE_DOWN) {
-                break;
-            }
-
-            initVelocityTrackerIfNotExists();
-            mVelocityTracker.addMovement(ev);
-
-            final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
-            if (index < 0) {
-                Log.e(LOGTAG, "onInterceptTouchEvent could not find pointer with id " +
-                        mActivePointerId + " - did TwoWayView receive an inconsistent " +
-                        "event stream?");
-                return false;
-            }
-
-            final float pos;
-            if (mIsVertical) {
-                pos = MotionEventCompat.getY(ev, index);
-            } else {
-                pos = MotionEventCompat.getX(ev, index);
-            }
-
-            final float diff = pos - mLastTouchPos + mTouchRemainderPos;
-            final int delta = (int) diff;
-            mTouchRemainderPos = diff - delta;
-
-            if (maybeStartScrolling(delta)) {
-                return true;
-            }
-
-            break;
-        }
-
-        case MotionEvent.ACTION_CANCEL:
-        case MotionEvent.ACTION_UP:
-            mActivePointerId = INVALID_POINTER;
-            mTouchMode = TOUCH_MODE_REST;
-            recycleVelocityTracker();
-            reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
-
-            break;
-        }
-
-        return false;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        if (!isEnabled()) {
-            // A disabled view that is clickable still consumes the touch
-            // events, it just doesn't respond to them.
-            return isClickable() || isLongClickable();
-        }
-
-        if (!mIsAttached || mAdapter == null) {
-            return false;
-        }
-
-        boolean needsInvalidate = false;
-
-        initVelocityTrackerIfNotExists();
-        mVelocityTracker.addMovement(ev);
-
-        final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
-        switch (action) {
-        case MotionEvent.ACTION_DOWN: {
-            if (mDataChanged) {
-                break;
-            }
-
-            mVelocityTracker.clear();
-            mScroller.abortAnimation();
-            if (mPositionScroller != null) {
-                mPositionScroller.stop();
-            }
-
-            final float x = ev.getX();
-            final float y = ev.getY();
-
-            mLastTouchPos = (mIsVertical ? y : x);
-
-            int motionPosition = pointToPosition((int) x, (int) y);
-
-            mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
-            mTouchRemainderPos = 0;
-
-            if (mDataChanged) {
-                break;
-            }
-
-            if (mTouchMode == TOUCH_MODE_FLINGING) {
-                mTouchMode = TOUCH_MODE_DRAGGING;
-                reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
-                motionPosition = findMotionRowOrColumn((int) mLastTouchPos);
-            } else if (mMotionPosition >= 0 && mAdapter.isEnabled(mMotionPosition)) {
-                mTouchMode = TOUCH_MODE_DOWN;
-                triggerCheckForTap();
-            }
-
-            mMotionPosition = motionPosition;
-
-            break;
-        }
-
-        case MotionEvent.ACTION_MOVE: {
-            final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
-            if (index < 0) {
-                Log.e(LOGTAG, "onInterceptTouchEvent could not find pointer with id " +
-                        mActivePointerId + " - did TwoWayView receive an inconsistent " +
-                        "event stream?");
-                return false;
-            }
-
-            final float pos;
-            if (mIsVertical) {
-                pos = MotionEventCompat.getY(ev, index);
-            } else {
-                pos = MotionEventCompat.getX(ev, index);
-            }
-
-            if (mDataChanged) {
-                // Re-sync everything if data has been changed
-                // since the scroll operation can query the adapter.
-                layoutChildren();
-            }
-
-            final float diff = pos - mLastTouchPos + mTouchRemainderPos;
-            final int delta = (int) diff;
-            mTouchRemainderPos = diff - delta;
-
-            switch (mTouchMode) {
-            case TOUCH_MODE_DOWN:
-            case TOUCH_MODE_TAP:
-            case TOUCH_MODE_DONE_WAITING:
-                // Check if we have moved far enough that it looks more like a
-                // scroll than a tap
-                maybeStartScrolling(delta);
-                break;
-
-            case TOUCH_MODE_DRAGGING:
-            case TOUCH_MODE_OVERSCROLL:
-                mLastTouchPos = pos;
-                maybeScroll(delta);
-                break;
-            }
-
-            break;
-        }
-
-        case MotionEvent.ACTION_CANCEL:
-            cancelCheckForTap();
-            mTouchMode = TOUCH_MODE_REST;
-            reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
-
-            setPressed(false);
-            View motionView = this.getChildAt(mMotionPosition - mFirstPosition);
-            if (motionView != null) {
-                motionView.setPressed(false);
-            }
-
-            if (mStartEdge != null && mEndEdge != null) {
-                needsInvalidate = mStartEdge.onRelease() | mEndEdge.onRelease();
-            }
-
-            recycleVelocityTracker();
-
-            break;
-
-        case MotionEvent.ACTION_UP: {
-            switch (mTouchMode) {
-            case TOUCH_MODE_DOWN:
-            case TOUCH_MODE_TAP:
-            case TOUCH_MODE_DONE_WAITING: {
-                final int motionPosition = mMotionPosition;
-                final View child = getChildAt(motionPosition - mFirstPosition);
-
-                final float x = ev.getX();
-                final float y = ev.getY();
-
-                final boolean inList;
-                if (mIsVertical) {
-                    inList = x > getPaddingLeft() && x < getWidth() - getPaddingRight();
-                } else {
-                    inList = y > getPaddingTop() && y < getHeight() - getPaddingBottom();
-                }
-
-                if (child != null && !child.hasFocusable() && inList) {
-                    if (mTouchMode != TOUCH_MODE_DOWN) {
-                        child.setPressed(false);
-                    }
-
-                    if (mPerformClick == null) {
-                        mPerformClick = new PerformClick();
-                    }
-
-                    final PerformClick performClick = mPerformClick;
-                    performClick.mClickMotionPosition = motionPosition;
-                    performClick.rememberWindowAttachCount();
-
-                    mResurrectToPosition = motionPosition;
-
-                    if (mTouchMode == TOUCH_MODE_DOWN || mTouchMode == TOUCH_MODE_TAP) {
-                        if (mTouchMode == TOUCH_MODE_DOWN) {
-                            cancelCheckForTap();
-                        } else {
-                            cancelCheckForLongPress();
-                        }
-
-                        mLayoutMode = LAYOUT_NORMAL;
-
-                        if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {
-                            mTouchMode = TOUCH_MODE_TAP;
-
-                            setPressed(true);
-                            positionSelector(mMotionPosition, child);
-                            child.setPressed(true);
-
-                            if (mSelector != null) {
-                                Drawable d = mSelector.getCurrent();
-                                if (d != null && d instanceof TransitionDrawable) {
-                                    ((TransitionDrawable) d).resetTransition();
-                                }
-                            }
-
-                            if (mTouchModeReset != null) {
-                                removeCallbacks(mTouchModeReset);
-                            }
-
-                            mTouchModeReset = new Runnable() {
-                                @Override
-                                public void run() {
-                                    mTouchMode = TOUCH_MODE_REST;
-
-                                    setPressed(false);
-                                    child.setPressed(false);
-
-                                    if (!mDataChanged) {
-                                        performClick.run();
-                                    }
-
-                                    mTouchModeReset = null;
-                                }
-                            };
-
-                            postDelayed(mTouchModeReset,
-                                    ViewConfiguration.getPressedStateDuration());
-                        } else {
-                            mTouchMode = TOUCH_MODE_REST;
-                            updateSelectorState();
-                        }
-                    } else if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {
-                        performClick.run();
-                    }
-                }
-
-                mTouchMode = TOUCH_MODE_REST;
-
-                finishSmoothScrolling();
-                updateSelectorState();
-
-                break;
-            }
-
-            case TOUCH_MODE_DRAGGING:
-                if (contentFits()) {
-                    mTouchMode = TOUCH_MODE_REST;
-                    reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
-                    break;
-                }
-
-                mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
-
-                final float velocity;
-                if (mIsVertical) {
-                    velocity = VelocityTrackerCompat.getYVelocity(mVelocityTracker,
-                            mActivePointerId);
-                } else {
-                    velocity = VelocityTrackerCompat.getXVelocity(mVelocityTracker,
-                            mActivePointerId);
-                }
-
-                if (Math.abs(velocity) >= mFlingVelocity) {
-                    mTouchMode = TOUCH_MODE_FLINGING;
-                    reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
-
-                    mScroller.fling(0, 0,
-                                    (int) (mIsVertical ? 0 : velocity),
-                                    (int) (mIsVertical ? velocity : 0),
-                                    (mIsVertical ? 0 : Integer.MIN_VALUE),
-                                    (mIsVertical ? 0 : Integer.MAX_VALUE),
-                                    (mIsVertical ? Integer.MIN_VALUE : 0),
-                                    (mIsVertical ? Integer.MAX_VALUE : 0));
-
-                    mLastTouchPos = 0;
-                    needsInvalidate = true;
-                } else {
-                    mTouchMode = TOUCH_MODE_REST;
-                    reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
-                }
-
-                break;
-
-            case TOUCH_MODE_OVERSCROLL:
-                mTouchMode = TOUCH_MODE_REST;
-                reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
-                break;
-            }
-
-            cancelCheckForTap();
-            cancelCheckForLongPress();
-            setPressed(false);
-
-            if (mStartEdge != null && mEndEdge != null) {
-                needsInvalidate |= mStartEdge.onRelease() | mEndEdge.onRelease();
-            }
-
-            recycleVelocityTracker();
-
-            break;
-        }
-        }
-
-        if (needsInvalidate) {
-            ViewCompat.postInvalidateOnAnimation(this);
-        }
-
-        return true;
-    }
-
-    @Override
-    public void onTouchModeChanged(boolean isInTouchMode) {
-        if (isInTouchMode) {
-            // Get rid of the selection when we enter touch mode
-            hideSelector();
-
-            // Layout, but only if we already have done so previously.
-            // (Otherwise may clobber a LAYOUT_SYNC layout that was requested to restore
-            // state.)
-            if (getWidth() > 0 && getHeight() > 0 && getChildCount() > 0) {
-                layoutChildren();
-            }
-
-            updateSelectorState();
-        } else {
-            final int touchMode = mTouchMode;
-            if (touchMode == TOUCH_MODE_OVERSCROLL) {
-                finishSmoothScrolling();
-                if (mOverScroll != 0) {
-                    mOverScroll = 0;
-                    finishEdgeGlows();
-                    invalidate();
-                }
-            }
-        }
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        return handleKeyEvent(keyCode, 1, event);
-    }
-
-    @Override
-    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
-        return handleKeyEvent(keyCode, repeatCount, event);
-    }
-
-    @Override
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
-        return handleKeyEvent(keyCode, 1, event);
-    }
-
-    @Override
-    public void sendAccessibilityEvent(int eventType) {
-        // Since this class calls onScrollChanged even if the mFirstPosition and the
-        // child count have not changed we will avoid sending duplicate accessibility
-        // events.
-        if (eventType == AccessibilityEvent.TYPE_VIEW_SCROLLED) {
-            final int firstVisiblePosition = getFirstVisiblePosition();
-            final int lastVisiblePosition = getLastVisiblePosition();
-
-            if (mLastAccessibilityScrollEventFromIndex == firstVisiblePosition
-                    && mLastAccessibilityScrollEventToIndex == lastVisiblePosition) {
-                return;
-            } else {
-                mLastAccessibilityScrollEventFromIndex = firstVisiblePosition;
-                mLastAccessibilityScrollEventToIndex = lastVisiblePosition;
-            }
-        }
-
-        super.sendAccessibilityEvent(eventType);
-    }
-
-    @Override
-    @TargetApi(14)
-    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(event);
-        event.setClassName(TwoWayView.class.getName());
-    }
-
-    @Override
-    @TargetApi(14)
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        info.setClassName(TwoWayView.class.getName());
-
-        AccessibilityNodeInfoCompat infoCompat = new AccessibilityNodeInfoCompat(info);
-
-        if (isEnabled()) {
-            if (getFirstVisiblePosition() > 0) {
-                infoCompat.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
-            }
-
-            if (getLastVisiblePosition() < getCount() - 1) {
-                infoCompat.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
-            }
-        }
-    }
-
-    @Override
-    @TargetApi(16)
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
-        if (super.performAccessibilityAction(action, arguments)) {
-            return true;
-        }
-
-        switch (action) {
-        case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD:
-            if (isEnabled() && getLastVisiblePosition() < getCount() - 1) {
-                // TODO: Use some form of smooth scroll instead
-                scrollListItemsBy(getAvailableSize());
-                return true;
-            }
-            return false;
-
-        case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD:
-            if (isEnabled() && mFirstPosition > 0) {
-                // TODO: Use some form of smooth scroll instead
-                scrollListItemsBy(-getAvailableSize());
-                return true;
-            }
-            return false;
-        }
-
-        return false;
-    }
-
-    /**
-     * Return true if child is an ancestor of parent, (or equal to the parent).
-     */
-    private boolean isViewAncestorOf(View child, View parent) {
-        if (child == parent) {
-            return true;
-        }
-
-        final ViewParent theParent = child.getParent();
-
-        return (theParent instanceof ViewGroup) &&
-                 isViewAncestorOf((View) theParent, parent);
-    }
-
-    private void forceValidFocusDirection(int direction) {
-        if (mIsVertical && direction != View.FOCUS_UP && direction != View.FOCUS_DOWN)  {
-            throw new IllegalArgumentException("Focus direction must be one of"
-                    + " {View.FOCUS_UP, View.FOCUS_DOWN} for vertical orientation");
-        } else if (!mIsVertical && direction != View.FOCUS_LEFT && direction != View.FOCUS_RIGHT)  {
-            throw new IllegalArgumentException("Focus direction must be one of"
-                    + " {View.FOCUS_LEFT, View.FOCUS_RIGHT} for vertical orientation");
-        }
-    }
-
-    private void forceValidInnerFocusDirection(int direction) {
-        if (mIsVertical && direction != View.FOCUS_LEFT && direction != View.FOCUS_RIGHT)  {
-            throw new IllegalArgumentException("Direction must be one of"
-                    + " {View.FOCUS_LEFT, View.FOCUS_RIGHT} for vertical orientation");
-        } else if (!mIsVertical && direction != View.FOCUS_UP && direction != View.FOCUS_DOWN)  {
-            throw new IllegalArgumentException("direction must be one of"
-                    + " {View.FOCUS_UP, View.FOCUS_DOWN} for horizontal orientation");
-        }
-    }
-
-    /**
-     * Scrolls up or down by the number of items currently present on screen.
-     *
-     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN} or
-     *        {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT} depending on the
-     *        current view orientation.
-     *
-     * @return whether selection was moved
-     */
-    boolean pageScroll(int direction) {
-        forceValidFocusDirection(direction);
-
-        boolean forward = false;
-        int nextPage = -1;
-
-        if (direction == View.FOCUS_UP || direction == View.FOCUS_LEFT) {
-            nextPage = Math.max(0, mSelectedPosition - getChildCount() - 1);
-        } else if (direction == View.FOCUS_DOWN || direction == View.FOCUS_RIGHT) {
-            nextPage = Math.min(mItemCount - 1, mSelectedPosition + getChildCount() - 1);
-            forward = true;
-        }
-
-        if (nextPage < 0) {
-            return false;
-        }
-
-        final int position = lookForSelectablePosition(nextPage, forward);
-        if (position >= 0) {
-            mLayoutMode = LAYOUT_SPECIFIC;
-            mSpecificStart = getStartEdge() + getFadingEdgeLength();
-
-            if (forward && position > mItemCount - getChildCount()) {
-                mLayoutMode = LAYOUT_FORCE_BOTTOM;
-            }
-
-            if (!forward && position < getChildCount()) {
-                mLayoutMode = LAYOUT_FORCE_TOP;
-            }
-
-            setSelectionInt(position);
-            invokeOnItemScrollListener();
-
-            if (!awakenScrollbarsInternal()) {
-                invalidate();
-            }
-
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Go to the last or first item if possible (not worrying about panning across or navigating
-     * within the internal focus of the currently selected item.)
-     *
-     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN} or
-     *        {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT} depending on the
-     *        current view orientation.
-     *
-     * @return whether selection was moved
-     */
-    boolean fullScroll(int direction) {
-        forceValidFocusDirection(direction);
-
-        boolean moved = false;
-        if (direction == View.FOCUS_UP || direction == View.FOCUS_LEFT) {
-            if (mSelectedPosition != 0) {
-                int position = lookForSelectablePosition(0, true);
-                if (position >= 0) {
-                    mLayoutMode = LAYOUT_FORCE_TOP;
-                    setSelectionInt(position);
-                    invokeOnItemScrollListener();
-                }
-
-                moved = true;
-            }
-        } else if (direction == View.FOCUS_DOWN || direction == View.FOCUS_RIGHT) {
-            if (mSelectedPosition < mItemCount - 1) {
-                int position = lookForSelectablePosition(mItemCount - 1, true);
-                if (position >= 0) {
-                    mLayoutMode = LAYOUT_FORCE_BOTTOM;
-                    setSelectionInt(position);
-                    invokeOnItemScrollListener();
-                }
-
-                moved = true;
-            }
-        }
-
-        if (moved && !awakenScrollbarsInternal()) {
-            awakenScrollbarsInternal();
-            invalidate();
-        }
-
-        return moved;
-    }
-
-    /**
-     * To avoid horizontal/vertical focus searches changing the selected item,
-     * we manually focus search within the selected item (as applicable), and
-     * prevent focus from jumping to something within another item.
-     *
-     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN} or
-     *        {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT} depending on the
-     *        current view orientation.
-     *
-     * @return Whether this consumes the key event.
-     */
-    private boolean handleFocusWithinItem(int direction) {
-        forceValidInnerFocusDirection(direction);
-
-        final int numChildren = getChildCount();
-
-        if (mItemsCanFocus && numChildren > 0 && mSelectedPosition != INVALID_POSITION) {
-            final View selectedView = getSelectedView();
-
-            if (selectedView != null && selectedView.hasFocus() &&
-                    selectedView instanceof ViewGroup) {
-
-                final View currentFocus = selectedView.findFocus();
-                final View nextFocus = FocusFinder.getInstance().findNextFocus(
-                        (ViewGroup) selectedView, currentFocus, direction);
-
-                if (nextFocus != null) {
-                    // Do the math to get interesting rect in next focus' coordinates
-                    currentFocus.getFocusedRect(mTempRect);
-                    offsetDescendantRectToMyCoords(currentFocus, mTempRect);
-                    offsetRectIntoDescendantCoords(nextFocus, mTempRect);
-
-                    if (nextFocus.requestFocus(direction, mTempRect)) {
-                        return true;
-                    }
-                }
-
-                // We are blocking the key from being handled (by returning true)
-                // if the global result is going to be some other view within this
-                // list. This is to achieve the overall goal of having horizontal/vertical
-                // d-pad navigation remain in the current item depending on the current
-                // orientation in this view.
-                final View globalNextFocus = FocusFinder.getInstance().findNextFocus(
-                        (ViewGroup) getRootView(), currentFocus, direction);
-
-                if (globalNextFocus != null) {
-                    return isViewAncestorOf(globalNextFocus, this);
-                }
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Scrolls to the next or previous item if possible.
-     *
-     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN} or
-     *        {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT} depending on the
-     *        current view orientation.
-     *
-     * @return whether selection was moved
-     */
-    private boolean arrowScroll(int direction) {
-        forceValidFocusDirection(direction);
-
-        try {
-            mInLayout = true;
-
-            final boolean handled = arrowScrollImpl(direction);
-            if (handled) {
-                playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction));
-            }
-
-            return handled;
-        } finally {
-            mInLayout = false;
-        }
-    }
-
-    /**
-     * When selection changes, it is possible that the previously selected or the
-     * next selected item will change its size.  If so, we need to offset some folks,
-     * and re-layout the items as appropriate.
-     *
-     * @param selectedView The currently selected view (before changing selection).
-     *   should be <code>null</code> if there was no previous selection.
-     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN} or
-     *        {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT} depending on the
-     *        current view orientation.
-     * @param newSelectedPosition The position of the next selection.
-     * @param newFocusAssigned whether new focus was assigned.  This matters because
-     *        when something has focus, we don't want to show selection (ugh).
-     */
-    private void handleNewSelectionChange(View selectedView, int direction, int newSelectedPosition,
-            boolean newFocusAssigned) {
-        forceValidFocusDirection(direction);
-
-        if (newSelectedPosition == INVALID_POSITION) {
-            throw new IllegalArgumentException("newSelectedPosition needs to be valid");
-        }
-
-        // Whether or not we are moving down/right or up/left, we want to preserve the
-        // top/left of whatever view is at the start:
-        // - moving down/right: the view that had selection
-        // - moving up/left: the view that is getting selection
-        final int selectedIndex = mSelectedPosition - mFirstPosition;
-        final int nextSelectedIndex = newSelectedPosition - mFirstPosition;
-        int startViewIndex, endViewIndex;
-        boolean topSelected = false;
-        View startView;
-        View endView;
-
-        if (direction == View.FOCUS_UP || direction == View.FOCUS_LEFT) {
-            startViewIndex = nextSelectedIndex;
-            endViewIndex = selectedIndex;
-            startView = getChildAt(startViewIndex);
-            endView = selectedView;
-            topSelected = true;
-        } else {
-            startViewIndex = selectedIndex;
-            endViewIndex = nextSelectedIndex;
-            startView = selectedView;
-            endView = getChildAt(endViewIndex);
-        }
-
-        final int numChildren = getChildCount();
-
-        // start with top view: is it changing size?
-        if (startView != null) {
-            startView.setSelected(!newFocusAssigned && topSelected);
-            measureAndAdjustDown(startView, startViewIndex, numChildren);
-        }
-
-        // is the bottom view changing size?
-        if (endView != null) {
-            endView.setSelected(!newFocusAssigned && !topSelected);
-            measureAndAdjustDown(endView, endViewIndex, numChildren);
-        }
-    }
-
-    /**
-     * Re-measure a child, and if its height changes, lay it out preserving its
-     * top, and adjust the children below it appropriately.
-     *
-     * @param child The child
-     * @param childIndex The view group index of the child.
-     * @param numChildren The number of children in the view group.
-     */
-    private void measureAndAdjustDown(View child, int childIndex, int numChildren) {
-        int oldSize = getChildSize(child);
-        measureChild(child);
-
-        if (getChildMeasuredSize(child) == oldSize) {
-            return;
-        }
-
-        // lay out the view, preserving its top
-        relayoutMeasuredChild(child);
-
-        // adjust views below appropriately
-        final int sizeDelta = getChildMeasuredSize(child) - oldSize;
-        for (int i = childIndex + 1; i < numChildren; i++) {
-            getChildAt(i).offsetTopAndBottom(sizeDelta);
-        }
-    }
-
-    /**
-     * Do an arrow scroll based on focus searching.  If a new view is
-     * given focus, return the selection delta and amount to scroll via
-     * an {@link ArrowScrollFocusResult}, otherwise, return null.
-     *
-     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN} or
-     *        {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT} depending on the
-     *        current view orientation.
-     *
-     * @return The result if focus has changed, or <code>null</code>.
-     */
-    private ArrowScrollFocusResult arrowScrollFocused(final int direction) {
-        forceValidFocusDirection(direction);
-
-        final View selectedView = getSelectedView();
-        final View newFocus;
-        final int searchPoint;
-
-        if (selectedView != null && selectedView.hasFocus()) {
-            View oldFocus = selectedView.findFocus();
-            newFocus = FocusFinder.getInstance().findNextFocus(this, oldFocus, direction);
-        } else {
-            if (direction == View.FOCUS_DOWN || direction == View.FOCUS_RIGHT) {
-                boolean fadingEdgeShowing = (mFirstPosition > 0);
-                final int start = getStartEdge() +
-                        (fadingEdgeShowing ? getArrowScrollPreviewLength() : 0);
-
-                final int selectedStart;
-                if (selectedView != null) {
-                    selectedStart = getChildStartEdge(selectedView);
-                } else {
-                    selectedStart = start;
-                }
-
-                searchPoint = Math.max(selectedStart, start);
-            } else {
-                final boolean fadingEdgeShowing =
-                        (mFirstPosition + getChildCount() - 1) < mItemCount;
-                final int end = getEndEdge() - (fadingEdgeShowing ? getArrowScrollPreviewLength() : 0);
-
-                final int selectedEnd;
-                if (selectedView != null) {
-                    selectedEnd = getChildEndEdge(selectedView);
-                } else {
-                    selectedEnd = end;
-                }
-
-                searchPoint = Math.min(selectedEnd, end);
-            }
-
-            final int x = (mIsVertical ? 0 : searchPoint);
-            final int y = (mIsVertical ? searchPoint : 0);
-            mTempRect.set(x, y, x, y);
-
-            newFocus = FocusFinder.getInstance().findNextFocusFromRect(this, mTempRect, direction);
-        }
-
-        if (newFocus != null) {
-            final int positionOfNewFocus = positionOfNewFocus(newFocus);
-
-            // If the focus change is in a different new position, make sure
-            // we aren't jumping over another selectable position.
-            if (mSelectedPosition != INVALID_POSITION && positionOfNewFocus != mSelectedPosition) {
-                final int selectablePosition = lookForSelectablePositionOnScreen(direction);
-
-                final boolean movingForward =
-                        (direction == View.FOCUS_DOWN || direction == View.FOCUS_RIGHT);
-                final boolean movingBackward =
-                        (direction == View.FOCUS_UP || direction == View.FOCUS_LEFT);
-
-                if (selectablePosition != INVALID_POSITION &&
-                        ((movingForward && selectablePosition < positionOfNewFocus) ||
-                         (movingBackward && selectablePosition > positionOfNewFocus))) {
-                    return null;
-                }
-            }
-
-            int focusScroll = amountToScrollToNewFocus(direction, newFocus, positionOfNewFocus);
-
-            final int maxScrollAmount = getMaxScrollAmount();
-            if (focusScroll < maxScrollAmount) {
-                // Not moving too far, safe to give next view focus
-                newFocus.requestFocus(direction);
-                mArrowScrollFocusResult.populate(positionOfNewFocus, focusScroll);
-                return mArrowScrollFocusResult;
-            } else if (distanceToView(newFocus) < maxScrollAmount) {
-                // Case to consider:
-                // Too far to get entire next focusable on screen, but by going
-                // max scroll amount, we are getting it at least partially in view,
-                // so give it focus and scroll the max amount.
-                newFocus.requestFocus(direction);
-                mArrowScrollFocusResult.populate(positionOfNewFocus, maxScrollAmount);
-                return mArrowScrollFocusResult;
-            }
-        }
-
-        return null;
-    }
-
-    /**
-     * @return The maximum amount a list view will scroll in response to
-     *   an arrow event.
-     */
-    public int getMaxScrollAmount() {
-        return (int) (MAX_SCROLL_FACTOR * getSize());
-    }
-
-    /**
-     * @return The amount to preview next items when arrow scrolling.
-     */
-    private int getArrowScrollPreviewLength() {
-        return mItemMargin + Math.max(MIN_SCROLL_PREVIEW_PIXELS, getFadingEdgeLength());
-    }
-
-    /**
-     * @param newFocus The view that would have focus.
-     * @return the position that contains newFocus
-     */
-    private int positionOfNewFocus(View newFocus) {
-        final int numChildren = getChildCount();
-
-        for (int i = 0; i < numChildren; i++) {
-            final View child = getChildAt(i);
-            if (isViewAncestorOf(newFocus, child)) {
-                return mFirstPosition + i;
-            }
-        }
-
-        throw new IllegalArgumentException("newFocus is not a child of any of the"
-                + " children of the list!");
-    }
-
-    /**
-     * Handle an arrow scroll going up or down.  Take into account whether items are selectable,
-     * whether there are focusable items, etc.
-     *
-     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN} or
-     *        {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT} depending on the
-     *        current view orientation.
-     *
-     * @return Whether any scrolling, selection or focus change occurred.
-     */
-    private boolean arrowScrollImpl(int direction) {
-        forceValidFocusDirection(direction);
-
-        if (getChildCount() <= 0) {
-            return false;
-        }
-
-        View selectedView = getSelectedView();
-        int selectedPos = mSelectedPosition;
-
-        int nextSelectedPosition = lookForSelectablePositionOnScreen(direction);
-        int amountToScroll = amountToScroll(direction, nextSelectedPosition);
-
-        // If we are moving focus, we may OVERRIDE the default behaviour
-        final ArrowScrollFocusResult focusResult = (mItemsCanFocus ? arrowScrollFocused(direction) : null);
-        if (focusResult != null) {
-            nextSelectedPosition = focusResult.getSelectedPosition();
-            amountToScroll = focusResult.getAmountToScroll();
-        }
-
-        boolean needToRedraw = (focusResult != null);
-        if (nextSelectedPosition != INVALID_POSITION) {
-            handleNewSelectionChange(selectedView, direction, nextSelectedPosition, focusResult != null);
-
-            setSelectedPositionInt(nextSelectedPosition);
-            setNextSelectedPositionInt(nextSelectedPosition);
-
-            selectedView = getSelectedView();
-            selectedPos = nextSelectedPosition;
-
-            if (mItemsCanFocus && focusResult == null) {
-                // There was no new view found to take focus, make sure we
-                // don't leave focus with the old selection.
-                final View focused = getFocusedChild();
-                if (focused != null) {
-                    focused.clearFocus();
-                }
-            }
-
-            needToRedraw = true;
-            checkSelectionChanged();
-        }
-
-        if (amountToScroll > 0) {
-            scrollListItemsBy(direction == View.FOCUS_UP || direction == View.FOCUS_LEFT ?
-                    amountToScroll : -amountToScroll);
-            needToRedraw = true;
-        }
-
-        // If we didn't find a new focusable, make sure any existing focused
-        // item that was panned off screen gives up focus.
-        if (mItemsCanFocus && focusResult == null &&
-                selectedView != null && selectedView.hasFocus()) {
-            final View focused = selectedView.findFocus();
-            if (!isViewAncestorOf(focused, this) || distanceToView(focused) > 0) {
-                focused.clearFocus();
-            }
-        }
-
-        // If the current selection is panned off, we need to remove the selection
-        if (nextSelectedPosition == INVALID_POSITION && selectedView != null
-                && !isViewAncestorOf(selectedView, this)) {
-            selectedView = null;
-            hideSelector();
-
-            // But we don't want to set the ressurect position (that would make subsequent
-            // unhandled key events bring back the item we just scrolled off)
-            mResurrectToPosition = INVALID_POSITION;
-        }
-
-        if (needToRedraw) {
-            if (selectedView != null) {
-                positionSelector(selectedPos, selectedView);
-                mSelectedStart = getChildStartEdge(selectedView);
-            }
-
-            if (!awakenScrollbarsInternal()) {
-                invalidate();
-            }
-
-            invokeOnItemScrollListener();
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Determine how much we need to scroll in order to get the next selected view
-     * visible. The amount is capped at {@link #getMaxScrollAmount()}.
-     *
-     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN} or
-     *        {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT} depending on the
-     *        current view orientation.
-     * @param nextSelectedPosition The position of the next selection, or
-     *        {@link #INVALID_POSITION} if there is no next selectable position
-     *
-     * @return The amount to scroll. Note: this is always positive!  Direction
-     *         needs to be taken into account when actually scrolling.
-     */
-    private int amountToScroll(int direction, int nextSelectedPosition) {
-        forceValidFocusDirection(direction);
-
-        final int numChildren = getChildCount();
-
-        if (direction == View.FOCUS_DOWN || direction == View.FOCUS_RIGHT) {
-            final int end = getEndEdge();
-
-            int indexToMakeVisible = numChildren - 1;
-            if (nextSelectedPosition != INVALID_POSITION) {
-                indexToMakeVisible = nextSelectedPosition - mFirstPosition;
-            }
-
-            final int positionToMakeVisible = mFirstPosition + indexToMakeVisible;
-            final View viewToMakeVisible = getChildAt(indexToMakeVisible);
-
-            int goalEnd = end;
-            if (positionToMakeVisible < mItemCount - 1) {
-                goalEnd -= getArrowScrollPreviewLength();
-            }
-
-            final int viewToMakeVisibleStart = getChildStartEdge(viewToMakeVisible);
-            final int viewToMakeVisibleEnd = getChildEndEdge(viewToMakeVisible);
-
-            if (viewToMakeVisibleEnd <= goalEnd) {
-                // Target item is fully visible
-                return 0;
-            }
-
-            if (nextSelectedPosition != INVALID_POSITION &&
-                    (goalEnd - viewToMakeVisibleStart) >= getMaxScrollAmount()) {
-                // Item already has enough of it visible, changing selection is good enough
-                return 0;
-            }
-
-            int amountToScroll = (viewToMakeVisibleEnd - goalEnd);
-
-            if (mFirstPosition + numChildren == mItemCount) {
-                final int lastChildEnd = getChildEndEdge(getChildAt(numChildren - 1));
-
-                // Last is last in list -> Make sure we don't scroll past it
-                final int max = lastChildEnd - end;
-                amountToScroll = Math.min(amountToScroll, max);
-            }
-
-            return Math.min(amountToScroll, getMaxScrollAmount());
-        } else {
-            final int start = getStartEdge();
-
-            int indexToMakeVisible = 0;
-            if (nextSelectedPosition != INVALID_POSITION) {
-                indexToMakeVisible = nextSelectedPosition - mFirstPosition;
-            }
-
-            final int positionToMakeVisible = mFirstPosition + indexToMakeVisible;
-            final View viewToMakeVisible = getChildAt(indexToMakeVisible);
-
-            int goalStart = start;
-            if (positionToMakeVisible > 0) {
-                goalStart += getArrowScrollPreviewLength();
-            }
-
-            final int viewToMakeVisibleStart = getChildStartEdge(viewToMakeVisible);
-            final int viewToMakeVisibleEnd = getChildEndEdge(viewToMakeVisible);
-
-            if (viewToMakeVisibleStart >= goalStart) {
-                // Item is fully visible
-                return 0;
-            }
-
-            if (nextSelectedPosition != INVALID_POSITION &&
-                    (viewToMakeVisibleEnd - goalStart) >= getMaxScrollAmount()) {
-                // Item already has enough of it visible, changing selection is good enough
-                return 0;
-            }
-
-            int amountToScroll = (goalStart - viewToMakeVisibleStart);
-
-            if (mFirstPosition == 0) {
-                final int firstChildStart = getChildStartEdge(getChildAt(0));
-
-                // First is first in list -> make sure we don't scroll past it
-                final int max = start - firstChildStart;
-                amountToScroll = Math.min(amountToScroll,  max);
-            }
-
-            return Math.min(amountToScroll, getMaxScrollAmount());
-        }
-    }
-
-    /**
-     * Determine how much we need to scroll in order to get newFocus in view.
-     *
-     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN} or
-     *        {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT} depending on the
-     *        current view orientation.
-     * @param newFocus The view that would take focus.
-     * @param positionOfNewFocus The position of the list item containing newFocus
-     *
-     * @return The amount to scroll. Note: this is always positive! Direction
-     *   needs to be taken into account when actually scrolling.
-     */
-    private int amountToScrollToNewFocus(int direction, View newFocus, int positionOfNewFocus) {
-        forceValidFocusDirection(direction);
-
-        int amountToScroll = 0;
-
-        newFocus.getDrawingRect(mTempRect);
-        offsetDescendantRectToMyCoords(newFocus, mTempRect);
-
-        if (direction == View.FOCUS_UP || direction == View.FOCUS_LEFT) {
-            final int start = getStartEdge();
-            final int newFocusStart = (mIsVertical ? mTempRect.top : mTempRect.left);
-
-            if (newFocusStart < start) {
-                amountToScroll = start - newFocusStart;
-                if (positionOfNewFocus > 0) {
-                    amountToScroll += getArrowScrollPreviewLength();
-                }
-            }
-        } else {
-            final int end = getEndEdge();
-            final int newFocusEnd = (mIsVertical ? mTempRect.bottom : mTempRect.right);
-
-            if (newFocusEnd > end) {
-                amountToScroll = newFocusEnd - end;
-                if (positionOfNewFocus < mItemCount - 1) {
-                    amountToScroll += getArrowScrollPreviewLength();
-                }
-            }
-        }
-
-        return amountToScroll;
-    }
-
-    /**
-     * Determine the distance to the nearest edge of a view in a particular
-     * direction.
-     *
-     * @param descendant A descendant of this list.
-     * @return The distance, or 0 if the nearest edge is already on screen.
-     */
-    private int distanceToView(View descendant) {
-        descendant.getDrawingRect(mTempRect);
-        offsetDescendantRectToMyCoords(descendant, mTempRect);
-
-        final int start = getStartEdge();
-        final int end = getEndEdge();
-
-        final int viewStart = (mIsVertical ? mTempRect.top : mTempRect.left);
-        final int viewEnd = (mIsVertical ? mTempRect.bottom : mTempRect.right);
-
-        int distance = 0;
-        if (viewEnd < start) {
-            distance = start - viewEnd;
-        } else if (viewStart > end) {
-            distance = viewStart - end;
-        }
-
-        return distance;
-    }
-
-    private boolean handleKeyScroll(KeyEvent event, int count, int direction) {
-        boolean handled = false;
-
-        if (KeyEventCompat.hasNoModifiers(event)) {
-            handled = resurrectSelectionIfNeeded();
-            if (!handled) {
-                while (count-- > 0) {
-                    if (arrowScroll(direction)) {
-                        handled = true;
-                    } else {
-                        break;
-                    }
-                }
-            }
-        } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_ALT_ON)) {
-            handled = resurrectSelectionIfNeeded() || fullScroll(direction);
-        }
-
-        return handled;
-    }
-
-    private boolean handleKeyEvent(int keyCode, int count, KeyEvent event) {
-        if (mAdapter == null || !mIsAttached) {
-            return false;
-        }
-
-        if (mDataChanged) {
-            layoutChildren();
-        }
-
-        boolean handled = false;
-        final int action = event.getAction();
-
-        if (action != KeyEvent.ACTION_UP) {
-            switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_UP:
-                if (mIsVertical) {
-                    handled = handleKeyScroll(event, count, View.FOCUS_UP);
-                } else if (KeyEventCompat.hasNoModifiers(event)) {
-                    handled = handleFocusWithinItem(View.FOCUS_UP);
-                }
-                break;
-
-            case KeyEvent.KEYCODE_DPAD_DOWN: {
-                if (mIsVertical) {
-                    handled = handleKeyScroll(event, count, View.FOCUS_DOWN);
-                } else if (KeyEventCompat.hasNoModifiers(event)) {
-                    handled = handleFocusWithinItem(View.FOCUS_DOWN);
-                }
-                break;
-            }
-
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-                if (!mIsVertical) {
-                    handled = handleKeyScroll(event, count, View.FOCUS_LEFT);
-                } else if (KeyEventCompat.hasNoModifiers(event)) {
-                    handled = handleFocusWithinItem(View.FOCUS_LEFT);
-                }
-                break;
-
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                if (!mIsVertical) {
-                    handled = handleKeyScroll(event, count, View.FOCUS_RIGHT);
-                } else if (KeyEventCompat.hasNoModifiers(event)) {
-                    handled = handleFocusWithinItem(View.FOCUS_RIGHT);
-                }
-                break;
-
-            case KeyEvent.KEYCODE_DPAD_CENTER:
-            case KeyEvent.KEYCODE_ENTER:
-                if (KeyEventCompat.hasNoModifiers(event)) {
-                    handled = resurrectSelectionIfNeeded();
-                    if (!handled
-                            && event.getRepeatCount() == 0 && getChildCount() > 0) {
-                        keyPressed();
-                        handled = true;
-                    }
-                }
-                break;
-
-            case KeyEvent.KEYCODE_SPACE:
-                if (KeyEventCompat.hasNoModifiers(event)) {
-                    handled = resurrectSelectionIfNeeded() ||
-                            pageScroll(mIsVertical ? View.FOCUS_DOWN : View.FOCUS_RIGHT);
-                } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) {
-                    handled = resurrectSelectionIfNeeded() ||
-                            fullScroll(mIsVertical ? View.FOCUS_UP : View.FOCUS_LEFT);
-                }
-
-                handled = true;
-                break;
-
-            case KeyEvent.KEYCODE_PAGE_UP:
-                if (KeyEventCompat.hasNoModifiers(event)) {
-                    handled = resurrectSelectionIfNeeded() ||
-                            pageScroll(mIsVertical ? View.FOCUS_UP : View.FOCUS_LEFT);
-                } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_ALT_ON)) {
-                    handled = resurrectSelectionIfNeeded() ||
-                            fullScroll(mIsVertical ? View.FOCUS_UP : View.FOCUS_LEFT);
-                }
-                break;
-
-            case KeyEvent.KEYCODE_PAGE_DOWN:
-                if (KeyEventCompat.hasNoModifiers(event)) {
-                    handled = resurrectSelectionIfNeeded() ||
-                            pageScroll(mIsVertical ? View.FOCUS_DOWN : View.FOCUS_RIGHT);
-                } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_ALT_ON)) {
-                    handled = resurrectSelectionIfNeeded() ||
-                            fullScroll(mIsVertical ? View.FOCUS_DOWN : View.FOCUS_RIGHT);
-                }
-                break;
-
-            case KeyEvent.KEYCODE_MOVE_HOME:
-                if (KeyEventCompat.hasNoModifiers(event)) {
-                    handled = resurrectSelectionIfNeeded() ||
-                            fullScroll(mIsVertical ? View.FOCUS_UP : View.FOCUS_LEFT);
-                }
-                break;
-
-            case KeyEvent.KEYCODE_MOVE_END:
-                if (KeyEventCompat.hasNoModifiers(event)) {
-                    handled = resurrectSelectionIfNeeded() ||
-                            fullScroll(mIsVertical ? View.FOCUS_DOWN : View.FOCUS_RIGHT);
-                }
-                break;
-            }
-        }
-
-        if (handled) {
-            return true;
-        }
-
-        switch (action) {
-        case KeyEvent.ACTION_DOWN:
-            return super.onKeyDown(keyCode, event);
-
-        case KeyEvent.ACTION_UP:
-            if (!isEnabled()) {
-                return true;
-            }
-
-            if (isClickable() && isPressed() &&
-                    mSelectedPosition >= 0 && mAdapter != null &&
-                    mSelectedPosition < mAdapter.getCount()) {
-
-                final View child = getChildAt(mSelectedPosition - mFirstPosition);
-                if (child != null) {
-                    performItemClick(child, mSelectedPosition, mSelectedRowId);
-                    child.setPressed(false);
-                }
-
-                setPressed(false);
-                return true;
-            }
-
-            return false;
-
-        case KeyEvent.ACTION_MULTIPLE:
-            return super.onKeyMultiple(keyCode, count, event);
-
-        default:
-            return false;
-        }
-    }
-
-    private void initOrResetVelocityTracker() {
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        } else {
-            mVelocityTracker.clear();
-        }
-    }
-
-    private void initVelocityTrackerIfNotExists() {
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-    }
-
-    private void recycleVelocityTracker() {
-        if (mVelocityTracker != null) {
-            mVelocityTracker.recycle();
-            mVelocityTracker = null;
-        }
-    }
-
-    /**
-     * Notify our scroll listener (if there is one) of a change in scroll state
-     */
-    private void invokeOnItemScrollListener() {
-        if (mOnScrollListener != null) {
-            mOnScrollListener.onScroll(this, mFirstPosition, getChildCount(), mItemCount);
-        }
-
-        // Dummy values, View's implementation does not use these.
-        onScrollChanged(0, 0, 0, 0);
-    }
-
-    private void reportScrollStateChange(int newState) {
-        if (newState == mLastScrollState) {
-            return;
-        }
-
-        if (mOnScrollListener != null) {
-            mLastScrollState = newState;
-            mOnScrollListener.onScrollStateChanged(this, newState);
-        }
-    }
-
-    private boolean maybeStartScrolling(int delta) {
-        final boolean isOverScroll = (mOverScroll != 0);
-        if (Math.abs(delta) <= mTouchSlop && !isOverScroll) {
-            return false;
-        }
-
-        if (isOverScroll) {
-            mTouchMode = TOUCH_MODE_OVERSCROLL;
-        } else {
-            mTouchMode = TOUCH_MODE_DRAGGING;
-        }
-
-        // Time to start stealing events! Once we've stolen them, don't
-        // let anyone steal from us.
-        final ViewParent parent = getParent();
-        if (parent != null) {
-            parent.requestDisallowInterceptTouchEvent(true);
-        }
-
-        cancelCheckForLongPress();
-
-        setPressed(false);
-        View motionView = getChildAt(mMotionPosition - mFirstPosition);
-        if (motionView != null) {
-            motionView.setPressed(false);
-        }
-
-        reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
-
-        return true;
-    }
-
-    private void maybeScroll(int delta) {
-        if (mTouchMode == TOUCH_MODE_DRAGGING) {
-            handleDragChange(delta);
-        } else if (mTouchMode == TOUCH_MODE_OVERSCROLL) {
-            handleOverScrollChange(delta);
-        }
-    }
-
-    private void handleDragChange(int delta) {
-        // Time to start stealing events! Once we've stolen them, don't
-        // let anyone steal from us.
-        final ViewParent parent = getParent();
-        if (parent != null) {
-            parent.requestDisallowInterceptTouchEvent(true);
-        }
-
-        final int motionIndex;
-        if (mMotionPosition >= 0) {
-            motionIndex = mMotionPosition - mFirstPosition;
-        } else {
-            // If we don't have a motion position that we can reliably track,
-            // pick something in the middle to make a best guess at things below.
-            motionIndex = getChildCount() / 2;
-        }
-
-        int motionViewPrevStart = 0;
-        View motionView = this.getChildAt(motionIndex);
-        if (motionView != null) {
-            motionViewPrevStart = getChildStartEdge(motionView);
-        }
-
-        boolean atEdge = scrollListItemsBy(delta);
-
-        motionView = this.getChildAt(motionIndex);
-        if (motionView != null) {
-            final int motionViewRealStart = getChildStartEdge(motionView);
-
-            if (atEdge) {
-                final int overscroll = -delta - (motionViewRealStart - motionViewPrevStart);
-                updateOverScrollState(delta, overscroll);
-            }
-        }
-    }
-
-    private void updateOverScrollState(int delta, int overscroll) {
-        overScrollByInternal((mIsVertical ? 0 : overscroll),
-                             (mIsVertical ? overscroll : 0),
-                             (mIsVertical ? 0 : mOverScroll),
-                             (mIsVertical ? mOverScroll : 0),
-                             0, 0,
-                             (mIsVertical ? 0 : mOverscrollDistance),
-                             (mIsVertical ? mOverscrollDistance : 0),
-                             true);
-
-        if (Math.abs(mOverscrollDistance) == Math.abs(mOverScroll)) {
-            // Break fling velocity if we impacted an edge
-            if (mVelocityTracker != null) {
-                mVelocityTracker.clear();
-            }
-        }
-
-        final int overscrollMode = ViewCompat.getOverScrollMode(this);
-        if (overscrollMode == ViewCompat.OVER_SCROLL_ALWAYS ||
-                (overscrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && !contentFits())) {
-            mTouchMode = TOUCH_MODE_OVERSCROLL;
-
-            float pull = (float) overscroll / getSize();
-            if (delta > 0) {
-                mStartEdge.onPull(pull);
-
-                if (!mEndEdge.isFinished()) {
-                    mEndEdge.onRelease();
-                }
-            } else if (delta < 0) {
-                mEndEdge.onPull(pull);
-
-                if (!mStartEdge.isFinished()) {
-                    mStartEdge.onRelease();
-                }
-            }
-
-            if (delta != 0) {
-                ViewCompat.postInvalidateOnAnimation(this);
-            }
-        }
-    }
-
-    private void handleOverScrollChange(int delta) {
-        final int oldOverScroll = mOverScroll;
-        final int newOverScroll = oldOverScroll - delta;
-
-        int overScrollDistance = -delta;
-        if ((newOverScroll < 0 && oldOverScroll >= 0) ||
-                (newOverScroll > 0 && oldOverScroll <= 0)) {
-            overScrollDistance = -oldOverScroll;
-            delta += overScrollDistance;
-        } else {
-            delta = 0;
-        }
-
-        if (overScrollDistance != 0) {
-            updateOverScrollState(delta, overScrollDistance);
-        }
-
-        if (delta != 0) {
-            if (mOverScroll != 0) {
-                mOverScroll = 0;
-                ViewCompat.postInvalidateOnAnimation(this);
-            }
-
-            scrollListItemsBy(delta);
-            mTouchMode = TOUCH_MODE_DRAGGING;
-
-            // We did not scroll the full amount. Treat this essentially like the
-            // start of a new touch scroll
-            mMotionPosition = findClosestMotionRowOrColumn((int) mLastTouchPos);
-            mTouchRemainderPos = 0;
-        }
-    }
-
-    /**
-     * What is the distance between the source and destination rectangles given the direction of
-     * focus navigation between them? The direction basically helps figure out more quickly what is
-     * self evident by the relationship between the rects...
-     *
-     * @param source the source rectangle
-     * @param dest the destination rectangle
-     * @param direction the direction
-     * @return the distance between the rectangles
-     */
-    private static int getDistance(Rect source, Rect dest, int direction) {
-        int sX, sY; // source x, y
-        int dX, dY; // dest x, y
-
-        switch (direction) {
-        case View.FOCUS_RIGHT:
-            sX = source.right;
-            sY = source.top + source.height() / 2;
-            dX = dest.left;
-            dY = dest.top + dest.height() / 2;
-            break;
-
-        case View.FOCUS_DOWN:
-            sX = source.left + source.width() / 2;
-            sY = source.bottom;
-            dX = dest.left + dest.width() / 2;
-            dY = dest.top;
-            break;
-
-        case View.FOCUS_LEFT:
-            sX = source.left;
-            sY = source.top + source.height() / 2;
-            dX = dest.right;
-            dY = dest.top + dest.height() / 2;
-            break;
-
-        case View.FOCUS_UP:
-            sX = source.left + source.width() / 2;
-            sY = source.top;
-            dX = dest.left + dest.width() / 2;
-            dY = dest.bottom;
-            break;
-
-        case View.FOCUS_FORWARD:
-        case View.FOCUS_BACKWARD:
-            sX = source.right + source.width() / 2;
-            sY = source.top + source.height() / 2;
-            dX = dest.left + dest.width() / 2;
-            dY = dest.top + dest.height() / 2;
-            break;
-
-        default:
-            throw new IllegalArgumentException("direction must be one of "
-                    + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, "
-                    + "FOCUS_FORWARD, FOCUS_BACKWARD}.");
-        }
-
-        int deltaX = dX - sX;
-        int deltaY = dY - sY;
-
-        return deltaY * deltaY + deltaX * deltaX;
-    }
-
-    private int findMotionRowOrColumn(int motionPos) {
-        int childCount = getChildCount();
-        if (childCount == 0) {
-            return INVALID_POSITION;
-        }
-
-        for (int i = 0; i < childCount; i++) {
-            final View v = getChildAt(i);
-            if (motionPos <= getChildEndEdge(v)) {
-                return mFirstPosition + i;
-            }
-        }
-
-        return INVALID_POSITION;
-    }
-
-    private int findClosestMotionRowOrColumn(int motionPos) {
-        final int childCount = getChildCount();
-        if (childCount == 0) {
-            return INVALID_POSITION;
-        }
-
-        final int motionRow = findMotionRowOrColumn(motionPos);
-        if (motionRow != INVALID_POSITION) {
-            return motionRow;
-        } else {
-            return mFirstPosition + childCount - 1;
-        }
-    }
-
-    @TargetApi(9)
-    private int getScaledOverscrollDistance(ViewConfiguration vc) {
-        if (Build.VERSION.SDK_INT < 9) {
-            return 0;
-        }
-
-        return vc.getScaledOverscrollDistance();
-    }
-
-    private int getStartEdge() {
-        return (mIsVertical ? getPaddingTop() : getPaddingLeft());
-    }
-
-    private int getEndEdge() {
-        if (mIsVertical) {
-            return (getHeight() - getPaddingBottom());
-        } else {
-            return (getWidth() - getPaddingRight());
-        }
-    }
-
-    private int getSize() {
-        return (mIsVertical ? getHeight() : getWidth());
-    }
-
-    private int getAvailableSize() {
-        if (mIsVertical) {
-            return getHeight() - getPaddingBottom() - getPaddingTop();
-        } else {
-            return getWidth() - getPaddingRight() - getPaddingLeft();
-        }
-    }
-
-    private int getChildStartEdge(View child) {
-        return (mIsVertical ? child.getTop() : child.getLeft());
-    }
-
-    private int getChildEndEdge(View child) {
-        return (mIsVertical ? child.getBottom() : child.getRight());
-    }
-
-    private int getChildSize(View child) {
-        return (mIsVertical ? child.getHeight() : child.getWidth());
-    }
-
-    private int getChildMeasuredSize(View child) {
-        return (mIsVertical ? child.getMeasuredHeight() : child.getMeasuredWidth());
-    }
-
-    private int getFadingEdgeLength() {
-        return (mIsVertical ? getVerticalFadingEdgeLength() : getHorizontalFadingEdgeLength());
-    }
-
-    private int getMinSelectionPixel(int start, int fadingEdgeLength, int selectedPosition) {
-        // First pixel we can draw the selection into.
-        int selectionPixelStart = start;
-        if (selectedPosition > 0) {
-            selectionPixelStart += fadingEdgeLength;
-        }
-
-        return selectionPixelStart;
-    }
-
-    private int getMaxSelectionPixel(int end, int fadingEdgeLength,
-                                     int selectedPosition) {
-        int selectionPixelEnd = end;
-        if (selectedPosition != mItemCount - 1) {
-            selectionPixelEnd -= fadingEdgeLength;
-        }
-
-        return selectionPixelEnd;
-    }
-
-    private boolean contentFits() {
-        final int childCount = getChildCount();
-        if (childCount == 0) {
-            return true;
-        }
-
-        if (childCount != mItemCount) {
-            return false;
-        }
-
-        View first = getChildAt(0);
-        View last = getChildAt(childCount - 1);
-
-        return (getChildStartEdge(first) >= getStartEdge() &&
-                getChildEndEdge(last) <= getEndEdge());
-    }
-
-    private void triggerCheckForTap() {
-        if (mPendingCheckForTap == null) {
-            mPendingCheckForTap = new CheckForTap();
-        }
-
-        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
-    }
-
-    private void cancelCheckForTap() {
-        if (mPendingCheckForTap == null) {
-            return;
-        }
-
-        removeCallbacks(mPendingCheckForTap);
-    }
-
-    private void triggerCheckForLongPress() {
-        if (mPendingCheckForLongPress == null) {
-            mPendingCheckForLongPress = new CheckForLongPress();
-        }
-
-        mPendingCheckForLongPress.rememberWindowAttachCount();
-
-        postDelayed(mPendingCheckForLongPress,
-                ViewConfiguration.getLongPressTimeout());
-    }
-
-    private void cancelCheckForLongPress() {
-        if (mPendingCheckForLongPress == null) {
-            return;
-        }
-
-        removeCallbacks(mPendingCheckForLongPress);
-    }
-
-    private boolean scrollListItemsBy(int incrementalDelta) {
-        final int childCount = getChildCount();
-        if (childCount == 0) {
-            return true;
-        }
-
-        final int firstStart = getChildStartEdge(getChildAt(0));
-        final int lastEnd = getChildEndEdge(getChildAt(childCount - 1));
-
-        final int paddingTop = getPaddingTop();
-        final int paddingLeft = getPaddingLeft();
-
-        final int paddingStart = (mIsVertical ? paddingTop : paddingLeft);
-
-        final int spaceBefore = paddingStart - firstStart;
-        final int end = getEndEdge();
-        final int spaceAfter = lastEnd - end;
-
-        final int size = getAvailableSize();
-
-        if (incrementalDelta < 0) {
-            incrementalDelta = Math.max(-(size - 1), incrementalDelta);
-        } else {
-            incrementalDelta = Math.min(size - 1, incrementalDelta);
-        }
-
-        final int firstPosition = mFirstPosition;
-
-        final boolean cannotScrollDown = (firstPosition == 0 &&
-                firstStart >= paddingStart && incrementalDelta >= 0);
-        final boolean cannotScrollUp = (firstPosition + childCount == mItemCount &&
-                lastEnd <= end && incrementalDelta <= 0);
-
-        if (cannotScrollDown || cannotScrollUp) {
-            return incrementalDelta != 0;
-        }
-
-        final boolean inTouchMode = isInTouchMode();
-        if (inTouchMode) {
-            hideSelector();
-        }
-
-        int start = 0;
-        int count = 0;
-
-        final boolean down = (incrementalDelta < 0);
-        if (down) {
-            int childrenStart = -incrementalDelta + paddingStart;
-
-            for (int i = 0; i < childCount; i++) {
-                final View child = getChildAt(i);
-                final int childEnd = getChildEndEdge(child);
-
-                if (childEnd >= childrenStart) {
-                    break;
-                }
-
-                count++;
-                mRecycler.addScrapView(child, firstPosition + i);
-            }
-        } else {
-            int childrenEnd = end - incrementalDelta;
-
-            for (int i = childCount - 1; i >= 0; i--) {
-                final View child = getChildAt(i);
-                final int childStart = getChildStartEdge(child);
-
-                if (childStart <= childrenEnd) {
-                    break;
-                }
-
-                start = i;
-                count++;
-                mRecycler.addScrapView(child, firstPosition + i);
-            }
-        }
-
-        mBlockLayoutRequests = true;
-
-        if (count > 0) {
-            detachViewsFromParent(start, count);
-        }
-
-        // invalidate before moving the children to avoid unnecessary invalidate
-        // calls to bubble up from the children all the way to the top
-        if (!awakenScrollbarsInternal()) {
-           invalidate();
-        }
-
-        offsetChildren(incrementalDelta);
-
-        if (down) {
-            mFirstPosition += count;
-        }
-
-        final int absIncrementalDelta = Math.abs(incrementalDelta);
-        if (spaceBefore < absIncrementalDelta || spaceAfter < absIncrementalDelta) {
-            fillGap(down);
-        }
-
-        if (!inTouchMode && mSelectedPosition != INVALID_POSITION) {
-            final int childIndex = mSelectedPosition - mFirstPosition;
-            if (childIndex >= 0 && childIndex < getChildCount()) {
-                positionSelector(mSelectedPosition, getChildAt(childIndex));
-            }
-        } else if (mSelectorPosition != INVALID_POSITION) {
-            final int childIndex = mSelectorPosition - mFirstPosition;
-            if (childIndex >= 0 && childIndex < getChildCount()) {
-                positionSelector(INVALID_POSITION, getChildAt(childIndex));
-            }
-        } else {
-            mSelectorRect.setEmpty();
-        }
-
-        mBlockLayoutRequests = false;
-
-        invokeOnItemScrollListener();
-
-        return false;
-    }
-
-    @TargetApi(14)
-    private final float getCurrVelocity() {
-        if (Build.VERSION.SDK_INT >= 14) {
-            return mScroller.getCurrVelocity();
-        }
-
-        return 0;
-    }
-
-    @TargetApi(5)
-    private boolean awakenScrollbarsInternal() {
-        return (Build.VERSION.SDK_INT >= 5) && super.awakenScrollBars();
-    }
-
-    @Override
-    public void computeScroll() {
-        if (!mScroller.computeScrollOffset()) {
-            return;
-        }
-
-        final int pos;
-        if (mIsVertical) {
-            pos = mScroller.getCurrY();
-        } else {
-            pos = mScroller.getCurrX();
-        }
-
-        final int diff = (int) (pos - mLastTouchPos);
-        mLastTouchPos = pos;
-
-        final boolean stopped = scrollListItemsBy(diff);
-
-        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 =
-                            (diff > 0 ? mStartEdge : mEndEdge);
-
-                    boolean needsInvalidate =
-                            edge.onAbsorb(Math.abs((int) getCurrVelocity()));
-
-                    if (needsInvalidate) {
-                        ViewCompat.postInvalidateOnAnimation(this);
-                    }
-                }
-
-                finishSmoothScrolling();
-            }
-
-            mTouchMode = TOUCH_MODE_REST;
-            reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
-        }
-    }
-
-    private void finishEdgeGlows() {
-        if (mStartEdge != null) {
-            mStartEdge.finish();
-        }
-
-        if (mEndEdge != null) {
-            mEndEdge.finish();
-        }
-    }
-
-    private boolean drawStartEdge(Canvas canvas) {
-        if (mStartEdge.isFinished()) {
-            return false;
-        }
-
-        if (mIsVertical) {
-            return mStartEdge.draw(canvas);
-        }
-
-        final int restoreCount = canvas.save();
-        final int height = getHeight();
-
-        canvas.translate(0, height);
-        canvas.rotate(270);
-
-        final boolean needsInvalidate = mStartEdge.draw(canvas);
-        canvas.restoreToCount(restoreCount);
-        return needsInvalidate;
-    }
-
-    private boolean drawEndEdge(Canvas canvas) {
-        if (mEndEdge.isFinished()) {
-            return false;
-        }
-
-        final int restoreCount = canvas.save();
-        final int width = getWidth();
-        final int height = getHeight();
-
-        if (mIsVertical) {
-            canvas.translate(-width, height);
-            canvas.rotate(180, width, 0);
-        } else {
-            canvas.translate(width, 0);
-            canvas.rotate(90);
-        }
-
-        final boolean needsInvalidate = mEndEdge.draw(canvas);
-        canvas.restoreToCount(restoreCount);
-        return needsInvalidate;
-    }
-
-    private void finishSmoothScrolling() {
-        mTouchMode = TOUCH_MODE_REST;
-        reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
-
-        mScroller.abortAnimation();
-        if (mPositionScroller != null) {
-            mPositionScroller.stop();
-        }
-    }
-
-    private void drawSelector(Canvas canvas) {
-        if (!mSelectorRect.isEmpty()) {
-            final Drawable selector = mSelector;
-            selector.setBounds(mSelectorRect);
-            selector.draw(canvas);
-        }
-    }
-
-    private void useDefaultSelector() {
-        setSelector(getResources().getDrawable(
-                android.R.drawable.list_selector_background));
-    }
-
-    private boolean shouldShowSelector() {
-        return (hasFocus() && !isInTouchMode()) || touchModeDrawsInPressedState();
-    }
-
-    private void positionSelector(int position, View selected) {
-        if (position != INVALID_POSITION) {
-            mSelectorPosition = position;
-        }
-
-        mSelectorRect.set(selected.getLeft(), selected.getTop(), selected.getRight(),
-                selected.getBottom());
-
-        final boolean isChildViewEnabled = mIsChildViewEnabled;
-        if (selected.isEnabled() != isChildViewEnabled) {
-            mIsChildViewEnabled = !isChildViewEnabled;
-
-            if (getSelectedItemPosition() != INVALID_POSITION) {
-                refreshDrawableState();
-            }
-        }
-    }
-
-    private void hideSelector() {
-        if (mSelectedPosition != INVALID_POSITION) {
-            if (mLayoutMode != LAYOUT_SPECIFIC) {
-                mResurrectToPosition = mSelectedPosition;
-            }
-
-            if (mNextSelectedPosition >= 0 && mNextSelectedPosition != mSelectedPosition) {
-                mResurrectToPosition = mNextSelectedPosition;
-            }
-
-            setSelectedPositionInt(INVALID_POSITION);
-            setNextSelectedPositionInt(INVALID_POSITION);
-
-            mSelectedStart = 0;
-        }
-    }
-
-    private void setSelectedPositionInt(int position) {
-        mSelectedPosition = position;
-        mSelectedRowId = getItemIdAtPosition(position);
-    }
-
-    private void setSelectionInt(int position) {
-        setNextSelectedPositionInt(position);
-        boolean awakeScrollbars = false;
-
-        final int selectedPosition = mSelectedPosition;
-        if (selectedPosition >= 0) {
-            if (position == selectedPosition - 1) {
-                awakeScrollbars = true;
-            } else if (position == selectedPosition + 1) {
-                awakeScrollbars = true;
-            }
-        }
-
-        layoutChildren();
-
-        if (awakeScrollbars) {
-            awakenScrollbarsInternal();
-        }
-    }
-
-    private void setNextSelectedPositionInt(int position) {
-        mNextSelectedPosition = position;
-        mNextSelectedRowId = getItemIdAtPosition(position);
-
-        // If we are trying to sync to the selection, update that too
-        if (mNeedSync && mSyncMode == SYNC_SELECTED_POSITION && position >= 0) {
-            mSyncPosition = position;
-            mSyncRowId = mNextSelectedRowId;
-        }
-    }
-
-    private boolean touchModeDrawsInPressedState() {
-        switch (mTouchMode) {
-        case TOUCH_MODE_TAP:
-        case TOUCH_MODE_DONE_WAITING:
-            return true;
-        default:
-            return false;
-        }
-    }
-
-    /**
-     * Sets the selector state to "pressed" and posts a CheckForKeyLongPress to see if
-     * this is a long press.
-     */
-    private void keyPressed() {
-        if (!isEnabled() || !isClickable()) {
-            return;
-        }
-
-        final Drawable selector = mSelector;
-        final Rect selectorRect = mSelectorRect;
-
-        if (selector != null && (isFocused() || touchModeDrawsInPressedState())
-                && !selectorRect.isEmpty()) {
-
-            final View child = getChildAt(mSelectedPosition - mFirstPosition);
-
-            if (child != null) {
-                if (child.hasFocusable()) {
-                    return;
-                }
-
-                child.setPressed(true);
-            }
-
-            setPressed(true);
-
-            final boolean longClickable = isLongClickable();
-            final Drawable d = selector.getCurrent();
-            if (d != null && d instanceof TransitionDrawable) {
-                if (longClickable) {
-                    ((TransitionDrawable) d).startTransition(
-                            ViewConfiguration.getLongPressTimeout());
-                } else {
-                    ((TransitionDrawable) d).resetTransition();
-                }
-            }
-
-            if (longClickable && !mDataChanged) {
-                if (mPendingCheckForKeyLongPress == null) {
-                    mPendingCheckForKeyLongPress = new CheckForKeyLongPress();
-                }
-
-                mPendingCheckForKeyLongPress.rememberWindowAttachCount();
-                postDelayed(mPendingCheckForKeyLongPress, ViewConfiguration.getLongPressTimeout());
-            }
-        }
-    }
-
-    private void updateSelectorState() {
-        if (mSelector != null) {
-            if (shouldShowSelector()) {
-                mSelector.setState(getDrawableState());
-            } else {
-                mSelector.setState(STATE_NOTHING);
-            }
-        }
-    }
-
-    private void checkSelectionChanged() {
-        if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) {
-            selectionChanged();
-            mOldSelectedPosition = mSelectedPosition;
-            mOldSelectedRowId = mSelectedRowId;
-        }
-    }
-
-    private void selectionChanged() {
-        OnItemSelectedListener listener = getOnItemSelectedListener();
-        if (listener == null) {
-            return;
-        }
-
-        if (mInLayout || mBlockLayoutRequests) {
-            // If we are in a layout traversal, defer notification
-            // by posting. This ensures that the view tree is
-            // in a consistent state and is able to accommodate
-            // new layout or invalidate requests.
-            if (mSelectionNotifier == null) {
-                mSelectionNotifier = new SelectionNotifier();
-            }
-
-            post(mSelectionNotifier);
-        } else {
-            fireOnSelected();
-            performAccessibilityActionsOnSelected();
-        }
-    }
-
-    private void fireOnSelected() {
-        OnItemSelectedListener listener = getOnItemSelectedListener();
-        if (listener == null) {
-            return;
-        }
-
-        final int selection = getSelectedItemPosition();
-        if (selection >= 0) {
-            View v = getSelectedView();
-            listener.onItemSelected(this, v, selection,
-                    mAdapter.getItemId(selection));
-        } else {
-            listener.onNothingSelected(this);
-        }
-    }
-
-    private void performAccessibilityActionsOnSelected() {
-        final int position = getSelectedItemPosition();
-        if (position >= 0) {
-            // We fire selection events here not in View
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
-        }
-    }
-
-    private int lookForSelectablePosition(int position) {
-        return lookForSelectablePosition(position, true);
-    }
-
-    private int lookForSelectablePosition(int position, boolean lookDown) {
-        final ListAdapter adapter = mAdapter;
-        if (adapter == null || isInTouchMode()) {
-            return INVALID_POSITION;
-        }
-
-        final int itemCount = mItemCount;
-        if (!mAreAllItemsSelectable) {
-            if (lookDown) {
-                position = Math.max(0, position);
-                while (position < itemCount && !adapter.isEnabled(position)) {
-                    position++;
-                }
-            } else {
-                position = Math.min(position, itemCount - 1);
-                while (position >= 0 && !adapter.isEnabled(position)) {
-                    position--;
-                }
-            }
-
-            if (position < 0 || position >= itemCount) {
-                return INVALID_POSITION;
-            }
-
-            return position;
-        } else {
-            if (position < 0 || position >= itemCount) {
-                return INVALID_POSITION;
-            }
-
-            return position;
-        }
-    }
-
-    /**
-     * @param direction either {@link View#FOCUS_UP} or {@link View#FOCUS_DOWN} or
-     *        {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT} depending on the
-     *        current view orientation.
-     *
-     * @return The position of the next selectable position of the views that
-     *         are currently visible, taking into account the fact that there might
-     *         be no selection.  Returns {@link #INVALID_POSITION} if there is no
-     *         selectable view on screen in the given direction.
-     */
-    private int lookForSelectablePositionOnScreen(int direction) {
-        forceValidFocusDirection(direction);
-
-        final int firstPosition = mFirstPosition;
-        final ListAdapter adapter = getAdapter();
-
-        if (direction == View.FOCUS_DOWN || direction == View.FOCUS_RIGHT) {
-            int startPos = (mSelectedPosition != INVALID_POSITION ?
-                    mSelectedPosition + 1 : firstPosition);
-
-            if (startPos >= adapter.getCount()) {
-                return INVALID_POSITION;
-            }
-
-            if (startPos < firstPosition) {
-                startPos = firstPosition;
-            }
-
-            final int lastVisiblePos = getLastVisiblePosition();
-
-            for (int pos = startPos; pos <= lastVisiblePos; pos++) {
-                if (adapter.isEnabled(pos)
-                        && getChildAt(pos - firstPosition).getVisibility() == View.VISIBLE) {
-                    return pos;
-                }
-            }
-        } else {
-            final int last = firstPosition + getChildCount() - 1;
-
-            int startPos = (mSelectedPosition != INVALID_POSITION) ?
-                    mSelectedPosition - 1 : firstPosition + getChildCount() - 1;
-
-            if (startPos < 0 || startPos >= adapter.getCount()) {
-                return INVALID_POSITION;
-            }
-
-            if (startPos > last) {
-                startPos = last;
-            }
-
-            for (int pos = startPos; pos >= firstPosition; pos--) {
-                if (adapter.isEnabled(pos)
-                        && getChildAt(pos - firstPosition).getVisibility() == View.VISIBLE) {
-                    return pos;
-                }
-            }
-        }
-
-        return INVALID_POSITION;
-    }
-
-    @Override
-    protected void drawableStateChanged() {
-        super.drawableStateChanged();
-        updateSelectorState();
-    }
-
-    @Override
-    protected int[] onCreateDrawableState(int extraSpace) {
-        // If the child view is enabled then do the default behavior.
-        if (mIsChildViewEnabled) {
-            // Common case
-            return super.onCreateDrawableState(extraSpace);
-        }
-
-        // The selector uses this View's drawable state. The selected child view
-        // is disabled, so we need to remove the enabled state from the drawable
-        // states.
-        final int enabledState = ENABLED_STATE_SET[0];
-
-        // If we don't have any extra space, it will return one of the static state arrays,
-        // and clearing the enabled state on those arrays is a bad thing!  If we specify
-        // we need extra space, it will create+copy into a new array that safely mutable.
-        int[] state = super.onCreateDrawableState(extraSpace + 1);
-        int enabledPos = -1;
-        for (int i = state.length - 1; i >= 0; i--) {
-            if (state[i] == enabledState) {
-                enabledPos = i;
-                break;
-            }
-        }
-
-        // Remove the enabled state
-        if (enabledPos >= 0) {
-            System.arraycopy(state, enabledPos + 1, state, enabledPos,
-                    state.length - enabledPos - 1);
-        }
-
-        return state;
-    }
-
-    @Override
-    protected boolean canAnimate() {
-        return (super.canAnimate() && mItemCount > 0);
-    }
-
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        final boolean drawSelectorOnTop = mDrawSelectorOnTop;
-        if (!drawSelectorOnTop) {
-            drawSelector(canvas);
-        }
-
-        super.dispatchDraw(canvas);
-
-        if (drawSelectorOnTop) {
-            drawSelector(canvas);
-        }
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        super.draw(canvas);
-
-        boolean needsInvalidate = false;
-
-        if (mStartEdge != null) {
-            needsInvalidate |= drawStartEdge(canvas);
-        }
-
-        if (mEndEdge != null) {
-            needsInvalidate |= drawEndEdge(canvas);
-        }
-
-        if (needsInvalidate) {
-            ViewCompat.postInvalidateOnAnimation(this);
-        }
-    }
-
-    @Override
-    public void requestLayout() {
-        if (!mInLayout && !mBlockLayoutRequests) {
-            super.requestLayout();
-        }
-    }
-
-    @Override
-    public View getSelectedView() {
-        if (mItemCount > 0 && mSelectedPosition >= 0) {
-            return getChildAt(mSelectedPosition - mFirstPosition);
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public void setSelection(int position) {
-        setSelectionFromOffset(position, 0);
-    }
-
-    public void setSelectionFromOffset(int position, int offset) {
-        if (mAdapter == null) {
-            return;
-        }
-
-        if (!isInTouchMode()) {
-            position = lookForSelectablePosition(position);
-            if (position >= 0) {
-                setNextSelectedPositionInt(position);
-            }
-        } else {
-            mResurrectToPosition = position;
-        }
-
-        if (position >= 0) {
-            mLayoutMode = LAYOUT_SPECIFIC;
-
-            if (mIsVertical) {
-                mSpecificStart = getPaddingTop() + offset;
-            } else {
-                mSpecificStart = getPaddingLeft() + offset;
-            }
-
-            if (mNeedSync) {
-                mSyncPosition = position;
-                mSyncRowId = mAdapter.getItemId(position);
-            }
-
-            requestLayout();
-        }
-    }
-
-    public void scrollBy(int offset) {
-        scrollListItemsBy(-offset);
-    }
-
-    /**
-     * Smoothly scroll to the specified adapter position. The view will
-     * scroll such that the indicated position is displayed.
-     * @param position Scroll to this adapter position.
-     */
-    public void smoothScrollToPosition(int position) {
-        if (mPositionScroller == null) {
-            mPositionScroller = new PositionScroller();
-        }
-        mPositionScroller.start(position);
-    }
-
-    /**
-     * Smoothly scroll to the specified adapter position. The view will scroll
-     * such that the indicated position is displayed <code>offset</code> pixels from
-     * the top/left edge of the view, according to the orientation. If this is
-     * impossible, (e.g. the offset would scroll the first or last item beyond the boundaries
-     * of the list) it will get as close as possible. The scroll will take
-     * <code>duration</code> milliseconds to complete.
-     *
-     * @param position Position to scroll to
-     * @param offset Desired distance in pixels of <code>position</code> from the top/left
-     *               of the view when scrolling is finished
-     * @param duration Number of milliseconds to use for the scroll
-     */
-    public void smoothScrollToPositionFromOffset(int position, int offset, int duration) {
-        if (mPositionScroller == null) {
-            mPositionScroller = new PositionScroller();
-        }
-        mPositionScroller.startWithOffset(position, offset, duration);
-    }
-
-    /**
-     * Smoothly scroll to the specified adapter position. The view will scroll
-     * such that the indicated position is displayed <code>offset</code> pixels from
-     * the top edge of the view. If this is impossible, (e.g. the offset would scroll
-     * the first or last item beyond the boundaries of the list) it will get as close
-     * as possible.
-     *
-     * @param position Position to scroll to
-     * @param offset Desired distance in pixels of <code>position</code> from the top
-     *               of the view when scrolling is finished
-     */
-    public void smoothScrollToPositionFromOffset(int position, int offset) {
-        if (mPositionScroller == null) {
-            mPositionScroller = new PositionScroller();
-        }
-        mPositionScroller.startWithOffset(position, offset);
-    }
-
-    /**
-     * Smoothly scroll to the specified adapter position. The view will
-     * scroll such that the indicated position is displayed, but it will
-     * stop early if scrolling further would scroll boundPosition out of
-     * view.
-     *
-     * @param position Scroll to this adapter position.
-     * @param boundPosition Do not scroll if it would move this adapter
-     *          position out of view.
-     */
-    public void smoothScrollToPosition(int position, int boundPosition) {
-        if (mPositionScroller == null) {
-            mPositionScroller = new PositionScroller();
-        }
-        mPositionScroller.start(position, boundPosition);
-    }
-
-    /**
-     * Smoothly scroll by distance pixels over duration milliseconds.
-     * @param distance Distance to scroll in pixels.
-     * @param duration Duration of the scroll animation in milliseconds.
-     */
-    public void smoothScrollBy(int distance, int duration) {
-        // No sense starting to scroll if we're not going anywhere
-        final int firstPosition = mFirstPosition;
-        final int childCount = getChildCount();
-        final int lastPosition = firstPosition + childCount;
-        final int start = getStartEdge();
-        final int end = getEndEdge();
-
-        if (distance == 0 || mItemCount == 0 || childCount == 0 ||
-                (firstPosition == 0 && getChildStartEdge(getChildAt(0)) == start && distance < 0) ||
-                (lastPosition == mItemCount &&
-                            getChildEndEdge(getChildAt(childCount - 1)) == end && distance > 0)) {
-            finishSmoothScrolling();
-        } else {
-            mScroller.startScroll(0, 0,
-                                  mIsVertical ? 0 : -distance,
-                                  mIsVertical ? -distance : 0,
-                                  duration);
-
-            mLastTouchPos = 0;
-
-            mTouchMode = TOUCH_MODE_FLINGING;
-            reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
-
-            ViewCompat.postInvalidateOnAnimation(this);
-        }
-    }
-
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        // Dispatch in the normal way
-        boolean handled = super.dispatchKeyEvent(event);
-        if (!handled) {
-            // If we didn't handle it...
-            final View focused = getFocusedChild();
-            if (focused != null && event.getAction() == KeyEvent.ACTION_DOWN) {
-                // ... and our focused child didn't handle it
-                // ... give it to ourselves so we can scroll if necessary
-                handled = onKeyDown(event.getKeyCode(), event);
-            }
-        }
-
-        return handled;
-    }
-
-    @Override
-    protected void dispatchSetPressed(boolean pressed) {
-        // Don't dispatch setPressed to our children. We call setPressed on ourselves to
-        // get the selector in the right state, but we don't want to press each child.
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (mSelector == null) {
-            useDefaultSelector();
-        }
-
-        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
-        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
-        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-
-        int childWidth = 0;
-        int childHeight = 0;
-
-        mItemCount = (mAdapter == null ? 0 : mAdapter.getCount());
-        if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED ||
-                heightMode == MeasureSpec.UNSPECIFIED)) {
-            final View child = obtainView(0, mIsScrap);
-
-            final int secondaryMeasureSpec =
-                    (mIsVertical ? widthMeasureSpec : heightMeasureSpec);
-
-            measureScrapChild(child, 0, secondaryMeasureSpec);
-
-            childWidth = child.getMeasuredWidth();
-            childHeight = child.getMeasuredHeight();
-
-            if (recycleOnMeasure()) {
-                mRecycler.addScrapView(child, -1);
-            }
-        }
-
-        if (widthMode == MeasureSpec.UNSPECIFIED) {
-            widthSize = getPaddingLeft() + getPaddingRight() + childWidth;
-            if (mIsVertical) {
-                widthSize += getVerticalScrollbarWidth();
-            }
-        }
-
-        if (heightMode == MeasureSpec.UNSPECIFIED) {
-            heightSize = getPaddingTop() + getPaddingBottom() + childHeight;
-            if (!mIsVertical) {
-                heightSize += getHorizontalScrollbarHeight();
-            }
-        }
-
-        if (mIsVertical && heightMode == MeasureSpec.AT_MOST) {
-            heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
-        }
-
-        if (!mIsVertical && widthMode == MeasureSpec.AT_MOST) {
-            widthSize = measureWidthOfChildren(heightMeasureSpec, 0, NO_POSITION, widthSize, -1);
-        }
-
-        setMeasuredDimension(widthSize, heightSize);
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        mInLayout = true;
-
-        if (changed) {
-            final int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                getChildAt(i).forceLayout();
-            }
-
-            mRecycler.markChildrenDirty();
-        }
-
-        layoutChildren();
-
-        mInLayout = false;
-
-        final int width = r - l - getPaddingLeft() - getPaddingRight();
-        final int height = b - t - getPaddingTop() - getPaddingBottom();
-
-        if (mStartEdge != null && mEndEdge != null) {
-            if (mIsVertical) {
-                mStartEdge.setSize(width, height);
-                mEndEdge.setSize(width, height);
-            } else {
-                mStartEdge.setSize(height, width);
-                mEndEdge.setSize(height, width);
-            }
-        }
-    }
-
-    private void layoutChildren() {
-        if (getWidth() == 0 || getHeight() == 0) {
-            return;
-        }
-
-        final boolean blockLayoutRequests = mBlockLayoutRequests;
-        if (!blockLayoutRequests) {
-            mBlockLayoutRequests = true;
-        } else {
-            return;
-        }
-
-        try {
-            invalidate();
-
-            if (mAdapter == null) {
-                resetState();
-                return;
-            }
-
-            final int start = getStartEdge();
-            final int end = getEndEdge();
-
-            int childCount = getChildCount();
-            int index = 0;
-            int delta = 0;
-
-            View focusLayoutRestoreView = null;
-
-            View selected = null;
-            View oldSelected = null;
-            View newSelected = null;
-            View oldFirstChild = null;
-
-            switch (mLayoutMode) {
-            case LAYOUT_SET_SELECTION:
-                index = mNextSelectedPosition - mFirstPosition;
-                if (index >= 0 && index < childCount) {
-                    newSelected = getChildAt(index);
-                }
-
-                break;
-
-            case LAYOUT_FORCE_TOP:
-            case LAYOUT_FORCE_BOTTOM:
-            case LAYOUT_SPECIFIC:
-            case LAYOUT_SYNC:
-                break;
-
-            case LAYOUT_MOVE_SELECTION:
-            default:
-                // Remember the previously selected view
-                index = mSelectedPosition - mFirstPosition;
-                if (index >= 0 && index < childCount) {
-                    oldSelected = getChildAt(index);
-                }
-
-                // Remember the previous first child
-                oldFirstChild = getChildAt(0);
-
-                if (mNextSelectedPosition >= 0) {
-                    delta = mNextSelectedPosition - mSelectedPosition;
-                }
-
-                // Caution: newSelected might be null
-                newSelected = getChildAt(index + delta);
-            }
-
-            final boolean dataChanged = mDataChanged;
-            if (dataChanged) {
-                handleDataChanged();
-            }
-
-            // Handle the empty set by removing all views that are visible
-            // and calling it a day
-            if (mItemCount == 0) {
-                resetState();
-                return;
-            } else if (mItemCount != mAdapter.getCount()) {
-                throw new IllegalStateException("The content of the adapter has changed but "
-                        + "TwoWayView did not receive a notification. Make sure the content of "
-                        + "your adapter is not modified from a background thread, but only "
-                        + "from the UI thread. [in TwoWayView(" + getId() + ", " + getClass()
-                        + ") with Adapter(" + mAdapter.getClass() + ")]");
-            }
-
-            setSelectedPositionInt(mNextSelectedPosition);
-
-            // Reset the focus restoration
-            View focusLayoutRestoreDirectChild = null;
-
-            // Pull all children into the RecycleBin.
-            // These views will be reused if possible
-            final int firstPosition = mFirstPosition;
-            final RecycleBin recycleBin = mRecycler;
-
-            if (dataChanged) {
-                for (int i = 0; i < childCount; i++) {
-                    recycleBin.addScrapView(getChildAt(i), firstPosition + i);
-                }
-            } else {
-                recycleBin.fillActiveViews(childCount, firstPosition);
-            }
-
-            // Take focus back to us temporarily to avoid the eventual
-            // call to clear focus when removing the focused child below
-            // from messing things up when ViewAncestor assigns focus back
-            // to someone else.
-            final View focusedChild = getFocusedChild();
-            if (focusedChild != null) {
-                // We can remember the focused view to restore after relayout if the
-                // data hasn't changed, or if the focused position is a header or footer.
-                if (!dataChanged) {
-                    focusLayoutRestoreDirectChild = focusedChild;
-
-                    // Remember the specific view that had focus
-                    focusLayoutRestoreView = findFocus();
-                    if (focusLayoutRestoreView != null) {
-                        // Tell it we are going to mess with it
-                        focusLayoutRestoreView.onStartTemporaryDetach();
-                    }
-                }
-
-                requestFocus();
-            }
-
-            // FIXME: We need a way to save current accessibility focus here
-            // so that it can be restored after we re-attach the children on each
-            // layout round.
-
-            detachAllViewsFromParent();
-
-            switch (mLayoutMode) {
-            case LAYOUT_SET_SELECTION:
-                if (newSelected != null) {
-                    final int newSelectedStart = getChildStartEdge(newSelected);
-                    selected = fillFromSelection(newSelectedStart, start, end);
-                } else {
-                    selected = fillFromMiddle(start, end);
-                }
-
-                break;
-
-            case LAYOUT_SYNC:
-                selected = fillSpecific(mSyncPosition, mSpecificStart);
-                break;
-
-            case LAYOUT_FORCE_BOTTOM:
-                selected = fillBefore(mItemCount - 1, end);
-                adjustViewsStartOrEnd();
-                break;
-
-            case LAYOUT_FORCE_TOP:
-                mFirstPosition = 0;
-                selected = fillFromOffset(start);
-                adjustViewsStartOrEnd();
-                break;
-
-            case LAYOUT_SPECIFIC:
-                selected = fillSpecific(reconcileSelectedPosition(), mSpecificStart);
-                break;
-
-            case LAYOUT_MOVE_SELECTION:
-                selected = moveSelection(oldSelected, newSelected, delta, start, end);
-                break;
-
-            default:
-                if (childCount == 0) {
-                    final int position = lookForSelectablePosition(0);
-                    setSelectedPositionInt(position);
-                    selected = fillFromOffset(start);
-                } else {
-                    if (mSelectedPosition >= 0 && mSelectedPosition < mItemCount) {
-                        int offset = start;
-                        if (oldSelected != null) {
-                            offset = getChildStartEdge(oldSelected);
-                        }
-                        selected = fillSpecific(mSelectedPosition, offset);
-                    } else if (mFirstPosition < mItemCount) {
-                        int offset = start;
-                        if (oldFirstChild != null) {
-                            offset = getChildStartEdge(oldFirstChild);
-                        }
-
-                        selected = fillSpecific(mFirstPosition, offset);
-                    } else {
-                        selected = fillSpecific(0, start);
-                    }
-                }
-
-                break;
-
-            }
-
-            recycleBin.scrapActiveViews();
-
-            if (selected != null) {
-                if (mItemsCanFocus && hasFocus() && !selected.hasFocus()) {
-                    final boolean focusWasTaken = (selected == focusLayoutRestoreDirectChild &&
-                            focusLayoutRestoreView != null &&
-                            focusLayoutRestoreView.requestFocus()) || selected.requestFocus();
-
-                    if (!focusWasTaken) {
-                        // Selected item didn't take focus, fine, but still want
-                        // to make sure something else outside of the selected view
-                        // has focus
-                        final View focused = getFocusedChild();
-                        if (focused != null) {
-                            focused.clearFocus();
-                        }
-
-                        positionSelector(INVALID_POSITION, selected);
-                    } else {
-                        selected.setSelected(false);
-                        mSelectorRect.setEmpty();
-                    }
-                } else {
-                    positionSelector(INVALID_POSITION, selected);
-                }
-
-                mSelectedStart = getChildStartEdge(selected);
-            } else {
-                if (mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_DRAGGING) {
-                    View child = getChildAt(mMotionPosition - mFirstPosition);
-
-                    if (child != null) {
-                        positionSelector(mMotionPosition, child);
-                    }
-                } else {
-                    mSelectedStart = 0;
-                    mSelectorRect.setEmpty();
-                }
-
-                // Even if there is not selected position, we may need to restore
-                // focus (i.e. something focusable in touch mode)
-                if (hasFocus() && focusLayoutRestoreView != null) {
-                    focusLayoutRestoreView.requestFocus();
-                }
-            }
-
-            // Tell focus view we are done mucking with it, if it is still in
-            // our view hierarchy.
-            if (focusLayoutRestoreView != null
-                    && focusLayoutRestoreView.getWindowToken() != null) {
-                focusLayoutRestoreView.onFinishTemporaryDetach();
-            }
-
-            mLayoutMode = LAYOUT_NORMAL;
-            mDataChanged = false;
-            mNeedSync = false;
-
-            setNextSelectedPositionInt(mSelectedPosition);
-            if (mItemCount > 0) {
-                checkSelectionChanged();
-            }
-
-            invokeOnItemScrollListener();
-        } finally {
-            if (!blockLayoutRequests) {
-                mBlockLayoutRequests = false;
-                mDataChanged = false;
-            }
-        }
-    }
-
-    protected boolean recycleOnMeasure() {
-        return true;
-    }
-
-    private void offsetChildren(int offset) {
-        final int childCount = getChildCount();
-
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-
-            if (mIsVertical) {
-                child.offsetTopAndBottom(offset);
-            } else {
-                child.offsetLeftAndRight(offset);
-            }
-        }
-    }
-
-    private View moveSelection(View oldSelected, View newSelected, int delta, int start,
-            int end) {
-        final int fadingEdgeLength = getFadingEdgeLength();
-        final int selectedPosition = mSelectedPosition;
-
-        final int oldSelectedStart = getChildStartEdge(oldSelected);
-        final int oldSelectedEnd = getChildEndEdge(oldSelected);
-
-        final int minStart = getMinSelectionPixel(start, fadingEdgeLength, selectedPosition);
-        final int maxEnd = getMaxSelectionPixel(end, fadingEdgeLength, selectedPosition);
-
-        View selected = null;
-
-        if (delta > 0) {
-            /*
-             * Case 1: Scrolling down.
-             */
-
-            /*
-             *     Before           After
-             *    |       |        |       |
-             *    +-------+        +-------+
-             *    |   A   |        |   A   |
-             *    |   1   |   =>   +-------+
-             *    +-------+        |   B   |
-             *    |   B   |        |   2   |
-             *    +-------+        +-------+
-             *    |       |        |       |
-             *
-             *    Try to keep the top of the previously selected item where it was.
-             *    oldSelected = A
-             *    selected = B
-             */
-
-            // Put oldSelected (A) where it belongs
-            oldSelected = makeAndAddView(selectedPosition - 1, oldSelectedStart, true, false);
-
-            final int itemMargin = mItemMargin;
-
-            // Now put the new selection (B) below that
-            selected = makeAndAddView(selectedPosition, oldSelectedEnd + itemMargin, true, true);
-
-            final int selectedStart = getChildStartEdge(selected);
-            final int selectedEnd = getChildEndEdge(selected);
-
-            // Some of the newly selected item extends below the bottom of the list
-            if (selectedEnd > end) {
-                // Find space available above the selection into which we can scroll upwards
-                final int spaceBefore = selectedStart - minStart;
-
-                // Find space required to bring the bottom of the selected item fully into view
-                final int spaceAfter = selectedEnd - maxEnd;
-
-                // Don't scroll more than half the size of the list
-                final int halfSpace = (end - start) / 2;
-                int offset = Math.min(spaceBefore, spaceAfter);
-                offset = Math.min(offset, halfSpace);
-
-                if (mIsVertical) {
-                    oldSelected.offsetTopAndBottom(-offset);
-                    selected.offsetTopAndBottom(-offset);
-                } else {
-                    oldSelected.offsetLeftAndRight(-offset);
-                    selected.offsetLeftAndRight(-offset);
-                }
-            }
-
-            // Fill in views before and after
-            fillBefore(mSelectedPosition - 2, selectedStart - itemMargin);
-            adjustViewsStartOrEnd();
-            fillAfter(mSelectedPosition + 1, selectedEnd + itemMargin);
-        } else if (delta < 0) {
-            /*
-             * Case 2: Scrolling up.
-             */
-
-            /*
-             *     Before           After
-             *    |       |        |       |
-             *    +-------+        +-------+
-             *    |   A   |        |   A   |
-             *    +-------+   =>   |   1   |
-             *    |   B   |        +-------+
-             *    |   2   |        |   B   |
-             *    +-------+        +-------+
-             *    |       |        |       |
-             *
-             *    Try to keep the top of the item about to become selected where it was.
-             *    newSelected = A
-             *    olSelected = B
-             */
-
-            if (newSelected != null) {
-                // Try to position the top of newSel (A) where it was before it was selected
-                final int newSelectedStart = getChildStartEdge(newSelected);
-                selected = makeAndAddView(selectedPosition, newSelectedStart, true, true);
-            } else {
-                // If (A) was not on screen and so did not have a view, position
-                // it above the oldSelected (B)
-                selected = makeAndAddView(selectedPosition, oldSelectedStart, false, true);
-            }
-
-            final int selectedStart = getChildStartEdge(selected);
-            final int selectedEnd = getChildEndEdge(selected);
-
-            // Some of the newly selected item extends above the top of the list
-            if (selectedStart < minStart) {
-                // Find space required to bring the top of the selected item fully into view
-                final int spaceBefore = minStart - selectedStart;
-
-               // Find space available below the selection into which we can scroll downwards
-                final int spaceAfter = maxEnd - selectedEnd;
-
-                // Don't scroll more than half the height of the list
-                final int halfSpace = (end - start) / 2;
-                int offset = Math.min(spaceBefore, spaceAfter);
-                offset = Math.min(offset, halfSpace);
-
-                if (mIsVertical) {
-                    selected.offsetTopAndBottom(offset);
-                } else {
-                    selected.offsetLeftAndRight(offset);
-                }
-            }
-
-            // Fill in views above and below
-            fillBeforeAndAfter(selected, selectedPosition);
-        } else {
-            /*
-             * Case 3: Staying still
-             */
-
-            selected = makeAndAddView(selectedPosition, oldSelectedStart, true, true);
-
-            final int selectedStart = getChildStartEdge(selected);
-            final int selectedEnd = getChildEndEdge(selected);
-
-            // We're staying still...
-            if (oldSelectedStart < start) {
-                // ... but the top of the old selection was off screen.
-                // (This can happen if the data changes size out from under us)
-                int newEnd = selectedEnd;
-                if (newEnd < start + 20) {
-                    // Not enough visible -- bring it onscreen
-                    if (mIsVertical) {
-                        selected.offsetTopAndBottom(start - selectedStart);
-                    } else {
-                        selected.offsetLeftAndRight(start - selectedStart);
-                    }
-                }
-            }
-
-            // Fill in views above and below
-            fillBeforeAndAfter(selected, selectedPosition);
-        }
-
-        return selected;
-    }
-
-    void confirmCheckedPositionsById() {
-        // Clear out the positional check states, we'll rebuild it below from IDs.
-        mCheckStates.clear();
-
-        for (int checkedIndex = 0; checkedIndex < mCheckedIdStates.size(); checkedIndex++) {
-            final long id = mCheckedIdStates.keyAt(checkedIndex);
-            final int lastPos = mCheckedIdStates.valueAt(checkedIndex);
-
-            final long lastPosId = mAdapter.getItemId(lastPos);
-            if (id != lastPosId) {
-                // Look around to see if the ID is nearby. If not, uncheck it.
-                final int start = Math.max(0, lastPos - CHECK_POSITION_SEARCH_DISTANCE);
-                final int end = Math.min(lastPos + CHECK_POSITION_SEARCH_DISTANCE, mItemCount);
-                boolean found = false;
-
-                for (int searchPos = start; searchPos < end; searchPos++) {
-                    final long searchId = mAdapter.getItemId(searchPos);
-                    if (id == searchId) {
-                        found = true;
-                        mCheckStates.put(searchPos, true);
-                        mCheckedIdStates.setValueAt(checkedIndex, searchPos);
-                        break;
-                    }
-                }
-
-                if (!found) {
-                    mCheckedIdStates.delete(id);
-                    checkedIndex--;
-                    mCheckedItemCount--;
-                }
-            } else {
-                mCheckStates.put(lastPos, true);
-            }
-        }
-    }
-
-    private void handleDataChanged() {
-        if (mChoiceMode != ChoiceMode.NONE && mAdapter != null && mAdapter.hasStableIds()) {
-            confirmCheckedPositionsById();
-        }
-
-        mRecycler.clearTransientStateViews();
-
-        final int itemCount = mItemCount;
-        if (itemCount > 0) {
-            int newPos;
-            int selectablePos;
-
-            // Find the row we are supposed to sync to
-            if (mNeedSync) {
-                // Update this first, since setNextSelectedPositionInt inspects it
-                mNeedSync = false;
-                mPendingSync = null;
-
-                switch (mSyncMode) {
-                case SYNC_SELECTED_POSITION:
-                    if (isInTouchMode()) {
-                        // We saved our state when not in touch mode. (We know this because
-                        // mSyncMode is SYNC_SELECTED_POSITION.) Now we are trying to
-                        // restore in touch mode. Just leave mSyncPosition as it is (possibly
-                        // adjusting if the available range changed) and return.
-                        mLayoutMode = LAYOUT_SYNC;
-                        mSyncPosition = Math.min(Math.max(0, mSyncPosition), itemCount - 1);
-
-                        return;
-                    } else {
-                        // See if we can find a position in the new data with the same
-                        // id as the old selection. This will change mSyncPosition.
-                        newPos = findSyncPosition();
-                        if (newPos >= 0) {
-                            // Found it. Now verify that new selection is still selectable
-                            selectablePos = lookForSelectablePosition(newPos, true);
-                            if (selectablePos == newPos) {
-                                // Same row id is selected
-                                mSyncPosition = newPos;
-
-                                if (mSyncSize == getSize()) {
-                                    // If we are at the same height as when we saved state, try
-                                    // to restore the scroll position too.
-                                    mLayoutMode = LAYOUT_SYNC;
-                                } else {
-                                    // We are not the same height as when the selection was saved, so
-                                    // don't try to restore the exact position
-                                    mLayoutMode = LAYOUT_SET_SELECTION;
-                                }
-
-                                // Restore selection
-                                setNextSelectedPositionInt(newPos);
-                                return;
-                            }
-                        }
-                    }
-                    break;
-
-                case SYNC_FIRST_POSITION:
-                    // Leave mSyncPosition as it is -- just pin to available range
-                    mLayoutMode = LAYOUT_SYNC;
-                    mSyncPosition = Math.min(Math.max(0, mSyncPosition), itemCount - 1);
-
-                    return;
-                }
-            }
-
-            if (!isInTouchMode()) {
-                // We couldn't find matching data -- try to use the same position
-                newPos = getSelectedItemPosition();
-
-                // Pin position to the available range
-                if (newPos >= itemCount) {
-                    newPos = itemCount - 1;
-                }
-                if (newPos < 0) {
-                    newPos = 0;
-                }
-
-                // Make sure we select something selectable -- first look down
-                selectablePos = lookForSelectablePosition(newPos, true);
-
-                if (selectablePos >= 0) {
-                    setNextSelectedPositionInt(selectablePos);
-                    return;
-                } else {
-                    // Looking down didn't work -- try looking up
-                    selectablePos = lookForSelectablePosition(newPos, false);
-                    if (selectablePos >= 0) {
-                        setNextSelectedPositionInt(selectablePos);
-                        return;
-                    }
-                }
-            } else {
-                // We already know where we want to resurrect the selection
-                if (mResurrectToPosition >= 0) {
-                    return;
-                }
-            }
-        }
-
-        // Nothing is selected. Give up and reset everything.
-        mLayoutMode = LAYOUT_FORCE_TOP;
-        mSelectedPosition = INVALID_POSITION;
-        mSelectedRowId = INVALID_ROW_ID;
-        mNextSelectedPosition = INVALID_POSITION;
-        mNextSelectedRowId = INVALID_ROW_ID;
-        mNeedSync = false;
-        mPendingSync = null;
-        mSelectorPosition = INVALID_POSITION;
-
-        checkSelectionChanged();
-    }
-
-    private int reconcileSelectedPosition() {
-        int position = mSelectedPosition;
-        if (position < 0) {
-            position = mResurrectToPosition;
-        }
-
-        position = Math.max(0, position);
-        position = Math.min(position, mItemCount - 1);
-
-        return position;
-    }
-
-    boolean resurrectSelection() {
-        final int childCount = getChildCount();
-        if (childCount <= 0) {
-            return false;
-        }
-
-        int selectedStart = 0;
-        int selectedPosition;
-
-        int start = getStartEdge();
-        int end = getEndEdge();
-
-        final int firstPosition = mFirstPosition;
-        final int toPosition = mResurrectToPosition;
-        boolean down = true;
-
-        if (toPosition >= firstPosition && toPosition < firstPosition + childCount) {
-            selectedPosition = toPosition;
-
-            final View selected = getChildAt(selectedPosition - mFirstPosition);
-            selectedStart = getChildStartEdge(selected);
-
-            final int selectedEnd = getChildEndEdge(selected);
-
-            // We are scrolled, don't get in the fade
-            if (selectedStart < start) {
-                selectedStart = start + getFadingEdgeLength();
-            } else if (selectedEnd > end) {
-                selectedStart = end - getChildMeasuredSize(selected) - getFadingEdgeLength();
-            }
-        } else if (toPosition < firstPosition) {
-            // Default to selecting whatever is first
-            selectedPosition = firstPosition;
-
-            for (int i = 0; i < childCount; i++) {
-                final View child = getChildAt(i);
-                final int childStart = getChildStartEdge(child);
-
-                if (i == 0) {
-                    // Remember the position of the first item
-                    selectedStart = childStart;
-
-                    // See if we are scrolled at all
-                    if (firstPosition > 0 || childStart < start) {
-                        // If we are scrolled, don't select anything that is
-                        // in the fade region
-                        start += getFadingEdgeLength();
-                    }
-                }
-
-                if (childStart >= start) {
-                    // Found a view whose top is fully visible
-                    selectedPosition = firstPosition + i;
-                    selectedStart = childStart;
-                    break;
-                }
-            }
-        } else {
-            final int itemCount = mItemCount;
-            selectedPosition = firstPosition + childCount - 1;
-            down = false;
-
-            for (int i = childCount - 1; i >= 0; i--) {
-                final View child = getChildAt(i);
-                final int childStart = getChildStartEdge(child);
-                final int childEnd = getChildEndEdge(child);
-
-                if (i == childCount - 1) {
-                    selectedStart = childStart;
-
-                    if (firstPosition + childCount < itemCount || childEnd > end) {
-                        end -= getFadingEdgeLength();
-                    }
-                }
-
-                if (childEnd <= end) {
-                    selectedPosition = firstPosition + i;
-                    selectedStart = childStart;
-                    break;
-                }
-            }
-        }
-
-        mResurrectToPosition = INVALID_POSITION;
-
-        finishSmoothScrolling();
-
-        mTouchMode = TOUCH_MODE_REST;
-        reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
-
-        mSpecificStart = selectedStart;
-
-        selectedPosition = lookForSelectablePosition(selectedPosition, down);
-        if (selectedPosition >= firstPosition && selectedPosition <= getLastVisiblePosition()) {
-            mLayoutMode = LAYOUT_SPECIFIC;
-            updateSelectorState();
-            setSelectionInt(selectedPosition);
-            invokeOnItemScrollListener();
-        } else {
-            selectedPosition = INVALID_POSITION;
-        }
-
-        return selectedPosition >= 0;
-    }
-
-    /**
-     * If there is a selection returns false.
-     * Otherwise resurrects the selection and returns true if resurrected.
-     */
-    boolean resurrectSelectionIfNeeded() {
-        if (mSelectedPosition < 0 && resurrectSelection()) {
-            updateSelectorState();
-            return true;
-        }
-
-        return false;
-    }
-
-    private int getChildWidthMeasureSpec(LayoutParams lp) {
-        if (!mIsVertical && lp.width == LayoutParams.WRAP_CONTENT) {
-            return MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-        } else if (mIsVertical) {
-            final int maxWidth = getWidth() - getPaddingLeft() - getPaddingRight();
-            return MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.EXACTLY);
-        } else {
-            return MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
-        }
-    }
-
-    private int getChildHeightMeasureSpec(LayoutParams lp) {
-        if (mIsVertical && lp.height == LayoutParams.WRAP_CONTENT) {
-            return MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-        } else if (!mIsVertical) {
-            final int maxHeight = getHeight() - getPaddingTop() - getPaddingBottom();
-            return MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY);
-        } else {
-            return MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
-        }
-    }
-
-    private void measureChild(View child) {
-        measureChild(child, (LayoutParams) child.getLayoutParams());
-    }
-
-    private void measureChild(View child, LayoutParams lp) {
-        final int widthSpec = getChildWidthMeasureSpec(lp);
-        final int heightSpec = getChildHeightMeasureSpec(lp);
-        child.measure(widthSpec, heightSpec);
-    }
-
-    private void relayoutMeasuredChild(View child) {
-        final int w = child.getMeasuredWidth();
-        final int h = child.getMeasuredHeight();
-
-        final int childLeft = getPaddingLeft();
-        final int childRight = childLeft + w;
-        final int childTop = child.getTop();
-        final int childBottom = childTop + h;
-
-        child.layout(childLeft, childTop, childRight, childBottom);
-    }
-
-    private void measureScrapChild(View scrapChild, int position, int secondaryMeasureSpec) {
-        LayoutParams lp = (LayoutParams) scrapChild.getLayoutParams();
-        if (lp == null) {
-            lp = generateDefaultLayoutParams();
-            scrapChild.setLayoutParams(lp);
-        }
-
-        lp.viewType = mAdapter.getItemViewType(position);
-        lp.forceAdd = true;
-
-        final int widthMeasureSpec;
-        final int heightMeasureSpec;
-        if (mIsVertical) {
-            widthMeasureSpec = secondaryMeasureSpec;
-            heightMeasureSpec = getChildHeightMeasureSpec(lp);
-        } else {
-            widthMeasureSpec = getChildWidthMeasureSpec(lp);
-            heightMeasureSpec = secondaryMeasureSpec;
-        }
-
-        scrapChild.measure(widthMeasureSpec, heightMeasureSpec);
-    }
-
-    /**
-     * Measures the height of the given range of children (inclusive) and
-     * returns the height with this TwoWayView's padding and item margin heights
-     * included. If maxHeight is provided, the measuring will stop when the
-     * current height reaches maxHeight.
-     *
-     * @param widthMeasureSpec The width measure spec to be given to a child's
-     *            {@link View#measure(int, int)}.
-     * @param startPosition The position of the first child to be shown.
-     * @param endPosition The (inclusive) position of the last child to be
-     *            shown. Specify {@link #NO_POSITION} if the last child should be
-     *            the last available child from the adapter.
-     * @param maxHeight The maximum height that will be returned (if all the
-     *            children don't fit in this value, this value will be
-     *            returned).
-     * @param disallowPartialChildPosition In general, whether the returned
-     *            height should only contain entire children. This is more
-     *            powerful--it is the first inclusive position at which partial
-     *            children will not be allowed. Example: it looks nice to have
-     *            at least 3 completely visible children, and in portrait this
-     *            will most likely fit; but in landscape there could be times
-     *            when even 2 children can not be completely shown, so a value
-     *            of 2 (remember, inclusive) would be good (assuming
-     *            startPosition is 0).
-     * @return The height of this TwoWayView with the given children.
-     */
-    private int measureHeightOfChildren(int widthMeasureSpec, int startPosition, int endPosition,
-            final int maxHeight, int disallowPartialChildPosition) {
-
-        final int paddingTop = getPaddingTop();
-        final int paddingBottom = getPaddingBottom();
-
-        final ListAdapter adapter = mAdapter;
-        if (adapter == null) {
-            return paddingTop + paddingBottom;
-        }
-
-        // Include the padding of the list
-        int returnedHeight = paddingTop + paddingBottom;
-        final int itemMargin = mItemMargin;
-
-        // The previous height value that was less than maxHeight and contained
-        // no partial children
-        int prevHeightWithoutPartialChild = 0;
-        int i;
-        View child;
-
-        // mItemCount - 1 since endPosition parameter is inclusive
-        endPosition = (endPosition == NO_POSITION) ? adapter.getCount() - 1 : endPosition;
-        final RecycleBin recycleBin = mRecycler;
-        final boolean shouldRecycle = recycleOnMeasure();
-        final boolean[] isScrap = mIsScrap;
-
-        for (i = startPosition; i <= endPosition; ++i) {
-            child = obtainView(i, isScrap);
-
-            measureScrapChild(child, i, widthMeasureSpec);
-
-            if (i > 0) {
-                // Count the item margin for all but one child
-                returnedHeight += itemMargin;
-            }
-
-            // Recycle the view before we possibly return from the method
-            if (shouldRecycle) {
-                recycleBin.addScrapView(child, -1);
-            }
-
-            returnedHeight += child.getMeasuredHeight();
-
-            if (returnedHeight >= maxHeight) {
-                // We went over, figure out which height to return.  If returnedHeight > maxHeight,
-                // then the i'th position did not fit completely.
-                return (disallowPartialChildPosition >= 0) // Disallowing is enabled (> -1)
-                            && (i > disallowPartialChildPosition) // We've past the min pos
-                            && (prevHeightWithoutPartialChild > 0) // We have a prev height
-                            && (returnedHeight != maxHeight) // i'th child did not fit completely
-                        ? prevHeightWithoutPartialChild
-                        : maxHeight;
-            }
-
-            if ((disallowPartialChildPosition >= 0) && (i >= disallowPartialChildPosition)) {
-                prevHeightWithoutPartialChild = returnedHeight;
-            }
-        }
-
-        // At this point, we went through the range of children, and they each
-        // completely fit, so return the returnedHeight
-        return returnedHeight;
-    }
-
-    /**
-     * Measures the width of the given range of children (inclusive) and
-     * returns the width with this TwoWayView's padding and item margin widths
-     * included. If maxWidth is provided, the measuring will stop when the
-     * current width reaches maxWidth.
-     *
-     * @param heightMeasureSpec The height measure spec to be given to a child's
-     *            {@link View#measure(int, int)}.
-     * @param startPosition The position of the first child to be shown.
-     * @param endPosition The (inclusive) position of the last child to be
-     *            shown. Specify {@link #NO_POSITION} if the last child should be
-     *            the last available child from the adapter.
-     * @param maxWidth The maximum width that will be returned (if all the
-     *            children don't fit in this value, this value will be
-     *            returned).
-     * @param disallowPartialChildPosition In general, whether the returned
-     *            width should only contain entire children. This is more
-     *            powerful--it is the first inclusive position at which partial
-     *            children will not be allowed. Example: it looks nice to have
-     *            at least 3 completely visible children, and in portrait this
-     *            will most likely fit; but in landscape there could be times
-     *            when even 2 children can not be completely shown, so a value
-     *            of 2 (remember, inclusive) would be good (assuming
-     *            startPosition is 0).
-     * @return The width of this TwoWayView with the given children.
-     */
-    private int measureWidthOfChildren(int heightMeasureSpec, int startPosition, int endPosition,
-            final int maxWidth, int disallowPartialChildPosition) {
-
-        final int paddingLeft = getPaddingLeft();
-        final int paddingRight = getPaddingRight();
-
-        final ListAdapter adapter = mAdapter;
-        if (adapter == null) {
-            return paddingLeft + paddingRight;
-        }
-
-        // Include the padding of the list
-        int returnedWidth = paddingLeft + paddingRight;
-        final int itemMargin = mItemMargin;
-
-        // The previous height value that was less than maxHeight and contained
-        // no partial children
-        int prevWidthWithoutPartialChild = 0;
-        int i;
-        View child;
-
-        // mItemCount - 1 since endPosition parameter is inclusive
-        endPosition = (endPosition == NO_POSITION) ? adapter.getCount() - 1 : endPosition;
-        final RecycleBin recycleBin = mRecycler;
-        final boolean shouldRecycle = recycleOnMeasure();
-        final boolean[] isScrap = mIsScrap;
-
-        for (i = startPosition; i <= endPosition; ++i) {
-            child = obtainView(i, isScrap);
-
-            measureScrapChild(child, i, heightMeasureSpec);
-
-            if (i > 0) {
-                // Count the item margin for all but one child
-                returnedWidth += itemMargin;
-            }
-
-            // Recycle the view before we possibly return from the method
-            if (shouldRecycle) {
-                recycleBin.addScrapView(child, -1);
-            }
-
-            returnedWidth += child.getMeasuredWidth();
-
-            if (returnedWidth >= maxWidth) {
-                // We went over, figure out which width to return.  If returnedWidth > maxWidth,
-                // then the i'th position did not fit completely.
-                return (disallowPartialChildPosition >= 0) // Disallowing is enabled (> -1)
-                            && (i > disallowPartialChildPosition) // We've past the min pos
-                            && (prevWidthWithoutPartialChild > 0) // We have a prev width
-                            && (returnedWidth != maxWidth) // i'th child did not fit completely
-                        ? prevWidthWithoutPartialChild
-                        : maxWidth;
-            }
-
-            if ((disallowPartialChildPosition >= 0) && (i >= disallowPartialChildPosition)) {
-                prevWidthWithoutPartialChild = returnedWidth;
-            }
-        }
-
-        // At this point, we went through the range of children, and they each
-        // completely fit, so return the returnedWidth
-        return returnedWidth;
-    }
-
-    private View makeAndAddView(int position, int offset, boolean flow, boolean selected) {
-        final int top;
-        final int left;
-
-        // Compensate item margin on the first item of the list if the item margin
-        // is negative to avoid incorrect offset for the very first child.
-        if (mIsVertical) {
-            top = offset;
-            left = getPaddingLeft();
-        } else {
-            top = getPaddingTop();
-            left = offset;
-        }
-
-        if (!mDataChanged) {
-            // Try to use an existing view for this position
-            final View activeChild = mRecycler.getActiveView(position);
-            if (activeChild != null) {
-                // Found it -- we're using an existing child
-                // This just needs to be positioned
-                setupChild(activeChild, position, top, left, flow, selected, true);
-
-                return activeChild;
-            }
-        }
-
-        // Make a new view for this position, or convert an unused view if possible
-        final View child = obtainView(position, mIsScrap);
-
-        // This needs to be positioned and measured
-        setupChild(child, position, top, left, flow, selected, mIsScrap[0]);
-
-        return child;
-    }
-
-    @TargetApi(11)
-    private void setupChild(View child, int position, int top, int left,
-            boolean flow, boolean selected, boolean recycled) {
-        final boolean isSelected = selected && shouldShowSelector();
-        final boolean updateChildSelected = isSelected != child.isSelected();
-        final int touchMode = mTouchMode;
-
-        final boolean isPressed = touchMode > TOUCH_MODE_DOWN && touchMode < TOUCH_MODE_DRAGGING &&
-                mMotionPosition == position;
-
-        final boolean updateChildPressed = isPressed != child.isPressed();
-        final boolean needToMeasure = !recycled || updateChildSelected || child.isLayoutRequested();
-
-        // Respect layout params that are already in the view. Otherwise make some up...
-        LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        if (lp == null) {
-            lp = generateDefaultLayoutParams();
-        }
-
-        lp.viewType = mAdapter.getItemViewType(position);
-
-        if (recycled && !lp.forceAdd) {
-            attachViewToParent(child, (flow ? -1 : 0), lp);
-        } else {
-            lp.forceAdd = false;
-            addViewInLayout(child, (flow ? -1 : 0), lp, true);
-        }
-
-        if (updateChildSelected) {
-            child.setSelected(isSelected);
-        }
-
-        if (updateChildPressed) {
-            child.setPressed(isPressed);
-        }
-
-        if (mChoiceMode != ChoiceMode.NONE && mCheckStates != null) {
-            if (child instanceof Checkable) {
-                ((Checkable) child).setChecked(mCheckStates.get(position));
-            } else if (Build.VERSION.SDK_INT >= HONEYCOMB) {
-                child.setActivated(mCheckStates.get(position));
-            }
-        }
-
-        if (needToMeasure) {
-            measureChild(child, lp);
-        } else {
-            cleanupLayoutState(child);
-        }
-
-        final int w = child.getMeasuredWidth();
-        final int h = child.getMeasuredHeight();
-
-        final int childTop = (mIsVertical && !flow ? top - h : top);
-        final int childLeft = (!mIsVertical && !flow ? left - w : left);
-
-        if (needToMeasure) {
-            final int childRight = childLeft + w;
-            final int childBottom = childTop + h;
-
-            child.layout(childLeft, childTop, childRight, childBottom);
-        } else {
-            child.offsetLeftAndRight(childLeft - child.getLeft());
-            child.offsetTopAndBottom(childTop - child.getTop());
-        }
-    }
-
-    void fillGap(boolean down) {
-        final int childCount = getChildCount();
-
-        if (down) {
-            final int start = getStartEdge();
-            final int lastEnd = getChildEndEdge(getChildAt(childCount - 1));
-            final int offset = (childCount > 0 ? lastEnd + mItemMargin : start);
-            fillAfter(mFirstPosition + childCount, offset);
-            correctTooHigh(getChildCount());
-        } else {
-            final int end = getEndEdge();
-            final int firstStart = getChildStartEdge(getChildAt(0));
-            final int offset = (childCount > 0 ? firstStart - mItemMargin : end);
-            fillBefore(mFirstPosition - 1, offset);
-            correctTooLow(getChildCount());
-        }
-    }
-
-    private View fillBefore(int pos, int nextOffset) {
-        View selectedView = null;
-
-        final int start = getStartEdge();
-
-        while (nextOffset > start && pos >= 0) {
-            boolean isSelected = (pos == mSelectedPosition);
-
-            View child = makeAndAddView(pos, nextOffset, false, isSelected);
-            nextOffset = getChildStartEdge(child) - mItemMargin;
-
-            if (isSelected) {
-                selectedView = child;
-            }
-
-            pos--;
-        }
-
-        mFirstPosition = pos + 1;
-
-        return selectedView;
-    }
-
-    private View fillAfter(int pos, int nextOffset) {
-        View selectedView = null;
-
-        final int end = getEndEdge();
-
-        while (nextOffset < end && pos < mItemCount) {
-            boolean selected = (pos == mSelectedPosition);
-
-            View child = makeAndAddView(pos, nextOffset, true, selected);
-            nextOffset = getChildEndEdge(child) + mItemMargin;
-
-            if (selected) {
-                selectedView = child;
-            }
-
-            pos++;
-        }
-
-        return selectedView;
-    }
-
-    private View fillSpecific(int position, int offset) {
-        final boolean tempIsSelected = (position == mSelectedPosition);
-        View temp = makeAndAddView(position, offset, true, tempIsSelected);
-
-        // Possibly changed again in fillBefore if we add rows above this one.
-        mFirstPosition = position;
-
-        final int offsetBefore = getChildStartEdge(temp) - mItemMargin;
-        final View before = fillBefore(position - 1, offsetBefore);
-
-        // This will correct for the top of the first view not touching the top of the list
-        adjustViewsStartOrEnd();
-
-        final int offsetAfter = getChildEndEdge(temp) + mItemMargin;
-        final View after = fillAfter(position + 1, offsetAfter);
-
-        final int childCount = getChildCount();
-        if (childCount > 0) {
-            correctTooHigh(childCount);
-        }
-
-        if (tempIsSelected) {
-            return temp;
-        } else if (before != null) {
-            return before;
-        } else {
-            return after;
-        }
-    }
-
-    private View fillFromOffset(int nextOffset) {
-        mFirstPosition = Math.min(mFirstPosition, mSelectedPosition);
-        mFirstPosition = Math.min(mFirstPosition, mItemCount - 1);
-
-        if (mFirstPosition < 0) {
-            mFirstPosition = 0;
-        }
-
-        return fillAfter(mFirstPosition, nextOffset);
-    }
-
-    private View fillFromMiddle(int start, int end) {
-        final int size = end - start;
-        int position = reconcileSelectedPosition();
-
-        View selected = makeAndAddView(position, start, true, true);
-        mFirstPosition = position;
-
-        if (mIsVertical) {
-            int selectedHeight = selected.getMeasuredHeight();
-            if (selectedHeight <= size) {
-                selected.offsetTopAndBottom((size - selectedHeight) / 2);
-            }
-        } else {
-            int selectedWidth = selected.getMeasuredWidth();
-            if (selectedWidth <= size) {
-                selected.offsetLeftAndRight((size - selectedWidth) / 2);
-            }
-        }
-
-        fillBeforeAndAfter(selected, position);
-        correctTooHigh(getChildCount());
-
-        return selected;
-    }
-
-    private void fillBeforeAndAfter(View selected, int position) {
-        final int offsetBefore = getChildStartEdge(selected) + mItemMargin;
-        fillBefore(position - 1, offsetBefore);
-
-        adjustViewsStartOrEnd();
-
-        final int offsetAfter = getChildEndEdge(selected) + mItemMargin;
-        fillAfter(position + 1, offsetAfter);
-    }
-
-    private View fillFromSelection(int selectedTop, int start, int end) {
-        int fadingEdgeLength = getFadingEdgeLength();
-        final int selectedPosition = mSelectedPosition;
-
-        final int minStart = getMinSelectionPixel(start, fadingEdgeLength, selectedPosition);
-        final int maxEnd = getMaxSelectionPixel(end, fadingEdgeLength, selectedPosition);
-
-        View selected = makeAndAddView(selectedPosition, selectedTop, true, true);
-
-        final int selectedStart = getChildStartEdge(selected);
-        final int selectedEnd = getChildEndEdge(selected);
-
-        // Some of the newly selected item extends below the bottom of the list
-        if (selectedEnd > maxEnd) {
-            // Find space available above the selection into which we can scroll
-            // upwards
-            final int spaceAbove = selectedStart - minStart;
-
-            // Find space required to bring the bottom of the selected item
-            // fully into view
-            final int spaceBelow = selectedEnd - maxEnd;
-
-            final int offset = Math.min(spaceAbove, spaceBelow);
-
-            // Now offset the selected item to get it into view
-            selected.offsetTopAndBottom(-offset);
-        } else if (selectedStart < minStart) {
-            // Find space required to bring the top of the selected item fully
-            // into view
-            final int spaceAbove = minStart - selectedStart;
-
-            // Find space available below the selection into which we can scroll
-            // downwards
-            final int spaceBelow = maxEnd - selectedEnd;
-
-            final int offset = Math.min(spaceAbove, spaceBelow);
-
-            // Offset the selected item to get it into view
-            selected.offsetTopAndBottom(offset);
-        }
-
-        // Fill in views above and below
-        fillBeforeAndAfter(selected, selectedPosition);
-        correctTooHigh(getChildCount());
-
-        return selected;
-    }
-
-    private void correctTooHigh(int childCount) {
-        // First see if the last item is visible. If it is not, it is OK for the
-        // top of the list to be pushed up.
-        final int lastPosition = mFirstPosition + childCount - 1;
-        if (lastPosition != mItemCount - 1 || childCount == 0) {
-            return;
-        }
-
-        // Get the last child end edge
-        final int lastEnd = getChildEndEdge(getChildAt(childCount - 1));
-
-        // This is bottom of our drawable area
-        final int start = getStartEdge();
-        final int end = getEndEdge();
-
-        // This is how far the end edge of the last view is from the end of the
-        // drawable area
-        int endOffset = end - lastEnd;
-
-        View firstChild = getChildAt(0);
-        int firstStart = getChildStartEdge(firstChild);
-
-        // Make sure we are 1) Too high, and 2) Either there are more rows above the
-        // first row or the first row is scrolled off the top of the drawable area
-        if (endOffset > 0 && (mFirstPosition > 0 || firstStart < start))  {
-            if (mFirstPosition == 0) {
-                // Don't pull the top too far down
-                endOffset = Math.min(endOffset, start - firstStart);
-            }
-
-            // Move everything down
-            offsetChildren(endOffset);
-
-            if (mFirstPosition > 0) {
-                firstStart = getChildStartEdge(firstChild);
-
-                // Fill the gap that was opened above mFirstPosition with more rows, if
-                // possible
-                fillBefore(mFirstPosition - 1, firstStart - mItemMargin);
-
-                // Close up the remaining gap
-                adjustViewsStartOrEnd();
-            }
-        }
-    }
-
-    private void correctTooLow(int childCount) {
-        // First see if the first item is visible. If it is not, it is OK for the
-        // bottom of the list to be pushed down.
-        if (mFirstPosition != 0 || childCount == 0) {
-            return;
-        }
-
-        final int firstStart = getChildStartEdge(getChildAt(0));
-
-        final int start = getStartEdge();
-        final int end = getEndEdge();
-
-        // This is how far the start edge of the first view is from the start of the
-        // drawable area
-        int startOffset = firstStart - start;
-
-        View last = getChildAt(childCount - 1);
-        int lastEnd = getChildEndEdge(last);
-
-        int lastPosition = mFirstPosition + childCount - 1;
-
-        // Make sure we are 1) Too low, and 2) Either there are more columns/rows below the
-        // last column/row or the last column/row is scrolled off the end of the
-        // drawable area
-        if (startOffset > 0) {
-            if (lastPosition < mItemCount - 1 || lastEnd > end)  {
-                if (lastPosition == mItemCount - 1) {
-                    // Don't pull the bottom too far up
-                    startOffset = Math.min(startOffset, lastEnd - end);
-                }
-
-                // Move everything up
-                offsetChildren(-startOffset);
-
-                if (lastPosition < mItemCount - 1) {
-                    lastEnd = getChildEndEdge(last);
-
-                    // Fill the gap that was opened below the last position with more rows, if
-                    // possible
-                    fillAfter(lastPosition + 1, lastEnd + mItemMargin);
-
-                    // Close up the remaining gap
-                    adjustViewsStartOrEnd();
-                }
-            } else if (lastPosition == mItemCount - 1) {
-                adjustViewsStartOrEnd();
-            }
-        }
-    }
-
-    private void adjustViewsStartOrEnd() {
-        if (getChildCount() == 0) {
-            return;
-        }
-
-        int delta = getChildStartEdge(getChildAt(0)) - getStartEdge();
-
-        // If item margin is negative we shouldn't apply it in the
-        // first item of the list to avoid offsetting it incorrectly.
-        if (mItemMargin >= 0 || mFirstPosition != 0) {
-            delta -= mItemMargin;
-        }
-
-        if (delta < 0) {
-            // We only are looking to see if we are too low, not too high
-            delta = 0;
-        }
-
-        if (delta != 0) {
-            offsetChildren(-delta);
-        }
-    }
-
-    @TargetApi(14)
-    private SparseBooleanArray cloneCheckStates() {
-        if (mCheckStates == null) {
-            return null;
-        }
-
-        SparseBooleanArray checkedStates;
-
-        if (Build.VERSION.SDK_INT >= 14) {
-            checkedStates = mCheckStates.clone();
-        } else {
-            checkedStates = new SparseBooleanArray();
-
-            for (int i = 0; i < mCheckStates.size(); i++) {
-                checkedStates.put(mCheckStates.keyAt(i), mCheckStates.valueAt(i));
-            }
-        }
-
-        return checkedStates;
-    }
-
-    private int findSyncPosition() {
-        int itemCount = mItemCount;
-
-        if (itemCount == 0) {
-            return INVALID_POSITION;
-        }
-
-        final long idToMatch = mSyncRowId;
-
-        // If there isn't a selection don't hunt for it
-        if (idToMatch == INVALID_ROW_ID) {
-            return INVALID_POSITION;
-        }
-
-        // Pin seed to reasonable values
-        int seed = mSyncPosition;
-        seed = Math.max(0, seed);
-        seed = Math.min(itemCount - 1, seed);
-
-        long endTime = SystemClock.uptimeMillis() + SYNC_MAX_DURATION_MILLIS;
-
-        long rowId;
-
-        // first position scanned so far
-        int first = seed;
-
-        // last position scanned so far
-        int last = seed;
-
-        // True if we should move down on the next iteration
-        boolean next = false;
-
-        // True when we have looked at the first item in the data
-        boolean hitFirst;
-
-        // True when we have looked at the last item in the data
-        boolean hitLast;
-
-        // Get the item ID locally (instead of getItemIdAtPosition), so
-        // we need the adapter
-        final ListAdapter adapter = mAdapter;
-        if (adapter == null) {
-            return INVALID_POSITION;
-        }
-
-        while (SystemClock.uptimeMillis() <= endTime) {
-            rowId = adapter.getItemId(seed);
-            if (rowId == idToMatch) {
-                // Found it!
-                return seed;
-            }
-
-            hitLast = (last == itemCount - 1);
-            hitFirst = (first == 0);
-
-            if (hitLast && hitFirst) {
-                // Looked at everything
-                break;
-            }
-
-            if (hitFirst || (next && !hitLast)) {
-                // Either we hit the top, or we are trying to move down
-                last++;
-                seed = last;
-
-                // Try going up next time
-                next = false;
-            } else if (hitLast || (!next && !hitFirst)) {
-                // Either we hit the bottom, or we are trying to move up
-                first--;
-                seed = first;
-
-                // Try going down next time
-                next = true;
-            }
-        }
-
-        return INVALID_POSITION;
-    }
-
-    @TargetApi(16)
-    private View obtainView(int position, boolean[] isScrap) {
-        isScrap[0] = false;
-
-        View scrapView = mRecycler.getTransientStateView(position);
-        if (scrapView != null) {
-            return scrapView;
-        }
-
-        scrapView = mRecycler.getScrapView(position);
-
-        final View child;
-        if (scrapView != null) {
-            child = mAdapter.getView(position, scrapView, this);
-
-            if (child != scrapView) {
-                mRecycler.addScrapView(scrapView, position);
-            } else {
-                isScrap[0] = true;
-            }
-        } else {
-            child = mAdapter.getView(position, null, this);
-        }
-
-        if (ViewCompat.getImportantForAccessibility(child) == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
-            ViewCompat.setImportantForAccessibility(child, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
-        }
-
-        if (mHasStableIds) {
-            LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            if (lp == null) {
-                lp = generateDefaultLayoutParams();
-            } else if (!checkLayoutParams(lp)) {
-                lp = generateLayoutParams(lp);
-            }
-
-            lp.id = mAdapter.getItemId(position);
-
-            child.setLayoutParams(lp);
-        }
-
-        if (mAccessibilityDelegate == null) {
-            mAccessibilityDelegate = new ListItemAccessibilityDelegate();
-        }
-
-        ViewCompat.setAccessibilityDelegate(child, mAccessibilityDelegate);
-
-        return child;
-    }
-
-    void resetState() {
-        mScroller.forceFinished(true);
-
-        removeAllViewsInLayout();
-
-        mSelectedStart = 0;
-        mFirstPosition = 0;
-        mDataChanged = false;
-        mNeedSync = false;
-        mPendingSync = null;
-        mOldSelectedPosition = INVALID_POSITION;
-        mOldSelectedRowId = INVALID_ROW_ID;
-
-        mOverScroll = 0;
-
-        setSelectedPositionInt(INVALID_POSITION);
-        setNextSelectedPositionInt(INVALID_POSITION);
-
-        mSelectorPosition = INVALID_POSITION;
-        mSelectorRect.setEmpty();
-
-        invalidate();
-    }
-
-    private void rememberSyncState() {
-        if (getChildCount() == 0) {
-            return;
-        }
-
-        mNeedSync = true;
-
-        if (mSelectedPosition >= 0) {
-            View child = getChildAt(mSelectedPosition - mFirstPosition);
-
-            mSyncRowId = mNextSelectedRowId;
-            mSyncPosition = mNextSelectedPosition;
-
-            if (child != null) {
-                mSpecificStart = getChildStartEdge(child);
-            }
-
-            mSyncMode = SYNC_SELECTED_POSITION;
-        } else {
-            // Sync the based on the offset of the first view
-            View child = getChildAt(0);
-            ListAdapter adapter = getAdapter();
-
-            if (mFirstPosition >= 0 && mFirstPosition < adapter.getCount()) {
-                mSyncRowId = adapter.getItemId(mFirstPosition);
-            } else {
-                mSyncRowId = NO_ID;
-            }
-
-            mSyncPosition = mFirstPosition;
-
-            if (child != null) {
-                mSpecificStart = getChildStartEdge(child);
-            }
-
-            mSyncMode = SYNC_FIRST_POSITION;
-        }
-    }
-
-    private ContextMenuInfo createContextMenuInfo(View view, int position, long id) {
-        return new AdapterContextMenuInfo(view, position, id);
-    }
-
-    @TargetApi(11)
-    private void updateOnScreenCheckedViews() {
-        final int firstPos = mFirstPosition;
-        final int count = getChildCount();
-
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            final int position = firstPos + i;
-
-            if (child instanceof Checkable) {
-                ((Checkable) child).setChecked(mCheckStates.get(position));
-            } else if (Build.VERSION.SDK_INT >= HONEYCOMB) {
-                child.setActivated(mCheckStates.get(position));
-            }
-        }
-    }
-
-    @Override
-    public boolean performItemClick(View view, int position, long id) {
-        boolean checkedStateChanged = false;
-
-        if (mChoiceMode == ChoiceMode.MULTIPLE) {
-            boolean checked = !mCheckStates.get(position, false);
-            mCheckStates.put(position, checked);
-
-            if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
-                if (checked) {
-                    mCheckedIdStates.put(mAdapter.getItemId(position), position);
-                } else {
-                    mCheckedIdStates.delete(mAdapter.getItemId(position));
-                }
-            }
-
-            if (checked) {
-                mCheckedItemCount++;
-            } else {
-                mCheckedItemCount--;
-            }
-
-            checkedStateChanged = true;
-        } else if (mChoiceMode == ChoiceMode.SINGLE) {
-            boolean checked = !mCheckStates.get(position, false);
-            if (checked) {
-                mCheckStates.clear();
-                mCheckStates.put(position, true);
-
-                if (mCheckedIdStates != null && mAdapter.hasStableIds()) {
-                    mCheckedIdStates.clear();
-                    mCheckedIdStates.put(mAdapter.getItemId(position), position);
-                }
-
-                mCheckedItemCount = 1;
-            } else if (mCheckStates.size() == 0 || !mCheckStates.valueAt(0)) {
-                mCheckedItemCount = 0;
-            }
-
-            checkedStateChanged = true;
-        }
-
-        if (checkedStateChanged) {
-            updateOnScreenCheckedViews();
-        }
-
-        return super.performItemClick(view, position, id);
-    }
-
-    private boolean performLongPress(final View child,
-            final int longPressPosition, final long longPressId) {
-        // CHOICE_MODE_MULTIPLE_MODAL takes over long press.
-        boolean handled = false;
-
-        OnItemLongClickListener listener = getOnItemLongClickListener();
-        if (listener != null) {
-            handled = listener.onItemLongClick(TwoWayView.this, child,
-                    longPressPosition, longPressId);
-        }
-
-        if (!handled) {
-            mContextMenuInfo = createContextMenuInfo(child, longPressPosition, longPressId);
-            handled = super.showContextMenuForChild(TwoWayView.this);
-        }
-
-        if (handled) {
-            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-        }
-
-        return handled;
-    }
-
-    @Override
-    protected LayoutParams generateDefaultLayoutParams() {
-        if (mIsVertical) {
-            return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
-        } else {
-            return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
-        }
-    }
-
-    @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);
-    }
-
-    @Override
-    protected ContextMenuInfo getContextMenuInfo() {
-        return mContextMenuInfo;
-    }
-
-    @Override
-    public Parcelable onSaveInstanceState() {
-        Parcelable superState = super.onSaveInstanceState();
-        SavedState ss = new SavedState(superState);
-
-        if (mPendingSync != null) {
-            ss.selectedId = mPendingSync.selectedId;
-            ss.firstId = mPendingSync.firstId;
-            ss.viewStart = mPendingSync.viewStart;
-            ss.position = mPendingSync.position;
-            ss.size = mPendingSync.size;
-
-            return ss;
-        }
-
-        boolean haveChildren = (getChildCount() > 0 && mItemCount > 0);
-        long selectedId = getSelectedItemId();
-        ss.selectedId = selectedId;
-        ss.size = getSize();
-
-        if (selectedId >= 0) {
-            ss.viewStart = mSelectedStart;
-            ss.position = getSelectedItemPosition();
-            ss.firstId = INVALID_POSITION;
-        } else if (haveChildren && mFirstPosition > 0) {
-            // Remember the position of the first child.
-            // We only do this if we are not currently at the top of
-            // the list, for two reasons:
-            //
-            // (1) The list may be in the process of becoming empty, in
-            // which case mItemCount may not be 0, but if we try to
-            // ask for any information about position 0 we will crash.
-            //
-            // (2) Being "at the top" seems like a special case, anyway,
-            // and the user wouldn't expect to end up somewhere else when
-            // they revisit the list even if its content has changed.
-
-            ss.viewStart = getChildStartEdge(getChildAt(0));
-
-            int firstPos = mFirstPosition;
-            if (firstPos >= mItemCount) {
-                firstPos = mItemCount - 1;
-            }
-
-            ss.position = firstPos;
-            ss.firstId = mAdapter.getItemId(firstPos);
-        } else {
-            ss.viewStart = 0;
-            ss.firstId = INVALID_POSITION;
-            ss.position = 0;
-        }
-
-        if (mCheckStates != null) {
-            ss.checkState = cloneCheckStates();
-        }
-
-        if (mCheckedIdStates != null) {
-            final LongSparseArray<Integer> idState = new LongSparseArray<Integer>();
-
-            final int count = mCheckedIdStates.size();
-            for (int i = 0; i < count; i++) {
-                idState.put(mCheckedIdStates.keyAt(i), mCheckedIdStates.valueAt(i));
-            }
-
-            ss.checkIdState = idState;
-        }
-
-        ss.checkedItemCount = mCheckedItemCount;
-
-        return ss;
-    }
-
-    @Override
-    public void onRestoreInstanceState(Parcelable state) {
-        SavedState ss = (SavedState) state;
-        super.onRestoreInstanceState(ss.getSuperState());
-
-        mDataChanged = true;
-        mSyncSize = ss.size;
-
-        if (ss.selectedId >= 0) {
-            mNeedSync = true;
-            mPendingSync = ss;
-            mSyncRowId = ss.selectedId;
-            mSyncPosition = ss.position;
-            mSpecificStart = ss.viewStart;
-            mSyncMode = SYNC_SELECTED_POSITION;
-        } else if (ss.firstId >= 0) {
-            setSelectedPositionInt(INVALID_POSITION);
-
-            // Do this before setting mNeedSync since setNextSelectedPosition looks at mNeedSync
-            setNextSelectedPositionInt(INVALID_POSITION);
-
-            mSelectorPosition = INVALID_POSITION;
-            mNeedSync = true;
-            mPendingSync = ss;
-            mSyncRowId = ss.firstId;
-            mSyncPosition = ss.position;
-            mSpecificStart = ss.viewStart;
-            mSyncMode = SYNC_FIRST_POSITION;
-        }
-
-        if (ss.checkState != null) {
-            mCheckStates = ss.checkState;
-        }
-
-        if (ss.checkIdState != null) {
-            mCheckedIdStates = ss.checkIdState;
-        }
-
-        mCheckedItemCount = ss.checkedItemCount;
-
-        requestLayout();
-    }
-
-    public static class LayoutParams extends ViewGroup.LayoutParams {
-        /**
-         * Type of this view as reported by the adapter
-         */
-        int viewType;
-
-        /**
-         * The stable ID of the item this view displays
-         */
-        long id = -1;
-
-        /**
-         * The position the view was removed from when pulled out of the
-         * scrap heap.
-         * @hide
-         */
-        int scrappedFromPosition;
-
-        /**
-         * When a TwoWayView is measured with an AT_MOST measure spec, it needs
-         * to obtain children views to measure itself. When doing so, the children
-         * are not attached to the window, but put in the recycler which assumes
-         * they've been attached before. Setting this flag will force the reused
-         * view to be attached to the window rather than just attached to the
-         * parent.
-         */
-        boolean forceAdd;
-
-        public LayoutParams(int width, int height) {
-            super(width, height);
-
-            if (this.width == MATCH_PARENT) {
-                Log.w(LOGTAG, "Constructing LayoutParams with width FILL_PARENT " +
-                        "does not make much sense as the view might change orientation. " +
-                        "Falling back to WRAP_CONTENT");
-                this.width = WRAP_CONTENT;
-            }
-
-            if (this.height == MATCH_PARENT) {
-                Log.w(LOGTAG, "Constructing LayoutParams with height FILL_PARENT " +
-                        "does not make much sense as the view might change orientation. " +
-                        "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(LOGTAG, "Inflation setting LayoutParams width to MATCH_PARENT - " +
-                        "does not make much sense as the view might change orientation. " +
-                        "Falling back to WRAP_CONTENT");
-                this.width = MATCH_PARENT;
-            }
-
-            if (this.height == MATCH_PARENT) {
-                Log.w(LOGTAG, "Inflation setting LayoutParams height to MATCH_PARENT - " +
-                        "does not make much sense as the view might change orientation. " +
-                        "Falling back to WRAP_CONTENT");
-                this.height = WRAP_CONTENT;
-            }
-        }
-
-        public LayoutParams(ViewGroup.LayoutParams other) {
-            super(other);
-
-            if (this.width == MATCH_PARENT) {
-                Log.w(LOGTAG, "Constructing LayoutParams with width MATCH_PARENT - " +
-                        "does not make much sense as the view might change orientation. " +
-                        "Falling back to WRAP_CONTENT");
-                this.width = WRAP_CONTENT;
-            }
-
-            if (this.height == MATCH_PARENT) {
-                Log.w(LOGTAG, "Constructing LayoutParams with height MATCH_PARENT - " +
-                        "does not make much sense as the view might change orientation. " +
-                        "Falling back to WRAP_CONTENT");
-                this.height = WRAP_CONTENT;
-            }
-        }
-    }
-
-    class RecycleBin {
-        private RecyclerListener mRecyclerListener;
-        private int mFirstActivePosition;
-        private View[] mActiveViews = new View[0];
-        private ArrayList<View>[] mScrapViews;
-        private int mViewTypeCount;
-        private ArrayList<View> mCurrentScrap;
-        private SparseArrayCompat<View> mTransientStateViews;
-
-        public void setViewTypeCount(int viewTypeCount) {
-            if (viewTypeCount < 1) {
-                throw new IllegalArgumentException("Can't have a viewTypeCount < 1");
-            }
-
-            @SuppressWarnings({"unchecked", "rawtypes"})
-            ArrayList<View>[] scrapViews = new ArrayList[viewTypeCount];
-            for (int i = 0; i < viewTypeCount; i++) {
-                scrapViews[i] = new ArrayList<View>();
-            }
-
-            mViewTypeCount = viewTypeCount;
-            mCurrentScrap = scrapViews[0];
-            mScrapViews = scrapViews;
-        }
-
-        public void markChildrenDirty() {
-            if (mViewTypeCount == 1) {
-                final ArrayList<View> scrap = mCurrentScrap;
-                final int scrapCount = scrap.size();
-
-                for (int i = 0; i < scrapCount; i++) {
-                    scrap.get(i).forceLayout();
-                }
-            } else {
-                final int typeCount = mViewTypeCount;
-                for (int i = 0; i < typeCount; i++) {
-                    for (View scrap : mScrapViews[i]) {
-                        scrap.forceLayout();
-                    }
-                }
-            }
-
-            if (mTransientStateViews != null) {
-                final int count = mTransientStateViews.size();
-                for (int i = 0; i < count; i++) {
-                    mTransientStateViews.valueAt(i).forceLayout();
-                }
-            }
-        }
-
-        public boolean shouldRecycleViewType(int viewType) {
-            return viewType >= 0;
-        }
-
-        void clear() {
-            if (mViewTypeCount == 1) {
-                final ArrayList<View> scrap = mCurrentScrap;
-                final int scrapCount = scrap.size();
-
-                for (int i = 0; i < scrapCount; i++) {
-                    removeDetachedView(scrap.remove(scrapCount - 1 - i), false);
-                }
-            } else {
-                final int typeCount = mViewTypeCount;
-                for (int i = 0; i < typeCount; i++) {
-                    final ArrayList<View> scrap = mScrapViews[i];
-                    final int scrapCount = scrap.size();
-
-                    for (int j = 0; j < scrapCount; j++) {
-                        removeDetachedView(scrap.remove(scrapCount - 1 - j), false);
-                    }
-                }
-            }
-
-            if (mTransientStateViews != null) {
-                mTransientStateViews.clear();
-            }
-        }
-
-        void fillActiveViews(int childCount, int firstActivePosition) {
-            if (mActiveViews.length < childCount) {
-                mActiveViews = new View[childCount];
-            }
-
-            mFirstActivePosition = firstActivePosition;
-
-            final View[] activeViews = mActiveViews;
-            for (int i = 0; i < childCount; i++) {
-                View child = getChildAt(i);
-
-                // Note:  We do place AdapterView.ITEM_VIEW_TYPE_IGNORE in active views.
-                //        However, we will NOT place them into scrap views.
-                activeViews[i] = child;
-            }
-        }
-
-        View getActiveView(int position) {
-            final int index = position - mFirstActivePosition;
-            final View[] activeViews = mActiveViews;
-
-            if (index >= 0 && index < activeViews.length) {
-                final View match = activeViews[index];
-                activeViews[index] = null;
-
-                return match;
-            }
-
-            return null;
-        }
-
-        View getTransientStateView(int position) {
-            if (mTransientStateViews == null) {
-                return null;
-            }
-
-            final int index = mTransientStateViews.indexOfKey(position);
-            if (index < 0) {
-                return null;
-            }
-
-            final View result = mTransientStateViews.valueAt(index);
-            mTransientStateViews.removeAt(index);
-
-            return result;
-        }
-
-        void clearTransientStateViews() {
-            if (mTransientStateViews != null) {
-                mTransientStateViews.clear();
-            }
-        }
-
-        View getScrapView(int position) {
-            if (mViewTypeCount == 1) {
-                return retrieveFromScrap(mCurrentScrap, position);
-            } else {
-                int whichScrap = mAdapter.getItemViewType(position);
-                if (whichScrap >= 0 && whichScrap < mScrapViews.length) {
-                    return retrieveFromScrap(mScrapViews[whichScrap], position);
-                }
-            }
-
-            return null;
-        }
-
-        @TargetApi(14)
-        void addScrapView(View scrap, int position) {
-            LayoutParams lp = (LayoutParams) scrap.getLayoutParams();
-            if (lp == null) {
-                return;
-            }
-
-            lp.scrappedFromPosition = position;
-
-            final int viewType = lp.viewType;
-            final boolean scrapHasTransientState = ViewCompat.hasTransientState(scrap);
-
-            // Don't put views that should be ignored into the scrap heap
-            if (!shouldRecycleViewType(viewType) || scrapHasTransientState) {
-                if (scrapHasTransientState) {
-                    if (mTransientStateViews == null) {
-                        mTransientStateViews = new SparseArrayCompat<View>();
-                    }
-
-                    mTransientStateViews.put(position, scrap);
-                }
-
-                return;
-            }
-
-            if (mViewTypeCount == 1) {
-                mCurrentScrap.add(scrap);
-            } else {
-                mScrapViews[viewType].add(scrap);
-            }
-
-            // FIXME: Unfortunately, ViewCompat.setAccessibilityDelegate() doesn't accept
-            // null delegates.
-            if (Build.VERSION.SDK_INT >= 14) {
-                scrap.setAccessibilityDelegate(null);
-            }
-
-            if (mRecyclerListener != null) {
-                mRecyclerListener.onMovedToScrapHeap(scrap);
-            }
-        }
-
-        @TargetApi(14)
-        void scrapActiveViews() {
-            final View[] activeViews = mActiveViews;
-            final boolean multipleScraps = (mViewTypeCount > 1);
-
-            ArrayList<View> scrapViews = mCurrentScrap;
-            final int count = activeViews.length;
-
-            for (int i = count - 1; i >= 0; i--) {
-                final View victim = activeViews[i];
-                if (victim != null) {
-                    final LayoutParams lp = (LayoutParams) victim.getLayoutParams();
-                    int whichScrap = lp.viewType;
-
-                    activeViews[i] = null;
-
-                    final boolean scrapHasTransientState = ViewCompat.hasTransientState(victim);
-                    if (!shouldRecycleViewType(whichScrap) || scrapHasTransientState) {
-                        if (scrapHasTransientState) {
-                            removeDetachedView(victim, false);
-
-                            if (mTransientStateViews == null) {
-                                mTransientStateViews = new SparseArrayCompat<View>();
-                            }
-
-                            mTransientStateViews.put(mFirstActivePosition + i, victim);
-                        }
-
-                        continue;
-                    }
-
-                    if (multipleScraps) {
-                        scrapViews = mScrapViews[whichScrap];
-                    }
-
-                    lp.scrappedFromPosition = mFirstActivePosition + i;
-                    scrapViews.add(victim);
-
-                    // FIXME: Unfortunately, ViewCompat.setAccessibilityDelegate() doesn't accept
-                    // null delegates.
-                    if (Build.VERSION.SDK_INT >= 14) {
-                        victim.setAccessibilityDelegate(null);
-                    }
-
-                    if (mRecyclerListener != null) {
-                        mRecyclerListener.onMovedToScrapHeap(victim);
-                    }
-                }
-            }
-
-            pruneScrapViews();
-        }
-
-        private void pruneScrapViews() {
-            final int maxViews = mActiveViews.length;
-            final int viewTypeCount = mViewTypeCount;
-            final ArrayList<View>[] scrapViews = mScrapViews;
-
-            for (int i = 0; i < viewTypeCount; ++i) {
-                final ArrayList<View> scrapPile = scrapViews[i];
-                int size = scrapPile.size();
-                final int extras = size - maxViews;
-
-                size--;
-
-                for (int j = 0; j < extras; j++) {
-                    removeDetachedView(scrapPile.remove(size--), false);
-                }
-            }
-
-            if (mTransientStateViews != null) {
-                for (int i = 0; i < mTransientStateViews.size(); i++) {
-                    final View v = mTransientStateViews.valueAt(i);
-                    if (!ViewCompat.hasTransientState(v)) {
-                        mTransientStateViews.removeAt(i);
-                        i--;
-                    }
-                }
-            }
-        }
-
-        void reclaimScrapViews(List<View> views) {
-            if (mViewTypeCount == 1) {
-                views.addAll(mCurrentScrap);
-            } else {
-                final int viewTypeCount = mViewTypeCount;
-                final ArrayList<View>[] scrapViews = mScrapViews;
-
-                for (int i = 0; i < viewTypeCount; ++i) {
-                    final ArrayList<View> scrapPile = scrapViews[i];
-                    views.addAll(scrapPile);
-                }
-            }
-        }
-
-        View retrieveFromScrap(ArrayList<View> scrapViews, int position) {
-            int size = scrapViews.size();
-            if (size <= 0) {
-                return null;
-            }
-
-            for (int i = 0; i < size; i++) {
-                final View scrapView = scrapViews.get(i);
-                final LayoutParams lp = (LayoutParams) scrapView.getLayoutParams();
-
-                if (lp.scrappedFromPosition == position) {
-                    scrapViews.remove(i);
-                    return scrapView;
-                }
-            }
-
-            return scrapViews.remove(size - 1);
-        }
-    }
-
-    @Override
-    public void setEmptyView(View emptyView) {
-        super.setEmptyView(emptyView);
-        mEmptyView = emptyView;
-        updateEmptyStatus();
-    }
-
-    @Override
-    public void setFocusable(boolean focusable) {
-        final ListAdapter adapter = getAdapter();
-        final boolean empty = (adapter == null || adapter.getCount() == 0);
-
-        mDesiredFocusableState = focusable;
-        if (!focusable) {
-            mDesiredFocusableInTouchModeState = false;
-        }
-
-        super.setFocusable(focusable && !empty);
-    }
-
-    @Override
-    public void setFocusableInTouchMode(boolean focusable) {
-        final ListAdapter adapter = getAdapter();
-        final boolean empty = (adapter == null || adapter.getCount() == 0);
-
-        mDesiredFocusableInTouchModeState = focusable;
-        if (focusable) {
-            mDesiredFocusableState = true;
-        }
-
-        super.setFocusableInTouchMode(focusable && !empty);
-    }
-
-    private void checkFocus() {
-        final ListAdapter adapter = getAdapter();
-        final boolean focusable = (adapter != null && adapter.getCount() > 0);
-
-        // The order in which we set focusable in touch mode/focusable may matter
-        // for the client, see View.setFocusableInTouchMode() comments for more
-        // details
-        super.setFocusableInTouchMode(focusable && mDesiredFocusableInTouchModeState);
-        super.setFocusable(focusable && mDesiredFocusableState);
-
-        if (mEmptyView != null) {
-            updateEmptyStatus();
-        }
-    }
-
-    private void updateEmptyStatus() {
-        final boolean isEmpty = (mAdapter == null || mAdapter.isEmpty());
-
-        if (isEmpty) {
-            if (mEmptyView != null) {
-                mEmptyView.setVisibility(View.VISIBLE);
-                setVisibility(View.GONE);
-            } else {
-                // If the caller just removed our empty view, make sure the list
-                // view is visible
-                setVisibility(View.VISIBLE);
-            }
-
-            // We are now GONE, so pending layouts will not be dispatched.
-            // Force one here to make sure that the state of the list matches
-            // the state of the adapter.
-            if (mDataChanged) {
-                layout(getLeft(), getTop(), getRight(), getBottom());
-            }
-        } else {
-            if (mEmptyView != null) {
-                mEmptyView.setVisibility(View.GONE);
-            }
-
-            setVisibility(View.VISIBLE);
-        }
-    }
-
-    private class AdapterDataSetObserver extends DataSetObserver {
-        private Parcelable mInstanceState = null;
-
-        @Override
-        public void onChanged() {
-            mDataChanged = true;
-            mOldItemCount = mItemCount;
-            mItemCount = getAdapter().getCount();
-
-            // Detect the case where a cursor that was previously invalidated has
-            // been re-populated with new data.
-            if (TwoWayView.this.mHasStableIds && mInstanceState != null
-                    && mOldItemCount == 0 && mItemCount > 0) {
-                TwoWayView.this.onRestoreInstanceState(mInstanceState);
-                mInstanceState = null;
-            } else {
-                rememberSyncState();
-            }
-
-            checkFocus();
-            requestLayout();
-        }
-
-        @Override
-        public void onInvalidated() {
-            mDataChanged = true;
-
-            if (TwoWayView.this.mHasStableIds) {
-                // Remember the current state for the case where our hosting activity is being
-                // stopped and later restarted
-                mInstanceState = TwoWayView.this.onSaveInstanceState();
-            }
-
-            // Data is invalid so we should reset our state
-            mOldItemCount = mItemCount;
-            mItemCount = 0;
-
-            mSelectedPosition = INVALID_POSITION;
-            mSelectedRowId = INVALID_ROW_ID;
-
-            mNextSelectedPosition = INVALID_POSITION;
-            mNextSelectedRowId = INVALID_ROW_ID;
-
-            mNeedSync = false;
-
-            checkFocus();
-            requestLayout();
-        }
-    }
-
-    static class SavedState extends BaseSavedState {
-        long selectedId;
-        long firstId;
-        int viewStart;
-        int position;
-        int size;
-        int checkedItemCount;
-        SparseBooleanArray checkState;
-        LongSparseArray<Integer> checkIdState;
-
-        /**
-         * Constructor called from {@link TwoWayView#onSaveInstanceState()}
-         */
-        SavedState(Parcelable superState) {
-            super(superState);
-        }
-
-        /**
-         * Constructor called from {@link #CREATOR}
-         */
-        private SavedState(Parcel in) {
-            super(in);
-
-            selectedId = in.readLong();
-            firstId = in.readLong();
-            viewStart = in.readInt();
-            position = in.readInt();
-            size = in.readInt();
-
-            checkedItemCount = in.readInt();
-            checkState = in.readSparseBooleanArray();
-
-            final int N = in.readInt();
-            if (N > 0) {
-                checkIdState = new LongSparseArray<Integer>();
-                for (int i = 0; i < N; i++) {
-                    final long key = in.readLong();
-                    final int value = in.readInt();
-                    checkIdState.put(key, value);
-                }
-            }
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            super.writeToParcel(out, flags);
-
-            out.writeLong(selectedId);
-            out.writeLong(firstId);
-            out.writeInt(viewStart);
-            out.writeInt(position);
-            out.writeInt(size);
-
-            out.writeInt(checkedItemCount);
-            out.writeSparseBooleanArray(checkState);
-
-            final int N = checkIdState != null ? checkIdState.size() : 0;
-            out.writeInt(N);
-
-            for (int i = 0; i < N; i++) {
-                out.writeLong(checkIdState.keyAt(i));
-                out.writeInt(checkIdState.valueAt(i));
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "TwoWayView.SavedState{"
-                    + Integer.toHexString(System.identityHashCode(this))
-                    + " selectedId=" + selectedId
-                    + " firstId=" + firstId
-                    + " viewStart=" + viewStart
-                    + " size=" + size
-                    + " position=" + position
-                    + " checkState=" + checkState + "}";
-        }
-
-        public static final Parcelable.Creator<SavedState> CREATOR
-                = new Parcelable.Creator<SavedState>() {
-            @Override
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            @Override
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
-    private class SelectionNotifier implements Runnable {
-        @Override
-        public void run() {
-            if (mDataChanged) {
-                // Data has changed between when this SelectionNotifier
-                // was posted and now. We need to wait until the AdapterView
-                // has been synched to the new data.
-                if (mAdapter != null) {
-                    post(this);
-                }
-            } else {
-                fireOnSelected();
-                performAccessibilityActionsOnSelected();
-            }
-        }
-    }
-
-    private class WindowRunnable {
-        private int mOriginalAttachCount;
-
-        public void rememberWindowAttachCount() {
-            mOriginalAttachCount = getWindowAttachCount();
-        }
-
-        public boolean sameWindow() {
-            return hasWindowFocus() && getWindowAttachCount() == mOriginalAttachCount;
-        }
-    }
-
-    private class PerformClick extends WindowRunnable implements Runnable {
-        int mClickMotionPosition;
-
-        @Override
-        public void run() {
-            if (mDataChanged) {
-                return;
-            }
-
-            final ListAdapter adapter = mAdapter;
-            final int motionPosition = mClickMotionPosition;
-
-            if (adapter != null && mItemCount > 0 &&
-                motionPosition != INVALID_POSITION &&
-                motionPosition < adapter.getCount() && sameWindow()) {
-
-                final View child = getChildAt(motionPosition - mFirstPosition);
-                if (child != null) {
-                    performItemClick(child, motionPosition, adapter.getItemId(motionPosition));
-                }
-            }
-        }
-    }
-
-    private final class CheckForTap implements Runnable {
-        @Override
-        public void run() {
-            if (mTouchMode != TOUCH_MODE_DOWN) {
-                return;
-            }
-
-            mTouchMode = TOUCH_MODE_TAP;
-
-            final View child = getChildAt(mMotionPosition - mFirstPosition);
-            if (child != null && !child.hasFocusable()) {
-                mLayoutMode = LAYOUT_NORMAL;
-
-                if (!mDataChanged) {
-                    setPressed(true);
-                    child.setPressed(true);
-
-                    layoutChildren();
-                    positionSelector(mMotionPosition, child);
-                    refreshDrawableState();
-
-                    positionSelector(mMotionPosition, child);
-                    refreshDrawableState();
-
-                    final boolean longClickable = isLongClickable();
-
-                    if (mSelector != null) {
-                        Drawable d = mSelector.getCurrent();
-
-                        if (d != null && d instanceof TransitionDrawable) {
-                            if (longClickable) {
-                                final int longPressTimeout = ViewConfiguration.getLongPressTimeout();
-                                ((TransitionDrawable) d).startTransition(longPressTimeout);
-                            } else {
-                                ((TransitionDrawable) d).resetTransition();
-                            }
-                        }
-                    }
-
-                    if (longClickable) {
-                        triggerCheckForLongPress();
-                    } else {
-                        mTouchMode = TOUCH_MODE_DONE_WAITING;
-                    }
-                } else {
-                    mTouchMode = TOUCH_MODE_DONE_WAITING;
-                }
-            }
-        }
-    }
-
-    private class CheckForLongPress extends WindowRunnable implements Runnable {
-        @Override
-        public void run() {
-            final int motionPosition = mMotionPosition;
-            final View child = getChildAt(motionPosition - mFirstPosition);
-
-            if (child != null) {
-                final long longPressId = mAdapter.getItemId(mMotionPosition);
-
-                boolean handled = false;
-                if (sameWindow() && !mDataChanged) {
-                    handled = performLongPress(child, motionPosition, longPressId);
-                }
-
-                if (handled) {
-                    mTouchMode = TOUCH_MODE_REST;
-                    setPressed(false);
-                    child.setPressed(false);
-                } else {
-                    mTouchMode = TOUCH_MODE_DONE_WAITING;
-                }
-            }
-        }
-    }
-
-    private class CheckForKeyLongPress extends WindowRunnable implements Runnable {
-        public void run() {
-            if (!isPressed() || mSelectedPosition < 0) {
-                return;
-            }
-
-            final int index = mSelectedPosition - mFirstPosition;
-            final View v = getChildAt(index);
-
-            if (!mDataChanged) {
-                boolean handled = false;
-
-                if (sameWindow()) {
-                    handled = performLongPress(v, mSelectedPosition, mSelectedRowId);
-                }
-
-                if (handled) {
-                    setPressed(false);
-                    v.setPressed(false);
-                }
-            } else {
-                setPressed(false);
-
-                if (v != null) {
-                    v.setPressed(false);
-                }
-            }
-        }
-    }
-
-    private static class ArrowScrollFocusResult {
-        private int mSelectedPosition;
-        private int mAmountToScroll;
-
-        /**
-         * How {@link TwoWayView#arrowScrollFocused} returns its values.
-         */
-        void populate(int selectedPosition, int amountToScroll) {
-            mSelectedPosition = selectedPosition;
-            mAmountToScroll = amountToScroll;
-        }
-
-        public int getSelectedPosition() {
-            return mSelectedPosition;
-        }
-
-        public int getAmountToScroll() {
-            return mAmountToScroll;
-        }
-    }
-
-    private class ListItemAccessibilityDelegate extends AccessibilityDelegateCompat {
-        @Override
-        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
-            super.onInitializeAccessibilityNodeInfo(host, info);
-
-            final int position = getPositionForView(host);
-            final ListAdapter adapter = getAdapter();
-
-            // Cannot perform actions on invalid items
-            if (position == INVALID_POSITION || adapter == null) {
-                return;
-            }
-
-            // Cannot perform actions on disabled items
-            if (!isEnabled() || !adapter.isEnabled(position)) {
-                return;
-            }
-
-            if (position == getSelectedItemPosition()) {
-                info.setSelected(true);
-                info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_SELECTION);
-            } else {
-                info.addAction(AccessibilityNodeInfoCompat.ACTION_SELECT);
-            }
-
-            if (isClickable()) {
-                info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
-                info.setClickable(true);
-            }
-
-            if (isLongClickable()) {
-                info.addAction(AccessibilityNodeInfoCompat.ACTION_LONG_CLICK);
-                info.setLongClickable(true);
-            }
-        }
-
-        @Override
-        public boolean performAccessibilityAction(View host, int action, Bundle arguments) {
-            if (super.performAccessibilityAction(host, action, arguments)) {
-                return true;
-            }
-
-            final int position = getPositionForView(host);
-            final ListAdapter adapter = getAdapter();
-
-            // Cannot perform actions on invalid items
-            if (position == INVALID_POSITION || adapter == null) {
-                return false;
-            }
-
-            // Cannot perform actions on disabled items
-            if (!isEnabled() || !adapter.isEnabled(position)) {
-                return false;
-            }
-
-            final long id = getItemIdAtPosition(position);
-
-            switch (action) {
-            case AccessibilityNodeInfoCompat.ACTION_CLEAR_SELECTION:
-                if (getSelectedItemPosition() == position) {
-                    setSelection(INVALID_POSITION);
-                    return true;
-                }
-                return false;
-
-            case AccessibilityNodeInfoCompat.ACTION_SELECT:
-                if (getSelectedItemPosition() != position) {
-                    setSelection(position);
-                    return true;
-                }
-                return false;
-
-            case AccessibilityNodeInfoCompat.ACTION_CLICK:
-                return isClickable() && performItemClick(host, position, id);
-
-            case AccessibilityNodeInfoCompat.ACTION_LONG_CLICK:
-                return isLongClickable() && performLongPress(host, position, id);
-            }
-
-            return false;
-        }
-    }
-
-    private class PositionScroller implements Runnable {
-        private static final int SCROLL_DURATION = 200;
-
-        private static final int MOVE_AFTER_POS = 1;
-        private static final int MOVE_BEFORE_POS = 2;
-        private static final int MOVE_AFTER_BOUND = 3;
-        private static final int MOVE_BEFORE_BOUND = 4;
-        private static final int MOVE_OFFSET = 5;
-
-        private int mMode;
-        private int mTargetPosition;
-        private int mBoundPosition;
-        private int mLastSeenPosition;
-        private int mScrollDuration;
-        private final int mExtraScroll;
-
-        private int mOffsetFromStart;
-
-        PositionScroller() {
-            mExtraScroll = ViewConfiguration.get(mContext).getScaledFadingEdgeLength();
-        }
-
-        void start(final int position) {
-            stop();
-
-            if (mDataChanged) {
-                // Wait until we're back in a stable state to try this.
-                mPositionScrollAfterLayout = new Runnable() {
-                    @Override public void run() {
-                        start(position);
-                    }
-                };
-
-                return;
-            }
-
-            final int childCount = getChildCount();
-            if (childCount == 0) {
-                // Can't scroll without children.
-                return;
-            }
-
-            final int firstPosition = mFirstPosition;
-            final int lastPosition = firstPosition + childCount - 1;
-
-            final int clampedPosition = Math.max(0, Math.min(getCount() - 1, position));
-
-            final int viewTravelCount;
-            if (clampedPosition < firstPosition) {
-                viewTravelCount = firstPosition - clampedPosition + 1;
-                mMode = MOVE_BEFORE_POS;
-            } else if (clampedPosition > lastPosition) {
-                viewTravelCount = clampedPosition - lastPosition + 1;
-                mMode = MOVE_AFTER_POS;
-            } else {
-                scrollToVisible(clampedPosition, INVALID_POSITION, SCROLL_DURATION);
-                return;
-            }
-
-            if (viewTravelCount > 0) {
-                mScrollDuration = SCROLL_DURATION / viewTravelCount;
-            } else {
-                mScrollDuration = SCROLL_DURATION;
-            }
-
-            mTargetPosition = clampedPosition;
-            mBoundPosition = INVALID_POSITION;
-            mLastSeenPosition = INVALID_POSITION;
-
-            ViewCompat.postOnAnimation(TwoWayView.this, this);
-        }
-
-        void start(final int position, final int boundPosition) {
-            stop();
-
-            if (boundPosition == INVALID_POSITION) {
-                start(position);
-                return;
-            }
-
-            if (mDataChanged) {
-                // Wait until we're back in a stable state to try this.
-                mPositionScrollAfterLayout = new Runnable() {
-                    @Override public void run() {
-                        start(position, boundPosition);
-                    }
-                };
-
-                return;
-            }
-
-            final int childCount = getChildCount();
-            if (childCount == 0) {
-                // Can't scroll without children.
-                return;
-            }
-
-            final int firstPosition = mFirstPosition;
-            final int lastPosition = firstPosition + childCount - 1;
-
-            final int clampedPosition = Math.max(0, Math.min(getCount() - 1, position));
-
-            final int viewTravelCount;
-            if (clampedPosition < firstPosition) {
-                final int boundPositionFromLast = lastPosition - boundPosition;
-                if (boundPositionFromLast < 1) {
-                    // Moving would shift our bound position off the screen. Abort.
-                    return;
-                }
-
-                final int positionTravel = firstPosition - clampedPosition + 1;
-                final int boundTravel = boundPositionFromLast - 1;
-                if (boundTravel < positionTravel) {
-                    viewTravelCount = boundTravel;
-                    mMode = MOVE_BEFORE_BOUND;
-                } else {
-                    viewTravelCount = positionTravel;
-                    mMode = MOVE_BEFORE_POS;
-                }
-            } else if (clampedPosition > lastPosition) {
-                final int boundPositionFromFirst = boundPosition - firstPosition;
-                if (boundPositionFromFirst < 1) {
-                    // Moving would shift our bound position off the screen. Abort.
-                    return;
-                }
-
-                final int positionTravel = clampedPosition - lastPosition + 1;
-                final int boundTravel = boundPositionFromFirst - 1;
-                if (boundTravel < positionTravel) {
-                    viewTravelCount = boundTravel;
-                    mMode = MOVE_AFTER_BOUND;
-                } else {
-                    viewTravelCount = positionTravel;
-                    mMode = MOVE_AFTER_POS;
-                }
-            } else {
-                scrollToVisible(clampedPosition, boundPosition, SCROLL_DURATION);
-                return;
-            }
-
-            if (viewTravelCount > 0) {
-                mScrollDuration = SCROLL_DURATION / viewTravelCount;
-            } else {
-                mScrollDuration = SCROLL_DURATION;
-            }
-
-            mTargetPosition = clampedPosition;
-            mBoundPosition = boundPosition;
-            mLastSeenPosition = INVALID_POSITION;
-
-            ViewCompat.postOnAnimation(TwoWayView.this, this);
-        }
-
-        void startWithOffset(int position, int offset) {
-            startWithOffset(position, offset, SCROLL_DURATION);
-        }
-
-        void startWithOffset(final int position, int offset, final int duration) {
-            stop();
-
-            if (mDataChanged) {
-                // Wait until we're back in a stable state to try this.
-                final int postOffset = offset;
-                mPositionScrollAfterLayout = new Runnable() {
-                    @Override public void run() {
-                        startWithOffset(position, postOffset, duration);
-                    }
-                };
-
-                return;
-            }
-
-            final int childCount = getChildCount();
-            if (childCount == 0) {
-                // Can't scroll without children.
-                return;
-            }
-
-            offset += getStartEdge();
-
-            mTargetPosition = Math.max(0, Math.min(getCount() - 1, position));
-            mOffsetFromStart = offset;
-            mBoundPosition = INVALID_POSITION;
-            mLastSeenPosition = INVALID_POSITION;
-            mMode = MOVE_OFFSET;
-
-            final int firstPosition = mFirstPosition;
-            final int lastPosition = firstPosition + childCount - 1;
-
-            final int viewTravelCount;
-            if (mTargetPosition < firstPosition) {
-                viewTravelCount = firstPosition - mTargetPosition;
-            } else if (mTargetPosition > lastPosition) {
-                viewTravelCount = mTargetPosition - lastPosition;
-            } else {
-                // On-screen, just scroll.
-                final View targetView = getChildAt(mTargetPosition - firstPosition);
-                final int targetStart = getChildStartEdge(targetView);
-                smoothScrollBy(targetStart - offset, duration);
-                return;
-            }
-
-            // Estimate how many screens we should travel
-            final float screenTravelCount = (float) viewTravelCount / childCount;
-            mScrollDuration = screenTravelCount < 1 ?
-                    duration : (int) (duration / screenTravelCount);
-            mLastSeenPosition = INVALID_POSITION;
-
-            ViewCompat.postOnAnimation(TwoWayView.this, this);
-        }
-
-        /**
-         * Scroll such that targetPos is in the visible padded region without scrolling
-         * boundPos out of view. Assumes targetPos is onscreen.
-         */
-        void scrollToVisible(int targetPosition, int boundPosition, int duration) {
-            final int childCount = getChildCount();
-            final int firstPosition = mFirstPosition;
-            final int lastPosition = firstPosition + childCount - 1;
-
-            final int start = getStartEdge();
-            final int end = getEndEdge();
-
-            if (targetPosition < firstPosition || targetPosition > lastPosition) {
-                Log.w(LOGTAG, "scrollToVisible called with targetPosition " + targetPosition +
-                        " not visible [" + firstPosition + ", " + lastPosition + "]");
-            }
-
-            if (boundPosition < firstPosition || boundPosition > lastPosition) {
-                // boundPos doesn't matter, it's already offscreen.
-                boundPosition = INVALID_POSITION;
-            }
-
-            final View targetChild = getChildAt(targetPosition - firstPosition);
-            final int targetStart = getChildStartEdge(targetChild);
-            final int targetEnd = getChildEndEdge(targetChild);
-
-            int scrollBy = 0;
-            if (targetEnd > end) {
-                scrollBy = targetEnd - end;
-            }
-            if (targetStart < start) {
-                scrollBy = targetStart - start;
-            }
-
-            if (scrollBy == 0) {
-                return;
-            }
-
-            if (boundPosition >= 0) {
-                final View boundChild = getChildAt(boundPosition - firstPosition);
-                final int boundStart = getChildStartEdge(boundChild);
-                final int boundEnd = getChildEndEdge(boundChild);
-                final int absScroll = Math.abs(scrollBy);
-
-                if (scrollBy < 0 && boundEnd + absScroll > end) {
-                    // Don't scroll the bound view off the end of the screen.
-                    scrollBy = Math.max(0, boundEnd - end);
-                } else if (scrollBy > 0 && boundStart - absScroll < start) {
-                    // Don't scroll the bound view off the top of the screen.
-                    scrollBy = Math.min(0, boundStart - start);
-                }
-            }
-
-            smoothScrollBy(scrollBy, duration);
-        }
-
-        void stop() {
-            removeCallbacks(this);
-        }
-
-        @Override
-        public void run() {
-            final int size = getAvailableSize();
-            final int firstPosition = mFirstPosition;
-
-            final int startPadding = (mIsVertical ? getPaddingTop() : getPaddingLeft());
-            final int endPadding = (mIsVertical ? getPaddingBottom() : getPaddingRight());
-
-            switch (mMode) {
-                case MOVE_AFTER_POS: {
-                    final int lastViewIndex = getChildCount() - 1;
-                    if (lastViewIndex < 0) {
-                        return;
-                    }
-
-                    final int lastPosition = firstPosition + lastViewIndex;
-                    if (lastPosition == mLastSeenPosition) {
-                        // No new views, let things keep going.
-                        ViewCompat.postOnAnimation(TwoWayView.this, this);
-                        return;
-                    }
-
-                    final View lastView = getChildAt(lastViewIndex);
-                    final int lastViewSize = getChildSize(lastView);
-                    final int lastViewStart = getChildStartEdge(lastView);
-                    final int lastViewPixelsShowing = size - lastViewStart;
-                    final int extraScroll = lastPosition < mItemCount - 1 ?
-                            Math.max(endPadding, mExtraScroll) : endPadding;
-
-                    final int scrollBy = lastViewSize - lastViewPixelsShowing + extraScroll;
-                    smoothScrollBy(scrollBy, mScrollDuration);
-
-                    mLastSeenPosition = lastPosition;
-                    if (lastPosition < mTargetPosition) {
-                        ViewCompat.postOnAnimation(TwoWayView.this, this);
-                    }
-
-                    break;
-                }
-
-                case MOVE_AFTER_BOUND: {
-                    final int nextViewIndex = 1;
-                    final int childCount = getChildCount();
-                    if (firstPosition == mBoundPosition ||
-                        childCount <= nextViewIndex ||
-                        firstPosition + childCount >= mItemCount) {
-                        return;
-                    }
-
-                    final int nextPosition = firstPosition + nextViewIndex;
-
-                    if (nextPosition == mLastSeenPosition) {
-                        // No new views, let things keep going.
-                        ViewCompat.postOnAnimation(TwoWayView.this, this);
-                        return;
-                    }
-
-                    final View nextView = getChildAt(nextViewIndex);
-                    final int nextViewSize = getChildSize(nextView);
-                    final int nextViewStart = getChildStartEdge(nextView);
-                    final int extraScroll = Math.max(endPadding, mExtraScroll);
-                    if (nextPosition < mBoundPosition) {
-                        smoothScrollBy(Math.max(0, nextViewSize + nextViewStart - extraScroll),
-                                mScrollDuration);
-                        mLastSeenPosition = nextPosition;
-                        ViewCompat.postOnAnimation(TwoWayView.this, this);
-                    } else  {
-                        if (nextViewSize > extraScroll) {
-                            smoothScrollBy(nextViewSize - extraScroll, mScrollDuration);
-                        }
-                    }
-
-                    break;
-                }
-
-                case MOVE_BEFORE_POS: {
-                    if (firstPosition == mLastSeenPosition) {
-                        // No new views, let things keep going.
-                        ViewCompat.postOnAnimation(TwoWayView.this, this);
-                        return;
-                    }
-
-                    final View firstView = getChildAt(0);
-                    if (firstView == null) {
-                        return;
-                    }
-
-                    final int firstViewTop = getChildStartEdge(firstView);
-                    final int extraScroll = firstPosition > 0 ?
-                            Math.max(mExtraScroll, startPadding) : startPadding;
-
-                    smoothScrollBy(firstViewTop - extraScroll, mScrollDuration);
-                    mLastSeenPosition = firstPosition;
-
-                    if (firstPosition > mTargetPosition) {
-                        ViewCompat.postOnAnimation(TwoWayView.this, this);
-                    }
-
-                    break;
-                }
-
-                case MOVE_BEFORE_BOUND: {
-                    final int lastViewIndex = getChildCount() - 2;
-                    if (lastViewIndex < 0) {
-                        return;
-                    }
-
-                    final int lastPosition = firstPosition + lastViewIndex;
-
-                    if (lastPosition == mLastSeenPosition) {
-                        // No new views, let things keep going.
-                        ViewCompat.postOnAnimation(TwoWayView.this, this);
-                        return;
-                    }
-
-                    final View lastView = getChildAt(lastViewIndex);
-                    final int lastViewSize = getChildSize(lastView);
-                    final int lastViewStart = getChildStartEdge(lastView);
-                    final int lastViewPixelsShowing = size - lastViewStart;
-                    final int extraScroll = Math.max(startPadding, mExtraScroll);
-
-                    mLastSeenPosition = lastPosition;
-
-                    if (lastPosition > mBoundPosition) {
-                        smoothScrollBy(-(lastViewPixelsShowing - extraScroll), mScrollDuration);
-                        ViewCompat.postOnAnimation(TwoWayView.this, this);
-                    } else {
-                        final int end = size - extraScroll;
-                        final int lastViewEnd = lastViewStart + lastViewSize;
-                        if (end > lastViewEnd) {
-                            smoothScrollBy(-(end - lastViewEnd), mScrollDuration);
-                        }
-                    }
-
-                    break;
-                }
-
-                case MOVE_OFFSET: {
-                    if (mLastSeenPosition == firstPosition) {
-                        // No new views, let things keep going.
-                        ViewCompat.postOnAnimation(TwoWayView.this, this);
-                        return;
-                    }
-
-                    mLastSeenPosition = firstPosition;
-
-                    final int childCount = getChildCount();
-                    final int position = mTargetPosition;
-                    final int lastPos = firstPosition + childCount - 1;
-
-                    int viewTravelCount = 0;
-                    if (position < firstPosition) {
-                        viewTravelCount = firstPosition - position + 1;
-                    } else if (position > lastPos) {
-                        viewTravelCount = position - lastPos;
-                    }
-
-                    // Estimate how many screens we should travel
-                    final float screenTravelCount = (float) viewTravelCount / childCount;
-
-                    final float modifier = Math.min(Math.abs(screenTravelCount), 1.f);
-                    if (position < firstPosition) {
-                        final int distance = (int) (-getSize() * modifier);
-                        final int duration = (int) (mScrollDuration * modifier);
-                        smoothScrollBy(distance, duration);
-                        ViewCompat.postOnAnimation(TwoWayView.this, this);
-                    } else if (position > lastPos) {
-                        final int distance = (int) (getSize() * modifier);
-                        final int duration = (int) (mScrollDuration * modifier);
-                        smoothScrollBy(distance, duration);
-                        ViewCompat.postOnAnimation(TwoWayView.this, this);
-                    } else {
-                        // On-screen, just scroll.
-                        final View targetView = getChildAt(position - firstPosition);
-                        final int targetStart = getChildStartEdge(targetView);
-                        final int distance = targetStart - mOffsetFromStart;
-                        final int duration = (int) (mScrollDuration *
-                                ((float) Math.abs(distance) / getSize()));
-                        smoothScrollBy(distance, duration);
-                    }
-
-                    break;
-                }
-
-                default:
-                    break;
-            }
-        }
-    }
-}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -796,17 +796,16 @@ gbjar.sources += ['java/org/mozilla/geck
     'widget/RoundedCornerLayout.java',
     'widget/SiteLogins.java',
     'widget/SquaredImageView.java',
     'widget/SquaredRelativeLayout.java',
     'widget/SwipeDismissListViewTouchListener.java',
     'widget/TabThumbnailWrapper.java',
     'widget/ThumbnailView.java',
     'widget/TouchDelegateWithReset.java',
-    'widget/TwoWayView.java',
     'ZoomedView.java',
 ]]
 # The following sources are checked in to version control but
 # generated by a script (java/org/mozilla/gecko/widget/themed/generate_themed_views.py).
 # If you're editing this list, make sure to edit that script.
 gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
     'widget/themed/ThemedEditText.java',
     'widget/themed/ThemedFrameLayout.java',
--- a/mobile/android/base/resources/layout/search_engine_bar_item.xml
+++ b/mobile/android/base/resources/layout/search_engine_bar_item.xml
@@ -1,18 +1,14 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
-<!-- TwoWayView doesn't let us set the margin around items (except as
-     gecko:itemMargin, but that doesn't increase the hit area) so we
-     have to surround the main View by a ViewGroup to create a pressable margin.
-
-     Note: the layout_height values are shared with the parent
+<!-- Note: the layout_height values are shared with the parent
      View (browser_search at the time of this writing).
 
      The actual width of the FrameLayout is calculated at runtime by the
      SearchEngineBar class to spread the icons across the device's width. -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/search_engine_icon_container"
     android:layout_width="72dp"
--- a/mobile/android/base/resources/layout/search_engine_bar_label.xml
+++ b/mobile/android/base/resources/layout/search_engine_bar_label.xml
@@ -1,16 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
-<!-- TwoWayView doesn't let us set the margin around items (except as
-     gecko:itemMargin, but that doesn't increase the hit area) so we
-     have to surround the main View by a ViewGroup to create a pressable margin. -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="48dp"
     android:layout_height="match_parent"
     android:clickable="true"
     android:background="@color/pressed_about_page_header_grey">
 
     <ImageView
--- a/mobile/android/base/resources/values/attrs.xml
+++ b/mobile/android/base/resources/values/attrs.xml
@@ -95,23 +95,16 @@
     </declare-styleable>
 
     <declare-styleable name="LightweightTheme">
         <attr name="state_light" format="boolean"/>
         <attr name="state_dark" format="boolean"/>
         <attr name="autoUpdateTheme" format="boolean"/>
     </declare-styleable>
 
-    <declare-styleable name="TwoWayView">
-        <attr name="android:orientation"/>
-        <attr name="android:choiceMode"/>
-        <attr name="android:listSelector"/>
-        <attr name="android:drawSelectorOnTop"/>
-    </declare-styleable>
-
     <declare-styleable name="HomeListView">
         <!-- Draws a divider on top of the list, if true. Defaults to false. -->
         <attr name="topDivider" format="boolean"/>
     </declare-styleable>
 
     <declare-styleable name="FadedTextView">
         <attr name="fadeWidth" format="dimension"/>
     </declare-styleable>