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