Home | History | Annotate | Download | only in repository
      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.internal.repository;
     18 
     19 import com.android.annotations.VisibleForTesting;
     20 import com.android.annotations.VisibleForTesting.Visibility;
     21 import com.android.sdklib.AndroidVersion;
     22 import com.android.sdklib.IAndroidTarget;
     23 import com.android.sdklib.SdkConstants;
     24 import com.android.sdklib.SdkManager;
     25 import com.android.sdklib.internal.repository.Archive.Arch;
     26 import com.android.sdklib.internal.repository.Archive.Os;
     27 import com.android.sdklib.repository.PkgProps;
     28 import com.android.sdklib.repository.SdkRepoConstants;
     29 import com.android.util.Pair;
     30 
     31 import org.w3c.dom.Node;
     32 
     33 import java.io.File;
     34 import java.util.Map;
     35 import java.util.Properties;
     36 
     37 /**
     38  * Represents a platform XML node in an SDK repository.
     39  */
     40 public class PlatformPackage extends MinToolsPackage implements IPackageVersion, ILayoutlibVersion {
     41 
     42     /** The package version, for platform, add-on and doc packages. */
     43     private final AndroidVersion mVersion;
     44 
     45     /** The version, a string, for platform packages. */
     46     private final String mVersionName;
     47 
     48     /** The ABI of the system-image included in this platform. Can be null but not empty. */
     49     private final String mIncludedAbi;
     50 
     51     /** The helper handling the layoutlib version. */
     52     private final LayoutlibVersionMixin mLayoutlibVersion;
     53 
     54     /**
     55      * Creates a new platform package from the attributes and elements of the given XML node.
     56      * This constructor should throw an exception if the package cannot be created.
     57      *
     58      * @param source The {@link SdkSource} where this is loaded from.
     59      * @param packageNode The XML element being parsed.
     60      * @param nsUri The namespace URI of the originating XML document, to be able to deal with
     61      *          parameters that vary according to the originating XML schema.
     62      * @param licenses The licenses loaded from the XML originating document.
     63      */
     64     PlatformPackage(SdkSource source, Node packageNode, String nsUri, Map<String,String> licenses) {
     65         super(source, packageNode, nsUri, licenses);
     66 
     67         mVersionName = XmlParserUtils.getXmlString(packageNode, SdkRepoConstants.NODE_VERSION);
     68 
     69         int apiLevel = XmlParserUtils.getXmlInt   (packageNode, SdkRepoConstants.NODE_API_LEVEL, 0);
     70         String codeName = XmlParserUtils.getXmlString(packageNode, SdkRepoConstants.NODE_CODENAME);
     71         if (codeName.length() == 0) {
     72             codeName = null;
     73         }
     74         mVersion = new AndroidVersion(apiLevel, codeName);
     75 
     76         mIncludedAbi = XmlParserUtils.getOptionalXmlString(
     77                 packageNode, SdkRepoConstants.NODE_ABI_INCLUDED);
     78 
     79         mLayoutlibVersion = new LayoutlibVersionMixin(packageNode);
     80     }
     81 
     82     /**
     83      * Creates a new platform package based on an actual {@link IAndroidTarget} (which
     84      * must have {@link IAndroidTarget#isPlatform()} true) from the {@link SdkManager}.
     85      * This is used to list local SDK folders in which case there is one archive which
     86      * URL is the actual target location.
     87      * <p/>
     88      * By design, this creates a package with one and only one archive.
     89      */
     90     static Package create(IAndroidTarget target, Properties props) {
     91         return new PlatformPackage(target, props);
     92     }
     93 
     94     @VisibleForTesting(visibility=Visibility.PRIVATE)
     95     protected PlatformPackage(IAndroidTarget target, Properties props) {
     96         this(null /*source*/, target, props);
     97     }
     98 
     99     @VisibleForTesting(visibility=Visibility.PRIVATE)
    100     protected PlatformPackage(SdkSource source, IAndroidTarget target, Properties props) {
    101         super(  source,                     //source
    102                 props,                      //properties
    103                 target.getRevision(),       //revision
    104                 null,                       //license
    105                 target.getDescription(),    //description
    106                 null,                       //descUrl
    107                 Os.getCurrentOs(),          //archiveOs
    108                 Arch.getCurrentArch(),      //archiveArch
    109                 target.getLocation()        //archiveOsPath
    110                 );
    111 
    112         mVersion = target.getVersion();
    113         mVersionName  = target.getVersionName();
    114         mLayoutlibVersion = new LayoutlibVersionMixin(props);
    115         mIncludedAbi = props == null ? null : props.getProperty(PkgProps.PLATFORM_INCLUDED_ABI);
    116     }
    117 
    118     /**
    119      * Save the properties of the current packages in the given {@link Properties} object.
    120      * These properties will later be given to a constructor that takes a {@link Properties} object.
    121      */
    122     @Override
    123     void saveProperties(Properties props) {
    124         super.saveProperties(props);
    125 
    126         mVersion.saveProperties(props);
    127         mLayoutlibVersion.saveProperties(props);
    128 
    129         if (mVersionName != null) {
    130             props.setProperty(PkgProps.PLATFORM_VERSION, mVersionName);
    131         }
    132 
    133         if (mIncludedAbi != null) {
    134             props.setProperty(PkgProps.PLATFORM_INCLUDED_ABI, mIncludedAbi);
    135         }
    136 
    137     }
    138 
    139     /** Returns the version, a string, for platform packages. */
    140     public String getVersionName() {
    141         return mVersionName;
    142     }
    143 
    144     /** Returns the package version, for platform, add-on and doc packages. */
    145     public AndroidVersion getVersion() {
    146         return mVersion;
    147     }
    148 
    149     /**
    150      * Returns the ABI of the system-image included in this platform.
    151      *
    152      * @return Null if the platform does not include any system-image.
    153      *  Otherwise should be a valid non-empty ABI string (e.g. "x86" or "armeabi-v7a").
    154      */
    155     public String getIncludedAbi() {
    156         return mIncludedAbi;
    157     }
    158 
    159     /**
    160      * Returns the layoutlib version. Mandatory starting with repository XSD rev 4.
    161      * <p/>
    162      * The first integer is the API of layoublib, which should be > 0.
    163      * It will be equal to {@link ILayoutlibVersion#LAYOUTLIB_API_NOT_SPECIFIED} (0)
    164      * if the layoutlib version isn't specified.
    165      * <p/>
    166      * The second integer is the revision for that given API. It is >= 0
    167      * and works as a minor revision number, incremented for the same API level.
    168      *
    169      * @since sdk-repository-4.xsd
    170      */
    171     public Pair<Integer, Integer> getLayoutlibVersion() {
    172         return mLayoutlibVersion.getLayoutlibVersion();
    173     }
    174 
    175     /**
    176      * Returns a string identifier to install this package from the command line.
    177      * For platforms, we use "android-N" where N is the API or the preview codename.
    178      * <p/>
    179      * {@inheritDoc}
    180      */
    181     @Override
    182     public String installId() {
    183         return "android-" + mVersion.getApiString();    //$NON-NLS-1$
    184     }
    185 
    186     /**
    187      * Returns a description of this package that is suitable for a list display.
    188      * <p/>
    189      * {@inheritDoc}
    190      */
    191     @Override
    192     public String getListDescription() {
    193         String s;
    194 
    195         if (mVersion.isPreview()) {
    196             s = String.format("SDK Platform Android %1$s Preview%2$s",
    197                     getVersionName(),
    198                     isObsolete() ? " (Obsolete)" : "");  //$NON-NLS-2$
    199         } else {
    200             s = String.format("SDK Platform Android %1$s%2$s",
    201                 getVersionName(),
    202                 isObsolete() ? " (Obsolete)" : "");      //$NON-NLS-2$
    203         }
    204 
    205         return s;
    206     }
    207 
    208     /**
    209      * Returns a short description for an {@link IDescription}.
    210      */
    211     @Override
    212     public String getShortDescription() {
    213         String s;
    214 
    215         if (mVersion.isPreview()) {
    216             s = String.format("SDK Platform Android %1$s Preview, revision %2$s%3$s",
    217                     getVersionName(),
    218                     getRevision(),
    219                     isObsolete() ? " (Obsolete)" : "");  //$NON-NLS-2$
    220         } else {
    221             s = String.format("SDK Platform Android %1$s, API %2$d, revision %3$s%4$s",
    222                 getVersionName(),
    223                 mVersion.getApiLevel(),
    224                 getRevision(),
    225                 isObsolete() ? " (Obsolete)" : "");      //$NON-NLS-2$
    226         }
    227 
    228         return s;
    229     }
    230 
    231     /**
    232      * Returns a long description for an {@link IDescription}.
    233      *
    234      * The long description is whatever the XML contains for the &lt;description&gt; field,
    235      * or the short description if the former is empty.
    236      */
    237     @Override
    238     public String getLongDescription() {
    239         String s = getDescription();
    240         if (s == null || s.length() == 0) {
    241             s = getShortDescription();
    242         }
    243 
    244         if (s.indexOf("revision") == -1) {
    245             s += String.format("\nRevision %1$d%2$s",
    246                     getRevision(),
    247                     isObsolete() ? " (Obsolete)" : "");
    248         }
    249 
    250         return s;
    251     }
    252 
    253     /**
    254      * Computes a potential installation folder if an archive of this package were
    255      * to be installed right away in the given SDK root.
    256      * <p/>
    257      * A platform package is typically installed in SDK/platforms/android-"version".
    258      * However if we can find a different directory under SDK/platform that already
    259      * has this platform version installed, we'll use that one.
    260      *
    261      * @param osSdkRoot The OS path of the SDK root folder.
    262      * @param sdkManager An existing SDK manager to list current platforms and addons.
    263      * @return A new {@link File} corresponding to the directory to use to install this package.
    264      */
    265     @Override
    266     public File getInstallFolder(String osSdkRoot, SdkManager sdkManager) {
    267 
    268         // First find if this platform is already installed. If so, reuse the same directory.
    269         for (IAndroidTarget target : sdkManager.getTargets()) {
    270             if (target.isPlatform() && target.getVersion().equals(mVersion)) {
    271                 return new File(target.getLocation());
    272             }
    273         }
    274 
    275         File platforms = new File(osSdkRoot, SdkConstants.FD_PLATFORMS);
    276         File folder = new File(platforms,
    277                 String.format("android-%s", getVersion().getApiString())); //$NON-NLS-1$
    278 
    279         return folder;
    280     }
    281 
    282     @Override
    283     public boolean sameItemAs(Package pkg) {
    284         if (pkg instanceof PlatformPackage) {
    285             PlatformPackage newPkg = (PlatformPackage)pkg;
    286 
    287             // check they are the same version.
    288             return newPkg.getVersion().equals(this.getVersion());
    289         }
    290 
    291         return false;
    292     }
    293 
    294     @Override
    295     public int hashCode() {
    296         final int prime = 31;
    297         int result = super.hashCode();
    298         result = prime * result +
    299                     ((mLayoutlibVersion == null) ? 0 : mLayoutlibVersion.hashCode());
    300         result = prime * result + ((mVersion == null) ? 0 : mVersion.hashCode());
    301         result = prime * result + ((mVersionName == null) ? 0 : mVersionName.hashCode());
    302         return result;
    303     }
    304 
    305     @Override
    306     public boolean equals(Object obj) {
    307         if (this == obj) {
    308             return true;
    309         }
    310         if (!super.equals(obj)) {
    311             return false;
    312         }
    313         if (!(obj instanceof PlatformPackage)) {
    314             return false;
    315         }
    316         PlatformPackage other = (PlatformPackage) obj;
    317         if (mLayoutlibVersion == null) {
    318             if (other.mLayoutlibVersion != null) {
    319                 return false;
    320             }
    321         } else if (!mLayoutlibVersion.equals(other.mLayoutlibVersion)) {
    322             return false;
    323         }
    324         if (mVersion == null) {
    325             if (other.mVersion != null) {
    326                 return false;
    327             }
    328         } else if (!mVersion.equals(other.mVersion)) {
    329             return false;
    330         }
    331         if (mVersionName == null) {
    332             if (other.mVersionName != null) {
    333                 return false;
    334             }
    335         } else if (!mVersionName.equals(other.mVersionName)) {
    336             return false;
    337         }
    338         return true;
    339     }
    340 }
    341