Upstream version 8.36.161.0
[platform/framework/web/crosswalk.git] / src / xwalk / app / tools / android / make_apk.py
index 9313342..2c1bbc1 100755 (executable)
@@ -14,25 +14,32 @@ import subprocess
 import sys
 
 sys.path.append('scripts/gyp')
-from customize import ReplaceInvalidChars
+
+from app_info import AppInfo
+from customize import VerifyAppName, CustomizeAll, \
+                      ParseParameterForCompressor, ReplaceSpaceWithUnderscore
 from dex import AddExeExtensions
 from handle_permissions import permission_mapping_table
 from manifest_json_parser import HandlePermissionList
 from manifest_json_parser import ManifestJsonParser
 
+
 def CleanDir(path):
   if os.path.exists(path):
     shutil.rmtree(path)
 
+def AllArchitectures():
+  return ("x86", "arm")
 
-def RunCommand(command, shell=False):
+def RunCommand(command, verbose=False, shell=False):
   """Runs the command list, print the output, and propagate its result."""
   proc = subprocess.Popen(command, stdout=subprocess.PIPE,
                           stderr=subprocess.STDOUT, shell=shell)
   if not shell:
     output = proc.communicate()[0]
     result = proc.returncode
-    print output
+    if verbose:
+      print(output.decode("utf-8").strip())
     if result != 0:
       print ('Command "%s" exited with non-zero exit code %d'
              % (' '.join(command), result))
@@ -42,7 +49,7 @@ def RunCommand(command, shell=False):
 def Which(name):
   """Search PATH for executable files with the given name."""
   result = []
-  exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep))
+  exts = [_f for _f in os.environ.get('PATHEXT', '').split(os.pathsep) if _f]
   path = os.environ.get('PATH', None)
   if path is None:
     return []
@@ -72,7 +79,7 @@ def Find(name, path):
         result[key] = 0
   if not result:
     raise Exception()
-  return max(result.iteritems(), key=operator.itemgetter(1))[0]
+  return max(iter(result.items()), key=operator.itemgetter(1))[0]
 
 
 def GetVersion(path):
@@ -86,14 +93,27 @@ def GetVersion(path):
   return version_str
 
 
-def ParseManifest(options):
+def ParseManifest(options, app_info):
   parser = ManifestJsonParser(os.path.expanduser(options.manifest))
-  if not options.package:
-    options.package = 'org.xwalk.' + parser.GetAppName().lower()
-  if not options.name:
-    options.name = parser.GetAppName()
+  original_name = app_info.original_name = parser.GetAppName()
+  app_name = None
+  if options.package:
+    VerifyAppName(options.package, 'packagename')
+  else:
+    VerifyAppName(original_name)
+    app_name = ReplaceSpaceWithUnderscore(original_name)
+    options.package = 'org.xwalk.' + app_name.lower()
+  if options.name:
+    VerifyAppName(options.name)
+    app_info.original_name = options.name
+    options.name = ReplaceSpaceWithUnderscore(options.name)
+  else:
+    VerifyAppName(original_name)
+    options.name = ReplaceSpaceWithUnderscore(original_name)
   if not options.app_version:
     options.app_version = parser.GetVersion()
+  if not options.app_versionCode and not options.app_versionCodeBase:
+    options.app_versionCode = 1
   if parser.GetDescription():
     options.description = parser.GetDescription()
   if parser.GetPermissions():
@@ -103,20 +123,11 @@ def ParseManifest(options):
   elif parser.GetAppLocalPath():
     options.app_local_path = parser.GetAppLocalPath()
   else:
-    print 'Error: there is no app launch path defined in manifest.json.'
+    print('Error: there is no app launch path defined in manifest.json.')
     sys.exit(9)
   if parser.GetAppRoot():
     options.app_root = parser.GetAppRoot()
-    temp_dict = parser.GetIcons()
-    try:
-      icon_dict = dict((int(k), v) for k, v in temp_dict.iteritems())
-    except ValueError:
-      print 'The key of icon in the manifest file should be a number.'
-    # TODO(junmin): add multiple icons support.
-    if icon_dict:
-      icon_file = max(icon_dict.iteritems(), key=operator.itemgetter(0))[1]
-      options.icon = os.path.join(options.app_root, icon_file)
-  options.enable_remote_debugging = False
+    options.icon_dict = parser.GetIcons()
   if parser.GetFullScreenFlag().lower() == 'true':
     options.fullscreen = True
   elif parser.GetFullScreenFlag().lower() == 'false':
@@ -137,7 +148,7 @@ def ParseXPK(options, out_dir):
   if os.path.isfile(os.path.join(out_dir, 'manifest.json')):
     options.manifest = os.path.join(out_dir, 'manifest.json')
   else:
-    print 'XPK doesn\'t contain manifest file.'
+    print('XPK doesn\'t contain manifest file.')
     sys.exit(8)
 
 
@@ -156,71 +167,75 @@ def FindExtensionJars(root_path):
   return extension_jars
 
 
-def Customize(options):
-  package = '--package=org.xwalk.app.template'
+# Follows the recommendation from
+# http://software.intel.com/en-us/blogs/2012/11/12/how-to-publish-
+# your-apps-on-google-play-for-x86-based-android-devices-using
+def MakeVersionCode(options):
+  ''' Construct a version code'''
+  if options.app_versionCode:
+    return options.app_versionCode
+
+  # First digit is ABI, ARM=2, x86=6
+  abi = '0'
+  if options.arch == 'arm':
+    abi = '2'
+  if options.arch == 'x86':
+    abi = '6'
+  b = '0'
+  if options.app_versionCodeBase:
+    b = str(options.app_versionCodeBase)
+    if len(b) > 7:
+      print('Version code base must be 7 digits or less: '
+            'versionCodeBase=%s' % (b))
+      sys.exit(12)
+  # zero pad to 7 digits, middle digits can be used for other
+  # features, according to recommendation in URL
+  return '%s%s' % (abi, b.zfill(7))
+
+
+def Customize(options, app_info):
   if options.package:
-    package = '--package=%s' % options.package
-  name = '--name=AppTemplate'
+    app_info.package = options.package
   if options.name:
-    name = '--name=%s' % options.name
-  app_version = '--app-version=1.0.0'
+    app_info.name = options.name
   if options.app_version:
-    app_version = '--app-version=%s' % options.app_version
-  description = ''
-  if options.description:
-    description = '--description=%s' % options.description
-  permissions = ''
-  if options.permissions:
-    permissions = '--permissions=%s' % options.permissions
-  icon = ''
-  if options.icon:
-    icon = '--icon=%s' % os.path.expanduser(options.icon)
-  app_url =  ''
-  if options.app_url:
-    app_url = '--app-url=%s' % options.app_url
-  app_root = ''
+    app_info.app_version = options.app_version
+  app_info.app_versionCode = MakeVersionCode(options)
   if options.app_root:
-    app_root = '--app-root=%s' % os.path.expanduser(options.app_root)
-  app_local_path = ''
-  if options.app_local_path:
-    app_local_path = '--app-local-path=%s' % options.app_local_path
-  remote_debugging = ''
+    app_info.app_root = os.path.expanduser(options.app_root)
   if options.enable_remote_debugging:
-    remote_debugging = '--enable-remote-debugging'
-  fullscreen_flag = ''
+    app_info.remote_debugging = '--enable-remote-debugging'
   if options.fullscreen:
-    fullscreen_flag = '-f'
-  extensions_list = ''
-  if options.extensions:
-    extensions_list = '--extensions=%s' % options.extensions
-  orientation = '--orientation=unspecified'
+    app_info.fullscreen_flag = '-f'
   if options.orientation:
-    orientation = '--orientation=%s' % options.orientation
-  cmd = ['python', 'customize.py', package,
-          name, app_version, description, icon, permissions, app_url,
-          remote_debugging, app_root, app_local_path, fullscreen_flag,
-          extensions_list, orientation]
-  RunCommand(cmd)
+    app_info.orientation = options.orientation
+  if options.icon:
+    app_info.icon = '%s' % os.path.expanduser(options.icon)
+  CustomizeAll(app_info, options.description, options.icon_dict,
+               options.permissions, options.app_url, options.app_local_path,
+               options.keep_screen_on, options.extensions, options.manifest,
+               options.xwalk_command_line, options.compressor)
 
 
-def Execution(options, sanitized_name):
+def Execution(options, name):
   android_path_array = Which('android')
   if not android_path_array:
-    print 'Please install Android SDK first.'
+    print('Please install Android SDK first.')
     sys.exit(1)
 
   sdk_root_path = os.path.dirname(os.path.dirname(android_path_array[0]))
 
   try:
-    sdk_jar_path = Find('android.jar', os.path.join(sdk_root_path, 'platforms'))
+    sdk_jar_path = Find('android.jar',
+                        os.path.join(sdk_root_path, 'platforms'))
   except Exception:
-    print 'Your Android SDK may be ruined, please reinstall it.'
+    print('Your Android SDK may be ruined, please reinstall it.')
     sys.exit(2)
 
   level_string = os.path.basename(os.path.dirname(sdk_jar_path))
   api_level = int(re.search(r'\d+', level_string).group())
   if api_level < 14:
-    print 'Please install Android API level (>=14) first.'
+    print('Please install Android API level (>=14) first.')
     sys.exit(3)
 
   if options.keystore_path:
@@ -228,12 +243,12 @@ def Execution(options, sanitized_name):
     if options.keystore_alias:
       key_alias = options.keystore_alias
     else:
-      print 'Please provide an alias name of the developer key.'
+      print('Please provide an alias name of the developer key.')
       sys.exit(6)
     if options.keystore_passcode:
       key_code = options.keystore_passcode
     else:
-      print 'Please provide the passcode of the developer key.'
+      print('Please provide the passcode of the developer key.')
       sys.exit(6)
   else:
     print ('Use xwalk\'s keystore by default for debugging. '
@@ -252,26 +267,26 @@ def Execution(options, sanitized_name):
                                     'tools', 'lib', 'ant-tasks.jar')
   if not os.path.exists(ant_tasks_jar_path):
     ant_tasks_jar_path = os.path.join(sdk_root_path,
-                                      'tools', 'lib' ,'anttasks.jar')
+                                      'tools', 'lib''anttasks.jar')
 
   aapt_path = ''
   for aapt_str in AddExeExtensions('aapt'):
     try:
       aapt_path = Find(aapt_str, sdk_root_path)
-      print 'Use %s in %s.' % (aapt_str, sdk_root_path)
+      print('Use %s in %s.' % (aapt_str, sdk_root_path))
       break
     except Exception:
-      print 'There doesn\'t exist %s in %s.' % (aapt_str, sdk_root_path)
+      pass
   if not aapt_path:
-    print 'Your Android SDK may be ruined, please reinstall it.'
+    print('Your Android SDK may be ruined, please reinstall it.')
     sys.exit(2)
 
   # Check whether ant is installed.
   try:
     cmd = ['ant', '-version']
-    RunCommand(cmd, True)
+    RunCommand(cmd, shell=True)
   except EnvironmentError:
-    print 'Please install ant first.'
+    print('Please install ant first.')
     sys.exit(4)
 
   res_dirs = '-DADDITIONAL_RES_DIRS=\'\''
@@ -280,18 +295,23 @@ def Execution(options, sanitized_name):
   if options.mode == 'embedded':
     # Prepare the .pak file for embedded mode.
     pak_src_path = os.path.join('native_libs_res', 'xwalk.pak')
-    pak_des_path = os.path.join(sanitized_name, 'assets', 'xwalk.pak')
+    pak_des_path = os.path.join(name, 'assets', 'xwalk.pak')
     shutil.copy(pak_src_path, pak_des_path)
 
+    # Prepare the icudtl.dat for embedded mode.
+    icudtl_src_path = os.path.join('native_libs_res', 'icudtl.dat')
+    icudtl_des_path = os.path.join(name, 'assets', 'icudtl.dat')
+    shutil.copy(icudtl_src_path, icudtl_des_path)
+
     js_src_dir = os.path.join('native_libs_res', 'jsapi')
-    js_des_dir = os.path.join(sanitized_name, 'assets', 'jsapi')
+    js_des_dir = os.path.join(name, 'assets', 'jsapi')
     if os.path.exists(js_des_dir):
       shutil.rmtree(js_des_dir)
     shutil.copytree(js_src_dir, js_des_dir)
 
     res_ui_java = os.path.join('gen', 'ui_java')
     res_content_java = os.path.join('gen', 'content_java')
-    res_xwalk_java = os.path.join('gen', 'xwalk_core_java')
+    res_xwalk_java = os.path.join('gen', 'xwalk_core_internal_java')
     res_dirs = ('-DADDITIONAL_RES_DIRS='
                 + os.path.join(res_ui_java, 'res_crunched') + ' '
                 + os.path.join(res_ui_java, 'res_v14_compatibility') + ' '
@@ -306,14 +326,14 @@ def Execution(options, sanitized_name):
                 + os.path.join('libs_res', 'runtime') + ' '
                 + os.path.join(res_xwalk_java, 'res_grit'))
     res_packages = ('-DADDITIONAL_RES_PACKAGES=org.chromium.ui '
-                    'org.xwalk.core org.chromium.content')
+                    'org.xwalk.core.internal org.chromium.content')
     res_r_text_files = ('-DADDITIONAL_R_TEXT_FILES='
                         + os.path.join(res_ui_java, 'java_R', 'R.txt') + ' '
                         + os.path.join(res_xwalk_java, 'java_R', 'R.txt') + ' '
                         + os.path.join(res_content_java, 'java_R', 'R.txt'))
 
-  resource_dir = '-DRESOURCE_DIR=' + os.path.join(sanitized_name, 'res')
-  manifest_path = os.path.join(sanitized_name, 'AndroidManifest.xml')
+  resource_dir = '-DRESOURCE_DIR=' + os.path.join(name, 'res')
+  manifest_path = os.path.join(name, 'AndroidManifest.xml')
   cmd = ['python', os.path.join('scripts', 'gyp', 'ant.py'),
          '-DAAPT_PATH=%s' % aapt_path,
          res_dirs,
@@ -331,34 +351,33 @@ def Execution(options, sanitized_name):
          '-Dbasedir=.',
          '-buildfile',
          os.path.join('scripts', 'ant', 'apk-codegen.xml')]
-  RunCommand(cmd)
+  RunCommand(cmd, options.verbose)
 
   # Check whether java is installed.
   try:
     cmd = ['java', '-version']
-    RunCommand(cmd, True)
+    RunCommand(cmd, shell=True)
   except EnvironmentError:
-    print 'Please install Oracle JDK first.'
+    print('Please install Oracle JDK first.')
     sys.exit(5)
 
   # Compile App source code with app runtime code.
-  classpath = '--classpath='
-  classpath += os.path.join(os.getcwd(), 'libs',
-                            'xwalk_app_runtime_java.jar')
-  classpath += ' ' + sdk_jar_path
-  src_dirs = '--src-dirs=' + os.path.join(os.getcwd(), sanitized_name, 'src') +\
-             ' ' + os.path.join(os.getcwd(), 'out', 'gen')
   cmd = ['python', os.path.join('scripts', 'gyp', 'javac.py'),
          '--output-dir=%s' % os.path.join('out', 'classes'),
-         classpath,
-         src_dirs,
-         '--javac-includes=',
+         '--classpath',
+         os.path.join(os.getcwd(), 'libs', 'xwalk_app_runtime_java.jar'),
+         '--classpath',
+         sdk_jar_path,
+         '--src-dirs',
+         os.path.join(os.getcwd(), name, 'src'),
+         '--src-dirs',
+         os.path.join(os.getcwd(), 'out', 'gen'),
          '--chromium-code=0',
          '--stamp=compile.stam']
-  RunCommand(cmd)
+  RunCommand(cmd, options.verbose)
 
   # Package resources.
-  asset_dir = '-DASSET_DIR=%s' % os.path.join(sanitized_name, 'assets')
+  asset_dir = '-DASSET_DIR=%s' % os.path.join(name, 'assets')
   xml_path = os.path.join('scripts', 'ant', 'apk-package-resources.xml')
   cmd = ['python', os.path.join('scripts', 'gyp', 'ant.py'),
          '-DAAPT_PATH=%s' % aapt_path,
@@ -368,7 +387,7 @@ def Execution(options, sanitized_name):
          '-DANDROID_SDK_JAR=%s' % sdk_jar_path,
          '-DANDROID_SDK_ROOT=%s' % sdk_root_path,
          '-DANT_TASKS_JAR=%s' % ant_tasks_jar_path,
-         '-DAPK_NAME=%s' % sanitized_name,
+         '-DAPK_NAME=%s' % name,
          '-DAPP_MANIFEST_VERSION_CODE=0',
          '-DAPP_MANIFEST_VERSION_NAME=Developer Build',
          asset_dir,
@@ -379,7 +398,7 @@ def Execution(options, sanitized_name):
          '-Dbasedir=.',
          '-buildfile',
          xml_path]
-  RunCommand(cmd)
+  RunCommand(cmd, options.verbose)
 
   dex_path = '--dex-path=' + os.path.join(os.getcwd(), 'out', 'classes.dex')
   app_runtime_jar = os.path.join(os.getcwd(),
@@ -387,12 +406,12 @@ def Execution(options, sanitized_name):
 
   # Check whether external extensions are included.
   extensions_string = 'xwalk-extensions'
-  extensions_dir = os.path.join(os.getcwd(), sanitized_name, extensions_string)
+  extensions_dir = os.path.join(os.getcwd(), name, extensions_string)
   external_extension_jars = FindExtensionJars(extensions_dir)
   input_jars = []
   if options.mode == 'embedded':
     input_jars.append(os.path.join(os.getcwd(), 'libs',
-                                   'xwalk_core_embedded.dex.jar'))
+                                   'xwalk_runtime_embedded.dex.jar'))
   dex_command_list = ['python', os.path.join('scripts', 'gyp', 'dex.py'),
                       dex_path,
                       '--android-sdk-root=%s' % sdk_root_path,
@@ -402,7 +421,7 @@ def Execution(options, sanitized_name):
   dex_command_list.extend(input_jars)
   RunCommand(dex_command_list)
 
-  src_dir = '-DSOURCE_DIR=' + os.path.join(sanitized_name, 'src')
+  src_dir = '-DSOURCE_DIR=' + os.path.join(name, 'src')
   apk_path = '-DUNSIGNED_APK_PATH=' + os.path.join('out', 'app-unsigned.apk')
   native_lib_path = '-DNATIVE_LIBS_DIR='
   if options.mode == 'embedded':
@@ -412,7 +431,7 @@ def Execution(options, sanitized_name):
       if os.path.isfile(x86_native_lib_path):
         native_lib_path += os.path.join('native_libs', 'x86', 'libs')
       else:
-        print 'Missing x86 native library for Crosswalk embedded APK. Abort!'
+        print('Missing x86 native library for Crosswalk embedded APK. Abort!')
         sys.exit(10)
     elif options.arch == 'arm':
       arm_native_lib_path = os.path.join('native_libs', 'armeabi-v7a', 'libs',
@@ -420,14 +439,14 @@ def Execution(options, sanitized_name):
       if os.path.isfile(arm_native_lib_path):
         native_lib_path += os.path.join('native_libs', 'armeabi-v7a', 'libs')
       else:
-        print 'Missing ARM native library for Crosswalk embedded APK. Abort!'
+        print('Missing ARM native library for Crosswalk embedded APK. Abort!')
         sys.exit(10)
   # A space is needed for Windows.
   native_lib_path += ' '
   cmd = ['python', 'scripts/gyp/ant.py',
          '-DANDROID_SDK_ROOT=%s' % sdk_root_path,
          '-DANT_TASKS_JAR=%s' % ant_tasks_jar_path,
-         '-DAPK_NAME=%s' % sanitized_name,
+         '-DAPK_NAME=%s' % name,
          '-DCONFIGURATION_NAME=Release',
          native_lib_path,
          '-DOUT_DIR=out',
@@ -436,11 +455,11 @@ def Execution(options, sanitized_name):
          '-Dbasedir=.',
          '-buildfile',
          'scripts/ant/apk-package.xml']
-  RunCommand(cmd)
+  RunCommand(cmd, options.verbose)
 
   apk_path = '--unsigned-apk-path=' + os.path.join('out', 'app-unsigned.apk')
   final_apk_path = '--final-apk-path=' + \
-                   os.path.join('out', sanitized_name + '.apk')
+                   os.path.join('out', name + '.apk')
   cmd = ['python', 'scripts/gyp/finalize_apk.py',
          '--android-sdk-root=%s' % sdk_root_path,
          apk_path,
@@ -450,68 +469,104 @@ def Execution(options, sanitized_name):
          '--keystore-passcode=%s' % key_code]
   RunCommand(cmd)
 
-  src_file = os.path.join('out', sanitized_name + '.apk')
+  src_file = os.path.join('out', name + '.apk')
+  package_name = options.name
+  if options.app_version:
+    package_name += ('_' + options.app_version)
   if options.mode == 'shared':
-    dst_file = '%s.apk' % options.name
+    dst_file = os.path.join(options.target_dir, '%s.apk' % package_name)
   elif options.mode == 'embedded':
-    dst_file = '%s_%s.apk' % (options.name, options.arch)
+    dst_file = os.path.join(options.target_dir,
+                            '%s_%s.apk' % (package_name, options.arch))
   shutil.copyfile(src_file, dst_file)
   CleanDir('out')
   if options.mode == 'embedded':
     os.remove(pak_des_path)
 
 
-def MakeApk(options, sanitized_name):
-  Customize(options)
+def PrintPackageInfo(options, packaged_archs):
+  package_name_version = os.path.join(options.target_dir, options.name)
+  if options.app_version:
+    package_name_version += '_' + options.app_version
+
+  if len(packaged_archs) == 0:
+    print ('A non-platform specific APK for the web application "%s" was '
+           'generated successfully at\n%s.apk. It requires a shared Crosswalk '
+           'Runtime to be present.'
+           % (options.name, package_name_version))
+    return
+
+  for arch in packaged_archs:
+    print ('An APK for the web application "%s" including the Crosswalk '
+           'Runtime built for %s was generated successfully, which can be '
+           'found at\n%s_%s.apk.'
+           % (options.name, arch, package_name_version, arch))
+
+  all_archs = set(AllArchitectures())
+
+  if len(packaged_archs) != len(all_archs):
+    missed_archs = all_archs - set(packaged_archs)
+    print ('\n\nWARNING: ')
+    print ('This APK will only work on %s based Android devices. Consider '
+           'building for %s as well.' %
+           (', '.join(packaged_archs), ', '.join(missed_archs)))
+  else:
+    print ('\n\n%d APKs were created for %s devices. '
+           % (len(all_archs), ', '.join(all_archs)))
+    print ('Please install the one that matches the processor architecture '
+           'of your device.\n\n')
+    print ('If you are going to submit this application to an application '
+           'store, please make sure you submit both packages.\nInstructions '
+           'for submitting multiple APKs to Google Play Store are available '
+           'here:\nhttps://software.intel.com/en-us/html5/articles/submitting'
+           '-multiple-crosswalk-apk-to-google-play-store')
+
+def MakeApk(options, app_info):
+  Customize(options, app_info)
+  name = options.name
+  packaged_archs = []
   if options.mode == 'shared':
-    Execution(options, sanitized_name)
-    print ('The cross platform APK of the web application was '
-           'generated successfully at %s.apk, based on the shared '
-           'Crosswalk library.'
-           % sanitized_name)
+    Execution(options, name)
   elif options.mode == 'embedded':
     if options.arch:
-      Execution(options, sanitized_name)
-      print ('The Crosswalk embedded APK of web application "%s" for '
-             'platform %s was generated successfully at %s_%s.apk.'
-             % (sanitized_name, options.arch, sanitized_name, options.arch))
+      Execution(options, name)
+      packaged_archs.append(options.arch)
     else:
       # If the arch option is unspecified, all of available platform APKs
       # will be generated.
-      platform_str = ''
-      apk_str = ''
       valid_archs = ['x86', 'armeabi-v7a']
       for arch in valid_archs:
-        if os.path.isfile(os.path.join('native_libs', arch, 'libs',
-                                       arch, 'libxwalkcore.so')):
-          if platform_str != '':
-            platform_str += ' and '
-            apk_str += ' and '
+        lib_path = os.path.join('native_libs', arch, 'libs',
+                                arch, 'libxwalkcore.so')
+        if os.path.isfile(lib_path):
           if arch.find('x86') != -1:
             options.arch = 'x86'
           elif arch.find('arm') != -1:
             options.arch = 'arm'
-          platform_str += options.arch
-          apk_str += '%s_%s.apk' % (sanitized_name, options.arch)
-          Execution(options, sanitized_name)
-      if apk_str.find('and') != -1:
-        print ('The Crosswalk embedded APKs of web application "%s" for '
-               'platform %s were generated successfully at %s.'
-               % (sanitized_name, platform_str, apk_str))
-      else:
-        print ('The Crosswalk embedded APK of web application "%s" for '
-               'platform %s was generated successfully at %s.'
-               % (sanitized_name, platform_str, apk_str))
+          Execution(options, name)
+          packaged_archs.append(options.arch)
+        else:
+          print('Warning: failed to create package for arch "%s" '
+                'due to missing library %s' %
+                (arch, lib_path))
+
+      if len(packaged_archs) == 0:
+        print('No packages created, aborting')
+        sys.exit(13)
   else:
-    print 'Unknown mode for packaging the application. Abort!'
+    print('Unknown mode for packaging the application. Abort!')
     sys.exit(11)
 
+  PrintPackageInfo(options, packaged_archs)
 
 def main(argv):
   parser = optparse.OptionParser()
   parser.add_option('-v', '--version', action='store_true',
                     dest='version', default=False,
                     help='The version of this python tool.')
+  parser.add_option('--verbose', action="store_true",
+                    dest='verbose', default=False,
+                    help='Print debug messages.')
   info = ('The packaging mode of the web application. The value \'shared\' '
           'means that the runtime is shared across multiple application '
           'instances and that the runtime needs to be distributed separately. '
@@ -522,7 +577,7 @@ def main(argv):
   info = ('The target architecture of the embedded runtime. Supported values '
           'are \'x86\' and \'arm\'. Note, if undefined, APKs for all possible '
           'architestures will be generated.')
-  parser.add_option('--arch', help=info)
+  parser.add_option('--arch', choices=AllArchitectures(), help=info)
   group = optparse.OptionGroup(parser, 'Application Source Options',
       'This packaging tool supports 3 kinds of web application source: '
       '1) XPK package; 2) manifest.json; 3) various command line options, '
@@ -549,7 +604,7 @@ def main(argv):
   group = optparse.OptionGroup(parser, 'Mandatory arguments',
       'They are used for describing the APK information through '
       'command line options.')
-  info = ('The apk name. For example, --name=YourApplicationName')
+  info = ('The apk name. For example, --name="Your Application Name"')
   group.add_option('--name', help=info)
   info = ('The package name. For example, '
           '--package=com.example.YourPackage')
@@ -561,12 +616,24 @@ def main(argv):
   info = ('The version name of the application. '
           'For example, --app-version=1.0.0')
   group.add_option('--app-version', help=info)
+  info = ('The version code of the application. '
+          'For example, --app-versionCode=24')
+  group.add_option('--app-versionCode', type='int', help=info)
+  info = ('The version code base of the application. Version code will '
+          'be made by adding a prefix based on architecture to the version '
+          'code base. For example, --app-versionCodeBase=24')
+  group.add_option('--app-versionCodeBase', type='int', help=info)
+  info = ('Use command lines.'
+          'Crosswalk is powered by Chromium and supports Chromium command line.'
+          'For example, '
+          '--xwalk-command-line=\'--chromium-command-1 --xwalk-command-2\'')
+  group.add_option('--xwalk-command-line', default='', help=info)
   info = ('The description of the application. For example, '
           '--description=YourApplicationDescription')
   group.add_option('--description', help=info)
   group.add_option('--enable-remote-debugging', action='store_true',
-                    dest='enable_remote_debugging', default=False,
-                    help = 'Enable remote debugging.')
+                   dest='enable_remote_debugging', default=False,
+                   help='Enable remote debugging.')
   info = ('The list of external extension paths splitted by OS separators. '
           'The separators are \':\' , \';\' and \':\' on Linux, Windows and '
           'Mac OS respectively. For example, '
@@ -575,6 +642,8 @@ def main(argv):
   group.add_option('-f', '--fullscreen', action='store_true',
                    dest='fullscreen', default=False,
                    help='Make application fullscreen.')
+  group.add_option('--keep-screen-on', action='store_true', default=False,
+                   help='Support keeping screen on')
   info = ('The path of application icon. '
           'Such as: --icon=/path/to/your/customized/icon')
   group.add_option('--icon', help=info)
@@ -587,6 +656,8 @@ def main(argv):
   info = ('The list of permissions to be used by web application. For example, '
           '--permissions=geolocation:webgl')
   group.add_option('--permissions', help=info)
+  info = ('Packaging tool will move the output APKS to the target directory')
+  group.add_option('--target-dir', default=os.getcwd(), help=info)
   parser.add_option_group(group)
   group = optparse.OptionGroup(parser, 'Keystore Options',
       'The keystore is a signature from web developer, it\'s used when '
@@ -598,6 +669,13 @@ def main(argv):
   group.add_option('--keystore-alias', help=info)
   info = ('The passcode of keystore. For example, --keystore-passcode=code')
   group.add_option('--keystore-passcode', help=info)
+  info = ('Minify and obfuscate javascript and css.'
+          '--compressor: compress javascript and css.'
+          '--compressor=js: compress javascript.'
+          '--compressor=css: compress css.')
+  group.add_option('--compressor', dest='compressor', action='callback',
+                   callback=ParseParameterForCompressor, type='string',
+                   nargs=0, help=info)
   parser.add_option_group(group)
   options, _ = parser.parse_args()
   if len(argv) == 1:
@@ -606,7 +684,7 @@ def main(argv):
 
   if options.version:
     if os.path.isfile('VERSION'):
-      print GetVersion('VERSION')
+      print(GetVersion('VERSION'))
       return 0
     else:
       parser.error('Can\'t get version due to the VERSION file missing!')
@@ -623,15 +701,25 @@ def main(argv):
       print('Using manifest.json distributed with the application.')
       options.manifest = manifest_path
 
+  app_info = AppInfo()
   if not options.manifest:
-    if not options.package:
+    if options.package:
+      VerifyAppName(options.package, 'packagename')
+    else:
       parser.error('The package name is required! '
                    'Please use "--package" option.')
-    if not options.name:
-      parser.error('The APK name is required! Pleaes use "--name" option.')
-    if not ((options.app_url and not options.app_root
-        and not options.app_local_path) or ((not options.app_url)
-            and options.app_root and options.app_local_path)):
+    if options.name:
+      VerifyAppName(options.name)
+      app_info.original_name = options.name
+      options.name = ReplaceSpaceWithUnderscore(options.name)
+    else:
+      parser.error('The APK name is required! Please use "--name" option.')
+    if not ((options.app_url and
+             not options.app_root and
+             not options.app_local_path) or
+            (not options.app_url and
+             options.app_root and
+             options.app_local_path)):
       parser.error('The entry is required. If the entry is a remote url, '
                    'please use "--app-url" option; If the entry is local, '
                    'please use "--app-root" and '
@@ -639,29 +727,37 @@ def main(argv):
     if options.permissions:
       permission_list = options.permissions.split(':')
     else:
-      print ('Warning: all supported permissions on Android port are added. '
-             'Refer to https://github.com/crosswalk-project/'
-             'crosswalk-website/wiki/Crosswalk-manifest')
+      print('Warning: all supported permissions on Android port are added. '
+            'Refer to https://github.com/crosswalk-project/'
+            'crosswalk-website/wiki/Crosswalk-manifest')
       permission_list = permission_mapping_table.keys()
     options.permissions = HandlePermissionList(permission_list)
-
+    options.icon_dict = {}
   else:
     try:
-      ParseManifest(options)
-    except SystemExit, ec:
+      ParseManifest(options, app_info)
+    except SystemExit as ec:
       return ec.code
 
-  options.name = ReplaceInvalidChars(options.name, 'apkname')
-  options.package = ReplaceInvalidChars(options.package)
-  sanitized_name = ReplaceInvalidChars(options.name)
+  if (options.app_root and options.app_local_path and
+      not os.path.isfile(os.path.join(options.app_root,
+                                      options.app_local_path))):
+    print('Please make sure that the local path file of launching app '
+          'does exist.')
+    sys.exit(7)
+
+  if options.target_dir:
+    target_dir = os.path.abspath(os.path.expanduser(options.target_dir))
+    options.target_dir = target_dir
+    if not os.path.isdir(target_dir):
+      os.makedirs(target_dir)
 
   try:
-    MakeApk(options, sanitized_name)
-  except SystemExit, ec:
-    CleanDir(sanitized_name)
+    MakeApk(options, app_info)
+  except SystemExit as ec:
+    CleanDir(options.name)
     CleanDir('out')
-    if os.path.exists(xpk_temp_dir):
-      CleanDir(xpk_temp_dir)
+    CleanDir(xpk_temp_dir)
     return ec.code
   return 0