diff options
author | Tor Norbye <tnorbye@google.com> | 2012-09-20 17:49:42 -0700 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2012-09-20 17:49:43 -0700 |
commit | a5217f041c1d9596ca2d39b880edb4c266a9edc7 (patch) | |
tree | 2f5d84b06a344339eaa76b0ba56fc9614ddc5d1a | |
parent | 69e16b2fbea467122cea308ac5ad74f27ca94d95 (diff) | |
parent | 454f0e05d3e202320b0cd7bc176360458e88658e (diff) | |
download | sdk-a5217f041c1d9596ca2d39b880edb4c266a9edc7.zip sdk-a5217f041c1d9596ca2d39b880edb4c266a9edc7.tar.gz sdk-a5217f041c1d9596ca2d39b880edb4c266a9edc7.tar.bz2 |
Merge "37497: Templates should escape string literals in resource files"
22 files changed, 471 insertions, 15 deletions
diff --git a/common/src/com/android/utils/XmlUtils.java b/common/src/com/android/utils/XmlUtils.java index 73e1d11..94b7405 100644 --- a/common/src/com/android/utils/XmlUtils.java +++ b/common/src/com/android/utils/XmlUtils.java @@ -182,6 +182,27 @@ public class XmlUtils { } /** + * Converts the given attribute value to an XML-text-safe value, meaning that + * less than and ampersand characters are escaped. + * + * @param textValue the text value to be escaped + * @return the escaped value + */ + @NonNull + public static String toXmlTextValue(@NonNull String textValue) { + for (int i = 0, n = textValue.length(); i < n; i++) { + char c = textValue.charAt(i); + if (c == '<' || c == '&') { + StringBuilder sb = new StringBuilder(2 * textValue.length()); + appendXmlTextValue(sb, textValue); + return sb.toString(); + } + } + + return textValue; + } + + /** * Appends text to the given {@link StringBuilder} and escapes it as required for a * DOM attribute node. * diff --git a/common/tests/src/com/android/utils/XmlUtilsTest.java b/common/tests/src/com/android/utils/XmlUtilsTest.java index 6c28451..ea33346 100644 --- a/common/tests/src/com/android/utils/XmlUtilsTest.java +++ b/common/tests/src/com/android/utils/XmlUtilsTest.java @@ -16,7 +16,6 @@ package com.android.utils; import com.android.SdkConstants; -import com.android.utils.XmlUtils; import org.w3c.dom.Attr; import org.w3c.dom.Document; @@ -79,6 +78,10 @@ public class XmlUtilsTest extends TestCase { assertEquals("<"'>&", sb.toString()); } + public void testToXmlTextValue() throws Exception { + assertEquals("<\"'>&", XmlUtils.toXmlTextValue("<\"'>&")); + } + public void testAppendXmlTextValue() throws Exception { StringBuilder sb = new StringBuilder(); XmlUtils.appendXmlTextValue(sb, "<\"'>&"); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlAttributeMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlAttributeMethod.java new file mode 100644 index 0000000..21f33b8 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlAttributeMethod.java @@ -0,0 +1,40 @@ +/* + * 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.wizards.templates; + +import com.android.utils.XmlUtils; + +import freemarker.template.SimpleScalar; +import freemarker.template.TemplateMethodModel; +import freemarker.template.TemplateModel; +import freemarker.template.TemplateModelException; + +import java.util.List; + +/** + * Method invoked by FreeMarker to escape a string such that it can be used + * as an XML attribute (escaping ', ", & and <). + */ +public class FmEscapeXmlAttributeMethod implements TemplateMethodModel { + @Override + public TemplateModel exec(List args) throws TemplateModelException { + if (args.size() != 1) { + throw new TemplateModelException("Wrong arguments"); + } + String string = args.get(0).toString(); + return new SimpleScalar(XmlUtils.toXmlAttributeValue(string)); + } +}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlStringMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlStringMethod.java new file mode 100644 index 0000000..7e5866e --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlStringMethod.java @@ -0,0 +1,43 @@ +/* + * 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.wizards.templates; + +import com.android.ide.eclipse.adt.internal.refactorings.extractstring.ExtractStringRefactoring; + +import freemarker.template.SimpleScalar; +import freemarker.template.TemplateMethodModel; +import freemarker.template.TemplateModel; +import freemarker.template.TemplateModelException; + +import java.util.List; + +/** + * Method invoked by FreeMarker to escape a string such that it can be placed + * as text in a string resource file. + * This is similar to {@link FmEscapeXmlTextMethod}, but in addition to escaping + * < and & it also escapes characters such as quotes necessary for Android + *{@code <string>} elements. + */ +public class FmEscapeXmlStringMethod implements TemplateMethodModel { + @Override + public TemplateModel exec(List args) throws TemplateModelException { + if (args.size() != 1) { + throw new TemplateModelException("Wrong arguments"); + } + String string = args.get(0).toString(); + return new SimpleScalar(ExtractStringRefactoring.escapeString(string)); + } +}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlTextMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlTextMethod.java new file mode 100644 index 0000000..55a4bc8 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlTextMethod.java @@ -0,0 +1,40 @@ +/* + * 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.wizards.templates; + +import com.android.utils.XmlUtils; + +import freemarker.template.SimpleScalar; +import freemarker.template.TemplateMethodModel; +import freemarker.template.TemplateModel; +import freemarker.template.TemplateModelException; + +import java.util.List; + +/** + * Method invoked by FreeMarker to escape a string such that it can be used + * as XML text (escaping < and &, but not ' and " etc). + */ +public class FmEscapeXmlTextMethod implements TemplateMethodModel { + @Override + public TemplateModel exec(List args) throws TemplateModelException { + if (args.size() != 1) { + throw new TemplateModelException("Wrong arguments"); + } + String string = args.get(0).toString(); + return new SimpleScalar(XmlUtils.toXmlTextValue(string)); + } +}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmExtractLettersMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmExtractLettersMethod.java new file mode 100644 index 0000000..09fa81c --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmExtractLettersMethod.java @@ -0,0 +1,45 @@ +/* + * 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.wizards.templates; + +import freemarker.template.SimpleScalar; +import freemarker.template.TemplateMethodModel; +import freemarker.template.TemplateModel; +import freemarker.template.TemplateModelException; + +import java.util.List; + +/** + * Method invoked by FreeMarker to extract letters from a string; this will remove + * any whitespace, punctuation and digits. + */ +public class FmExtractLettersMethod implements TemplateMethodModel { + @Override + public TemplateModel exec(List args) throws TemplateModelException { + if (args.size() != 1) { + throw new TemplateModelException("Wrong arguments"); + } + String string = args.get(0).toString(); + StringBuilder sb = new StringBuilder(string.length()); + for (int i = 0, n = string.length(); i < n; i++) { + char c = string.charAt(i); + if (Character.isLetter(c)) { + sb.append(c); + } + } + return new SimpleScalar(sb.toString()); + } +}
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java index cb45522..f2c64ae 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java @@ -315,6 +315,10 @@ class TemplateHandler { paramMap.put("activityToLayout", new FmActivityToLayoutMethod()); //$NON-NLS-1$ paramMap.put("layoutToActivity", new FmLayoutToActivityMethod()); //$NON-NLS-1$ paramMap.put("classToResource", new FmClassNameToResourceMethod()); //$NON-NLS-1$ + paramMap.put("escapeXmlAttribute", new FmEscapeXmlStringMethod()); //$NON-NLS-1$ + paramMap.put("escapeXmlText", new FmEscapeXmlStringMethod()); //$NON-NLS-1$ + paramMap.put("escapeXmlString", new FmEscapeXmlStringMethod()); //$NON-NLS-1$ + paramMap.put("extractLetters", new FmExtractLettersMethod()); //$NON-NLS-1$ // This should be handled better: perhaps declared "required packages" as part of the // inputs? (It would be better if we could conditionally disable template based diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlAttributeMethodTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlAttributeMethodTest.java new file mode 100644 index 0000000..eb1e949 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlAttributeMethodTest.java @@ -0,0 +1,50 @@ +/* + * 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.wizards.templates; + +import freemarker.template.SimpleScalar; +import freemarker.template.TemplateModelException; + +import java.util.Collections; +import java.util.List; + +import junit.framework.TestCase; + +@SuppressWarnings("javadoc") +public class FmEscapeXmlAttributeMethodTest extends TestCase { + @SuppressWarnings("rawtypes") + private void check(String s, String expected) throws TemplateModelException { + FmEscapeXmlAttributeMethod method = new FmEscapeXmlAttributeMethod(); + List list = Collections.singletonList(new SimpleScalar(s)); + assertEquals(expected, ((SimpleScalar) method.exec(list)).getAsString()); + } + + public void test1() throws Exception { + check("", ""); + } + + public void test2() throws Exception { + check("foo", "foo"); + } + + public void test3() throws Exception { + check("<\"'>&", "<"'>&"); + } + + public void test4() throws Exception { + check("foo>bar", "foo>bar"); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlStringMethodTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlStringMethodTest.java new file mode 100644 index 0000000..1a4289a --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlStringMethodTest.java @@ -0,0 +1,66 @@ +/* + * 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.wizards.templates; + +import freemarker.template.SimpleScalar; +import freemarker.template.TemplateModelException; + +import java.util.Collections; +import java.util.List; + +import junit.framework.TestCase; + +@SuppressWarnings("javadoc") +public class FmEscapeXmlStringMethodTest extends TestCase { + @SuppressWarnings("rawtypes") + private void check(String s, String expected) throws TemplateModelException { + FmEscapeXmlStringMethod method = new FmEscapeXmlStringMethod(); + List list = Collections.singletonList(new SimpleScalar(s)); + assertEquals(expected, ((SimpleScalar) method.exec(list)).getAsString()); + } + + public void test1() throws Exception { + check("", ""); + } + + public void test2() throws Exception { + check("foo", "foo"); + } + + public void test3() throws Exception { + check(" Foo Bar ", "\" Foo Bar \""); + } + + public void test4() throws Exception { + check("@foo", "\\@foo"); + } + + public void test5() throws Exception { + check("Hello\nWorld", "Hello\\nWorld"); + } + + public void test6() throws Exception { + check("A & B", "A & B"); + } + + public void test7() throws Exception { + check("Foo's Bar", "Foo\\'s Bar"); + } + + public void test8() throws Exception { + check("'\"\\", "\\'\\\"\\\\"); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlTextMethodTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlTextMethodTest.java new file mode 100644 index 0000000..c08b834 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapeXmlTextMethodTest.java @@ -0,0 +1,46 @@ +/* + * 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.wizards.templates; + +import freemarker.template.SimpleScalar; +import freemarker.template.TemplateModelException; + +import java.util.Collections; +import java.util.List; + +import junit.framework.TestCase; + +@SuppressWarnings("javadoc") +public class FmEscapeXmlTextMethodTest extends TestCase { + @SuppressWarnings("rawtypes") + private void check(String s, String expected) throws TemplateModelException { + FmEscapeXmlTextMethod method = new FmEscapeXmlTextMethod(); + List list = Collections.singletonList(new SimpleScalar(s)); + assertEquals(expected, ((SimpleScalar) method.exec(list)).getAsString()); + } + + public void test1() throws Exception { + check("", ""); + } + + public void test2() throws Exception { + check("foo", "foo"); + } + + public void test3() throws Exception { + check("<\"'>&", "<\"'>&"); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/wizards/templates/FmExtractLettersMethodTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/wizards/templates/FmExtractLettersMethodTest.java new file mode 100644 index 0000000..b1d3cee --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/internal/wizards/templates/FmExtractLettersMethodTest.java @@ -0,0 +1,46 @@ +/* + * 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.wizards.templates; + +import freemarker.template.SimpleScalar; +import freemarker.template.TemplateModelException; + +import java.util.Collections; +import java.util.List; + +import junit.framework.TestCase; + +@SuppressWarnings("javadoc") +public class FmExtractLettersMethodTest extends TestCase { + @SuppressWarnings("rawtypes") + private void check(String s, String expected) throws TemplateModelException { + FmExtractLettersMethod method = new FmExtractLettersMethod(); + List list = Collections.singletonList(new SimpleScalar(s)); + assertEquals(expected, ((SimpleScalar) method.exec(list)).getAsString()); + } + + public void test1() throws Exception { + check("", ""); + } + + public void test2() throws Exception { + check("foo", "foo"); + } + + public void test3() throws Exception { + check("<\"'>&foo ", "foo"); + } +} diff --git a/templates/activities/BlankActivity/root/res/values/strings.xml.ftl b/templates/activities/BlankActivity/root/res/values/strings.xml.ftl index 6c636d6..4ba950a 100644 --- a/templates/activities/BlankActivity/root/res/values/strings.xml.ftl +++ b/templates/activities/BlankActivity/root/res/values/strings.xml.ftl @@ -1,6 +1,6 @@ <resources> <#if !isNewProject> - <string name="title_${activityToLayout(activityClass)}">${activityTitle}</string> + <string name="title_${activityToLayout(activityClass)}">${escapeXmlString(activityTitle)}</string> </#if> <string name="menu_settings">Settings</string> diff --git a/templates/activities/FullscreenActivity/root/res/values/strings.xml.ftl b/templates/activities/FullscreenActivity/root/res/values/strings.xml.ftl index 53ff7df..5a43acf 100644 --- a/templates/activities/FullscreenActivity/root/res/values/strings.xml.ftl +++ b/templates/activities/FullscreenActivity/root/res/values/strings.xml.ftl @@ -1,7 +1,7 @@ <resources> <#if !isNewProject> - <string name="title_${simpleName}">${activityTitle}</string> + <string name="title_${simpleName}">${escapeXmlString(activityTitle)}</string> </#if> <string name="dummy_button1">Button 1</string> <string name="dummy_button2">Button 2</string> diff --git a/templates/activities/LoginActivity/root/res/values/strings.xml.ftl b/templates/activities/LoginActivity/root/res/values/strings.xml.ftl index c2ad046..18bf85f 100644 --- a/templates/activities/LoginActivity/root/res/values/strings.xml.ftl +++ b/templates/activities/LoginActivity/root/res/values/strings.xml.ftl @@ -1,6 +1,6 @@ <resources> <#if !isNewProject> - <string name="title_${simpleName}">${activityTitle}</string> + <string name="title_${simpleName}">${escapeXmlString(activityTitle)}</string> </#if> <!-- Strings related to login --> diff --git a/templates/activities/MasterDetailFlow/globals.xml.ftl b/templates/activities/MasterDetailFlow/globals.xml.ftl index 519c081..952e278 100644 --- a/templates/activities/MasterDetailFlow/globals.xml.ftl +++ b/templates/activities/MasterDetailFlow/globals.xml.ftl @@ -1,8 +1,8 @@ <?xml version="1.0"?> <globals> <global id="srcOut" value="src/${slashedPackageName(packageName)}" /> - <global id="CollectionName" value="${objectKind}List" /> - <global id="collection_name" value="${objectKind?lower_case}_list" /> - <global id="DetailName" value="${objectKind}Detail" /> - <global id="detail_name" value="${objectKind?lower_case}_detail" /> + <global id="CollectionName" value="${extractLetters(objectKind)}List" /> + <global id="collection_name" value="${extractLetters(objectKind?lower_case)}_list" /> + <global id="DetailName" value="${extractLetters(objectKind)}Detail" /> + <global id="detail_name" value="${extractLetters(objectKind?lower_case)}_detail" /> </globals> diff --git a/templates/activities/MasterDetailFlow/recipe.xml.ftl b/templates/activities/MasterDetailFlow/recipe.xml.ftl index 2c1f057..8b09c84 100644 --- a/templates/activities/MasterDetailFlow/recipe.xml.ftl +++ b/templates/activities/MasterDetailFlow/recipe.xml.ftl @@ -11,7 +11,7 @@ <instantiate from="res/layout/activity_content_list.xml.ftl" to="res/layout/activity_${collection_name}.xml" /> <instantiate from="res/layout/activity_content_twopane.xml.ftl" - to="res/layout/activity_${objectKind?lower_case}_twopane.xml" /> + to="res/layout/activity_${extractLetters(objectKind?lower_case)}_twopane.xml" /> <instantiate from="res/layout/fragment_content_detail.xml.ftl" to="res/layout/fragment_${detail_name}.xml" /> diff --git a/templates/activities/MasterDetailFlow/root/res/values-large/refs.xml.ftl b/templates/activities/MasterDetailFlow/root/res/values-large/refs.xml.ftl index 3008e2e..97215c3 100644 --- a/templates/activities/MasterDetailFlow/root/res/values-large/refs.xml.ftl +++ b/templates/activities/MasterDetailFlow/root/res/values-large/refs.xml.ftl @@ -6,5 +6,5 @@ For more on layout aliases, see: http://developer.android.com/training/multiscreen/screensizes.html#TaskUseAliasFilters --> - <item type="layout" name="activity_${collection_name}">@layout/activity_${objectKind?lower_case}_twopane</item> + <item type="layout" name="activity_${collection_name}">@layout/activity_${extractLetters(objectKind?lower_case)}_twopane</item> </resources> diff --git a/templates/activities/MasterDetailFlow/root/res/values-sw600dp/refs.xml.ftl b/templates/activities/MasterDetailFlow/root/res/values-sw600dp/refs.xml.ftl index c698e6e..d592404 100644 --- a/templates/activities/MasterDetailFlow/root/res/values-sw600dp/refs.xml.ftl +++ b/templates/activities/MasterDetailFlow/root/res/values-sw600dp/refs.xml.ftl @@ -7,5 +7,5 @@ For more on layout aliases, see: http://developer.android.com/training/multiscreen/screensizes.html#TaskUseAliasFilters --> - <item type="layout" name="activity_${collection_name}">@layout/activity_${objectKind?lower_case}_twopane</item> + <item type="layout" name="activity_${collection_name}">@layout/activity_${extractLetters(objectKind?lower_case)}_twopane</item> </resources> diff --git a/templates/activities/MasterDetailFlow/root/res/values/strings.xml.ftl b/templates/activities/MasterDetailFlow/root/res/values/strings.xml.ftl index 8c555ae..ea882bc 100644 --- a/templates/activities/MasterDetailFlow/root/res/values/strings.xml.ftl +++ b/templates/activities/MasterDetailFlow/root/res/values/strings.xml.ftl @@ -1,6 +1,6 @@ <resources> <#if !isNewProject> - <string name="title_${collection_name}">${objectKindPlural}</string> + <string name="title_${collection_name}">${escapeXmlString(objectKindPlural)}</string> </#if> - <string name="title_${detail_name}">${objectKind} Detail</string> + <string name="title_${detail_name}">${escapeXmlString(objectKind)} Detail</string> </resources> diff --git a/templates/activities/SettingsActivity/root/res/values/strings.xml.ftl b/templates/activities/SettingsActivity/root/res/values/strings.xml.ftl index bf881a3..8dc52ac 100644 --- a/templates/activities/SettingsActivity/root/res/values/strings.xml.ftl +++ b/templates/activities/SettingsActivity/root/res/values/strings.xml.ftl @@ -1,6 +1,6 @@ <resources> <#if !isNewProject> - <string name="title_${simpleName}">${activityTitle}</string> + <string name="title_${simpleName}">${escapeXmlString(activityTitle)}</string> </#if> <!-- Strings related to Settings --> diff --git a/templates/docs/index.html b/templates/docs/index.html index 0916157..f8e89eb 100644 --- a/templates/docs/index.html +++ b/templates/docs/index.html @@ -471,6 +471,58 @@ <h4>See also</h4> <p><a href="#toc_underscoretocamelcase"><code>underscoreToCamelCase</code></a></p> +<h3 data-toctitle="escapeXmlAttribute">string <em>escapeXmlAttribute</em>(string)</h3> + +<p>This function escapes a string, such as <code>Android's</code> such that it can be used as an XML attribute value: <code>Android&apos;s</code>. In particular, it will escape ', ", < and &.</p> + +<h4>Arguments</h4> +<dl> + <dt><code>str</code></dt> + <dd>The string to be escaped.</dd> +</dl> + +<h4>See also</h4> +<p><a href="#toc_escapexmltext"><code>escapeXmlText</code></a></p> +<p><a href="#toc_escapexmlstring"><code>escapeXmlString</code></a></p> + +<h3 data-toctitle="escapeXmlText">string <em>escapeXmlText</em>(string)</h3> + +<p>This function escapes a string, such as <code>A & B's</code> such that it can be used as XML text. This means it will escape < and >, but unlike <a href="#toc_escapexmlattribute"><code>escapeXmlAttribute</code></a> it will <b>not</b> escape ' and ". In the preceeding example, it will escape the string to <code>A &amp; B\s</code>. Note that if you plan to use the XML text as the value for a <string> resource value, you should consider using <a href="#toc_escapexmlstring"><code>escapeXmlString</code></a> instead, since it performs additional escapes necessary for string resources.</p> + +<h4>Arguments</h4> +<dl> + <dt><code>str</code></dt> + <dd>The string to escape to proper XML text.</dd> +</dl> + +<h4>See also</h4> +<p><a href="#toc_escapexmlattribute"><code>escapeXmlAttribute</code></a></p> +<p><a href="#toc_escapexmlstring"><code>escapeXmlString</code></a></p> + +<h3 data-toctitle="escapeXmlString">string <em>escapeXmlString</em>(string)</h3> + +<p>This function escapes a string, such as <code>A & B's</code> such that it is suitable to be inserted in a string resource file as XML text, such as <code>A &amp; B\s</code>. In addition to escaping XML characters like < and &, it also performs additional Android specific escapes, such as escaping apostrophes with a backslash, and so on.</p> + +<h4>Arguments</h4> +<dl> + <dt><code>str</code></dt> + <dd>The string, e.g. <code>Activity's Title</code> to escape to a proper resource XML value.</dd> +</dl> + +<h4>See also</h4> +<p><a href="#toc_escapexmlattribute"><code>escapeXmlAttribute</code></a></p> +<p><a href="#toc_escapexmltext"><code>escapeXmlText</code></a></p> + +<h3 data-toctitle="extractLetters">string <em>extractLetters</em>(string)</h3> + +<p>This function extracts all the letters from a string, effectively removing any punctuation and whitespace characters.</p> + +<h4>Arguments</h4> +<dl> + <dt><code>str</code></dt> + <dd>The string to extract letters from</dd> +</dl> + <h3 data-toctitle="classToResource">string <em>classToResource</em>(string)</h3> <p>This function converts an Android class name, such as <code>FooActivity</code> or <code>FooFragment</code>, to a corresponding resource-friendly identifier string, such as <code>foo</code>, stripping the 'Activity' or 'Fragment' suffix. Currently stripped suffixes are listed below.</p> diff --git a/templates/projects/NewAndroidApplication/root/res/values/strings.xml.ftl b/templates/projects/NewAndroidApplication/root/res/values/strings.xml.ftl index 557e5c2..ee03444 100644 --- a/templates/projects/NewAndroidApplication/root/res/values/strings.xml.ftl +++ b/templates/projects/NewAndroidApplication/root/res/values/strings.xml.ftl @@ -1,3 +1,3 @@ <resources> - <string name="app_name">${appTitle}</string> + <string name="app_name">${escapeXmlString(appTitle)}</string> </resources> |