import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.ISdkLog;
+import com.android.sdklib.ISystemImage;
import com.android.sdklib.SdkConstants;
import com.android.sdklib.SdkManager;
import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
int index = 1;
for (IAndroidTarget target : mSdkManager.getTargets()) {
+ mSdkLog.printf("----------\n");
mSdkLog.printf("id: %1$d or \"%2$s\"\n", index, target.hashString());
mSdkLog.printf(" Name: %s\n", target.getName());
if (target.isPlatform()) {
}
}
- // get the target skins
+ // get the target skins & ABIs
displaySkinList(target, " Skins: ");
+ displayAbiList (target, " ABIs : ");
if (target.getUsbVendorId() != IAndroidTarget.NO_USB_ID) {
mSdkLog.printf(" Adds USB support for devices (Vendor: 0x%04X)\n",
* Displays the ABIs valid for the given target.
*/
private void displayAbiList(IAndroidTarget target, String message) {
- String[] abis = target.getAbiList();
+ ISystemImage[] systemImages = target.getSystemImages();
mSdkLog.printf(message);
- if (abis != null) {
+ if (systemImages.length > 0) {
boolean first = true;
- for (String skin : abis) {
+ for (ISystemImage si : systemImages) {
if (first == false) {
mSdkLog.printf(", ");
} else {
first = false;
}
- mSdkLog.printf(skin);
+ mSdkLog.printf(si.getAbiType());
}
mSdkLog.printf("\n");
} else {
mSdkLog.printf(" Based on Android %s (API level %s)\n",
target.getVersionName(), target.getVersion().getApiString());
}
+ mSdkLog.printf(" ABI: %s\n", info.getAbiType());
// display some extra values.
Map<String, String> properties = info.getProperties();
String abiType = mSdkCommandLine.getParamAbi();
if (target != null && (abiType == null || abiType.length() == 0)) {
- String[] abis = target.getAbiList();
- if (abis != null && abis.length == 1) {
+ ISystemImage[] systemImages = target.getSystemImages();
+ if (systemImages != null && systemImages.length == 1) {
// Auto-select the single ABI available
- abiType = abis[0];
+ abiType = systemImages[0].getAbiType();
mSdkLog.printf("Auto-selecting single ABI %1$s", abiType);
} else {
displayAbiList(target, "Valid ABIs: ");
errorAndExit("This platform has more than one ABI. Please specify one using --%1$s.",
SdkCommandLine.KEY_ABI);
-
}
}
+ ", P Name: " + this.getName() + "\n"
+ ", P Path: " + mAvdFolder + "\n"
+ ", P Target: Android 0.0 (API level 0)\n"
+ + ", P ABI: armeabi\n"
+ ", P Skin: HVGA\n"
+ "]",
getLog().toString());
+ ", P Name: " + this.getName() + "\n"
+ ", P Path: " + mAvdFolder + "\n"
+ ", P Target: Android 0.0 (API level 0)\n"
+ + ", P ABI: armeabi\n"
+ ", P Skin: HVGA\n"
+ ", P Snapshot: true\n"
+ "]",
private final String mLocation;
private final PlatformTarget mBasePlatform;
private final String mName;
- private String[] mAbis;
+ private final ISystemImage[] mSystemImages;
private final String mVendor;
private final int mRevision;
private final String mDescription;
private String mDefaultSkin;
private IOptionalLibrary[] mLibraries;
private int mVendorId = NO_USB_ID;
- private boolean mAbiCompatibilityMode;
/**
* Creates a new 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 abis list of supported abis
+ * @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.
*/
- AddOnTarget(String location, String name, String vendor, int revision, String description,
- String[] abis, Map<String, String[]> libMap,
- boolean hasRenderingLibrary, boolean hasRenderingResources,
+ 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;
mHasRenderingResources = hasRenderingResources;
mBasePlatform = basePlatform;
- //set compatibility mode
- if (abis.length > 0) {
- mAbis = abis;
- } else {
- mAbiCompatibilityMode = true;
- mAbis = new String[] { SdkConstants.ABI_ARMEABI };
- }
+ // 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) {
return mName;
}
- /**
- * Return the full path for images
- * @param abiType type of the abi
- * @return complete path where the image files are located
- */
- public String getImagePath(String abiType) {
-
- if (mAbiCompatibilityMode) {
- // Use legacy directory structure if only arm
- return mLocation + SdkConstants.OS_IMAGES_FOLDER;
- } else {
- return mLocation + SdkConstants.OS_IMAGES_FOLDER + abiType + File.separator;
- }
+ public ISystemImage getSystemImage(String abiType) {
+ for (ISystemImage sysImg : mSystemImages) {
+ if (sysImg.getAbiType().equals(abiType)) {
+ return sysImg;
+ }
+ }
+ return null;
}
- public String[] getAbiList() {
- return mAbis;
+ public ISystemImage[] getSystemImages() {
+ return mSystemImages;
}
public String getVendor() {
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.
void setSkins(String[] skins, String defaultSkin) {
int getUsbVendorId();
/**
- * Returns array of permitted processor architectures
+ * Returns an array of system images for this target.
+ * The array can be empty but not null.
*/
- public String[] getAbiList();
+ public ISystemImage[] getSystemImages();
/**
- * Returns string to append to images directory for current ProcessorType
+ * Returns the system image information for the given {@code abiType}.
+ *
+ * @param abiType An ABI type string.
+ * @return An existing {@link ISystemImage} for the requested {@code abiType}
+ * or null if none exists for this type.
*/
- public String getImagePath(String abiType);
+ public ISystemImage getSystemImage(String abiType);
/**
* Returns whether the given target is compatible with the receiver.
--- /dev/null
+/*
+ * Copyright (C) 2011 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;
+
+import java.io.File;
+
+
+/**
+ * Describes a system image as used by an {@link IAndroidTarget}.
+ * A system image has an installation path, a location type and an ABI type.
+ */
+public interface ISystemImage extends Comparable<ISystemImage> {
+
+ /** Indicates the type of location for the system image folder in the SDK. */
+ public enum LocationType {
+ /**
+ * The system image is located in the legacy platform's {@link SdkConstants#FD_IMAGES}
+ * folder.
+ * <p/>
+ * Used by both platform and add-ons.
+ */
+ IN_PLATFORM_LEGACY,
+
+ /**
+ * The system image is located in a sub-directory of the platform's
+ * {@link SdkConstants#FD_IMAGES} folder, allowing for multiple system
+ * images within the platform.
+ * <p/>
+ * Used by both platform and add-ons.
+ */
+ IN_PLATFORM_SUBFOLDER,
+
+ /**
+ * The system image is located in the new SDK's {@link SdkConstants#FD_SYSTEM_IMAGES}
+ * folder. Supported as of Tools R14 and Repository XSD version 5.
+ * <p/>
+ * Used <em>only</em> by both platform. This is not supported for add-ons yet.
+ */
+ IN_SYSTEM_IMAGE,
+ }
+
+ /** Returns the actual location of an installed system image. */
+ public abstract File getLocation();
+
+ /** Indicates the location strategy for this system image in the SDK. */
+ public abstract LocationType getLocationType();
+
+ /**
+ * Returns the ABI type. For example, one of {@link SdkConstants#ABI_ARMEABI},
+ * {@link SdkConstants#ABI_ARMEABI_V7A} or {@link SdkConstants#ABI_INTEL_ATOM}.
+ * Cannot be null nor empty.
+ */
+ public abstract String getAbiType();
+}
import com.android.sdklib.util.SparseArray;
import java.io.File;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
private final Map<String, String> mProperties;
private final SparseArray<String> mPaths = new SparseArray<String>();
private String[] mSkins;
- private String[] mAbis;
- private boolean mAbiCompatibilityMode;
+ private final ISystemImage[] mSystemImages;
private final LayoutlibVersion mLayoutlibVersion;
/**
* @param versionName the version name of the platform.
* @param revision the revision of the platform component.
* @param layoutlibVersion The {@link LayoutlibVersion}. May be null.
- * @param abis the list of supported abis
+ * @param systemImages list of supported system images
* @param properties the platform properties
*/
@SuppressWarnings("deprecation")
String versionName,
int revision,
LayoutlibVersion layoutlibVersion,
- String[] abis,
+ ISystemImage[] systemImages,
Map<String, String> properties) {
if (platformOSPath.endsWith(File.separator) == false) {
platformOSPath = platformOSPath + File.separator;
mVersionName = versionName;
mRevision = revision;
mLayoutlibVersion = layoutlibVersion;
+ mSystemImages = systemImages == null ? new ISystemImage[0] : systemImages;
+ Arrays.sort(mSystemImages);
if (mVersion.isPreview()) {
mName = String.format(PLATFORM_NAME_PREVIEW, mVersionName);
SdkConstants.FN_DX);
mPaths.put(DX_JAR, sdkOsPath + SdkConstants.OS_SDK_PLATFORM_TOOLS_LIB_FOLDER +
SdkConstants.FN_DX_JAR);
-
- //set compatibility mode, abis length would be 0 for older APIs
- if (abis.length > 0) {
- mAbis = abis;
- } else {
- mAbiCompatibilityMode = true;
- mAbis = new String[] { SdkConstants.ABI_ARMEABI };
- }
}
/**
return mLayoutlibVersion;
}
- /**
- * Return the full path for images
- * @param abiType type of the abi
- * @return complete path where the image files are located
- */
- public String getImagePath(String abiType) {
- if (mAbiCompatibilityMode) {
- // Use legacy directory structure if only arm is supported
- return mRootFolderOsPath + SdkConstants.OS_IMAGES_FOLDER;
- } else {
- return mRootFolderOsPath + SdkConstants.OS_IMAGES_FOLDER + abiType + File.separator;
+ public ISystemImage getSystemImage(String abiType) {
+ for (ISystemImage sysImg : mSystemImages) {
+ if (sysImg.getAbiType().equals(abiType)) {
+ return sysImg;
+ }
}
+ return null;
}
- /**
- * Retrieve and return the list of abis
- */
- public String[] getAbiList() {
- return mAbis;
+ public ISystemImage[] getSystemImages() {
+ return mSystemImages;
}
public String getLocation() {
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("PlatformTarget %1$s rev %2$d", //$NON-NLS-1$
+ getVersion(),
+ getRevision());
+ }
public String getProperty(String name) {
return mProperties.get(name);
import com.android.prefs.AndroidLocation;
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.AndroidVersion.AndroidVersionException;
+import com.android.sdklib.ISystemImage.LocationType;
import com.android.sdklib.internal.project.ProjectProperties;
import com.android.util.Pair;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
return null;
}
- String[] abiList = getAbiList(platformFolder.getAbsolutePath());
+ ISystemImage[] systemImages =
+ getPlatformSystemImages(sdkOsPath, platformFolder, apiNumber, apiCodename);
+
// create the target.
PlatformTarget target = new PlatformTarget(
sdkOsPath,
apiName,
revision,
layoutlibVersion,
- abiList,
+ systemImages,
map);
// need to parse the skins.
}
/**
- * Get all the abi types supported for a given target
- * @param path Path where the images folder for a target is located
- * @return an array of strings containing all the abi names for the target
+ * Get all the system images supported by an add-on target.
+ * For an add-on, we first look for sub-folders in the addon/images directory.
+ * If none are found but the directory exists and is not empty, assume it's a legacy
+ * arm eabi system image.
+ * <p/>
+ * Note that it's OK for an add-on to have no system-images at all, since it can always
+ * rely on the ones from its base platform.
+ *
+ * @param root Root of the add-on target being loaded.
+ * @return an array of ISystemImage containing all the system images for the target.
+ * The list can be empty.
*/
- private static String[] getAbiList(String path) {
- ArrayList<String> list = new ArrayList<String>();
+ private static ISystemImage[] getAddonSystemImages(File root) {
+ Set<ISystemImage> found = new TreeSet<ISystemImage>();
- File imagesFolder = new File(path + File.separator + SdkConstants.OS_IMAGES_FOLDER);
- File[] files = imagesFolder.listFiles();
+ root = new File(root, SdkConstants.OS_IMAGES_FOLDER);
+ File[] files = root.listFiles();
+ boolean hasImgFiles = false;
if (files != null) {
- // Loop through Images directory. If subdirectories exist, set multiprocessor mode
+ // Look for sub-directories
for (File file : files) {
if (file.isDirectory()) {
- list.add(file.getName());
+ found.add(new SystemImage(
+ file,
+ LocationType.IN_PLATFORM_SUBFOLDER,
+ file.getName()));
+ } else if (!hasImgFiles && file.isFile()) {
+ if (file.getName().endsWith(".img")) { //$NON-NLS-1$
+ hasImgFiles = true;
+ }
}
}
}
- String[] abis = new String[list.size()];
- list.toArray(abis);
- return abis;
+ if (found.size() == 0 && hasImgFiles && root.isDirectory()) {
+ // We found no sub-folder system images but it looks like the top directory
+ // has some img files in it. It must be a legacy ARM EABI system image folder.
+ found.add(new SystemImage(
+ root,
+ LocationType.IN_PLATFORM_LEGACY,
+ SdkConstants.ABI_ARMEABI));
+ }
+
+ return found.toArray(new ISystemImage[found.size()]);
+ }
+
+ /**
+ * Get all the system images supported by a platform target.
+ * For a platform, we first look in the new sdk/system-images folders then we
+ * look for sub-folders in the platform/images directory and/or the one legacy
+ * folder.
+ * If any given API appears twice or more, the first occurrence wins.
+ *
+ * @param sdkOsPath The path to the SDK.
+ * @param root Root of the platform target being loaded.
+ * @param apiCodename
+ * @return an array of ISystemImage containing all the system images for the target.
+ * The list can be empty.
+ */
+ private static ISystemImage[] getPlatformSystemImages(
+ String sdkOsPath,
+ File root,
+ int apiNumber,
+ String apiCodename) {
+ Set<ISystemImage> found = new TreeSet<ISystemImage>();
+ Set<String> abiFound = new HashSet<String>();
+
+ // First look in the SDK/system-image folder
+
+ AndroidVersion version = new AndroidVersion(apiNumber, apiCodename);
+ File siFolder = SystemImage.getCanonicalFolder(sdkOsPath, version, null /*abiType*/);
+ File[] files = siFolder.listFiles();
+
+ if (files != null) {
+ // Look for sub-directories
+ for (File file : files) {
+ if (file.isDirectory()) {
+ String abi = file.getName();
+ found.add(new SystemImage(
+ file,
+ LocationType.IN_SYSTEM_IMAGE,
+ abi));
+ abiFound.add(abi);
+ }
+ }
+ }
+
+ // Then look in either the platform/images/abi or the legacy folder
+ root = new File(root, SdkConstants.OS_IMAGES_FOLDER);
+ files = root.listFiles();
+ boolean useLegacy = true;
+ boolean hasImgFiles = false;
+
+ if (files != null) {
+ // Look for sub-directories
+ for (File file : files) {
+ if (file.isDirectory()) {
+ useLegacy = false;
+ String abi = file.getName();
+ if (!abiFound.contains(abi)) {
+ found.add(new SystemImage(
+ file,
+ LocationType.IN_PLATFORM_SUBFOLDER,
+ abi));
+ abiFound.add(abi);
+ }
+ } else if (!hasImgFiles && file.isFile()) {
+ if (file.getName().endsWith(".img")) { //$NON-NLS-1$
+ hasImgFiles = true;
+ }
+ }
+ }
+ }
+
+ if (useLegacy && hasImgFiles && root.isDirectory() &&
+ !abiFound.contains(SdkConstants.ABI_ARMEABI)) {
+ // We found no sub-folder system images but it looks like the top directory
+ // has some img files in it. It must be a legacy ARM EABI system image folder.
+ found.add(new SystemImage(
+ root,
+ LocationType.IN_PLATFORM_LEGACY,
+ SdkConstants.ABI_ARMEABI));
+ }
+
+ return found.toArray(new ISystemImage[found.size()]);
}
/**
}
// get the abi list.
- String[] abiList = getAbiList(addonDir.getAbsolutePath());
+ ISystemImage[] systemImages = getAddonSystemImages(addonDir);
// check whether the add-on provides its own rendering info/library.
boolean hasRenderingLibrary = false;
}
AddOnTarget target = new AddOnTarget(addonDir.getAbsolutePath(), name, vendor,
- revisionValue, description, abiList, libMap,
+ revisionValue, description, systemImages, libMap,
hasRenderingLibrary, hasRenderingResources,baseTarget);
// need to parse the skins.
--- /dev/null
+/*
+ * Copyright (C) 2011 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;
+
+import com.android.sdklib.io.FileOp;
+
+import java.io.File;
+
+
+/**
+ * Describes a system image as used by an {@link IAndroidTarget}.
+ * A system image has an installation path, a location type and an ABI type.
+ */
+public class SystemImage implements ISystemImage {
+
+ public static final String ANDROID_PREFIX = "android-"; //$NON-NLS-1$
+
+ private final LocationType mLocationtype;
+ private final String mAbiType;
+ private final File mLocation;
+
+ /**
+ * Creates a {@link SystemImage} description for an existing system image folder.
+ *
+ * @param location The location of an installed system image.
+ * @param locationType Where the system image folder is located for this ABI.
+ * @param abiType The ABI type. For example, one of {@link SdkConstants#ABI_ARMEABI},
+ * {@link SdkConstants#ABI_ARMEABI_V7A} or {@link SdkConstants#ABI_INTEL_ATOM}.
+ */
+ public SystemImage(File location, LocationType locationType, String abiType) {
+ mLocation = location;
+ mLocationtype = locationType;
+ mAbiType = abiType;
+ }
+
+ /**
+ * Creates a {@link SystemImage} description for a non-existing system image folder.
+ * The actual location is computed based on the {@code locationtype}.
+ *
+ * @param sdkManager The current SDK manager.
+ * @param locationType Where the system image folder is located for this ABI.
+ * @param abiType The ABI type. For example, one of {@link SdkConstants#ABI_ARMEABI},
+ * {@link SdkConstants#ABI_ARMEABI_V7A} or {@link SdkConstants#ABI_INTEL_ATOM}.
+ * @throws IllegalArgumentException if the {@code target} used for
+ * {@link ISystemImage.LocationType#IN_SYSTEM_IMAGE} is not a {@link PlatformTarget}.
+ */
+ public SystemImage(
+ SdkManager sdkManager,
+ IAndroidTarget target,
+ LocationType locationType,
+ String abiType) {
+ mLocationtype = locationType;
+ mAbiType = abiType;
+
+ File location = null;
+ switch(locationType) {
+ case IN_PLATFORM_LEGACY:
+ location = new File(target.getLocation(), SdkConstants.OS_IMAGES_FOLDER);
+ break;
+
+ case IN_PLATFORM_SUBFOLDER:
+ location = FileOp.append(target.getLocation(), SdkConstants.OS_IMAGES_FOLDER, abiType);
+ break;
+
+ case IN_SYSTEM_IMAGE:
+ if (!target.isPlatform()) {
+ throw new IllegalArgumentException(
+ "Add-ons do not support the system-image location type"); //$NON-NLS-1$
+ }
+
+ location = getCanonicalFolder(sdkManager.getLocation(), target.getVersion(), abiType);
+ break;
+ default:
+ // This is not supposed to happen unless LocationType is
+ // extended without adjusting this code.
+ assert false : "SystemImage used with an incorrect locationType"; //$NON-NLS-1$
+ }
+ mLocation = location;
+ }
+
+ /**
+ * Static helper method that returns the canonical path for a system-image that uses
+ * the {@link ISystemImage.LocationType#IN_SYSTEM_IMAGE} location type.
+ * <p/>
+ * Such an image is located in {@code SDK/system-images/android-N/abiType}.
+ * For this reason this method requires the root SDK as well as the platform and the ABI type.
+ *
+ * @param sdkOsPath The OS path to the SDK.
+ * @param platformVersion The platform version.
+ * @param abiType An optional ABI type. If null, the parent directory is returned.
+ * @return A file that represents the location of the canonical system-image folder
+ * for this configuration.
+ */
+ public static File getCanonicalFolder(
+ String sdkOsPath,
+ AndroidVersion platformVersion,
+ String abiType) {
+ File root = FileOp.append(
+ sdkOsPath,
+ SdkConstants.FD_SYSTEM_IMAGES,
+ ANDROID_PREFIX + platformVersion.getApiString());
+ if (abiType == null) {
+ return root;
+ } else {
+ return FileOp.append(root, abiType);
+ }
+ }
+
+ /** Returns the actual location of an installed system image. */
+ public File getLocation() {
+ return mLocation;
+ }
+
+ /** Indicates the location strategy for this system image in the SDK. */
+ public LocationType getLocationType() {
+ return mLocationtype;
+ }
+
+ /**
+ * Returns the ABI type. For example, one of {@link SdkConstants#ABI_ARMEABI},
+ * {@link SdkConstants#ABI_ARMEABI_V7A} or {@link SdkConstants#ABI_INTEL_ATOM}.
+ * Cannot be null nor empty.
+ */
+ public String getAbiType() {
+ return mAbiType;
+ }
+
+ public int compareTo(ISystemImage other) {
+ // Sort by ABI name only. This is what matters from a user point of view.
+ return this.getAbiType().compareToIgnoreCase(other.getAbiType());
+ }
+
+ /**
+ * Generates a string representation suitable for debug purposes.
+ * The string is not intended to be displayed to the user.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return String.format("SystemImage ABI=%s, location %s='%s'", //$NON-NLS-1$
+ mAbiType,
+ mLocationtype.toString().replace('_', ' ').toLowerCase(),
+ mLocation
+ );
+ }
+
+
+}
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.ISdkLog;
+import com.android.sdklib.ISystemImage;
import com.android.sdklib.SdkConstants;
import com.android.sdklib.SdkManager;
import com.android.sdklib.internal.avd.AvdInfo.AvdStatus;
iniFile = createAvdIniFile(avdName, avdFolder, target, removePrevious);
// writes the userdata.img in it.
- String imagePath = target.getImagePath(abiType);
- File userdataSrc = new File(imagePath, USERDATA_IMG);
+ File userdataSrc = null;
- if (userdataSrc.exists() == false && target.isPlatform() == false) {
- imagePath = target.getParent().getImagePath(abiType);
- userdataSrc = new File(imagePath, USERDATA_IMG);
+ // Look for a system image in the add-on.
+ // If we don't find one there, look in the base platform.
+ ISystemImage systemImage = target.getSystemImage(abiType);
+
+ if (systemImage != null) {
+ File imageFolder = systemImage.getLocation();
+ userdataSrc = new File(imageFolder, USERDATA_IMG);
}
- if (userdataSrc.exists() == false) {
+ if ((userdataSrc == null || !userdataSrc.exists()) && !target.isPlatform()) {
+ // If we don't find a system-image in the add-on, look into the platform.
+
+ systemImage = target.getParent().getSystemImage(abiType);
+ if (systemImage != null) {
+ File imageFolder = systemImage.getLocation();
+ userdataSrc = new File(imageFolder, USERDATA_IMG);
+ }
+ }
+
+ if (userdataSrc == null || !userdataSrc.exists()) {
log.error(null,
- "Unable to find a '%1$s' file of '%2$s' to copy into the AVD folder.",
- USERDATA_IMG, imagePath);
+ "Unable to find a '%1$s' file for ABI %2$s to copy into the AVD folder.",
+ USERDATA_IMG,
+ abiType);
needCleanup = true;
return null;
}
+
File userdataDest = new File(avdFolder, USERDATA_IMG);
copyImageFile(userdataSrc, userdataDest);
*/
private String getImageRelativePath(IAndroidTarget target, String abiType)
throws InvalidTargetPathException {
- String imageFullPath = target.getImagePath(abiType);
+
+ ISystemImage systemImage = target.getSystemImage(abiType);
+ if (systemImage == null) {
+ throw new IllegalArgumentException(String.format(
+ "ABI Type %s is unknown for target %s",
+ abiType,
+ target.getDescription()));
+ }
+
+ File folder = systemImage.getLocation();
+ String imageFullPath = folder.getAbsolutePath();
// make this path relative to the SDK location
String sdkLocation = mSdkManager.getLocation();
- if (imageFullPath.startsWith(sdkLocation) == false) {
+ if (!imageFullPath.startsWith(sdkLocation)) {
// this really really should not happen.
assert false;
throw new InvalidTargetPathException("Target location is not inside the SDK.");
}
- File folder = new File(imageFullPath);
if (folder.isDirectory()) {
String[] list = folder.list(new FilenameFilter() {
public boolean accept(File dir, String name) {
});
if (list.length > 0) {
+ // Remove the SDK root path, e.g. /sdk/dir1/dir2 => /dir1/dir2
imageFullPath = imageFullPath.substring(sdkLocation.length());
+ // The path is relative, so it must not start with a file separator
if (imageFullPath.charAt(0) == File.separatorChar) {
imageFullPath = imageFullPath.substring(1);
}
+ // For compatibility with previous versions, we denote folders
+ // by ending the path with file separator
+ if (!imageFullPath.endsWith(File.separator)) {
+ imageFullPath += File.separator;
+ }
return imageFullPath;
}
/**
* Sets the paths to the system images in a properties map.
+ *
* @param target the target in which to find the system images.
* @param abiType the abi type of the avd to find
* the architecture-dependent system images.
* @return true if success, false if some path are missing.
*/
private boolean setImagePathProperties(IAndroidTarget target,
- String abiType, Map<String, String> properties, ISdkLog log) {
+ String abiType,
+ Map<String, String> properties,
+ ISdkLog log) {
properties.remove(AVD_INI_IMAGES_1);
properties.remove(AVD_INI_IMAGES_2);
\r
import com.android.sdklib.IAndroidTarget;\r
import com.android.sdklib.ISdkLog;\r
+import com.android.sdklib.ISystemImage;\r
import com.android.sdklib.SdkConstants;\r
import com.android.sdklib.SdkManager;\r
+import com.android.sdklib.ISystemImage.LocationType;\r
import com.android.sdklib.internal.repository.Archive.Arch;\r
import com.android.sdklib.internal.repository.Archive.Os;\r
import com.android.util.Pair;\r
* Store the packages internally. You can use {@link #getPackages()} to retrieve them\r
* at any time later.\r
*\r
- * @param osSdkRoot The path to the SDK folder.\r
+ * @param osSdkRoot The path to the SDK folder, typically {@code sdkManager.getLocation()}.\r
* @param sdkManager An existing SDK manager to list current platforms and addons.\r
* @param monitor A monitor to track progress. Cannot be null.\r
* @return The packages found. Can be retrieved later using {@link #getPackages()}.\r
} else {\r
pkg = AddonPackage.create(target, props);\r
}\r
+\r
+ for (ISystemImage systemImage : target.getSystemImages()) {\r
+ if (systemImage.getLocationType() == LocationType.IN_SYSTEM_IMAGE) {\r
+ File siDir = systemImage.getLocation();\r
+ if (siDir.isDirectory()) {\r
+ Properties siProps = parseProperties(\r
+ new File(siDir, SdkConstants.FN_SOURCE_PROP));\r
+ Package pkg2 = new SystemImagePackage(\r
+ target.getVersion(),\r
+ 0 /*revision*/, // this will use the one from siProps if any\r
+ systemImage.getAbiType(),\r
+ siProps);\r
+ packages.add(pkg2);\r
+ visited.add(siDir);\r
+ }\r
+ }\r
+ }\r
+\r
} catch (Exception e) {\r
monitor.error(e, null);\r
}\r
}\r
monitor.incProgress(1);\r
\r
+ scanMissingSystemImages(sdkManager, visited, packages, monitor);\r
+ monitor.incProgress(1);\r
scanMissingAddons(sdkManager, visited, packages, monitor);\r
monitor.incProgress(1);\r
scanMissingSamples(osSdkRoot, visited, packages, monitor);\r
ISdkLog log) {\r
File addons = new File(new File(sdkManager.getLocation()), SdkConstants.FD_ADDONS);\r
\r
- if (!addons.isDirectory()) {\r
- // It makes listFiles() return null so let's avoid it.\r
+ File[] files = addons.listFiles();\r
+ if (files == null) {\r
return;\r
}\r
\r
- for (File dir : addons.listFiles()) {\r
+ for (File dir : files) {\r
if (dir.isDirectory() && !visited.contains(dir)) {\r
Pair<Map<String, String>, String> infos =\r
SdkManager.parseAddonProperties(dir, sdkManager.getTargets(), log);\r
}\r
\r
/**\r
+ * The sdk manager only lists valid system image via its addons or platform targets.\r
+ * However here we also want to find "broken" system images, that is system images\r
+ * that are located in the sdk/system-images folder but somehow not loaded properly.\r
+ */\r
+ private void scanMissingSystemImages(SdkManager sdkManager,\r
+ HashSet<File> visited,\r
+ ArrayList<Package> packages,\r
+ ISdkLog log) {\r
+ File siRoot = new File(sdkManager.getLocation(), SdkConstants.FD_SYSTEM_IMAGES);\r
+\r
+ File[] files = siRoot.listFiles();\r
+ if (files == null) {\r
+ return;\r
+ }\r
+\r
+ // The system-images folder contains a list of platform folders.\r
+ for (File platformDir : files) {\r
+ if (platformDir.isDirectory() && !visited.contains(platformDir)) {\r
+ visited.add(platformDir);\r
+\r
+ // In the platform directory, we expect a list of abi folders\r
+ File[] platformFiles = platformDir.listFiles();\r
+ if (platformFiles != null) {\r
+ for (File abiDir : platformFiles) {\r
+ if (abiDir.isDirectory() && !visited.contains(abiDir)) {\r
+ visited.add(abiDir);\r
+\r
+ // Ignore empty directories\r
+ File[] abiFiles = abiDir.listFiles();\r
+ if (abiFiles != null && abiFiles.length > 0) {\r
+ Properties props =\r
+ parseProperties(new File(abiDir, SdkConstants.FN_SOURCE_PROP));\r
+\r
+ try {\r
+ Package pkg = SystemImagePackage.createBroken(abiDir, props);\r
+ packages.add(pkg);\r
+ } catch (Exception e) {\r
+ log.error(e, null);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
* Try to find a tools package at the given location.\r
* Returns null if not found.\r
*/\r
import com.android.annotations.VisibleForTesting;\r
import com.android.annotations.VisibleForTesting.Visibility;\r
import com.android.sdklib.AndroidVersion;\r
-import com.android.sdklib.IAndroidTarget;\r
import com.android.sdklib.SdkConstants;\r
import com.android.sdklib.SdkManager;\r
+import com.android.sdklib.SystemImage;\r
import com.android.sdklib.internal.repository.Archive.Arch;\r
import com.android.sdklib.internal.repository.Archive.Os;\r
import com.android.sdklib.repository.SdkRepoConstants;\r
implements IPackageVersion, IPlatformDependency {\r
\r
@VisibleForTesting(visibility=Visibility.PRIVATE)\r
- static final String PROP_ABI = "System.Image.Abi"; //$NON-NLS-1$\r
+ static final String PROP_ABI = "SystemImage.Abi"; //$NON-NLS-1$\r
\r
/** The package version, for platform, add-on and doc packages. */\r
private final AndroidVersion mVersion;\r
mAbi = XmlParserUtils.getXmlString(packageNode, SdkRepoConstants.NODE_ABI);\r
}\r
\r
- /**\r
- * TODO OBSOLETE DOC\r
- * Creates and returns a new system image package based on an actual {@link IAndroidTarget}\r
- * (which {@link IAndroidTarget#isPlatform()} is true) from the {@link SdkManager}.\r
- * This is used to list local SDK folders in which case there is one archive which\r
- * URL is the actual target location.\r
- * <p/>\r
- * By design, this creates a package with one and only one archive.\r
- * @deprecated TODO CHANGE AS ACTUALLY NEEDED\r
- */\r
- @Deprecated\r
- static Package create(AndroidVersion platformVersion, int revision, String abi, Properties props) {\r
- return new SystemImagePackage(platformVersion, revision, abi, props);\r
- }\r
-\r
@VisibleForTesting(visibility=Visibility.PRIVATE)\r
protected SystemImagePackage(\r
AndroidVersion platformVersion,\r
}\r
\r
/**\r
+ * Creates a {@link BrokenPackage} representing a system image that failed to load\r
+ * with the regular {@link SdkManager} workflow.\r
+ *\r
+ * @param abiDir The SDK/system-images/android-N/abi folder\r
+ * @param props The properties located in {@code abiDir} or null if not found.\r
+ * @return A new {@link BrokenPackage} that represents this installed package.\r
+ */\r
+ public static Package createBroken(File abiDir, Properties props) {\r
+\r
+ String abiType = abiDir.getName();\r
+\r
+ StringBuilder sb = new StringBuilder(String.format("Broken %1$s System Image",\r
+ getAbiDisplayNameInternal(abiType)));\r
+\r
+ int apiLevel = IExactApiLevelDependency.API_LEVEL_INVALID;\r
+ try {\r
+ // Try to parse the first number out of the platform folder name.\r
+ String platform = abiDir.getParentFile().getName();\r
+ platform = platform.replaceAll("[^0-9]+", " ").trim(); //$NON-NLS-1$ //$NON-NLS-2$\r
+ int pos = platform.indexOf(' ');\r
+ if (pos >= 0) {\r
+ platform = platform.substring(0, pos);\r
+ }\r
+\r
+ apiLevel = Integer.parseInt(platform);\r
+\r
+ sb.append(String.format(", API %1$d", apiLevel));\r
+ } catch (Exception ignore) {\r
+ }\r
+\r
+ String shortDesc = sb.toString();\r
+\r
+ return new BrokenPackage(props, shortDesc, shortDesc /*longDesc*/,\r
+ IMinApiLevelDependency.MIN_API_LEVEL_NOT_SPECIFIED,\r
+ apiLevel,\r
+ abiDir.getAbsolutePath());\r
+ }\r
+\r
+ /**\r
* Save the properties of the current packages in the given {@link Properties} object.\r
* These properties will later be given to a constructor that takes a {@link Properties} object.\r
*/\r
\r
/** Returns a display-friendly name for the ABI of the system-image. */\r
public String getAbiDisplayName() {\r
- String abi = mAbi\r
- .replace("armeabi", "ARM EABI") //$NON-NLS-1$ //$NON-NLS-2$\r
- .replace("x86", "Intel x86 Atom") //$NON-NLS-1$ //$NON-NLS-2$\r
- .replace("-", " "); //$NON-NLS-1$ //$NON-NLS-2$\r
- return abi;\r
+ return getAbiDisplayNameInternal(mAbi);\r
+ }\r
+\r
+ private static String getAbiDisplayNameInternal(String abi) {\r
+ return abi.replace("armeabi", "ARM EABI") //$NON-NLS-1$ //$NON-NLS-2$\r
+ .replace("x86", "Intel x86 Atom") //$NON-NLS-1$ //$NON-NLS-2$\r
+ .replace("-", " "); //$NON-NLS-1$ //$NON-NLS-2$\r
}\r
\r
/**\r
@Override\r
public File getInstallFolder(String osSdkRoot, SdkManager sdkManager) {\r
File folder = new File(osSdkRoot, SdkConstants.FD_SYSTEM_IMAGES);\r
- folder = new File(folder, "android-" + mVersion.getApiString()); //$NON-NLS-1$\r
+ folder = new File(folder, SystemImage.ANDROID_PREFIX + mVersion.getApiString());\r
\r
// Computes a folder directory using the sanitized abi string.\r
String abi = mAbi;\r
}\r
\r
/**\r
+ * Appends the given {@code segments} to the {@code base} file.\r
+ *\r
+ * @param base A base file, non-null.\r
+ * @param segments Individual folder or filename segments to append to the base file.\r
+ * @return A new file representing the concatenation of the base path with all the segments.\r
+ */\r
+ public static File append(File base, String...segments) {\r
+ for (String segment : segments) {\r
+ base = new File(base, segment);\r
+ }\r
+ return base;\r
+ }\r
+\r
+ /**\r
+ * Appends the given {@code segments} to the {@code base} file.\r
+ *\r
+ * @param base A base file path, non-empty and non-null.\r
+ * @param segments Individual folder or filename segments to append to the base path.\r
+ * @return A new file representing the concatenation of the base path with all the segments.\r
+ */\r
+ public static File append(String base, String...segments) {\r
+ return append(new File(base), segments);\r
+ }\r
+\r
+ /**\r
* Helper to delete a file or a directory.\r
* For a directory, recursively deletes all of its content.\r
* Files that cannot be deleted right away are marked for deletion on exit.\r
package com.android.sdklib;
+import com.android.sdklib.ISystemImage.LocationType;
import com.android.sdklib.SdkManager.LayoutlibVersion;
-public class SdkManagerTest extends SdkManagerTestCase {
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- }
+import java.util.Arrays;
+import java.util.regex.Pattern;
- @Override
- public void tearDown() throws Exception {
- super.tearDown();
- }
+public class SdkManagerTest extends SdkManagerTestCase {
@SuppressWarnings("deprecation")
public void testSdkManager_LayoutlibVersion() {
assertSame(lv, sdkman.getMaxLayoutlibVersion());
}
+
+ public void testSdkManager_SystemImage() throws Exception {
+ SdkManager sdkman = getSdkManager();
+ assertEquals("[PlatformTarget API 0 rev 1]", Arrays.toString(sdkman.getTargets()));
+ IAndroidTarget t = sdkman.getTargets()[0];
+
+ // By default SdkManagerTestCase creates an SDK with one platform containing
+ // a legacy armeabi system image.
+ assertEquals(
+ "[SystemImage ABI=armeabi, location in platform legacy='$SDK/platforms/v0_0/images']",
+ cleanPath(sdkman, Arrays.toString(t.getSystemImages())));
+
+ // Now add a few "platform subfolders" system images and reload the SDK.
+ // This disables the "legacy" mode, which means that although the armeabi
+ // target from above is present, it is no longer visible.
+
+ makeSystemImageFolder(new SystemImage(
+ sdkman, t, LocationType.IN_PLATFORM_SUBFOLDER, SdkConstants.ABI_ARMEABI_V7A));
+ makeSystemImageFolder(new SystemImage(
+ sdkman, t, LocationType.IN_PLATFORM_SUBFOLDER, SdkConstants.ABI_INTEL_ATOM));
+
+ sdkman.reloadSdk(getLog());
+ assertEquals("[PlatformTarget API 0 rev 1]", Arrays.toString(sdkman.getTargets()));
+ t = sdkman.getTargets()[0];
+
+ assertEquals(
+ "[SystemImage ABI=armeabi-v7a, location in platform subfolder='$SDK/platforms/v0_0/images/armeabi-v7a', " +
+ "SystemImage ABI=x86, location in platform subfolder='$SDK/platforms/v0_0/images/x86']",
+ cleanPath(sdkman, Arrays.toString(t.getSystemImages())));
+
+ // Now add arm + arm v7a images using the new SDK/system-images.
+ // The x86 one from the platform subfolder is still visible.
+ // The armeabi one from the legacy folder is overridden by the new one.
+ // The armeabi-v7a one from the platform subfolder is overridden by the new one.
+
+ makeSystemImageFolder(new SystemImage(
+ sdkman, t, LocationType.IN_SYSTEM_IMAGE, SdkConstants.ABI_ARMEABI));
+ makeSystemImageFolder(new SystemImage(
+ sdkman, t, LocationType.IN_SYSTEM_IMAGE, SdkConstants.ABI_ARMEABI_V7A));
+
+ sdkman.reloadSdk(getLog());
+ assertEquals("[PlatformTarget API 0 rev 1]", Arrays.toString(sdkman.getTargets()));
+ t = sdkman.getTargets()[0];
+
+ assertEquals(
+ "[SystemImage ABI=armeabi, location in system image='$SDK/system-images/android-0/armeabi', " +
+ "SystemImage ABI=armeabi-v7a, location in system image='$SDK/system-images/android-0/armeabi-v7a', " +
+ "SystemImage ABI=x86, location in platform subfolder='$SDK/platforms/v0_0/images/x86']",
+ cleanPath(sdkman, Arrays.toString(t.getSystemImages())));
+ }
+
+ public void testSdkManager_SystemImage_LegacyOverride() throws Exception {
+ SdkManager sdkman = getSdkManager();
+ assertEquals("[PlatformTarget API 0 rev 1]", Arrays.toString(sdkman.getTargets()));
+ IAndroidTarget t = sdkman.getTargets()[0];
+
+ // By default SdkManagerTestCase creates an SDK with one platform containing
+ // a legacy armeabi system image.
+ assertEquals(
+ "[SystemImage ABI=armeabi, location in platform legacy='$SDK/platforms/v0_0/images']",
+ cleanPath(sdkman, Arrays.toString(t.getSystemImages())));
+
+ // Now add a different ABI system image in the new system-images folder.
+ // This does not hide the legacy one as long as the ABI type is different
+ // (to contrast: having at least one sub-folder in the platform's legacy images folder
+ // will hide the legacy system image. Whereas this does not happen with the new type.)
+
+ makeSystemImageFolder(new SystemImage(
+ sdkman, t, LocationType.IN_SYSTEM_IMAGE, SdkConstants.ABI_INTEL_ATOM));
+
+ sdkman.reloadSdk(getLog());
+ assertEquals("[PlatformTarget API 0 rev 1]", Arrays.toString(sdkman.getTargets()));
+ t = sdkman.getTargets()[0];
+
+ assertEquals(
+ "[SystemImage ABI=armeabi, location in platform legacy='$SDK/platforms/v0_0/images', " +
+ "SystemImage ABI=x86, location in system image='$SDK/system-images/android-0/x86']",
+ cleanPath(sdkman, Arrays.toString(t.getSystemImages())));
+
+ // Now if we have one new system-image using the same ABI type, it will override the
+ // legacy one. This gives us a good path for updates.
+
+ makeSystemImageFolder(new SystemImage(
+ sdkman, t, LocationType.IN_SYSTEM_IMAGE, SdkConstants.ABI_ARMEABI));
+
+
+ sdkman.reloadSdk(getLog());
+ assertEquals("[PlatformTarget API 0 rev 1]", Arrays.toString(sdkman.getTargets()));
+ t = sdkman.getTargets()[0];
+
+ assertEquals(
+ "[SystemImage ABI=armeabi, location in system image='$SDK/system-images/android-0/armeabi', " +
+ "SystemImage ABI=x86, location in system image='$SDK/system-images/android-0/x86']",
+ cleanPath(sdkman, Arrays.toString(t.getSystemImages())));
+ }
+
+ /**
+ * Sanitizes the paths used when testing results.
+ * <p/>
+ * The system image text representation contains the absolute path to the SDK.
+ * However the SDK path is actually a randomized location.
+ * We clean it by replacing it by the constant '$SDK'.
+ * Also all the Windows path separators are converted to unix-like / separators.
+ */
+ private String cleanPath(SdkManager sdkman, String string) {
+ return string
+ .replaceAll(Pattern.quote(sdkman.getLocation()), "\\$SDK") //$NON-NLS-1$
+ .replace('\\', '/');
+ }
}
* A empty test method to placate the JUnit test runner, which doesn't
* like TestCase classes with no test methods.
*/
- public void testSetup() {
+ public void testPlaceholder() {
}
/**
* @throws IOException
*/
private File makeFakeSdk() throws IOException {
-
// First we create a temp file to "reserve" the temp directory name we want to use.
File tmpFile = File.createTempFile(
this.getClass().getSimpleName() + '_' + this.getName(), null);
File imagesDir = new File(targetDir, "images");
imagesDir.mkdirs();
-
new File(imagesDir, "userdata.img").createNewFile();
+
File skinsDir = new File(targetDir, "skins");
File hvgaDir = new File(skinsDir, "HVGA");
hvgaDir.mkdirs();
}
/**
+ * Creates the system image folder and places a fake userdata.img in it.
+ *
+ * @param systemImage A system image with a valid location.
+ * @throws IOException if the file fails to be created.
+ */
+ protected void makeSystemImageFolder(ISystemImage systemImage) throws IOException {
+ File imagesDir = systemImage.getLocation();
+ imagesDir.mkdirs();
+ new File(imagesDir, "userdata.img").createNewFile();
+ }
+
+ /**
* Recursive delete directory. Mostly for fake SDKs.
*
* @param root directory to delete
--- /dev/null
+/*
+ * Copyright (C) 2011 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.repository;
+
+import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.SdkConstants;
+import com.android.sdklib.SdkManager;
+import com.android.sdklib.SdkManagerTestCase;
+import com.android.sdklib.SystemImage;
+import com.android.sdklib.ISystemImage.LocationType;
+
+import java.util.Arrays;
+
+public class LocalSdkParserTest extends SdkManagerTestCase {
+
+ public void testLocalSdkParser_SystemImages() throws Exception {
+ SdkManager sdkman = getSdkManager();
+ LocalSdkParser parser = new LocalSdkParser();
+ MockMonitor monitor = new MockMonitor();
+
+ // By default SdkManagerTestCase creates an SDK with one platform containing
+ // a legacy armeabi system image (this is not a separate system image package)
+
+ assertEquals(
+ "[SDK Platform Android 0.0, API 0, revision 1]",
+ Arrays.toString(parser.parseSdk(sdkman.getLocation(), sdkman, monitor)));
+
+ // Now add a few "platform subfolders" system images and reload the SDK.
+ // This disables the "legacy" mode but it still doesn't create any system image package
+
+ IAndroidTarget t = sdkman.getTargets()[0];
+ makeSystemImageFolder(new SystemImage(
+ sdkman, t, LocationType.IN_PLATFORM_SUBFOLDER, SdkConstants.ABI_ARMEABI_V7A));
+ makeSystemImageFolder(new SystemImage(
+ sdkman, t, LocationType.IN_PLATFORM_SUBFOLDER, SdkConstants.ABI_INTEL_ATOM));
+
+ sdkman.reloadSdk(getLog());
+ t = sdkman.getTargets()[0];
+
+ assertEquals(
+ "[SDK Platform Android 0.0, API 0, revision 1]",
+ Arrays.toString(parser.parseSdk(sdkman.getLocation(), sdkman, monitor)));
+
+ // Now add arm + arm v7a images using the new SDK/system-images.
+ // The local parser will find the 2 system image packages which are associated
+ // with the PlatformTarger in the SdkManager.
+
+ makeSystemImageFolder(new SystemImage(
+ sdkman, t, LocationType.IN_SYSTEM_IMAGE, SdkConstants.ABI_ARMEABI));
+ makeSystemImageFolder(new SystemImage(
+ sdkman, t, LocationType.IN_SYSTEM_IMAGE, SdkConstants.ABI_ARMEABI_V7A));
+
+ sdkman.reloadSdk(getLog());
+
+ assertEquals(
+ "[SDK Platform Android 0.0, API 0, revision 1, " +
+ "ARM EABI System Image, Android API 0, revision 0, " +
+ "ARM EABI v7a System Image, Android API 0, revision 0]",
+ Arrays.toString(parser.parseSdk(sdkman.getLocation(), sdkman, monitor)));
+
+ // Now add an x86 image using the new SDK/system-images.
+ // How this time we do NOT reload the SdkManager instance. Instead the parser
+ // will find an unused system image and load it as a "broken package".
+
+ makeSystemImageFolder(new SystemImage(
+ sdkman, t, LocationType.IN_SYSTEM_IMAGE, SdkConstants.ABI_INTEL_ATOM));
+
+ assertEquals(
+ "[SDK Platform Android 0.0, API 0, revision 1, " +
+ "ARM EABI System Image, Android API 0, revision 0, " +
+ "ARM EABI v7a System Image, Android API 0, revision 0, " +
+ "Broken Intel x86 Atom System Image, API 0]",
+ Arrays.toString(parser.parseSdk(sdkman.getLocation(), sdkman, monitor)));
+ }
+
+}
+
\r
import com.android.sdklib.AndroidVersion;\r
import com.android.sdklib.IAndroidTarget;\r
+import com.android.sdklib.ISystemImage;\r
import com.android.sdklib.SdkConstants;\r
+import com.android.sdklib.SystemImage;\r
+import com.android.sdklib.ISystemImage.LocationType;\r
+import com.android.sdklib.io.FileOp;\r
\r
import java.util.Map;\r
\r
private final IAndroidTarget mParentTarget;\r
private final int mRevision;\r
private final String mName;\r
+ private ISystemImage[] mSystemImages;\r
\r
public MockAddonTarget(String name, IAndroidTarget parentTarget, int revision) {\r
mName = name;\r
return getName();\r
}\r
\r
- public String[] getAbiList() {\r
- return new String[] { SdkConstants.ABI_ARMEABI };\r
+ public ISystemImage[] getSystemImages() {\r
+ if (mSystemImages == null) {\r
+ SystemImage si = new SystemImage(\r
+ FileOp.append(getLocation(), SdkConstants.OS_IMAGES_FOLDER),\r
+ LocationType.IN_PLATFORM_LEGACY,\r
+ SdkConstants.ABI_ARMEABI);\r
+ mSystemImages = new SystemImage[] { si };\r
+ }\r
+ return mSystemImages;\r
}\r
\r
- public String getImagePath(String abiType) {\r
- return SdkConstants.OS_IMAGES_FOLDER;\r
+ public ISystemImage getSystemImage(String abiType) {\r
+ if (SdkConstants.ABI_ARMEABI.equals(abiType)) {\r
+ return getSystemImages()[0];\r
+ }\r
+ return null;\r
}\r
\r
public String getLocation() {\r
- return "";\r
+ return "/sdk/add-ons/addon-" + mName;\r
}\r
\r
public IOptionalLibrary[] getOptionalLibraries() {\r
}\r
\r
public String getPath(int pathId) {\r
- return null;\r
+ throw new UnsupportedOperationException("Implement this as needed for tests");\r
}\r
\r
public String[] getPlatformLibraries() {\r
\r
import com.android.sdklib.AndroidVersion;\r
import com.android.sdklib.IAndroidTarget;\r
+import com.android.sdklib.ISystemImage;\r
import com.android.sdklib.SdkConstants;\r
+import com.android.sdklib.SystemImage;\r
+import com.android.sdklib.ISystemImage.LocationType;\r
+import com.android.sdklib.io.FileOp;\r
\r
import java.util.Map;\r
\r
\r
private final int mApiLevel;\r
private final int mRevision;\r
+ private ISystemImage[] mSystemImages;\r
\r
public MockPlatformTarget(int apiLevel, int revision) {\r
mApiLevel = apiLevel;\r
return getName();\r
}\r
\r
- public String[] getAbiList() {\r
- return new String[] { SdkConstants.ABI_ARMEABI };\r
+ public ISystemImage[] getSystemImages() {\r
+ if (mSystemImages == null) {\r
+ SystemImage si = new SystemImage(\r
+ FileOp.append(getLocation(), SdkConstants.OS_IMAGES_FOLDER),\r
+ LocationType.IN_PLATFORM_LEGACY,\r
+ SdkConstants.ABI_ARMEABI);\r
+ mSystemImages = new SystemImage[] { si };\r
+ }\r
+ return mSystemImages;\r
}\r
\r
- public String getImagePath(String abiType) {\r
- return SdkConstants.OS_IMAGES_FOLDER;\r
+ public ISystemImage getSystemImage(String abiType) {\r
+ if (SdkConstants.ABI_ARMEABI.equals(abiType)) {\r
+ return getSystemImages()[0];\r
+ }\r
+ return null;\r
}\r
\r
public String getLocation() {\r
- return "";\r
+ return "/sdk/platforms/android-" + getVersion().getApiString();\r
}\r
\r
public IOptionalLibrary[] getOptionalLibraries() {\r
}\r
\r
public String getPath(int pathId) {\r
- return null;\r
+ throw new UnsupportedOperationException("Implement this as needed for tests");\r
}\r
\r
public String[] getPlatformLibraries() {\r
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.ISdkLog;
+import com.android.sdklib.ISystemImage;
import com.android.sdklib.SdkConstants;
import com.android.sdklib.SdkManager;
import com.android.sdklib.internal.avd.AvdInfo;
}
// select the abi type
- if (target != null && target.getAbiList().length > 0) {
- mAbiTypeCombo.setEnabled(target.getAbiList().length > 1);
+ ISystemImage[] systemImages = getSystemImages(target);
+ if (target != null && systemImages.length > 0) {
+ mAbiTypeCombo.setEnabled(systemImages.length > 1);
String abiType = AvdInfo.getPrettyAbiType(mEditAvdInfo.getAbiType());
int n = mAbiTypeCombo.getItemCount();
for (int i = 0; i < n; i++) {
if (index >= 0) {
String targetName = mTargetCombo.getItem(index);
IAndroidTarget target = mCurrentTargets.get(targetName);
- String[] arches = target.getAbiList();
- mAbiTypeCombo.setEnabled(arches.length > 1);
+ ISystemImage[] systemImages = getSystemImages(target);
+
+ mAbiTypeCombo.setEnabled(systemImages.length > 1);
// If user explicitly selected an ABI before, preserve that option
// If user did not explicitly select before (only one option before)
mAbiTypeCombo.removeAll();
int i;
- for ( i = 0; i < arches.length ; i++ ) {
- String prettyAbiType = AvdInfo.getPrettyAbiType(arches[i]);
+ for ( i = 0; i < systemImages.length ; i++ ) {
+ String prettyAbiType = AvdInfo.getPrettyAbiType(systemImages[i].getAbiType());
mAbiTypeCombo.add(prettyAbiType);
if (!found) {
found = prettyAbiType.equals(selected);
}
}
- if (arches.length == 1) {
+ if (systemImages.length == 1) {
mAbiTypeCombo.select(0);
}
}
int index = mTargetCombo.getSelectionIndex();
String targetName = mTargetCombo.getItem(index);
IAndroidTarget target = mCurrentTargets.get(targetName);
- if (target.getAbiList().length > 1 && mAbiTypeCombo.getSelectionIndex() < 0) {
- error = "An abi type must be selected in order to create an AVD.";
+ ISystemImage[] systemImages = getSystemImages(target);
+ if (systemImages.length > 1 && mAbiTypeCombo.getSelectionIndex() < 0) {
+ error = "An ABI type must be selected in order to create an AVD.";
}
}
// get the abi type
mAbiType = SdkConstants.ABI_ARMEABI;
- if (target.getAbiList().length > 0) {
+ ISystemImage[] systemImages = getSystemImages(target);
+ if (systemImages.length > 0) {
int abiIndex = mAbiTypeCombo.getSelectionIndex();
if (abiIndex >= 0) {
String prettyname = mAbiTypeCombo.getItem(abiIndex);
return success;
}
+ /**
+ * Returns the list of system images of a target.
+ * <p/>
+ * If target is null, returns an empty list.
+ * If target is an add-on with no system images, return the list from its parent platform.
+ *
+ * @param target An IAndroidTarget. Can be null.
+ * @return A non-null ISystemImage array. Can be empty.
+ */
+ private ISystemImage[] getSystemImages(IAndroidTarget target) {
+ if (target != null) {
+ ISystemImage[] images = target.getSystemImages();
+
+ if ((images == null || images.length == 0) && !target.isPlatform()) {
+ // If an add-on does not provide any system images, use the ones from the parent.
+ images = target.getParent().getSystemImages();
+ }
+
+ if (images != null) {
+ return images;
+ }
+ }
+
+ return new ISystemImage[0];
+ }
+
// End of hiding from SWT Designer
//$hide<<$
}