Java tutorial
/* * Copyright (C) 2015 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.repository.targets; import com.android.SdkConstants; import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.annotations.VisibleForTesting; import com.android.repository.api.LocalPackage; import com.android.repository.api.ProgressIndicator; import com.android.repository.impl.meta.TypeDetails; import com.android.repository.io.FileOp; import com.android.sdklib.AndroidTargetHash; import com.android.sdklib.AndroidVersion; import com.android.sdklib.BuildToolInfo; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkVersionInfo; import com.android.sdklib.internal.project.ProjectProperties; import com.android.sdklib.repository.PackageParserUtils; import com.android.sdklib.repository.AndroidSdkHandler; import com.android.sdklib.repository.meta.DetailsTypes; import com.google.common.base.Charsets; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.common.io.Files; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Type; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; /** * Represents a platform target in the SDK. */ public class PlatformTarget implements IAndroidTarget { /** * Default vendor for platform targets */ public static final String PLATFORM_VENDOR = "Android Open Source Project"; /** * "Android NN" is the default name for platform targets. */ private static final String PLATFORM_NAME = "Android %s"; /** * "Android NN (Preview)" is the default name for preview platform targets. */ private static final String PLATFORM_NAME_PREVIEW = "Android %s (Preview)"; /** * The {@link LocalPackage} from which this target was created. */ private LocalPackage mPackage; /** * The {@link TypeDetails} of {@link #mPackage}. */ private DetailsTypes.PlatformDetailsType mDetails; /** * Additional {@link IAndroidTarget.OptionalLibrary}s provided by this target. */ private List<OptionalLibrary> mOptionalLibraries = ImmutableList.of(); /** * The emulator skins for this target, including those included in the package as well as those * from associated system images. */ private Set<File> mSkins; /** * Parsed version of the {@code build.prop} file in {@link #mPackage}. */ private Map<String, String> mBuildProps; /** * Reference to the latest {@link BuildToolInfo}. */ private BuildToolInfo mBuildToolInfo; /** * Location of the sources for this package. If {@code null} the legacy path will be used. */ private File mSourcesPath = null; /** * Construct a new {@code PlatformTarget} based on the given package. */ public PlatformTarget(@NonNull LocalPackage p, @NonNull AndroidSdkHandler sdkHandler, @NonNull FileOp fop, @NonNull ProgressIndicator progress) { mPackage = p; TypeDetails details = p.getTypeDetails(); assert details instanceof DetailsTypes.PlatformDetailsType; mDetails = (DetailsTypes.PlatformDetailsType) details; File optionalDir = new File(p.getLocation(), "optional"); if (optionalDir.isDirectory()) { File optionalJson = new File(optionalDir, "optional.json"); if (optionalJson.isFile()) { mOptionalLibraries = getLibsFromJson(optionalJson); } } File buildProp = new File(getLocation(), SdkConstants.FN_BUILD_PROP); if (!fop.isFile(buildProp)) { String message = "Build properties not found for package " + p.getDisplayName(); progress.logWarning(message); throw new IllegalArgumentException(message); } try { mBuildProps = ProjectProperties.parsePropertyStream(fop.newFileInputStream(buildProp), buildProp.getPath(), null); } catch (IOException ignore) { } if (mBuildProps == null) { mBuildProps = Maps.newHashMap(); } mBuildToolInfo = sdkHandler.getLatestBuildTool(progress, getVersion().isPreview()); mSkins = Sets.newTreeSet(PackageParserUtils.parseSkinFolder(getFile(IAndroidTarget.SKINS), fop)); } public void setSources(@Nullable File location) { mSourcesPath = location; } /** * Simple struct used by {@link Gson} when parsing the library file. */ public static class Library { String name; String jar; boolean manifest; } /** * Parses {@link IAndroidTarget.OptionalLibrary}s from the given json file. */ @VisibleForTesting @NonNull static List<OptionalLibrary> getLibsFromJson(@NonNull File jsonFile) { Gson gson = new Gson(); try { Type collectionType = new TypeToken<Collection<Library>>() { }.getType(); Collection<Library> libs = gson.fromJson(Files.newReader(jsonFile, Charsets.UTF_8), collectionType); // convert into the right format. List<OptionalLibrary> optionalLibraries = Lists.newArrayListWithCapacity(libs.size()); File rootFolder = jsonFile.getParentFile(); for (Library lib : libs) { optionalLibraries.add( new OptionalLibraryImpl(lib.name, new File(rootFolder, lib.jar), lib.name, lib.manifest)); } return optionalLibraries; } catch (FileNotFoundException e) { // shouldn't happen since we've checked the file is here, but can happen in // some cases (too many files open). return Collections.emptyList(); } } @Override public String getLocation() { return mPackage.getLocation().getPath() + File.separator; } /** * {@inheritDoc} * * For platform, this is always {@link #PLATFORM_VENDOR} */ @Override public String getVendor() { return PLATFORM_VENDOR; } @Override public String getName() { AndroidVersion version = getVersion(); if (version.isPreview()) { return String.format(PLATFORM_NAME_PREVIEW, version); } else { return String.format(PLATFORM_NAME, version); } } @Override public String getFullName() { return getName(); } @Override public String getDescription() { // Unused outside swt return getName(); } @NonNull @Override public AndroidVersion getVersion() { return mDetails.getAndroidVersion(); } @Override public String getVersionName() { return SdkVersionInfo.getVersionString(mDetails.getApiLevel()); } @Override public int getRevision() { return mPackage.getVersion().getMajor(); } @Override public boolean isPlatform() { return true; } @Override public IAndroidTarget getParent() { return null; } @NonNull @Override public String getPath(int pathId) { switch (pathId) { case ANDROID_JAR: return getLocation() + SdkConstants.FN_FRAMEWORK_LIBRARY; case UI_AUTOMATOR_JAR: return getLocation() + SdkConstants.FN_UI_AUTOMATOR_LIBRARY; case SOURCES: if (mSourcesPath != null) { return mSourcesPath.getPath(); } // It seems that such a path doesn't usually exist, but this is left here to // preserve the old behavior. return getLocation() + SdkConstants.FD_ANDROID_SOURCES; case ANDROID_AIDL: return getLocation() + SdkConstants.FN_FRAMEWORK_AIDL; case SAMPLES: return getLocation() + SdkConstants.OS_PLATFORM_SAMPLES_FOLDER; case SKINS: return getLocation() + SdkConstants.OS_SKINS_FOLDER; case TEMPLATES: return getLocation() + SdkConstants.OS_PLATFORM_TEMPLATES_FOLDER; case DATA: return getLocation() + SdkConstants.OS_PLATFORM_DATA_FOLDER; case ATTRIBUTES: return getLocation() + SdkConstants.OS_PLATFORM_ATTRS_XML; case MANIFEST_ATTRIBUTES: return getLocation() + SdkConstants.OS_PLATFORM_ATTRS_MANIFEST_XML; case RESOURCES: return getLocation() + SdkConstants.OS_PLATFORM_RESOURCES_FOLDER; case FONTS: return getLocation() + SdkConstants.OS_PLATFORM_FONTS_FOLDER; case LAYOUT_LIB: return getLocation() + SdkConstants.OS_PLATFORM_DATA_FOLDER + SdkConstants.FN_LAYOUTLIB_JAR; case WIDGETS: return getLocation() + SdkConstants.OS_PLATFORM_DATA_FOLDER + SdkConstants.FN_WIDGETS; case ACTIONS_ACTIVITY: return getLocation() + SdkConstants.OS_PLATFORM_DATA_FOLDER + SdkConstants.FN_INTENT_ACTIONS_ACTIVITY; case ACTIONS_BROADCAST: return getLocation() + SdkConstants.OS_PLATFORM_DATA_FOLDER + SdkConstants.FN_INTENT_ACTIONS_BROADCAST; case ACTIONS_SERVICE: return getLocation() + SdkConstants.OS_PLATFORM_DATA_FOLDER + SdkConstants.FN_INTENT_ACTIONS_SERVICE; case CATEGORIES: return getLocation() + SdkConstants.OS_PLATFORM_DATA_FOLDER + SdkConstants.FN_INTENT_CATEGORIES; case ANT: return getLocation() + SdkConstants.OS_PLATFORM_ANT_FOLDER; default: return getLocation(); } } @NonNull @Override public File getFile(int pathId) { return new File(getPath(pathId)); } @Nullable @Override public BuildToolInfo getBuildToolInfo() { return mBuildToolInfo; } @NonNull @Override public List<String> getBootClasspath() { return ImmutableList.of(getPath(IAndroidTarget.ANDROID_JAR)); } @NonNull @Override public List<OptionalLibrary> getOptionalLibraries() { return mOptionalLibraries; } @NonNull @Override public List<OptionalLibrary> getAdditionalLibraries() { return ImmutableList.of(); } @Override public boolean hasRenderingLibrary() { return true; } @NonNull @Override public File[] getSkins() { return mSkins.toArray(new File[mSkins.size()]); } public int getLayoutlibApi() { return mDetails.getLayoutlib().getApi(); } @Nullable @Override public File getDefaultSkin() { // TODO: validate choice to ignore property in sdk.properties // only one skin? easy. if (mSkins.size() == 1) { return mSkins.iterator().next(); } String skinName; // otherwise try to find a good default. if (getVersion().getApiLevel() >= 11 && getVersion().getApiLevel() <= 13) { skinName = "WXGA"; } else if (getVersion().getApiLevel() >= 4) { // at this time, this is the default skin for all older platforms that had 2+ skins. skinName = "WVGA800"; } else { skinName = "HVGA"; // this is for 1.5 and earlier. } return new File(getFile(IAndroidTarget.SKINS), skinName); } /** * {@inheritDoc} * * For platforms this is always {@link SdkConstants#ANDROID_TEST_RUNNER_LIB}. */ @NonNull @Override public String[] getPlatformLibraries() { return new String[] { SdkConstants.ANDROID_TEST_RUNNER_LIB }; } @Nullable @Override public String getProperty(@NonNull String name) { return mBuildProps.get(name); } @Nullable @Override public Map<String, String> getProperties() { return mBuildProps; } @NonNull @Override public String getShortClasspathName() { return getName(); } @NonNull @Override public String getClasspathName() { return getName(); } @Override public boolean canRunOn(@NonNull IAndroidTarget target) { if (getVersion().isPreview()) { return target.getVersion().equals(getVersion()); } return target.getVersion().getApiLevel() > getVersion().getApiLevel(); } @NonNull @Override public String hashString() { return AndroidTargetHash.getPlatformHashString(getVersion()); } @Override public int compareTo(@NonNull IAndroidTarget o) { int res = getVersion().compareTo(o.getVersion()); if (res != 0) { return res; } return o.isPlatform() ? 0 : -1; } @Override public boolean equals(Object obj) { return obj instanceof PlatformTarget && compareTo((PlatformTarget) obj) == 0; } @Override public int hashCode() { return hashString().hashCode(); } }