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 String mVendor; 71 private final int mRevision; 72 private final String mDescription; 73 private String[] mSkins; 74 private String mDefaultSkin; 75 private IOptionalLibrary[] mLibraries; 76 private int mVendorId = NO_USB_ID; 77 78 /** 79 * Creates a new add-on 80 * @param location the OS path location of the add-on 81 * @param name the name of the add-on 82 * @param vendor the vendor name of the add-on 83 * @param revision the revision of the add-on 84 * @param description the add-on description 85 * @param libMap A map containing the optional libraries. The map key is the fully-qualified 86 * library name. The value is a 2 string array with the .jar filename, and the description. 87 * @param basePlatform the platform the add-on is extending. 88 */ 89 AddOnTarget(String location, String name, String vendor, int revision, String description, 90 Map<String, String[]> libMap, PlatformTarget basePlatform) { 91 if (location.endsWith(File.separator) == false) { 92 location = location + File.separator; 93 } 94 95 mLocation = location; 96 mName = name; 97 mVendor = vendor; 98 mRevision = revision; 99 mDescription = description; 100 mBasePlatform = basePlatform; 101 102 // handle the optional libraries. 103 if (libMap != null) { 104 mLibraries = new IOptionalLibrary[libMap.size()]; 105 int index = 0; 106 for (Entry<String, String[]> entry : libMap.entrySet()) { 107 String jarFile = entry.getValue()[0]; 108 String desc = entry.getValue()[1]; 109 mLibraries[index++] = new OptionalLibrary(jarFile, 110 mLocation + SdkConstants.OS_ADDON_LIBS_FOLDER + jarFile, 111 entry.getKey(), desc); 112 } 113 } 114 } 115 116 public String getLocation() { 117 return mLocation; 118 } 119 120 public String getName() { 121 return mName; 122 } 123 124 public String getVendor() { 125 return mVendor; 126 } 127 128 public String getFullName() { 129 return String.format("%1$s (%2$s)", mName, mVendor); 130 } 131 132 public String getClasspathName() { 133 return String.format("%1$s [%2$s]", mName, mBasePlatform.getName()); 134 } 135 136 public String getDescription() { 137 return mDescription; 138 } 139 140 public AndroidVersion getVersion() { 141 // this is always defined by the base platform 142 return mBasePlatform.getVersion(); 143 } 144 145 public String getVersionName() { 146 return mBasePlatform.getVersionName(); 147 } 148 149 public int getRevision() { 150 return mRevision; 151 } 152 153 public boolean isPlatform() { 154 return false; 155 } 156 157 public IAndroidTarget getParent() { 158 return mBasePlatform; 159 } 160 161 public String getPath(int pathId) { 162 switch (pathId) { 163 case IMAGES: 164 return mLocation + SdkConstants.OS_IMAGES_FOLDER; 165 case SKINS: 166 return mLocation + SdkConstants.OS_SKINS_FOLDER; 167 case DOCS: 168 return mLocation + SdkConstants.FD_DOCS + File.separator 169 + SdkConstants.FD_DOCS_REFERENCE; 170 case SAMPLES: 171 // only return the add-on samples folder if there is actually a sample (or more) 172 File sampleLoc = new File(mLocation, SdkConstants.FD_SAMPLES); 173 if (sampleLoc.isDirectory()) { 174 File[] files = sampleLoc.listFiles(new FileFilter() { 175 public boolean accept(File pathname) { 176 return pathname.isDirectory(); 177 } 178 179 }); 180 if (files != null && files.length > 0) { 181 return sampleLoc.getAbsolutePath(); 182 } 183 } 184 // INTENDED FALL-THROUGH 185 default : 186 return mBasePlatform.getPath(pathId); 187 } 188 } 189 190 public String[] getSkins() { 191 return mSkins; 192 } 193 194 public String getDefaultSkin() { 195 return mDefaultSkin; 196 } 197 198 public IOptionalLibrary[] getOptionalLibraries() { 199 return mLibraries; 200 } 201 202 /** 203 * Returns the list of libraries of the underlying platform. 204 * 205 * {@inheritDoc} 206 */ 207 public String[] getPlatformLibraries() { 208 return mBasePlatform.getPlatformLibraries(); 209 } 210 211 public String getProperty(String name) { 212 return mBasePlatform.getProperty(name); 213 } 214 215 public Integer getProperty(String name, Integer defaultValue) { 216 return mBasePlatform.getProperty(name, defaultValue); 217 } 218 219 public Boolean getProperty(String name, Boolean defaultValue) { 220 return mBasePlatform.getProperty(name, defaultValue); 221 } 222 223 public Map<String, String> getProperties() { 224 return mBasePlatform.getProperties(); 225 } 226 227 public int getUsbVendorId() { 228 return mVendorId; 229 } 230 231 public boolean canRunOn(IAndroidTarget target) { 232 // basic test 233 if (target == this) { 234 return true; 235 } 236 237 /* 238 * The method javadoc indicates: 239 * Returns whether the given target is compatible with the receiver. 240 * <p/>A target is considered compatible if applications developed for the receiver can 241 * run on the given target. 242 */ 243 244 // The receiver is an add-on. There are 2 big use cases: The add-on has libraries 245 // or the add-on doesn't (in which case we consider it a platform). 246 if (mLibraries == null || mLibraries.length == 0) { 247 return mBasePlatform.canRunOn(target); 248 } else { 249 // the only targets that can run the receiver are the same add-on in the same or later 250 // versions. 251 // first check: vendor/name 252 if (mVendor.equals(target.getVendor()) == false || 253 mName.equals(target.getName()) == false) { 254 return false; 255 } 256 257 // now check the version. At this point since we checked the add-on part, 258 // we can revert to the basic check on version/codename which are done by the 259 // base platform already. 260 return mBasePlatform.canRunOn(target); 261 } 262 263 } 264 265 public String hashString() { 266 return String.format(ADD_ON_FORMAT, mVendor, mName, 267 mBasePlatform.getVersion().getApiString()); 268 } 269 270 @Override 271 public int hashCode() { 272 return hashString().hashCode(); 273 } 274 275 @Override 276 public boolean equals(Object obj) { 277 if (obj instanceof AddOnTarget) { 278 AddOnTarget addon = (AddOnTarget)obj; 279 280 return mVendor.equals(addon.mVendor) && mName.equals(addon.mName) && 281 mBasePlatform.getVersion().equals(addon.mBasePlatform.getVersion()); 282 } 283 284 return false; 285 } 286 287 /* 288 * Order by API level (preview/n count as between n and n+1). 289 * At the same API level, order as: Platform first, then add-on ordered by vendor and then name 290 * (non-Javadoc) 291 * @see java.lang.Comparable#compareTo(java.lang.Object) 292 */ 293 public int compareTo(IAndroidTarget target) { 294 // quick check. 295 if (this == target) { 296 return 0; 297 } 298 299 int versionDiff = getVersion().compareTo(target.getVersion()); 300 301 // only if the version are the same do we care about platform/add-ons. 302 if (versionDiff == 0) { 303 // platforms go before add-ons. 304 if (target.isPlatform()) { 305 return +1; 306 } else { 307 AddOnTarget targetAddOn = (AddOnTarget)target; 308 309 // both are add-ons of the same version. Compare per vendor then by name 310 int vendorDiff = mVendor.compareTo(targetAddOn.mVendor); 311 if (vendorDiff == 0) { 312 return mName.compareTo(targetAddOn.mName); 313 } else { 314 return vendorDiff; 315 } 316 } 317 318 } 319 320 return versionDiff; 321 } 322 323 // ---- local methods. 324 325 void setSkins(String[] skins, String defaultSkin) { 326 mDefaultSkin = defaultSkin; 327 328 // we mix the add-on and base platform skins 329 HashSet<String> skinSet = new HashSet<String>(); 330 skinSet.addAll(Arrays.asList(skins)); 331 skinSet.addAll(Arrays.asList(mBasePlatform.getSkins())); 332 333 mSkins = skinSet.toArray(new String[skinSet.size()]); 334 } 335 336 /** 337 * Sets the USB vendor id in the add-on. 338 */ 339 void setUsbVendorId(int vendorId) { 340 if (vendorId == 0) { 341 throw new IllegalArgumentException( "VendorId must be > 0"); 342 } 343 344 mVendorId = vendorId; 345 } 346 } 347