summaryrefslogtreecommitdiffstats
path: root/actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsAdapterView.java
diff options
context:
space:
mode:
Diffstat (limited to 'actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsAdapterView.java')
-rw-r--r--actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsAdapterView.java1160
1 files changed, 0 insertions, 1160 deletions
diff --git a/actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsAdapterView.java b/actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsAdapterView.java
deleted file mode 100644
index c786dc5c1..000000000
--- a/actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsAdapterView.java
+++ /dev/null
@@ -1,1160 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.actionbarsherlock.internal.widget;
-
-import android.content.Context;
-import android.database.DataSetObserver;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.util.AttributeSet;
-import android.util.SparseArray;
-import android.view.ContextMenu;
-import android.view.SoundEffectConstants;
-import android.view.View;
-import android.view.ViewDebug;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.Adapter;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ListView;
-
-
-/**
- * An AdapterView is a view whose children are determined by an {@link Adapter}.
- *
- * <p>
- * See {@link ListView}, {@link GridView}, {@link Spinner} and
- * {@link Gallery} for commonly used subclasses of AdapterView.
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about using AdapterView, read the
- * <a href="{@docRoot}guide/topics/ui/binding.html">Binding to Data with AdapterView</a>
- * developer guide.</p></div>
- */
-public abstract class IcsAdapterView<T extends Adapter> extends ViewGroup {
-
- /**
- * The item view type returned by {@link Adapter#getItemViewType(int)} when
- * the adapter does not want the item's view recycled.
- */
- public static final int ITEM_VIEW_TYPE_IGNORE = -1;
-
- /**
- * The item view type returned by {@link Adapter#getItemViewType(int)} when
- * the item is a header or footer.
- */
- public static final int ITEM_VIEW_TYPE_HEADER_OR_FOOTER = -2;
-
- /**
- * The position of the first child displayed
- */
- @ViewDebug.ExportedProperty(category = "scrolling")
- int mFirstPosition = 0;
-
- /**
- * The offset in pixels from the top of the AdapterView to the top
- * of the view to select during the next layout.
- */
- int mSpecificTop;
-
- /**
- * Position from which to start looking for mSyncRowId
- */
- int mSyncPosition;
-
- /**
- * Row id to look for when data has changed
- */
- long mSyncRowId = INVALID_ROW_ID;
-
- /**
- * Height of the view when mSyncPosition and mSyncRowId where set
- */
- long mSyncHeight;
-
- /**
- * True if we need to sync to mSyncRowId
- */
- boolean mNeedSync = false;
-
- /**
- * Indicates whether to sync based on the selection or position. Possible
- * values are {@link #SYNC_SELECTED_POSITION} or
- * {@link #SYNC_FIRST_POSITION}.
- */
- int mSyncMode;
-
- /**
- * Our height after the last layout
- */
- private int mLayoutHeight;
-
- /**
- * Sync based on the selected child
- */
- static final int SYNC_SELECTED_POSITION = 0;
-
- /**
- * Sync based on the first child displayed
- */
- static final int SYNC_FIRST_POSITION = 1;
-
- /**
- * Maximum amount of time to spend in {@link #findSyncPosition()}
- */
- static final int SYNC_MAX_DURATION_MILLIS = 100;
-
- /**
- * Indicates that this view is currently being laid out.
- */
- boolean mInLayout = false;
-
- /**
- * The listener that receives notifications when an item is selected.
- */
- OnItemSelectedListener mOnItemSelectedListener;
-
- /**
- * The listener that receives notifications when an item is clicked.
- */
- OnItemClickListener mOnItemClickListener;
-
- /**
- * The listener that receives notifications when an item is long clicked.
- */
- OnItemLongClickListener mOnItemLongClickListener;
-
- /**
- * True if the data has changed since the last layout
- */
- boolean mDataChanged;
-
- /**
- * The position within the adapter's data set of the item to select
- * during the next layout.
- */
- @ViewDebug.ExportedProperty(category = "list")
- int mNextSelectedPosition = INVALID_POSITION;
-
- /**
- * The item id of the item to select during the next layout.
- */
- long mNextSelectedRowId = INVALID_ROW_ID;
-
- /**
- * The position within the adapter's data set of the currently selected item.
- */
- @ViewDebug.ExportedProperty(category = "list")
- int mSelectedPosition = INVALID_POSITION;
-
- /**
- * The item id of the currently selected item.
- */
- long mSelectedRowId = INVALID_ROW_ID;
-
- /**
- * View to show if there are no items to show.
- */
- private View mEmptyView;
-
- /**
- * The number of items in the current adapter.
- */
- @ViewDebug.ExportedProperty(category = "list")
- int mItemCount;
-
- /**
- * The number of items in the adapter before a data changed event occurred.
- */
- int mOldItemCount;
-
- /**
- * Represents an invalid position. All valid positions are in the range 0 to 1 less than the
- * number of items in the current adapter.
- */
- public static final int INVALID_POSITION = -1;
-
- /**
- * Represents an empty or invalid row id
- */
- public static final long INVALID_ROW_ID = Long.MIN_VALUE;
-
- /**
- * The last selected position we used when notifying
- */
- int mOldSelectedPosition = INVALID_POSITION;
-
- /**
- * The id of the last selected position we used when notifying
- */
- long mOldSelectedRowId = INVALID_ROW_ID;
-
- /**
- * Indicates what focusable state is requested when calling setFocusable().
- * In addition to this, this view has other criteria for actually
- * determining the focusable state (such as whether its empty or the text
- * filter is shown).
- *
- * @see #setFocusable(boolean)
- * @see #checkFocus()
- */
- private boolean mDesiredFocusableState;
- private boolean mDesiredFocusableInTouchModeState;
-
- private SelectionNotifier mSelectionNotifier;
- /**
- * When set to true, calls to requestLayout() will not propagate up the parent hierarchy.
- * This is used to layout the children during a layout pass.
- */
- boolean mBlockLayoutRequests = false;
-
- public IcsAdapterView(Context context) {
- super(context);
- }
-
- public IcsAdapterView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public IcsAdapterView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
-
- /**
- * Register a callback to be invoked when an item in this AdapterView has
- * been clicked.
- *
- * @param listener The callback that will be invoked.
- */
- public void setOnItemClickListener(OnItemClickListener listener) {
- mOnItemClickListener = listener;
- }
-
- /**
- * @return The callback to be invoked with an item in this AdapterView has
- * been clicked, or null id no callback has been set.
- */
- public final OnItemClickListener getOnItemClickListener() {
- return mOnItemClickListener;
- }
-
- /**
- * Call the OnItemClickListener, if it is defined.
- *
- * @param view The view within the AdapterView that was clicked.
- * @param position The position of the view in the adapter.
- * @param id The row id of the item that was clicked.
- * @return True if there was an assigned OnItemClickListener that was
- * called, false otherwise is returned.
- */
- public boolean performItemClick(View view, int position, long id) {
- if (mOnItemClickListener != null) {
- playSoundEffect(SoundEffectConstants.CLICK);
- if (view != null) {
- view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
- }
- mOnItemClickListener.onItemClick(/*this*/null, view, position, id);
- return true;
- }
-
- return false;
- }
-
- /**
- * Interface definition for a callback to be invoked when an item in this
- * view has been clicked and held.
- */
- public interface OnItemLongClickListener {
- /**
- * Callback method to be invoked when an item in this view has been
- * clicked and held.
- *
- * Implementers can call getItemAtPosition(position) if they need to access
- * the data associated with the selected item.
- *
- * @param parent The AbsListView where the click happened
- * @param view The view within the AbsListView that was clicked
- * @param position The position of the view in the list
- * @param id The row id of the item that was clicked
- *
- * @return true if the callback consumed the long click, false otherwise
- */
- boolean onItemLongClick(IcsAdapterView<?> parent, View view, int position, long id);
- }
-
-
- /**
- * Register a callback to be invoked when an item in this AdapterView has
- * been clicked and held
- *
- * @param listener The callback that will run
- */
- public void setOnItemLongClickListener(OnItemLongClickListener listener) {
- if (!isLongClickable()) {
- setLongClickable(true);
- }
- mOnItemLongClickListener = listener;
- }
-
- /**
- * @return The callback to be invoked with an item in this AdapterView has
- * been clicked and held, or null id no callback as been set.
- */
- public final OnItemLongClickListener getOnItemLongClickListener() {
- return mOnItemLongClickListener;
- }
-
- /**
- * Interface definition for a callback to be invoked when
- * an item in this view has been selected.
- */
- public interface OnItemSelectedListener {
- /**
- * <p>Callback method to be invoked when an item in this view has been
- * selected. This callback is invoked only when the newly selected
- * position is different from the previously selected position or if
- * there was no selected item.</p>
- *
- * Impelmenters can call getItemAtPosition(position) if they need to access the
- * data associated with the selected item.
- *
- * @param parent The AdapterView where the selection happened
- * @param view The view within the AdapterView that was clicked
- * @param position The position of the view in the adapter
- * @param id The row id of the item that is selected
- */
- void onItemSelected(IcsAdapterView<?> parent, View view, int position, long id);
-
- /**
- * Callback method to be invoked when the selection disappears from this
- * view. The selection can disappear for instance when touch is activated
- * or when the adapter becomes empty.
- *
- * @param parent The AdapterView that now contains no selected item.
- */
- void onNothingSelected(IcsAdapterView<?> parent);
- }
-
-
- /**
- * Register a callback to be invoked when an item in this AdapterView has
- * been selected.
- *
- * @param listener The callback that will run
- */
- public void setOnItemSelectedListener(OnItemSelectedListener listener) {
- mOnItemSelectedListener = listener;
- }
-
- public final OnItemSelectedListener getOnItemSelectedListener() {
- return mOnItemSelectedListener;
- }
-
- /**
- * Extra menu information provided to the
- * {@link android.view.View.OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo) }
- * callback when a context menu is brought up for this AdapterView.
- *
- */
- public static class AdapterContextMenuInfo implements ContextMenu.ContextMenuInfo {
-
- public AdapterContextMenuInfo(View targetView, int position, long id) {
- this.targetView = targetView;
- this.position = position;
- this.id = id;
- }
-
- /**
- * The child view for which the context menu is being displayed. This
- * will be one of the children of this AdapterView.
- */
- public View targetView;
-
- /**
- * The position in the adapter for which the context menu is being
- * displayed.
- */
- public int position;
-
- /**
- * The row id of the item for which the context menu is being displayed.
- */
- public long id;
- }
-
- /**
- * Returns the adapter currently associated with this widget.
- *
- * @return The adapter used to provide this view's content.
- */
- public abstract T getAdapter();
-
- /**
- * Sets the adapter that provides the data and the views to represent the data
- * in this widget.
- *
- * @param adapter The adapter to use to create this view's content.
- */
- public abstract void setAdapter(T adapter);
-
- /**
- * This method is not supported and throws an UnsupportedOperationException when called.
- *
- * @param child Ignored.
- *
- * @throws UnsupportedOperationException Every time this method is invoked.
- */
- @Override
- public void addView(View child) {
- throw new UnsupportedOperationException("addView(View) is not supported in AdapterView");
- }
-
- /**
- * This method is not supported and throws an UnsupportedOperationException when called.
- *
- * @param child Ignored.
- * @param index Ignored.
- *
- * @throws UnsupportedOperationException Every time this method is invoked.
- */
- @Override
- public void addView(View child, int index) {
- throw new UnsupportedOperationException("addView(View, int) is not supported in AdapterView");
- }
-
- /**
- * This method is not supported and throws an UnsupportedOperationException when called.
- *
- * @param child Ignored.
- * @param params Ignored.
- *
- * @throws UnsupportedOperationException Every time this method is invoked.
- */
- @Override
- public void addView(View child, LayoutParams params) {
- throw new UnsupportedOperationException("addView(View, LayoutParams) "
- + "is not supported in AdapterView");
- }
-
- /**
- * This method is not supported and throws an UnsupportedOperationException when called.
- *
- * @param child Ignored.
- * @param index Ignored.
- * @param params Ignored.
- *
- * @throws UnsupportedOperationException Every time this method is invoked.
- */
- @Override
- public void addView(View child, int index, LayoutParams params) {
- throw new UnsupportedOperationException("addView(View, int, LayoutParams) "
- + "is not supported in AdapterView");
- }
-
- /**
- * This method is not supported and throws an UnsupportedOperationException when called.
- *
- * @param child Ignored.
- *
- * @throws UnsupportedOperationException Every time this method is invoked.
- */
- @Override
- public void removeView(View child) {
- throw new UnsupportedOperationException("removeView(View) is not supported in AdapterView");
- }
-
- /**
- * This method is not supported and throws an UnsupportedOperationException when called.
- *
- * @param index Ignored.
- *
- * @throws UnsupportedOperationException Every time this method is invoked.
- */
- @Override
- public void removeViewAt(int index) {
- throw new UnsupportedOperationException("removeViewAt(int) is not supported in AdapterView");
- }
-
- /**
- * This method is not supported and throws an UnsupportedOperationException when called.
- *
- * @throws UnsupportedOperationException Every time this method is invoked.
- */
- @Override
- public void removeAllViews() {
- throw new UnsupportedOperationException("removeAllViews() is not supported in AdapterView");
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- mLayoutHeight = getHeight();
- }
-
- /**
- * Return the position of the currently selected item within the adapter's data set
- *
- * @return int Position (starting at 0), or {@link #INVALID_POSITION} if there is nothing selected.
- */
- @ViewDebug.CapturedViewProperty
- public int getSelectedItemPosition() {
- return mNextSelectedPosition;
- }
-
- /**
- * @return The id corresponding to the currently selected item, or {@link #INVALID_ROW_ID}
- * if nothing is selected.
- */
- @ViewDebug.CapturedViewProperty
- public long getSelectedItemId() {
- return mNextSelectedRowId;
- }
-
- /**
- * @return The view corresponding to the currently selected item, or null
- * if nothing is selected
- */
- public abstract View getSelectedView();
-
- /**
- * @return The data corresponding to the currently selected item, or
- * null if there is nothing selected.
- */
- public Object getSelectedItem() {
- T adapter = getAdapter();
- int selection = getSelectedItemPosition();
- if (adapter != null && adapter.getCount() > 0 && selection >= 0) {
- return adapter.getItem(selection);
- } else {
- return null;
- }
- }
-
- /**
- * @return The number of items owned by the Adapter associated with this
- * AdapterView. (This is the number of data items, which may be
- * larger than the number of visible views.)
- */
- @ViewDebug.CapturedViewProperty
- public int getCount() {
- return mItemCount;
- }
-
- /**
- * Get the position within the adapter's data set for the view, where view is a an adapter item
- * or a descendant of an adapter item.
- *
- * @param view an adapter item, or a descendant of an adapter item. This must be visible in this
- * AdapterView at the time of the call.
- * @return the position within the adapter's data set of the view, or {@link #INVALID_POSITION}
- * if the view does not correspond to a list item (or it is not currently visible).
- */
- public int getPositionForView(View view) {
- View listItem = view;
- try {
- View v;
- while (!(v = (View) listItem.getParent()).equals(this)) {
- listItem = 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(listItem)) {
- return mFirstPosition + i;
- }
- }
-
- // Child not found!
- return INVALID_POSITION;
- }
-
- /**
- * Returns the position within the adapter's data set for the first item
- * displayed on screen.
- *
- * @return The position within the adapter's data set
- */
- public int getFirstVisiblePosition() {
- return mFirstPosition;
- }
-
- /**
- * Returns the position within the adapter's data set for the last item
- * displayed on screen.
- *
- * @return The position within the adapter's data set
- */
- public int getLastVisiblePosition() {
- return mFirstPosition + getChildCount() - 1;
- }
-
- /**
- * Sets the currently selected item. To support accessibility subclasses that
- * override this method must invoke the overriden super method first.
- *
- * @param position Index (starting at 0) of the data item to be selected.
- */
- public abstract void setSelection(int position);
-
- /**
- * Sets the view to show if the adapter is empty
- */
- public void setEmptyView(View emptyView) {
- mEmptyView = emptyView;
-
- final T adapter = getAdapter();
- final boolean empty = ((adapter == null) || adapter.isEmpty());
- updateEmptyStatus(empty);
- }
-
- /**
- * When the current adapter is empty, the AdapterView can display a special view
- * call the empty view. The empty view is used to provide feedback to the user
- * that no data is available in this AdapterView.
- *
- * @return The view to show if the adapter is empty.
- */
- public View getEmptyView() {
- return mEmptyView;
- }
-
- /**
- * Indicates whether this view is in filter mode. Filter mode can for instance
- * be enabled by a user when typing on the keyboard.
- *
- * @return True if the view is in filter mode, false otherwise.
- */
- boolean isInFilterMode() {
- return false;
- }
-
- @Override
- public void setFocusable(boolean focusable) {
- final T adapter = getAdapter();
- final boolean empty = adapter == null || adapter.getCount() == 0;
-
- mDesiredFocusableState = focusable;
- if (!focusable) {
- mDesiredFocusableInTouchModeState = false;
- }
-
- super.setFocusable(focusable && (!empty || isInFilterMode()));
- }
-
- @Override
- public void setFocusableInTouchMode(boolean focusable) {
- final T adapter = getAdapter();
- final boolean empty = adapter == null || adapter.getCount() == 0;
-
- mDesiredFocusableInTouchModeState = focusable;
- if (focusable) {
- mDesiredFocusableState = true;
- }
-
- super.setFocusableInTouchMode(focusable && (!empty || isInFilterMode()));
- }
-
- void checkFocus() {
- final T adapter = getAdapter();
- final boolean empty = adapter == null || adapter.getCount() == 0;
- final boolean focusable = !empty || isInFilterMode();
- // 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((adapter == null) || adapter.isEmpty());
- }
- }
-
- /**
- * Update the status of the list based on the empty parameter. If empty is true and
- * we have an empty view, display it. In all the other cases, make sure that the listview
- * is VISIBLE and that the empty view is GONE (if it's not null).
- */
- private void updateEmptyStatus(boolean empty) {
- if (isInFilterMode()) {
- empty = false;
- }
-
- if (empty) {
- 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) {
- this.onLayout(false, getLeft(), getTop(), getRight(), getBottom());
- }
- } else {
- if (mEmptyView != null) mEmptyView.setVisibility(View.GONE);
- setVisibility(View.VISIBLE);
- }
- }
-
- /**
- * Gets the data associated with the specified position in the list.
- *
- * @param position Which data to get
- * @return The data associated with the specified position in the list
- */
- public Object getItemAtPosition(int position) {
- T adapter = getAdapter();
- return (adapter == null || position < 0) ? null : adapter.getItem(position);
- }
-
- public long getItemIdAtPosition(int position) {
- T adapter = getAdapter();
- return (adapter == null || position < 0) ? INVALID_ROW_ID : adapter.getItemId(position);
- }
-
- @Override
- public void setOnClickListener(OnClickListener l) {
- throw new RuntimeException("Don't call setOnClickListener for an AdapterView. "
- + "You probably want setOnItemClickListener instead");
- }
-
- /**
- * Override to prevent freezing of any views created by the adapter.
- */
- @Override
- protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
- dispatchFreezeSelfOnly(container);
- }
-
- /**
- * Override to prevent thawing of any views created by the adapter.
- */
- @Override
- protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
- dispatchThawSelfOnly(container);
- }
-
- 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 repopulated with new data.
- if (IcsAdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
- && mOldItemCount == 0 && mItemCount > 0) {
- IcsAdapterView.this.onRestoreInstanceState(mInstanceState);
- mInstanceState = null;
- } else {
- rememberSyncState();
- }
- checkFocus();
- requestLayout();
- }
-
- @Override
- public void onInvalidated() {
- mDataChanged = true;
-
- if (IcsAdapterView.this.getAdapter().hasStableIds()) {
- // Remember the current state for the case where our hosting activity is being
- // stopped and later restarted
- mInstanceState = IcsAdapterView.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();
- }
-
- public void clearSavedState() {
- mInstanceState = null;
- }
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- removeCallbacks(mSelectionNotifier);
- }
-
- private class SelectionNotifier implements Runnable {
- 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 (getAdapter() != null) {
- post(this);
- }
- } else {
- fireOnSelected();
- }
- }
- }
-
- void selectionChanged() {
- if (mOnItemSelectedListener != null) {
- 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 accomodate
- // new layout or invalidate requests.
- if (mSelectionNotifier == null) {
- mSelectionNotifier = new SelectionNotifier();
- }
- post(mSelectionNotifier);
- } else {
- fireOnSelected();
- }
- }
-
- // we fire selection events here not in View
- if (mSelectedPosition != ListView.INVALID_POSITION && isShown() && !isInTouchMode()) {
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
- }
- }
-
- private void fireOnSelected() {
- if (mOnItemSelectedListener == null)
- return;
-
- int selection = this.getSelectedItemPosition();
- if (selection >= 0) {
- View v = getSelectedView();
- mOnItemSelectedListener.onItemSelected(this, v, selection,
- getAdapter().getItemId(selection));
- } else {
- mOnItemSelectedListener.onNothingSelected(this);
- }
- }
-
- @Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
- View selectedView = getSelectedView();
- if (selectedView != null && selectedView.getVisibility() == VISIBLE
- && selectedView.dispatchPopulateAccessibilityEvent(event)) {
- return true;
- }
- return false;
- }
-
- @Override
- public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
- if (super.onRequestSendAccessibilityEvent(child, event)) {
- // Add a record for ourselves as well.
- AccessibilityEvent record = AccessibilityEvent.obtain();
- onInitializeAccessibilityEvent(record);
- // Populate with the text of the requesting child.
- child.dispatchPopulateAccessibilityEvent(record);
- event.appendRecord(record);
- return true;
- }
- return false;
- }
-
- @Override
- public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(info);
- info.setScrollable(isScrollableForAccessibility());
- View selectedView = getSelectedView();
- if (selectedView != null) {
- info.setEnabled(selectedView.isEnabled());
- }
- }
-
- @Override
- public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
- super.onInitializeAccessibilityEvent(event);
- event.setScrollable(isScrollableForAccessibility());
- View selectedView = getSelectedView();
- if (selectedView != null) {
- event.setEnabled(selectedView.isEnabled());
- }
- event.setCurrentItemIndex(getSelectedItemPosition());
- event.setFromIndex(getFirstVisiblePosition());
- event.setToIndex(getLastVisiblePosition());
- event.setItemCount(getCount());
- }
-
- private boolean isScrollableForAccessibility() {
- T adapter = getAdapter();
- if (adapter != null) {
- final int itemCount = adapter.getCount();
- return itemCount > 0
- && (getFirstVisiblePosition() > 0 || getLastVisiblePosition() < itemCount - 1);
- }
- return false;
- }
-
- @Override
- protected boolean canAnimate() {
- return super.canAnimate() && mItemCount > 0;
- }
-
- void handleDataChanged() {
- final int count = mItemCount;
- boolean found = false;
-
- if (count > 0) {
-
- int newPos;
-
- // Find the row we are supposed to sync to
- if (mNeedSync) {
- // Update this first, since setNextSelectedPositionInt inspects
- // it
- mNeedSync = false;
-
- // See if we can find a position in the new data with the same
- // id as the old selection
- newPos = findSyncPosition();
- if (newPos >= 0) {
- // Verify that new selection is selectable
- int selectablePos = lookForSelectablePosition(newPos, true);
- if (selectablePos == newPos) {
- // Same row id is selected
- setNextSelectedPositionInt(newPos);
- found = true;
- }
- }
- }
- if (!found) {
- // Try to use the same position if we can't find matching data
- newPos = getSelectedItemPosition();
-
- // Pin position to the available range
- if (newPos >= count) {
- newPos = count - 1;
- }
- if (newPos < 0) {
- newPos = 0;
- }
-
- // Make sure we select something selectable -- first look down
- int selectablePos = lookForSelectablePosition(newPos, true);
- if (selectablePos < 0) {
- // Looking down didn't work -- try looking up
- selectablePos = lookForSelectablePosition(newPos, false);
- }
- if (selectablePos >= 0) {
- setNextSelectedPositionInt(selectablePos);
- checkSelectionChanged();
- found = true;
- }
- }
- }
- if (!found) {
- // Nothing is selected
- mSelectedPosition = INVALID_POSITION;
- mSelectedRowId = INVALID_ROW_ID;
- mNextSelectedPosition = INVALID_POSITION;
- mNextSelectedRowId = INVALID_ROW_ID;
- mNeedSync = false;
- checkSelectionChanged();
- }
- }
-
- void checkSelectionChanged() {
- if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) {
- selectionChanged();
- mOldSelectedPosition = mSelectedPosition;
- mOldSelectedRowId = mSelectedRowId;
- }
- }
-
- /**
- * Searches the adapter for a position matching mSyncRowId. The search starts at mSyncPosition
- * and then alternates between moving up and moving down until 1) we find the right position, or
- * 2) we run out of time, or 3) we have looked at every position
- *
- * @return Position of the row that matches mSyncRowId, or {@link #INVALID_POSITION} if it can't
- * be found
- */
- int findSyncPosition() {
- int count = mItemCount;
-
- if (count == 0) {
- return INVALID_POSITION;
- }
-
- long idToMatch = mSyncRowId;
- int seed = mSyncPosition;
-
- // If there isn't a selection don't hunt for it
- if (idToMatch == INVALID_ROW_ID) {
- return INVALID_POSITION;
- }
-
- // Pin seed to reasonable values
- seed = Math.max(0, seed);
- seed = Math.min(count - 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
- T adapter = getAdapter();
- if (adapter == null) {
- return INVALID_POSITION;
- }
-
- while (SystemClock.uptimeMillis() <= endTime) {
- rowId = adapter.getItemId(seed);
- if (rowId == idToMatch) {
- // Found it!
- return seed;
- }
-
- hitLast = last == count - 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;
- }
-
- /**
- * Find a position that can be selected (i.e., is not a separator).
- *
- * @param position The starting position to look at.
- * @param lookDown Whether to look down for other positions.
- * @return The next selectable position starting at position and then searching either up or
- * down. Returns {@link #INVALID_POSITION} if nothing can be found.
- */
- int lookForSelectablePosition(int position, boolean lookDown) {
- return position;
- }
-
- /**
- * Utility to keep mSelectedPosition and mSelectedRowId in sync
- * @param position Our current position
- */
- void setSelectedPositionInt(int position) {
- mSelectedPosition = position;
- mSelectedRowId = getItemIdAtPosition(position);
- }
-
- /**
- * Utility to keep mNextSelectedPosition and mNextSelectedRowId in sync
- * @param position Intended value for mSelectedPosition the next time we go
- * through layout
- */
- 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;
- }
- }
-
- /**
- * Remember enough information to restore the screen state when the data has
- * changed.
- *
- */
- void rememberSyncState() {
- if (getChildCount() > 0) {
- mNeedSync = true;
- mSyncHeight = mLayoutHeight;
- if (mSelectedPosition >= 0) {
- // Sync the selection state
- View v = getChildAt(mSelectedPosition - mFirstPosition);
- mSyncRowId = mNextSelectedRowId;
- mSyncPosition = mNextSelectedPosition;
- if (v != null) {
- mSpecificTop = v.getTop();
- }
- mSyncMode = SYNC_SELECTED_POSITION;
- } else {
- // Sync the based on the offset of the first view
- View v = getChildAt(0);
- T adapter = getAdapter();
- if (mFirstPosition >= 0 && mFirstPosition < adapter.getCount()) {
- mSyncRowId = adapter.getItemId(mFirstPosition);
- } else {
- mSyncRowId = NO_ID;
- }
- mSyncPosition = mFirstPosition;
- if (v != null) {
- mSpecificTop = v.getTop();
- }
- mSyncMode = SYNC_FIRST_POSITION;
- }
- }
- }
-}