| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php |
| * |
| * 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.ide.eclipse.adt.internal.wizards.newproject; |
| |
| import com.android.SdkConstants; |
| import com.android.annotations.Nullable; |
| import com.android.ide.common.xml.ManifestData; |
| import com.android.ide.common.xml.ManifestData.Activity; |
| import com.android.ide.eclipse.adt.AdtConstants; |
| import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper; |
| import com.android.ide.eclipse.adt.internal.sdk.Sdk; |
| import com.android.sdklib.IAndroidTarget; |
| import com.android.sdklib.internal.project.ProjectProperties; |
| import com.android.sdklib.internal.project.ProjectProperties.PropertyType; |
| import com.android.utils.Pair; |
| import com.android.xml.AndroidManifest; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.ui.IWorkingSet; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * The {@link NewProjectWizardState} holds the state used by the various pages |
| * in the {@link NewProjectWizard} and its variations, and it can also be used |
| * to pass project information to the {@link NewProjectCreator}. |
| */ |
| public class NewProjectWizardState { |
| /** The mode to run the wizard in: creating test, or sample, or plain project */ |
| public Mode mode; |
| |
| /** |
| * If true, the project should be created from an existing codebase (pointed |
| * to by the {@link #projectLocation} or in the case of sample projects, the |
| * {@link #chosenSample}. Otherwise, create a brand new project from scratch. |
| */ |
| public boolean useExisting; |
| |
| /** |
| * Whether new projects should be created into the default project location |
| * (e.g. in the Eclipse workspace) or not |
| */ |
| public boolean useDefaultLocation = true; |
| |
| /** The build target SDK */ |
| public IAndroidTarget target; |
| /** True if the user has manually modified the target */ |
| public boolean targetModifiedByUser; |
| |
| /** The location to store projects into */ |
| public File projectLocation = new File(Platform.getLocation().toOSString()); |
| /** True if the project location name has been manually edited by the user */ |
| public boolean projectLocationModifiedByUser; |
| |
| /** The name of the project */ |
| public String projectName = ""; //$NON-NLS-1$ |
| /** True if the project name has been manually edited by the user */ |
| public boolean projectNameModifiedByUser; |
| |
| /** The application name */ |
| public String applicationName; |
| /** True if the application name has been manually edited by the user */ |
| public boolean applicationNameModifiedByUser; |
| |
| /** The package path */ |
| public String packageName; |
| /** True if the package name has been manually edited by the user */ |
| public boolean packageNameModifiedByUser; |
| |
| /** True if a new activity should be created */ |
| public boolean createActivity; |
| |
| /** The name of the new activity to be created */ |
| public String activityName; |
| /** True if the activity name has been manually edited by the user */ |
| public boolean activityNameModifiedByUser; |
| |
| /** The minimum SDK version to use with the project (may be null or blank) */ |
| public String minSdk; |
| /** True if the minimum SDK version has been manually edited by the user */ |
| public boolean minSdkModifiedByUser; |
| /** |
| * A list of paths to each of the available samples for the current SDK. |
| * The pair is (String: sample display name => File: sample directory). |
| * Note we want a list, not a map since we might have duplicates. |
| * */ |
| public List<Pair<String, File>> samples = new ArrayList<Pair<String, File>>(); |
| /** Path to the currently chosen sample */ |
| public File chosenSample; |
| |
| /** The name of the source folder, relative to the project root */ |
| public String sourceFolder = SdkConstants.FD_SOURCES; |
| /** The set of chosen working sets to use when creating the project */ |
| public IWorkingSet[] workingSets = new IWorkingSet[0]; |
| |
| /** |
| * A reference to a different project that the current test project will be |
| * testing. |
| */ |
| public IProject testedProject; |
| /** |
| * If true, this test project should be testing itself, otherwise it will be |
| * testing the project pointed to by {@link #testedProject}. |
| */ |
| public boolean testingSelf; |
| |
| // NOTE: These apply only to creating paired projects; when isTest is true |
| // we're using |
| // the normal fields above |
| /** |
| * If true, create a test project along with this plain project which will |
| * be testing the plain project. (This flag only applies when creating |
| * normal projects.) |
| */ |
| public boolean createPairProject; |
| /** |
| * The application name of the test application (only applies when |
| * {@link #createPairProject} is true) |
| */ |
| public String testApplicationName; |
| /** |
| * True if the testing application name has been modified by the user (only |
| * applies when {@link #createPairProject} is true) |
| */ |
| public boolean testApplicationNameModified; |
| /** |
| * The package name of the test application (only applies when |
| * {@link #createPairProject} is true) |
| */ |
| public String testPackageName; |
| /** |
| * True if the testing package name has been modified by the user (only |
| * applies when {@link #createPairProject} is true) |
| */ |
| public boolean testPackageModified; |
| /** |
| * The project name of the test project (only applies when |
| * {@link #createPairProject} is true) |
| */ |
| public String testProjectName; |
| /** |
| * True if the testing project name has been modified by the user (only |
| * applies when {@link #createPairProject} is true) |
| */ |
| public boolean testProjectModified; |
| /** Package name of the tested app */ |
| public String testTargetPackageName; |
| |
| /** |
| * Copy project into workspace? This flag only applies when importing |
| * projects (creating projects from existing source) |
| */ |
| public boolean copyIntoWorkspace; |
| |
| /** |
| * List of projects to be imported. Null if not importing projects. |
| */ |
| @Nullable |
| public List<ImportedProject> importProjects; |
| |
| /** |
| * Creates a new {@link NewProjectWizardState} |
| * |
| * @param mode the mode to run the wizard in |
| */ |
| public NewProjectWizardState(Mode mode) { |
| this.mode = mode; |
| if (mode == Mode.SAMPLE) { |
| useExisting = true; |
| } else if (mode == Mode.TEST) { |
| createActivity = false; |
| } |
| } |
| |
| /** |
| * Extract information (package name, application name, minimum SDK etc) from |
| * the given Android project. |
| * |
| * @param path the path to the project to extract information from |
| */ |
| public void extractFromAndroidManifest(Path path) { |
| String osPath = path.append(SdkConstants.FN_ANDROID_MANIFEST_XML).toOSString(); |
| if (!(new File(osPath).exists())) { |
| return; |
| } |
| |
| ManifestData manifestData = AndroidManifestHelper.parseForData(osPath); |
| if (manifestData == null) { |
| return; |
| } |
| |
| String newPackageName = null; |
| Activity activity = null; |
| String newActivityName = null; |
| String minSdkVersion = null; |
| try { |
| newPackageName = manifestData.getPackage(); |
| minSdkVersion = manifestData.getMinSdkVersionString(); |
| |
| // try to get the first launcher activity. If none, just take the first activity. |
| activity = manifestData.getLauncherActivity(); |
| if (activity == null) { |
| Activity[] activities = manifestData.getActivities(); |
| if (activities != null && activities.length > 0) { |
| activity = activities[0]; |
| } |
| } |
| } catch (Exception e) { |
| // ignore exceptions |
| } |
| |
| if (newPackageName != null && newPackageName.length() > 0) { |
| packageName = newPackageName; |
| } |
| |
| if (activity != null) { |
| newActivityName = AndroidManifest.extractActivityName(activity.getName(), |
| newPackageName); |
| } |
| |
| if (newActivityName != null && newActivityName.length() > 0) { |
| activityName = newActivityName; |
| // we are "importing" an existing activity, not creating a new one |
| createActivity = false; |
| |
| // If project name and application names are empty, use the activity |
| // name as a default. If the activity name has dots, it's a part of a |
| // package specification and only the last identifier must be used. |
| if (newActivityName.indexOf('.') != -1) { |
| String[] ids = newActivityName.split(AdtConstants.RE_DOT); |
| newActivityName = ids[ids.length - 1]; |
| } |
| if (projectName == null || projectName.length() == 0 || |
| !projectNameModifiedByUser) { |
| projectName = newActivityName; |
| projectNameModifiedByUser = false; |
| } |
| if (applicationName == null || applicationName.length() == 0 || |
| !applicationNameModifiedByUser) { |
| applicationNameModifiedByUser = false; |
| applicationName = newActivityName; |
| } |
| } else { |
| activityName = ""; //$NON-NLS-1$ |
| |
| // There is no activity name to use to fill in the project and application |
| // name. However if there's a package name, we can use this as a base. |
| if (newPackageName != null && newPackageName.length() > 0) { |
| // Package name is a java identifier, so it's most suitable for |
| // an application name. |
| |
| if (applicationName == null || applicationName.length() == 0 || |
| !applicationNameModifiedByUser) { |
| applicationName = newPackageName; |
| } |
| |
| // For the project name, remove any dots |
| newPackageName = newPackageName.replace('.', '_'); |
| if (projectName == null || projectName.length() == 0 || |
| !projectNameModifiedByUser) { |
| projectName = newPackageName; |
| } |
| |
| } |
| } |
| |
| if (mode == Mode.ANY && useExisting) { |
| updateSdkTargetToMatchProject(path.toFile()); |
| } |
| |
| minSdk = minSdkVersion; |
| minSdkModifiedByUser = false; |
| } |
| |
| /** |
| * Try to find an SDK Target that matches the current MinSdkVersion. |
| * |
| * There can be multiple targets with the same sdk api version, so don't change |
| * it if it's already at the right version. Otherwise pick the first target |
| * that matches. |
| */ |
| public void updateSdkTargetToMatchMinSdkVersion() { |
| IAndroidTarget currentTarget = target; |
| if (currentTarget != null && currentTarget.getVersion().equals(minSdk)) { |
| return; |
| } |
| |
| Sdk sdk = Sdk.getCurrent(); |
| if (sdk != null) { |
| IAndroidTarget[] targets = sdk.getTargets(); |
| for (IAndroidTarget t : targets) { |
| if (t.getVersion().equals(minSdk)) { |
| target = t; |
| return; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Updates the SDK to reflect the SDK required by the project at the given |
| * location |
| * |
| * @param location the location of the project |
| */ |
| public void updateSdkTargetToMatchProject(File location) { |
| // Select the target matching the manifest's sdk or build properties, if any |
| IAndroidTarget foundTarget = null; |
| // This is the target currently in the UI |
| IAndroidTarget currentTarget = target; |
| String projectPath = location.getPath(); |
| |
| // If there's a current target defined, we do not allow to change it when |
| // operating in the create-from-sample mode -- since the available sample list |
| // is tied to the current target, so changing it would invalidate the project we're |
| // trying to load in the first place. |
| if (!targetModifiedByUser) { |
| ProjectProperties p = ProjectProperties.load(projectPath, |
| PropertyType.PROJECT); |
| if (p != null) { |
| String v = p.getProperty(ProjectProperties.PROPERTY_TARGET); |
| IAndroidTarget desiredTarget = Sdk.getCurrent().getTargetFromHashString(v); |
| // We can change the current target if: |
| // - we found a new desired target |
| // - there is no current target |
| // - or the current target can't run the desired target |
| if (desiredTarget != null && |
| (currentTarget == null || !desiredTarget.canRunOn(currentTarget))) { |
| foundTarget = desiredTarget; |
| } |
| } |
| |
| Sdk sdk = Sdk.getCurrent(); |
| IAndroidTarget[] targets = null; |
| if (sdk != null) { |
| targets = sdk.getTargets(); |
| } |
| if (targets == null) { |
| targets = new IAndroidTarget[0]; |
| } |
| |
| if (foundTarget == null && minSdk != null) { |
| // Otherwise try to match the requested min-sdk-version if we find an |
| // exact match, regardless of the currently selected target. |
| for (IAndroidTarget existingTarget : targets) { |
| if (existingTarget != null && |
| existingTarget.getVersion().equals(minSdk)) { |
| foundTarget = existingTarget; |
| break; |
| } |
| } |
| } |
| |
| if (foundTarget == null) { |
| // Or last attempt, try to match a sample project location and use it |
| // if we find an exact match, regardless of the currently selected target. |
| for (IAndroidTarget existingTarget : targets) { |
| if (existingTarget != null && |
| projectPath.startsWith(existingTarget.getLocation())) { |
| foundTarget = existingTarget; |
| break; |
| } |
| } |
| } |
| } |
| |
| if (foundTarget != null) { |
| target = foundTarget; |
| } |
| } |
| |
| /** |
| * Type of project being offered/created by the wizard |
| */ |
| public enum Mode { |
| /** Create a sample project. Testing options are not presented. */ |
| SAMPLE, |
| |
| /** |
| * Create a test project, either testing itself or some other project. |
| * Note that even if in the {@link #ANY} mode, a test project can be |
| * created as a *paired* project with the main project, so this flag |
| * only means that we are creating *just* a test project |
| */ |
| TEST, |
| |
| /** |
| * Create an Android project, which can be a plain project, optionally |
| * with a paired test project, or a sample project (the first page |
| * contains toggles for choosing which |
| */ |
| ANY; |
| } |
| } |