blob: ee50a6f33b2bb14d1f672c7cbbbf871a3a336d9f [file] [log] [blame]
/*
* Copyright (C) 2014 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.npw;
import com.android.SdkConstants;
import com.android.sdklib.BuildToolInfo;
import com.android.sdklib.repository.FullRevision;
import com.android.sdklib.repository.descriptors.PkgDesc;
import com.android.tools.idea.sdk.VersionCheck;
import com.android.tools.idea.sdk.wizard.LicenseAgreementStep;
import com.android.tools.idea.sdk.wizard.SmwOldApiDirectInstall;
import com.android.tools.idea.templates.Template;
import com.android.tools.idea.templates.TemplateManager;
import com.android.tools.idea.wizard.WizardConstants;
import com.android.tools.idea.wizard.dynamic.DynamicWizardStepWithHeaderAndDescription.WizardStepHeaderSettings;
import com.android.tools.idea.wizard.dynamic.DynamicWizardPath;
import com.android.tools.idea.wizard.dynamic.ScopedStateStore;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import org.jetbrains.android.sdk.AndroidSdkData;
import org.jetbrains.android.sdk.AndroidSdkUtils;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import static com.android.tools.idea.templates.Template.CATEGORY_PROJECTS;
/**
* A path to configure global details of a new Android project
*/
public class ConfigureAndroidProjectPath extends DynamicWizardPath {
private static final Logger LOG = Logger.getInstance(ConfigureAndroidProjectPath.class);
@NotNull
private final Disposable myParentDisposable;
public ConfigureAndroidProjectPath(@NotNull Disposable parentDisposable) {
myParentDisposable = parentDisposable;
}
@Override
protected void init() {
putSdkDependentParams(myState);
addStep(new ConfigureAndroidProjectStep(myParentDisposable));
addStep(new ConfigureFormFactorStep(myParentDisposable));
addStep(new LicenseAgreementStep(myParentDisposable));
addStep(new SmwOldApiDirectInstall(myParentDisposable));
}
@Override
public boolean validate() {
if (!AndroidSdkUtils.isAndroidSdkAvailable() || !TemplateManager.templatesAreValid()) {
setErrorHtml("<html>Your Android SDK is missing, out of date, or is missing templates. " +
"Please ensure you are using SDK version " + VersionCheck.MIN_TOOLS_REV + " or later.<br>" +
"You can configure your SDK via <b>Configure | Project Defaults | Project Structure | SDKs</b></html>");
return false;
} else {
return true;
}
}
@NotNull
@Override
public String getPathName() {
return "Configure Android Project";
}
/**
* Populate the given state with a set of variables that depend on the user's installed SDK. This method should
* be called early in the initialization of a wizard or path.
* Variables:
* Build Tools Version: Used to populate the project level build.gradle with the correct Gradle plugin version number
* If the required build tools version is not installed, a request is added for installation
* SDK Home: The location of the installed SDK
* @param state the state store to populate with the values stored in the SDK
*/
public static void putSdkDependentParams(@NotNull ScopedStateStore state) {
final AndroidSdkData sdkData = AndroidSdkUtils.tryToChooseAndroidSdk();
BuildToolInfo buildTool = sdkData != null ? sdkData.getLatestBuildTool() : null;
FullRevision minimumRequiredBuildToolVersion = FullRevision.parseRevision(SdkConstants.MIN_BUILD_TOOLS_VERSION);
if (buildTool != null && buildTool.getRevision().compareTo(minimumRequiredBuildToolVersion) >= 0) {
state.put(WizardConstants.BUILD_TOOLS_VERSION_KEY, buildTool.getRevision().toString());
} else {
// We need to install a new build tools version
state.listPush(WizardConstants.INSTALL_REQUESTS_KEY, PkgDesc.Builder.newBuildTool(minimumRequiredBuildToolVersion).create());
state.put(WizardConstants.BUILD_TOOLS_VERSION_KEY, minimumRequiredBuildToolVersion.toString());
}
if (sdkData != null) {
// Gradle expects a platform-neutral path
state.put(WizardConstants.SDK_HOME_KEY, FileUtil.toSystemIndependentName(sdkData.getPath()));
}
}
@Override
public boolean performFinishingActions() {
try {
Project project = getProject();
assert project != null;
File projectRoot = VfsUtilCore.virtualToIoFile(project.getBaseDir());
Template projectTemplate = Template.createFromName(CATEGORY_PROJECTS, NewProjectWizardState.PROJECT_TEMPLATE_NAME);
projectTemplate.render(projectRoot, projectRoot, myState.flatten(), project);
setGradleWrapperExecutable(projectRoot);
return true;
}
catch (IOException e) {
LOG.error(e);
return false;
}
}
/**
* Create a header banner for steps in this path.
* @return
*/
protected static WizardStepHeaderSettings buildConfigurationHeader() {
return WizardStepHeaderSettings.createProductHeader("New Project");
}
/**
* Set the executable bit on the 'gradlew' wrapper script on Mac/Linux
* On Windows, we use a separate gradlew.bat file which does not need an
* executable bit.
* @throws IOException
*/
public static void setGradleWrapperExecutable(File projectRoot) throws IOException {
if (SystemInfo.isUnix) {
File gradlewFile = new File(projectRoot, "gradlew");
if (!gradlewFile.isFile()) {
LOG.error("Could not find gradle wrapper. Command line builds may not work properly.");
}
else {
FileUtil.setExecutableAttribute(gradlewFile.getPath(), true);
}
}
}
}