Merge "Allow the parent to be set for nodes created by ExploreByTouchHelper." into nyc-support-25.1-dev
diff --git a/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java b/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
index bb43456..1b21bc2 100644
--- a/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
+++ b/core-ui/java/android/support/v4/widget/ExploreByTouchHelper.java
@@ -798,6 +798,7 @@
node.setClassName(DEFAULT_CLASS_NAME);
node.setBoundsInParent(INVALID_PARENT_BOUNDS);
node.setBoundsInScreen(INVALID_PARENT_BOUNDS);
+ node.setParent(mHost);
// Allow the client to populate the node.
onPopulateNodeForVirtualView(virtualViewId, node);
@@ -827,7 +828,6 @@
// Don't allow the client to override these properties.
node.setPackageName(mHost.getContext().getPackageName());
node.setSource(mHost, virtualViewId);
- node.setParent(mHost);
// Manage internal accessibility focus state.
if (mAccessibilityFocusedVirtualViewId == virtualViewId) {
diff --git a/samples/Support4Demos/res/values/strings.xml b/samples/Support4Demos/res/values/strings.xml
index bd6b31b..2d4f0db 100644
--- a/samples/Support4Demos/res/values/strings.xml
+++ b/samples/Support4Demos/res/values/strings.xml
@@ -214,6 +214,7 @@
<string name="explore_by_touch_helper_support">Widget/Explore by Touch helper</string>
<string name="sample_item_a">Sample item A</string>
<string name="sample_item_b">Sample item B</string>
+ <string name="sample_item_c">Sample item C</string>
<!-- ContentLoadingProgressBar -->
<string name="content_loading_progress_bar">Widget/Content Loading Progress Bar</string>
diff --git a/samples/Support4Demos/src/com/example/android/supportv4/widget/ExploreByTouchHelperActivity.java b/samples/Support4Demos/src/com/example/android/supportv4/widget/ExploreByTouchHelperActivity.java
index 946de01..3f7675c 100644
--- a/samples/Support4Demos/src/com/example/android/supportv4/widget/ExploreByTouchHelperActivity.java
+++ b/samples/Support4Demos/src/com/example/android/supportv4/widget/ExploreByTouchHelperActivity.java
@@ -36,6 +36,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
+
import com.example.android.supportv4.R;
import java.util.ArrayList;
@@ -78,7 +79,13 @@
customView.addItem(getString(R.string.sample_item_a), 0, 0, 0.5f, 0.5f);
// Adds an item at the bottom-right quarter of the custom view.
- customView.addItem(getString(R.string.sample_item_b), 0.5f, 0.5f, 1, 1);
+ CustomView.CustomItem itemB =
+ customView.addItem(getString(R.string.sample_item_b), 0.5f, 0.5f, 1, 1);
+
+ // Add an item at the bottom quarter of Item B.
+ CustomView.CustomItem itemC =
+ customView.addItem(getString(R.string.sample_item_c), 0, 0.75f, 1, 1);
+ customView.setParentItem(itemC, itemB);
}
/**
@@ -142,12 +149,32 @@
* @param right Right coordinate as a fraction of the parent width,
* range is [0,1].
*/
- public void addItem(String description, float top, float left, float bottom, float right) {
+ public CustomItem addItem(String description, float left, float top, float right,
+ float bottom) {
final CustomItem item = new CustomItem();
- item.bounds = new RectF(top, left, bottom, right);
- item.description = description;
- item.checked = false;
+ item.mId = mItems.size();
+ item.mBounds = new RectF(left, top, right, bottom);
+ item.mDescription = description;
+ item.mChecked = false;
mItems.add(item);
+ return item;
+ }
+
+ /**
+ * Sets the parent of an CustomItem. This adjusts the bounds so that they are relative to
+ * the specified view, and initializes the parent and child info to point to each either.
+ * @param item CustomItem that will become a child node.
+ * @param parent CustomItem that will become the parent node.
+ */
+ public void setParentItem(CustomItem item, CustomItem parent) {
+ item.mParent = parent;
+ parent.mChildren.add(item.mId);
+ RectF bounds = item.mBounds;
+ item.mBounds = new RectF(parent.mBounds.left + bounds.left * parent.mBounds.width(),
+ parent.mBounds.top + bounds.top * parent.mBounds.height(),
+ parent.mBounds.left + bounds.right * parent.mBounds.width(),
+ parent.mBounds.top + bounds.bottom * parent.mBounds.height());
+
}
@Override
@@ -160,13 +187,17 @@
final int width = getWidth();
for (CustomItem item : mItems) {
- paint.setColor(item.checked ? Color.RED : Color.BLUE);
+ if (item.mParent == null) {
+ paint.setColor(item.mChecked ? Color.RED : Color.BLUE);
+ } else {
+ paint.setColor(item.mChecked ? Color.MAGENTA : Color.GREEN);
+ }
paint.setStyle(Style.FILL);
- scaleRectF(item.bounds, bounds, width, height);
+ scaleRectF(item.mBounds, bounds, width, height);
canvas.drawRect(bounds, paint);
paint.setColor(Color.WHITE);
paint.setTextAlign(Align.CENTER);
- canvas.drawText(item.description, bounds.centerX(), bounds.centerY(), paint);
+ canvas.drawText(item.mDescription, bounds.centerX(), bounds.centerY(), paint);
}
}
@@ -176,7 +207,7 @@
return false;
}
- item.checked = !item.checked;
+ item.mChecked = !item.mChecked;
invalidate();
// Since the item's checked state is exposed to accessibility
@@ -198,9 +229,10 @@
final float scaledY = (y / getHeight());
final int n = mItems.size();
- for (int i = 0; i < n; i++) {
+ // Search in reverse order, so that topmost items are selected first.
+ for (int i = n - 1; i >= 0; i--) {
final CustomItem item = mItems.get(i);
- if (item.bounds.contains(scaledX, scaledY)) {
+ if (item.mBounds.contains(scaledX, scaledY)) {
return i;
}
}
@@ -246,11 +278,13 @@
@Override
protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
// Since every item should be visible, and since we're mapping
- // directly from item index to virtual view id, we can just add
- // every available index in the item list.
+ // directly from item index to virtual view id, we can add
+ // the index of every view that doesn't have a parent.
final int n = mItems.size();
for (int i = 0; i < n; i++) {
- virtualViewIds.add(i);
+ if (mItems.get(i).mParent == null) {
+ virtualViewIds.add(i);
+ }
}
}
@@ -267,7 +301,7 @@
// description is displayed visually, we'll add it to the event
// text. If it was only used for accessibility, we would use
// setContentDescription().
- event.getText().add(item.description);
+ event.getText().add(item.mDescription);
}
@Override
@@ -280,7 +314,7 @@
// Node and event text and content descriptions are usually
// identical, so we'll use the exact same string as before.
- node.setText(item.description);
+ node.setText(item.mDescription);
// Reported bounds should be consistent with those used to draw
// the item in onDraw(). They should also be consistent with the
@@ -289,7 +323,7 @@
final Rect bounds = mTempRect;
final int height = getHeight();
final int width = getWidth();
- scaleRectF(item.bounds, bounds, width, height);
+ scaleRectF(item.mBounds, bounds, width, height);
node.setBoundsInParent(bounds);
// Since the user can tap an item, add the CLICK action. We'll
@@ -298,7 +332,15 @@
// This item has a checked state.
node.setCheckable(true);
- node.setChecked(item.checked);
+ node.setChecked(item.mChecked);
+
+ // Setup the hierarchy.
+ if (item.mParent != null) {
+ node.setParent(CustomView.this, item.mParent.mId);
+ }
+ for (Integer id : item.mChildren) {
+ node.addChild(CustomView.this, id);
+ }
}
@Override
@@ -318,9 +360,12 @@
}
public static class CustomItem {
- private String description;
- private RectF bounds;
- private boolean checked;
+ private int mId;
+ private CustomItem mParent;
+ private List<Integer> mChildren = new ArrayList<>();
+ private String mDescription;
+ private RectF mBounds;
+ private boolean mChecked;
}
}
}