• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.sdklib.xml;
18 
19 import com.android.sdklib.SdkConstants;
20 import com.android.sdklib.io.IAbstractFile;
21 import com.android.sdklib.io.IAbstractFolder;
22 import com.android.sdklib.io.StreamException;
23 
24 import org.w3c.dom.Node;
25 import org.xml.sax.InputSource;
26 
27 import javax.xml.xpath.XPath;
28 import javax.xml.xpath.XPathConstants;
29 import javax.xml.xpath.XPathExpressionException;
30 
31 /**
32  * Helper and Constants for the AndroidManifest.xml file.
33  *
34  */
35 public final class AndroidManifest {
36 
37     public final static String NODE_MANIFEST = "manifest";
38     public final static String NODE_APPLICATION = "application";
39     public final static String NODE_ACTIVITY = "activity";
40     public final static String NODE_SERVICE = "service";
41     public final static String NODE_RECEIVER = "receiver";
42     public final static String NODE_PROVIDER = "provider";
43     public final static String NODE_INTENT = "intent-filter";
44     public final static String NODE_ACTION = "action";
45     public final static String NODE_CATEGORY = "category";
46     public final static String NODE_USES_SDK = "uses-sdk";
47     public final static String NODE_INSTRUMENTATION = "instrumentation";
48     public final static String NODE_USES_LIBRARY = "uses-library";
49     public final static String NODE_SUPPORTS_SCREENS = "supports-screens";
50     public final static String NODE_USES_CONFIGURATION = "uses-configuration";
51     public final static String NODE_USES_FEATURE = "uses-feature";
52 
53     public final static String ATTRIBUTE_PACKAGE = "package";
54     public final static String ATTRIBUTE_VERSIONCODE = "versionCode";
55     public final static String ATTRIBUTE_NAME = "name";
56     public final static String ATTRIBUTE_REQUIRED = "required";
57     public final static String ATTRIBUTE_GLESVERSION = "glEsVersion";
58     public final static String ATTRIBUTE_PROCESS = "process";
59     public final static String ATTRIBUTE_DEBUGGABLE = "debuggable";
60     public final static String ATTRIBUTE_MIN_SDK_VERSION = "minSdkVersion";
61     public final static String ATTRIBUTE_TARGET_SDK_VERSION = "targetSdkVersion";
62     public final static String ATTRIBUTE_TARGET_PACKAGE = "targetPackage";
63     public final static String ATTRIBUTE_EXPORTED = "exported";
64     public final static String ATTRIBUTE_RESIZEABLE = "resizeable";
65     public final static String ATTRIBUTE_ANYDENSITY = "anyDensity";
66     public final static String ATTRIBUTE_SMALLSCREENS = "smallScreens";
67     public final static String ATTRIBUTE_NORMALSCREENS = "normalScreens";
68     public final static String ATTRIBUTE_LARGESCREENS = "largeScreens";
69     public final static String ATTRIBUTE_REQ_5WAYNAV = "reqFiveWayNav";
70     public final static String ATTRIBUTE_REQ_NAVIGATION = "reqNavigation";
71     public final static String ATTRIBUTE_REQ_HARDKEYBOARD = "reqHardKeyboard";
72     public final static String ATTRIBUTE_REQ_KEYBOARDTYPE = "reqKeyboardType";
73     public final static String ATTRIBUTE_REQ_TOUCHSCREEN = "reqTouchScreen";
74 
75     /**
76      * Returns the package for a given project.
77      * @param projectFolder the folder of the project.
78      * @return the package info or null (or empty) if not found.
79      * @throws XPathExpressionException
80      * @throws StreamException If any error happens when reading the manifest.
81      */
getPackage(IAbstractFolder projectFolder)82     public static String getPackage(IAbstractFolder projectFolder)
83             throws XPathExpressionException, StreamException {
84         IAbstractFile file = projectFolder.getFile(SdkConstants.FN_ANDROID_MANIFEST_XML);
85         return getPackage(file);
86     }
87 
88     /**
89      * Returns the package for a given manifest.
90      * @param manifestFile the manifest to parse.
91      * @return the package info or null (or empty) if not found.
92      * @throws XPathExpressionException
93      * @throws StreamException If any error happens when reading the manifest.
94      */
getPackage(IAbstractFile manifestFile)95     public static String getPackage(IAbstractFile manifestFile)
96             throws XPathExpressionException, StreamException {
97         XPath xPath = AndroidXPathFactory.newXPath();
98 
99         return xPath.evaluate(
100                 "/"  + NODE_MANIFEST +
101                 "/@" + ATTRIBUTE_PACKAGE,
102                 new InputSource(manifestFile.getContents()));
103     }
104 
105     /**
106      * Returns the value of the versionCode attribute or -1 if the value is not set.
107      * @param manifestFile the manifest file to read the attribute from.
108      * @return the integer value or -1 if not set.
109      * @throws XPathExpressionException
110      * @throws StreamException If any error happens when reading the manifest.
111      */
getVersionCode(IAbstractFile manifestFile)112     public static int getVersionCode(IAbstractFile manifestFile)
113             throws XPathExpressionException, StreamException {
114         XPath xPath = AndroidXPathFactory.newXPath();
115 
116         String result = xPath.evaluate(
117                 "/"  + NODE_MANIFEST +
118                 "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX +
119                 ":"  + ATTRIBUTE_VERSIONCODE,
120                 new InputSource(manifestFile.getContents()));
121 
122         try {
123             return Integer.parseInt(result);
124         } catch (NumberFormatException e) {
125             return -1;
126         }
127     }
128 
129     /**
130      * Returns whether the version Code attribute is set in a given manifest.
131      * @param manifestFile the manifest to check
132      * @return true if the versionCode attribute is present and its value is not empty.
133      * @throws XPathExpressionException
134      * @throws StreamException If any error happens when reading the manifest.
135      */
hasVersionCode(IAbstractFile manifestFile)136     public static boolean hasVersionCode(IAbstractFile manifestFile)
137             throws XPathExpressionException, StreamException {
138         XPath xPath = AndroidXPathFactory.newXPath();
139 
140         Object result = xPath.evaluate(
141                 "/"  + NODE_MANIFEST +
142                 "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX +
143                 ":"  + ATTRIBUTE_VERSIONCODE,
144                 new InputSource(manifestFile.getContents()),
145                 XPathConstants.NODE);
146 
147         if (result != null) {
148             Node node  = (Node)result;
149             if (node.getNodeValue().length() > 0) {
150                 return true;
151             }
152         }
153 
154         return false;
155     }
156 
157     /**
158      * Returns the value of the minSdkVersion attribute (defaults to 1 if the attribute is not set),
159      * or -1 if the value is a codename.
160      * @param manifestFile the manifest file to read the attribute from.
161      * @return the integer value or -1 if not set.
162      * @throws XPathExpressionException
163      * @throws StreamException If any error happens when reading the manifest.
164      */
getMinSdkVersion(IAbstractFile manifestFile)165     public static int getMinSdkVersion(IAbstractFile manifestFile)
166             throws XPathExpressionException, StreamException {
167         XPath xPath = AndroidXPathFactory.newXPath();
168 
169         String result = xPath.evaluate(
170                 "/"  + NODE_MANIFEST +
171                 "/"  + NODE_USES_SDK +
172                 "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX +
173                 ":"  + ATTRIBUTE_MIN_SDK_VERSION,
174                 new InputSource(manifestFile.getContents()));
175 
176         try {
177             return Integer.parseInt(result);
178         } catch (NumberFormatException e) {
179             return result.length() > 0 ? -1 : 1;
180         }
181     }
182 
183 
184     /**
185      * Combines a java package, with a class value from the manifest to make a fully qualified
186      * class name
187      * @param javaPackage the java package from the manifest.
188      * @param className the class name from the manifest.
189      * @return the fully qualified class name.
190      */
combinePackageAndClassName(String javaPackage, String className)191     public static String combinePackageAndClassName(String javaPackage, String className) {
192         if (className == null || className.length() == 0) {
193             return javaPackage;
194         }
195         if (javaPackage == null || javaPackage.length() == 0) {
196             return className;
197         }
198 
199         // the class name can be a subpackage (starts with a '.'
200         // char), a simple class name (no dot), or a full java package
201         boolean startWithDot = (className.charAt(0) == '.');
202         boolean hasDot = (className.indexOf('.') != -1);
203         if (startWithDot || hasDot == false) {
204 
205             // add the concatenation of the package and class name
206             if (startWithDot) {
207                 return javaPackage + className;
208             } else {
209                 return javaPackage + '.' + className;
210             }
211         } else {
212             // just add the class as it should be a fully qualified java name.
213             return className;
214         }
215     }
216 
217     /**
218      * Given a fully qualified activity name (e.g. com.foo.test.MyClass) and given a project
219      * package base name (e.g. com.foo), returns the relative activity name that would be used
220      * the "name" attribute of an "activity" element.
221      *
222      * @param fullActivityName a fully qualified activity class name, e.g. "com.foo.test.MyClass"
223      * @param packageName The project base package name, e.g. "com.foo"
224      * @return The relative activity name if it can be computed or the original fullActivityName.
225      */
extractActivityName(String fullActivityName, String packageName)226     public static String extractActivityName(String fullActivityName, String packageName) {
227         if (packageName != null && fullActivityName != null) {
228             if (packageName.length() > 0 && fullActivityName.startsWith(packageName)) {
229                 String name = fullActivityName.substring(packageName.length());
230                 if (name.length() > 0 && name.charAt(0) == '.') {
231                     return name;
232                 }
233             }
234         }
235 
236         return fullActivityName;
237     }
238 }
239