Home | History | Annotate | Download | only in xml
      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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    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      */
    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