Example usage for android.view View requestFocus

List of usage examples for android.view View requestFocus

Introduction

In this page you can find the example usage for android.view View requestFocus.

Prototype

public final boolean requestFocus() 

Source Link

Document

Call this to try to give focus to a specific view or to one of its descendants.

Usage

From source file:com.datarita.ultimatecamera.turu.views.TwoWayView.java

private void layoutChildren() {
    if (getWidth() == 0 || getHeight() == 0) {
        return;/*from www.  ja  v  a  2s .c  o m*/
    }

    final boolean blockLayoutRequests = mBlockLayoutRequests;
    if (!blockLayoutRequests) {
        mBlockLayoutRequests = true;
    } else {
        return;
    }

    try {
        invalidate();

        if (mAdapter == null) {
            resetState();
            return;
        }

        final int start = (mIsVertical ? getPaddingTop() : getPaddingLeft());
        final int end = (mIsVertical ? getHeight() - getPaddingBottom() : getWidth() - getPaddingRight());

        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 mAdapter has changed but "
                    + "TwoWayView did not receive a notification. Make sure the content of "
                    + "your mAdapter 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 = (mIsVertical ? newSelected.getTop() : newSelected.getLeft());

                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 = (mIsVertical ? oldSelected.getTop() : oldSelected.getLeft());
                    }
                    selected = fillSpecific(mSelectedPosition, offset);
                } else if (mFirstPosition < mItemCount) {
                    int offset = start;
                    if (oldFirstChild != null) {
                        offset = (mIsVertical ? oldFirstChild.getTop() : oldFirstChild.getLeft());
                    }

                    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 = (mIsVertical ? selected.getTop() : selected.getLeft());
        } 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;
        }
    }
}

From source file:com.boutline.sports.helpers.TwoWayView.java

private void layoutChildren() {
    if (getWidth() == 0 || getHeight() == 0) {
        return;/* w  w  w .  ja  v  a 2  s  .  c  o m*/
    }

    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 = (mIsVertical ? newSelected.getTop() : newSelected.getLeft());

                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 = (mIsVertical ? oldSelected.getTop() : oldSelected.getLeft());
                    }
                    selected = fillSpecific(mSelectedPosition, offset);
                } else if (mFirstPosition < mItemCount) {
                    int offset = start;
                    if (oldFirstChild != null) {
                        offset = (mIsVertical ? oldFirstChild.getTop() : oldFirstChild.getLeft());
                    }

                    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 = (mIsVertical ? selected.getTop() : selected.getLeft());
        } 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;
        }
    }
}

From source file:com.aliasapps.seq.scroller.TwoWayView.java

private void layoutChildren() {
    if (getWidth() == 0 || getHeight() == 0) {
        return;/*  w w w.  j av  a 2 s  .  co  m*/
    }

    final boolean blockLayoutRequests = mBlockLayoutRequests;
    if (!blockLayoutRequests) {
        mBlockLayoutRequests = true;
    } else {
        return;
    }

    try {
        invalidate();

        if (mAdapter == null) {
            resetState();
            return;
        }

        final int start = (mIsVertical ? getPaddingTop() : getPaddingLeft());
        final int end = (mIsVertical ? getHeight() - getPaddingBottom() : getWidth() - getPaddingRight());

        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 = (mIsVertical ? newSelected.getTop() : newSelected.getLeft());

                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 = (mIsVertical ? oldSelected.getTop() : oldSelected.getLeft());
                    }
                    selected = fillSpecific(mSelectedPosition, offset);
                } else if (mFirstPosition < mItemCount) {
                    int offset = start;
                    if (oldFirstChild != null) {
                        offset = (mIsVertical ? oldFirstChild.getTop() : oldFirstChild.getLeft());
                    }

                    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 = (mIsVertical ? selected.getTop() : selected.getLeft());
        } 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;
        }
    }
}

From source file:com.ferdi2005.secondgram.support.widget.RecyclerView.java

private void recoverFocusFromState() {
    if (!mPreserveFocusAfterLayout || mAdapter == null || !hasFocus()
            || getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS
            || (getDescendantFocusability() == FOCUS_BEFORE_DESCENDANTS && isFocused())) {
        // No-op if either of these cases happens:
        // 1. RV has no focus, or 2. RV blocks focus to its children, or 3. RV takes focus
        // before its children and is focused (i.e. it already stole the focus away from its
        // descendants).
        return;//from   ww  w  . j  av  a 2s  . co m
    }
    // only recover focus if RV itself has the focus or the focused view is hidden
    if (!isFocused()) {
        final View focusedChild = getFocusedChild();
        if (IGNORE_DETACHED_FOCUSED_CHILD && (focusedChild.getParent() == null || !focusedChild.hasFocus())) {
            // Special handling of API 15-. A focused child can be invalid because mFocus is not
            // cleared when the child is detached (mParent = null),
            // This happens because clearFocus on API 15- does not invalidate mFocus of its
            // parent when this child is detached.
            // For API 16+, this is not an issue because requestFocus takes care of clearing the
            // prior detached focused child. For API 15- the problem happens in 2 cases because
            // clearChild does not call clearChildFocus on RV: 1. setFocusable(false) is called
            // for the current focused item which calls clearChild or 2. when the prior focused
            // child is removed, removeDetachedView called in layout step 3 which calls
            // clearChild. We should ignore this invalid focused child in all our calculations
            // for the next view to receive focus, and apply the focus recovery logic instead.
            if (mChildHelper.getChildCount() == 0) {
                // No children left. Request focus on the RV itself since one of its children
                // was holding focus previously.
                requestFocus();
                return;
            }
        } else if (!mChildHelper.isHidden(focusedChild)) {
            // If the currently focused child is hidden, apply the focus recovery logic.
            // Otherwise return, i.e. the currently (unhidden) focused child is good enough :/.
            return;
        }
    }
    ViewHolder focusTarget = null;
    // RV first attempts to locate the previously focused item to request focus on using
    // mFocusedItemId. If such an item no longer exists, it then makes a best-effort attempt to
    // find the next best candidate to request focus on based on mFocusedItemPosition.
    if (mState.mFocusedItemId != NO_ID && mAdapter.hasStableIds()) {
        focusTarget = findViewHolderForItemId(mState.mFocusedItemId);
    }
    View viewToFocus = null;
    if (focusTarget == null || mChildHelper.isHidden(focusTarget.itemView)
            || !focusTarget.itemView.hasFocusable()) {
        if (mChildHelper.getChildCount() > 0) {
            // At this point, RV has focus and either of these conditions are true:
            // 1. There's no previously focused item either because RV received focused before
            // layout, or the previously focused item was removed, or RV doesn't have stable IDs
            // 2. Previous focus child is hidden, or 3. Previous focused child is no longer
            // focusable. In either of these cases, we make sure that RV still passes down the
            // focus to one of its focusable children using a best-effort algorithm.
            viewToFocus = findNextViewToFocus();
        }
    } else {
        // looks like the focused item has been replaced with another view that represents the
        // same item in the adapter. Request focus on that.
        viewToFocus = focusTarget.itemView;
    }

    if (viewToFocus != null) {
        if (mState.mFocusedSubChildId != NO_ID) {
            View child = viewToFocus.findViewById(mState.mFocusedSubChildId);
            if (child != null && child.isFocusable()) {
                viewToFocus = child;
            }
        }
        viewToFocus.requestFocus();
    }
}

From source file:com.artifex.mupdf.view.ThumbnailViews.java

private void layoutChildren() {
    if (getWidth() == 0 || getHeight() == 0) {
        return;/*from w w  w . ja  v  a 2 s.c o m*/
    }

    final boolean blockLayoutRequests = mBlockLayoutRequests;
    if (!blockLayoutRequests) {
        mBlockLayoutRequests = true;
    } else {
        return;
    }

    try {
        invalidate();

        if (mAdapter == null) {
            resetState();
            return;
        }

        final int start = (mIsVertical ? getPaddingTop() : getPaddingLeft());
        final int end = (mIsVertical ? getHeight() - getPaddingBottom() : getWidth() - getPaddingRight());

        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 = (mIsVertical ? newSelected.getTop() : newSelected.getLeft());

                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 = (mIsVertical ? oldSelected.getTop() : oldSelected.getLeft());
                    }
                    selected = fillSpecific(mSelectedPosition, offset);
                } else if (mFirstPosition < mItemCount) {
                    int offset = start;
                    if (oldFirstChild != null) {
                        offset = (mIsVertical ? oldFirstChild.getTop() : oldFirstChild.getLeft());
                    }

                    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 = (mIsVertical ? selected.getTop() : selected.getLeft());
        } 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;
        }
    }
}

From source file:com.artifex.mupdflib.TwoWayView.java

private void layoutChildren() {
    if (getWidth() == 0 || getHeight() == 0) {
        return;/* w  w w  .j  av  a2 s  . c o m*/
    }

    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;
        }
    }
}