blob: 83c3555d69f4a2a9c6cb096abdbb29f52fca4f52 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.sdklib.internal.androidTarget;
import com.android.SdkConstants;
import com.android.annotations.NonNull;
import com.android.sdklib.AndroidTargetHash;
import com.android.sdklib.AndroidVersion;
import com.android.sdklib.BuildToolInfo;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.ISystemImage;
import java.io.File;
import java.io.FileFilter;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* Represents an add-on target in the SDK.
* An add-on extends a standard {@link PlatformTarget}.
*/
public final class AddOnTarget implements IAndroidTarget {
private static final class OptionalLibrary implements IOptionalLibrary {
private final String mJarName;
private final String mJarPath;
private final String mName;
private final String mDescription;
OptionalLibrary(String jarName, String jarPath, String name, String description) {
mJarName = jarName;
mJarPath = jarPath;
mName = name;
mDescription = description;
}
@Override
public String getJarName() {
return mJarName;
}
@Override
public String getJarPath() {
return mJarPath;
}
@Override
public String getName() {
return mName;
}
@Override
public String getDescription() {
return mDescription;
}
}
private final String mLocation;
private final PlatformTarget mBasePlatform;
private final String mName;
private final ISystemImage[] mSystemImages;
private final String mVendor;
private final int mRevision;
private final String mDescription;
private final boolean mHasRenderingLibrary;
private final boolean mHasRenderingResources;
private String[] mSkins;
private String mDefaultSkin;
private IOptionalLibrary[] mLibraries;
private int mVendorId = NO_USB_ID;
/**
* Creates a new add-on
* @param location the OS path location of the add-on
* @param name the name of the add-on
* @param vendor the vendor name of the add-on
* @param revision the revision of the add-on
* @param description the add-on description
* @param systemImages list of supported system images. Can be null or empty.
* @param libMap A map containing the optional libraries. The map key is the fully-qualified
* library name. The value is a 2 string array with the .jar filename, and the description.
* @param hasRenderingLibrary whether the addon has a custom layoutlib.jar
* @param hasRenderingResources whether the add has custom framework resources.
* @param basePlatform the platform the add-on is extending.
*/
public AddOnTarget(
String location,
String name,
String vendor,
int revision,
String description,
ISystemImage[] systemImages,
Map<String, String[]> libMap,
boolean hasRenderingLibrary,
boolean hasRenderingResources,
PlatformTarget basePlatform) {
if (location.endsWith(File.separator) == false) {
location = location + File.separator;
}
mLocation = location;
mName = name;
mVendor = vendor;
mRevision = revision;
mDescription = description;
mHasRenderingLibrary = hasRenderingLibrary;
mHasRenderingResources = hasRenderingResources;
mBasePlatform = basePlatform;
// If the add-on does not have any system-image of its own, the list here
// is empty and it's up to the callers to query the parent platform.
mSystemImages = systemImages == null ? new ISystemImage[0] : systemImages;
Arrays.sort(mSystemImages);
// handle the optional libraries.
if (libMap != null) {
mLibraries = new IOptionalLibrary[libMap.size()];
int index = 0;
for (Entry<String, String[]> entry : libMap.entrySet()) {
String jarFile = entry.getValue()[0];
String desc = entry.getValue()[1];
mLibraries[index++] = new OptionalLibrary(jarFile,
mLocation + SdkConstants.OS_ADDON_LIBS_FOLDER + jarFile,
entry.getKey(), desc);
}
}
}
@Override
public String getLocation() {
return mLocation;
}
@Override
public String getName() {
return mName;
}
@Override
public ISystemImage getSystemImage(String abiType) {
for (ISystemImage sysImg : mSystemImages) {
if (sysImg.getAbiType().equals(abiType)) {
return sysImg;
}
}
return null;
}
@Override
public ISystemImage[] getSystemImages() {
return mSystemImages;
}
@Override
public String getVendor() {
return mVendor;
}
@Override
public String getFullName() {
return String.format("%1$s (%2$s)", mName, mVendor);
}
@Override
public String getClasspathName() {
return String.format("%1$s [%2$s]", mName, mBasePlatform.getClasspathName());
}
@Override
public String getShortClasspathName() {
return String.format("%1$s [%2$s]", mName, mBasePlatform.getVersionName());
}
@Override
public String getDescription() {
return mDescription;
}
@Override
public AndroidVersion getVersion() {
// this is always defined by the base platform
return mBasePlatform.getVersion();
}
@Override
public String getVersionName() {
return mBasePlatform.getVersionName();
}
@Override
public int getRevision() {
return mRevision;
}
@Override
public boolean isPlatform() {
return false;
}
@Override
public IAndroidTarget getParent() {
return mBasePlatform;
}
@Override
public String getPath(int pathId) {
switch (pathId) {
case SKINS:
return mLocation + SdkConstants.OS_SKINS_FOLDER;
case DOCS:
return mLocation + SdkConstants.FD_DOCS + File.separator
+ SdkConstants.FD_DOCS_REFERENCE;
case LAYOUT_LIB:
if (mHasRenderingLibrary) {
return mLocation + SdkConstants.FD_DATA + File.separator
+ SdkConstants.FN_LAYOUTLIB_JAR;
}
return mBasePlatform.getPath(pathId);
case RESOURCES:
if (mHasRenderingResources) {
return mLocation + SdkConstants.FD_DATA + File.separator
+ SdkConstants.FD_RES;
}
return mBasePlatform.getPath(pathId);
case FONTS:
if (mHasRenderingResources) {
return mLocation + SdkConstants.FD_DATA + File.separator
+ SdkConstants.FD_FONTS;
}
return mBasePlatform.getPath(pathId);
case SAMPLES:
// only return the add-on samples folder if there is actually a sample (or more)
File sampleLoc = new File(mLocation, SdkConstants.FD_SAMPLES);
if (sampleLoc.isDirectory()) {
File[] files = sampleLoc.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
});
if (files != null && files.length > 0) {
return sampleLoc.getAbsolutePath();
}
}
//$FALL-THROUGH$
default :
return mBasePlatform.getPath(pathId);
}
}
@Override
public BuildToolInfo getBuildToolInfo() {
return mBasePlatform.getBuildToolInfo();
}
@Override @NonNull
public List<String> getBootClasspath() {
return Collections.singletonList(getPath(IAndroidTarget.ANDROID_JAR));
}
@Override
public boolean hasRenderingLibrary() {
return mHasRenderingLibrary || mHasRenderingResources;
}
@Override
public String[] getSkins() {
return mSkins;
}
@Override
public String getDefaultSkin() {
return mDefaultSkin;
}
@Override
public IOptionalLibrary[] getOptionalLibraries() {
return mLibraries;
}
/**
* Returns the list of libraries of the underlying platform.
*
* {@inheritDoc}
*/
@Override
public String[] getPlatformLibraries() {
return mBasePlatform.getPlatformLibraries();
}
@Override
public String getProperty(String name) {
return mBasePlatform.getProperty(name);
}
@Override
public Integer getProperty(String name, Integer defaultValue) {
return mBasePlatform.getProperty(name, defaultValue);
}
@Override
public Boolean getProperty(String name, Boolean defaultValue) {
return mBasePlatform.getProperty(name, defaultValue);
}
@Override
public Map<String, String> getProperties() {
return mBasePlatform.getProperties();
}
@Override
public int getUsbVendorId() {
return mVendorId;
}
@Override
public boolean canRunOn(IAndroidTarget target) {
// basic test
if (target == this) {
return true;
}
/*
* The method javadoc indicates:
* Returns whether the given target is compatible with the receiver.
* <p/>A target is considered compatible if applications developed for the receiver can
* run on the given target.
*/
// The receiver is an add-on. There are 2 big use cases: The add-on has libraries
// or the add-on doesn't (in which case we consider it a platform).
if (mLibraries == null || mLibraries.length == 0) {
return mBasePlatform.canRunOn(target);
} else {
// the only targets that can run the receiver are the same add-on in the same or later
// versions.
// first check: vendor/name
if (mVendor.equals(target.getVendor()) == false ||
mName.equals(target.getName()) == false) {
return false;
}
// now check the version. At this point since we checked the add-on part,
// we can revert to the basic check on version/codename which are done by the
// base platform already.
return mBasePlatform.canRunOn(target);
}
}
@Override
public String hashString() {
return String.format(AndroidTargetHash.ADD_ON_FORMAT, mVendor, mName,
mBasePlatform.getVersion().getApiString());
}
@Override
public int hashCode() {
return hashString().hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof AddOnTarget) {
AddOnTarget addon = (AddOnTarget)obj;
return mVendor.equals(addon.mVendor) && mName.equals(addon.mName) &&
mBasePlatform.getVersion().equals(addon.mBasePlatform.getVersion());
}
return false;
}
/*
* Order by API level (preview/n count as between n and n+1).
* At the same API level, order as: Platform first, then add-on ordered by vendor and then name
* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(IAndroidTarget target) {
// quick check.
if (this == target) {
return 0;
}
int versionDiff = getVersion().compareTo(target.getVersion());
// only if the version are the same do we care about platform/add-ons.
if (versionDiff == 0) {
// platforms go before add-ons.
if (target.isPlatform()) {
return +1;
} else {
AddOnTarget targetAddOn = (AddOnTarget)target;
// both are add-ons of the same version. Compare per vendor then by name
int vendorDiff = mVendor.compareTo(targetAddOn.mVendor);
if (vendorDiff == 0) {
return mName.compareTo(targetAddOn.mName);
} else {
return vendorDiff;
}
}
}
return versionDiff;
}
/**
* Returns a string representation suitable for debugging.
* The representation is not intended for display to the user.
*
* The representation is also purposely compact. It does not describe _all_ the properties
* of the target, only a few key ones.
*
* @see #getDescription()
*/
@Override
public String toString() {
return String.format("AddonTarget %1$s rev %2$d (based on %3$s)", //$NON-NLS-1$
getVersion(),
getRevision(),
getParent().toString());
}
// ---- local methods.
public void setSkins(String[] skins, String defaultSkin) {
mDefaultSkin = defaultSkin;
// we mix the add-on and base platform skins
HashSet<String> skinSet = new HashSet<String>();
skinSet.addAll(Arrays.asList(skins));
skinSet.addAll(Arrays.asList(mBasePlatform.getSkins()));
mSkins = skinSet.toArray(new String[skinSet.size()]);
}
/**
* Sets the USB vendor id in the add-on.
*/
public void setUsbVendorId(int vendorId) {
if (vendorId == 0) {
throw new IllegalArgumentException( "VendorId must be > 0");
}
mVendorId = vendorId;
}
}