1#!/usr/bin/python2.4
2#
3#
4# Copyright 2009, The Android Open Source Project
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#     http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17
18"""In memory representation of AndroidManifest.xml file.
19
20Specification of AndroidManifest.xml can be found at
21http://developer.android.com/guide/topics/manifest/manifest-intro.html
22"""
23
24# python imports
25import os
26import xml.dom.minidom
27import xml.parsers
28
29
30class AndroidManifest(object):
31  """In memory representation of AndroidManifest.xml file."""
32
33  FILENAME = 'AndroidManifest.xml'
34
35  def __init__(self, app_path=None):
36    if app_path:
37      self._ParseManifest(app_path)
38
39  def GetAppPath(self):
40    """Retrieve file system path to this manifest file's directory."""
41    return self._app_path
42
43  def GetPackageName(self):
44    """Retrieve package name defined at <manifest package="...">.
45
46    Returns:
47      Package name if defined, otherwise None
48    """
49    manifest = self._GetManifestElement()
50    if not manifest or not manifest.hasAttribute('package'):
51      return None
52    return manifest.getAttribute('package')
53
54  def _ParseManifest(self, app_path):
55    """Parse AndroidManifest.xml at the specified path.
56
57    Args:
58      app_path: path to folder containing AndroidManifest.xml
59    Raises:
60      IOError: AndroidManifest.xml cannot be found at given path, or cannot be
61          opened for reading
62    """
63    self._app_path = app_path
64    self._manifest_path = os.path.join(app_path, self.FILENAME)
65    self._dom = xml.dom.minidom.parse(self._manifest_path)
66
67  def AddUsesSdk(self, min_sdk_version):
68    """Adds a uses-sdk element to manifest.
69
70    Args:
71      min_sdk_version: value to provide for minSdkVersion attribute.
72    """
73    manifest = self._GetManifestElement()
74    uses_sdk_elements = manifest.getElementsByTagName('uses-sdk')
75    if uses_sdk_elements:
76      uses_sdk_element = uses_sdk_elements[0]
77    else:
78      uses_sdk_element = self._dom.createElement('uses-sdk')
79      manifest.appendChild(uses_sdk_element)
80
81    uses_sdk_element.setAttribute('android:minSdkVersion', min_sdk_version)
82    self._SaveXml()
83
84  def GetInstrumentationNames(self):
85    """Get the instrumentation names from manifest.
86
87    Returns:
88      list of names, might be empty
89    """
90    instr_elements = self._dom.getElementsByTagName('instrumentation')
91    instrs = []
92    for element in instr_elements:
93      instrs.append(element.getAttribute('android:name'))
94    return instrs
95
96  def _GetManifestElement(self):
97    """Retrieve the root manifest element.
98
99    Returns:
100      the DOM element for manifest or None.
101    """
102    manifests = self._dom.getElementsByTagName('manifest')
103    if not manifests:
104      return None
105    return manifests[0]
106
107  def _SaveXml(self):
108    """Saves the manifest to disk."""
109    self._dom.writexml(open(self._manifest_path, mode='w'), encoding='utf-8')
110
111
112def CreateAndroidManifest(path):
113  """Factory method for creating a AndroidManifest.
114
115  Args:
116    path: the directory for the manifest file
117
118  Return:
119    the AndroidManifest or None if there was no file present
120  """
121  manifest_path = os.path.join(path, AndroidManifest.FILENAME)
122  if os.path.isfile(manifest_path):
123    manifest = AndroidManifest()
124    manifest._ParseManifest(path)
125    return manifest
126  else:
127    return None
128