blob: 74af651caf626a4a96a1211ee8f807978e141e93 [file] [log] [blame]
/*
* Copyright (C) 2012 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 static com.android.SdkConstants.ATTR_NAME;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.ide.common.xml.AndroidManifestParser;
import com.android.ide.common.xml.ManifestData;
import com.android.ide.common.xml.ManifestData.Activity;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.io.FolderWrapper;
import com.android.sdklib.AndroidVersion;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.internal.project.ProjectProperties;
import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import java.io.File;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** An Android project to be imported */
class ImportedProject {
private final File mLocation;
private String mActivityName;
private ManifestData mManifest;
private String mProjectName;
private String mRelativePath;
ImportedProject(File location, String relativePath) {
super();
mLocation = location;
mRelativePath = relativePath;
}
File getLocation() {
return mLocation;
}
String getRelativePath() {
return mRelativePath;
}
@Nullable
ManifestData getManifest() {
if (mManifest == null) {
try {
mManifest = AndroidManifestParser.parse(new FolderWrapper(mLocation));
} catch (SAXException e) {
// Some sort of error in the manifest file: report to the user in a better way?
AdtPlugin.log(e, null);
return null;
} catch (Exception e) {
AdtPlugin.log(e, null);
return null;
}
}
return mManifest;
}
@Nullable
public String getActivityName() {
if (mActivityName == null) {
// Compute the project name and the package name from the manifest
ManifestData manifest = getManifest();
if (manifest != null) {
if (manifest.getLauncherActivity() != null) {
mActivityName = manifest.getLauncherActivity().getName();
}
if (mActivityName == null || mActivityName.isEmpty()) {
Activity[] activities = manifest.getActivities();
for (Activity activity : activities) {
mActivityName = activity.getName();
if (mActivityName != null && !mActivityName.isEmpty()) {
break;
}
}
}
if (mActivityName != null) {
int index = mActivityName.lastIndexOf('.');
mActivityName = mActivityName.substring(index + 1);
}
}
}
return mActivityName;
}
@NonNull
public String getProjectName() {
if (mProjectName == null) {
// Are we importing an Eclipse project? If so just use the existing project name
mProjectName = findEclipseProjectName();
if (mProjectName != null) {
return mProjectName;
}
String activityName = getActivityName();
if (activityName == null || activityName.isEmpty()) {
// I could also look at the build files, say build.xml from ant, and
// try to glean the project name from there
mProjectName = mLocation.getName();
} else {
// Try to derive it from the activity name:
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IStatus nameStatus = workspace.validateName(activityName, IResource.PROJECT);
if (nameStatus.isOK()) {
mProjectName = activityName;
} else {
// Try to derive it by escaping characters
StringBuilder sb = new StringBuilder();
for (int i = 0, n = activityName.length(); i < n; i++) {
char c = activityName.charAt(i);
if (c != IPath.DEVICE_SEPARATOR && c != IPath.SEPARATOR && c != '\\') {
sb.append(c);
}
}
if (sb.length() == 0) {
mProjectName = mLocation.getName();
} else {
mProjectName = sb.toString();
}
}
}
}
return mProjectName;
}
@Nullable
private String findEclipseProjectName() {
File projectFile = new File(mLocation, ".project"); //$NON-NLS-1$
if (projectFile.exists()) {
String xml;
try {
xml = Files.toString(projectFile, Charsets.UTF_8);
Document doc = DomUtilities.parseDocument(xml, false);
if (doc != null) {
NodeList names = doc.getElementsByTagName(ATTR_NAME);
if (names.getLength() >= 1) {
Node nameElement = names.item(0);
String name = nameElement.getTextContent().trim();
if (!name.isEmpty()) {
return name;
}
}
}
} catch (IOException e) {
// pass: don't attempt to read project name; must be some sort of unrelated
// file with the same name, perhaps from a different editor or IDE
}
}
return null;
}
public void setProjectName(@NonNull String newName) {
mProjectName = newName;
}
public IAndroidTarget getTarget() {
// Pick a target:
// First try to find the one requested by project.properties
IAndroidTarget[] targets = Sdk.getCurrent().getTargets();
ProjectProperties properties = ProjectProperties.load(mLocation.getPath(),
PropertyType.PROJECT);
if (properties != null) {
String targetProperty = properties.getProperty(ProjectProperties.PROPERTY_TARGET);
if (targetProperty != null) {
Matcher m = Pattern.compile("android-(.+)").matcher( //$NON-NLS-1$
targetProperty.trim());
if (m.matches()) {
String targetName = m.group(1);
int targetLevel;
try {
targetLevel = Integer.parseInt(targetName);
} catch (NumberFormatException nufe) {
// pass
targetLevel = -1;
}
for (IAndroidTarget t : targets) {
AndroidVersion version = t.getVersion();
if (version.isPreview() && targetName.equals(version.getCodename())) {
return t;
} else if (targetLevel == version.getApiLevel()) {
return t;
}
}
if (targetLevel > 0) {
// If not found, pick the closest one that is higher than the
// api level
IAndroidTarget target = targets[targets.length - 1];
int targetDelta = target.getVersion().getApiLevel() - targetLevel;
for (IAndroidTarget t : targets) {
int newDelta = t.getVersion().getApiLevel() - targetLevel;
if (newDelta >= 0 && newDelta < targetDelta) {
targetDelta = newDelta;
target = t;
}
}
return target;
}
}
}
}
// If not found, pick the closest one to the one requested by the
// project (in project.properties) that is still >= the minSdk version
IAndroidTarget target = targets[targets.length - 1];
ManifestData manifest = getManifest();
if (manifest != null) {
int minSdkLevel = manifest.getMinSdkVersion();
int targetDelta = target.getVersion().getApiLevel() - minSdkLevel;
for (IAndroidTarget t : targets) {
int newDelta = t.getVersion().getApiLevel() - minSdkLevel;
if (newDelta >= 0 && newDelta < targetDelta) {
targetDelta = newDelta;
target = t;
}
}
}
return target;
}
}