Upstream version 10.38.217.0
[platform/framework/web/crosswalk.git] / src / xwalk / app / tools / android / customize.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2013,2014 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
7 import compress_js_and_css
8 import fnmatch
9 import json
10 import optparse
11 import os
12 import re
13 import shutil
14 import stat
15 import sys
16 import tempfile
17
18 # get xwalk absolute path so we can run this script from any location
19 xwalk_dir = os.path.dirname(os.path.abspath(__file__))
20 sys.path.append(xwalk_dir)
21
22 from app_info import AppInfo
23 from customize_launch_screen import CustomizeLaunchScreen
24 from handle_xml import AddElementAttribute
25 from handle_xml import AddElementAttributeAndText
26 from handle_xml import EditElementAttribute
27 from handle_xml import EditElementValueByNodeName
28 from handle_permissions import HandlePermissions
29 from util import CleanDir, CreateAndCopyDir
30 from xml.dom import minidom
31
32 TEMPLATE_DIR_NAME = 'template'
33
34 def VerifyPackageName(value):
35   regex = r'^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$'
36   descrpt = 'Each part of package'
37   sample = 'org.xwalk.example, org.xwalk.example_'
38
39   if len(value) >= 128:
40     print('To be safe, the length of package name or app name '
41           'should be less than 128.')
42     sys.exit(6)
43
44   if not re.match(regex, value):
45     print('Error: %s name should be started with letters and should not '
46           'contain invalid characters.\n'
47           'It may contain lowercase letters, numbers, blank spaces and '
48           'underscores\n'
49           'Sample: %s' % (descrpt, sample))
50     sys.exit(6)
51
52
53 def ReplaceSpaceWithUnderscore(value):
54   return value.replace(' ', '_')
55
56
57 def ReplaceInvalidChars(value, mode='default'):
58   """ Replace the invalid chars with '_' for input string.
59   Args:
60     value: the original string.
61     mode: the target usage mode of original string.
62   """
63   if mode == 'default':
64     invalid_chars = '\/:*?"<>|- '
65   elif mode == 'apkname':
66     invalid_chars = '\/:.*?"<>|- '
67   for c in invalid_chars:
68     if mode == 'apkname' and c in value:
69       print('Illegal character: "%s" replaced with "_"' % c)
70     value = value.replace(c, '_')
71   return value
72
73
74 def GetFilesByExt(path, ext, sub_dir=True):
75   if os.path.exists(path):
76     file_list = []
77     for name in os.listdir(path):
78       full_name = os.path.join(path, name)
79       st = os.lstat(full_name)
80       if stat.S_ISDIR(st.st_mode) and sub_dir:
81         file_list += GetFilesByExt(full_name, ext)
82       elif os.path.isfile(full_name):
83         if fnmatch.fnmatch(full_name, ext):
84           file_list.append(full_name)
85     return file_list
86   else:
87     return []
88
89
90 def ParseParameterForCompressor(option, value, values, parser):
91   if ((not values or values.startswith('-'))
92       and value.find('--compressor') != -1):
93     values = 'all'
94   val = values
95   if parser.rargs and not parser.rargs[0].startswith('-'):
96     val = parser.rargs[0]
97     parser.rargs.pop(0)
98   setattr(parser.values, option.dest, val)
99
100
101 def CompressSourceFiles(app_root, compressor):
102   js_list = []
103   css_list = []
104   js_ext = '*.js'
105   css_ext = '*.css'
106
107   if compressor == 'all' or compressor == 'js':
108     js_list = GetFilesByExt(app_root, js_ext)
109     compress_js_and_css.CompressJavaScript(js_list)
110
111   if compressor == 'all' or compressor == 'css':
112     css_list = GetFilesByExt(app_root, css_ext)
113     compress_js_and_css.CompressCss(css_list)
114
115
116 def Prepare(app_info, compressor):
117   """Copy the Android template project to a new app project
118      named app_info.app_name
119   """
120   # create new app_dir in temp dir
121   app_name = app_info.android_name
122   app_dir = os.path.join(tempfile.gettempdir(), app_name)
123   app_package = app_info.package
124   app_root = app_info.app_root
125   template_app_dir = os.path.join(xwalk_dir, TEMPLATE_DIR_NAME)
126
127   # 1) copy template project to app_dir
128   CleanDir(app_dir)
129   if not os.path.isdir(template_app_dir):
130     print('Error: The template directory could not be found (%s).' %
131           template_app_dir)
132     sys.exit(7)
133   shutil.copytree(template_app_dir, app_dir)
134
135   # 2) replace app_dir 'src' dir with template 'src' dir
136   CleanDir(os.path.join(app_dir, 'src'))
137   template_src_root = os.path.join(template_app_dir, 'src', 'org', 'xwalk',
138                                    'app', 'template')
139
140   # 3) Create directory tree from app package (org.xyz.foo -> src/org/xyz/foo)
141   #    and copy AppTemplateActivity.java to <app_name>Activity.java
142   template_activity_file = os.path.join(template_src_root,
143                                         'AppTemplateActivity.java')
144   if not os.path.isfile(template_activity_file):
145     print ('Error: The template file %s was not found. '
146            'Please make sure this file exists.' % template_activity_file)
147     sys.exit(7)
148   app_pkg_dir = os.path.join(app_dir, 'src',
149                              app_package.replace('.', os.path.sep))
150   if not os.path.exists(app_pkg_dir):
151     os.makedirs(app_pkg_dir)
152   app_activity_file = app_name + 'Activity.java'
153   shutil.copyfile(template_activity_file,
154                   os.path.join(app_pkg_dir, app_activity_file))
155
156   # 4) Copy all HTML source from app_root to app_dir
157   if app_root:
158     app_assets_dir = os.path.join(app_dir, 'assets', 'www')
159     CleanDir(app_assets_dir)
160     shutil.copytree(app_root, app_assets_dir)
161     if compressor:
162       CompressSourceFiles(app_assets_dir, compressor)
163
164
165 def EncodingUnicodeValue(value):
166   try:
167     if isinstance(value, unicode):
168       value = value.encode("utf-8")
169   except NameError:
170     pass
171   return value
172
173
174 def CustomizeStringXML(name, description):
175   strings_path = os.path.join(tempfile.gettempdir(), name, 'res', 'values',
176                               'strings.xml')
177   if not os.path.isfile(strings_path):
178     print ('Please make sure strings_xml'
179            ' exists under template folder.')
180     sys.exit(6)
181
182   if description:
183     description = EncodingUnicodeValue(description)
184     xmldoc = minidom.parse(strings_path)
185     AddElementAttributeAndText(xmldoc, 'string', 'name', 'description',
186                                description)
187     strings_file = open(strings_path, 'w')
188     xmldoc.writexml(strings_file, encoding='utf-8')
189     strings_file.close()
190
191
192 def CustomizeThemeXML(name, fullscreen, manifest):
193   theme_path = os.path.join(tempfile.gettempdir(), name, 'res', 'values-v14',
194                             'theme.xml')
195   if not os.path.isfile(theme_path):
196     print('Error: theme.xml is missing in the build tool.')
197     sys.exit(6)
198
199   theme_xmldoc = minidom.parse(theme_path)
200   if fullscreen:
201     EditElementValueByNodeName(theme_xmldoc, 'item',
202                                'android:windowFullscreen', 'true')
203   has_background = CustomizeLaunchScreen(manifest, name)
204   if has_background:
205     EditElementValueByNodeName(theme_xmldoc, 'item',
206                                'android:windowBackground',
207                                '@drawable/launchscreen_bg')
208   theme_file = open(theme_path, 'w')
209   theme_xmldoc.writexml(theme_file, encoding='utf-8')
210   theme_file.close()
211
212
213 def CustomizeXML(app_info, description, icon_dict, manifest, permissions):
214   app_version = app_info.app_version
215   app_versionCode = app_info.app_versionCode
216   name = app_info.android_name
217   orientation = app_info.orientation
218   package = app_info.package
219   app_name = app_info.app_name
220   app_dir = os.path.join(tempfile.gettempdir(), name)
221   # Chinese character with unicode get from 'manifest.json' will cause
222   # 'UnicodeEncodeError' when finally wrote to 'AndroidManifest.xml'.
223   app_name = EncodingUnicodeValue(app_name)
224   # If string start with '@' or '?', it will be treated as Android resource,
225   # which will cause 'No resource found' error,
226   # append a space before '@' or '?' to fix that.
227   if app_name.startswith('@') or app_name.startswith('?'):
228     app_name = ' ' + app_name
229   manifest_path = os.path.join(app_dir, 'AndroidManifest.xml')
230   if not os.path.isfile(manifest_path):
231     print ('Please make sure AndroidManifest.xml'
232            ' exists under template folder.')
233     sys.exit(6)
234
235   CustomizeStringXML(name, description)
236   CustomizeThemeXML(name, app_info.fullscreen_flag, manifest)
237   xmldoc = minidom.parse(manifest_path)
238   EditElementAttribute(xmldoc, 'manifest', 'package', package)
239   if app_versionCode:
240     EditElementAttribute(xmldoc, 'manifest', 'android:versionCode',
241                          str(app_versionCode))
242   if app_version:
243     EditElementAttribute(xmldoc, 'manifest', 'android:versionName',
244                          app_version)
245   if description:
246     EditElementAttribute(xmldoc, 'manifest', 'android:description',
247                          "@string/description")
248   HandlePermissions(permissions, xmldoc)
249   EditElementAttribute(xmldoc, 'application', 'android:label', app_name)
250   activity_name = package + '.' + name + 'Activity'
251   EditElementAttribute(xmldoc, 'activity', 'android:name', activity_name)
252   EditElementAttribute(xmldoc, 'activity', 'android:label', app_name)
253   if orientation:
254     EditElementAttribute(xmldoc, 'activity', 'android:screenOrientation',
255                          orientation)
256   icon_name = CustomizeIcon(name, app_info.app_root, app_info.icon, icon_dict)
257   if icon_name:
258     EditElementAttribute(xmldoc, 'application', 'android:icon',
259                          '@drawable/%s' % icon_name)
260
261   file_handle = open(os.path.join(app_dir, 'AndroidManifest.xml'), 'w')
262   xmldoc.writexml(file_handle, encoding='utf-8')
263   file_handle.close()
264
265
266 def ReplaceString(file_path, src, dest):
267   file_handle = open(file_path, 'r')
268   src_content = file_handle.read()
269   file_handle.close()
270   file_handle = open(file_path, 'w')
271   dest_content = src_content.replace(src, dest)
272   file_handle.write(dest_content)
273   file_handle.close()
274
275
276 def SetVariable(file_path, string_line, variable, value):
277   function_string = ('%sset%s(%s);\n' %
278                      ('        ', variable, value))
279   temp_file_path = file_path + '.backup'
280   file_handle = open(temp_file_path, 'w+')
281   for line in open(file_path):
282     file_handle.write(line)
283     if (line.find(string_line) >= 0):
284       file_handle.write(function_string)
285   file_handle.close()
286   shutil.move(temp_file_path, file_path)
287
288
289 def CustomizeJava(app_info, app_url, app_local_path, keep_screen_on):
290   name = app_info.android_name
291   package = app_info.package
292   app_dir = os.path.join(tempfile.gettempdir(), name)
293   app_pkg_dir = os.path.join(app_dir, 'src', package.replace('.', os.path.sep))
294   dest_activity = os.path.join(app_pkg_dir, name + 'Activity.java')
295   ReplaceString(dest_activity, 'org.xwalk.app.template', package)
296   ReplaceString(dest_activity, 'AppTemplate', name)
297   manifest_file = os.path.join(app_dir, 'assets', 'www', 'manifest.json')
298   if os.path.isfile(manifest_file):
299     ReplaceString(
300         dest_activity,
301         'loadAppFromUrl("file:///android_asset/www/index.html")',
302         'loadAppFromManifest("file:///android_asset/www/manifest.json")')
303   else:
304     if app_url:
305       if re.search(r'^http(|s)', app_url):
306         ReplaceString(dest_activity, 'file:///android_asset/www/index.html',
307                       app_url)
308     elif app_local_path:
309       if os.path.isfile(os.path.join(app_dir, 'assets', 'www', app_local_path)):
310         ReplaceString(dest_activity, 'file:///android_asset/www/index.html',
311                       'app://' + package + '/' + app_local_path)
312       else:
313         print ('Please make sure that the relative path of entry file'
314                ' is correct.')
315         sys.exit(8)
316
317   if app_info.remote_debugging:
318     SetVariable(dest_activity,
319                 'public void onCreate(Bundle savedInstanceState)',
320                 'RemoteDebugging', 'true')
321   if app_info.use_animatable_view:
322     SetVariable(dest_activity,
323                 'public void onCreate(Bundle savedInstanceState)',
324                 'UseAnimatableView', 'true')
325   if app_info.fullscreen_flag:
326     SetVariable(dest_activity,
327                 'super.onCreate(savedInstanceState)',
328                 'IsFullscreen', 'true')
329   if keep_screen_on:
330     ReplaceString(
331         dest_activity,
332         'super.onCreate(savedInstanceState);',
333         'super.onCreate(savedInstanceState);\n        ' +
334         'getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);')
335
336
337 def CopyExtensionFile(extension_name, suffix, src_path, dest_path):
338   # Copy the file from src_path into dest_path.
339   dest_extension_path = os.path.join(dest_path, extension_name)
340   if os.path.exists(dest_extension_path):
341     # TODO: Refine it by renaming it internally.
342     print('Error: duplicate extension names were found (%s). Please rename it.'
343           % extension_name)
344     sys.exit(9)
345   else:
346     os.mkdir(dest_extension_path)
347
348   file_name = extension_name + suffix
349   src_file = os.path.join(src_path, file_name)
350   dest_file = os.path.join(dest_extension_path, file_name)
351   if not os.path.isfile(src_file):
352     print('Error: %s was not found in %s.' % (file_name, src_path))
353     sys.exit(9)
354   else:
355     shutil.copyfile(src_file, dest_file)
356
357
358 def CustomizeExtensions(app_info, extensions):
359   """Copy the files from external extensions and merge them into APK.
360
361   The directory of one external extension should be like:
362     myextension/
363       myextension.jar
364       myextension.js
365       myextension.json
366   That means the name of the internal files should be the same as the
367   directory name.
368   For .jar files, they'll be copied to xwalk-extensions/ and then
369   built into classes.dex in make_apk.py.
370   For .js files, they'll be copied into assets/xwalk-extensions/.
371   For .json files, the'll be merged into one file called
372   extensions-config.json and copied into assets/.
373   """
374   if not extensions:
375     return
376   name = app_info.android_name
377   app_dir = os.path.join(tempfile.gettempdir(), name)
378   apk_assets_path = os.path.join(app_dir, 'assets')
379   extensions_string = 'xwalk-extensions'
380
381   # Set up the target directories and files.
382   dest_jar_path = os.path.join(app_dir, extensions_string)
383   os.mkdir(dest_jar_path)
384   dest_js_path = os.path.join(apk_assets_path, extensions_string)
385   os.mkdir(dest_js_path)
386   apk_extensions_json_path = os.path.join(apk_assets_path,
387                                           'extensions-config.json')
388
389   # Split the paths into a list.
390   extension_paths = extensions.split(os.pathsep)
391   extension_json_list = []
392   for source_path in extension_paths:
393     if not os.path.exists(source_path):
394       print('Error: can not find the extension directory \'%s\'.' % source_path)
395       sys.exit(9)
396     # Remove redundant separators to avoid empty basename.
397     source_path = os.path.normpath(source_path)
398     extension_name = os.path.basename(source_path)
399
400     # Copy .jar file into xwalk-extensions.
401     CopyExtensionFile(extension_name, '.jar', source_path, dest_jar_path)
402
403     # Copy .js file into assets/xwalk-extensions.
404     CopyExtensionFile(extension_name, '.js', source_path, dest_js_path)
405
406     # Merge .json file into assets/xwalk-extensions.
407     file_name = extension_name + '.json'
408     src_file = os.path.join(source_path, file_name)
409     if not os.path.isfile(src_file):
410       print('Error: %s was not found in %s.' % (file_name, source_path))
411       sys.exit(9)
412     else:
413       src_file_handle = open(src_file)
414       src_file_content = src_file_handle.read()
415       json_output = json.JSONDecoder().decode(src_file_content)
416       # Below 3 properties are used by runtime. See extension manager.
417       # And 'permissions' will be merged.
418       if not ('name' in json_output and
419               'class' in json_output and
420               'jsapi' in json_output):
421         print ('Error: properties \'name\', \'class\' and \'jsapi\' in a json '
422                'file are mandatory.')
423         sys.exit(9)
424       # Reset the path for JavaScript.
425       js_path_prefix = extensions_string + '/' + extension_name + '/'
426       json_output['jsapi'] = js_path_prefix + json_output['jsapi']
427       extension_json_list.append(json_output)
428       # Merge the permissions of extensions into AndroidManifest.xml.
429       manifest_path = os.path.join(app_dir, 'AndroidManifest.xml')
430       xmldoc = minidom.parse(manifest_path)
431       if ('permissions' in json_output):
432         # Get used permission list to avoid repetition as "--permissions"
433         # option can also be used to declare used permissions.
434         existingList = []
435         usedPermissions = xmldoc.getElementsByTagName("uses-permission")
436         for used in usedPermissions:
437           existingList.append(used.getAttribute("android:name"))
438
439         # Add the permissions to manifest file if not used yet.
440         for p in json_output['permissions']:
441           if p in existingList:
442             continue
443           AddElementAttribute(xmldoc, 'uses-permission', 'android:name', p)
444           existingList.append(p)
445
446         # Write to the manifest file to save the update.
447         file_handle = open(manifest_path, 'w')
448         xmldoc.writexml(file_handle, encoding='utf-8')
449         file_handle.close()
450
451   # Write configuration of extensions into the target extensions-config.json.
452   if extension_json_list:
453     extensions_string = json.JSONEncoder().encode(extension_json_list)
454     extension_json_file = open(apk_extensions_json_path, 'w')
455     extension_json_file.write(extensions_string)
456     extension_json_file.close()
457
458
459 def GenerateCommandLineFile(app_info, xwalk_command_line):
460   if xwalk_command_line == '':
461     return
462   assets_path = os.path.join(tempfile.gettempdir(), app_info.android_name,
463                              'assets')
464   file_path = os.path.join(assets_path, 'xwalk-command-line')
465   command_line_file = open(file_path, 'w')
466   command_line_file.write('xwalk ' + xwalk_command_line)
467
468
469 def CustomizeIconByDict(name, app_root, icon_dict):
470   app_dir = os.path.join(tempfile.gettempdir(), name)
471   icon_name = None
472   drawable_dict = {'ldpi': [1, 37], 'mdpi': [37, 72], 'hdpi': [72, 96],
473                    'xhdpi': [96, 120], 'xxhdpi': [120, 144],
474                    'xxxhdpi': [144, 168]}
475   if not icon_dict:
476     return icon_name
477
478   try:
479     icon_dict = dict((int(k), v) for k, v in icon_dict.items())
480   except ValueError:
481     print('The key of icon in the manifest file should be a number.')
482
483   if len(icon_dict) > 0:
484     icon_list = sorted(icon_dict.items(), key=lambda d: d[0])
485     for kd, vd in drawable_dict.items():
486       for item in icon_list:
487         if item[0] >= vd[0] and item[0] < vd[1]:
488           drawable_path = os.path.join(app_dir, 'res', 'drawable-' + kd)
489           if not os.path.exists(drawable_path):
490             os.makedirs(drawable_path)
491           icon = os.path.join(app_root, item[1])
492           if icon and os.path.isfile(icon):
493             icon_name = os.path.basename(icon)
494             icon_suffix = icon_name.split('.')[-1]
495             shutil.copyfile(icon, os.path.join(drawable_path,
496                                                'icon.' + icon_suffix))
497             icon_name = 'icon'
498           elif icon and (not os.path.isfile(icon)):
499             print('Error: "%s" does not exist.' % icon)
500             sys.exit(6)
501           break
502   return icon_name
503
504
505 def CustomizeIconByOption(name, icon):
506   if os.path.isfile(icon):
507     drawable_path = os.path.join(tempfile.gettempdir(), name, 'res', 'drawable')
508     if not os.path.exists(drawable_path):
509       os.makedirs(drawable_path)
510     icon_file = os.path.basename(icon)
511     icon_file = ReplaceInvalidChars(icon_file)
512     shutil.copyfile(icon, os.path.join(drawable_path, icon_file))
513     icon_name = os.path.splitext(icon_file)[0]
514     return icon_name
515   else:
516     print('Error: "%s" does not exist.' % icon)
517     sys.exit(6)
518
519
520 def CustomizeIcon(name, app_root, icon, icon_dict):
521   icon_name = None
522   if icon:
523     icon_name = CustomizeIconByOption(name, icon)
524   else:
525     icon_name = CustomizeIconByDict(name, app_root, icon_dict)
526   return icon_name
527
528
529 def CustomizeAll(app_info, description, icon_dict, permissions, app_url,
530                  app_local_path, keep_screen_on, extensions, manifest,
531                  xwalk_command_line='', compressor=None):
532   try:
533     Prepare(app_info, compressor)
534     CustomizeXML(app_info, description, icon_dict, manifest, permissions)
535     CustomizeJava(app_info, app_url, app_local_path, keep_screen_on)
536     CustomizeExtensions(app_info, extensions)
537     GenerateCommandLineFile(app_info, xwalk_command_line)
538   except SystemExit as ec:
539     print('Exiting with error code: %d' % ec.code)
540     sys.exit(ec.code)
541
542
543 def main():
544   parser = optparse.OptionParser()
545   info = ('The package name. Such as: '
546           '--package=com.example.YourPackage')
547   parser.add_option('--package', help=info)
548   info = ('The apk name. Such as: --name="Your Application Name"')
549   parser.add_option('--name', help=info)
550   info = ('The version of the app. Such as: --app-version=TheVersionNumber')
551   parser.add_option('--app-version', help=info)
552   info = ('The versionCode of the app. Such as: --app-versionCode=24')
553   parser.add_option('--app-versionCode', type='int', help=info)
554   info = ('The application description. Such as:'
555           '--description=YourApplicationdDescription')
556   parser.add_option('--description', help=info)
557   info = ('The permission list. Such as: --permissions="geolocation"'
558           'For more permissions, such as:'
559           '--permissions="geolocation:permission2"')
560   parser.add_option('--permissions', help=info)
561   info = ('The url of application. '
562           'This flag allows to package website as apk. Such as: '
563           '--app-url=http://www.intel.com')
564   parser.add_option('--app-url', help=info)
565   info = ('The root path of the web app. '
566           'This flag allows to package local web app as apk. Such as: '
567           '--app-root=/root/path/of/the/web/app')
568   parser.add_option('--app-root', help=info)
569   info = ('The reletive path of entry file based on |app_root|. '
570           'This flag should work with "--app-root" together. '
571           'Such as: --app-local-path=/reletive/path/of/entry/file')
572   parser.add_option('--app-local-path', help=info)
573   parser.add_option('--enable-remote-debugging', action='store_true',
574                     dest='enable_remote_debugging', default=False,
575                     help='Enable remote debugging.')
576   parser.add_option('--use-animatable-view', action='store_true',
577                     dest='use_animatable_view', default=False,
578                     help='Enable using animatable view (TextureView).')
579   parser.add_option('-f', '--fullscreen', action='store_true',
580                     dest='fullscreen', default=False,
581                     help='Make application fullscreen.')
582   parser.add_option('--keep-screen-on', action='store_true', default=False,
583                     help='Support keeping screen on')
584   info = ('The path list for external extensions separated by os separator.'
585           'On Linux and Mac, the separator is ":". On Windows, it is ";".'
586           'Such as: --extensions="/path/to/extension1:/path/to/extension2"')
587   parser.add_option('--extensions', help=info)
588   info = ('The orientation of the web app\'s display on the device. '
589           'Such as: --orientation=landscape. The default value is "unspecified"'
590           'The value options are the same as those on the Android: '
591           'http://developer.android.com/guide/topics/manifest/'
592           'activity-element.html#screen')
593   parser.add_option('--orientation', help=info)
594   parser.add_option('--manifest', help='The manifest path')
595   info = ('Use command lines.'
596           'Crosswalk is powered by Chromium and supports Chromium command line.'
597           'For example, '
598           '--xwalk-command-line=\'--chromium-command-1 --xwalk-command-2\'')
599   info = ('Create an Android project directory at this location. ')
600   parser.add_option('--project-dir', help=info)
601   parser.add_option('--xwalk-command-line', default='', help=info)
602   info = ('Minify and obfuscate javascript and css.'
603           '--compressor: compress javascript and css.'
604           '--compressor=js: compress javascript.'
605           '--compressor=css: compress css.')
606   parser.add_option('--compressor', dest='compressor', action='callback',
607                     callback=ParseParameterForCompressor,
608                     type='string', nargs=0, help=info)
609   options, _ = parser.parse_args()
610   try:
611     icon_dict = {144: 'icons/icon_144.png',
612                  72: 'icons/icon_72.png',
613                  96: 'icons/icon_96.png',
614                  48: 'icons/icon_48.png'}
615     app_info = AppInfo()
616     if options.name is not None:
617       app_info.android_name = options.name
618     if options.app_root is None:
619       app_info.app_root = os.path.join(xwalk_dir, 'test_data', 'manifest')
620     else:
621       app_info.app_root = options.app_root
622     if options.package is not None:
623       app_info.package = options.package
624     if options.orientation is not None:
625       app_info.orientation = options.orientation
626     if options.app_version is not None:
627       app_info.app_version = options.app_version
628     if options.enable_remote_debugging is not None:
629       app_info.remote_debugging = options.enable_remote_debugging
630     if options.fullscreen is not None:
631       app_info.fullscreen_flag = options.fullscreen
632     app_info.icon = os.path.join('test_data', 'manifest', 'icons',
633                                  'icon_96.png')
634     CustomizeAll(app_info, options.description, icon_dict,
635                  options.permissions, options.app_url, options.app_local_path,
636                  options.keep_screen_on, options.extensions, None,
637                  options.xwalk_command_line, options.compressor)
638
639     # build project is now in /tmp/<name>. Copy to project_dir
640     if options.project_dir:
641       src_dir = os.path.join(tempfile.gettempdir(), app_info.android_name)
642       dest_dir = os.path.join(options.project_dir, app_info.android_name)
643       CreateAndCopyDir(src_dir, dest_dir, True)
644
645   except SystemExit as ec:
646     print('Exiting with error code: %d' % ec.code)
647     return ec.code
648   finally:
649     CleanDir(os.path.join(tempfile.gettempdir(), app_info.android_name))
650   return 0
651
652
653 if __name__ == '__main__':
654   sys.exit(main())