diff options
author | Tor Norbye <tnorbye@google.com> | 2011-06-09 17:44:03 -0700 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2011-06-13 11:28:32 -0700 |
commit | 8c3f16ae7d66cedf70c494de3a38a54e90f2a54e (patch) | |
tree | ab5f8c7ebf5b198ad58f84dfcd887a405b85ca68 | |
parent | f03ec978e97330f1611bca3fe63b11279c07febd (diff) | |
download | sdk-8c3f16ae7d66cedf70c494de3a38a54e90f2a54e.zip sdk-8c3f16ae7d66cedf70c494de3a38a54e90f2a54e.tar.gz sdk-8c3f16ae7d66cedf70c494de3a38a54e90f2a54e.tar.bz2 |
Merge 0b95acc1 from master to r12. do not merge.
RelativeLayout: Assign ids dynamically, handle multi-drag, bugs
This CL fixes three issues with the new relative layout interaction:
(1) Assign ids dynamically. Before this changeset you couldn't attach
to a node which does not have an @id attribute, since layout
params need to name the constraint by id.
This changeset changes this such that you can attach to any
arbitrary edge, and when you commit the drag, a unique id is
generated on the fly and assigned to the node.
(2) Handle dragging multiple nodes at the same time. The new
constraints code was unconditionally applying the same constraints
to all the dragged nodes, which meant they ended up on top of each
other. This fixes things such that the first node is assigned the
new constraints, and then all subsequent nodes are attached one
next to the other, in a direction depending on which edge you
attached to (e.g. attaching on the right will arrange the siblings
towards the left out from the edge.)
(3) Fix a bug in the code to detect and prevent cycles.
Change-Id: I3da16903ffac6c34a0d5efee52a87824fb9e04fb
12 files changed, 165 insertions, 36 deletions
diff --git a/eclipse/dictionary.txt b/eclipse/dictionary.txt index 853cb3c..86f5e2f 100644 --- a/eclipse/dictionary.txt +++ b/eclipse/dictionary.txt @@ -152,6 +152,7 @@ num ok os palette +param params pings placeholder diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java index b696332..eb3f7e7 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/IClientRulesEngine.java @@ -210,5 +210,18 @@ public interface IClientRulesEngine { */ String getAttribute(INode node, String namespace, String localName); } + + /** + * Given a UI root node and a potential XML node name, returns the first available id + * that matches the pattern "prefix%d". + * <p/> + * TabWidget is a special case and the method will always return "@android:id/tabs". + * + * @param fqcn The fully qualified class name of the view to generate a unique id for + * @return A suitable generated id in the attribute form needed by the XML id tag + * (e.g. "@+id/something") + */ + public String getUniqueId(String fqcn); + } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/Segment.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/Segment.java index 845f82d..0fb961a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/Segment.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/api/Segment.java @@ -45,7 +45,10 @@ public class Segment { /** The node that contains this edge */ public final INode node; - /** The id of the node */ + /** + * The id of the node. May be null (in which case id should be generated when + * move/resize is completed + */ public final String id; public Segment(int at, int from, int to, INode node, String id, SegmentType edgeType, diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java index 5b3334e..c332649 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java @@ -187,6 +187,7 @@ public class RelativeLayoutRule extends BaseLayoutRule { state.removeCycles(); // Now write the new elements. + INode previous = null; for (IDragElement element : elements) { String fqcn = element.getFqcn(); @@ -202,7 +203,25 @@ public class RelativeLayoutRule extends BaseLayoutRule { addAttributes(newChild, element, idMap, BaseLayoutRule.DEFAULT_ATTR_FILTER); addInnerElements(newChild, element, idMap); - state.applyConstraints(newChild); + if (previous == null) { + state.applyConstraints(newChild); + previous = newChild; + } else { + // Arrange the nodes next to each other, depending on which + // edge we are attaching to. For example, if attaching to the + // top edge, arrange the subsequent nodes in a column below it. + // + // TODO: Try to do something smarter here where we detect + // constraints between the dragged edges, and we preserve these. + // We have to do this carefully though because if the + // constraints go through some other nodes not part of the + // selection, this doesn't work right, and you might be + // dragging several connected components, which we'd then + // need to stitch together such that they are all visible. + + state.attachPrevious(previous, newChild); + previous = newChild; + } } } }); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/DependencyGraph.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/DependencyGraph.java index a0039fb..0b1d9e6 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/DependencyGraph.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/DependencyGraph.java @@ -21,8 +21,8 @@ import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_PREFIX; import static com.android.ide.common.layout.LayoutConstants.VALUE_TRUE; import com.android.ide.common.api.IDragElement; -import com.android.ide.common.api.INode; import com.android.ide.common.api.IDragElement.IDragAttribute; +import com.android.ide.common.api.INode; import com.android.ide.common.api.INode.IAttribute; import com.android.ide.common.layout.BaseLayoutRule; @@ -150,8 +150,8 @@ class DependencyGraph { * * @param nodes the set of nodes that we want to compute the transitive dependencies * for - * @param vertical if true, look for vertical dependencies, otherwise look for - * horizontal dependencies + * @param vertical if true, look for vertical edge dependencies, otherwise look for + * horizontal edge dependencies * @return the set of nodes that directly or indirectly depend on the given nodes in * the given direction */ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/GuidelineHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/GuidelineHandler.java index 8faf364..7c6e1d2 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/GuidelineHandler.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/GuidelineHandler.java @@ -24,6 +24,7 @@ import static com.android.ide.common.api.SegmentType.RIGHT; import static com.android.ide.common.api.SegmentType.TOP; import static com.android.ide.common.layout.BaseLayoutRule.getMaxMatchDistance; import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI; +import static com.android.ide.common.layout.LayoutConstants.ATTR_ID; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_ABOVE; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_ALIGN_BASELINE; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_ALIGN_BOTTOM; @@ -109,13 +110,15 @@ public class GuidelineHandler { /** * The set of nodes which depend on the currently selected nodes, including - * transitively, through horizontal constraints. + * transitively, through horizontal constraints (a "horizontal constraint" + * is a constraint between two horizontal edges) */ protected Set<INode> mHorizontalDeps; /** * The set of nodes which depend on the currently selected nodes, including - * transitively, through vertical constraints. + * transitively, through vertical constraints (a "vertical constraint" + * is a constraint between two vertical edges) */ protected Set<INode> mVerticalDeps; @@ -468,7 +471,7 @@ public class GuidelineHandler { continue; } - Match match = new Match(edge, draggedEdge, type, delta); + Match match = new Match(this, edge, draggedEdge, type, delta); if (distance < closestDistance) { closest.clear(); @@ -492,6 +495,8 @@ public class GuidelineHandler { /** * Given a node, apply the suggestions by expressing them as relative layout param * values + * + * @param n the node to apply constraints to */ public void applyConstraints(INode n) { // Process each edge separately @@ -548,25 +553,25 @@ public class GuidelineHandler { } if (mMoveTop && mCurrentTopMatch != null) { - applyConstraint(n, mCurrentTopMatch.getConstraint()); + applyConstraint(n, mCurrentTopMatch.getConstraint(true /* generateId */)); if (mCurrentTopMatch.type == ALIGN_BASELINE) { // HACK! WORKAROUND! Baseline doesn't provide a new bottom edge for attachments - String c = mCurrentTopMatch.getConstraint(); + String c = mCurrentTopMatch.getConstraint(true); c = c.replace(ATTR_LAYOUT_ALIGN_BASELINE, ATTR_LAYOUT_ALIGN_BOTTOM); applyConstraint(n, c); } } if (mMoveBottom && mCurrentBottomMatch != null) { - applyConstraint(n, mCurrentBottomMatch.getConstraint()); + applyConstraint(n, mCurrentBottomMatch.getConstraint(true)); } if (mMoveLeft && mCurrentLeftMatch != null) { - applyConstraint(n, mCurrentLeftMatch.getConstraint()); + applyConstraint(n, mCurrentLeftMatch.getConstraint(true)); } if (mMoveRight && mCurrentRightMatch != null) { - applyConstraint(n, mCurrentRightMatch.getConstraint()); + applyConstraint(n, mCurrentRightMatch.getConstraint(true)); } if (mMoveLeft) { @@ -588,7 +593,6 @@ public class GuidelineHandler { String name = constraint.substring(0, constraint.indexOf('=')); String value = constraint.substring(constraint.indexOf('=') + 1); n.setAttribute(ANDROID_URI, name, value); - } private void applyMargin(INode n, String marginAttribute, int margin) { @@ -601,6 +605,58 @@ public class GuidelineHandler { } } + private void removeRelativeParams(INode node) { + for (ConstraintType type : ConstraintType.values()) { + node.setAttribute(ANDROID_URI, type.name, null); + } + node.setAttribute(ANDROID_URI,ATTR_LAYOUT_MARGIN_LEFT, null); + node.setAttribute(ANDROID_URI,ATTR_LAYOUT_MARGIN_RIGHT, null); + node.setAttribute(ANDROID_URI,ATTR_LAYOUT_MARGIN_TOP, null); + node.setAttribute(ANDROID_URI,ATTR_LAYOUT_MARGIN_BOTTOM, null); + } + + /** + * Attach the new child to the previous node + * @param previous the previous child + * @param node the new child to attach it to + */ + public void attachPrevious(INode previous, INode node) { + removeRelativeParams(node); + + String id = previous.getStringAttr(ANDROID_URI, ATTR_ID); + if (id == null) { + return; + } + + if (mCurrentTopMatch != null || mCurrentBottomMatch != null) { + // Attaching the top: arrange below, and for bottom arrange above + node.setAttribute(ANDROID_URI, + mCurrentTopMatch != null ? ATTR_LAYOUT_BELOW : ATTR_LAYOUT_ABOVE, id); + // Apply same left/right constraints as the parent + if (mCurrentLeftMatch != null) { + applyConstraint(node, mCurrentLeftMatch.getConstraint(true)); + applyMargin(node, ATTR_LAYOUT_MARGIN_LEFT, mLeftMargin); + } else if (mCurrentRightMatch != null) { + applyConstraint(node, mCurrentRightMatch.getConstraint(true)); + applyMargin(node, ATTR_LAYOUT_MARGIN_RIGHT, mRightMargin); + } + } else if (mCurrentLeftMatch != null || mCurrentRightMatch != null) { + node.setAttribute(ANDROID_URI, + mCurrentLeftMatch != null ? ATTR_LAYOUT_TO_RIGHT_OF : ATTR_LAYOUT_TO_LEFT_OF, + id); + // Apply same top/bottom constraints as the parent + if (mCurrentTopMatch != null) { + applyConstraint(node, mCurrentTopMatch.getConstraint(true)); + applyMargin(node, ATTR_LAYOUT_MARGIN_TOP, mTopMargin); + } else if (mCurrentBottomMatch != null) { + applyConstraint(node, mCurrentBottomMatch.getConstraint(true)); + applyMargin(node, ATTR_LAYOUT_MARGIN_BOTTOM, mBottomMargin); + } + } else { + return; + } + } + public void removeCycles() { if (mHorizontalCycle != null) { removeCycles(mHorizontalDeps); @@ -762,4 +818,13 @@ public class GuidelineHandler { return 0; } } + + /** + * Returns the {@link IClientRulesEngine} IDE callback + * + * @return the {@link IClientRulesEngine} IDE callback, never null + */ + public IClientRulesEngine getRulesEngine() { + return mRulesEngine; + } }
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/GuidelinePainter.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/GuidelinePainter.java index 158a792..be0fb09 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/GuidelinePainter.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/GuidelinePainter.java @@ -130,7 +130,7 @@ public final class GuidelinePainter implements IFeedbackPainter { // Display the constraint. Remove the @id/ and @+id/ prefixes to make the text // shorter and easier to read. This doesn't use stripPrefix() because the id is // usually not a prefix of the value (for example, 'layout_alignBottom=@+id/foo'). - String constraint = m.getConstraint(); + String constraint = m.getConstraint(false /* generateId */); String description = constraint.replace(NEW_ID_PREFIX, "").replace(ID_PREFIX, ""); if (description.startsWith(ATTR_LAYOUT_PREFIX)) { description = description.substring(ATTR_LAYOUT_PREFIX.length()); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/Match.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/Match.java index a341113..98d02e8 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/Match.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/Match.java @@ -15,6 +15,8 @@ */ package com.android.ide.common.layout.relative; +import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI; +import static com.android.ide.common.layout.LayoutConstants.ATTR_ID; import static com.android.ide.common.layout.LayoutConstants.VALUE_TRUE; import com.android.ide.common.api.Segment; @@ -36,15 +38,22 @@ class Match { /** whether this {@link Match} results in a cycle */ public boolean cycle; + /** The associated {@link GuidelineHander} which performed the match */ + private final GuidelineHandler mHandler; + /** * Create a new match. * + * @param handler the handler which performed the match * @param edge the "other" edge that the dragged edge is matched with * @param with the edge of the dragged node that is matched * @param type the type of constraint this is a match for * @param delta the signed distance between the matched edges */ - public Match(Segment edge, Segment with, ConstraintType type, int delta) { + public Match(GuidelineHandler handler, Segment edge, Segment with, + ConstraintType type, int delta) { + mHandler = handler; + this.edge = edge; this.with = with; this.type = type; @@ -54,13 +63,29 @@ class Match { /** * Returns the XML constraint attribute value for this match * + * @param generateId whether an id should be generated if one is missing * @return the XML constraint attribute value for this match */ - public String getConstraint() { + public String getConstraint(boolean generateId) { if (type.targetParent) { return type.name + '=' + VALUE_TRUE; } else { String id = edge.id; + if (id == null || id.length() == -1) { + if (!generateId) { + // Placeholder to display for the user during dragging + id = "<generated>"; + } else { + // Must generate an id on the fly! + // See if it's been set by a different constraint we've already applied + // to this same node + id = edge.node.getStringAttr(ANDROID_URI, ATTR_ID); + if (id == null || id.length() == 0) { + id = mHandler.getRulesEngine().getUniqueId(edge.node.getFqcn()); + edge.node.setAttribute(ANDROID_URI, ATTR_ID, id); + } + } + } return type.name + '=' + id; } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/MoveHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/MoveHandler.java index c7d25b4..a2f9ac2 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/MoveHandler.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/MoveHandler.java @@ -63,8 +63,8 @@ public class MoveHandler extends GuidelineHandler { } mDraggedNodes = nodes; - mHorizontalDeps = mDependencyGraph.dependsOn(nodes, false /* vertical */); - mVerticalDeps = mDependencyGraph.dependsOn(nodes, true /* vertical */); + mHorizontalDeps = mDependencyGraph.dependsOn(nodes, false /* verticalEdge */); + mVerticalDeps = mDependencyGraph.dependsOn(nodes, true /* verticalEdge */); for (INode child : layout.getChildren()) { Rect bc = child.getBounds(); @@ -81,12 +81,9 @@ public class MoveHandler extends GuidelineHandler { } if (!isDragged) { - // Need an id to reference child in attachments to it, so skip - // nodes without ids String id = child.getStringAttr(ANDROID_URI, ATTR_ID); - if (id == null) { - continue; - } + // It's okay for id to be null; if you apply a constraint + // to a node with a missing id we will generate the id boolean addHorizontal = !mHorizontalDeps.contains(child); boolean addVertical = !mVerticalDeps.contains(child); @@ -233,7 +230,7 @@ public class MoveHandler extends GuidelineHandler { Match match = pickBestMatch(mHorizontalSuggestions); if (match != null) { - if (mVerticalDeps.contains(match.edge.node)) { + if (mHorizontalDeps.contains(match.edge.node)) { match.cycle = true; } @@ -259,7 +256,7 @@ public class MoveHandler extends GuidelineHandler { match = pickBestMatch(mVerticalSuggestions); if (match != null) { - if (mHorizontalDeps.contains(match.edge.node)) { + if (mVerticalDeps.contains(match.edge.node)) { match.cycle = true; } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/ResizeHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/ResizeHandler.java index 870798d..6cf421a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/ResizeHandler.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/ResizeHandler.java @@ -84,14 +84,7 @@ public class ResizeHandler extends GuidelineHandler { for (INode child : layout.getChildren()) { if (child != resized) { - // Need an id to reference child in attachments to it, so skip nodes - // without ids - // TODO: Generate an id on the fly when needed (at commit time) instead! String id = child.getStringAttr(ANDROID_URI, ATTR_ID); - if (id == null) { - continue; - } - addBounds(child, id, !mHorizontalDeps.contains(child), !mVerticalDeps.contains(child)); @@ -208,7 +201,7 @@ public class ResizeHandler extends GuidelineHandler { Match match = pickBestMatch(mHorizontalSuggestions); if (match != null && (!mSnap || Math.abs(match.delta) < BaseLayoutRule.getMaxMatchDistance())) { - if (mVerticalDeps.contains(match.edge.node)) { + if (mHorizontalDeps.contains(match.edge.node)) { match.cycle = true; } @@ -232,7 +225,7 @@ public class ResizeHandler extends GuidelineHandler { Match match = pickBestMatch(mVerticalSuggestions); if (match != null && (!mSnap || Math.abs(match.delta) < BaseLayoutRule.getMaxMatchDistance())) { - if (mHorizontalDeps.contains(match.edge.node)) { + if (mVerticalDeps.contains(match.edge.node)) { match.cycle = true; } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java index 5f60911..e23f05c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java @@ -29,21 +29,23 @@ import com.android.ide.common.resources.ResourceRepository; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.actions.AddCompatibilityJarAction; import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; +import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils; import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationComposite; import com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart; import com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutCanvas; import com.android.ide.eclipse.adt.internal.editors.layout.gle2.RenderService; import com.android.ide.eclipse.adt.internal.editors.layout.gle2.SelectionManager; import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo; +import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode; import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; import com.android.ide.eclipse.adt.internal.resources.CyclicDependencyValidator; import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData; import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.ide.eclipse.adt.internal.ui.MarginChooser; -import com.android.ide.eclipse.adt.internal.ui.ResourcePreviewHelper; import com.android.ide.eclipse.adt.internal.ui.ReferenceChooserDialog; import com.android.ide.eclipse.adt.internal.ui.ResourceChooser; +import com.android.ide.eclipse.adt.internal.ui.ResourcePreviewHelper; import com.android.resources.ResourceType; import com.android.sdklib.IAndroidTarget; @@ -481,4 +483,10 @@ class ClientRulesEngine implements IClientRulesEngine { } } + public String getUniqueId(String fqcn) { + UiDocumentNode root = mRulesEngine.getEditor().getModel(); + String prefix = fqcn.substring(fqcn.lastIndexOf('.') + 1); + prefix = Character.toLowerCase(prefix.charAt(0)) + prefix.substring(1); + return DescriptorsUtils.getFreeWidgetId(root, prefix); + } }
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java index b59f2f9..b29424e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java @@ -276,6 +276,11 @@ public class LayoutTestBase extends TestCase { fail("Not supported in tests yet"); return px; } + + public String getUniqueId(String prefix) { + fail("Not supported in tests yet"); + return null; + } } public void testDummy() { |