• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2#
3# Copyright 2014 The Chromium Authors. 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# pylint: disable=C0301
8"""Package resources into an apk.
9
10See https://android.googlesource.com/platform/tools/base/+/master/legacy/ant-tasks/src/main/java/com/android/ant/AaptExecTask.java
11and
12https://android.googlesource.com/platform/sdk/+/master/files/ant/build.xml
13"""
14# pylint: enable=C0301
15
16import optparse
17import os
18import shutil
19
20from util import build_utils
21
22def ParseArgs():
23  """Parses command line options.
24
25  Returns:
26    An options object as from optparse.OptionsParser.parse_args()
27  """
28  parser = optparse.OptionParser()
29  build_utils.AddDepfileOption(parser)
30  parser.add_option('--android-sdk', help='path to the Android SDK folder')
31  parser.add_option('--android-sdk-tools',
32                    help='path to the Android SDK build tools folder')
33
34  parser.add_option('--configuration-name',
35                    help='Gyp\'s configuration name (Debug or Release).')
36
37  parser.add_option('--android-manifest', help='AndroidManifest.xml path')
38  parser.add_option('--version-code', help='Version code for apk.')
39  parser.add_option('--version-name', help='Version name for apk.')
40  parser.add_option('--resource-zips',
41                    help='zip files containing resources to be packaged')
42  parser.add_option('--asset-dir',
43                    help='directories containing assets to be packaged')
44  parser.add_option('--no-compress', help='disables compression for the '
45                    'given comma separated list of extensions')
46
47  parser.add_option('--apk-path',
48                    help='Path to output (partial) apk.')
49
50  (options, args) = parser.parse_args()
51
52  if args:
53    parser.error('No positional arguments should be given.')
54
55  # Check that required options have been provided.
56  required_options = ('android_sdk', 'android_sdk_tools', 'configuration_name',
57                      'android_manifest', 'version_code', 'version_name',
58                      'resource_zips', 'asset_dir', 'apk_path')
59
60  build_utils.CheckOptions(options, parser, required=required_options)
61
62  return options
63
64
65def MoveImagesToNonMdpiFolders(res_root):
66  """Move images from drawable-*-mdpi-* folders to drawable-* folders.
67
68  Why? http://crbug.com/289843
69  """
70  for src_dir_name in os.listdir(res_root):
71    src_components = src_dir_name.split('-')
72    if src_components[0] != 'drawable' or 'mdpi' not in src_components:
73      continue
74    src_dir = os.path.join(res_root, src_dir_name)
75    if not os.path.isdir(src_dir):
76      continue
77    dst_components = [c for c in src_components if c != 'mdpi']
78    assert dst_components != src_components
79    dst_dir_name = '-'.join(dst_components)
80    dst_dir = os.path.join(res_root, dst_dir_name)
81    build_utils.MakeDirectory(dst_dir)
82    for src_file_name in os.listdir(src_dir):
83      if not src_file_name.endswith('.png'):
84        continue
85      src_file = os.path.join(src_dir, src_file_name)
86      dst_file = os.path.join(dst_dir, src_file_name)
87      assert not os.path.lexists(dst_file)
88      shutil.move(src_file, dst_file)
89
90
91def PackageArgsForExtractedZip(d):
92  """Returns the aapt args for an extracted resources zip.
93
94  A resources zip either contains the resources for a single target or for
95  multiple targets. If it is multiple targets merged into one, the actual
96  resource directories will be contained in the subdirectories 0, 1, 2, ...
97  """
98  res_dirs = []
99  subdirs = [os.path.join(d, s) for s in os.listdir(d)]
100  subdirs = sorted([s for s in subdirs if os.path.isdir(s)])
101  if subdirs and os.path.basename(subdirs[0]) == '0':
102    res_dirs = subdirs
103  else:
104    res_dirs = [d]
105  package_command = []
106  for d in res_dirs:
107    MoveImagesToNonMdpiFolders(d)
108    package_command += ['-S', d]
109  return package_command
110
111
112def main():
113  options = ParseArgs()
114  android_jar = os.path.join(options.android_sdk, 'android.jar')
115  aapt = os.path.join(options.android_sdk_tools, 'aapt')
116
117  with build_utils.TempDir() as temp_dir:
118    package_command = [aapt,
119                       'package',
120                       '--version-code', options.version_code,
121                       '--version-name', options.version_name,
122                       '-M', options.android_manifest,
123                       '--no-crunch',
124                       '-f',
125                       '--auto-add-overlay',
126
127                       '-I', android_jar,
128                       '-F', options.apk_path,
129                       ]
130
131    if options.no_compress:
132      for ext in options.no_compress.split(','):
133        package_command += ['-0', ext]
134
135    if os.path.exists(options.asset_dir):
136      package_command += ['-A', options.asset_dir]
137
138    dep_zips = build_utils.ParseGypList(options.resource_zips)
139    for z in dep_zips:
140      subdir = os.path.join(temp_dir, os.path.basename(z))
141      if os.path.exists(subdir):
142        raise Exception('Resource zip name conflict: ' + os.path.basename(z))
143      build_utils.ExtractAll(z, path=subdir)
144      package_command += PackageArgsForExtractedZip(subdir)
145
146    if 'Debug' in options.configuration_name:
147      package_command += ['--debug-mode']
148
149    build_utils.CheckOutput(
150        package_command, print_stdout=False, print_stderr=False)
151
152    if options.depfile:
153      build_utils.WriteDepfile(
154          options.depfile,
155          build_utils.GetPythonDependencies())
156
157
158if __name__ == '__main__':
159  main()
160