c3fb2b0ff79e2b3d774c0c131161656539da1f7e
[platform/framework/web/crosswalk.git] / src / xwalk / build / android / generate_xwalk_core_library.py
1 #!/usr/bin/env python
2 #
3 # Copyright (c) 2013 Intel Corporation. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6 # pylint: disable=F0401
7
8 import distutils.dir_util
9 import optparse
10 import os
11 import shutil
12 import sys
13 import zipfile
14 from common_function import RemoveUnusedFilesInReleaseMode
15 from xml.dom.minidom import Document
16
17 LIBRARY_PROJECT_NAME = 'xwalk_core_library'
18 XWALK_CORE_SHELL_APK = 'xwalk_core_shell_apk'
19
20 def AddGeneratorOptions(option_parser):
21   option_parser.add_option('-s', dest='source',
22                            help='Source directory of project root.',
23                            type='string')
24   option_parser.add_option('-t', dest='target',
25                            help='Product out target directory.',
26                            type='string')
27
28
29 def CleanLibraryProject(out_dir):
30   out_project_path = os.path.join(out_dir, LIBRARY_PROJECT_NAME)
31   if os.path.exists(out_project_path):
32     for item in os.listdir(out_project_path):
33       sub_path = os.path.join(out_project_path, item)
34       if os.path.isdir(sub_path):
35         shutil.rmtree(sub_path)
36       elif os.path.isfile(sub_path):
37         os.remove(sub_path)
38
39
40 def CopyProjectFiles(project_source, out_dir):
41   """cp xwalk/build/android/xwalkcore_library_template/<file>
42         out/Release/xwalk_core_library/<file>
43   """
44
45   print 'Copying library project files...'
46   template_dir = os.path.join(project_source, 'xwalk', 'build', 'android',
47                               'xwalkcore_library_template')
48   files_to_copy = [
49       # AndroidManifest.xml from template.
50       'AndroidManifest.xml',
51       # Eclipse project properties from template.
52       'project.properties',
53       # Ant build file.
54       'build.xml',
55       # Ant properties file.
56       'ant.properties',
57   ]
58   for f in files_to_copy:
59     source_file = os.path.join(template_dir, f)
60     target_file = os.path.join(out_dir, LIBRARY_PROJECT_NAME, f)
61
62     shutil.copy2(source_file, target_file)
63
64
65 def CopyJSBindingFiles(project_source, out_dir):
66   print 'Copying js binding files...'
67   jsapi_dir = os.path.join(out_dir,
68                            LIBRARY_PROJECT_NAME,
69                            'res',
70                            'raw')
71   if not os.path.exists(jsapi_dir):
72     os.makedirs(jsapi_dir)
73
74   jsfiles_to_copy = [
75       'xwalk/experimental/launch_screen/launch_screen_api.js',
76       'xwalk/experimental/presentation/presentation_api.js',
77       'xwalk/runtime/android/core_internal/src/org/xwalk/core/'
78       + 'internal/extension/api/contacts/contacts_api.js',
79       'xwalk/runtime/android/core_internal/src/org/xwalk/core/'
80       + 'internal/extension/api/device_capabilities/device_capabilities_api.js',
81       'xwalk/runtime/android/core_internal/src/org/xwalk/core/'
82       + 'internal/extension/api/messaging/messaging_api.js'
83   ]
84
85   # Copy JS binding file to assets/jsapi folder.
86   for jsfile in jsfiles_to_copy:
87     source_file = os.path.join(project_source, jsfile)
88     target_file = os.path.join(jsapi_dir, os.path.basename(source_file))
89     shutil.copyfile(source_file, target_file)
90
91
92 def CopyBinaries(out_dir):
93   """cp out/Release/<pak> out/Release/xwalk_core_library/res/raw/<pak>
94      cp out/Release/lib.java/<lib> out/Release/xwalk_core_library/libs/<lib>
95      cp out/Release/xwalk_core_shell_apk/libs/*
96         out/Release/xwalk_core_library/libs
97   """
98
99   print 'Copying binaries...'
100   # Copy assets.
101   res_raw_dir = os.path.join(
102       out_dir, LIBRARY_PROJECT_NAME, 'res', 'raw')
103   res_value_dir = os.path.join(
104       out_dir, LIBRARY_PROJECT_NAME, 'res', 'values')
105   if not os.path.exists(res_raw_dir):
106     os.mkdir(res_raw_dir)
107   if not os.path.exists(res_value_dir):
108     os.mkdir(res_value_dir)
109
110   paks_to_copy = [
111       'icudtl.dat',
112       'xwalk.pak',
113   ]
114
115   pak_list_xml = Document()
116   resources_node = pak_list_xml.createElement('resources')
117   string_array_node = pak_list_xml.createElement('string-array')
118   string_array_node.setAttribute('name', 'xwalk_resources_list')
119   pak_list_xml.appendChild(resources_node)
120   resources_node.appendChild(string_array_node)
121   for pak in paks_to_copy:
122     source_file = os.path.join(out_dir, pak)
123     target_file = os.path.join(res_raw_dir, pak)
124     shutil.copyfile(source_file, target_file)
125     item_node = pak_list_xml.createElement('item')
126     item_node.appendChild(pak_list_xml.createTextNode(pak))
127     string_array_node.appendChild(item_node)
128   pak_list_file = open(os.path.join(res_value_dir,
129                                     'xwalk_resources_list.xml'), 'w')
130   pak_list_xml.writexml(pak_list_file, newl='\n', encoding='utf-8')
131   pak_list_file.close()
132
133   # Copy jar files to libs.
134   libs_dir = os.path.join(out_dir, LIBRARY_PROJECT_NAME, 'libs')
135   if not os.path.exists(libs_dir):
136     os.mkdir(libs_dir)
137
138   libs_to_copy = [
139       'xwalk_core_library_java_app_part.jar',
140       'xwalk_core_library_java_library_part.jar',
141   ]
142
143   for lib in libs_to_copy:
144     source_file = os.path.join(out_dir, 'lib.java', lib)
145     target_file = os.path.join(libs_dir, lib)
146     shutil.copyfile(source_file, target_file)
147
148   # Copy native libraries.
149   source_dir = os.path.join(out_dir, XWALK_CORE_SHELL_APK, 'libs')
150   target_dir = libs_dir
151   distutils.dir_util.copy_tree(source_dir, target_dir)
152
153
154 def CopyDirAndPrefixDuplicates(input_dir, output_dir, prefix):
155   """ Copy the files into the output directory. If one file in input_dir folder
156   doesn't exist, copy it directly. If a file exists, copy it and rename the
157   file so that the resources won't be overrided. So all of them could be
158   packaged into the xwalk core library.
159   """
160   for root, _, files in os.walk(input_dir):
161     for f in files:
162       src_file = os.path.join(root, f)
163       relative_path = os.path.relpath(src_file, input_dir)
164       target_file = os.path.join(output_dir, relative_path)
165       target_dir_name = os.path.dirname(target_file)
166       if not os.path.exists(target_dir_name):
167         os.makedirs(target_dir_name)
168       # If the file exists, copy it and rename it with another name to
169       # avoid overwriting the existing one.
170       if os.path.exists(target_file):
171         target_base_name = os.path.basename(target_file)
172         target_base_name = prefix + '_' + target_base_name
173         target_file = os.path.join(target_dir_name, target_base_name)
174       shutil.copyfile(src_file, target_file)
175
176
177 def MoveImagesToNonMdpiFolders(res_root):
178   """Move images from drawable-*-mdpi-* folders to drawable-* folders.
179
180   Why? http://crbug.com/289843
181
182   Copied from build/android/gyp/package_resources.py.
183   """
184   for src_dir_name in os.listdir(res_root):
185     src_components = src_dir_name.split('-')
186     if src_components[0] != 'drawable' or 'mdpi' not in src_components:
187       continue
188     src_dir = os.path.join(res_root, src_dir_name)
189     if not os.path.isdir(src_dir):
190       continue
191     dst_components = [c for c in src_components if c != 'mdpi']
192     assert dst_components != src_components
193     dst_dir_name = '-'.join(dst_components)
194     dst_dir = os.path.join(res_root, dst_dir_name)
195     if not os.path.isdir(dst_dir):
196       os.makedirs(dst_dir)
197     for src_file_name in os.listdir(src_dir):
198       if not src_file_name.endswith('.png'):
199         continue
200       src_file = os.path.join(src_dir, src_file_name)
201       dst_file = os.path.join(dst_dir, src_file_name)
202       assert not os.path.lexists(dst_file)
203       shutil.move(src_file, dst_file)
204
205
206 def ReplaceCrunchedImage(project_source, filename, filepath):
207   """Replace crunched images with source images.
208   """
209   search_dir = [
210       'content/public/android/java/res',
211       'ui/android/java/res'
212   ]
213
214   pathname = os.path.basename(filepath)
215   #replace crunched 9-patch image resources.
216   for search in search_dir:
217     absdir = os.path.join(project_source, search)
218     for dirname, _, files in os.walk(absdir):
219       if filename in files:
220         relativedir = os.path.basename(dirname)
221         if (pathname == 'drawable' and relativedir == 'drawable-mdpi') or \
222             relativedir == pathname:
223           source_file = os.path.abspath(os.path.join(dirname, filename))
224           target_file = os.path.join(filepath, filename)
225           shutil.copyfile(source_file, target_file)
226           return 
227         
228
229 def CopyResources(project_source, out_dir):
230   print 'Copying resources...'
231   res_dir = os.path.join(out_dir, LIBRARY_PROJECT_NAME, 'res')
232   temp_dir = os.path.join(out_dir, LIBRARY_PROJECT_NAME, 'temp')
233   if os.path.exists(res_dir):
234     shutil.rmtree(res_dir)
235   if os.path.exists(temp_dir):
236     shutil.rmtree(temp_dir)
237
238   # All resources should be in specific folders in res_directory.
239   # Since there might be some resource files with same names from
240   # different folders like ui_java, content_java and others,
241   # it's necessary to rename some files to avoid overridding.
242   res_to_copy = [
243       # zip file list
244       'content_java.zip',
245       'content_strings_grd.zip',
246       'ui_java.zip',
247       'ui_strings_grd.zip',
248       'xwalk_core_internal_java.zip',
249       'xwalk_core_strings.zip'
250   ]
251
252   for res_zip in res_to_copy:
253     zip_file = os.path.join(out_dir, 'res.java', res_zip)
254     zip_name = os.path.splitext(res_zip)[0]
255     if not os.path.isfile(zip_file):
256       raise Exception('Resource zip not found: ' + zip_file)
257     subdir = os.path.join(temp_dir, zip_name)
258     if os.path.isdir(subdir):
259       raise Exception('Resource zip name conflict: ' + zip_name)
260     os.makedirs(subdir)
261     with zipfile.ZipFile(zip_file) as z:
262       z.extractall(path=subdir)
263     CopyDirAndPrefixDuplicates(subdir, res_dir, zip_name)
264     MoveImagesToNonMdpiFolders(res_dir)
265
266   if os.path.isdir(temp_dir):
267     shutil.rmtree(temp_dir)
268
269   #search 9-patch, then replace it with uncrunch image.
270   for dirname, _, files in os.walk(res_dir):
271     for filename in files:
272       if filename.endswith('.9.png'):
273         ReplaceCrunchedImage(project_source, filename, dirname)
274
275
276 def PostCopyLibraryProject(out_dir):
277   print 'Post Copy Library Project...'
278   aidls_to_remove = [
279       'org/chromium/content/common/common.aidl',
280       'org/chromium/net/IRemoteAndroidKeyStoreInterface.aidl',
281   ]
282   for aidl in aidls_to_remove:
283     aidl_file = os.path.join(out_dir, LIBRARY_PROJECT_NAME, 'src', aidl)
284     if os.path.exists(aidl_file):
285       os.remove(aidl_file)
286
287
288 def main(argv):
289   print 'Generating XWalkCore Library Project...'
290   option_parser = optparse.OptionParser()
291   AddGeneratorOptions(option_parser)
292   options, _ = option_parser.parse_args(argv)
293
294   if not os.path.exists(options.source):
295     print 'Source project does not exist, please provide correct directory.'
296     sys.exit(1)
297   out_dir = options.target
298
299   # Clean directory for project first.
300   CleanLibraryProject(out_dir)
301
302   out_project_dir = os.path.join(out_dir, LIBRARY_PROJECT_NAME)
303   if not os.path.exists(out_project_dir):
304     os.mkdir(out_project_dir)
305
306   # Copy Eclipse project files of library project.
307   CopyProjectFiles(options.source, out_dir)
308   # Copy binaries and resuorces.
309   CopyResources(options.source, out_dir)
310   CopyBinaries(out_dir)
311   # Copy JS API binding files.
312   CopyJSBindingFiles(options.source, out_dir)
313   # Post copy library project.
314   PostCopyLibraryProject(out_dir)
315   # Remove unused files.
316   mode = os.path.basename(os.path.normpath(out_dir))
317   RemoveUnusedFilesInReleaseMode(mode,
318       os.path.join(out_dir, LIBRARY_PROJECT_NAME, 'libs'))
319   # Create empty src directory
320   src_dir = os.path.join(out_project_dir, 'src')
321   if not os.path.isdir(src_dir):
322     os.mkdir(src_dir)
323   readme = os.path.join(src_dir, 'README.md')
324   open(readme, 'w').write(
325       "# Source folder for xwalk_core_library\n"
326       "## Why it's empty\n"
327       "xwalk_core_library doesn't contain java sources.\n"
328       "## Why put me here\n"
329       "To make archives keep the folder, "
330       "the src directory is needed to build an apk by ant.")
331   print 'Your Android library project has been created at %s' % (
332       out_project_dir)
333
334 if __name__ == '__main__':
335   sys.exit(main(sys.argv))