Home | History | Annotate | Download | only in sdklib
      1 /*
      2  * Copyright (C) 2008 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;
     18 
     19 import java.io.File;
     20 import java.io.FileFilter;
     21 import java.util.Arrays;
     22 import java.util.HashSet;
     23 import java.util.Map;
     24 import java.util.Map.Entry;
     25 
     26 /**
     27  * Represents an add-on target in the SDK.
     28  * An add-on extends a standard {@link PlatformTarget}.
     29  */
     30 final class AddOnTarget implements IAndroidTarget {
     31     /**
     32      * String to compute hash for add-on targets.
     33      * Format is vendor:name:apiVersion
     34      * */
     35     private final static String ADD_ON_FORMAT = "%s:%s:%s"; //$NON-NLS-1$
     36 
     37     private final static class OptionalLibrary implements IOptionalLibrary {
     38         private final String mJarName;
     39         private final String mJarPath;
     40         private final String mName;
     41         private final String mDescription;
     42 
     43         OptionalLibrary(String jarName, String jarPath, String name, String description) {
     44             mJarName = jarName;
     45             mJarPath = jarPath;
     46             mName = name;
     47             mDescription = description;
     48         }
     49 
     50         public String getJarName() {
     51             return mJarName;
     52         }
     53 
     54         public String getJarPath() {
     55             return mJarPath;
     56         }
     57 
     58         public String getName() {
     59             return mName;
     60         }
     61 
     62         public String getDescription() {
     63             return mDescription;
     64         }
     65     }
     66 
     67     private final String mLocation;
     68     private final PlatformTarget mBasePlatform;
     69     private final String mName;
     70     private final ISystemImage[] mSystemImages;
     71     private final String mVendor;
     72     private final int mRevision;
     73     private final String mDescription;
     74     private final boolean mHasRenderingLibrary;
     75     private final boolean mHasRenderingResources;
     76 
     77     private String[] mSkins;
     78     private String mDefaultSkin;
     79     private IOptionalLibrary[] mLibraries;
     80     private int mVendorId = NO_USB_ID;
     81 
     82     /**
     83      * Creates a new add-on
     84      * @param location the OS path location of the add-on
     85      * @param name the name of the add-on
     86      * @param vendor the vendor name of the add-on
     87      * @param revision the revision of the add-on
     88      * @param description the add-on description
     89      * @param systemImages list of supported system images. Can be null or empty.
     90      * @param libMap A map containing the optional libraries. The map key is the fully-qualified
     91      * library name. The value is a 2 string array with the .jar filename, and the description.
     92      * @param hasRenderingLibrary whether the addon has a custom layoutlib.jar
     93      * @param hasRenderingResources whether the add has custom framework resources.
     94      * @param basePlatform the platform the add-on is extending.
     95      */
     96     AddOnTarget(
     97             String location,
     98             String name,
     99             String vendor,
    100             int revision,
    101             String description,
    102             ISystemImage[] systemImages,
    103             Map<String, String[]> libMap,
    104             boolean hasRenderingLibrary,
    105             boolean hasRenderingResources,
    106             PlatformTarget basePlatform) {
    107         if (location.endsWith(File.separator) == false) {
    108             location = location + File.separator;
    109         }
    110 
    111         mLocation = location;
    112         mName = name;
    113         mVendor = vendor;
    114         mRevision = revision;
    115         mDescription = description;
    116         mHasRenderingLibrary = hasRenderingLibrary;
    117         mHasRenderingResources = hasRenderingResources;
    118         mBasePlatform = basePlatform;
    119 
    120         // If the add-on does not have any system-image of its own, the list here
    121         // is empty and it's up to the callers to query the parent platform.
    122         mSystemImages = systemImages == null ? new ISystemImage[0] : systemImages;
    123         Arrays.sort(mSystemImages);
    124 
    125         // handle the optional libraries.
    126         if (libMap != null) {
    127             mLibraries = new IOptionalLibrary[libMap.size()];
    128             int index = 0;
    129             for (Entry<String, String[]> entry : libMap.entrySet()) {
    130                 String jarFile = entry.getValue()[0];
    131                 String desc = entry.getValue()[1];
    132                 mLibraries[index++] = new OptionalLibrary(jarFile,
    133                         mLocation + SdkConstants.OS_ADDON_LIBS_FOLDER + jarFile,
    134                         entry.getKey(), desc);
    135             }
    136         }
    137     }
    138 
    139     public String getLocation() {
    140         return mLocation;
    141     }
    142 
    143     public String getName() {
    144         return mName;
    145     }
    146 
    147     public ISystemImage getSystemImage(String abiType) {
    148         for (ISystemImage sysImg : mSystemImages) {
    149             if (sysImg.getAbiType().equals(abiType)) {
    150                 return sysImg;
    151             }
    152         }
    153         return null;
    154     }
    155 
    156     public ISystemImage[] getSystemImages() {
    157         return mSystemImages;
    158     }
    159 
    160     public String getVendor() {
    161         return mVendor;
    162     }
    163 
    164     public String getFullName() {
    165         return String.format("%1$s (%2$s)", mName, mVendor);
    166     }
    167 
    168     public String getClasspathName() {
    169         return String.format("%1$s [%2$s]", mName, mBasePlatform.getClasspathName());
    170     }
    171 
    172     public String getShortClasspathName() {
    173         return String.format("%1$s [%2$s]", mName, mBasePlatform.getVersionName());
    174     }
    175 
    176     public String getDescription() {
    177         return mDescription;
    178     }
    179 
    180     public AndroidVersion getVersion() {
    181         // this is always defined by the base platform
    182         return mBasePlatform.getVersion();
    183     }
    184 
    185     public String getVersionName() {
    186         return mBasePlatform.getVersionName();
    187     }
    188 
    189     public int getRevision() {
    190         return mRevision;
    191     }
    192 
    193     public boolean isPlatform() {
    194         return false;
    195     }
    196 
    197     public IAndroidTarget getParent() {
    198         return mBasePlatform;
    199     }
    200 
    201     public String getPath(int pathId) {
    202         switch (pathId) {
    203             case SKINS:
    204                 return mLocation + SdkConstants.OS_SKINS_FOLDER;
    205             case DOCS:
    206                 return mLocation + SdkConstants.FD_DOCS + File.separator
    207                         + SdkConstants.FD_DOCS_REFERENCE;
    208 
    209             case LAYOUT_LIB:
    210                 if (mHasRenderingLibrary) {
    211                     return mLocation + SdkConstants.FD_DATA + File.separator
    212                             + SdkConstants.FN_LAYOUTLIB_JAR;
    213                 }
    214                 return mBasePlatform.getPath(pathId);
    215 
    216             case RESOURCES:
    217                 if (mHasRenderingResources) {
    218                     return mLocation + SdkConstants.FD_DATA + File.separator
    219                             + SdkConstants.FD_RES;
    220                 }
    221                 return mBasePlatform.getPath(pathId);
    222 
    223             case FONTS:
    224                 if (mHasRenderingResources) {
    225                     return mLocation + SdkConstants.FD_DATA + File.separator
    226                             + SdkConstants.FD_FONTS;
    227                 }
    228                 return mBasePlatform.getPath(pathId);
    229 
    230             case SAMPLES:
    231                 // only return the add-on samples folder if there is actually a sample (or more)
    232                 File sampleLoc = new File(mLocation, SdkConstants.FD_SAMPLES);
    233                 if (sampleLoc.isDirectory()) {
    234                     File[] files = sampleLoc.listFiles(new FileFilter() {
    235                         public boolean accept(File pathname) {
    236                             return pathname.isDirectory();
    237                         }
    238 
    239                     });
    240                     if (files != null && files.length > 0) {
    241                         return sampleLoc.getAbsolutePath();
    242                     }
    243                 }
    244                 //$FALL-THROUGH$
    245             default :
    246                 return mBasePlatform.getPath(pathId);
    247         }
    248     }
    249 
    250     public boolean hasRenderingLibrary() {
    251         return mHasRenderingLibrary || mHasRenderingResources;
    252     }
    253 
    254     public String[] getSkins() {
    255         return mSkins;
    256     }
    257 
    258     public String getDefaultSkin() {
    259         return mDefaultSkin;
    260     }
    261 
    262     public IOptionalLibrary[] getOptionalLibraries() {
    263         return mLibraries;
    264     }
    265 
    266     /**
    267      * Returns the list of libraries of the underlying platform.
    268      *
    269      * {@inheritDoc}
    270      */
    271     public String[] getPlatformLibraries() {
    272         return mBasePlatform.getPlatformLibraries();
    273     }
    274 
    275     public String getProperty(String name) {
    276         return mBasePlatform.getProperty(name);
    277     }
    278 
    279     public Integer getProperty(String name, Integer defaultValue) {
    280         return mBasePlatform.getProperty(name, defaultValue);
    281     }
    282 
    283     public Boolean getProperty(String name, Boolean defaultValue) {
    284         return mBasePlatform.getProperty(name, defaultValue);
    285     }
    286 
    287     public Map<String, String> getProperties() {
    288         return mBasePlatform.getProperties();
    289     }
    290 
    291     public int getUsbVendorId() {
    292         return mVendorId;
    293     }
    294 
    295     public boolean canRunOn(IAndroidTarget target) {
    296         // basic test
    297         if (target == this) {
    298             return true;
    299         }
    300 
    301         /*
    302          * The method javadoc indicates:
    303          * Returns whether the given target is compatible with the receiver.
    304          * <p/>A target is considered compatible if applications developed for the receiver can
    305          * run on the given target.
    306          */
    307 
    308         // The receiver is an add-on. There are 2 big use cases: The add-on has libraries
    309         // or the add-on doesn't (in which case we consider it a platform).
    310         if (mLibraries == null || mLibraries.length == 0) {
    311             return mBasePlatform.canRunOn(target);
    312         } else {
    313             // the only targets that can run the receiver are the same add-on in the same or later
    314             // versions.
    315             // first check: vendor/name
    316             if (mVendor.equals(target.getVendor()) == false ||
    317                             mName.equals(target.getName()) == false) {
    318                 return false;
    319             }
    320 
    321             // now check the version. At this point since we checked the add-on part,
    322             // we can revert to the basic check on version/codename which are done by the
    323             // base platform already.
    324             return mBasePlatform.canRunOn(target);
    325         }
    326 
    327     }
    328 
    329     public String hashString() {
    330         return String.format(ADD_ON_FORMAT, mVendor, mName,
    331                 mBasePlatform.getVersion().getApiString());
    332     }
    333 
    334     @Override
    335     public int hashCode() {
    336         return hashString().hashCode();
    337     }
    338 
    339     @Override
    340     public boolean equals(Object obj) {
    341         if (obj instanceof AddOnTarget) {
    342             AddOnTarget addon = (AddOnTarget)obj;
    343 
    344             return mVendor.equals(addon.mVendor) && mName.equals(addon.mName) &&
    345                 mBasePlatform.getVersion().equals(addon.mBasePlatform.getVersion());
    346         }
    347 
    348         return false;
    349     }
    350 
    351     /*
    352      * Order by API level (preview/n count as between n and n+1).
    353      * At the same API level, order as: Platform first, then add-on ordered by vendor and then name
    354      * (non-Javadoc)
    355      * @see java.lang.Comparable#compareTo(java.lang.Object)
    356      */
    357     public int compareTo(IAndroidTarget target) {
    358         // quick check.
    359         if (this == target) {
    360             return 0;
    361         }
    362 
    363         int versionDiff = getVersion().compareTo(target.getVersion());
    364 
    365         // only if the version are the same do we care about platform/add-ons.
    366         if (versionDiff == 0) {
    367             // platforms go before add-ons.
    368             if (target.isPlatform()) {
    369                 return +1;
    370             } else {
    371                 AddOnTarget targetAddOn = (AddOnTarget)target;
    372 
    373                 // both are add-ons of the same version. Compare per vendor then by name
    374                 int vendorDiff = mVendor.compareTo(targetAddOn.mVendor);
    375                 if (vendorDiff == 0) {
    376                     return mName.compareTo(targetAddOn.mName);
    377                 } else {
    378                     return vendorDiff;
    379                 }
    380             }
    381 
    382         }
    383 
    384         return versionDiff;
    385     }
    386 
    387     /**
    388      * Returns a string representation suitable for debugging.
    389      * The representation is not intended for display to the user.
    390      *
    391      * The representation is also purposely compact. It does not describe _all_ the properties
    392      * of the target, only a few key ones.
    393      *
    394      * @see #getDescription()
    395      */
    396     @Override
    397     public String toString() {
    398         return String.format("AddonTarget %1$s rev %2$d (based on %3$s)",     //$NON-NLS-1$
    399                 getVersion(),
    400                 getRevision(),
    401                 getParent().toString());
    402     }
    403 
    404     // ---- local methods.
    405 
    406     void setSkins(String[] skins, String defaultSkin) {
    407         mDefaultSkin = defaultSkin;
    408 
    409         // we mix the add-on and base platform skins
    410         HashSet<String> skinSet = new HashSet<String>();
    411         skinSet.addAll(Arrays.asList(skins));
    412         skinSet.addAll(Arrays.asList(mBasePlatform.getSkins()));
    413 
    414         mSkins = skinSet.toArray(new String[skinSet.size()]);
    415     }
    416 
    417     /**
    418      * Sets the USB vendor id in the add-on.
    419      */
    420     void setUsbVendorId(int vendorId) {
    421         if (vendorId == 0) {
    422             throw new IllegalArgumentException( "VendorId must be > 0");
    423         }
    424 
    425         mVendorId = vendorId;
    426     }
    427 }
    428