Merge "SdkMan2: Fix edge case when install/delete packages."
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/AndroidXmlFormattingStrategy.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/AndroidXmlFormattingStrategy.java
index a228fd2..661621d 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/AndroidXmlFormattingStrategy.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/AndroidXmlFormattingStrategy.java
@@ -287,13 +287,20 @@
/**
* Guess what style to use to edit the given document - layout, resource, manifest, ... ? */
private XmlFormatStyle guessStyle(IStructuredModel model, Document domDocument) {
+ // The "layout" style is used for most XML resource file types:
+ // layouts, color-lists and state-lists, animations, drawables, menus, etc
XmlFormatStyle style = XmlFormatStyle.LAYOUT;
+
+ // The "resource" style is used for most value-based XML files:
+ // strings, dimensions, booleans, colors, integers, plurals,
+ // integer-arrays, string-arrays, and typed-arrays
if (domDocument.getDocumentElement() != null
&& ResourcesDescriptors.ROOT_ELEMENT.equals(domDocument.getDocumentElement()
.getTagName())) {
style = XmlFormatStyle.RESOURCE;
}
+ // The "manifest" style is used for manifest files
String baseLocation = model.getBaseLocation();
if (baseLocation != null) {
if (baseLocation.endsWith(SdkConstants.FN_ANDROID_MANIFEST_XML)) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/XmlPrettyPrinter.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/XmlPrettyPrinter.java
index 9b97dde..018d976 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/XmlPrettyPrinter.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/XmlPrettyPrinter.java
@@ -15,6 +15,7 @@
*/
package com.android.ide.eclipse.adt.internal.editors.formatting;
+import static com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor.XMLNS;
import static com.android.ide.eclipse.adt.internal.editors.resources.descriptors.ResourcesDescriptors.COLOR_ELEMENT;
import static com.android.ide.eclipse.adt.internal.editors.resources.descriptors.ResourcesDescriptors.DIMEN_ELEMENT;
import static com.android.ide.eclipse.adt.internal.editors.resources.descriptors.ResourcesDescriptors.ITEM_TAG;
@@ -64,11 +65,15 @@
*
* @param prefs the preferences to format with
* @param style the style to format with
- * @param lineSeparator the line separator to use, such as "\n"
+ * @param lineSeparator the line separator to use, such as "\n" (can be null, in which
+ * case the system default is looked up via the line.separator property)
*/
XmlPrettyPrinter(XmlFormatPreferences prefs, XmlFormatStyle style, String lineSeparator) {
mPrefs = prefs;
mStyle = style;
+ if (lineSeparator == null) {
+ lineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$
+ }
mLineSeparator = lineSeparator;
}
@@ -85,6 +90,13 @@
*/
public void prettyPrint(int rootDepth, Node root, Node startNode, Node endNode,
StringBuilder out) {
+ if (startNode == null) {
+ startNode = root;
+ }
+ if (endNode == null) {
+ endNode = root;
+ }
+
mStartNode = startNode;
mEndNode = endNode;
mOut = out;
@@ -223,10 +235,42 @@
}
private void printComment(int depth, Node node) {
+ String comment = node.getNodeValue();
+ boolean multiLine = comment.indexOf('\n') != -1;
+ String trimmed = comment.trim();
+
+ // See if this is an "end-of-the-line" comment, e.g. it is not a multi-line
+ // comment and it appears on the same line as an opening or closing element tag;
+ // if so, continue to place it as a suffix comment
+ boolean isSuffixComment = false;
+ if (!multiLine) {
+ Node previous = node.getPreviousSibling();
+ isSuffixComment = true;
+ while (previous != null) {
+ short type = previous.getNodeType();
+ if (type == Node.TEXT_NODE || type == Node.COMMENT_NODE) {
+ if (previous.getNodeValue().indexOf('\n') != -1) {
+ isSuffixComment = false;
+ break;
+ }
+ } else {
+ break;
+ }
+ previous = previous.getPreviousSibling();
+ }
+ if (isSuffixComment) {
+ // Remove newline added by element open tag or element close tag
+ if (endsWithLineSeparator()) {
+ removeLastLineSeparator();
+ }
+ mOut.append(' ');
+ }
+ }
+
// Put the comment on a line on its own? Only if it does not follow some other comment
// (e.g. is the first child in an element or follows some other element only separated
// by whitespace)
- if (depth > 0) {
+ if (!mPrefs.removeEmptyLines && depth > 0 && !isSuffixComment) {
Node curr = node.getPreviousSibling();
if (curr == null
|| curr.getNodeType() == Node.ELEMENT_NODE
@@ -239,11 +283,10 @@
}
// TODO: Reformat the comment text?
- String comment = node.getNodeValue();
- boolean multiLine = comment.indexOf('\n') != -1;
- String trimmed = comment.trim();
if (!multiLine && trimmed.length() < 70) {
- indent(depth);
+ if (!isSuffixComment) {
+ indent(depth);
+ }
mOut.append("<!-- "); //$NON-NLS-1$
mOut.append(trimmed);
mOut.append(" -->"); //$NON-NLS-1$
@@ -289,6 +332,45 @@
mOut.append("-->"); //$NON-NLS-1$
mOut.append(mLineSeparator);
}
+
+ // Preserve whitespace after comment: See if the original document had two or
+ // more newlines after the comment, and if so have a blank line between this
+ // comment and the next
+ Node next = node.getNextSibling();
+ if (!mPrefs.removeEmptyLines && next != null && next.getNodeType() == Node.TEXT_NODE) {
+ String text = next.getNodeValue();
+ int newLinesBeforeText = 0;
+ for (int i = 0, n = text.length(); i < n; i++) {
+ char c = text.charAt(i);
+ if (c == '\n') {
+ newLinesBeforeText++;
+ if (newLinesBeforeText == 2) {
+ // Yes
+ mOut.append(mLineSeparator);
+ break;
+ }
+ } else if (!Character.isWhitespace(c)) {
+ break;
+ }
+ }
+ }
+ }
+
+ private boolean endsWithLineSeparator() {
+ int separatorLength = mLineSeparator.length();
+ if (mOut.length() >= separatorLength) {
+ for (int i = 0, j = mOut.length() - separatorLength; i < separatorLength; i++) {
+ if (mOut.charAt(j) != mLineSeparator.charAt(i)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private void removeLastLineSeparator() {
+ mOut.setLength(mOut.length() - mLineSeparator.length());
}
private void printOpenElementTag(int depth, Node node) {
@@ -304,17 +386,6 @@
NamedNodeMap attributes = element.getAttributes();
int attributeCount = attributes.getLength();
if (attributeCount > 0) {
- // Put the single attribute on the same line as the element tag?
- boolean singleLine = mPrefs.oneAttributeOnFirstLine && attributeCount == 1
- // In resource files we always put all the attributes (which is
- // usually just zero, one or two) on the same line
- || mStyle == XmlFormatStyle.RESOURCE;
- if (singleLine) {
- mOut.append(' ');
- } else {
- mOut.append(mLineSeparator);
- }
-
// Sort the attributes
List<Attr> attributeList = new ArrayList<Attr>();
for (int i = 0, n = attributeCount; i < n; i++) {
@@ -323,9 +394,27 @@
Comparator<Attr> comparator = mPrefs.sortAttributes.getAttributeComparator();
Collections.sort(attributeList, comparator);
+ // Put the single attribute on the same line as the element tag?
+ boolean singleLine = mPrefs.oneAttributeOnFirstLine && attributeCount == 1
+ // In resource files we always put all the attributes (which is
+ // usually just zero, one or two) on the same line
+ || mStyle == XmlFormatStyle.RESOURCE;
+
+ // We also place the namespace declaration on the same line as the root element,
+ // but this doesn't also imply singleLine handling; subsequent attributes end up
+ // on their own lines
+ boolean indentNextAttribute;
+ if (singleLine || (depth == 0 && XMLNS.equals(attributeList.get(0).getPrefix()))) {
+ mOut.append(' ');
+ indentNextAttribute = false;
+ } else {
+ mOut.append(mLineSeparator);
+ indentNextAttribute = true;
+ }
+
Attr last = attributeList.get(attributeCount - 1);
for (Attr attribute : attributeList) {
- if (!singleLine) {
+ if (indentNextAttribute) {
indent(depth + 1);
}
mOut.append(attribute.getName());
@@ -337,6 +426,7 @@
// immediately follow the last attribute
if (attribute != last) {
mOut.append(singleLine ? " " : mLineSeparator); //$NON-NLS-1$
+ indentNextAttribute = true;
}
}
}
@@ -345,7 +435,9 @@
// Add a space before the > or /> ? In resource files, only do this when closing the
// element
- if (mPrefs.spaceBeforeClose && (mStyle != XmlFormatStyle.RESOURCE || isClosed)) {
+ if (mPrefs.spaceBeforeClose && (mStyle != XmlFormatStyle.RESOURCE || isClosed)
+ // in <selector> files etc still treat the <item> entries as in resource files
+ && !ITEM_TAG.equals(element.getTagName())) {
mOut.append(' ');
}
@@ -472,7 +564,7 @@
}
private boolean newlineBeforeElementClose(Element element, int depth) {
- return depth == 0;
+ return depth == 0 && !mPrefs.removeEmptyLines;
}
private boolean newlineAfterElementClose(Element element, int depth) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AdtPrefs.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AdtPrefs.java
index 4f1fd5b..435a101 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AdtPrefs.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AdtPrefs.java
@@ -311,7 +311,10 @@
@Override
public void initializeDefaultPreferences() {
IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore();
+ initializeStoreWithDefaults(store);
+ }
+ public void initializeStoreWithDefaults(IPreferenceStore store) {
store.setDefault(PREFS_BUILD_RES_AUTO_REFRESH, true);
store.setDefault(PREFS_BUILD_FORCE_ERROR_ON_NATIVELIB_IN_JAR, true);
store.setDefault(PREFS_BUILD_SKIP_POST_COMPILE_ON_FILE_SAVE, false);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AttributeSortOrder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AttributeSortOrder.java
index 3b11a22..63ed876 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AttributeSortOrder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/AttributeSortOrder.java
@@ -25,6 +25,7 @@
import java.util.Comparator;
/** Order to use when sorting attributes */
+@SuppressWarnings("restriction") // IndexedRegion
public enum AttributeSortOrder {
NO_SORTING("none"), //$NON-NLS-1$
ALPHABETICAL("alpha"), //$NON-NLS-1$
@@ -71,7 +72,6 @@
* Comparator which can be used to "sort" attributes into their existing source order
* (which is not the same as the node map iteration order in the DOM model)
*/
- @SuppressWarnings("restriction")
private static final Comparator<Attr> EXISTING_ORDER_COMPARATOR = new Comparator<Attr>() {
public int compare(Attr attr1, Attr attr2) {
IndexedRegion region1 = (IndexedRegion) attr1;
@@ -82,10 +82,21 @@
};
/**
- * Comparator which can be used to sort attributes into alphabetical order
+ * Comparator which can be used to sort attributes into alphabetical order (but xmlns
+ * is always first)
*/
private static final Comparator<Attr> ALPHABETICAL_COMPARATOR = new Comparator<Attr>() {
public int compare(Attr attr1, Attr attr2) {
+ // Namespace declarations should always go first
+ if (XMLNS.equals(attr1.getPrefix())) {
+ if (XMLNS.equals(attr2.getPrefix())) {
+ return 0;
+ }
+ return -1;
+ } else if (XMLNS.equals(attr2.getPrefix())) {
+ return 1;
+ }
+
return attr1.getLocalName().compareTo(attr2.getLocalName());
}
};
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/formatting/XmlPrettyPrinterTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/formatting/XmlPrettyPrinterTest.java
index ab4cc2f..edccbf0 100644
--- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/formatting/XmlPrettyPrinterTest.java
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/editors/formatting/XmlPrettyPrinterTest.java
@@ -15,7 +15,12 @@
*/
package com.android.ide.eclipse.adt.internal.editors.formatting;
+import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
+
+import org.eclipse.jface.preference.PreferenceStore;
import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@@ -29,8 +34,21 @@
import junit.framework.TestCase;
public class XmlPrettyPrinterTest extends TestCase {
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ PreferenceStore store = new PreferenceStore();
+ AdtPrefs.init(store);
+ AdtPrefs prefs = AdtPrefs.getPrefs();
+ prefs.initializeStoreWithDefaults(store);
+ prefs.loadValues(null);
+ XmlFormatPreferences formatPrefs = XmlFormatPreferences.create();
+ assertTrue(formatPrefs.oneAttributeOnFirstLine);
+ }
+
private void checkFormat(XmlFormatPreferences prefs, XmlFormatStyle style,
- String xml, String expected, String delimiter) throws Exception {
+ String xml, String expected, String delimiter,
+ String startNodeName, String endNodeName) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
InputSource is = new InputSource(new StringReader(xml));
@@ -53,7 +71,16 @@
XmlPrettyPrinter printer = new XmlPrettyPrinter(prefs, style, delimiter);
StringBuilder sb = new StringBuilder(1000);
- printer.prettyPrint(-1, document, document, document, sb);
+ Node startNode = document;
+ Node endNode = document;
+ if (startNodeName != null) {
+ startNode = findNode(document.getDocumentElement(), startNodeName);
+ }
+ if (endNodeName != null) {
+ endNode = findNode(document.getDocumentElement(), endNodeName);
+ }
+
+ printer.prettyPrint(-1, document, startNode, endNode, sb);
String formatted = sb.toString();
if (!expected.equals(formatted)) {
System.out.println(formatted);
@@ -61,6 +88,40 @@
assertEquals(expected, formatted);
}
+ private Node findNode(Node node, String nodeName) {
+ if (node.getNodeName().equals(nodeName)) {
+ return node;
+ }
+
+ NodeList children = node.getChildNodes();
+ for (int i = 0, n = children.getLength(); i < n; i++) {
+ Node child = children.item(i);
+ Node result = findNode(child, nodeName);
+ if (result != null) {
+ return result;
+ }
+ }
+
+ return null;
+ }
+
+ protected int getCaretOffset(String fileContent, String caretLocation) {
+ int caretDelta = caretLocation.indexOf("^"); //$NON-NLS-1$
+ assertTrue(caretLocation, caretDelta != -1);
+
+ String caretContext = caretLocation.substring(0, caretDelta)
+ + caretLocation.substring(caretDelta + 1); // +1: skip "^"
+ int caretContextIndex = fileContent.indexOf(caretContext);
+ assertTrue("Caret content " + caretContext + " not found in file",
+ caretContextIndex != -1);
+ return caretContextIndex + caretDelta;
+ }
+
+ private void checkFormat(XmlFormatPreferences prefs, XmlFormatStyle style,
+ String xml, String expected, String delimiter) throws Exception {
+ checkFormat(prefs, style, xml, expected, delimiter, null, null);
+ }
+
private void checkFormat(XmlFormatPreferences prefs, XmlFormatStyle style,
String xml, String expected) throws Exception {
checkFormat(prefs, style, xml, expected, "\n"); //$NON-NLS-1$
@@ -78,9 +139,9 @@
public void testLayout1() throws Exception {
checkFormat(
"<LinearLayout><Button></Button></LinearLayout>",
- "<LinearLayout>\n" +
+ "<LinearLayout >\n" +
"\n" +
- " <Button>\n" +
+ " <Button >\n" +
" </Button>\n" +
"\n" +
"</LinearLayout>");
@@ -89,10 +150,9 @@
public void testLayout2() throws Exception {
checkFormat(
"<LinearLayout><Button foo=\"bar\"></Button></LinearLayout>",
- "<LinearLayout>\n" +
+ "<LinearLayout >\n" +
"\n" +
- " <Button\n" +
- " foo=\"bar\">\n" +
+ " <Button foo=\"bar\" >\n" +
" </Button>\n" +
"\n" +
"</LinearLayout>");
@@ -104,9 +164,9 @@
checkFormat(
prefs, XmlFormatStyle.LAYOUT,
"<LinearLayout><Button foo=\"bar\"></Button></LinearLayout>",
- "<LinearLayout>\n" +
+ "<LinearLayout >\n" +
"\n" +
- " <Button foo=\"bar\">\n" +
+ " <Button foo=\"bar\" >\n" +
" </Button>\n" +
"\n" +
"</LinearLayout>");
@@ -191,9 +251,8 @@
" SYSTEM \"http://www.xml.com/iso/isolat2-xml.entities\" >\n" +
"]>\n" +
*/
- "<LinearLayout\n" +
- " xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
- " android:orientation=\"vertical\">\n" +
+ "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+ " android:orientation=\"vertical\" >\n" +
" <![CDATA[\n" +
"This is character data!\n" +
"<!-- This is not a comment! -->\n" +
@@ -218,13 +277,158 @@
checkFormat(
XmlFormatPreferences.create(), XmlFormatStyle.LAYOUT,
"<LinearLayout><Button foo=\"bar\"></Button></LinearLayout>",
- "<LinearLayout>\r\n" +
+ "<LinearLayout >\r\n" +
"\r\n" +
- " <Button\r\n" +
- " foo=\"bar\">\r\n" +
+ " <Button foo=\"bar\" >\r\n" +
" </Button>\r\n" +
"\r\n" +
"</LinearLayout>",
"\r\n");
}
+
+ public void testRemoveBlanklines() throws Exception {
+ XmlFormatPreferences prefs = XmlFormatPreferences.create();
+ prefs.removeEmptyLines = true;
+ checkFormat(
+ prefs, XmlFormatStyle.LAYOUT,
+ "<foo><bar><baz1></baz1><baz2></baz2></bar><bar2></bar2><bar3><baz12></baz12></bar3></foo>",
+ "<foo >\n" +
+ " <bar >\n" +
+ " <baz1 >\n" +
+ " </baz1>\n" +
+ " <baz2 >\n" +
+ " </baz2>\n" +
+ " </bar>\n" +
+ " <bar2 >\n" +
+ " </bar2>\n" +
+ " <bar3 >\n" +
+ " <baz12 >\n" +
+ " </baz12>\n" +
+ " </bar3>\n" +
+ "</foo>");
+ }
+
+ public void testRange() throws Exception {
+ checkFormat(
+ XmlFormatPreferences.create(), XmlFormatStyle.LAYOUT,
+ "<LinearLayout><Button foo=\"bar\"></Button><CheckBox/></LinearLayout>",
+ "\n" +
+ " <Button foo=\"bar\" >\n" +
+ " </Button>\n" +
+ "\n" +
+ " <CheckBox >\n" +
+ " </CheckBox>\n",
+ "\n", "Button", "CheckBox");
+ }
+
+ public void testRange2() throws Exception {
+ XmlFormatPreferences prefs = XmlFormatPreferences.create();
+ prefs.removeEmptyLines = true;
+ checkFormat(
+ prefs, XmlFormatStyle.LAYOUT,
+ "<foo><bar><baz1></baz1><baz2></baz2></bar><bar2></bar2><bar3><baz12></baz12></bar3></foo>",
+ " <baz1 >\n" +
+ " </baz1>\n" +
+ " <baz2 >\n" +
+ " </baz2>\n" +
+ " </bar>\n" +
+ " <bar2 >\n" +
+ " </bar2>\n" +
+ " <bar3 >\n" +
+ " <baz12 >\n" +
+ " </baz12>\n",
+ "\n", "baz1", "baz12");
+ }
+
+ public void testEOLcomments() throws Exception {
+ checkFormat(
+ XmlFormatStyle.LAYOUT,
+ "<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n" +
+ " <item android:state_pressed=\"true\"\n" +
+ " android:color=\"#ffff0000\"></item> <!-- pressed -->\n" +
+ " <item android:state_focused=\"true\"\n" +
+ " android:color=\"#ff0000ff\"></item> <!-- focused -->\n" +
+ " <item android:color=\"#ff000000\"></item> <!-- default -->\n" +
+ "</selector>",
+
+ "<selector xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n" +
+ "\n" +
+ " <item\n" +
+ " android:color=\"#ffff0000\"\n" +
+ " android:state_pressed=\"true\"></item> <!-- pressed -->\n" +
+ "\n" +
+ " <item\n" +
+ " android:color=\"#ff0000ff\"\n" +
+ " android:state_focused=\"true\"></item> <!-- focused -->\n" +
+ "\n" +
+ " <item android:color=\"#ff000000\"></item> <!-- default -->\n" +
+ "\n" +
+ "</selector>");
+ }
+
+ public void testPreserveNewlineAfterComment() throws Exception {
+ checkFormat(
+ XmlFormatStyle.RESOURCE,
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
+ "<resources><dimen name=\"colorstrip_height\">6dip</dimen>\n" +
+ " <!-- comment1 --><dimen name=\"title_height\">45dip</dimen>\n" +
+ "\n" +
+ " <!-- comment2: newline above --><dimen name=\"now_playing_height\">90dip</dimen>\n" +
+ " <dimen name=\"text_size_small\">14sp</dimen>\n" +
+ "\n" +
+ "\n" +
+ " <!-- comment3: newline above and below -->\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ " <dimen name=\"text_size_medium\">18sp</dimen><dimen name=\"text_size_large\">22sp</dimen>\n" +
+ "</resources>",
+
+ "<resources>\n" +
+ "\n" +
+ " <dimen name=\"colorstrip_height\">6dip</dimen>\n" +
+ "\n" +
+ " <!-- comment1 -->\n" +
+ " <dimen name=\"title_height\">45dip</dimen>\n" +
+ "\n" +
+ " <!-- comment2: newline above -->\n" +
+ " <dimen name=\"now_playing_height\">90dip</dimen>\n" +
+ " <dimen name=\"text_size_small\">14sp</dimen>\n" +
+ "\n" +
+ " <!-- comment3: newline above and below -->\n" +
+ "\n" +
+ " <dimen name=\"text_size_medium\">18sp</dimen>\n" +
+ " <dimen name=\"text_size_large\">22sp</dimen>\n" +
+ "\n" +
+ "</resources>");
+ }
+
+ public void testPlurals() throws Exception {
+ checkFormat(
+ XmlFormatStyle.RESOURCE,
+ "<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n" +
+ "<string name=\"toast_sync_error\">Sync error: <xliff:g id=\"error\">%1$s</xliff:g></string>\n" +
+ "<string name=\"session_subtitle\"><xliff:g id=\"time\">%1$s</xliff:g> in <xliff:g id=\"room\">%2$s</xliff:g></string>\n" +
+ "<plurals name=\"now_playing_countdown\">\n" +
+ "<item quantity=\"zero\"><xliff:g id=\"remaining_time\">%2$s</xliff:g></item>\n" +
+ "<item quantity=\"one\"><xliff:g id=\"number_of_days\">%1$s</xliff:g> day, <xliff:g id=\"remaining_time\">%2$s</xliff:g></item>\n" +
+ "<item quantity=\"other\"><xliff:g id=\"number_of_days\">%1$s</xliff:g> days, <xliff:g id=\"remaining_time\">%2$s</xliff:g></item>\n" +
+ "</plurals>\n" +
+ "</resources>",
+
+ "<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n" +
+ "\n" +
+ " <string name=\"toast_sync_error\">Sync error: <xliff:g id=\"error\">%1$s</xliff:g></string>\n" +
+ " <string name=\"session_subtitle\"><xliff:g id=\"time\">%1$s</xliff:g> in <xliff:g id=\"room\">%2$s</xliff:g></string>\n" +
+ "\n" +
+ " <plurals name=\"now_playing_countdown\">\n" +
+ " <item quantity=\"zero\"><xliff:g id=\"remaining_time\">%2$s</xliff:g></item>\n" +
+ " <item quantity=\"one\"><xliff:g id=\"number_of_days\">%1$s</xliff:g> day, <xliff:g id=\"remaining_time\">%2$s</xliff:g></item>\n" +
+ " <item quantity=\"other\"><xliff:g id=\"number_of_days\">%1$s</xliff:g> days, <xliff:g id=\"remaining_time\">%2$s</xliff:g></item>\n" +
+ " </plurals>\n" +
+ "\n" +
+ "</resources>");
+ }
+
+
}