aboutsummaryrefslogtreecommitdiffstats
path: root/eclipse
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse')
-rw-r--r--eclipse/dictionary.txt1
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/icons/GridLayout.pngbin466 -> 248 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/icons/Space.pngbin468 -> 248 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java29
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridLayoutRule.java45
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridDropHandler.java42
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridModel.java274
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java46
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/AddCompatibilityJarAction.java245
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/FixProjectAction.java16
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java374
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java5
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java18
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java7
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/IconFactory.java57
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java19
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/DescriptorsUtils.java4
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java10
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfo.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ClipboardSupport.java5
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java1
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java72
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java4
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java19
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java12
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java25
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/GridLayoutConverter.java13
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java12
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java99
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java8
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/AddSuppressAttribute.java17
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/CompatibilityLibraryHelper.java176
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java60
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java167
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectClassLoader.java91
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java5
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileWizard.java16
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoringTest.java5
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/refactoring/usecompound/compound5-expected-7.xml9
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/refactoring/usecompound/compound5.info3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/refactoring/usecompound/compound5.xml18
43 files changed, 1352 insertions, 684 deletions
diff --git a/eclipse/dictionary.txt b/eclipse/dictionary.txt
index aa985c7..dca9b23 100644
--- a/eclipse/dictionary.txt
+++ b/eclipse/dictionary.txt
@@ -199,6 +199,7 @@ preloaded
preloads
primordial
printf
+pristine
programmatic
programmatically
proguard
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/icons/GridLayout.png b/eclipse/plugins/com.android.ide.eclipse.adt/icons/GridLayout.png
index 1aa4165..ca64e8c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/icons/GridLayout.png
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/icons/GridLayout.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/icons/Space.png b/eclipse/plugins/com.android.ide.eclipse.adt/icons/Space.png
index 58afbe4..28b2553 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/icons/Space.png
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/icons/Space.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java
index b9c2290..47f3a58 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java
@@ -49,7 +49,6 @@ import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_TO_RIGHT
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_X;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_Y;
-import static com.android.ide.common.layout.LayoutConstants.ATTR_TEXT;
import static com.android.ide.common.layout.LayoutConstants.VALUE_FILL_PARENT;
import static com.android.ide.common.layout.LayoutConstants.VALUE_MATCH_PARENT;
import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT;
@@ -518,30 +517,11 @@ public class BaseLayoutRule extends BaseViewRule {
protected static void addAttributes(INode newNode, IDragElement oldElement,
Map<String, Pair<String, String>> idMap, AttributeFilter filter) {
- // A little trick here: when creating new UI widgets by dropping them
- // from the palette, we assign them a new id and then set the text
- // attribute to that id, so for example a Button will have
- // android:text="@+id/Button01".
- // Here we detect if such an id is being remapped to a new id and if
- // there's a text attribute with exactly the same id name, we update it
- // too.
- String oldText = null;
- String oldId = null;
- String newId = null;
-
for (IDragAttribute attr : oldElement.getAttributes()) {
String uri = attr.getUri();
String name = attr.getName();
String value = attr.getValue();
- if (uri.equals(ANDROID_URI)) {
- if (name.equals(ATTR_ID)) {
- oldId = value;
- } else if (name.equals(ATTR_TEXT)) {
- oldText = value;
- }
- }
-
IAttributeInfo attrInfo = newNode.getAttributeInfo(uri, name);
if (attrInfo != null) {
Format[] formats = attrInfo.getFormats();
@@ -557,17 +537,8 @@ public class BaseLayoutRule extends BaseViewRule {
}
if (value != null && value.length() > 0) {
newNode.setAttribute(uri, name, value);
-
- if (uri.equals(ANDROID_URI) && name.equals(ATTR_ID) &&
- oldId != null && !oldId.equals(value)) {
- newId = value;
- }
}
}
-
- if (newId != null && oldText != null && oldText.equals(oldId)) {
- newNode.setAttribute(ANDROID_URI, ATTR_TEXT, newId);
- }
}
/**
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridLayoutRule.java
index 4fda13d..f8f0a8c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridLayoutRule.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridLayoutRule.java
@@ -21,7 +21,9 @@ import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_COLUMN;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_GRAVITY;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_ROW;
import static com.android.ide.common.layout.LayoutConstants.ATTR_ORIENTATION;
+import static com.android.ide.common.layout.LayoutConstants.FQCN_GRID_LAYOUT;
import static com.android.ide.common.layout.LayoutConstants.FQCN_SPACE;
+import static com.android.ide.common.layout.LayoutConstants.FQCN_SPACE_V7;
import static com.android.ide.common.layout.LayoutConstants.GRAVITY_VALUE_FILL;
import static com.android.ide.common.layout.LayoutConstants.GRAVITY_VALUE_FILL_HORIZONTAL;
import static com.android.ide.common.layout.LayoutConstants.GRAVITY_VALUE_FILL_VERTICAL;
@@ -150,11 +152,12 @@ public class GridLayoutRule extends BaseLayoutRule {
final List<? extends INode> children) {
super.addLayoutActions(actions, parentNode, children);
+ String namespace = getNamespace(parentNode);
Choices orientationAction = RuleAction.createChoices(
ACTION_ORIENTATION,
"Orientation", //$NON-NLS-1$
new PropertyCallback(Collections.singletonList(parentNode),
- "Change LinearLayout Orientation", ANDROID_URI, ATTR_ORIENTATION), Arrays
+ "Change LinearLayout Orientation", namespace, ATTR_ORIENTATION), Arrays
.<String> asList("Set Horizontal Orientation", "Set Vertical Orientation"),
Arrays.<URL> asList(ICON_HORIZONTAL, ICON_VERTICAL), Arrays.<String> asList(
"horizontal", "vertical"), getCurrentOrientation(parentNode),
@@ -256,8 +259,8 @@ public class GridLayoutRule extends BaseLayoutRule {
* Returns the orientation attribute value currently used by the node (even if not
* defined, in which case the default horizontal value is returned)
*/
- private static String getCurrentOrientation(final INode node) {
- String orientation = node.getStringAttr(ANDROID_URI, ATTR_ORIENTATION);
+ private String getCurrentOrientation(final INode node) {
+ String orientation = node.getStringAttr(getNamespace(node), ATTR_ORIENTATION);
if (orientation == null || orientation.length() == 0) {
orientation = VALUE_HORIZONTAL;
}
@@ -332,11 +335,28 @@ public class GridLayoutRule extends BaseLayoutRule {
FillPreference fill = metadata.getFillPreference();
String gravity = computeDefaultGravity(fill);
if (gravity != null) {
- node.setAttribute(ANDROID_URI, ATTR_LAYOUT_GRAVITY, gravity);
+ node.setAttribute(getNamespace(parent), ATTR_LAYOUT_GRAVITY, gravity);
}
}
/**
+ * Returns the namespace URI to use for GridLayout-specific attributes, such
+ * as columnCount, layout_column, layout_column_span, layout_gravity etc.
+ *
+ * @param layout the GridLayout instance to look up the namespace for
+ * @return the namespace, never null
+ */
+ public String getNamespace(INode layout) {
+ String namespace = ANDROID_URI;
+
+ if (!layout.getFqcn().equals(FQCN_GRID_LAYOUT)) {
+ namespace = mRulesEngine.getAppNameSpace();
+ }
+
+ return namespace;
+ }
+
+ /**
* Computes the default gravity to be used for a widget of the given fill
* preference when added to a grid layout
*
@@ -374,7 +394,8 @@ public class GridLayoutRule extends BaseLayoutRule {
GridModel grid = new GridModel(mRulesEngine, parent, null);
for (INode child : deleted) {
// We don't care about deletion of spacers
- if (child.getFqcn().equals(FQCN_SPACE)) {
+ String fqcn = child.getFqcn();
+ if (fqcn.equals(FQCN_SPACE) || fqcn.equals(FQCN_SPACE_V7)) {
continue;
}
grid.markDeleted(child);
@@ -430,8 +451,9 @@ public class GridLayoutRule extends BaseLayoutRule {
Pair<Integer, Integer> spans = computeResizeSpans(state);
int rowSpan = spans.getFirst();
int columnSpan = spans.getSecond();
- GridModel.setColumnSpanAttribute(node, columnSpan);
- GridModel.setRowSpanAttribute(node, rowSpan);
+ GridModel grid = getGrid(state);
+ grid.setColumnSpanAttribute(node, columnSpan);
+ grid.setRowSpanAttribute(node, rowSpan);
}
}
@@ -561,7 +583,8 @@ public class GridLayoutRule extends BaseLayoutRule {
for (IDragElement element : elements) {
// Skip <Space> elements and only insert the real elements being
// copied
- if (elements.length > 1 && FQCN_SPACE.equals(element.getFqcn())) {
+ if (elements.length > 1 && (FQCN_SPACE.equals(element.getFqcn())
+ || FQCN_SPACE_V7.equals(element.getFqcn()))) {
continue;
}
@@ -571,8 +594,10 @@ public class GridLayoutRule extends BaseLayoutRule {
// Ensure that we reset any potential row/column attributes from a different
// grid layout being copied from
- newChild.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN, null);
- newChild.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW, null);
+ GridDropHandler handler = (GridDropHandler) feedback.userData;
+ GridModel grid = handler.getGrid();
+ grid.setGridAttribute(newChild, ATTR_LAYOUT_COLUMN, null);
+ grid.setGridAttribute(newChild, ATTR_LAYOUT_ROW, null);
// TODO: Set columnSpans to avoid making these widgets completely
// break the layout
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java
index 1b9f815..3129f4d 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LayoutConstants.java
@@ -196,6 +196,7 @@ public class LayoutConstants {
/** The fully qualified class name of a RelativeLayout view */
public static final String FQCN_GRID_LAYOUT = "android.widget.GridLayout"; //$NON-NLS-1$
+ public static final String FQCN_GRID_LAYOUT_V7 = "android.support.v7.widget.GridLayout"; //$NON-NLS-1$
/** The fully qualified class name of a FrameLayout view */
public static final String FQCN_FRAME_LAYOUT = "android.widget.FrameLayout"; //$NON-NLS-1$
@@ -247,6 +248,7 @@ public class LayoutConstants {
/** The fully qualified class name of a Space */
public static final String FQCN_SPACE = "android.widget.Space"; //$NON-NLS-1$
+ public static final String FQCN_SPACE_V7 = "android.support.v7.widget.Space"; //$NON-NLS-1$
/** The fully qualified class name of a TextView view */
public static final String FQCN_TEXT_VIEW = "android.widget.TextView"; //$NON-NLS-1$
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridDropHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridDropHandler.java
index 0c7ed9f..74c1b59 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridDropHandler.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridDropHandler.java
@@ -19,14 +19,12 @@ import static com.android.ide.common.layout.GridLayoutRule.GRID_SIZE;
import static com.android.ide.common.layout.GridLayoutRule.MARGIN_SIZE;
import static com.android.ide.common.layout.GridLayoutRule.MAX_CELL_DIFFERENCE;
import static com.android.ide.common.layout.GridLayoutRule.SHORT_GAP_DP;
-import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI;
import static com.android.ide.common.layout.LayoutConstants.ATTR_COLUMN_COUNT;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_COLUMN;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_COLUMN_SPAN;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_GRAVITY;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_ROW;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_ROW_SPAN;
-import static com.android.ide.common.layout.LayoutConstants.VALUE_1;
import static com.android.ide.common.layout.LayoutConstants.VALUE_BOTTOM;
import static com.android.ide.common.layout.LayoutConstants.VALUE_CENTER_HORIZONTAL;
import static com.android.ide.common.layout.LayoutConstants.VALUE_RIGHT;
@@ -478,20 +476,18 @@ public class GridDropHandler {
// bottom half!
- int columnX = mGrid.getColumnX(column);
- int rowY = mGrid.getRowY(row);
+ //int columnX = mGrid.getColumnX(column);
+ //int rowY = mGrid.getRowY(row);
- targetNode.setAttribute(ANDROID_URI, ATTR_COLUMN_COUNT, VALUE_1);
- //targetNode.setAttribute(ANDROID_URI, ATTR_COLUMN_COUNT, "3");
+ mGrid.setGridAttribute(targetNode, ATTR_COLUMN_COUNT, 2);
+ //mGrid.setGridAttribute(targetNode, ATTR_COLUMN_COUNT, 3);
//INode scr0 = addSpacer(targetNode, -1, 0, 0, 1, 1);
//INode sc1 = addSpacer(targetNode, -1, 0, 1, 0, 0);
//INode sc2 = addSpacer(targetNode, -1, 0, 2, 1, 0);
//INode sr1 = addSpacer(targetNode, -1, 1, 0, 0, 0);
//INode sr2 = addSpacer(targetNode, -1, 2, 0, 0, 1);
- //sc1.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN_WEIGHT, VALUE_1);
- //sr1.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW_WEIGHT, VALUE_1);
- //sc1.setAttribute(ANDROID_URI, ATTR_LAYOUT_GRAVITY, VALUE_FILL_HORIZONTAL);
- //sr1.setAttribute(ANDROID_URI, ATTR_LAYOUT_GRAVITY, VALUE_FILL_VERTICAL);
+ //mGrid.setGridAttribute(sc1, ATTR_LAYOUT_GRAVITY, VALUE_FILL_HORIZONTAL);
+ //mGrid.setGridAttribute(sr1, ATTR_LAYOUT_GRAVITY, VALUE_FILL_VERTICAL);
//
//mGrid.loadFromXml();
//column = mGrid.getColumn(columnX);
@@ -655,33 +651,33 @@ public class GridDropHandler {
// Set the cell position of the new widget
if (mColumnMatch.type == SegmentType.RIGHT) {
- newChild.setAttribute(ANDROID_URI, ATTR_LAYOUT_GRAVITY, VALUE_RIGHT);
+ mGrid.setGridAttribute(newChild, ATTR_LAYOUT_GRAVITY, VALUE_RIGHT);
} else if (mColumnMatch.type == SegmentType.CENTER_HORIZONTAL) {
- newChild.setAttribute(ANDROID_URI, ATTR_LAYOUT_GRAVITY, VALUE_CENTER_HORIZONTAL);
+ mGrid.setGridAttribute(newChild, ATTR_LAYOUT_GRAVITY, VALUE_CENTER_HORIZONTAL);
}
- newChild.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN, Integer.toString(column));
+ mGrid.setGridAttribute(newChild, ATTR_LAYOUT_COLUMN, column);
if (mRowMatch.type == SegmentType.BOTTOM) {
String value = VALUE_BOTTOM;
if (mColumnMatch.type == SegmentType.RIGHT) {
value = value + '|' + VALUE_RIGHT;
+ } else if (mColumnMatch.type == SegmentType.CENTER_HORIZONTAL) {
+ value = value + '|' + VALUE_CENTER_HORIZONTAL;
}
- newChild.setAttribute(ANDROID_URI, ATTR_LAYOUT_GRAVITY, value);
+ mGrid.setGridAttribute(newChild, ATTR_LAYOUT_GRAVITY, value);
}
- newChild.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW, Integer.toString(row));
+ mGrid.setGridAttribute(newChild, ATTR_LAYOUT_ROW, row);
// Apply spans to ensure that the widget can fit without pushing columns
if (columnSpan > 1) {
- newChild.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN_SPAN,
- Integer.toString(columnSpan));
+ mGrid.setGridAttribute(newChild, ATTR_LAYOUT_COLUMN_SPAN, columnSpan);
}
if (rowSpan > 1) {
- newChild.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW_SPAN, Integer.toString(rowSpan));
+ mGrid.setGridAttribute(newChild, ATTR_LAYOUT_ROW_SPAN, rowSpan);
}
// Ensure that we don't store columnCount=0
if (mGrid.actualColumnCount == 0) {
- mGrid.layout.setAttribute(ANDROID_URI, ATTR_COLUMN_COUNT,
- Integer.toString(Math.max(1, column + 1)));
+ mGrid.setGridAttribute(mGrid.layout, ATTR_COLUMN_COUNT, Math.max(1, column + 1));
}
return newChild;
@@ -708,10 +704,8 @@ public class GridDropHandler {
mGrid.addRow(mRowMatch.cellIndex, newChild, UNDEFINED, false, UNDEFINED, UNDEFINED);
}
- newChild.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN,
- Integer.toString(mColumnMatch.cellIndex));
- newChild.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW,
- Integer.toString(mRowMatch.cellIndex));
+ mGrid.setGridAttribute(newChild, ATTR_LAYOUT_COLUMN, mColumnMatch.cellIndex);
+ mGrid.setGridAttribute(newChild, ATTR_LAYOUT_ROW, mRowMatch.cellIndex);
return newChild;
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridModel.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridModel.java
index 1e4d5cd..9ef247e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridModel.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridModel.java
@@ -31,8 +31,12 @@ import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_ROW_SPAN
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH;
import static com.android.ide.common.layout.LayoutConstants.ATTR_ORIENTATION;
import static com.android.ide.common.layout.LayoutConstants.ATTR_ROW_COUNT;
+import static com.android.ide.common.layout.LayoutConstants.FQCN_GRID_LAYOUT;
import static com.android.ide.common.layout.LayoutConstants.FQCN_SPACE;
+import static com.android.ide.common.layout.LayoutConstants.FQCN_SPACE_V7;
+import static com.android.ide.common.layout.LayoutConstants.GRID_LAYOUT;
import static com.android.ide.common.layout.LayoutConstants.NEW_ID_PREFIX;
+import static com.android.ide.common.layout.LayoutConstants.SPACE;
import static com.android.ide.common.layout.LayoutConstants.VALUE_BOTTOM;
import static com.android.ide.common.layout.LayoutConstants.VALUE_CENTER_VERTICAL;
import static com.android.ide.common.layout.LayoutConstants.VALUE_N_DP;
@@ -147,6 +151,9 @@ public class GridModel {
*/
private Object mViewObject;
+ /** The namespace to use for attributes */
+ private String mNamespace;
+
/**
* Constructs a {@link GridModel} for the given layout
*
@@ -250,7 +257,7 @@ public class GridModel {
if (baseline != -1) {
// Even views that do have baselines do not count towards a row
// baseline if they have a vertical gravity
- String gravity = view.node.getStringAttr(ANDROID_URI, ATTR_LAYOUT_GRAVITY);
+ String gravity = getGridAttribute(view.node, ATTR_LAYOUT_GRAVITY);
if (gravity == null
|| !(gravity.contains(VALUE_TOP)
|| gravity.contains(VALUE_BOTTOM)
@@ -275,13 +282,61 @@ public class GridModel {
}
// Also fix the columnCount
- if (layout.getStringAttr(ANDROID_URI, ATTR_COLUMN_COUNT) != null &&
+ if (getGridAttribute(layout, ATTR_COLUMN_COUNT) != null &&
declaredColumnCount > actualColumnCount) {
- layout.setAttribute(ANDROID_URI, ATTR_COLUMN_COUNT,
- Integer.toString(actualColumnCount));
+ setGridAttribute(layout, ATTR_COLUMN_COUNT, actualColumnCount);
}
}
+ /**
+ * Sets the given GridLayout attribute (rowCount, layout_row, etc) to the
+ * given value. This automatically handles using the right XML namespace
+ * based on whether the GridLayout is the android.widget.GridLayout, or the
+ * support library GridLayout, and whether it's in a library project or not
+ * etc.
+ *
+ * @param node the node to apply the attribute to
+ * @param name the local name of the attribute
+ * @param value the integer value to set the attribute to
+ */
+ public void setGridAttribute(INode node, String name, int value) {
+ setGridAttribute(node, name, Integer.toString(value));
+ }
+
+ /**
+ * Sets the given GridLayout attribute (rowCount, layout_row, etc) to the
+ * given value. This automatically handles using the right XML namespace
+ * based on whether the GridLayout is the android.widget.GridLayout, or the
+ * support library GridLayout, and whether it's in a library project or not
+ * etc.
+ *
+ * @param node the node to apply the attribute to
+ * @param name the local name of the attribute
+ * @param value the string value to set the attribute to, or null to clear
+ * it
+ */
+ public void setGridAttribute(INode node, String name, String value) {
+ node.setAttribute(getNamespace(), name, value);
+ }
+
+ /**
+ * Returns the namespace URI to use for GridLayout-specific attributes, such
+ * as columnCount, layout_column, layout_column_span, layout_gravity etc.
+ *
+ * @return the namespace, never null
+ */
+ public String getNamespace() {
+ if (mNamespace == null) {
+ mNamespace = ANDROID_URI;
+
+ if (!layout.getFqcn().equals(FQCN_GRID_LAYOUT)) {
+ mNamespace = mRulesEngine.getAppNameSpace();
+ }
+ }
+
+ return mNamespace;
+ }
+
/** Removes the given flag from a flag attribute value and returns the result */
static String removeFlag(String flag, String value) {
if (value.equals(flag)) {
@@ -313,10 +368,10 @@ public class GridModel {
void loadFromXml() {
INode[] children = layout.getChildren();
- declaredRowCount = getInt(layout, ATTR_ROW_COUNT, UNDEFINED);
- declaredColumnCount = getInt(layout, ATTR_COLUMN_COUNT, UNDEFINED);
+ declaredRowCount = getGridAttribute(layout, ATTR_ROW_COUNT, UNDEFINED);
+ declaredColumnCount = getGridAttribute(layout, ATTR_COLUMN_COUNT, UNDEFINED);
// Horizontal is the default, so if no value is specified it is horizontal.
- vertical = VALUE_VERTICAL.equals(layout.getStringAttr(ANDROID_URI, ATTR_ORIENTATION));
+ vertical = VALUE_VERTICAL.equals(getGridAttribute(layout, ATTR_ORIENTATION));
mChildViews = new ArrayList<ViewData>(children.length);
int index = 0;
@@ -627,7 +682,7 @@ public class GridModel {
}
// The bounds should be in ascending order now
- if (GridLayoutRule.sDebugGridLayout) {
+ if (false && GridLayoutRule.sDebugGridLayout) {
for (int i = 1; i < actualRowCount; i++) {
assert mTop[i + 1] >= mTop[i];
}
@@ -756,8 +811,7 @@ public class GridModel {
// Insert a new column
if (declaredColumnCount != UNDEFINED) {
declaredColumnCount++;
- layout.setAttribute(ANDROID_URI, ATTR_COLUMN_COUNT,
- Integer.toString(declaredColumnCount));
+ setGridAttribute(layout, ATTR_COLUMN_COUNT, declaredColumnCount);
}
boolean isLastColumn = true;
@@ -796,12 +850,10 @@ public class GridModel {
// the new row number, but we use the spacer to assign the row
// some height.
if (view.column == newColumn) {
- view.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN,
- Integer.toString(view.column + 1));
+ setGridAttribute(view.node, ATTR_LAYOUT_COLUMN, view.column + 1);
} // else: endColumn == newColumn: handled below
- } else if (view.node.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN) != null) {
- view.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN,
- Integer.toString(view.column + 1));
+ } else if (getGridAttribute(view.node, ATTR_LAYOUT_COLUMN) != null) {
+ setGridAttribute(view.node, ATTR_LAYOUT_COLUMN, view.column + 1);
}
} else if (endColumn > newColumn) {
setColumnSpanAttribute(view.node, view.columnSpan + 1);
@@ -820,8 +872,7 @@ public class GridModel {
if (isLastColumn) {
for (ViewData view : mChildViews) {
if (view.column == 0 && view.row > 0) {
- view.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW,
- Integer.toString(view.row));
+ setGridAttribute(view.node, ATTR_LAYOUT_ROW, view.row);
}
}
if (split) {
@@ -867,8 +918,7 @@ public class GridModel {
// TODO: Do this under a write lock? / editXml lock?
if (declaredColumnCount != UNDEFINED) {
declaredColumnCount--;
- layout.setAttribute(ANDROID_URI, ATTR_COLUMN_COUNT,
- Integer.toString(declaredColumnCount));
+ setGridAttribute(layout, ATTR_COLUMN_COUNT, declaredColumnCount);
}
// Remove any elements that begin in the deleted columns...
@@ -894,9 +944,8 @@ public class GridModel {
// Subtract column span to skip this item
setColumnSpanAttribute(view.node, view.columnSpan - 1);
} else if (view.column > removedColumn) {
- if (view.node.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN) != null) {
- view.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN,
- Integer.toString(view.column - 1));
+ if (getGridAttribute(view.node, ATTR_LAYOUT_COLUMN) != null) {
+ setGridAttribute(view.node, ATTR_LAYOUT_COLUMN, view.column - 1);
}
}
}
@@ -948,8 +997,7 @@ public class GridModel {
if (declaredRowCount != UNDEFINED) {
declaredRowCount++;
- layout.setAttribute(ANDROID_URI, ATTR_ROW_COUNT,
- Integer.toString(declaredRowCount));
+ setGridAttribute(layout, ATTR_ROW_COUNT, declaredRowCount);
}
boolean added = false;
for (ViewData view : mChildViews) {
@@ -961,8 +1009,7 @@ public class GridModel {
int index = getChildIndex(layout.getChildren(), view.node);
assert view.index == index; // TODO: Get rid of getter
if (declaredColumnCount != UNDEFINED && !split) {
- layout.setAttribute(ANDROID_URI, ATTR_COLUMN_COUNT,
- Integer.toString(declaredColumnCount));
+ setGridAttribute(layout, ATTR_COLUMN_COUNT, declaredColumnCount);
}
newView = addSpacer(layout, index,
split ? newRow - 1 : UNDEFINED,
@@ -975,13 +1022,11 @@ public class GridModel {
// This means we don't really need the spacer above to imply
// the new row number, but we use the spacer to assign the row
// some height.
- view.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW,
- Integer.toString(view.row + 1));
+ setGridAttribute(view.node, ATTR_LAYOUT_ROW, view.row + 1);
added = true;
- } else if (view.node.getStringAttr(ANDROID_URI, ATTR_LAYOUT_ROW) != null) {
- view.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW,
- Integer.toString(view.row + 1));
+ } else if (getGridAttribute(view.node, ATTR_LAYOUT_ROW) != null) {
+ setGridAttribute(view.node, ATTR_LAYOUT_ROW, view.row + 1);
}
} else {
int endRow = view.row + view.rowSpan;
@@ -1003,12 +1048,12 @@ public class GridModel {
rowHeightDp != UNDEFINED ? rowHeightDp : DEFAULT_CELL_HEIGHT);
}
if (declaredColumnCount != UNDEFINED && !split) {
- newView.setAttribute(ANDROID_URI, ATTR_COLUMN_COUNT,
- Integer.toString(declaredColumnCount));
+ setGridAttribute(layout, ATTR_COLUMN_COUNT, declaredColumnCount);
}
if (split) {
- newView.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW, Integer.toString(newRow - 1));
- newView.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN, Integer.toString(column));
+ setGridAttribute(newView, ATTR_LAYOUT_ROW, newRow - 1);
+ setGridAttribute(newView, ATTR_LAYOUT_COLUMN, column);
+
}
}
@@ -1046,8 +1091,7 @@ public class GridModel {
// the declared row range!
if (declaredRowCount != UNDEFINED) {
declaredRowCount--;
- layout.setAttribute(ANDROID_URI, ATTR_ROW_COUNT,
- Integer.toString(declaredRowCount));
+ setGridAttribute(layout, ATTR_ROW_COUNT, declaredRowCount);
}
// Remove any elements that begin in the deleted rows...
@@ -1062,9 +1106,8 @@ public class GridModel {
// positions for other cells
layout.removeChild(view.node);
} else if (view.row > removedRow) {
- if (view.node.getStringAttr(ANDROID_URI, ATTR_LAYOUT_ROW) != null) {
- view.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW,
- Integer.toString(view.row - 1));
+ if (getGridAttribute(view.node, ATTR_LAYOUT_ROW) != null) {
+ setGridAttribute(view.node, ATTR_LAYOUT_ROW, view.row - 1);
}
} else if (view.row < removedRow
&& view.row + view.rowSpan > removedRow) {
@@ -1422,8 +1465,7 @@ public class GridModel {
if (insertMarginColumn) {
declaredColumnCount++;
}
- layout.setAttribute(ANDROID_URI, ATTR_COLUMN_COUNT,
- Integer.toString(declaredColumnCount));
+ setGridAttribute(layout, ATTR_COLUMN_COUNT, declaredColumnCount);
}
// Are we inserting a new last column in the grid? That requires some special handling...
@@ -1441,9 +1483,8 @@ public class GridModel {
if (isLastColumn) {
for (ViewData view : mChildViews) {
if (view.column == 0 && view.row > 0) {
- if (view.node.getStringAttr(ANDROID_URI, ATTR_LAYOUT_ROW) == null) {
- view.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW,
- Integer.toString(view.row));
+ if (getGridAttribute(view.node, ATTR_LAYOUT_ROW) == null) {
+ setGridAttribute(view.node, ATTR_LAYOUT_ROW, view.row);
}
}
}
@@ -1483,9 +1524,8 @@ public class GridModel {
// where necessary, e.g. only on the FIRST view on this row following the
// skipped column!
- //if (node.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN) != null) {
- node.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN,
- Integer.toString(column + (insertMarginColumn ? 2 : 1)));
+ //if (getGridAttribute(node, ATTR_LAYOUT_COLUMN) != null) {
+ setGridAttribute(node, ATTR_LAYOUT_COLUMN, column + (insertMarginColumn ? 2 : 1));
//}
} else if (!view.isSpacer()) {
int endColumn = column + view.columnSpan;
@@ -1508,8 +1548,8 @@ public class GridModel {
if (remaining > 0) {
prevColumnSpacer.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WIDTH,
String.format(VALUE_N_DP, remaining));
- prevColumnSpacer.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN,
- Integer.toString(insertMarginColumn ? newColumn + 1 : newColumn));
+ setGridAttribute(prevColumnSpacer.node, ATTR_LAYOUT_COLUMN,
+ insertMarginColumn ? newColumn + 1 : newColumn);
}
}
@@ -1541,8 +1581,7 @@ public class GridModel {
if (insertMarginRow) {
declaredRowCount++;
}
- layout.setAttribute(ANDROID_URI, ATTR_ROW_COUNT,
- Integer.toString(declaredRowCount));
+ setGridAttribute(layout, ATTR_ROW_COUNT, declaredRowCount);
}
// Find the spacer which marks this row, and if found, mark it as a split
@@ -1563,9 +1602,8 @@ public class GridModel {
INode node = view.node;
int row = view.row;
if (row > newRow || (row == newRow && view.node.getBounds().y2() > y)) {
- //if (node.getStringAttr(ANDROID_URI, ATTR_LAYOUT_ROW) != null) {
- node.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW,
- Integer.toString(row + (insertMarginRow ? 2 : 1)));
+ //if (getGridAttribute(node, ATTR_LAYOUT_ROW) != null) {
+ setGridAttribute(node, ATTR_LAYOUT_ROW, row + (insertMarginRow ? 2 : 1));
//}
} else if (!view.isSpacer()) {
int endRow = row + view.rowSpan;
@@ -1588,8 +1626,8 @@ public class GridModel {
if (remaining > 0) {
prevRowSpacer.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_HEIGHT,
String.format(VALUE_N_DP, remaining));
- prevRowSpacer.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW,
- Integer.toString(insertMarginRow ? newRow + 1 : newRow));
+ setGridAttribute(prevRowSpacer.node, ATTR_LAYOUT_ROW,
+ insertMarginRow ? newRow + 1 : newRow);
}
}
@@ -1604,7 +1642,7 @@ public class GridModel {
* Data about a view in a table; this is not the same as a cell because multiple views
* can share a single cell, and a view can span many cells.
*/
- static class ViewData {
+ class ViewData {
public final INode node;
public final int index;
public int row;
@@ -1617,23 +1655,20 @@ public class GridModel {
node = n;
this.index = index;
- column = getInt(n, ATTR_LAYOUT_COLUMN, UNDEFINED);
- columnSpan = getInt(n, ATTR_LAYOUT_COLUMN_SPAN, 1);
- row = getInt(n, ATTR_LAYOUT_ROW, UNDEFINED);
- rowSpan = getInt(n, ATTR_LAYOUT_ROW_SPAN, 1);
- gravity = GravityHelper.getGravity(n.getStringAttr(ANDROID_URI, ATTR_LAYOUT_GRAVITY),
- 0);
+ column = getGridAttribute(n, ATTR_LAYOUT_COLUMN, UNDEFINED);
+ columnSpan = getGridAttribute(n, ATTR_LAYOUT_COLUMN_SPAN, 1);
+ row = getGridAttribute(n, ATTR_LAYOUT_ROW, UNDEFINED);
+ rowSpan = getGridAttribute(n, ATTR_LAYOUT_ROW_SPAN, 1);
+ gravity = GravityHelper.getGravity(getGridAttribute(n, ATTR_LAYOUT_GRAVITY), 0);
}
/** Applies the column and row fields into the XML model */
void applyPositionAttributes() {
- if (node.getStringAttr(ANDROID_URI, ATTR_LAYOUT_COLUMN) == null) {
- node.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN,
- Integer.toString(column));
+ if (getGridAttribute(node, ATTR_LAYOUT_COLUMN) == null) {
+ setGridAttribute(node, ATTR_LAYOUT_COLUMN, column);
}
- if (node.getStringAttr(ANDROID_URI, ATTR_LAYOUT_ROW) == null) {
- node.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW,
- Integer.toString(row));
+ if (getGridAttribute(node, ATTR_LAYOUT_ROW) == null) {
+ setGridAttribute(node, ATTR_LAYOUT_ROW, row);
}
}
@@ -1653,7 +1688,8 @@ public class GridModel {
/** Returns true if this {@link ViewData} represents a spacer */
boolean isSpacer() {
- return FQCN_SPACE.equals(node.getFqcn());
+ String fqcn = node.getFqcn();
+ return FQCN_SPACE.equals(fqcn) || FQCN_SPACE_V7.equals(fqcn);
}
/**
@@ -1690,9 +1726,8 @@ public class GridModel {
* @param node the target node
* @param span the new column span
*/
- public static void setColumnSpanAttribute(INode node, int span) {
- node.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN_SPAN,
- span > 1 ? Integer.toString(span) : null);
+ public void setColumnSpanAttribute(INode node, int span) {
+ setGridAttribute(node, ATTR_LAYOUT_COLUMN_SPAN, span > 1 ? Integer.toString(span) : null);
}
/**
@@ -1702,9 +1737,8 @@ public class GridModel {
* @param node the target node
* @param span the new row span
*/
- public static void setRowSpanAttribute(INode node, int span) {
- node.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW_SPAN,
- span > 1 ? Integer.toString(span) : null);
+ public void setRowSpanAttribute(INode node, int span) {
+ setGridAttribute(node, ATTR_LAYOUT_ROW_SPAN, span > 1 ? Integer.toString(span) : null);
}
/** Returns the index of the given target node in the given child node array */
@@ -1768,7 +1802,8 @@ public class GridModel {
for (ViewData spacer : rowSpacers.values()) {
layout.removeChild(spacer.node);
}
- layout.setAttribute(ANDROID_URI, ATTR_COLUMN_COUNT, Integer.toString(2));
+ setGridAttribute(layout, ATTR_COLUMN_COUNT, 2);
+
return;
}
@@ -1792,8 +1827,7 @@ public class GridModel {
nextSpacer.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WIDTH,
String.format(VALUE_N_DP, combinedSizeDp));
// Also move the spacer into this column
- nextSpacer.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN,
- Integer.toString(column));
+ setGridAttribute(nextSpacer.node, ATTR_LAYOUT_COLUMN, column);
columnSpacers.put(column, nextSpacer);
} else {
continue;
@@ -1815,8 +1849,7 @@ public class GridModel {
if (view.column >= column) {
if (view.column > 0) {
view.column--;
- view.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN,
- Integer.toString(view.column));
+ setGridAttribute(view.node, ATTR_LAYOUT_COLUMN, view.column);
}
} else if (!view.isSpacer()) {
int endColumn = view.column + view.columnSpan;
@@ -1843,8 +1876,7 @@ public class GridModel {
int combinedSizeDp = nextSizeDp + rowHeightDp;
nextSpacer.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_HEIGHT,
String.format(VALUE_N_DP, combinedSizeDp));
- nextSpacer.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW,
- Integer.toString(row));
+ setGridAttribute(nextSpacer.node, ATTR_LAYOUT_ROW, row);
rowSpacers.put(row, nextSpacer);
} else {
continue;
@@ -1865,8 +1897,7 @@ public class GridModel {
if (view.row >= row) {
if (view.row > 0) {
view.row--;
- view.node.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW,
- Integer.toString(view.row));
+ setGridAttribute(view.node, ATTR_LAYOUT_ROW, view.row);
}
} else if (!view.isSpacer()) {
int endRow = view.row + view.rowSpan;
@@ -1937,19 +1968,27 @@ public class GridModel {
* @param heightDp the height in device independent pixels to assign to the spacer
* @return the newly added spacer
*/
- static INode addSpacer(INode parent, int index, int row, int column,
+ INode addSpacer(INode parent, int index, int row, int column,
int widthDp, int heightDp) {
INode spacer;
+
+ String tag = FQCN_SPACE;
+ String gridLayout = parent.getFqcn();
+ if (!gridLayout.equals(GRID_LAYOUT) && gridLayout.length() > GRID_LAYOUT.length()) {
+ String pkg = gridLayout.substring(0, gridLayout.length() - GRID_LAYOUT.length());
+ tag = pkg + SPACE;
+ }
if (index != -1) {
- spacer = parent.insertChildAt(FQCN_SPACE, index);
+ spacer = parent.insertChildAt(tag, index);
} else {
- spacer = parent.appendChild(FQCN_SPACE);
+ spacer = parent.appendChild(tag);
}
+
if (row != UNDEFINED) {
- spacer.setAttribute(ANDROID_URI, ATTR_LAYOUT_ROW, Integer.toString(row));
+ setGridAttribute(spacer, ATTR_LAYOUT_ROW, row);
}
if (column != UNDEFINED) {
- spacer.setAttribute(ANDROID_URI, ATTR_LAYOUT_COLUMN, Integer.toString(column));
+ setGridAttribute(spacer, ATTR_LAYOUT_COLUMN, column);
}
if (widthDp > 0) {
spacer.setAttribute(ANDROID_URI, ATTR_LAYOUT_WIDTH,
@@ -1985,41 +2024,34 @@ public class GridModel {
}
/**
- * Returns the integer value of the given attribute, or the given defaultValue if the
- * attribute was not set.
+ * Returns the string value of the given attribute, or null if it does not
+ * exist. This only works for attributes that are GridLayout specific, such
+ * as columnCount, layout_column, layout_row_span, etc.
*
* @param node the target node
- * @param attribute the attribute name (which must be in the android: namespace)
- * @param defaultValue the default value to use if the value is not set
- * @return the attribute integer value
+ * @param name the attribute name (which must be in the android: namespace)
+ * @return the attribute value or null
*/
- private static int getInt(INode node, String attribute, int defaultValue) {
- String valueString = node.getStringAttr(ANDROID_URI, attribute);
- if (valueString != null) {
- try {
- return Integer.decode(valueString);
- } catch (NumberFormatException nufe) {
- // Ignore - error in user's XML
- }
- }
- return defaultValue;
+ public String getGridAttribute(INode node, String name) {
+ return node.getStringAttr(getNamespace(), name);
}
/**
- * Returns the float value of the given attribute, or the given defaultValue if the
- * attribute was not set.
+ * Returns the integer value of the given attribute, or the given defaultValue if the
+ * attribute was not set. This only works for attributes that are GridLayout specific,
+ * such as columnCount, layout_column, layout_row_span, etc.
*
* @param node the target node
* @param attribute the attribute name (which must be in the android: namespace)
* @param defaultValue the default value to use if the value is not set
- * @return the attribute float value
+ * @return the attribute integer value
*/
- private static float getFloat(INode node, String attribute, float defaultValue) {
- String valueString = node.getStringAttr(ANDROID_URI, attribute);
+ private int getGridAttribute(INode node, String attribute, int defaultValue) {
+ String valueString = node.getStringAttr(getNamespace(), attribute);
if (valueString != null) {
try {
- return Float.parseFloat(valueString);
+ return Integer.decode(valueString);
} catch (NumberFormatException nufe) {
// Ignore - error in user's XML
}
@@ -2029,24 +2061,6 @@ public class GridModel {
}
/**
- * Returns the boolean value of the given attribute, or the given defaultValue if the
- * attribute was not set.
- *
- * @param node the target node
- * @param attribute the attribute name (which must be in the android: namespace)
- * @param defaultValue the default value to use if the value is not set
- * @return the attribute boolean value
- */
- private static boolean getBoolean(INode node, String attribute, boolean defaultValue) {
- String valueString = node.getStringAttr(ANDROID_URI, attribute);
- if (valueString != null) {
- return Boolean.valueOf(valueString);
- }
-
- return defaultValue;
- }
-
- /**
* Returns the number of children views in the GridLayout
*
* @return the number of children views in the GridLayout
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java
index 62b6804..7e0392a 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java
@@ -373,8 +373,12 @@ public class AdtUtils {
* @param offset the offset to be checked
* @return a list (possibly empty but never null) of matching markers
*/
- public static List<IMarker> findMarkersOnLine(String markerType,
- IResource file, IDocument document, int offset) {
+ @NonNull
+ public static List<IMarker> findMarkersOnLine(
+ @NonNull String markerType,
+ @NonNull IResource file,
+ @NonNull IDocument document,
+ int offset) {
List<IMarker> matchingMarkers = new ArrayList<IMarker>(2);
try {
IMarker[] markers = file.findMarkers(markerType, true, IResource.DEPTH_ZERO);
@@ -413,6 +417,7 @@ public class AdtUtils {
*
* @return the available and open Android projects, never null
*/
+ @NonNull
public static IJavaProject[] getOpenAndroidProjects() {
return BaseProjectHelper.getAndroidProjects(new IProjectFilter() {
@Override
@@ -423,6 +428,43 @@ public class AdtUtils {
}
/**
+ * Returns a unique project name, based on the given {@code base} file name
+ * possibly with a {@code conjunction} and a new number behind it to ensure
+ * that the project name is unique. For example,
+ * {@code getUniqueProjectName("project", "_")} will return
+ * {@code "project"} if that name does not already exist, and if it does, it
+ * will return {@code "project_2"}.
+ *
+ * @param base the base name to use, such as "foo"
+ * @param conjunction a string to insert between the base name and the
+ * number.
+ * @return a unique project name based on the given base and conjunction
+ */
+ public static String getUniqueProjectName(String base, String conjunction) {
+ // We're using all workspace projects here rather than just open Android project
+ // via getOpenAndroidProjects because the name cannot conflict with non-Android
+ // or closed projects either
+ IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
+ IProject[] projects = workspaceRoot.getProjects();
+
+ for (int i = 1; i < 1000; i++) {
+ String name = i == 1 ? base : base + conjunction + Integer.toString(i);
+ boolean found = false;
+ for (IProject project : projects) {
+ if (project.getName().equals(name)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return name;
+ }
+ }
+
+ return base;
+ }
+
+ /**
* Returns the name of the parent folder for the given editor input
*
* @param editorInput the editor input to check
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/AddCompatibilityJarAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/AddCompatibilityJarAction.java
index b758b67..2428e60 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/AddCompatibilityJarAction.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/AddCompatibilityJarAction.java
@@ -17,18 +17,28 @@
package com.android.ide.eclipse.adt.internal.actions;
import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.AdtUtils;
import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
import com.android.ide.eclipse.adt.internal.sdk.AdtConsoleSdkLog;
+import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.sdklib.SdkConstants;
+import com.android.sdklib.internal.project.ProjectProperties;
+import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
+import com.android.sdklib.internal.project.ProjectPropertiesWorkingCopy;
import com.android.sdklib.io.FileOp;
import com.android.sdkuilib.internal.repository.sdkman2.AdtUpdateDialog;
import com.android.util.Pair;
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.filesystem.IFileSystem;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
@@ -117,12 +127,22 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate {
AdtPlugin.log(IStatus.ERROR, "JavaProject is null for %1$s", project); //$NON-NLS-1$
}
+ File jarPath = installSupport();
+ if (jarPath != null) {
+ return addJar(javaProject, jarPath, waitForFinish);
+ } else {
+ return false;
+ }
+ }
+
+ private static File installSupport() {
+
final Sdk sdk = Sdk.getCurrent();
if (sdk == null) {
AdtPlugin.printErrorToConsole(
AddCompatibilityJarAction.class.getSimpleName(), // tag
"Error: Android SDK is not loaded yet."); //$NON-NLS-1$
- return false;
+ return null;
}
// TODO: For the generic action, check the library isn't in the project already.
@@ -138,9 +158,12 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate {
Pair<Boolean, File> result = window.installExtraPackage(
"android", "support"); //$NON-NLS-1$ //$NON-NLS-2$
+ // TODO: Make sure the version is at the required level; we know we need at least one
+ // containing the v7 support
+
if (!result.getFirst().booleanValue()) {
AdtPlugin.printErrorToConsole("Failed to install Android Compatibility library");
- return false;
+ return null;
}
// TODO these "v4" values needs to be dynamic, e.g. we could try to match
@@ -153,11 +176,19 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate {
if (!jarPath.isFile()) {
AdtPlugin.printErrorToConsole("Android Compatibility JAR not found:",
jarPath.getAbsolutePath());
- return false;
+ return null;
}
- // Then run an Eclipse asynchronous job to update the project
+ return jarPath;
+ }
+
+ private static boolean addJar(
+ final IJavaProject javaProject,
+ final File jarPath,
+ boolean waitForFinish) {
+ // Run an Eclipse asynchronous job to update the project
+ final IProject project = javaProject.getProject();
Job job = new Job("Add Compatibility Library to Project") {
@Override
protected IStatus run(IProgressMonitor monitor) {
@@ -208,6 +239,212 @@ public class AddCompatibilityJarAction implements IObjectActionDelegate {
return true;
}
+ /**
+ * Similar to {@link #install}, but rather than copy a jar into the given
+ * project, it creates a new library project in the workspace for the
+ * compatibility library, and adds a library dependency on the newly
+ * installed library from the given project.
+ *
+ * @param project the project to add a dependency on the library to
+ * @param waitForFinish If true, block until the task has finished
+ * @return true if the installation was successful (or if
+ * <code>waitForFinish</code> is false, if the installation is
+ * likely to be successful - e.g. the user has at least agreed to
+ * all installation prompts.)
+ */
+ public static boolean installLibrary(final IProject project, boolean waitForFinish) {
+ final IJavaProject javaProject = JavaCore.create(project);
+ if (javaProject != null) {
+
+ File sdk = new File(Sdk.getCurrent().getSdkLocation());
+ File supportPath = new File(sdk,
+ SdkConstants.FD_EXTRAS + File.separator
+ + "android" + File.separator //$NON-NLS-1$
+ + "support"); //$NON-NLS-1$
+ if (!supportPath.isDirectory()) {
+ File path = installSupport();
+ if (path == null) {
+ return false;
+ }
+ assert path.equals(supportPath);
+ }
+ File libraryPath = new File(supportPath,
+ "v7" + File.separator //$NON-NLS-1$
+ + "gridlayout"); //$NON-NLS-1$
+ if (!libraryPath.isDirectory()) {
+ // Upgrade support package: it's out of date. The SDK manager will
+ // perform an upgrade to the latest version if the package is already installed.
+ File path = installSupport();
+ if (path == null) {
+ return false;
+ }
+ assert path.equals(libraryPath) : path;
+ }
+
+ // Create workspace copy of the project and add library dependency
+ IProject libraryProject = createLibraryProject(libraryPath, project, waitForFinish);
+ if (libraryProject != null) {
+ return addLibraryDependency(libraryProject, project, waitForFinish);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Creates a library project in the Eclipse workspace out of the grid layout project
+ * in the SDK tree.
+ *
+ * @param libraryPath the path to the directory tree containing the project contents
+ * @param project the project to copy the SDK target out of
+ * @param waitForFinish whether the operation should finish before this method returns
+ * @return a library project, or null if it fails for some reason
+ */
+ private static IProject createLibraryProject(
+ final File libraryPath,
+ final IProject project,
+ boolean waitForFinish) {
+
+ // Install a new library into the workspace. This is a copy rather than
+ // a reference to the compatibility library version such that modifications
+ // do not modify the pristine copy in the SDK install area.
+
+ final IProject newProject;
+ try {
+ IProgressMonitor monitor = new NullProgressMonitor();
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+
+ String name = AdtUtils.getUniqueProjectName(
+ "gridlayout_v7", "_"); //$NON-NLS-1$ //$NON-NLS-2$
+ newProject = root.getProject(name);
+ newProject.create(monitor);
+
+ // Copy in the files recursively
+ IFileSystem fileSystem = EFS.getLocalFileSystem();
+ IFileStore sourceDir = fileSystem.getStore(libraryPath.toURI());
+ IFileStore destDir = fileSystem.getStore(newProject.getLocationURI());
+ sourceDir.copy(destDir, EFS.OVERWRITE, null);
+
+ // Make sure the src folder exists
+ destDir.getChild("src").mkdir(0, null /*monitor*/);
+
+ // Set the android platform to the same level as the calling project
+ ProjectState state = Sdk.getProjectState(project);
+ String target = state.getProperties().getProperty(ProjectProperties.PROPERTY_TARGET);
+ if (target != null && target.length() > 0) {
+ ProjectProperties properties = ProjectProperties.load(libraryPath.getPath(),
+ PropertyType.PROJECT);
+ ProjectPropertiesWorkingCopy copy = properties.makeWorkingCopy();
+ copy.setProperty(ProjectProperties.PROPERTY_TARGET, target);
+ try {
+ copy.save();
+ } catch (Exception e) {
+ AdtPlugin.log(e, null);
+ }
+ }
+
+ newProject.open(monitor);
+
+ return newProject;
+ } catch (CoreException e) {
+ AdtPlugin.log(e, null);
+ return null;
+ }
+ }
+
+ /**
+ * Adds a library dependency on the given library into the given project.
+ *
+ * @param libraryProject the library project to depend on
+ * @param dependentProject the project to write the dependency into
+ * @param waitForFinish whether this method should wait for the job to
+ * finish
+ * @return true if the operation succeeded
+ */
+ public static boolean addLibraryDependency(
+ final IProject libraryProject,
+ final IProject dependentProject,
+ boolean waitForFinish) {
+
+ // Now add library dependency
+
+ // Run an Eclipse asynchronous job to update the project
+ Job job = new Job("Add Compatibility Library Dependency to Project") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ monitor.beginTask("Add library dependency to project build path", 3);
+ monitor.worked(1);
+
+ // TODO: Add library project to the project.properties file!
+ ProjectState state = Sdk.getProjectState(dependentProject);
+ ProjectPropertiesWorkingCopy mPropertiesWorkingCopy =
+ state.getProperties().makeWorkingCopy();
+
+ // Get the highest version number of the libraries; there cannot be any
+ // gaps so we will assign the next library the next number
+ int nextVersion = 1;
+ for (String property : mPropertiesWorkingCopy.keySet()) {
+ if (property.startsWith(ProjectProperties.PROPERTY_LIB_REF)) {
+ String s = property.substring(
+ ProjectProperties.PROPERTY_LIB_REF.length());
+ int version = Integer.parseInt(s);
+ if (version >= nextVersion) {
+ nextVersion = version + 1;
+ }
+ }
+ }
+
+ IPath relativePath = libraryProject.getLocation().makeRelativeTo(
+ dependentProject.getLocation());
+
+ mPropertiesWorkingCopy.setProperty(
+ ProjectProperties.PROPERTY_LIB_REF + nextVersion,
+ relativePath.toString());
+ try {
+ mPropertiesWorkingCopy.save();
+ IResource projectProp = dependentProject.findMember(
+ SdkConstants.FN_PROJECT_PROPERTIES);
+ projectProp.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor());
+ } catch (Exception e) {
+ String msg = String.format(
+ "Failed to save %1$s for project %2$s",
+ SdkConstants.FN_PROJECT_PROPERTIES, dependentProject.getName());
+ AdtPlugin.log(e, msg);
+ }
+
+ // Project fix-ups
+ Job fix = FixProjectAction.createFixProjectJob(libraryProject);
+ fix.schedule();
+ fix.join();
+
+ monitor.worked(1);
+
+ return Status.OK_STATUS;
+ } catch (Exception e) {
+ return new Status(Status.ERROR, AdtPlugin.PLUGIN_ID, Status.ERROR,
+ "Failed", e); //$NON-NLS-1$
+ } finally {
+ if (monitor != null) {
+ monitor.done();
+ }
+ }
+ }
+ };
+ job.schedule();
+
+ if (waitForFinish) {
+ try {
+ job.join();
+ return job.getState() == IStatus.OK;
+ } catch (InterruptedException e) {
+ AdtPlugin.log(e, null);
+ }
+ }
+
+ return true;
+ }
+
private static IResource copyJarIntoProject(
IProject project,
File jarPath,
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/FixProjectAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/FixProjectAction.java
index c073022..254219f 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/FixProjectAction.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/FixProjectAction.java
@@ -16,6 +16,7 @@
package com.android.ide.eclipse.adt.internal.actions;
+import com.android.annotations.NonNull;
import com.android.ide.eclipse.adt.internal.project.AndroidNature;
import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
@@ -82,7 +83,18 @@ public class FixProjectAction implements IObjectActionDelegate {
}
private void fixProject(final IProject project) {
- new Job("Fix Project Properties") {
+ createFixProjectJob(project).schedule();
+ }
+
+ /**
+ * Creates a job to fix the project
+ *
+ * @param project the project to fix
+ * @return a job to perform the fix (not yet scheduled)
+ */
+ @NonNull
+ public static Job createFixProjectJob(@NonNull final IProject project) {
+ return new Job("Fix Project Properties") {
@Override
protected IStatus run(IProgressMonitor monitor) {
@@ -129,7 +141,7 @@ public class FixProjectAction implements IObjectActionDelegate {
}
}
}
- }.schedule();
+ };
}
/**
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java
index e915544..e8fbadb 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java
@@ -21,8 +21,6 @@ import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.AndroidPrintStream;
import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity;
-import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
-import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.IAndroidTarget;
@@ -33,11 +31,9 @@ import com.android.sdklib.build.ApkBuilder.JarStatus;
import com.android.sdklib.build.ApkBuilder.SigningInfo;
import com.android.sdklib.build.ApkCreationException;
import com.android.sdklib.build.DuplicateFileException;
-import com.android.sdklib.build.IArchiveBuilder;
import com.android.sdklib.build.SealedApkException;
import com.android.sdklib.internal.build.DebugKeyProvider;
import com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException;
-import com.android.sdklib.internal.build.SignedJarBuilder;
import com.android.sdklib.util.GrabProcessOutput;
import com.android.sdklib.util.GrabProcessOutput.IProcessOutput;
import com.android.sdklib.util.GrabProcessOutput.Wait;
@@ -46,9 +42,6 @@ import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IResourceProxy;
-import org.eclipse.core.resources.IResourceProxyVisitor;
-import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
@@ -69,8 +62,12 @@ import java.io.PrintStream;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.TreeMap;
/**
@@ -108,11 +105,14 @@ public class BuildHelper {
private final boolean mVerbose;
private final boolean mDebugMode;
+ private final Set<String> mCompiledCodePaths = new HashSet<String>();
+
public static final boolean BENCHMARK_FLAG = false;
public static long sStartOverallTime = 0;
public static long sStartJavaCTime = 0;
private final static int MILLION = 1000000;
+ private String mProguardFile;
/**
* An object able to put a marker on a resource.
@@ -128,14 +128,18 @@ public class BuildHelper {
* @param errStream
* @param debugMode whether this is a debug build
* @param verbose
+ * @throws CoreException
*/
public BuildHelper(IProject project, AndroidPrintStream outStream,
- AndroidPrintStream errStream, boolean debugMode, boolean verbose) {
+ AndroidPrintStream errStream, boolean debugMode, boolean verbose,
+ ResourceMarker resMarker) throws CoreException {
mProject = project;
mOutStream = outStream;
mErrStream = errStream;
mDebugMode = debugMode;
mVerbose = verbose;
+
+ gatherPaths(resMarker);
}
public void updateCrunchCache() throws AaptExecException, AaptResultException {
@@ -169,11 +173,6 @@ public class BuildHelper {
}
}
- public static void writeResources(IArchiveBuilder builder, IJavaProject javaProject)
- throws DuplicateFileException, ApkCreationException, SealedApkException, CoreException {
- writeStandardResources(builder, javaProject, null);
- }
-
/**
* Packages the resources of the projet into a .ap_ file.
* @param manifestFile the manifest of the project.
@@ -287,9 +286,7 @@ public class BuildHelper {
* @param intermediateApk The path to the temporary resource file.
* @param dex The path to the dex file.
* @param output The path to the final package file to create.
- * @param javaProject the java project being compiled
* @param libProjects an optional list of library projects (can be null)
- * @param referencedJavaProjects referenced projects.
* @return true if success, false otherwise.
* @throws ApkCreationException
* @throws AndroidLocationException
@@ -299,8 +296,7 @@ public class BuildHelper {
* @throws DuplicateFileException
*/
public void finalDebugPackage(String intermediateApk, String dex, String output,
- final IJavaProject javaProject, List<IProject> libProjects,
- List<IJavaProject> referencedJavaProjects, ResourceMarker resMarker)
+ List<IProject> libProjects, ResourceMarker resMarker)
throws ApkCreationException, KeytoolException, AndroidLocationException,
NativeLibInJarException, DuplicateFileException, CoreException {
@@ -324,8 +320,7 @@ public class BuildHelper {
// from the keystore, get the signing info
SigningInfo info = ApkBuilder.getDebugKey(keystoreOsPath, mVerbose ? mOutStream : null);
- finalPackage(intermediateApk, dex, output, javaProject, libProjects,
- referencedJavaProjects,
+ finalPackage(intermediateApk, dex, output, libProjects,
info != null ? info.key : null, info != null ? info.certificate : null, resMarker);
}
@@ -341,9 +336,7 @@ public class BuildHelper {
* @param dex The path to the dex file.
* @param output The path to the final package file to create.
* @param debugSign whether the apk must be signed with the debug key.
- * @param javaProject the java project being compiled
* @param libProjects an optional list of library projects (can be null)
- * @param referencedJavaProjects referenced projects.
* @param abiFilter an optional filter. If not null, then only the matching ABI is included in
* the final archive
* @return true if success, false otherwise.
@@ -353,9 +346,8 @@ public class BuildHelper {
* @throws DuplicateFileException
*/
public void finalPackage(String intermediateApk, String dex, String output,
- final IJavaProject javaProject, List<IProject> libProjects,
- List<IJavaProject> referencedJavaProjects, PrivateKey key,
- X509Certificate certificate, ResourceMarker resMarker)
+ List<IProject> libProjects,
+ PrivateKey key, X509Certificate certificate, ResourceMarker resMarker)
throws NativeLibInJarException, ApkCreationException, DuplicateFileException,
CoreException {
@@ -365,19 +357,24 @@ public class BuildHelper {
mVerbose ? mOutStream: null);
apkBuilder.setDebugMode(mDebugMode);
- // Now we write the standard resources from the project and the referenced projects.
- writeStandardResources(apkBuilder, javaProject, referencedJavaProjects);
+ // either use the full compiled code paths or just the proguard file
+ // if present
+ Collection<String> pathsCollection = mCompiledCodePaths;
+ if (mProguardFile != null) {
+ pathsCollection = Collections.singletonList(mProguardFile);
+ mProguardFile = null;
+ }
- // Now we write the standard resources from the external jars
- for (String libraryOsPath : getExternalDependencies(resMarker)) {
- File libFile = new File(libraryOsPath);
- if (libFile.isFile()) {
- JarStatus jarStatus = apkBuilder.addResourcesFromJar(new File(libraryOsPath));
+ // Now we write the standard resources from all the output paths.
+ for (String path : pathsCollection) {
+ File file = new File(path);
+ if (file.isFile()) {
+ JarStatus jarStatus = apkBuilder.addResourcesFromJar(file);
// check if we found native libraries in the external library. This
// constitutes an error or warning depending on if they are in lib/
if (jarStatus.getNativeLibs().size() > 0) {
- String libName = new File(libraryOsPath).getName();
+ String libName = file.getName();
String msg = String.format(
"Native libraries detected in '%1$s'. See console for more information.",
@@ -418,11 +415,11 @@ public class BuildHelper {
}
}
}
- } else if (libFile.isDirectory()) {
+ } else if (file.isDirectory()) {
// this is technically not a source folder (class folder instead) but since we
// only care about Java resources (ie non class/java files) this will do the
// same
- apkBuilder.addSourceFolder(libFile);
+ apkBuilder.addSourceFolder(file);
}
}
@@ -453,66 +450,15 @@ public class BuildHelper {
}
}
- /**
- * Return a list of the project output for compiled Java code.
- * @return
- * @throws CoreException
- */
- public String[] getProjectJavaOutputs() throws CoreException {
- IFolder outputFolder = BaseProjectHelper.getJavaOutputFolder(mProject);
-
- // get the list of referenced projects output to add
- List<IProject> javaProjects = ProjectHelper.getReferencedProjects(mProject);
- List<IJavaProject> referencedJavaProjects = BuildHelper.getJavaProjects(javaProjects);
-
- // get the project output, and since it's a new list object, just add the outputFolder
- // of the project directly to it.
- List<String> projectOutputs = getProjectJavaOutputs(referencedJavaProjects);
-
- projectOutputs.add(0, outputFolder.getLocation().toOSString());
-
- return projectOutputs.toArray(new String[projectOutputs.size()]);
+ public void setProguardOutput(String proguardFile) {
+ mProguardFile = proguardFile;
}
- /**
- * Returns an array for all the compiled code for the project. This can include the
- * code compiled by Eclipse for the main project and dependencies (Java only projects), as well
- * as external jars used by the project or its library.
- *
- * This array of paths is compatible with the input for dx and can be passed as is to
- * {@link #executeDx(IJavaProject, String[], String)}.
- *
- * @param resMarker
- * @return a array (never empty) containing paths to compiled code.
- * @throws CoreException
- */
- public String[] getCompiledCodePaths(boolean includeProjectOutputs, ResourceMarker resMarker)
- throws CoreException {
-
- // get the list of libraries to include with the source code
- String[] libraries = getExternalDependencies(resMarker);
-
- int startIndex = 0;
-
- String[] compiledPaths;
-
- if (includeProjectOutputs) {
- String[] projectOutputs = getProjectJavaOutputs();
-
- compiledPaths = new String[libraries.length + projectOutputs.length];
-
- System.arraycopy(projectOutputs, 0, compiledPaths, 0, projectOutputs.length);
- startIndex = projectOutputs.length;
- } else {
- compiledPaths = new String[libraries.length];
- }
-
- System.arraycopy(libraries, 0, compiledPaths, startIndex, libraries.length);
-
- return compiledPaths;
+ public Collection<String> getCompiledCodePaths() {
+ return mCompiledCodePaths;
}
- public void runProguard(List<File> proguardConfigs, File inputJar, String[] jarFiles,
+ public void runProguard(List<File> proguardConfigs, File inputJar, Collection<String> jarFiles,
File obfuscatedJar, File logOutput)
throws ProguardResultException, ProguardExecException, IOException {
IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
@@ -723,13 +669,14 @@ public class BuildHelper {
/**
* Execute the Dx tool for dalvik code conversion.
* @param javaProject The java project
- * @param inputPath the path to the main input of dex
+ * @param inputPaths the input paths for DX
* @param osOutFilePath the path of the dex file to create.
*
* @throws CoreException
* @throws DexException
*/
- public void executeDx(IJavaProject javaProject, String[] inputPaths, String osOutFilePath)
+ public void executeDx(IJavaProject javaProject, Collection<String> inputPaths,
+ String osOutFilePath)
throws CoreException, DexException {
// get the dex wrapper
@@ -917,153 +864,94 @@ public class BuildHelper {
}
/**
- * Writes the standard resources of a project and its referenced projects
- * into a {@link SignedJarBuilder}.
- * Standard resources are non java/aidl files placed in the java package folders.
- * @param builder the archive builder.
- * @param javaProject the javaProject object.
- * @param referencedJavaProjects the java projects that this project references.
- * @throws ApkCreationException if an error occurred
- * @throws SealedApkException if the APK is already sealed.
- * @throws DuplicateFileException if a file conflicts with another already added to the APK
- * at the same location inside the APK archive.
- * @throws CoreException
- */
- private static void writeStandardResources(IArchiveBuilder builder, IJavaProject javaProject,
- List<IJavaProject> referencedJavaProjects)
- throws DuplicateFileException, ApkCreationException, SealedApkException,
- CoreException {
- IWorkspace ws = ResourcesPlugin.getWorkspace();
- IWorkspaceRoot wsRoot = ws.getRoot();
-
- writeStandardProjectResources(builder, javaProject, wsRoot);
-
- if (referencedJavaProjects != null) {
- for (IJavaProject referencedJavaProject : referencedJavaProjects) {
- // only include output from non android referenced project
- // (This is to handle the case of reference Android projects in the context of
- // instrumentation projects that need to reference the projects to be tested).
- if (referencedJavaProject.getProject().hasNature(
- AdtConstants.NATURE_DEFAULT) == false) {
- writeStandardProjectResources(builder, referencedJavaProject, wsRoot);
- }
- }
- }
- }
-
- /**
- * Writes the standard resources of a {@link IJavaProject} into a {@link SignedJarBuilder}.
- * Standard resources are non java/aidl files placed in the java package folders.
- * @param jarBuilder the {@link ApkBuilder}.
- * @param javaProject the javaProject object.
- * @param wsRoot the {@link IWorkspaceRoot}.
- * @throws ApkCreationException if an error occurred
- * @throws SealedApkException if the APK is already sealed.
- * @throws DuplicateFileException if a file conflicts with another already added to the APK
- * at the same location inside the APK archive.
+ * Computes all the project output and dependencies that must go into building the apk.
+ *
+ * @param resMarker
* @throws CoreException
*/
- private static void writeStandardProjectResources(IArchiveBuilder builder,
- IJavaProject javaProject, IWorkspaceRoot wsRoot)
- throws DuplicateFileException, ApkCreationException, SealedApkException, CoreException {
- // get the source pathes
- List<IPath> sourceFolders = BaseProjectHelper.getSourceClasspaths(javaProject);
-
- // loop on them and then recursively go through the content looking for matching files.
- for (IPath sourcePath : sourceFolders) {
- IResource sourceResource = wsRoot.findMember(sourcePath);
- if (sourceResource != null && sourceResource.getType() == IResource.FOLDER) {
- writeFolderResources(builder, javaProject, (IFolder) sourceResource);
- }
- }
- }
-
- private static void writeFolderResources(IArchiveBuilder builder,
- final IJavaProject javaProject, IFolder root) throws CoreException,
- ApkCreationException, SealedApkException, DuplicateFileException {
- final List<IPath> pathsToPackage = new ArrayList<IPath>();
- root.accept(new IResourceProxyVisitor() {
- @Override
- public boolean visit(IResourceProxy proxy) throws CoreException {
- if (proxy.getType() == IResource.FOLDER) {
- // If this folder isn't wanted, don't traverse into it.
- return ApkBuilder.checkFolderForPackaging(proxy.getName());
- }
- // If it's not a folder, it must be a file. We won't see any other resource type.
- if (!ApkBuilder.checkFileForPackaging(proxy.getName())) {
- return true;
- }
- IResource res = proxy.requestResource();
- if (!javaProject.isOnClasspath(res)) {
- return true;
- }
- // Just record that we need to package this. Packaging here throws
- // inappropriate checked exceptions.
- IPath location = res.getLocation();
- pathsToPackage.add(location);
- return true;
- }
- }, 0);
- IPath rootLocation = root.getLocation();
- for (IPath path : pathsToPackage) {
- IPath archivePath = path.makeRelativeTo(rootLocation);
- builder.addFile(path.toFile(), archivePath.toString());
- }
- }
+ private void gatherPaths(ResourceMarker resMarker)
+ throws CoreException {
+ IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
- /**
- * Returns an array of external dependencies used the project. This can be paths to jar files
- * or to source folders.
- *
- * @param resMarker if non null, used to put Resource marker on problem files.
- * @return an array of OS-specific absolute file paths
- */
- private final String[] getExternalDependencies(ResourceMarker resMarker) {
- // get a java project from it
+ // get a java project for the project.
IJavaProject javaProject = JavaCore.create(mProject);
- IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
- ArrayList<String> oslibraryList = new ArrayList<String>();
+ // get the output of the main project
+ IPath path = javaProject.getOutputLocation();
+ IResource outputResource = wsRoot.findMember(path);
+ if (outputResource != null && outputResource.getType() == IResource.FOLDER) {
+ mCompiledCodePaths.add(outputResource.getLocation().toOSString());
+ }
// we could use IJavaProject.getResolvedClasspath directly, but we actually
// want to see the containers themselves.
IClasspathEntry[] classpaths = javaProject.readRawClasspath();
if (classpaths != null) {
for (IClasspathEntry e : classpaths) {
- // if this is a classpath variable reference, we resolve it.
- if (e.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
- e = JavaCore.getResolvedClasspathEntry(e);
+ // ignore non exported entries, unless it's the LIBRARIES container,
+ // in which case we always want it (there may be some older projects that
+ // have it as non exported).
+ if (e.isExported() ||
+ (e.getEntryKind() == IClasspathEntry.CPE_CONTAINER &&
+ e.getPath().toString().equals(AdtConstants.CONTAINER_LIBRARIES))) {
+ handleCPE(e, javaProject, wsRoot, resMarker);
}
+ }
+ }
+ }
- if (e.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
- handleClasspathEntry(e, wsRoot, oslibraryList, resMarker);
- } else if (e.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
- // get the container
- try {
- IClasspathContainer container = JavaCore.getClasspathContainer(
- e.getPath(), javaProject);
- // ignore the system and default_system types as they represent
- // libraries that are part of the runtime.
- if (container.getKind() == IClasspathContainer.K_APPLICATION) {
- IClasspathEntry[] entries = container.getClasspathEntries();
- for (IClasspathEntry entry : entries) {
- handleClasspathEntry(entry, wsRoot, oslibraryList, resMarker);
- }
- }
- } catch (JavaModelException jme) {
- // can't resolve the container? ignore it.
- AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s", e.getPath());
+ private void handleCPE(IClasspathEntry entry, IJavaProject javaProject,
+ IWorkspaceRoot wsRoot, ResourceMarker resMarker) {
+
+ // if this is a classpath variable reference, we resolve it.
+ if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
+ entry = JavaCore.getResolvedClasspathEntry(entry);
+ }
+
+ if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
+ IProject refProject = wsRoot.getProject(entry.getPath().lastSegment());
+ try {
+ // ignore if it's an Android project, or if it's not a Java Project
+ if (refProject.hasNature(JavaCore.NATURE_ID) &&
+ refProject.hasNature(AdtConstants.NATURE_DEFAULT) == false) {
+ IJavaProject refJavaProject = JavaCore.create(refProject);
+
+ // get the output folder
+ IPath path = refJavaProject.getOutputLocation();
+ IResource outputResource = wsRoot.findMember(path);
+ if (outputResource != null && outputResource.getType() == IResource.FOLDER) {
+ mCompiledCodePaths.add(outputResource.getLocation().toOSString());
}
}
+ } catch (CoreException exception) {
+ // can't query the project nature? ignore
}
- }
- return oslibraryList.toArray(new String[oslibraryList.size()]);
+ } else if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
+ handleClasspathLibrary(entry, wsRoot, resMarker);
+ } else if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
+ // get the container
+ try {
+ IClasspathContainer container = JavaCore.getClasspathContainer(
+ entry.getPath(), javaProject);
+ // ignore the system and default_system types as they represent
+ // libraries that are part of the runtime.
+ if (container.getKind() == IClasspathContainer.K_APPLICATION) {
+ IClasspathEntry[] entries = container.getClasspathEntries();
+ for (IClasspathEntry cpe : entries) {
+ handleCPE(cpe, javaProject, wsRoot, resMarker);
+ }
+ }
+ } catch (JavaModelException jme) {
+ // can't resolve the container? ignore it.
+ AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s", entry.getPath());
+ }
+ }
}
- private void handleClasspathEntry(IClasspathEntry e, IWorkspaceRoot wsRoot,
- ArrayList<String> oslibraryList, ResourceMarker resMarker) {
+ private void handleClasspathLibrary(IClasspathEntry e, IWorkspaceRoot wsRoot,
+ ResourceMarker resMarker) {
// get the IPath
IPath path = e.getPath();
@@ -1077,7 +965,7 @@ public class BuildHelper {
// case of a jar file (which could be relative to the workspace or a full path)
if (resource != null && resource.exists() &&
resource.getType() == IResource.FILE) {
- oslibraryList.add(resource.getLocation().toOSString());
+ mCompiledCodePaths.add(resource.getLocation().toOSString());
} else {
// if the jar path doesn't match a workspace resource,
// then we get an OSString and check if this links to a valid file.
@@ -1085,7 +973,7 @@ public class BuildHelper {
File f = new File(osFullPath);
if (f.isFile()) {
- oslibraryList.add(osFullPath);
+ mCompiledCodePaths.add(osFullPath);
} else {
String message = String.format( Messages.Couldnt_Locate_s_Error,
path);
@@ -1102,7 +990,7 @@ public class BuildHelper {
// this can be the case for a class folder.
if (resource != null && resource.exists() &&
resource.getType() == IResource.FOLDER) {
- oslibraryList.add(resource.getLocation().toOSString());
+ mCompiledCodePaths.add(resource.getLocation().toOSString());
} else {
// if the path doesn't match a workspace resource,
// then we get an OSString and check if this links to a valid folder.
@@ -1110,53 +998,13 @@ public class BuildHelper {
File f = new File(osFullPath);
if (f.isDirectory()) {
- oslibraryList.add(osFullPath);
+ mCompiledCodePaths.add(osFullPath);
}
}
}
}
/**
- * Returns the list of the output folders for the specified {@link IJavaProject} objects, if
- * they are Android projects.
- *
- * @param referencedJavaProjects the java projects.
- * @return a new list object containing the output folder paths.
- * @throws CoreException
- */
- private List<String> getProjectJavaOutputs(List<IJavaProject> referencedJavaProjects)
- throws CoreException {
- ArrayList<String> list = new ArrayList<String>();
-
- IWorkspace ws = ResourcesPlugin.getWorkspace();
- IWorkspaceRoot wsRoot = ws.getRoot();
-
- for (IJavaProject javaProject : referencedJavaProjects) {
- // only include output from non android referenced project
- // (This is to handle the case of reference Android projects in the context of
- // instrumentation projects that need to reference the projects to be tested).
- if (javaProject.getProject().hasNature(AdtConstants.NATURE_DEFAULT) == false) {
- // get the output folder
- IPath path = null;
- try {
- path = javaProject.getOutputLocation();
- } catch (JavaModelException e) {
- continue;
- }
-
- IResource outputResource = wsRoot.findMember(path);
- if (outputResource != null && outputResource.getType() == IResource.FOLDER) {
- String outputOsPath = outputResource.getLocation().toOSString();
-
- list.add(outputOsPath);
- }
- }
- }
-
- return list;
- }
-
- /**
* Checks a {@link IFile} to make sure it should be packaged as standard resources.
* @param file the IFile representing the file.
* @return true if the file should be packaged as standard java resources.
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java
index e03a150..015d230 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/DexWrapper.java
@@ -30,6 +30,7 @@ import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
+import java.util.Collection;
/**
* Wrapper to access dx.jar through reflection.
@@ -144,7 +145,7 @@ public final class DexWrapper {
* @return the integer return code of com.android.dx.command.dexer.Main.run()
* @throws CoreException
*/
- public synchronized int run(String osOutFilePath, String[] osFilenames,
+ public synchronized int run(String osOutFilePath, Collection<String> osFilenames,
boolean verbose, PrintStream outStream, PrintStream errStream) throws CoreException {
assert mRunMethod != null;
@@ -171,7 +172,7 @@ public final class DexWrapper {
// create the Arguments object.
Object args = mArgConstructor.newInstance();
mArgOutName.set(args, osOutFilePath);
- mArgFileNames.set(args, osFilenames);
+ mArgFileNames.set(args, osFilenames.toArray(new String[osFilenames.size()]));
mArgJarOutput.set(args, false);
mArgVerbose.set(args, verbose);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java
index 6c4eca4..8be6863 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PostCompilerBuilder.java
@@ -38,6 +38,7 @@ import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.ide.eclipse.adt.io.IFileWrapper;
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.SdkConstants;
+import com.android.sdklib.build.ApkBuilder;
import com.android.sdklib.build.ApkCreationException;
import com.android.sdklib.build.DuplicateFileException;
import com.android.sdklib.build.IArchiveBuilder;
@@ -68,6 +69,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.jar.Attributes;
@@ -427,7 +429,8 @@ public class PostCompilerBuilder extends BaseBuilder {
BuildHelper helper = new BuildHelper(project,
mOutStream, mErrStream,
true /*debugMode*/,
- AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE);
+ AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE,
+ mResourceMarker);
updateCrunchCache(project, helper);
// refresh recursively bin/res folder
@@ -542,7 +545,8 @@ public class PostCompilerBuilder extends BaseBuilder {
BuildHelper helper = new BuildHelper(project,
mOutStream, mErrStream,
true /*debugMode*/,
- AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE);
+ AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE,
+ mResourceMarker);
// resource to the AndroidManifest.xml file
IFile manifestFile = project.getFile(SdkConstants.FN_ANDROID_MANIFEST_XML);
@@ -637,8 +641,7 @@ public class PostCompilerBuilder extends BaseBuilder {
System.out.println("\trunning dex!");
}
try {
- String[] dxInputPaths = helper.getCompiledCodePaths(
- true /*includeProjectOutputs*/, mResourceMarker);
+ Collection<String> dxInputPaths = helper.getCompiledCodePaths();
helper.executeDx(javaProject, dxInputPaths, classesDexPath);
} catch (DexException e) {
@@ -677,8 +680,7 @@ public class PostCompilerBuilder extends BaseBuilder {
}
helper.finalDebugPackage(
osAndroidBinPath + File.separator + AdtConstants.FN_RESOURCES_AP_,
- classesDexPath, osFinalPackagePath,
- javaProject, libProjects, referencedJavaProjects, mResourceMarker);
+ classesDexPath, osFinalPackagePath, libProjects, mResourceMarker);
} catch (KeytoolException e) {
String eMessage = e.getMessage();
@@ -920,8 +922,8 @@ public class PostCompilerBuilder extends BaseBuilder {
// write the class files
writeClassFilesIntoJar(jarBuilder, javaOutputFolder, javaOutputFolder);
- // now write the standard Java resources
- BuildHelper.writeResources(jarBuilder, JavaCore.create(project));
+ // now write the standard Java resources from the output folder
+ ApkBuilder.addSourceFolder(jarBuilder, javaOutputFolder.getLocation().toFile());
saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX, mConvertToDex);
} catch (Exception e) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java
index 8234f25..7639338 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java
@@ -99,7 +99,7 @@ public class PreCompilerBuilder extends BaseBuilder {
private boolean mMustCreateBuildConfig = false;
private boolean mLastBuildConfigMode;
- private final List<SourceProcessor> mProcessors = new ArrayList<SourceProcessor>();
+ private final List<SourceProcessor> mProcessors = new ArrayList<SourceProcessor>(2);
/** cache of the java package defined in the manifest */
private String mManifestPackage;
@@ -588,7 +588,7 @@ public class PreCompilerBuilder extends BaseBuilder {
Messages.Removing_Generated_Classes);
// remove all the derived resources from the 'gen' source folder.
- if (mGenFolder != null) {
+ if (mGenFolder != null && mGenFolder.exists()) {
// gen folder should not be derived, but previous version could set it to derived
// so we make sure this isn't the case (or it'll get deleted by the clean)
mGenFolder.setDerived(false, monitor);
@@ -634,10 +634,11 @@ public class PreCompilerBuilder extends BaseBuilder {
// load the source processors
SourceProcessor aidlProcessor = new AidlProcessor(javaProject, mGenFolder);
- mProcessors.add(aidlProcessor);
SourceProcessor renderScriptProcessor = new RenderScriptProcessor(javaProject,
mGenFolder);
+ mProcessors.add(aidlProcessor);
mProcessors.add(renderScriptProcessor);
+
} catch (Throwable throwable) {
AdtPlugin.log(throwable, "Failed to finish PrecompilerBuilder#startupOnInitialize()");
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/IconFactory.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/IconFactory.java
index dfdc740..ca13d38 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/IconFactory.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/IconFactory.java
@@ -17,6 +17,7 @@
package com.android.ide.eclipse.adt.internal.editors;
+import com.android.annotations.NonNull;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.sdklib.SdkConstants;
@@ -104,7 +105,7 @@ public class IconFactory {
* Callers should not dispose it.
*
* @param osName The leaf name, without the extension, of an existing icon in the
- * editor's "icons" directory. If it doesn't exists, a default icon will be
+ * editor's "icons" directory. If it doesn't exist, a default icon will be
* generated automatically based on the name.
* @param color The color of the text in the automatically generated icons,
* one of COLOR_DEFAULT, COLOR_RED, COLOR_BLUE or COLOR_RED.
@@ -172,6 +173,60 @@ public class IconFactory {
}
/**
+ * Returns an Image for a given icon name.
+ * <p/>
+ * Callers should not dispose it.
+ *
+ * @param osName The leaf name, without the extension, of an existing icon
+ * in the editor's "icons" directory. If it doesn't exist, the
+ * fallback will be used instead.
+ * @param fallback the fallback icon name to use if the primary icon does
+ * not exist.
+ * @return the icon, which should not be disposed by the caller
+ */
+ public Image getIcon(String osName, String fallback) {
+ String key = osName;
+ Image icon = mIconMap.get(key);
+ if (icon == null && !mIconMap.containsKey(key)) {
+ ImageDescriptor id = getImageDescriptor(osName, fallback);
+ if (id != null) {
+ icon = id.createImage();
+ }
+ // Note that we store null references in the icon map, to avoid looking them
+ // up every time. If it didn't exist once, it will not exist later.
+ mIconMap.put(key, icon);
+ }
+ return icon;
+ }
+
+ /**
+ * Returns an icon of the given name, or if that image does not exist and icon
+ * of the given fallback name.
+ *
+ * @param key the icon name
+ * @param fallbackKey the fallback image to use if the primary key does not exist
+ * @return the image descriptor
+ */
+ @NonNull
+ public ImageDescriptor getImageDescriptor(@NonNull String key, @NonNull String fallbackKey) {
+ ImageDescriptor id = mImageDescMap.get(key);
+ if (id == null && !mImageDescMap.containsKey(key)) {
+ id = AbstractUIPlugin.imageDescriptorFromPlugin(
+ AdtPlugin.PLUGIN_ID,
+ String.format("/icons/%1$s.png", key)); //$NON-NLS-1$
+ if (id == null) {
+ id = getImageDescriptor(fallbackKey);
+ }
+
+ // Place the fallback image for this key as well such that we don't keep trying
+ // to load the failed image
+ mImageDescMap.put(key, id);
+ }
+
+ return id;
+ }
+
+ /**
* Returns the image indicated by the given URL
*
* @param url the url to the image resources
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java
index 5481456..96ce82b 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/common/CommonXmlEditor.java
@@ -136,10 +136,19 @@ public class CommonXmlEditor extends AndroidXmlEditor implements IShowEditorInpu
ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(file);
ResourceFolderType type = resFolder == null ? null : resFolder.getType();
- for (IDelegateCreator creator : DELEGATES) {
- mDelegate = creator.createForFile(this, type);
- if (mDelegate != null) {
- break;
+ if (type == null) {
+ // We lack any real resource information about that file.
+ // Let's take a guess using the actual path.
+ String folderName = AdtUtils.getParentFolderName(editorInput);
+ type = ResourceFolderType.getFolderType(folderName);
+ }
+
+ if (type != null) {
+ for (IDelegateCreator creator : DELEGATES) {
+ mDelegate = creator.createForFile(this, type);
+ if (mDelegate != null) {
+ break;
+ }
}
}
@@ -161,7 +170,7 @@ public class CommonXmlEditor extends AndroidXmlEditor implements IShowEditorInpu
// and IProjects so for now just use a plain XML editor for project-less layout
// files
mDelegate = new OtherXmlEditorDelegate(this);
- } else {
+ } else if (type != null) {
for (IDelegateCreator creator : DELEGATES) {
mDelegate = creator.createForFile(this, type);
if (mDelegate != null) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/DescriptorsUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/DescriptorsUtils.java
index 30c7687..f44faf4 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/DescriptorsUtils.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/DescriptorsUtils.java
@@ -773,7 +773,9 @@ public final class DescriptorsUtils {
|| tag.equals(VIEW_FRAGMENT)
|| tag.equals(VIEW_INCLUDE)
|| tag.equals(VIEW_MERGE)
- || tag.equals(SPACE)) {
+ || tag.equals(SPACE)
+ || tag.endsWith(SPACE) && tag.length() > SPACE.length() &&
+ tag.charAt(tag.length() - SPACE.length()) == '.') {
return false;
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java
index 90e46cf..5abbb0c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java
@@ -319,7 +319,15 @@ public final class CustomViewDescriptorService {
@Override
public Image getGenericIcon() {
- return IconFactory.getInstance().getIcon("customView"); //$NON-NLS-1$
+ IconFactory iconFactory = IconFactory.getInstance();
+
+ int index = mXmlName.lastIndexOf('.');
+ if (index != -1) {
+ return iconFactory.getIcon(mXmlName.substring(index + 1),
+ "customView"); //$NON-NLS-1$
+ }
+
+ return iconFactory.getIcon("customView"); //$NON-NLS-1$
}
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfo.java
index 792194e..dd103c5 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfo.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasViewInfo.java
@@ -17,6 +17,7 @@
package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
import static com.android.ide.common.layout.LayoutConstants.FQCN_SPACE;
+import static com.android.ide.common.layout.LayoutConstants.FQCN_SPACE_V7;
import static com.android.ide.common.layout.LayoutConstants.GESTURE_OVERLAY_VIEW;
import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.VIEW_MERGE;
@@ -457,7 +458,7 @@ public class CanvasViewInfo implements IPropertySource {
return false;
}
- return FQCN_SPACE.equals(mName);
+ return FQCN_SPACE.equals(mName) || FQCN_SPACE_V7.equals(mName);
}
/**
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ClipboardSupport.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ClipboardSupport.java
index b8ab3fd..b5bcf29 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ClipboardSupport.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ClipboardSupport.java
@@ -285,8 +285,9 @@ public class ClipboardSupport {
mCanvas.getEditorDelegate().getEditor().wrapUndoEditXmlModel("Paste", new Runnable() {
@Override
public void run() {
- mCanvas.getRulesEngine().callOnPaste(targetNode, target.getViewObject(), pasted);
- targetNode.applyPendingChanges();
+ RulesEngine engine = mCanvas.getRulesEngine();
+ NodeProxy node = engine.callOnPaste(targetNode, target.getViewObject(), pasted);
+ node.applyPendingChanges();
}
});
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
index 7c8cc81..b43cff9 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
@@ -1658,6 +1658,7 @@ public class GraphicalEditorPart extends EditorPart
for (String clazz : brokenClasses) {
addText(mErrorLabel, "- ");
+ addText(mErrorLabel, clazz);
addText(mErrorLabel, " (");
addActionLink(mErrorLabel,
ActionLinkStyleRange.LINK_OPEN_CLASS, "Open Class", clazz);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java
index 485d574..c5158af 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java
@@ -18,18 +18,23 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI;
import static com.android.ide.common.layout.LayoutConstants.ATTR_CLASS;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_COLUMN_COUNT;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_COLUMN;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_COLUMN_SPAN;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_ROW;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_ROW_SPAN;
import static com.android.ide.common.layout.LayoutConstants.ATTR_ORIENTATION;
+import static com.android.ide.common.layout.LayoutConstants.ATTR_ROW_COUNT;
import static com.android.ide.common.layout.LayoutConstants.ATTR_SRC;
import static com.android.ide.common.layout.LayoutConstants.ATTR_TEXT;
import static com.android.ide.common.layout.LayoutConstants.DRAWABLE_PREFIX;
+import static com.android.ide.common.layout.LayoutConstants.GRID_LAYOUT;
import static com.android.ide.common.layout.LayoutConstants.LAYOUT_PREFIX;
import static com.android.ide.common.layout.LayoutConstants.LINEAR_LAYOUT;
import static com.android.ide.common.layout.LayoutConstants.VALUE_VERTICAL;
import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.VIEW_VIEWTAG;
+import static com.android.tools.lint.detector.api.LintConstants.AUTO_URI;
+import static com.android.tools.lint.detector.api.LintConstants.URI_PREFIX;
import static org.eclipse.jface.viewers.StyledString.QUALIFIER_STYLER;
import com.android.annotations.VisibleForTesting;
@@ -46,10 +51,14 @@ import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDes
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder.Reference;
import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeProxy;
import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
+import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
import com.android.ide.eclipse.adt.internal.editors.ui.ErrorImageComposite;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
+import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.util.Pair;
+import org.eclipse.core.resources.IProject;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IAction;
@@ -58,6 +67,7 @@ import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.preference.JFacePreferences;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IElementComparer;
@@ -66,6 +76,7 @@ import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.StyledCellLabelProvider;
import org.eclipse.jface.viewers.StyledString;
+import org.eclipse.jface.viewers.StyledString.Styler;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
@@ -559,21 +570,59 @@ public class OutlinePage extends ContentOutlinePage
Element e = (Element) xmlNode;
// Temporary diagnostics code when developing GridLayout
- if (GridLayoutRule.sDebugGridLayout && e.getParentNode() != null
- && e.getParentNode().getNodeName() != null) {
- if (e.getParentNode().getNodeName().equals("GridLayout")) { //$NON-NLS-1$
+ if (GridLayoutRule.sDebugGridLayout) {
+ String namespace;
+ if (e.getParentNode().getNodeName().equals(GRID_LAYOUT)) {
+ namespace = ANDROID_URI;
+ } else {
+ IProject project = mGraphicalEditorPart.getProject();
+ ProjectState projectState = Sdk.getProjectState(project);
+ if (projectState != null && projectState.isLibrary()) {
+ namespace = AUTO_URI;
+ } else {
+ ManifestInfo info = ManifestInfo.get(project);
+ namespace = URI_PREFIX + info.getPackage();
+ }
+ }
+
+ if (e.getNodeName() != null && e.getNodeName().endsWith(GRID_LAYOUT)) {
+ // Attach rowCount/columnCount info
+ String rowCount = e.getAttributeNS(namespace, ATTR_ROW_COUNT);
+ if (rowCount.length() == 0) {
+ rowCount = "?";
+ }
+ String columnCount = e.getAttributeNS(namespace, ATTR_COLUMN_COUNT);
+ if (columnCount.length() == 0) {
+ columnCount = "?";
+ }
+
+ styledString.append(" - columnCount=", QUALIFIER_STYLER);
+ styledString.append(columnCount, QUALIFIER_STYLER);
+ styledString.append(", rowCount=", QUALIFIER_STYLER);
+ styledString.append(rowCount, QUALIFIER_STYLER);
+ } else if (e.getParentNode() != null
+ && e.getParentNode().getNodeName() != null
+ && e.getParentNode().getNodeName().endsWith(GRID_LAYOUT)) {
// Attach row/column info
- styledString.append(" - cell (", QUALIFIER_STYLER);
- String row = e.getAttributeNS(ANDROID_URI, ATTR_LAYOUT_ROW);
+ String row = e.getAttributeNS(namespace, ATTR_LAYOUT_ROW);
if (row.length() == 0) {
row = "?";
}
- String column = e.getAttributeNS(ANDROID_URI, ATTR_LAYOUT_COLUMN);
+ Styler colStyle = QUALIFIER_STYLER;
+ String column = e.getAttributeNS(namespace, ATTR_LAYOUT_COLUMN);
if (column.length() == 0) {
column = "?";
+ } else {
+ String colCount = ((Element) e.getParentNode()).getAttributeNS(
+ namespace, ATTR_COLUMN_COUNT);
+ if (colCount.length() > 0 && Integer.parseInt(colCount) <=
+ Integer.parseInt(column)) {
+ colStyle = StyledString.createColorRegistryStyler(
+ JFacePreferences.ERROR_COLOR, null);
+ }
}
- String rowSpan = e.getAttributeNS(ANDROID_URI, ATTR_LAYOUT_ROW_SPAN);
- String columnSpan = e.getAttributeNS(ANDROID_URI,
+ String rowSpan = e.getAttributeNS(namespace, ATTR_LAYOUT_ROW_SPAN);
+ String columnSpan = e.getAttributeNS(namespace,
ATTR_LAYOUT_COLUMN_SPAN);
if (rowSpan.length() == 0) {
rowSpan = "1";
@@ -582,10 +631,13 @@ public class OutlinePage extends ContentOutlinePage
columnSpan = "1";
}
+ styledString.append(" - cell (row=", QUALIFIER_STYLER);
styledString.append(row, QUALIFIER_STYLER);
styledString.append(',', QUALIFIER_STYLER);
- styledString.append(column, QUALIFIER_STYLER);
- styledString.append("), span=(", QUALIFIER_STYLER);
+ styledString.append("col=", colStyle);
+ styledString.append(column, colStyle);
+ styledString.append(')', colStyle);
+ styledString.append(", span=(", QUALIFIER_STYLER);
styledString.append(columnSpan, QUALIFIER_STYLER);
styledString.append(',', QUALIFIER_STYLER);
styledString.append(rowSpan, QUALIFIER_STYLER);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java
index 495600f..e2c573a 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SelectionManager.java
@@ -16,6 +16,7 @@
package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
import static com.android.ide.common.layout.LayoutConstants.FQCN_SPACE;
+import static com.android.ide.common.layout.LayoutConstants.FQCN_SPACE_V7;
import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.SelectionHandle.PIXEL_MARGIN;
import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.SelectionHandle.PIXEL_RADIUS;
@@ -874,7 +875,8 @@ public class SelectionManager implements ISelectionProvider {
// Skip spacers - unless you're dropping just one
continue;
}
- if (GridLayoutRule.sDebugGridLayout && viewInfo.getName().equals(FQCN_SPACE)) {
+ if (GridLayoutRule.sDebugGridLayout && (viewInfo.getName().equals(FQCN_SPACE)
+ || viewInfo.getName().equals(FQCN_SPACE_V7))) {
// In debug mode they might not be marked as hidden but we never never
// want to select these guys
continue;
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 9b186a1..7d21484 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
@@ -18,6 +18,8 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gre;
import static com.android.sdklib.SdkConstants.CLASS_FRAGMENT;
import static com.android.sdklib.SdkConstants.CLASS_V4_FRAGMENT;
+import static com.android.tools.lint.detector.api.LintConstants.AUTO_URI;
+import static com.android.tools.lint.detector.api.LintConstants.URI_PREFIX;
import com.android.ide.common.api.IClientRulesEngine;
import com.android.ide.common.api.INode;
@@ -43,6 +45,7 @@ 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.ProjectState;
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.ReferenceChooserDialog;
@@ -193,7 +196,9 @@ class ClientRulesEngine implements IClientRulesEngine {
Sdk currentSdk = Sdk.getCurrent();
if (currentSdk != null) {
IAndroidTarget target = currentSdk.getTarget(mRulesEngine.getEditor().getProject());
- return target.getVersion().getApiLevel();
+ if (target != null) {
+ return target.getVersion().getApiLevel();
+ }
}
return -1;
@@ -353,6 +358,7 @@ class ClientRulesEngine implements IClientRulesEngine {
// First check to make sure fragments are available, and if not,
// warn the user.
IAndroidTarget target = Sdk.getCurrent().getTarget(project);
+ // No, this should be using the min SDK instead!
if (target.getVersion().getApiLevel() < 11 && oldFragmentType == null) {
// Compatibility library must be present
MessageDialog dialog =
@@ -553,7 +559,14 @@ class ClientRulesEngine implements IClientRulesEngine {
@Override
public String getAppNameSpace() {
- ManifestInfo info = ManifestInfo.get(mRulesEngine.getEditor().getProject());
- return info.getPackage();
+ IProject project = mRulesEngine.getEditor().getProject();
+
+ ProjectState projectState = Sdk.getProjectState(project);
+ if (projectState != null && projectState.isLibrary()) {
+ return AUTO_URI;
+ }
+
+ ManifestInfo info = ManifestInfo.get(project);
+ return URI_PREFIX + info.getPackage();
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java
index a4306fa..ea464c1 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java
@@ -37,6 +37,7 @@ import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElement
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiAttributeNode;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
+import com.android.ide.eclipse.adt.internal.project.CompatibilityLibraryHelper;
import org.eclipse.swt.graphics.Rectangle;
import org.w3c.dom.NamedNodeMap;
@@ -256,6 +257,13 @@ public class NodeProxy implements INode {
private INode insertOrAppend(String viewFqcn, int index) {
checkEditOK();
+ AndroidXmlEditor editor = mNode.getEditor();
+ if (editor != null) {
+ // Possibly replace the tag with a compatibility version if the
+ // minimum SDK requires it
+ viewFqcn = CompatibilityLibraryHelper.getTagFor(editor.getProject(), viewFqcn);
+ }
+
// Find the descriptor for this FQCN
ViewElementDescriptor vd = getFqcnViewDescriptor(viewFqcn);
if (vd == null) {
@@ -277,14 +285,12 @@ public class NodeProxy implements INode {
}
}
+ // Set default attributes -- but only for new widgets (not when moving or copying)
RulesEngine engine = null;
- AndroidXmlEditor editor = mNode.getEditor();
LayoutEditorDelegate delegate = LayoutEditorDelegate.fromEditor(editor);
if (delegate != null) {
engine = delegate.getRulesEngine();
}
-
- // Set default attributes -- but only for new widgets (not when moving or copying)
if (engine == null || engine.getInsertType().isCreate()) {
// TODO: This should probably use IViewRule#getDefaultAttributes() at some point
DescriptorsUtils.setDefaultLayoutAttributes(uiNew, false /*updateLayout*/);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java
index 9c3af1d..a8438d8 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/RulesEngine.java
@@ -368,9 +368,30 @@ public class RulesEngine {
* @param targetNode The first node selected.
* @param targetView The view object for the target node, or null if not known
* @param pastedElements The elements being pasted.
+ * @return the parent node the paste was applied into
*/
- public void callOnPaste(NodeProxy targetNode, Object targetView,
+ public NodeProxy callOnPaste(NodeProxy targetNode, Object targetView,
SimpleElement[] pastedElements) {
+
+ // Find a target which accepts children. If you for example select a button
+ // and attempt to paste, this will reselect the parent of the button as the paste
+ // target. (This is a loop rather than just checking the direct parent since
+ // we will soon ask each child whether they are *willing* to accept the new child.
+ // A ScrollView for example, which only accepts one child, might also say no
+ // and delegate to its parent in turn.
+ INode parent = targetNode;
+ while (parent instanceof NodeProxy) {
+ NodeProxy np = (NodeProxy) parent;
+ if (np.getNode() != null && np.getNode().getDescriptor() != null) {
+ ElementDescriptor descriptor = np.getNode().getDescriptor();
+ if (descriptor.hasChildren()) {
+ targetNode = np;
+ break;
+ }
+ }
+ parent = parent.getParent();
+ }
+
// try to find a rule for this element's FQCN
IViewRule rule = loadRule(targetNode.getNode());
@@ -385,6 +406,8 @@ public class RulesEngine {
e.toString());
}
}
+
+ return targetNode;
}
// ---- Resize operations ----
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/GridLayoutConverter.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/GridLayoutConverter.java
index 912d216..daf1f54 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/GridLayoutConverter.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/GridLayoutConverter.java
@@ -38,6 +38,7 @@ import static com.android.ide.common.layout.LayoutConstants.FQCN_GRID_LAYOUT;
import static com.android.ide.common.layout.LayoutConstants.GRAVITY_VALUE_FILL;
import static com.android.ide.common.layout.LayoutConstants.GRAVITY_VALUE_FILL_HORIZONTAL;
import static com.android.ide.common.layout.LayoutConstants.GRAVITY_VALUE_FILL_VERTICAL;
+import static com.android.ide.common.layout.LayoutConstants.GRID_LAYOUT;
import static com.android.ide.common.layout.LayoutConstants.ID_PREFIX;
import static com.android.ide.common.layout.LayoutConstants.LINEAR_LAYOUT;
import static com.android.ide.common.layout.LayoutConstants.NEW_ID_PREFIX;
@@ -210,20 +211,26 @@ class GridLayoutConverter {
// TODO: May also have to increment column count!
int offset = 0; // WHERE?
+ String gridLayout = mLayout.getTagName();
if (mLayout instanceof IndexedRegion) {
IndexedRegion region = (IndexedRegion) mLayout;
int end = region.getEndOffset();
// TODO: Look backwards for the "</"
// (and can it ever be <foo/>) ?
- end -= (mLayout.getTagName().length() + 3); // 3: <, /, >
+ end -= (gridLayout.length() + 3); // 3: <, /, >
offset = end;
}
int row = rowFixed.size();
int column = columnFixed.size();
StringBuilder sb = new StringBuilder(64);
- String tag = SPACE;
- sb.append('<').append(tag).append(' ');
+ String spaceTag = SPACE;
+ if (!gridLayout.equals(GRID_LAYOUT) && gridLayout.length() > GRID_LAYOUT.length()) {
+ String pkg = gridLayout.substring(0, gridLayout.length() - GRID_LAYOUT.length());
+ spaceTag = pkg + spaceTag;
+ }
+
+ sb.append('<').append(spaceTag).append(' ');
String gravity;
if (!hasStretchableRow && !hasStretchableColumn) {
gravity = GRAVITY_VALUE_FILL;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java
index 0480cda..53b8f49 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java
@@ -56,6 +56,7 @@ import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
@@ -283,6 +284,17 @@ public class UseCompoundDrawableRefactoring extends VisualRefactoring {
setAndroidAttribute(newTextElement, androidNsPrefix, drawableAttribute, src);
+ // If the removed LinearLayout is the root container, transfer its namespace
+ // declaration to the TextView
+ if (layout.getParentNode() instanceof Document) {
+ List<Attr> declarations = findNamespaceAttributes(layout);
+ for (Attr attribute : declarations) {
+ if (attribute instanceof IndexedRegion) {
+ newTextElement.setAttribute(attribute.getName(), attribute.getValue());
+ }
+ }
+ }
+
// Update any layout references to the layout to point to the text view
String layoutId = getId(layout);
if (layoutId.length() > 0) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java
index 4ec3801..f749e2b 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java
@@ -29,6 +29,8 @@ import static com.android.sdklib.xml.AndroidManifest.NODE_ACTIVITY;
import static com.android.sdklib.xml.AndroidManifest.NODE_USES_SDK;
import static org.eclipse.jdt.core.search.IJavaSearchConstants.REFERENCES;
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
@@ -103,6 +105,7 @@ public class ManifestInfo {
private Map<String, String> mActivityThemes;
private IAbstractFile mManifestFile;
private long mLastModified;
+ private int mMinSdk;
private int mTargetSdk;
private String mApplicationIcon;
private String mApplicationLabel;
@@ -130,6 +133,7 @@ public class ManifestInfo {
* @param project the project the finder is associated with
* @return a {@ManifestInfo} for the given project, never null
*/
+ @NonNull
public static ManifestInfo get(IProject project) {
ManifestInfo finder = null;
try {
@@ -174,6 +178,7 @@ public class ManifestInfo {
mActivityThemes = new HashMap<String, String>();
mManifestTheme = null;
mTargetSdk = 1; // Default when not specified
+ mMinSdk = 1; // Default when not specified
mPackage = ""; //$NON-NLS-1$
mApplicationIcon = null;
mApplicationLabel = null;
@@ -227,32 +232,8 @@ public class ManifestInfo {
NodeList usesSdks = root.getElementsByTagName(NODE_USES_SDK);
if (usesSdks.getLength() > 0) {
Element usesSdk = (Element) usesSdks.item(0);
- String targetSdk = null;
- if (usesSdk.hasAttributeNS(NS_RESOURCES, ATTRIBUTE_TARGET_SDK_VERSION)) {
- targetSdk = usesSdk.getAttributeNS(NS_RESOURCES,
- ATTRIBUTE_TARGET_SDK_VERSION);
- } else if (usesSdk.hasAttributeNS(NS_RESOURCES, ATTRIBUTE_MIN_SDK_VERSION)) {
- targetSdk = usesSdk.getAttributeNS(NS_RESOURCES,
- ATTRIBUTE_MIN_SDK_VERSION);
- }
- if (targetSdk != null) {
- int apiLevel = -1;
- try {
- apiLevel = Integer.valueOf(targetSdk);
- } catch (NumberFormatException e) {
- // Handle codename
- if (Sdk.getCurrent() != null) {
- IAndroidTarget target = Sdk.getCurrent().getTargetFromHashString(
- "android-" + targetSdk); //$NON-NLS-1$
- if (target != null) {
- // codename future API level is current api + 1
- apiLevel = target.getVersion().getApiLevel() + 1;
- }
- }
- }
-
- mTargetSdk = apiLevel;
- }
+ mMinSdk = getApiVersion(usesSdk, ATTRIBUTE_MIN_SDK_VERSION, 1);
+ mTargetSdk = getApiVersion(usesSdk, ATTRIBUTE_TARGET_SDK_VERSION, mMinSdk);
}
} else {
mManifestTheme = defaultTheme;
@@ -264,11 +245,40 @@ public class ManifestInfo {
}
}
+ private static int getApiVersion(Element usesSdk, String attribute, int defaultApiLevel) {
+ String valueString = null;
+ if (usesSdk.hasAttributeNS(NS_RESOURCES, attribute)) {
+ valueString = usesSdk.getAttributeNS(NS_RESOURCES, attribute);
+ }
+
+ if (valueString != null) {
+ int apiLevel = -1;
+ try {
+ apiLevel = Integer.valueOf(valueString);
+ } catch (NumberFormatException e) {
+ // Handle codename
+ if (Sdk.getCurrent() != null) {
+ IAndroidTarget target = Sdk.getCurrent().getTargetFromHashString(
+ "android-" + valueString); //$NON-NLS-1$
+ if (target != null) {
+ // codename future API level is current api + 1
+ apiLevel = target.getVersion().getApiLevel() + 1;
+ }
+ }
+ }
+
+ return apiLevel;
+ }
+
+ return defaultApiLevel;
+ }
+
/**
* Returns the default package registered in the Android manifest
*
* @return the default package registered in the manifest
*/
+ @NonNull
public String getPackage() {
sync();
return mPackage;
@@ -280,6 +290,7 @@ public class ManifestInfo {
*
* @return a map from activity fqcn to theme style
*/
+ @NonNull
public Map<String, String> getActivityThemes() {
sync();
return mActivityThemes;
@@ -293,6 +304,7 @@ public class ManifestInfo {
* @param screenSize the screen size to obtain a default theme for, or null if unknown
* @return the theme to use for this project, never null
*/
+ @NonNull
public String getDefaultTheme(IAndroidTarget renderingTarget, ScreenSize screenSize) {
sync();
@@ -320,6 +332,7 @@ public class ManifestInfo {
*
* @return the application icon, or null
*/
+ @Nullable
public String getApplicationIcon() {
sync();
return mApplicationIcon;
@@ -330,16 +343,38 @@ public class ManifestInfo {
*
* @return the application label, or null
*/
+ @Nullable
public String getApplicationLabel() {
sync();
return mApplicationLabel;
}
/**
+ * Returns the target SDK version
+ *
+ * @return the target SDK version
+ */
+ public int getTargetSdkVersion() {
+ sync();
+ return mTargetSdk;
+ }
+
+ /**
+ * Returns the minimum SDK version
+ *
+ * @return the minimum SDK version
+ */
+ public int getMinSdkVersion() {
+ sync();
+ return mMinSdk;
+ }
+
+ /**
* Returns the {@link IPackageFragment} for the package registered in the manifest
*
* @return the {@link IPackageFragment} for the package registered in the manifest
*/
+ @Nullable
public IPackageFragment getPackageFragment() {
sync();
try {
@@ -367,6 +402,7 @@ public class ManifestInfo {
* @param pkg the package containing activities
* @return the activity name
*/
+ @Nullable
public static String guessActivity(IProject project, String layoutName, String pkg) {
final AtomicReference<String> activity = new AtomicReference<String>();
SearchRequestor requestor = new SearchRequestor() {
@@ -446,6 +482,7 @@ public class ManifestInfo {
* @return the activity name
*/
@SuppressWarnings("all")
+ @Nullable
public String guessActivityBySetContentView(String layoutName) {
if (false) {
// These should be fields
@@ -568,7 +605,13 @@ public class ManifestInfo {
return scope;
}
- /** Returns the first package root for the given java project */
+ /**
+ * Returns the first package root for the given java project
+ *
+ * @param javaProject the project to search in
+ * @return the first package root, or null
+ */
+ @Nullable
public static IPackageFragmentRoot getSourcePackageRoot(IJavaProject javaProject) {
IPackageFragmentRoot packageRoot = null;
List<IPath> sources = BaseProjectHelper.getSourceClasspaths(javaProject);
@@ -589,8 +632,10 @@ public class ManifestInfo {
/**
* Computes the minimum SDK and target SDK versions for the project
*
+ * @param project the project to look up the versions for
* @return a pair of (minimum SDK, target SDK) versions, never null
*/
+ @NonNull
public static Pair<Integer, Integer> computeSdkVersions(IProject project) {
int mMinSdkVersion = 1;
int mTargetSdkVersion = 1;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java
index a25d07b..dfe38b0 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/uimodel/UiElementNode.java
@@ -1725,15 +1725,17 @@ public class UiElementNode implements IPropertySource {
/**
* Returns the namespace prefix matching the requested namespace URI.
- * If no such declaration is found, returns the default "android" prefix.
+ * If no such declaration is found, returns the default "android" prefix for
+ * the Android URI, and "app" for other URI's.
*
* @param node The current node. Must not be null.
* @param nsUri The namespace URI of which the prefix is to be found,
* e.g. SdkConstants.NS_RESOURCES
- * @return The first prefix declared or the default "android" prefix.
+ * @return The first prefix declared or the default "android" prefix
+ * (or "app" for non-Android URIs)
*/
public static String lookupNamespacePrefix(Node node, String nsUri) {
- String defaultPrefix = NS_RESOURCES.equals(nsUri) ? ANDROID_NS_NAME : "ns"; //$NON-NLS-1$
+ String defaultPrefix = NS_RESOURCES.equals(nsUri) ? ANDROID_NS_NAME : "app"; //$NON-NLS-1$
return lookupNamespacePrefix(node, nsUri, defaultPrefix);
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/AddSuppressAttribute.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/AddSuppressAttribute.java
index fde228b..1137901 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/AddSuppressAttribute.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/AddSuppressAttribute.java
@@ -28,7 +28,6 @@ import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
import com.android.ide.eclipse.adt.internal.editors.IconFactory;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities;
import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
-import com.android.tools.lint.checks.DuplicateIdDetector;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
@@ -195,21 +194,9 @@ class AddSuppressAttribute implements ICompletionProposal {
return null;
}
- // Some issues cannot find a specific node scope associated with the error
- // (for example because it involves cross-file analysis and at the end of
- // the project scan when the warnings are computed the DOM model is no longer
- // available). Until that's resolved, we need to filter these out such that
- // we don't add misleading annotations on individual elements; the fallback
- // path is the DOM document itself instead.
- if (id.equals(DuplicateIdDetector.CROSS_LAYOUT.getId())) {
- node = document.getDocumentElement();
- }
-
+ node = document.getDocumentElement();
if (node == null) {
- node = document.getDocumentElement();
- if (node == null) {
- return null;
- }
+ return null;
}
String desc = String.format("Add ignore '%1$s\' to element", id);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/CompatibilityLibraryHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/CompatibilityLibraryHelper.java
new file mode 100644
index 0000000..8f6de3a
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/CompatibilityLibraryHelper.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2012 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.project;
+
+import static com.android.ide.common.layout.LayoutConstants.FQCN_GRID_LAYOUT;
+import static com.android.ide.common.layout.LayoutConstants.FQCN_GRID_LAYOUT_V7;
+import static com.android.ide.common.layout.LayoutConstants.FQCN_SPACE;
+import static com.android.ide.common.layout.LayoutConstants.FQCN_SPACE_V7;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.ide.eclipse.adt.AdtUtils;
+import com.android.ide.eclipse.adt.internal.actions.AddCompatibilityJarAction;
+import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
+import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
+import com.android.ide.eclipse.adt.internal.sdk.ProjectState.LibraryState;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Helper class for the Android Support Library. The support library provides
+ * (for example) a backport of GridLayout, which must be used as a library
+ * project rather than a jar library since it has resources. This class provides
+ * support for finding the library project, or downloading and installing it on
+ * demand if it does not, as well as translating tags such as
+ * {@code <GridLayout>} into {@code <com.android.support.v7.GridLayout>} if it
+ * does not.
+ */
+public class CompatibilityLibraryHelper {
+ /**
+ * Returns the correct tag to use for the given view tag. This is normally
+ * the same as the tag itself. However, for some views which are not available
+ * on all platforms, this will:
+ * <ul>
+ * <li> Check if the view is available in the compatibility library,
+ * and if so, if the support library is not installed, will offer to
+ * install it via the SDK manager.
+ * <li> (The tool may also offer to adjust the minimum SDK of the project
+ * up to a level such that the given tag is supported directly, and then
+ * this method will return the original tag.)
+ * <li> Check whether the compatibility library is included in the project, and
+ * if not, offer to copy it into the workspace and add a library dependency.
+ * <li> Return the alternative tag. For example, for "GridLayout", it will
+ * (if the minimum SDK is less than 14) return "com.android.support.v7.GridLayout"
+ * instead.
+ * </ul>
+ *
+ * @param project the project to add the dependency into
+ * @param tag the tag to look up, such as "GridLayout"
+ * @return the tag to use in the layout, normally the same as the input tag but possibly
+ * an equivalent compatibility library tag instead.
+ */
+ @NonNull
+ public static String getTagFor(@NonNull IProject project, @NonNull String tag) {
+ boolean isGridLayout = tag.equals(FQCN_GRID_LAYOUT);
+ boolean isSpace = tag.equals(FQCN_SPACE);
+ if (isGridLayout || isSpace) {
+ int minSdk = ManifestInfo.get(project).getMinSdkVersion();
+ if (minSdk < 14) {
+ // See if the support library is installed in the SDK area
+ // See if there is a local project in the workspace providing the
+ // project
+ IProject supportProject = getSupportProjectV7();
+ if (supportProject != null) {
+ // Make sure I have a dependency on it
+ ProjectState state = Sdk.getProjectState(project);
+ if (state != null) {
+ for (LibraryState library : state.getLibraries()) {
+ if (supportProject.equals(library.getProjectState().getProject())) {
+ // Found it: you have the compatibility library and have linked
+ // to it: use the alternative tag
+ return isGridLayout ? FQCN_GRID_LAYOUT_V7 : FQCN_SPACE_V7;
+ }
+ }
+ }
+ }
+
+ // Ask user to install it
+ String message = String.format(
+ "%1$s requires API level 14 or higher, or a compatibility "
+ + "library for older versions.\n\n"
+ + " Do you want to install the compatibility library?", tag);
+ MessageDialog dialog =
+ new MessageDialog(
+ Display.getCurrent().getActiveShell(),
+ "Warning",
+ null,
+ message,
+ MessageDialog.QUESTION,
+ new String[] {
+ "Install", "Cancel"
+ },
+ 1 /* default button: Cancel */);
+ int answer = dialog.open();
+ if (answer == 0) {
+ if (supportProject != null) {
+ // Just add library dependency
+ if (!AddCompatibilityJarAction.addLibraryDependency(
+ supportProject,
+ project,
+ true /* waitForFinish */)) {
+ return tag;
+ }
+ } else {
+ // Install library AND add dependency
+ if (!AddCompatibilityJarAction.installLibrary(
+ project,
+ true /* waitForFinish */)) {
+ return tag;
+ }
+ }
+
+ return isGridLayout ? FQCN_GRID_LAYOUT_V7 : FQCN_SPACE_V7;
+ }
+ }
+ }
+
+ return tag;
+ }
+
+ /** Cache for {@link #getSupportProjectV7()} */
+ private static IProject sCachedProject;
+
+ /**
+ * Finds and returns the support project in the workspace, if any.
+ *
+ * @return the android support library project, or null if not found
+ */
+ @Nullable
+ public static IProject getSupportProjectV7() {
+ if (sCachedProject != null) {
+ if (sCachedProject.isAccessible()) {
+ return sCachedProject;
+ } else {
+ sCachedProject = null;
+ }
+ }
+
+ sCachedProject = findSupportProjectV7();
+ return sCachedProject;
+ }
+
+ @Nullable
+ private static IProject findSupportProjectV7() {
+ for (IJavaProject javaProject : AdtUtils.getOpenAndroidProjects()) {
+ IProject project = javaProject.getProject();
+ ProjectState state = Sdk.getProjectState(project);
+ if (state.isLibrary()) {
+ ManifestInfo manifestInfo = ManifestInfo.get(project);
+ if (manifestInfo.getPackage().equals("android.support.v7.gridlayout")) { //$NON-NLS-1$
+ return project;
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java
index 93fe43d..86c9b22 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java
@@ -20,7 +20,6 @@ import static com.android.sdklib.internal.project.ProjectProperties.PROPERTY_SDK
import com.android.ide.eclipse.adt.AdtConstants;
import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.AdtUtils;
import com.android.ide.eclipse.adt.AndroidPrintStream;
import com.android.ide.eclipse.adt.internal.build.BuildHelper;
import com.android.ide.eclipse.adt.internal.build.DexException;
@@ -62,6 +61,8 @@ import java.io.OutputStream;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
@@ -122,7 +123,8 @@ public final class ExportHelper {
BuildHelper helper = new BuildHelper(project,
fakeStream, fakeStream,
- debugMode, false /*verbose*/);
+ debugMode, false /*verbose*/,
+ null /*resourceMarker*/);
// get the list of library projects
ProjectState projectState = Sdk.getProjectState(project);
@@ -200,50 +202,51 @@ public final class ExportHelper {
}
}
- String[] dxInput;
+ Collection<String> dxInput;
if (runProguard) {
- // the output of the main project (and any java-only project dependency)
- String[] projectOutputs = helper.getProjectJavaOutputs();
+ // get all the compiled code paths. This will contain both project output
+ // folder and jar files.
+ Collection<String> paths = helper.getCompiledCodePaths();
- // create a jar from the output of these projects
+ // create a jar file containing all the project output (as proguard cannot
+ // process folders of .class files).
File inputJar = File.createTempFile(TEMP_PREFIX, AdtConstants.DOT_JAR);
inputJar.deleteOnExit();
-
JarOutputStream jos = new JarOutputStream(new FileOutputStream(inputJar));
- for (String po : projectOutputs) {
- File root = new File(po);
- if (root.exists()) {
+
+ // a list of the other paths (jar files.)
+ List<String> jars = new ArrayList<String>();
+
+ for (String path : paths) {
+ File root = new File(path);
+ if (root.isDirectory()) {
addFileToJar(jos, root, root);
+ } else if (root.isFile()) {
+ jars.add(path);
}
}
jos.close();
- // get the other jar files
- String[] jarFiles = helper.getCompiledCodePaths(false /*includeProjectOutputs*/,
- null /*resourceMarker*/);
-
// destination file for proguard
File obfuscatedJar = File.createTempFile(TEMP_PREFIX, AdtConstants.DOT_JAR);
obfuscatedJar.deleteOnExit();
// run proguard
- helper.runProguard(proguardConfigFiles, inputJar, jarFiles, obfuscatedJar,
+ helper.runProguard(proguardConfigFiles, inputJar, jars, obfuscatedJar,
new File(project.getLocation().toFile(), SdkConstants.FD_PROGUARD));
+ helper.setProguardOutput(obfuscatedJar.getAbsolutePath());
+
// dx input is proguard's output
- dxInput = new String[] { obfuscatedJar.getAbsolutePath() };
+ dxInput = Collections.singletonList(obfuscatedJar.getAbsolutePath());
} else {
// no proguard, simply get all the compiled code path: project output(s) +
// jar file(s)
- dxInput = helper.getCompiledCodePaths(true /*includeProjectOutputs*/,
- null /*resourceMarker*/);
+ dxInput = helper.getCompiledCodePaths();
}
IJavaProject javaProject = JavaCore.create(project);
- List<IProject> javaProjects = ProjectHelper.getReferencedProjects(project);
- List<IJavaProject> referencedJavaProjects = BuildHelper.getJavaProjects(
- javaProjects);
helper.executeDx(javaProject, dxInput, dexFile.getAbsolutePath());
@@ -253,9 +256,7 @@ public final class ExportHelper {
resourceFile.getAbsolutePath(),
dexFile.getAbsolutePath(),
outputFile.getAbsolutePath(),
- javaProject,
libProjects,
- referencedJavaProjects,
key,
certificate,
null); //resourceMarker
@@ -370,17 +371,12 @@ public final class ExportHelper {
private static void addFileToJar(JarOutputStream jar, File file, File rootDirectory)
throws IOException {
if (file.isDirectory()) {
- for (File child: file.listFiles()) {
- addFileToJar(jar, child, rootDirectory);
+ if (file.getName().equals("META-INF") == false) {
+ for (File child: file.listFiles()) {
+ addFileToJar(jar, child, rootDirectory);
+ }
}
-
} else if (file.isFile()) {
- // check the extension
- String name = file.getName();
- if (!AdtUtils.endsWith(name, AdtConstants.DOT_CLASS)) {
- return;
- }
-
String rootPath = rootDirectory.getAbsolutePath();
String path = file.getAbsolutePath();
path = path.substring(rootPath.length()).replace("\\", "/"); //$NON-NLS-1$ //$NON-NLS-2$
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java
index 65fd9c7..c2f2510 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/LibraryClasspathContainerInitializer.java
@@ -214,17 +214,16 @@ public class LibraryClasspathContainerInitializer extends BaseClasspathContainer
entries.add(entry);
- // now, gather the content of this library project's libs folder.
+ // process all of the library project's dependencies
+ getDependencyListFromClasspath(libProject, refProjects, jarFiles, true);
+ // and the content of its libs folder.
getJarListFromLibsFolder(libProject, jarFiles);
}
-
- // get project dependencies
- processReferencedProjects(libProject, refProjects, jarFiles);
}
- // now process this projects' referenced projects
+ // now process this projects' referenced projects only.
processReferencedProjects(iProject, refProjects, jarFiles);
- // and its own jar files from libs
+ // and the content of its libs folder
getJarListFromLibsFolder(iProject, jarFiles);
// annotations support for older version of android
@@ -288,30 +287,6 @@ public class LibraryClasspathContainerInitializer extends BaseClasspathContainer
IClasspathContainer.K_APPLICATION);
}
-
- private static void processReferencedProjects(IProject project,
- Set<IProject> projects, Set<File> jarFiles) {
- try {
- IProject[] refs = project.getReferencedProjects();
- for (IProject p : refs) {
- // ignore if it's an Android project, or if it's not a Java Project
- if (p.hasNature(JavaCore.NATURE_ID) &&
- p.hasNature(AdtConstants.NATURE_DEFAULT) == false) {
- // add this project to the list
- projects.add(p);
-
- // get the jar dependencies of the project in the list
- getJarListFromClasspath(p, jarFiles);
-
- // and then process the referenced project by this project too.
- processReferencedProjects(p, projects, jarFiles);
- }
- }
- } catch (CoreException e) {
- // can't get the referenced projects? ignore
- }
- }
-
/**
* Finds all the jar files inside a project's libs folder.
* @param project
@@ -335,13 +310,45 @@ public class LibraryClasspathContainerInitializer extends BaseClasspathContainer
}
/**
- * Finds all the jars a given project depends on by looking at the classpath.
- * This must be a non android project, as android project have container that really
- * we shouldn't go through.
+ * Process reference projects from the main projects to add indirect dependencies coming
+ * from Java project.
+ * @param project the main project
+ * @param projects the project list to add to
+ * @param jarFiles the jar list to add to.
+ */
+ private static void processReferencedProjects(IProject project,
+ Set<IProject> projects, Set<File> jarFiles) {
+ try {
+ IProject[] refs = project.getReferencedProjects();
+ for (IProject p : refs) {
+ // ignore if it's an Android project, or if it's not a Java
+ // Project
+ if (p.hasNature(JavaCore.NATURE_ID)
+ && p.hasNature(AdtConstants.NATURE_DEFAULT) == false) {
+
+ // process this project's dependencies
+ getDependencyListFromClasspath(p, projects, jarFiles, true /*includeJarFiles*/);
+ }
+ }
+ } catch (CoreException e) {
+ // can't get the referenced projects? ignore
+ }
+ }
+
+ /**
+ * Finds all the dependencies of a given project and add them to a project list and
+ * a jar list.
+ * Only classpath entries that are exported are added, and only Java project (not Android
+ * project) are added.
+ *
* @param project the project to query
- * @param jarFiles the list of file to fill.
+ * @param projects the referenced project list to add to
+ * @param jarFiles the jar list to add to
+ * @param includeJarFiles whether to include jar files or just projects. This is useful when
+ * calling on an Android project (value should be <code>false</code>)
*/
- private static void getJarListFromClasspath(IProject project, Set<File> jarFiles) {
+ private static void getDependencyListFromClasspath(IProject project, Set<IProject> projects,
+ Set<File> jarFiles, boolean includeJarFiles) {
IJavaProject javaProject = JavaCore.create(project);
IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
@@ -350,38 +357,70 @@ public class LibraryClasspathContainerInitializer extends BaseClasspathContainer
IClasspathEntry[] classpaths = javaProject.readRawClasspath();
if (classpaths != null) {
for (IClasspathEntry e : classpaths) {
- // only consider the classpath entries that are exported.
- if (e.isExported() == false) {
- continue;
- }
- // if this is a classpath variable reference, we resolve it.
- if (e.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
- e = JavaCore.getResolvedClasspathEntry(e);
+ // ignore entries that are not exported
+ if (e.isExported()) {
+ processCPE(e, javaProject, wsRoot, projects, jarFiles, includeJarFiles);
}
+ }
+ }
+ }
- if (e.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
- handleClasspathEntry(e, wsRoot, jarFiles);
- } else if (e.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
- // get the container.
- try {
- IClasspathContainer container = JavaCore.getClasspathContainer(
- e.getPath(), javaProject);
- // ignore the system and default_system types as they represent
- // libraries that are part of the runtime.
- if (container != null &&
- container.getKind() == IClasspathContainer.K_APPLICATION) {
- IClasspathEntry[] entries = container.getClasspathEntries();
- for (IClasspathEntry entry : entries) {
- if (entry.isExported()) {
- handleClasspathEntry(entry, wsRoot, jarFiles);
- }
- }
- }
- } catch (JavaModelException jme) {
- // can't resolve the container? ignore it.
- AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s", e.getPath());
+ /**
+ * Processes a {@link IClasspathEntry} and add it to one of the list if applicable.
+ * @param entry the entry to process
+ * @param javaProject the {@link IJavaProject} from which this entry came.
+ * @param wsRoot the {@link IWorkspaceRoot}
+ * @param projects the project list to add to
+ * @param jarFiles the jar list to add to
+ * @param includeJarFiles whether to include jar files or just projects. This is useful when
+ * calling on an Android project (value should be <code>false</code>)
+ */
+ private static void processCPE(IClasspathEntry entry, IJavaProject javaProject,
+ IWorkspaceRoot wsRoot,
+ Set<IProject> projects, Set<File> jarFiles, boolean includeJarFiles) {
+
+ // if this is a classpath variable reference, we resolve it.
+ if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
+ entry = JavaCore.getResolvedClasspathEntry(entry);
+ }
+
+ if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
+ IProject refProject = wsRoot.getProject(entry.getPath().lastSegment());
+ try {
+ // ignore if it's an Android project, or if it's not a Java Project
+ if (refProject.hasNature(JavaCore.NATURE_ID) &&
+ refProject.hasNature(AdtConstants.NATURE_DEFAULT) == false) {
+ // add this project to the list
+ projects.add(refProject);
+
+ // also get the dependency from this project.
+ getDependencyListFromClasspath(refProject, projects, jarFiles,
+ true /*includeJarFiles*/);
+ }
+ } catch (CoreException exception) {
+ // can't query the project nature? ignore
+ }
+ } else if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
+ if (includeJarFiles) {
+ handleClasspathLibrary(entry, wsRoot, jarFiles);
+ }
+ } else if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
+ // get the container and its content
+ try {
+ IClasspathContainer container = JavaCore.getClasspathContainer(
+ entry.getPath(), javaProject);
+ // ignore the system and default_system types as they represent
+ // libraries that are part of the runtime.
+ if (container != null &&
+ container.getKind() == IClasspathContainer.K_APPLICATION) {
+ IClasspathEntry[] entries = container.getClasspathEntries();
+ for (IClasspathEntry cpe : entries) {
+ processCPE(cpe, javaProject, wsRoot, projects, jarFiles, includeJarFiles);
}
}
+ } catch (JavaModelException jme) {
+ // can't resolve the container? ignore it.
+ AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s", entry.getPath());
}
}
}
@@ -406,7 +445,7 @@ public class LibraryClasspathContainerInitializer extends BaseClasspathContainer
}
}
- private static void handleClasspathEntry(IClasspathEntry e, IWorkspaceRoot wsRoot,
+ private static void handleClasspathLibrary(IClasspathEntry e, IWorkspaceRoot wsRoot,
Set<File> jarFiles) {
// get the IPath
IPath path = e.getPath();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectClassLoader.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectClassLoader.java
index eb0ddf1..e118ff7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectClassLoader.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectClassLoader.java
@@ -17,6 +17,7 @@
package com.android.ide.eclipse.adt.internal.resources.manager;
import com.android.ide.eclipse.adt.AdtConstants;
+import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.build.BuildHelper;
import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
@@ -27,9 +28,11 @@ import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
+import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
import java.io.File;
import java.io.FileInputStream;
@@ -253,8 +256,6 @@ public final class ProjectClassLoader extends ClassLoader {
// get a java project from it
IJavaProject javaProject = JavaCore.create(mJavaProject.getProject());
- IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
-
ArrayList<URL> oslibraryList = new ArrayList<URL>();
IClasspathEntry[] classpaths = javaProject.readRawClasspath();
if (classpaths != null) {
@@ -266,38 +267,30 @@ public final class ProjectClassLoader extends ClassLoader {
e = JavaCore.getResolvedClasspathEntry(e);
}
- // get the IPath
- IPath path = e.getPath();
-
- // check the name ends with .jar
- if (AdtConstants.EXT_JAR.equalsIgnoreCase(path.getFileExtension())) {
- boolean local = false;
- IResource resource = wsRoot.findMember(path);
- if (resource != null && resource.exists() &&
- resource.getType() == IResource.FILE) {
- local = true;
- try {
- oslibraryList.add(new File(resource.getLocation().toOSString())
- .toURI().toURL());
- } catch (MalformedURLException mue) {
- // pass
- }
- }
-
- if (local == false) {
- // if the jar path doesn't match a workspace resource,
- // then we get an OSString and check if this links to a valid file.
- String osFullPath = path.toOSString();
-
- File f = new File(osFullPath);
- if (f.exists()) {
- try {
- oslibraryList.add(f.toURI().toURL());
- } catch (MalformedURLException mue) {
- // pass
+ handleClassPathEntry(e, oslibraryList);
+ } else if (e.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
+ // get the container.
+ try {
+ IClasspathContainer container = JavaCore.getClasspathContainer(
+ e.getPath(), javaProject);
+ // ignore the system and default_system types as they represent
+ // libraries that are part of the runtime.
+ if (container != null &&
+ container.getKind() == IClasspathContainer.K_APPLICATION) {
+ IClasspathEntry[] entries = container.getClasspathEntries();
+ for (IClasspathEntry entry : entries) {
+ // TODO: Xav -- is this necessary?
+ if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) {
+ entry = JavaCore.getResolvedClasspathEntry(entry);
}
+
+ handleClassPathEntry(entry, oslibraryList);
}
}
+ } catch (JavaModelException jme) {
+ // can't resolve the container? ignore it.
+ AdtPlugin.log(jme, "Failed to resolve ClasspathContainer: %s",
+ e.getPath());
}
}
}
@@ -305,4 +298,40 @@ public final class ProjectClassLoader extends ClassLoader {
return oslibraryList.toArray(new URL[oslibraryList.size()]);
}
+
+ private void handleClassPathEntry(IClasspathEntry e, ArrayList<URL> oslibraryList) {
+ // get the IPath
+ IPath path = e.getPath();
+
+ // check the name ends with .jar
+ if (AdtConstants.EXT_JAR.equalsIgnoreCase(path.getFileExtension())) {
+ boolean local = false;
+ IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(path);
+ if (resource != null && resource.exists() &&
+ resource.getType() == IResource.FILE) {
+ local = true;
+ try {
+ oslibraryList.add(new File(resource.getLocation().toOSString())
+ .toURI().toURL());
+ } catch (MalformedURLException mue) {
+ // pass
+ }
+ }
+
+ if (local == false) {
+ // if the jar path doesn't match a workspace resource,
+ // then we get an OSString and check if this links to a valid file.
+ String osFullPath = path.toOSString();
+
+ File f = new File(osFullPath);
+ if (f.exists()) {
+ try {
+ oslibraryList.add(f.toURI().toURL());
+ } catch (MalformedURLException mue) {
+ // pass
+ }
+ }
+ }
+ }
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
index a661334..2a1fba9 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
@@ -352,7 +352,7 @@ public final class Sdk {
/**
* Initializes a new project with a target. This creates the <code>project.properties</code>
* file.
- * @param project the project to intialize
+ * @param project the project to initialize
* @param target the project's target.
* @throws IOException if creating the file failed in any way.
* @throws StreamException
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java
index ff77b9f..d4c342c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/ProjectNamePage.java
@@ -40,6 +40,7 @@ import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.osgi.util.TextProcessor;
import org.eclipse.swt.SWT;
@@ -625,11 +626,11 @@ class ProjectNamePage extends WizardPage implements SelectionListener, ModifyLis
}
@Override
- public boolean canFlipToNextPage() {
+ public IWizardPage getNextPage() {
// Sync working set data to the value object, since the WorkingSetGroup
// doesn't let us add listeners to do this lazily
mValues.workingSets = getWorkingSets();
- return super.canFlipToNextPage();
+ return super.getNextPage();
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileWizard.java
index 4e17125..815848e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileWizard.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileWizard.java
@@ -18,6 +18,9 @@
package com.android.ide.eclipse.adt.internal.wizards.newxmlfile;
+import static com.android.ide.common.layout.LayoutConstants.FQCN_GRID_LAYOUT;
+import static com.android.ide.common.layout.LayoutConstants.GRID_LAYOUT;
+
import com.android.ide.common.resources.configuration.FolderConfiguration;
import com.android.ide.eclipse.adt.AdtConstants;
import com.android.ide.eclipse.adt.AdtPlugin;
@@ -26,7 +29,9 @@ import com.android.ide.eclipse.adt.internal.editors.IconFactory;
import com.android.ide.eclipse.adt.internal.editors.formatting.XmlFormatPreferences;
import com.android.ide.eclipse.adt.internal.editors.formatting.XmlFormatStyle;
import com.android.ide.eclipse.adt.internal.editors.formatting.XmlPrettyPrinter;
+import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
+import com.android.ide.eclipse.adt.internal.project.CompatibilityLibraryHelper;
import com.android.ide.eclipse.adt.internal.wizards.newxmlfile.NewXmlFileCreationPage.TypeInfo;
import com.android.resources.ResourceFolderType;
import com.android.util.Pair;
@@ -201,6 +206,17 @@ public class NewXmlFileWizard extends Wizard implements INewWizard {
StringBuilder sb = new StringBuilder(XML_HEADER_LINE);
+ if (folderType == ResourceFolderType.LAYOUT && root.equals(GRID_LAYOUT)) {
+ IProject project = file.getParent().getProject();
+ int minSdk = ManifestInfo.get(project).getMinSdkVersion();
+ if (minSdk < 14) {
+ root = CompatibilityLibraryHelper.getTagFor(project, FQCN_GRID_LAYOUT);
+ if (root.equals(FQCN_GRID_LAYOUT)) {
+ root = GRID_LAYOUT;
+ }
+ }
+ }
+
sb.append('<').append(root);
if (xmlns != null) {
sb.append('\n').append(" xmlns:android=\"").append(xmlns).append('"'); //$NON-NLS-1$
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoringTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoringTest.java
index 04b9b1a..c1a5ca4 100644
--- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoringTest.java
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoringTest.java
@@ -57,6 +57,11 @@ public class UseCompoundDrawableRefactoringTest extends RefactoringTest {
checkRefactoring("refactoring/usecompound/compound_all.xml", "@+id/layout3");
}
+ public void test7() throws Exception {
+ // Test converting where a namespace needs to be migrated
+ checkRefactoring("refactoring/usecompound/compound5.xml", "@+id/layout");
+ }
+
private void checkRefactoring(String basename, String id) throws Exception {
IFile file = getLayoutFile(getProject(), basename);
TestContext info = setupTestContext(file, basename);
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/refactoring/usecompound/compound5-expected-7.xml b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/refactoring/usecompound/compound5-expected-7.xml
new file mode 100644
index 0000000..e909811
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/refactoring/usecompound/compound5-expected-7.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/TextView1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:drawableBottom="@drawable/ic_launcher"
+ android:text="Hello World" >
+
+</TextView> \ No newline at end of file
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/refactoring/usecompound/compound5.info b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/refactoring/usecompound/compound5.info
new file mode 100644
index 0000000..8eb5c4b
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/refactoring/usecompound/compound5.info
@@ -0,0 +1,3 @@
+android.widget.LinearLayout [0,74,480,800] <LinearLayout>
+ android.widget.TextView [0,0,107,26] <TextView>
+ android.widget.ImageView [0,26,72,98] <ImageView>
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/refactoring/usecompound/compound5.xml b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/refactoring/usecompound/compound5.xml
new file mode 100644
index 0000000..49c0594
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/refactoring/usecompound/compound5.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:id="@+id/layout"
+ android:orientation="vertical" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Hello World" />
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_launcher" />
+
+</LinearLayout>