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