diff options
author | kkimlabs@chromium.org <kkimlabs@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-04 15:47:16 +0000 |
---|---|---|
committer | kkimlabs@chromium.org <kkimlabs@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-04 15:47:16 +0000 |
commit | 19635dcf8b5675293afffbecfea4b01d171afb99 (patch) | |
tree | 79efd1d8da5b4d02782962974475d9d47b8413f6 /build | |
parent | 94cd609b33ea2eb24e9f26bfdb12a20d25327d8a (diff) | |
download | chromium_src-19635dcf8b5675293afffbecfea4b01d171afb99.zip chromium_src-19635dcf8b5675293afffbecfea4b01d171afb99.tar.gz chromium_src-19635dcf8b5675293afffbecfea4b01d171afb99.tar.bz2 |
[Android] Auto-generate RTL layout xmls from existing layout xmls.
There are several attributes introduced in API 17, mostly for BiDi(RTL) support, e.g., paddingStart.
This build script will generate another set of resource that is API 14 compatible by
converting those API 17 attributes to API 14 attributes, e.g., paddingStart -> paddingLeft.
The goal of this script is for programmers to use those attributes without worrying
about backward-compatibility care and related bugs. About the bugs, please refer to crbug.com/235118 .
BUG=235118
Review URL: https://chromiumcodereview.appspot.com/14476011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@198325 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'build')
-rwxr-xr-x | build/android/gyp/copy_v17_resources.py | 87 | ||||
-rwxr-xr-x | build/android/gyp/generate_v14_resources.py | 177 | ||||
-rw-r--r-- | build/java.gypi | 61 |
3 files changed, 321 insertions, 4 deletions
diff --git a/build/android/gyp/copy_v17_resources.py b/build/android/gyp/copy_v17_resources.py new file mode 100755 index 0000000..81c9aed --- /dev/null +++ b/build/android/gyp/copy_v17_resources.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# +# Copyright 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Copy xml resource files and add -v17 to the sub directory names. + +This is coupled with generate_v14_resources.py. Please refer to +generate_v14_resources.py's comment for why we are doing this. +Or http://crbug.com/235118 . +""" + +import optparse +import os +import shutil +import sys + +from util import build_utils + + +def CopyXmlResourcesInDir(input_dir, output_dir): + """Copy all XML resources from input_dir to output_dir.""" + for input_file in build_utils.FindInDirectory(input_dir, '*.xml'): + output_path = os.path.join(output_dir, + os.path.relpath(input_file, input_dir)) + build_utils.MakeDirectory(os.path.dirname(output_path)) + shutil.copy2(input_file, output_path) + + +def ParseArgs(): + """Parses command line options. + + Returns: + An options object as from optparse.OptionsParser.parse_args() + """ + parser = optparse.OptionParser() + parser.add_option('--res-dir', + help='directory containing resources to be copied') + parser.add_option('--res-v17-dir', + help='output directory to which resources will be copied.') + parser.add_option('--stamp', help='File to touch on success') + + options, args = parser.parse_args() + + if args: + parser.error('No positional arguments should be given.') + + # Check that required options have been provided. + required_options = ('res_dir', 'res_v17_dir') + build_utils.CheckOptions(options, parser, required=required_options) + return options + + +def main(argv): + options = ParseArgs() + + build_utils.DeleteDirectory(options.res_v17_dir) + build_utils.MakeDirectory(options.res_v17_dir) + + for name in os.listdir(options.res_dir): + if not os.path.isdir(os.path.join(options.res_dir, name)): + continue + + dir_pieces = name.split('-') + resource_type = dir_pieces[0] + qualifiers = dir_pieces[1:] + + # We only copy resources under layout*/ and xml*/. + if resource_type not in ('layout', 'xml'): + continue + + # Skip RTL resources because they are not supported by API 14. + if 'ldrtl' in qualifiers: + continue + + # Copy all the resource files. + input_path = os.path.join(options.res_dir, name) + output_path = os.path.join(options.res_v17_dir, name + '-v17') + CopyXmlResourcesInDir(input_path, output_path) + + if options.stamp: + build_utils.Touch(options.stamp) + +if __name__ == '__main__': + sys.exit(main(sys.argv)) + diff --git a/build/android/gyp/generate_v14_resources.py b/build/android/gyp/generate_v14_resources.py new file mode 100755 index 0000000..ce9eebb --- /dev/null +++ b/build/android/gyp/generate_v14_resources.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python +# +# Copyright 2013 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Convert Android xml resources to API 14 compatible. + +There are two reasons that we cannot just use API attributes, +so we are generating another set of resources by this script. + +1. paddingStart attribute can cause a crash on Galaxy Tab 2. +2. There is a bug that paddingStart does not override paddingLeft on + JB-MR1. This is fixed on JB-MR2. + +Therefore, this resource generation script can be removed when +we drop the support for JB-MR1. + +Please refer to http://crbug.com/235118 for the details. +""" + +import optparse +import os +import re +import sys +import xml.dom.minidom as minidom + +from util import build_utils + + +ATTRIBUTE_NAMESPACE = 'http://schemas.android.com/apk/res/android' + +# Almost all the attributes that has "Start" or "End" in +# its name should be mapped. +ATTRIBUTES_TO_MAP = {'paddingStart' : 'paddingLeft', + 'drawableStart' : 'drawableLeft', + 'layout_alignStart' : 'layout_alignLeft', + 'layout_marginStart' : 'layout_marginLeft', + 'layout_alignParentStart' : 'layout_alignParentLeft', + 'layout_toStartOf' : 'layout_toLeftOf', + 'paddingEnd' : 'paddingRight', + 'drawableEnd' : 'drawableRight', + 'layout_alignEnd' : 'layout_alignRight', + 'layout_marginEnd' : 'layout_marginRight', + 'layout_alignParentEnd' : 'layout_alignParentRight', + 'layout_toEndOf' : 'layout_toRightOf'} + +ATTRIBUTES_TO_MAP_NS = {} + +for k, v in ATTRIBUTES_TO_MAP.items(): + ATTRIBUTES_TO_MAP_NS[(ATTRIBUTE_NAMESPACE, k)] = (ATTRIBUTE_NAMESPACE, v) + +ATTRIBUTES_TO_MAP_NS_VALUES = set(ATTRIBUTES_TO_MAP_NS.values()) + + +def IterateXmlElements(node): + """minidom helper function that iterates all the element nodes. + Iteration order is pre-order depth-first.""" + if node.nodeType == node.ELEMENT_NODE: + yield node + for child_node in node.childNodes: + for child_node_element in IterateXmlElements(child_node): + yield child_node_element + + +def GenerateV14Resource(input_filename, output_filename): + """Convert resource to API 14 compatible resource. + + It's mostly a simple replacement, s/Start/Left s/End/Right, + on the attribute names. + """ + dom = minidom.parse(input_filename) + + for element in IterateXmlElements(dom): + all_names = element.attributes.keysNS() + + # Iterate all the attributes to find attributes to convert. + # Note that name variable is actually a tuple that has namespace and name. + # For example, + # name == ('http://schemas.android.com/apk/res/android', 'paddingStart') + for name, value in list(element.attributes.itemsNS()): + # Note: gravity attributes are not necessary to convert because + # start/end values are backward-compatible. Explained at + # https://plus.sandbox.google.com/+RomanNurik/posts/huuJd8iVVXY?e=Showroom + + # Convert any other API 17 Start/End attributes to Left/Right attributes. + # For example, from paddingStart="10dp" to paddingLeft="10dp" + if name in ATTRIBUTES_TO_MAP_NS: + mapped_name = ATTRIBUTES_TO_MAP_NS[name] + + # Add the new mapped attribute and remove the original attribute. + # For example, add paddingLeft and remove paddingStart. + # Note that instead of element.setAttribute(...), this is more correct. + # element.setAttributeNS(mapped_name[0], mapped_name[1], value) + # However, there is a minidom bug that doesn't print namespace set by + # setAttributeNS. Hence this workaround. + # This is a similar bug discussion about minidom namespace normalizing. + # http://stackoverflow.com/questions/863774/how-to-generate-xml-documents-with-namespaces-in-python + element.setAttribute('android:' + mapped_name[1], value) + del element.attributes[name] + elif name in ATTRIBUTES_TO_MAP_NS_VALUES: + # TODO(kkimlabs): Enable warning once layouts have been converted + # print >> sys.stderror, 'Warning: layout should use xxx instead of yyy' + pass + + build_utils.MakeDirectory(os.path.dirname(output_filename)) + with open(output_filename, 'w') as f: + dom.writexml(f, ' ', '\n', encoding='utf-8') + + +def GenerateV14ResourcesInDir(input_dir, output_dir): + """Convert resources to API 14 compatible XML resources in the directory.""" + for input_file in build_utils.FindInDirectory(input_dir, '*.xml'): + output_path = os.path.join(output_dir, + os.path.relpath(input_file, input_dir)) + GenerateV14Resource(input_file, output_path) + + +def ParseArgs(): + """Parses command line options. + + Returns: + An options object as from optparse.OptionsParser.parse_args() + """ + parser = optparse.OptionParser() + parser.add_option('--res-dir', + help='directory containing resources ' + 'used to generate v14 resources') + parser.add_option('--res-v14-dir', + help='output directory into which ' + 'v14 resources will be generated') + parser.add_option('--stamp', help='File to touch on success') + + options, args = parser.parse_args() + + if args: + parser.error('No positional arguments should be given.') + + # Check that required options have been provided. + required_options = ('res_dir', 'res_v14_dir') + build_utils.CheckOptions(options, parser, required=required_options) + return options + + +def main(argv): + options = ParseArgs() + + build_utils.DeleteDirectory(options.res_v14_dir) + build_utils.MakeDirectory(options.res_v14_dir) + + for name in os.listdir(options.res_dir): + if not os.path.isdir(os.path.join(options.res_dir, name)): + continue + + dir_pieces = name.split('-') + resource_type = dir_pieces[0] + qualifiers = dir_pieces[1:] + + # We only convert resources under layout*/ and xml*/. + if resource_type not in ('layout', 'xml'): + continue + + # Android pre-v17 API doesn't support RTL. Skip. + if 'ldrtl' in qualifiers: + continue + + # Convert all the resource files. + input_path = os.path.join(options.res_dir, name) + output_path = os.path.join(options.res_v14_dir, name) + GenerateV14ResourcesInDir(input_path, output_path) + + if options.stamp: + build_utils.Touch(options.stamp) + +if __name__ == '__main__': + sys.exit(main(sys.argv)) + diff --git a/build/java.gypi b/build/java.gypi index fdcbe57..453c671 100644 --- a/build/java.gypi +++ b/build/java.gypi @@ -83,14 +83,21 @@ 'variables': { 'res_dir': '<(java_in_dir)/res', 'res_crunched_dir': '<(intermediate_dir)/res_crunched', + 'res_v14_dir': '<(intermediate_dir)/res_v14', + 'res_v14_stamp': '<(intermediate_dir)/res_v14.stamp', + 'res_v17_dir': '<(intermediate_dir)/res_v17', + 'res_v17_stamp': '<(intermediate_dir)/res_v17.stamp', 'res_input_dirs': ['<(res_dir)', '<@(res_extra_dirs)'], 'resource_input_paths': ['<!@(find <(res_dir) -type f)'], 'R_dir': '<(intermediate_dir)/java_R', 'R_text_file': '<(R_dir)/R.txt', 'R_stamp': '<(intermediate_dir)/resources.stamp', 'generated_src_dirs': ['<(R_dir)'], - 'additional_input_paths': ['<(R_stamp)'], + 'additional_input_paths': ['<(R_stamp)', + '<(res_v14_stamp)', + '<(res_v17_stamp)',], 'additional_res_dirs': [], + 'dependencies_res_input_dirs': [], 'dependencies_res_files': [], }, 'all_dependent_settings': { @@ -99,13 +106,20 @@ # generated_R_dirs and include its resources via # dependencies_res_files. 'generated_R_dirs': ['<(R_dir)'], - 'additional_input_paths': ['<(R_stamp)'], + 'additional_input_paths': ['<(R_stamp)', + '<(res_v14_stamp)', + '<(res_v17_stamp)',], 'dependencies_res_files': ['<@(resource_input_paths)'], + 'dependencies_res_input_dirs': ['<@(res_input_dirs)'], + # Dependent APKs include this target's resources via # additional_res_dirs, additional_res_packages, and # additional_R_text_files. - 'additional_res_dirs': ['<(res_crunched_dir)', '<@(res_input_dirs)'], + 'additional_res_dirs': ['<(res_crunched_dir)', + '<(res_v14_dir)', + '<(res_v17_dir)', + '<@(res_input_dirs)'], 'additional_res_packages': ['<(R_package)'], 'additional_R_text_files': ['<(R_text_file)'], }, @@ -141,7 +155,8 @@ 'android_manifest': '<(DEPTH)/build/android/AndroidManifest.xml', # Include the dependencies' res dirs so that references to # resources in dependencies can be resolved. - 'all_res_dirs': ['<@(res_input_dirs)', '>@(additional_res_dirs)'], + 'all_res_dirs': ['<@(res_input_dirs)', + '>@(dependencies_res_input_dirs)',], }, 'inputs': [ '<(DEPTH)/build/android/gyp/util/build_utils.py', @@ -171,6 +186,44 @@ '--ignore=>!(echo \'>(_inputs)\' | md5sum)', ], }, + # Copy API 17 resources. + { + 'action_name': 'copy_v17_resources_<(_target_name)', + 'message': 'Copying Android API 17 resources <(_target_name)', + 'inputs': [ + '<(DEPTH)/build/android/gyp/util/build_utils.py', + '<(DEPTH)/build/android/gyp/copy_v17_resources.py', + '>@(resource_input_paths)', + ], + 'outputs': [ + '<(res_v17_stamp)', + ], + 'action': [ + 'python', '<(DEPTH)/build/android/gyp/copy_v17_resources.py', + '--res-dir=<(res_dir)', + '--res-v17-dir=<(res_v17_dir)', + '--stamp', '<(res_v17_stamp)', + ] + }, + # Generate API 14 resources. + { + 'action_name': 'generate_api_14_resources_<(_target_name)', + 'message': 'Generating Android API 14 resources <(_target_name)', + 'inputs': [ + '<(DEPTH)/build/android/gyp/util/build_utils.py', + '<(DEPTH)/build/android/gyp/generate_v14_resources.py', + '>@(resource_input_paths)', + ], + 'outputs': [ + '<(res_v14_stamp)', + ], + 'action': [ + 'python', '<(DEPTH)/build/android/gyp/generate_v14_resources.py', + '--res-dir=<(res_dir)', + '--res-v14-dir=<(res_v14_dir)', + '--stamp', '<(res_v14_stamp)', + ] + }, ], }], ], |