diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfoTest.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfoTest.java | 797 |
1 files changed, 797 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfoTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfoTest.java new file mode 100644 index 000000000..5996f01c0 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfoTest.java @@ -0,0 +1,797 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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.android.ide.eclipse.adt.internal.editors.layout.gle2; + +import com.android.ide.common.rendering.api.Capability; +import com.android.ide.common.rendering.api.DataBindingItem; +import com.android.ide.common.rendering.api.MergeCookie; +import com.android.ide.common.rendering.api.ViewInfo; +import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; +import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor; +import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode; +import com.android.utils.Pair; + +import org.eclipse.swt.graphics.Rectangle; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import junit.framework.TestCase; + +@SuppressWarnings("javadoc") +public class CanvasViewInfoTest extends TestCase { + + public static ViewElementDescriptor createDesc(String name, String fqn, boolean hasChildren) { + if (hasChildren) { + return new ViewElementDescriptor(name, name, fqn, "", "", new AttributeDescriptor[0], + new AttributeDescriptor[0], new ElementDescriptor[1], false); + } else { + return new ViewElementDescriptor(name, fqn); + } + } + + public static UiViewElementNode createNode(UiViewElementNode parent, String fqn, + boolean hasChildren) { + String name = fqn.substring(fqn.lastIndexOf('.') + 1); + ViewElementDescriptor descriptor = createDesc(name, fqn, hasChildren); + if (parent == null) { + // All node hierarchies should be wrapped inside a document node at the root + parent = new UiViewElementNode(createDesc("doc", "doc", true)); + } + return (UiViewElementNode) parent.appendNewUiChild(descriptor); + } + + public static UiViewElementNode createNode(String fqn, boolean hasChildren) { + return createNode(null, fqn, hasChildren); + } + + public void testNormalCreate() throws Exception { + normal(true); + } + + public void testNormalCreateLayoutLib5() throws Exception { + normal(false); + } + + private void normal(boolean layoutlib5) { + + // Normal view hierarchy, no null keys anywhere + + UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true); + ViewInfo root = new ViewInfo("LinearLayout", rootNode, 10, 10, 100, 100); + UiViewElementNode child1Node = createNode(rootNode, "android.widget.Button", false); + ViewInfo child1 = new ViewInfo("Button", child1Node, 0, 0, 50, 20); + UiViewElementNode child2Node = createNode(rootNode, "android.widget.Button", false); + ViewInfo child2 = new ViewInfo("Button", child2Node, 0, 20, 70, 25); + root.setChildren(Arrays.asList(child1, child2)); + + CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst(); + assertNotNull(rootView); + assertEquals("LinearLayout", rootView.getName()); + assertEquals(new Rectangle(10, 10, 89, 89), rootView.getAbsRect()); + assertEquals(new Rectangle(10, 10, 89, 89), rootView.getSelectionRect()); + assertNull(rootView.getParent()); + assertSame(rootView.getUiViewNode(), rootNode); + assertEquals(2, rootView.getChildren().size()); + CanvasViewInfo childView1 = rootView.getChildren().get(0); + CanvasViewInfo childView2 = rootView.getChildren().get(1); + + assertEquals("Button", childView1.getName()); + assertSame(rootView, childView1.getParent()); + assertEquals(new Rectangle(10, 10, 49, 19), childView1.getAbsRect()); + assertEquals(new Rectangle(10, 10, 49, 19), childView1.getSelectionRect()); + assertSame(childView1.getUiViewNode(), child1Node); + + assertEquals("Button", childView2.getName()); + assertSame(rootView, childView2.getParent()); + assertEquals(new Rectangle(10, 30, 69, 4), childView2.getAbsRect()); + assertEquals(new Rectangle(10, 30, 69, 5), childView2.getSelectionRect()); + assertSame(childView2.getUiViewNode(), child2Node); + } + + public void testShowIn() throws Exception { + showIn(false); + } + + public void testShowInLayoutLib5() throws Exception { + showIn(true); + } + + public void showIn(boolean layoutlib5) throws Exception { + + // Test rendering of "Show Included In" (included content rendered + // within an outer content that has null keys) + + ViewInfo root = new ViewInfo("LinearLayout", null, 10, 10, 100, 100); + ViewInfo child1 = new ViewInfo("CheckBox", null, 0, 0, 50, 20); + UiViewElementNode child2Node = createNode("android.widget.RelativeLayout", true); + ViewInfo child2 = new ViewInfo("RelativeLayout", child2Node, 0, 20, 70, 25); + root.setChildren(Arrays.asList(child1, child2)); + UiViewElementNode child21Node = createNode("android.widget.Button", false); + ViewInfo child21 = new ViewInfo("RadioButton", child21Node, 0, 20, 70, 25); + child2.setChildren(Arrays.asList(child21)); + + CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst(); + assertNotNull(rootView); + assertEquals("LinearLayout", rootView.getName()); + assertEquals(new Rectangle(10, 10, 89, 89), rootView.getAbsRect()); + assertEquals(new Rectangle(10, 10, 89, 89), rootView.getSelectionRect()); + assertNull(rootView.getParent()); + assertNull(rootView.getUiViewNode()); + assertEquals(1, rootView.getChildren().size()); + CanvasViewInfo includedView = rootView.getChildren().get(0); + + assertEquals("RelativeLayout", includedView.getName()); + assertSame(rootView, includedView.getParent()); + assertEquals(new Rectangle(10, 30, 69, 4), includedView.getAbsRect()); + assertEquals(new Rectangle(10, 30, 69, 5), includedView.getSelectionRect()); + assertSame(includedView.getUiViewNode(), child2Node); + + CanvasViewInfo grandChild = includedView.getChildren().get(0); + assertNotNull(grandChild); + assertEquals("RadioButton", grandChild.getName()); + assertSame(child21Node, grandChild.getUiViewNode()); + assertEquals(new Rectangle(10, 50, 69, 4), grandChild.getAbsRect()); + assertEquals(new Rectangle(10, 50, 69, 5), grandChild.getSelectionRect()); + } + + public void testIncludeTag() throws Exception { + boolean layoutlib5 = true; + + // Test rendering of included views on layoutlib 5+ (e.g. has <include> tag) + + UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true); + ViewInfo root = new ViewInfo("LinearLayout", rootNode, 10, 10, 100, 100); + UiViewElementNode child1Node = createNode(rootNode, "android.widget.Button", false); + ViewInfo child1 = new ViewInfo("CheckBox", child1Node, 0, 0, 50, 20); + UiViewElementNode child2Node = createNode(rootNode, "include", true); + ViewInfo child2 = new ViewInfo("RelativeLayout", child2Node, 0, 20, 70, 25); + root.setChildren(Arrays.asList(child1, child2)); + ViewInfo child21 = new ViewInfo("RadioButton", null, 0, 20, 70, 25); + child2.setChildren(Arrays.asList(child21)); + + CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst(); + assertNotNull(rootView); + assertEquals("LinearLayout", rootView.getName()); + assertEquals(new Rectangle(10, 10, 89, 89), rootView.getAbsRect()); + assertEquals(new Rectangle(10, 10, 89, 89), rootView.getSelectionRect()); + assertNull(rootView.getParent()); + assertSame(rootNode, rootView.getUiViewNode()); + assertEquals(2, rootView.getChildren().size()); + + CanvasViewInfo childView1 = rootView.getChildren().get(0); + CanvasViewInfo includedView = rootView.getChildren().get(1); + + assertEquals("CheckBox", childView1.getName()); + assertSame(rootView, childView1.getParent()); + assertEquals(new Rectangle(10, 10, 49, 19), childView1.getAbsRect()); + assertEquals(new Rectangle(10, 10, 49, 19), childView1.getSelectionRect()); + assertSame(childView1.getUiViewNode(), child1Node); + + assertEquals("RelativeLayout", includedView.getName()); + assertSame(rootView, includedView.getParent()); + assertEquals(new Rectangle(10, 30, 69, 4), includedView.getAbsRect()); + assertEquals(new Rectangle(10, 30, 69, 5), includedView.getSelectionRect()); + assertSame(includedView.getUiViewNode(), child2Node); + assertEquals(0, includedView.getChildren().size()); + } + + public void testNoIncludeTag() throws Exception { + boolean layoutlib5 = false; + + // Test rendering of included views on layoutlib 4- (e.g. no <include> tag cookie + // in view info) + + UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true); + ViewInfo root = new ViewInfo("LinearLayout", rootNode, 10, 10, 100, 100); + UiViewElementNode child1Node = createNode(rootNode, "android.widget.Button", false); + ViewInfo child1 = new ViewInfo("CheckBox", child1Node, 0, 0, 50, 20); + UiViewElementNode child2Node = createNode(rootNode, "include", true); + ViewInfo child2 = new ViewInfo("RelativeLayout", null /* layoutlib 4 */, 0, 20, 70, 25); + root.setChildren(Arrays.asList(child1, child2)); + ViewInfo child21 = new ViewInfo("RadioButton", null, 0, 20, 70, 25); + child2.setChildren(Arrays.asList(child21)); + + CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst(); + assertNotNull(rootView); + assertEquals("LinearLayout", rootView.getName()); + assertEquals(new Rectangle(10, 10, 89, 89), rootView.getAbsRect()); + assertEquals(new Rectangle(10, 10, 89, 89), rootView.getSelectionRect()); + assertNull(rootView.getParent()); + assertSame(rootNode, rootView.getUiViewNode()); + assertEquals(2, rootView.getChildren().size()); + + CanvasViewInfo childView1 = rootView.getChildren().get(0); + CanvasViewInfo includedView = rootView.getChildren().get(1); + + assertEquals("CheckBox", childView1.getName()); + assertSame(rootView, childView1.getParent()); + assertEquals(new Rectangle(10, 10, 49, 19), childView1.getAbsRect()); + assertEquals(new Rectangle(10, 10, 49, 19), childView1.getSelectionRect()); + assertSame(childView1.getUiViewNode(), child1Node); + + assertEquals("RelativeLayout", includedView.getName()); + assertSame(rootView, includedView.getParent()); + assertEquals(new Rectangle(10, 30, 69, 4), includedView.getAbsRect()); + assertEquals(new Rectangle(10, 30, 69, 5), includedView.getSelectionRect()); + assertSame(includedView.getUiViewNode(), child2Node); + assertEquals(0, includedView.getChildren().size()); + } + + public void testMergeMatching() throws Exception { + boolean layoutlib5 = false; + + // Test rendering of MULTIPLE included views or when there is no simple match + // between view info and ui element node children + + UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true); + ViewInfo root = new ViewInfo("LinearLayout", rootNode, 10, 10, 100, 100); + UiViewElementNode child1Node = createNode(rootNode, "android.widget.Button", false); + ViewInfo child1 = new ViewInfo("CheckBox", child1Node, 0, 0, 50, 20); + UiViewElementNode multiChildNode1 = createNode(rootNode, "foo", true); + UiViewElementNode multiChildNode2 = createNode(rootNode, "bar", true); + ViewInfo child2 = new ViewInfo("RelativeLayout", null, 0, 20, 70, 25); + ViewInfo child3 = new ViewInfo("AbsoluteLayout", null, 10, 40, 50, 15); + root.setChildren(Arrays.asList(child1, child2, child3)); + ViewInfo child21 = new ViewInfo("RadioButton", null, 0, 20, 70, 25); + child2.setChildren(Arrays.asList(child21)); + + CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst(); + assertNotNull(rootView); + assertEquals("LinearLayout", rootView.getName()); + assertEquals(new Rectangle(10, 10, 89, 89), rootView.getAbsRect()); + assertEquals(new Rectangle(10, 10, 89, 89), rootView.getSelectionRect()); + assertNull(rootView.getParent()); + assertTrue(rootView.isRoot()); + assertSame(rootNode, rootView.getUiViewNode()); + assertEquals(3, rootView.getChildren().size()); + + CanvasViewInfo childView1 = rootView.getChildren().get(0); + assertFalse(childView1.isRoot()); + CanvasViewInfo includedView1 = rootView.getChildren().get(1); + assertFalse(includedView1.isRoot()); + CanvasViewInfo includedView2 = rootView.getChildren().get(2); + assertFalse(includedView1.isRoot()); + + assertEquals("CheckBox", childView1.getName()); + assertSame(rootView, childView1.getParent()); + assertEquals(new Rectangle(10, 10, 49, 19), childView1.getAbsRect()); + assertEquals(new Rectangle(10, 10, 49, 19), childView1.getSelectionRect()); + assertSame(childView1.getUiViewNode(), child1Node); + + assertEquals("RelativeLayout", includedView1.getName()); + assertSame(multiChildNode1, includedView1.getUiViewNode()); + assertEquals("foo", includedView1.getUiViewNode().getDescriptor().getXmlName()); + assertSame(multiChildNode2, includedView2.getUiViewNode()); + assertEquals("AbsoluteLayout", includedView2.getName()); + assertEquals("bar", includedView2.getUiViewNode().getDescriptor().getXmlName()); + assertSame(rootView, includedView1.getParent()); + assertSame(rootView, includedView2.getParent()); + assertEquals(new Rectangle(10, 30, 69, 4), includedView1.getAbsRect()); + assertEquals(new Rectangle(10, 30, 69, 5), includedView1.getSelectionRect()); + assertEquals(new Rectangle(20, 50, 39, -26), includedView2.getAbsRect()); + assertEquals(new Rectangle(20, 35, 39, 5), includedView2.getSelectionRect()); + assertEquals(0, includedView1.getChildren().size()); + assertEquals(0, includedView2.getChildren().size()); + } + + public void testMerge() throws Exception { + boolean layoutlib5 = false; + + // Test rendering of MULTIPLE included views or when there is no simple match + // between view info and ui element node children + + UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true); + ViewInfo root = new ViewInfo("LinearLayout", rootNode, 10, 10, 100, 100); + UiViewElementNode child1Node = createNode(rootNode, "android.widget.Button", false); + ViewInfo child1 = new ViewInfo("CheckBox", child1Node, 0, 0, 50, 20); + UiViewElementNode multiChildNode = createNode(rootNode, "foo", true); + ViewInfo child2 = new ViewInfo("RelativeLayout", null, 0, 20, 70, 25); + ViewInfo child3 = new ViewInfo("AbsoluteLayout", null, 10, 40, 50, 15); + root.setChildren(Arrays.asList(child1, child2, child3)); + ViewInfo child21 = new ViewInfo("RadioButton", null, 0, 20, 70, 25); + child2.setChildren(Arrays.asList(child21)); + + CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst(); + assertNotNull(rootView); + assertEquals("LinearLayout", rootView.getName()); + assertEquals(new Rectangle(10, 10, 89, 89), rootView.getAbsRect()); + assertEquals(new Rectangle(10, 10, 89, 89), rootView.getSelectionRect()); + assertNull(rootView.getParent()); + assertSame(rootNode, rootView.getUiViewNode()); + assertEquals(2, rootView.getChildren().size()); + + CanvasViewInfo childView1 = rootView.getChildren().get(0); + CanvasViewInfo includedView = rootView.getChildren().get(1); + + assertEquals("CheckBox", childView1.getName()); + assertSame(rootView, childView1.getParent()); + assertEquals(new Rectangle(10, 10, 49, 19), childView1.getAbsRect()); + assertEquals(new Rectangle(10, 10, 49, 19), childView1.getSelectionRect()); + assertSame(childView1.getUiViewNode(), child1Node); + + assertEquals("RelativeLayout", includedView.getName()); + assertSame(rootView, includedView.getParent()); + assertEquals(new Rectangle(10, 30, 69, 4), includedView.getAbsRect()); + assertEquals(new Rectangle(10, 30, 69, 5), includedView.getSelectionRect()); + assertEquals(0, includedView.getChildren().size()); + assertSame(multiChildNode, includedView.getUiViewNode()); + } + + public void testInsertMerge() throws Exception { + boolean layoutlib5 = false; + + // Test rendering of MULTIPLE included views or when there is no simple match + // between view info and ui element node children + + UiViewElementNode mergeNode = createNode("merge", true); + UiViewElementNode rootNode = createNode(mergeNode, "android.widget.Button", false); + ViewInfo root = new ViewInfo("Button", rootNode, 10, 10, 100, 100); + + CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst(); + assertNotNull(rootView); + assertEquals("merge", rootView.getName()); + assertSame(rootView.getUiViewNode(), mergeNode); + assertEquals(new Rectangle(10, 10, 89, 89), rootView.getAbsRect()); + assertEquals(new Rectangle(10, 10, 89, 89), rootView.getSelectionRect()); + assertNull(rootView.getParent()); + assertSame(mergeNode, rootView.getUiViewNode()); + assertEquals(1, rootView.getChildren().size()); + + CanvasViewInfo childView1 = rootView.getChildren().get(0); + + assertEquals("Button", childView1.getName()); + assertSame(rootView, childView1.getParent()); + assertEquals(new Rectangle(10, 10, 89, 89), childView1.getAbsRect()); + assertEquals(new Rectangle(10, 10, 89, 89), childView1.getSelectionRect()); + assertSame(childView1.getUiViewNode(), rootNode); + } + + public void testUnmatchedMissing() throws Exception { + boolean layoutlib5 = false; + + UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true); + ViewInfo root = new ViewInfo("LinearLayout", rootNode, 0, 0, 100, 100); + List<ViewInfo> children = new ArrayList<ViewInfo>(); + // Should be matched up with corresponding node: + Set<Integer> missingKeys = new HashSet<Integer>(); + // Should not be matched with any views, but should get view created: + Set<Integer> extraKeys = new HashSet<Integer>(); + // Should not be matched with any nodes + Set<Integer> extraViews = new HashSet<Integer>(); + int numViews = 30; + missingKeys.add(0); + missingKeys.add(4); + missingKeys.add(14); + missingKeys.add(29); + extraKeys.add(9); + extraKeys.add(20); + extraKeys.add(22); + extraViews.add(18); + extraViews.add(24); + + List<String> expectedViewNames = new ArrayList<String>(); + List<String> expectedNodeNames = new ArrayList<String>(); + + for (int i = 0; i < numViews; i++) { + UiViewElementNode childNode = null; + if (!extraViews.contains(i)) { + childNode = createNode(rootNode, "childNode" + i, false); + } + Object cookie = missingKeys.contains(i) || extraViews.contains(i) ? null : childNode; + ViewInfo childView = new ViewInfo("childView" + i, cookie, + 0, i * 20, 50, (i + 1) * 20); + children.add(childView); + + if (!extraViews.contains(i)) { + expectedViewNames.add("childView" + i); + expectedNodeNames.add("childNode" + i); + } + + if (extraKeys.contains(i)) { + createNode(rootNode, "extraNodeAt" + i, false); + + expectedViewNames.add("extraNodeAt" + i); + expectedNodeNames.add("extraNodeAt" + i); + } + } + root.setChildren(children); + + CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst(); + assertNotNull(rootView); + + // dump(root, 0); + // dump(rootView, 0); + + assertEquals("LinearLayout", rootView.getName()); + assertNull(rootView.getParent()); + assertSame(rootNode, rootView.getUiViewNode()); + assertEquals(numViews + extraKeys.size() - extraViews.size(), rootNode.getUiChildren() + .size()); + assertEquals(numViews + extraKeys.size() - extraViews.size(), + rootView.getChildren().size()); + assertEquals(expectedViewNames.size(), rootView.getChildren().size()); + for (int i = 0, n = rootView.getChildren().size(); i < n; i++) { + CanvasViewInfo childView = rootView.getChildren().get(i); + String expectedViewName = expectedViewNames.get(i); + String expectedNodeName = expectedNodeNames.get(i); + assertEquals(expectedViewName, childView.getName()); + assertNotNull(childView.getUiViewNode()); + assertEquals(expectedNodeName, childView.getUiViewNode().getDescriptor().getXmlName()); + } + } + + public void testMergeCookies() throws Exception { + boolean layoutlib5 = true; + + UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true); + ViewInfo root = new ViewInfo("LinearLayout", rootNode, 0, 0, 100, 100); + + // Create the merge cookies in the opposite order to ensure that we don't + // apply our own logic when matching up views with nodes + LinkedList<MergeCookie> cookies = new LinkedList<MergeCookie>(); + for (int i = 0; i < 10; i++) { + UiViewElementNode node = createNode(rootNode, "childNode" + i, false); + cookies.addFirst(new MergeCookie(node)); + } + Iterator<MergeCookie> it = cookies.iterator(); + ArrayList<ViewInfo> children = new ArrayList<ViewInfo>(); + for (int i = 0; i < 10; i++) { + ViewInfo childView = new ViewInfo("childView" + i, it.next(), 0, i * 20, 50, + (i + 1) * 20); + children.add(childView); + } + root.setChildren(children); + + CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst(); + assertNotNull(rootView); + + assertEquals("LinearLayout", rootView.getName()); + assertNull(rootView.getParent()); + assertSame(rootNode, rootView.getUiViewNode()); + for (int i = 0, n = rootView.getChildren().size(); i < n; i++) { + CanvasViewInfo childView = rootView.getChildren().get(i); + assertEquals("childView" + i, childView.getName()); + assertEquals("childNode" + (9 - i), childView.getUiViewNode().getDescriptor() + .getXmlName()); + } + } + + public void testMergeCookies2() throws Exception { + boolean layoutlib5 = true; + + UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true); + ViewInfo root = new ViewInfo("LinearLayout", rootNode, 0, 0, 100, 100); + + UiViewElementNode node1 = createNode(rootNode, "childNode1", false); + UiViewElementNode node2 = createNode(rootNode, "childNode2", false); + MergeCookie cookie1 = new MergeCookie(node1); + MergeCookie cookie2 = new MergeCookie(node2); + + // Sets alternating merge cookies and checks whether the node sibling lists are + // okay and merged correctly + + ArrayList<ViewInfo> children = new ArrayList<ViewInfo>(); + for (int i = 0; i < 10; i++) { + Object cookie = (i % 2) == 0 ? cookie1 : cookie2; + ViewInfo childView = new ViewInfo("childView" + i, cookie, 0, i * 20, 50, + (i + 1) * 20); + children.add(childView); + } + root.setChildren(children); + + Pair<CanvasViewInfo, List<Rectangle>> result = CanvasViewInfo.create(root, layoutlib5); + CanvasViewInfo rootView = result.getFirst(); + List<Rectangle> bounds = result.getSecond(); + assertNull(bounds); + assertNotNull(rootView); + + assertEquals("LinearLayout", rootView.getName()); + assertNull(rootView.getParent()); + assertSame(rootNode, rootView.getUiViewNode()); + assertEquals(10, rootView.getChildren().size()); + assertEquals(2, rootView.getUniqueChildren().size()); + for (int i = 0, n = rootView.getChildren().size(); i < n; i++) { + CanvasViewInfo childView = rootView.getChildren().get(i); + assertEquals("childView" + i, childView.getName()); + Object cookie = (i % 2) == 0 ? node1 : node2; + assertSame(cookie, childView.getUiViewNode()); + List<CanvasViewInfo> nodeSiblings = childView.getNodeSiblings(); + assertEquals(5, nodeSiblings.size()); + } + List<CanvasViewInfo> nodeSiblings = rootView.getChildren().get(0).getNodeSiblings(); + for (int j = 0; j < 5; j++) { + assertEquals("childView" + (j * 2), nodeSiblings.get(j).getName()); + } + nodeSiblings = rootView.getChildren().get(1).getNodeSiblings(); + for (int j = 0; j < 5; j++) { + assertEquals("childView" + (j * 2 + 1), nodeSiblings.get(j).getName()); + } + } + + public void testIncludeBounds() throws Exception { + boolean layoutlib5 = true; + + UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true); + ViewInfo root = new ViewInfo("included", null, 0, 0, 100, 100); + + UiViewElementNode node1 = createNode(rootNode, "childNode1", false); + UiViewElementNode node2 = createNode(rootNode, "childNode2", false); + MergeCookie cookie1 = new MergeCookie(node1); + MergeCookie cookie2 = new MergeCookie(node2); + + // Sets alternating merge cookies and checks whether the node sibling lists are + // okay and merged correctly + + ArrayList<ViewInfo> children = new ArrayList<ViewInfo>(); + for (int i = 0; i < 10; i++) { + Object cookie = (i % 2) == 0 ? cookie1 : cookie2; + ViewInfo childView = new ViewInfo("childView" + i, cookie, 0, i * 20, 50, + (i + 1) * 20); + children.add(childView); + } + root.setChildren(children); + + Pair<CanvasViewInfo, List<Rectangle>> result = CanvasViewInfo.create(root, layoutlib5); + CanvasViewInfo rootView = result.getFirst(); + List<Rectangle> bounds = result.getSecond(); + assertNotNull(rootView); + + assertEquals("included", rootView.getName()); + assertNull(rootView.getParent()); + assertNull(rootView.getUiViewNode()); + assertEquals(10, rootView.getChildren().size()); + assertEquals(2, rootView.getUniqueChildren().size()); + for (int i = 0, n = rootView.getChildren().size(); i < n; i++) { + CanvasViewInfo childView = rootView.getChildren().get(i); + assertEquals("childView" + i, childView.getName()); + Object cookie = (i % 2) == 0 ? node1 : node2; + assertSame(cookie, childView.getUiViewNode()); + List<CanvasViewInfo> nodeSiblings = childView.getNodeSiblings(); + assertEquals(5, nodeSiblings.size()); + } + List<CanvasViewInfo> nodeSiblings = rootView.getChildren().get(0).getNodeSiblings(); + for (int j = 0; j < 5; j++) { + assertEquals("childView" + (j * 2), nodeSiblings.get(j).getName()); + } + nodeSiblings = rootView.getChildren().get(1).getNodeSiblings(); + for (int j = 0; j < 5; j++) { + assertEquals("childView" + (j * 2 + 1), nodeSiblings.get(j).getName()); + } + + // Only show the primary bounds as included + assertEquals(2, bounds.size()); + assertEquals(new Rectangle(0, 0, 49, 19), bounds.get(0)); + assertEquals(new Rectangle(0, 20, 49, 19), bounds.get(1)); + } + + public void testIncludeBounds2() throws Exception { + includeBounds2(false); + } + + public void testIncludeBounds2LayoutLib5() throws Exception { + includeBounds2(true); + } + + public void includeBounds2(boolean layoutlib5) throws Exception { + + UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true); + ViewInfo root = new ViewInfo("included", null, 0, 0, 100, 100); + + UiViewElementNode node1 = createNode(rootNode, "childNode1", false); + UiViewElementNode node2 = createNode(rootNode, "childNode2", false); + + ViewInfo childView1 = new ViewInfo("childView1", node1, 0, 20, 50, 40); + ViewInfo childView2 = new ViewInfo("childView2", node2, 0, 40, 50, 60); + + root.setChildren(Arrays.asList(childView1, childView2)); + + Pair<CanvasViewInfo, List<Rectangle>> result = CanvasViewInfo.create(root, layoutlib5); + CanvasViewInfo rootView = result.getFirst(); + List<Rectangle> bounds = result.getSecond(); + assertNotNull(rootView); + + assertEquals("included", rootView.getName()); + assertNull(rootView.getParent()); + assertNull(rootView.getUiViewNode()); + assertEquals(2, rootView.getChildren().size()); + assertEquals(2, rootView.getUniqueChildren().size()); + + Rectangle bounds1 = bounds.get(0); + Rectangle bounds2 = bounds.get(1); + assertEquals(new Rectangle(0, 20, 49, 19), bounds1); + assertEquals(new Rectangle(0, 40, 49, 19), bounds2); + } + + public void testCookieWorkaround() throws Exception { + UiViewElementNode rootNode = createNode("android.widget.LinearLayout", true); + ViewInfo root = new ViewInfo("included", null, 0, 0, 100, 100); + + UiViewElementNode node2 = createNode(rootNode, "childNode2", false); + MergeCookie mergeCookie = new MergeCookie(root); + + ViewInfo childView1 = new ViewInfo("childView1", mergeCookie, 0, 20, 50, 40); + ViewInfo childView2 = new ViewInfo("childView2", node2, 0, 40, 50, 60); + + root.setChildren(Arrays.asList(childView1, childView2)); + + Pair<CanvasViewInfo, List<Rectangle>> result = CanvasViewInfo.create(root, true); + CanvasViewInfo rootView = result.getFirst(); + List<Rectangle> bounds = result.getSecond(); + assertNotNull(rootView); + + assertEquals("included", rootView.getName()); + assertNull(rootView.getParent()); + assertNull(rootView.getUiViewNode()); + // childView1 should have been removed since it has the wrong merge cookie + assertEquals(1, rootView.getChildren().size()); + assertEquals(1, rootView.getUniqueChildren().size()); + + Rectangle bounds1 = bounds.get(0); + assertEquals(new Rectangle(0, 40, 49, 19), bounds1); + } + + public void testGestureOverlayView() throws Exception { + boolean layoutlib5 = true; + + // Test rendering of included views on layoutlib 5+ (e.g. has <include> tag) + + UiViewElementNode rootNode = createNode("android.gesture.GestureOverlayView", true); + UiViewElementNode childNode = createNode(rootNode, "android.widget.LinearLayout", false); + UiViewElementNode grandChildNode = createNode(childNode, "android.widget.Button", false); + ViewInfo root = new ViewInfo("GestureOverlayView", rootNode, 10, 10, 100, 100); + ViewInfo child = new ViewInfo("LinearLayout", childNode, 0, 0, 50, 20); + root.setChildren(Collections.singletonList(child)); + ViewInfo grandChild = new ViewInfo("Button", grandChildNode, 0, 20, 70, 25); + child.setChildren(Collections.singletonList(grandChild)); + CanvasViewInfo rootView = CanvasViewInfo.create(root, layoutlib5).getFirst(); + assertNotNull(rootView); + assertEquals("GestureOverlayView", rootView.getName()); + + assertTrue(rootView.isRoot()); + assertNull(rootView.getParent()); + assertSame(rootNode, rootView.getUiViewNode()); + assertEquals(1, rootView.getChildren().size()); + + CanvasViewInfo childView = rootView.getChildren().get(0); + assertEquals("LinearLayout", childView.getName()); + + // This should also be a root for the special case that the root is + assertTrue(childView.isRoot()); + + assertEquals(1, childView.getChildren().size()); + CanvasViewInfo grandChildView = childView.getChildren().get(0); + assertEquals("Button", grandChildView.getName()); + assertFalse(grandChildView.isRoot()); + } + + public void testListView() throws Exception { + // For ListViews we get AdapterItemReferences as cookies. Ensure that this + // works properly. + // + // android.widget.FrameLayout [0,50,320,480] <FrameLayout> + // android.widget.ListView [0,0,320,430] <ListView> + // android.widget.LinearLayout [0,0,320,17] SessionParams$AdapterItemReference + // android.widget.TextView [0,0,73,17] + // android.widget.LinearLayout [0,18,320,35] SessionParams$AdapterItemReference + // android.widget.TextView [0,0,73,17] + // android.widget.LinearLayout [0,36,320,53] SessionParams$AdapterItemReference + // android.widget.TextView [0,0,73,17] + // ... + + UiViewElementNode rootNode = createNode("FrameLayout", true); + UiViewElementNode childNode = createNode(rootNode, "ListView", false); + /*UiViewElementNode grandChildNode =*/ createNode(childNode, "LinearLayout", false); + /*UiViewElementNode greatGrandChildNode =*/ createNode(childNode, "TextView", false); + DataBindingItem dataBindingItem = new DataBindingItem("foo"); + + ViewInfo root = new ViewInfo("FrameLayout", rootNode, 0, 50, 320, 480); + ViewInfo child = new ViewInfo("ListView", childNode, 0, 0, 320, 430); + root.setChildren(Collections.singletonList(child)); + ViewInfo grandChild = new ViewInfo("LinearLayout", dataBindingItem, 0, 0, 320, 17); + child.setChildren(Collections.singletonList(grandChild)); + ViewInfo greatGrandChild = new ViewInfo("Button", null, 0, 0, 73, 17); + grandChild.setChildren(Collections.singletonList(greatGrandChild)); + CanvasViewInfo rootView = CanvasViewInfo.create(root, true /*layoutlib5*/).getFirst(); + assertNotNull(rootView); + + assertEquals("FrameLayout", rootView.getName()); + assertEquals(1, rootView.getChildren().size()); + assertSame(rootNode, rootView.getUiViewNode()); + + CanvasViewInfo childView = rootView.getChildren().get(0); + assertEquals("ListView", childView.getName()); + assertEquals(0, childView.getChildren().size()); + assertSame(childNode, childView.getUiViewNode()); + } + + /** + * Dumps out the given {@link ViewInfo} hierarchy to standard out. + * Useful during development. + * + * @param graphicalEditor the editor associated with this hierarchy + * @param root the root of the {@link ViewInfo} hierarchy + */ + public static void dump(GraphicalEditorPart graphicalEditor, ViewInfo root) { + System.out.println("\n\nRendering:"); + boolean supportsEmbedding = graphicalEditor.renderingSupports(Capability.EMBEDDED_LAYOUT); + System.out.println("Supports Embedded Layout=" + supportsEmbedding); + System.out.println("Rendering context=" + graphicalEditor.getIncludedWithin()); + dump(root, 0); + } + + /** Helper for {@link #dump(GraphicalEditorPart, ViewInfo)} */ + public static void dump(ViewInfo info, int depth) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < depth; i++) { + sb.append(" "); + } + sb.append(info.getClassName()); + sb.append(" ["); + sb.append(info.getLeft()); + sb.append(","); + sb.append(info.getTop()); + sb.append(","); + sb.append(info.getRight()); + sb.append(","); + sb.append(info.getBottom()); + sb.append("] "); + Object cookie = info.getCookie(); + if (cookie instanceof UiViewElementNode) { + sb.append(" "); + UiViewElementNode node = (UiViewElementNode) cookie; + sb.append("<"); + sb.append(node.getDescriptor().getXmlName()); + sb.append("> "); + } else if (cookie != null) { + sb.append(" cookie=" + cookie); + } + + System.out.println(sb.toString()); + + for (ViewInfo child : info.getChildren()) { + dump(child, depth + 1); + } + } + + /** Helper for {@link #dump(GraphicalEditorPart, ViewInfo)} */ + public static void dump(CanvasViewInfo info, int depth) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < depth; i++) { + sb.append(" "); + } + sb.append(info.getName()); + sb.append(" ["); + sb.append(info.getAbsRect()); + sb.append("], node="); + sb.append(info.getUiViewNode()); + + System.out.println(sb.toString()); + + for (CanvasViewInfo child : info.getChildren()) { + dump(child, depth + 1); + } + } + +} |