| /* |
| * Copyright (C) 2013 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.tools.idea.templates; |
| |
| import com.android.annotations.VisibleForTesting; |
| import com.android.sdklib.AndroidTargetHash; |
| import com.android.sdklib.AndroidVersion; |
| import com.android.tools.idea.npw.AssetStudioAssetGenerator; |
| import com.google.common.base.Function; |
| import com.intellij.openapi.diagnostic.Logger; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.w3c.dom.*; |
| |
| import java.util.Collection; |
| import java.util.LinkedHashMap; |
| import java.util.Locale; |
| import java.util.Map; |
| |
| import static com.android.tools.idea.templates.Template.*; |
| |
| /** An ADT template along with metadata */ |
| public class TemplateMetadata { |
| private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.templates.TemplateMetadata"); |
| |
| public static final String ATTR_PARENT_ACTIVITY_CLASS = "parentActivityClass"; |
| public static final String ATTR_ACTIVITY_TITLE = "activityTitle"; |
| public static final String ATTR_IS_LAUNCHER = "isLauncher"; |
| public static final String ATTR_IS_LIBRARY_MODULE = "isLibraryProject"; |
| public static final String ATTR_CREATE_ICONS = "createIcons"; |
| public static final String ATTR_COPY_ICONS = "copyIcons"; |
| public static final String ATTR_TARGET_API = "targetApi"; |
| public static final String ATTR_TARGET_API_STRING = "targetApiString"; |
| public static final String ATTR_MIN_API = "minApi"; |
| public static final String ATTR_MIN_BUILD_API = "minBuildApi"; |
| public static final String ATTR_BUILD_API = "buildApi"; |
| public static final String ATTR_BUILD_API_STRING = "buildApiString"; |
| public static final String ATTR_REVISION = "revision"; |
| public static final String ATTR_MIN_API_LEVEL = "minApiLevel"; |
| public static final String ATTR_PACKAGE_NAME = "packageName"; |
| public static final String ATTR_PACKAGE_ROOT = "packageRoot"; |
| public static final String ATTR_RELATIVE_PACKAGE = "relativePackage"; |
| public static final String ATTR_APP_TITLE = "appTitle"; |
| public static final String ATTR_BASE_THEME = "baseTheme"; |
| public static final String ATTR_IS_NEW_PROJECT = "isNewProject"; |
| public static final String ATTR_IS_GRADLE = "isGradle"; |
| public static final String ATTR_TOP_OUT = "topOut"; |
| public static final String ATTR_PROJECT_OUT = "projectOut"; |
| public static final String ATTR_SRC_OUT = "srcOut"; |
| public static final String ATTR_RES_OUT = "resOut"; |
| public static final String ATTR_MANIFEST_OUT = "manifestOut"; |
| public static final String ATTR_TEST_OUT = "testOut"; |
| public static final String ATTR_MAVEN_URL = "mavenUrl"; |
| public static final String ATTR_SRC_DIR = "srcDir"; |
| public static final String ATTR_RES_DIR = "resDir"; |
| public static final String ATTR_MANIFEST_DIR = "manifestDir"; |
| public static final String ATTR_TEST_DIR = "testDir"; |
| public static final String ATTR_AIDL_DIR = "aidlDir"; |
| public static final String ATTR_AIDL_OUT = "aidlOut"; |
| public static final String ATTR_DEBUG_KEYSTORE_SHA1 = "debugKeystoreSha1"; |
| public static final String ATTR_BUILD_TOOLS_VERSION = "buildToolsVersion"; |
| public static final String ATTR_GRADLE_PLUGIN_VERSION = "gradlePluginVersion"; |
| public static final String ATTR_GRADLE_VERSION = "gradleVersion"; |
| public static final String ATTR_JAVA_VERSION = "javaVersion"; |
| public static final String ATTR_SDK_DIR = "sdkDir"; |
| public static final String ATTR_PER_MODULE_REPOS = "perModuleRepositories"; |
| public static final String ATTR_ICON_NAME = "iconName"; |
| public static final String ATTR_APPLICATION_PACKAGE = "applicationPackage"; |
| public static final String ATTR_SOURCE_PROVIDER_NAME = "sourceProviderName"; |
| |
| public static final String ATTR_DEPENDENCIES_LIST = "dependencyList"; |
| public static final String ATTR_FRAGMENTS_EXTRA = "usesFragments"; |
| public static final String ATTR_ACTION_BAR_EXTRA = "usesActionBar"; |
| public static final String ATTR_GRID_LAYOUT_EXTRA = "usesGridLayout"; |
| public static final String ATTR_NAVIGATION_DRAWER_EXTRA = "usesNavigationDrawer"; |
| |
| public static final String TAG_CATEGORY = "category"; |
| public static final String TAG_FORMFACTOR = "formfactor"; |
| |
| private final Document myDocument; |
| private final Map<String, Parameter> myParameterMap; |
| |
| private final AssetStudioAssetGenerator.AssetType myIconType; |
| private final String myIconName; |
| private String myFormFactor = null; |
| private String myCategory = null; |
| |
| @VisibleForTesting |
| public TemplateMetadata(@NotNull Document document) { |
| myDocument = document; |
| |
| NodeList parameters = myDocument.getElementsByTagName(TAG_PARAMETER); |
| myParameterMap = new LinkedHashMap<String, Parameter>(parameters.getLength()); |
| for (int index = 0, max = parameters.getLength(); index < max; index++) { |
| Element element = (Element) parameters.item(index); |
| Parameter parameter = new Parameter(this, element); |
| if (parameter.id != null) { |
| myParameterMap.put(parameter.id, parameter); |
| } |
| } |
| |
| NodeList icons = myDocument.getElementsByTagName(TAG_ICONS); |
| if (icons.getLength() > 0) { |
| Element element = (Element) icons.item(0); |
| if (element.hasAttribute(Template.ATTR_TYPE)) { |
| String iconTypeName = element.getAttribute(Template.ATTR_TYPE).toUpperCase(Locale.US); |
| myIconType = AssetStudioAssetGenerator.AssetType.valueOf(iconTypeName); |
| } else { |
| myIconType = null; |
| } |
| myIconName = element.getAttribute(Template.ATTR_NAME); |
| } else { |
| myIconType = null; |
| myIconName = null; |
| } |
| |
| NodeList categories = myDocument.getElementsByTagName(TAG_CATEGORY); |
| if (categories.getLength() > 0) { |
| Element element = (Element) categories.item(0); |
| if (element.hasAttribute(Template.ATTR_VALUE)) { |
| myCategory = element.getAttribute(Template.ATTR_VALUE); |
| } |
| } |
| |
| NodeList formFactors = myDocument.getElementsByTagName(TAG_FORMFACTOR); |
| if (formFactors.getLength() > 0) { |
| Element element = (Element) formFactors.item(0); |
| if (element.hasAttribute(Template.ATTR_VALUE)) { |
| myFormFactor = element.getAttribute(Template.ATTR_VALUE); |
| } |
| } |
| } |
| |
| @Nullable |
| public String getTitle() { |
| return getAttrNonEmpty(ATTR_NAME); |
| } |
| |
| @Nullable |
| public String getDescription() { |
| return getAttrNonEmpty(ATTR_DESCRIPTION); |
| } |
| |
| public int getMinSdk() { |
| return getInteger(ATTR_MIN_API, 1); |
| } |
| |
| public int getMinBuildApi() { |
| return getInteger(ATTR_MIN_BUILD_API, 1); |
| } |
| |
| public int getRevision() { |
| return getInteger(ATTR_REVISION, 1); |
| } |
| |
| @Nullable |
| public String getCategory() { |
| return myCategory; |
| } |
| |
| @Nullable |
| public String getFormFactor() { |
| return myFormFactor; |
| } |
| |
| @Nullable |
| public AssetStudioAssetGenerator.AssetType getIconType() { |
| return myIconType; |
| } |
| |
| @Nullable |
| public String getIconName() { |
| return myIconName; |
| } |
| |
| @Nullable |
| public String getThumbnailPath() { |
| return getThumbnailPath(null); |
| } |
| |
| @Nullable |
| public String getThumbnailPath(Function<String, Object> currentState) { |
| // Apply selector logic. Pick the thumb first thumb that satisfies the largest number |
| // of conditions. |
| NodeList thumbs = myDocument.getElementsByTagName(TAG_THUMB); |
| if (thumbs.getLength() == 0) { |
| return null; |
| } |
| |
| |
| int bestMatchCount = 0; |
| Element bestMatch = null; |
| |
| for (int i = 0, n = thumbs.getLength(); i < n; i++) { |
| Element thumb = (Element) thumbs.item(i); |
| |
| NamedNodeMap attributes = thumb.getAttributes(); |
| if (bestMatch == null && attributes.getLength() == 0) { |
| bestMatch = thumb; |
| } else if (attributes.getLength() <= bestMatchCount) { |
| // Already have a match with this number of attributes, no point checking |
| continue; |
| } else { |
| boolean match = true; |
| for (int j = 0, max = attributes.getLength(); j < max; j++) { |
| Attr attribute = (Attr) attributes.item(j); |
| Parameter parameter = myParameterMap.get(attribute.getName()); |
| if (parameter == null) { |
| LOG.warn("Unexpected parameter in template thumbnail: " + |
| attribute.getName()); |
| continue; |
| } |
| String thumbNailValue = attribute.getValue(); |
| |
| if (currentState == null || !thumbNailValue.equals(currentState.apply(parameter.id))) { |
| match = false; |
| break; |
| } |
| } |
| if (match) { |
| bestMatch = thumb; |
| bestMatchCount = attributes.getLength(); |
| } |
| } |
| } |
| |
| if (bestMatch != null) { |
| NodeList children = bestMatch.getChildNodes(); |
| for (int i = 0, n = children.getLength(); i < n; i++) { |
| Node child = children.item(i); |
| if (child.getNodeType() == Node.TEXT_NODE) { |
| return child.getNodeValue().trim(); |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| public boolean isSupported() { |
| String versionString = myDocument.getDocumentElement().getAttribute(ATTR_FORMAT); |
| if (versionString != null && !versionString.isEmpty()) { |
| try { |
| int version = Integer.parseInt(versionString); |
| return version <= CURRENT_FORMAT; |
| } catch (NumberFormatException nufe) { |
| return false; |
| } |
| } |
| |
| // Older templates without version specified: supported |
| return true; |
| } |
| |
| /** Returns the list of available parameters */ |
| @NotNull |
| public Collection<Parameter> getParameters() { |
| return myParameterMap.values(); |
| } |
| |
| /** |
| * Returns the parameter of the given id, or null if not found |
| * |
| * @param id the id of the target parameter |
| * @return the corresponding parameter, or null if not found |
| */ |
| @Nullable |
| public Parameter getParameter(@NotNull String id) { |
| return myParameterMap.get(id); |
| } |
| |
| @Nullable |
| private String getAttrNonEmpty(@NotNull String attrName) { |
| String attr = myDocument.getDocumentElement().getAttribute(attrName); |
| if (attr != null && !attr.isEmpty()) { |
| return attr; |
| } |
| return null; |
| } |
| |
| private int getInteger(@NotNull String attrName, int defaultValue) { |
| try { |
| return Integer.parseInt(myDocument.getDocumentElement().getAttribute(attrName)); |
| } catch (NumberFormatException nufe) { |
| // Templates aren't allowed to contain codenames, should always be an integer |
| //LOG.warn(nufe); |
| return defaultValue; |
| } catch (RuntimeException e) { |
| return defaultValue; |
| } |
| } |
| |
| /** |
| * Computes a suitable build api string, e.g. for API level 18 the build |
| * API string is "18". |
| */ |
| @NotNull |
| public static String getBuildApiString(@NotNull AndroidVersion version) { |
| if (version.isPreview()) { |
| return AndroidTargetHash.getPlatformHashString(version); |
| } |
| return version.getApiString(); |
| } |
| } |