Merge "Avoid OOBE when AbsListView layout is out of sync with adapter" into mnc-dr-dev

This commit is contained in:
Alan Viverette
2015-09-11 21:28:59 +00:00
committed by Android (Google) Code Review
4 changed files with 54 additions and 15 deletions

View File

@@ -2395,6 +2395,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
lp.itemId = mAdapter.getItemId(position); lp.itemId = mAdapter.getItemId(position);
} }
lp.viewType = mAdapter.getItemViewType(position); lp.viewType = mAdapter.getItemViewType(position);
lp.isEnabled = mAdapter.isEnabled(position);
if (lp != vlp) { if (lp != vlp) {
child.setLayoutParams(lp); child.setLayoutParams(lp);
} }
@@ -2416,19 +2417,33 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} }
final int position = getPositionForView(host); final int position = getPositionForView(host);
final ListAdapter adapter = getAdapter(); if (position == INVALID_POSITION || mAdapter == null) {
if ((position == INVALID_POSITION) || (adapter == null)) {
// Cannot perform actions on invalid items. // Cannot perform actions on invalid items.
return false; return false;
} }
if (!isEnabled() || !adapter.isEnabled(position)) { if (position >= mAdapter.getCount()) {
// Cannot perform actions on disabled items. // The position is no longer valid, likely due to a data set
// change. We could fail here for all data set changes, since
// there is a chance that the data bound to the view may no
// longer exist at the same position within the adapter, but
// it's more consistent with the standard touch interaction to
// click at whatever may have moved into that position.
return false; return false;
} }
final long id = getItemIdAtPosition(position); final boolean isItemEnabled;
final ViewGroup.LayoutParams lp = host.getLayoutParams();
if (lp instanceof AbsListView.LayoutParams) {
isItemEnabled = ((AbsListView.LayoutParams) lp).isEnabled;
} else {
isItemEnabled = false;
}
if (!isEnabled() || !isItemEnabled) {
// Cannot perform actions on disabled items.
return false;
}
switch (action) { switch (action) {
case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: {
@@ -2445,11 +2460,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} return false; } return false;
case AccessibilityNodeInfo.ACTION_CLICK: { case AccessibilityNodeInfo.ACTION_CLICK: {
if (isClickable()) { if (isClickable()) {
final long id = getItemIdAtPosition(position);
return performItemClick(host, position, id); return performItemClick(host, position, id);
} }
} return false; } return false;
case AccessibilityNodeInfo.ACTION_LONG_CLICK: { case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
if (isLongClickable()) { if (isLongClickable()) {
final long id = getItemIdAtPosition(position);
return performLongPress(host, position, id); return performLongPress(host, position, id);
} }
} return false; } return false;
@@ -2469,13 +2486,20 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/ */
public void onInitializeAccessibilityNodeInfoForItem( public void onInitializeAccessibilityNodeInfoForItem(
View view, int position, AccessibilityNodeInfo info) { View view, int position, AccessibilityNodeInfo info) {
final ListAdapter adapter = getAdapter(); if (position == INVALID_POSITION) {
if (position == INVALID_POSITION || adapter == null) {
// The item doesn't exist, so there's not much we can do here. // The item doesn't exist, so there's not much we can do here.
return; return;
} }
if (!isEnabled() || !adapter.isEnabled(position)) { final boolean isItemEnabled;
final ViewGroup.LayoutParams lp = view.getLayoutParams();
if (lp instanceof AbsListView.LayoutParams) {
isItemEnabled = ((AbsListView.LayoutParams) lp).isEnabled;
} else {
isItemEnabled = false;
}
if (!isEnabled() || !isItemEnabled) {
info.setEnabled(false); info.setEnabled(false);
return; return;
} }
@@ -6315,6 +6339,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/ */
long itemId = -1; long itemId = -1;
/** Whether the adapter considers the item enabled. */
boolean isEnabled;
public LayoutParams(Context c, AttributeSet attrs) { public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs); super(c, attrs);
} }
@@ -6340,6 +6367,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
encoder.addProperty("list:viewType", viewType); encoder.addProperty("list:viewType", viewType);
encoder.addProperty("list:recycledHeaderFooter", recycledHeaderFooter); encoder.addProperty("list:recycledHeaderFooter", recycledHeaderFooter);
encoder.addProperty("list:forceAdd", forceAdd); encoder.addProperty("list:forceAdd", forceAdd);
encoder.addProperty("list:isEnabled", isEnabled);
} }
} }

View File

@@ -600,13 +600,20 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
} }
/** /**
* Get the position within the adapter's data set for the view, where view is a an adapter item * Returns the position within the adapter's data set for the view, where
* or a descendant of an adapter item. * view is a an adapter item or a descendant of an adapter item.
* <p>
* <strong>Note:</strong> The result of this method only reflects the
* position of the data bound to <var>view</var> during the most recent
* layout pass. If the adapter's data set has changed without a subsequent
* layout pass, the position returned by this method may not match the
* current position of the data within the adapter.
* *
* @param view an adapter item, or a descendant of an adapter item. This must be visible in this * @param view an adapter item, or a descendant of an adapter item. This
* AdapterView at the time of the call. * 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} * @return the position within the adapter's data set of the view, or
* if the view does not correspond to a list item (or it is not currently visible). * {@link #INVALID_POSITION} if the view does not correspond to a
* list item (or it is not currently visible)
*/ */
public int getPositionForView(View view) { public int getPositionForView(View view) {
View listItem = view; View listItem = view;

View File

@@ -1070,6 +1070,7 @@ public class GridView extends AbsListView {
child.setLayoutParams(p); child.setLayoutParams(p);
} }
p.viewType = mAdapter.getItemViewType(0); p.viewType = mAdapter.getItemViewType(0);
p.isEnabled = mAdapter.isEnabled(0);
p.forceAdd = true; p.forceAdd = true;
int childHeightSpec = getChildMeasureSpec( int childHeightSpec = getChildMeasureSpec(
@@ -1480,6 +1481,7 @@ public class GridView extends AbsListView {
p = (AbsListView.LayoutParams) generateDefaultLayoutParams(); p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
} }
p.viewType = mAdapter.getItemViewType(position); p.viewType = mAdapter.getItemViewType(position);
p.isEnabled = mAdapter.isEnabled(position);
if (recycled && !p.forceAdd) { if (recycled && !p.forceAdd) {
attachViewToParent(child, where, p); attachViewToParent(child, where, p);

View File

@@ -1200,6 +1200,7 @@ public class ListView extends AbsListView {
child.setLayoutParams(p); child.setLayoutParams(p);
} }
p.viewType = mAdapter.getItemViewType(position); p.viewType = mAdapter.getItemViewType(position);
p.isEnabled = mAdapter.isEnabled(position);
p.forceAdd = true; p.forceAdd = true;
final int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec, final int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
@@ -1913,6 +1914,7 @@ public class ListView extends AbsListView {
p = (AbsListView.LayoutParams) generateDefaultLayoutParams(); p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
} }
p.viewType = mAdapter.getItemViewType(position); p.viewType = mAdapter.getItemViewType(position);
p.isEnabled = mAdapter.isEnabled(position);
if ((recycled && !p.forceAdd) || (p.recycledHeaderFooter if ((recycled && !p.forceAdd) || (p.recycledHeaderFooter
&& p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) { && p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) {