Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1218)

Side by Side Diff: build/android/gyp/generate_v14_resources.py

Issue 14969022: [Android] Warning if Left/Right attributes are used in layout and style xmls. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: added missed ".value" again Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # 2 #
3 # Copyright 2013 The Chromium Authors. All rights reserved. 3 # Copyright 2013 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 """Convert Android xml resources to API 14 compatible. 7 """Convert Android xml resources to API 14 compatible.
8 8
9 There are two reasons that we cannot just use API attributes, 9 There are two reasons that we cannot just use API attributes,
10 so we are generating another set of resources by this script. 10 so we are generating another set of resources by this script.
11 11
12 1. paddingStart attribute can cause a crash on Galaxy Tab 2. 12 1. paddingStart attribute can cause a crash on Galaxy Tab 2.
13 2. There is a bug that paddingStart does not override paddingLeft on 13 2. There is a bug that paddingStart does not override paddingLeft on
14 JB-MR1. This is fixed on JB-MR2. 14 JB-MR1. This is fixed on JB-MR2.
15 15
16 Therefore, this resource generation script can be removed when 16 Therefore, this resource generation script can be removed when
17 we drop the support for JB-MR1. 17 we drop the support for JB-MR1.
18 18
19 Please refer to http://crbug.com/235118 for the details. 19 Please refer to http://crbug.com/235118 for the details.
20 """ 20 """
21 21
22 import optparse 22 import optparse
23 import os 23 import os
24 import re 24 import re
25 import sys 25 import sys
26 import xml.dom.minidom as minidom 26 import xml.dom.minidom as minidom
27 27
28 from util import build_utils 28 from util import build_utils
29 29
30 # Note that we are assuming 'android:' is an alias of
31 # the namespace 'http://schemas.android.com/apk/res/android'.
30 32
31 ATTRIBUTE_NAMESPACE = 'http://schemas.android.com/apk/res/android' 33 GRAVITY_ATTRIBUTES = ('android:gravity', 'android:layout_gravity')
32 34
33 # Almost all the attributes that has "Start" or "End" in 35 # Almost all the attributes that has "Start" or "End" in
34 # its name should be mapped. 36 # its name should be mapped.
35 ATTRIBUTES_TO_MAP = {'paddingStart' : 'paddingLeft', 37 ATTRIBUTES_TO_MAP = {'paddingStart' : 'paddingLeft',
36 'drawableStart' : 'drawableLeft', 38 'drawableStart' : 'drawableLeft',
37 'layout_alignStart' : 'layout_alignLeft', 39 'layout_alignStart' : 'layout_alignLeft',
38 'layout_marginStart' : 'layout_marginLeft', 40 'layout_marginStart' : 'layout_marginLeft',
39 'layout_alignParentStart' : 'layout_alignParentLeft', 41 'layout_alignParentStart' : 'layout_alignParentLeft',
40 'layout_toStartOf' : 'layout_toLeftOf', 42 'layout_toStartOf' : 'layout_toLeftOf',
41 'paddingEnd' : 'paddingRight', 43 'paddingEnd' : 'paddingRight',
42 'drawableEnd' : 'drawableRight', 44 'drawableEnd' : 'drawableRight',
43 'layout_alignEnd' : 'layout_alignRight', 45 'layout_alignEnd' : 'layout_alignRight',
44 'layout_marginEnd' : 'layout_marginRight', 46 'layout_marginEnd' : 'layout_marginRight',
45 'layout_alignParentEnd' : 'layout_alignParentRight', 47 'layout_alignParentEnd' : 'layout_alignParentRight',
46 'layout_toEndOf' : 'layout_toRightOf'} 48 'layout_toEndOf' : 'layout_toRightOf'}
47 49
48 ATTRIBUTES_TO_MAP_NS = {} 50 ATTRIBUTES_TO_MAP = dict(['android:' + k, 'android:' + v] for k, v
51 in ATTRIBUTES_TO_MAP.iteritems())
49 52
50 for k, v in ATTRIBUTES_TO_MAP.items(): 53 ATTRIBUTES_TO_MAP_REVERSED = dict([v,k] for k, v
51 ATTRIBUTES_TO_MAP_NS[(ATTRIBUTE_NAMESPACE, k)] = (ATTRIBUTE_NAMESPACE, v) 54 in ATTRIBUTES_TO_MAP.iteritems())
52
53 ATTRIBUTES_TO_MAP_NS_VALUES = set(ATTRIBUTES_TO_MAP_NS.values())
54 55
55 56
56 def IterateXmlElements(node): 57 def IterateXmlElements(node):
57 """minidom helper function that iterates all the element nodes. 58 """minidom helper function that iterates all the element nodes.
58 Iteration order is pre-order depth-first.""" 59 Iteration order is pre-order depth-first."""
59 if node.nodeType == node.ELEMENT_NODE: 60 if node.nodeType == node.ELEMENT_NODE:
60 yield node 61 yield node
61 for child_node in node.childNodes: 62 for child_node in node.childNodes:
62 for child_node_element in IterateXmlElements(child_node): 63 for child_node_element in IterateXmlElements(child_node):
63 yield child_node_element 64 yield child_node_element
64 65
65 66
66 def GenerateV14StyleResource(dom, output_file): 67 def WarnDeprecatedAttribute(name, value, filename):
68 if name in ATTRIBUTES_TO_MAP_REVERSED:
69 print >> sys.stderr, ('warning: ' + filename + ' should use ' +
70 ATTRIBUTES_TO_MAP_REVERSED[name] +
71 ' instead of ' + name)
72 elif name in GRAVITY_ATTRIBUTES and ('left' in value or 'right' in value):
73 print >> sys.stderr, ('warning: ' + filename +
74 ' should use start/end instead of left/right for ' +
75 name)
76
77
78 def GenerateV14StyleResource(input_filename, output_filename):
67 """Convert style resource to API 14 compatible style resource. 79 """Convert style resource to API 14 compatible style resource.
68 80
69 It's mostly a simple replacement, s/Start/Left s/End/Right, 81 It's mostly a simple replacement, s/Start/Left s/End/Right,
70 on the attribute names specified by <item> element. 82 on the attribute names specified by <item> element.
83 If input_filename does not contain style resources, do nothing.
71 """ 84 """
72 for style_element in dom.getElementsByTagName('style'): 85 dom = minidom.parse(input_filename)
86 style_elements = dom.getElementsByTagName('style')
87
88 if not style_elements:
89 return
90
91 for style_element in style_elements:
73 for item_element in style_element.getElementsByTagName('item'): 92 for item_element in style_element.getElementsByTagName('item'):
74 namespace, name = item_element.attributes['name'].value.split(':') 93 name = item_element.attributes['name'].value
75 # Note: namespace == 'android' is not precise because 94 value = item_element.childNodes[0].nodeValue
76 # we are looking for 'http://schemas.android.com/apk/res/android' and 95 if name in ATTRIBUTES_TO_MAP:
77 # 'android' can be aliased to another name in layout xml files where 96 item_element.attributes['name'].value = ATTRIBUTES_TO_MAP[name]
78 # this style is used. e.g. xmlns:android="http://crbug.com/". 97 else:
79 if namespace == 'android' and name in ATTRIBUTES_TO_MAP: 98 WarnDeprecatedAttribute(name, value, input_filename)
80 mapped_name = ATTRIBUTES_TO_MAP[name]
81 item_element.attributes['name'] = namespace + ':' + mapped_name
82 99
83 build_utils.MakeDirectory(os.path.dirname(output_file)) 100 build_utils.MakeDirectory(os.path.dirname(output_filename))
84 with open(output_file, 'w') as f: 101 with open(output_filename, 'w') as f:
85 dom.writexml(f, '', ' ', '\n', encoding='utf-8') 102 dom.writexml(f, '', ' ', '\n', encoding='utf-8')
86 103
87 104
88 def GenerateV14LayoutResource(input_file, output_file): 105 def GenerateV14LayoutResource(input_filename, output_filename):
89 """Convert layout resource to API 14 compatible layout resource. 106 """Convert layout resource to API 14 compatible layout resource.
90 107
91 It's mostly a simple replacement, s/Start/Left s/End/Right, 108 It's mostly a simple replacement, s/Start/Left s/End/Right,
92 on the attribute names. 109 on the attribute names.
93 """ 110 """
94 dom = minidom.parse(input_file) 111 dom = minidom.parse(input_filename)
95 112
113 # Iterate all the elements' attributes to find attributes to convert.
96 for element in IterateXmlElements(dom): 114 for element in IterateXmlElements(dom):
97 all_names = element.attributes.keysNS() 115 for name, value in list(element.attributes.items()):
98 116 # Convert any other API 17 Start/End attributes to Left/Right attributes.
99 # Iterate all the attributes to find attributes to convert. 117 # For example, from paddingStart="10dp" to paddingLeft="10dp"
100 # Note that name variable is actually a tuple that has namespace and name.
101 # For example,
102 # name == ('http://schemas.android.com/apk/res/android', 'paddingStart')
103 for name, value in list(element.attributes.itemsNS()):
104 # Note: gravity attributes are not necessary to convert because 118 # Note: gravity attributes are not necessary to convert because
105 # start/end values are backward-compatible. Explained at 119 # start/end values are backward-compatible. Explained at
106 # https://plus.sandbox.google.com/+RomanNurik/posts/huuJd8iVVXY?e=Showroom 120 # https://plus.sandbox.google.com/+RomanNurik/posts/huuJd8iVVXY?e=Showroom
121 if name in ATTRIBUTES_TO_MAP:
122 element.setAttribute(ATTRIBUTES_TO_MAP[name], value)
123 del element.attributes[name]
124 else:
125 WarnDeprecatedAttribute(name, value, input_filename)
107 126
108 # Convert any other API 17 Start/End attributes to Left/Right attributes. 127 build_utils.MakeDirectory(os.path.dirname(output_filename))
109 # For example, from paddingStart="10dp" to paddingLeft="10dp" 128 with open(output_filename, 'w') as f:
110 if name in ATTRIBUTES_TO_MAP_NS:
111 mapped_name = ATTRIBUTES_TO_MAP_NS[name]
112
113 # Add the new mapped attribute and remove the original attribute.
114 # For example, add paddingLeft and remove paddingStart.
115 # Note that instead of element.setAttribute(...), this is more correct.
116 # element.setAttributeNS(mapped_name[0], mapped_name[1], value)
117 # However, there is a minidom bug that doesn't print namespace set by
118 # setAttributeNS. Hence this workaround.
119 # This is a similar bug discussion about minidom namespace normalizing.
120 # http://stackoverflow.com/questions/863774/how-to-generate-xml-document s-with-namespaces-in-python
121 element.setAttribute('android:' + mapped_name[1], value)
122 del element.attributes[name]
123 elif name in ATTRIBUTES_TO_MAP_NS_VALUES:
124 # TODO(kkimlabs): Enable warning once layouts have been converted
125 # print >> sys.stderror, 'Warning: layout should use xxx instead of yyy'
126 pass
127
128 build_utils.MakeDirectory(os.path.dirname(output_file))
129 with open(output_file, 'w') as f:
130 dom.writexml(f, '', ' ', '\n', encoding='utf-8') 129 dom.writexml(f, '', ' ', '\n', encoding='utf-8')
131 130
132 131
133 def GenerateV14XmlResourcesInDir(input_dir, output_dir, only_styles=False): 132 def GenerateV14XmlResourcesInDir(input_dir, output_dir, only_styles=False):
134 """Convert resources to API 14 compatible XML resources in the directory.""" 133 """Convert resources to API 14 compatible XML resources in the directory."""
135 for input_file in build_utils.FindInDirectory(input_dir, '*.xml'): 134 for input_filename in build_utils.FindInDirectory(input_dir, '*.xml'):
136 output_file = os.path.join(output_dir, 135 output_filename = os.path.join(output_dir,
137 os.path.relpath(input_file, input_dir)) 136 os.path.relpath(input_filename, input_dir))
138 if only_styles: 137 if only_styles:
139 dom = minidom.parse(input_file) 138 GenerateV14StyleResource(input_filename, output_filename)
140 if not dom.getElementsByTagName('style'):
141 continue
142 GenerateV14StyleResource(dom, output_file)
143 else: 139 else:
144 GenerateV14LayoutResource(input_file, output_file) 140 GenerateV14LayoutResource(input_filename, output_filename)
145 141
146 142
147 def ParseArgs(): 143 def ParseArgs():
148 """Parses command line options. 144 """Parses command line options.
149 145
150 Returns: 146 Returns:
151 An options object as from optparse.OptionsParser.parse_args() 147 An options object as from optparse.OptionsParser.parse_args()
152 """ 148 """
153 parser = optparse.OptionParser() 149 parser = optparse.OptionParser()
154 parser.add_option('--res-dir', 150 parser.add_option('--res-dir',
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 GenerateV14XmlResourcesInDir(input_dir, output_dir) 195 GenerateV14XmlResourcesInDir(input_dir, output_dir)
200 elif resource_type in ('values'): 196 elif resource_type in ('values'):
201 GenerateV14XmlResourcesInDir(input_dir, output_dir, only_styles=True) 197 GenerateV14XmlResourcesInDir(input_dir, output_dir, only_styles=True)
202 198
203 if options.stamp: 199 if options.stamp:
204 build_utils.Touch(options.stamp) 200 build_utils.Touch(options.stamp)
205 201
206 if __name__ == '__main__': 202 if __name__ == '__main__':
207 sys.exit(main(sys.argv)) 203 sys.exit(main(sys.argv))
208 204
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698