auto import from //branches/cupcake/...@125939
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.ide.eclipse.adt;
|
||||
|
||||
import com.android.ide.eclipse.adt.project.internal.AndroidClasspathContainerInitializer;
|
||||
|
||||
|
||||
/**
|
||||
@@ -42,8 +43,8 @@ public class AdtConstants {
|
||||
|
||||
/** Marker for Android Target errors.
|
||||
* This is not cleared on each like other markers. Instead, it's cleared
|
||||
* when a ContainerClasspathInitialized has succeeded in creating an
|
||||
* {@link AndroidClasspathContainer}*/
|
||||
* when an {@link AndroidClasspathContainerInitializer} has succeeded in creating an
|
||||
* AndroidClasspathContainer */
|
||||
public final static String MARKER_TARGET = AdtPlugin.PLUGIN_ID + ".targetProblem"; //$NON-NLS-1$
|
||||
|
||||
/** Build verbosity "Always". Those messages are always displayed. */
|
||||
|
||||
@@ -1201,7 +1201,7 @@ public class AdtPlugin extends AbstractUIPlugin {
|
||||
if (file.getFullPath().segmentCount() == 4) {
|
||||
// check if we are inside the res folder.
|
||||
String segment = file.getFullPath().segment(1);
|
||||
if (segment.equalsIgnoreCase(AndroidConstants.FD_RESOURCES)) {
|
||||
if (segment.equalsIgnoreCase(SdkConstants.FD_RESOURCES)) {
|
||||
// we are inside a res/ folder, get the actual ResourceFolder
|
||||
ProjectResources resources = ResourceManager.getInstance().
|
||||
getProjectResources(file.getProject());
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.android.jarutils.DebugKeyProvider.KeytoolException;
|
||||
import com.android.jarutils.SignedJarBuilder.IZipEntryFilter;
|
||||
import com.android.prefs.AndroidLocation.AndroidLocationException;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
|
||||
import org.eclipse.core.resources.IContainer;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
@@ -120,6 +121,10 @@ public class ApkBuilder extends BaseBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws CoreException
|
||||
*/
|
||||
public boolean visit(IResourceDelta delta) throws CoreException {
|
||||
// no need to keep looking if we already know we need to convert
|
||||
// to dex and make the final package.
|
||||
@@ -589,7 +594,7 @@ public class ApkBuilder extends BaseBuilder {
|
||||
* @param osBinPath the path to the output folder of the project
|
||||
* @param osOutFilePath the path of the dex file to create.
|
||||
* @param referencedJavaProjects the list of referenced projects for this project.
|
||||
* @return
|
||||
*
|
||||
* @throws CoreException
|
||||
*/
|
||||
private boolean executeDx(IJavaProject javaProject, String osBinPath, String osOutFilePath,
|
||||
@@ -756,8 +761,7 @@ public class ApkBuilder extends BaseBuilder {
|
||||
|
||||
// now write the native libraries.
|
||||
// First look if the lib folder is there.
|
||||
IResource libFolder = javaProject.getProject().findMember(
|
||||
AndroidConstants.FD_NATIVE_LIBS);
|
||||
IResource libFolder = javaProject.getProject().findMember(SdkConstants.FD_NATIVE_LIBS);
|
||||
if (libFolder != null && libFolder.exists() &&
|
||||
libFolder.getType() == IResource.FOLDER) {
|
||||
// look inside and put .so in lib/* by keeping the relative folder path.
|
||||
@@ -829,7 +833,7 @@ public class ApkBuilder extends BaseBuilder {
|
||||
* lib folder directly goes in this "lib" folder in the archive.
|
||||
*
|
||||
*
|
||||
* @param rooSegmentCount The number of segment of the path of the folder containing the
|
||||
* @param rootSegmentCount The number of segment of the path of the folder containing the
|
||||
* libraries. This is used to compute the path in the archive.
|
||||
* @param jarBuilder the {@link SignedJarBuilder} used to create the archive.
|
||||
* @param resource the IResource to write.
|
||||
@@ -847,7 +851,7 @@ public class ApkBuilder extends BaseBuilder {
|
||||
path = path.removeFirstSegments(rootSegmentCount);
|
||||
|
||||
// add it to the archive.
|
||||
IPath apkPath = new Path(AndroidConstants.FD_APK_NATIVE_LIBS);
|
||||
IPath apkPath = new Path(SdkConstants.FD_APK_NATIVE_LIBS);
|
||||
apkPath = apkPath.append(path);
|
||||
|
||||
// writes the file in the apk.
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.build;
|
||||
|
||||
import com.android.ide.eclipse.adt.build.BaseBuilder.BaseDeltaVisitor;
|
||||
import com.android.ide.eclipse.common.AndroidConstants;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IFolder;
|
||||
@@ -98,17 +99,17 @@ public class ApkDeltaVisitor extends BaseDeltaVisitor
|
||||
mOutputPath = outputfolder.getFullPath();
|
||||
}
|
||||
|
||||
IResource assetFolder = builder.getProject().findMember(AndroidConstants.FD_ASSETS);
|
||||
IResource assetFolder = builder.getProject().findMember(SdkConstants.FD_ASSETS);
|
||||
if (assetFolder != null) {
|
||||
mAssetPath = assetFolder.getFullPath();
|
||||
}
|
||||
|
||||
IResource resFolder = builder.getProject().findMember(AndroidConstants.FD_RESOURCES);
|
||||
IResource resFolder = builder.getProject().findMember(SdkConstants.FD_RESOURCES);
|
||||
if (resFolder != null) {
|
||||
mResPath = resFolder.getFullPath();
|
||||
}
|
||||
|
||||
IResource libFolder = builder.getProject().findMember(AndroidConstants.FD_NATIVE_LIBS);
|
||||
IResource libFolder = builder.getProject().findMember(SdkConstants.FD_NATIVE_LIBS);
|
||||
if (libFolder != null) {
|
||||
mLibFolder = libFolder.getFullPath();
|
||||
}
|
||||
@@ -126,8 +127,9 @@ public class ApkDeltaVisitor extends BaseDeltaVisitor
|
||||
return mMakeFinalPackage;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws CoreException
|
||||
*
|
||||
* @see org.eclipse.core.resources.IResourceDeltaVisitor
|
||||
* #visit(org.eclipse.core.resources.IResourceDelta)
|
||||
|
||||
@@ -69,15 +69,15 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
|
||||
/**
|
||||
* First line of dual line aapt error.<br>
|
||||
* "ERROR at line <line>: <error>"<br>
|
||||
* " (Occured while parsing <path>)"
|
||||
* " (Occurred while parsing <path>)"
|
||||
*/
|
||||
private final static Pattern sPattern1Line1 = Pattern.compile(
|
||||
"^ERROR\\s+at\\s+line\\s+(\\d+):\\s+(.*)$"); //$NON-NLS-1$
|
||||
/**
|
||||
* Second line of dual line aapt error.<br>
|
||||
* "ERROR at line <line>: <error>"<br>
|
||||
* " (Occured while parsing <path>)"<br>
|
||||
* @see sPattern1Line1
|
||||
* " (Occurred while parsing <path>)"<br>
|
||||
* @see #sPattern1Line1
|
||||
*/
|
||||
private final static Pattern sPattern1Line2 = Pattern.compile(
|
||||
"^\\s+\\(Occurred while parsing\\s+(.*)\\)$"); //$NON-NLS-1$
|
||||
@@ -92,7 +92,7 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
|
||||
* Second line of dual line aapt error.<br>
|
||||
* "ERROR: <error>"<br>
|
||||
* "Defined at file <path> line <line>"<br>
|
||||
* @see sPattern2Line1
|
||||
* @see #sPattern2Line1
|
||||
*/
|
||||
private final static Pattern sPattern2Line2 = Pattern.compile(
|
||||
"Defined\\s+at\\s+file\\s+(.+)\\s+line\\s+(\\d+)"); //$NON-NLS-1$
|
||||
@@ -113,7 +113,7 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
|
||||
* Second line of dual line aapt error.<br>
|
||||
* "ERROR parsing XML file <path>"<br>
|
||||
* "<error> at line <line>"<br>
|
||||
* @see sPattern4Line1
|
||||
* @see #sPattern4Line1
|
||||
*/
|
||||
private final static Pattern sPattern4Line2 = Pattern.compile(
|
||||
"^(.+)\\s+at\\s+line\\s+(\\d+)$"); //$NON-NLS-1$
|
||||
@@ -263,7 +263,7 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
|
||||
|
||||
/**
|
||||
* Adds a marker to the current project.
|
||||
* @param file the file to be marked
|
||||
*
|
||||
* @param markerId The id of the marker to add.
|
||||
* @param message the message associated with the mark
|
||||
* @param severity the severity of the marker.
|
||||
@@ -292,12 +292,11 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
|
||||
|
||||
/**
|
||||
* Removes markers from a container and its children.
|
||||
* @param container The container from which to delete the markers.
|
||||
* @param folder The container from which to delete the markers.
|
||||
* @param markerId The id of the markers to remove. If null, all marker of
|
||||
* type <code>IMarker.PROBLEM</code> will be removed.
|
||||
*/
|
||||
protected final void removeMarkersFromContainer(IContainer folder,
|
||||
String markerId) {
|
||||
protected final void removeMarkersFromContainer(IContainer folder, String markerId) {
|
||||
try {
|
||||
if (folder.exists()) {
|
||||
folder.deleteMarkers(markerId, true, IResource.DEPTH_INFINITE);
|
||||
|
||||
@@ -1128,10 +1128,8 @@ public class PreCompilerBuilder extends BaseBuilder {
|
||||
* Finish a file created/modified by an outside command line process.
|
||||
* The file is marked as modified by Android, and the parent folder is refreshed, so that,
|
||||
* in case the file didn't exist beforehand, the file appears in the package explorer.
|
||||
* @param file The file to "finish".
|
||||
* @param parent The parent container. Can be null (in which case it'll be
|
||||
* figured out from the file's IResource.
|
||||
* @param monitor a monitor to display progress.
|
||||
* @param rFile The R file to "finish".
|
||||
* @param manifestFile The manifest file to "finish".
|
||||
* @throws CoreException
|
||||
*/
|
||||
private void finishJavaFilesAfterExternalModification(IFile rFile, IFile manifestFile)
|
||||
@@ -1150,9 +1148,7 @@ public class PreCompilerBuilder extends BaseBuilder {
|
||||
* The file is marked as modified by Android, and the parent folder is refreshed, so that,
|
||||
* in case the file didn't exist beforehand, the file appears in the package explorer.
|
||||
* @param file The file to "finish".
|
||||
* @param parent The parent container. Can be null (in which case it'll be
|
||||
* figured out from the file's IResource.
|
||||
* @param monitor a monitor to display progress.
|
||||
* @param aidlFile The AIDL file to "finish".
|
||||
* @throws CoreException
|
||||
*/
|
||||
private void finishFileAfterExternalModification(IFile file, IFile aidlFile)
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.android.ide.eclipse.adt.project.ProjectHelper;
|
||||
import com.android.ide.eclipse.common.AndroidConstants;
|
||||
import com.android.ide.eclipse.common.project.AndroidManifestParser;
|
||||
import com.android.ide.eclipse.common.project.BaseProjectHelper;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
|
||||
import org.eclipse.core.resources.IContainer;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
@@ -154,7 +155,7 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
|
||||
// then we are not yet in a source or resource folder
|
||||
mInRes = mInSrc = false;
|
||||
|
||||
if (AndroidConstants.FD_RESOURCES.equalsIgnoreCase(segments[1])) {
|
||||
if (SdkConstants.FD_RESOURCES.equalsIgnoreCase(segments[1])) {
|
||||
// this is the resource folder that was modified. we want to
|
||||
// see its content.
|
||||
|
||||
|
||||
@@ -31,8 +31,12 @@ import com.android.ide.eclipse.adt.AdtPlugin;
|
||||
import com.android.ide.eclipse.adt.debug.launching.DeviceChooserDialog.DeviceChooserResponse;
|
||||
import com.android.ide.eclipse.adt.debug.ui.EmulatorConfigTab;
|
||||
import com.android.ide.eclipse.adt.project.ProjectHelper;
|
||||
import com.android.ide.eclipse.adt.sdk.Sdk;
|
||||
import com.android.ide.eclipse.common.project.AndroidManifestHelper;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.SdkManager;
|
||||
import com.android.sdklib.vm.VmManager;
|
||||
import com.android.sdklib.vm.VmManager.VmInfo;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
@@ -58,6 +62,7 @@ import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -69,9 +74,9 @@ import java.util.regex.Pattern;
|
||||
public final class AndroidLaunchController implements IDebugBridgeChangeListener,
|
||||
IDeviceChangeListener, IClientChangeListener {
|
||||
|
||||
private static final String FLAG_VM = "-vm"; //$NON-NLS-1$
|
||||
private static final String FLAG_NETDELAY = "-netdelay"; //$NON-NLS-1$
|
||||
private static final String FLAG_NETSPEED = "-netspeed"; //$NON-NLS-1$
|
||||
private static final String FLAG_SKIN = "-skin"; //$NON-NLS-1$
|
||||
private static final String FLAG_WIPE_DATA = "-wipe-data"; //$NON-NLS-1$
|
||||
private static final String FLAG_NO_BOOT_ANIM = "-no-boot-anim"; //$NON-NLS-1$
|
||||
|
||||
@@ -223,11 +228,10 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
public boolean mNoBootAnim = LaunchConfigDelegate.DEFAULT_NO_BOOT_ANIM;
|
||||
|
||||
/**
|
||||
* Screen size parameters.
|
||||
* This value can be provided to the emulator directly for the option "-skin"
|
||||
* Vm Name.
|
||||
*/
|
||||
public String mSkin = null;
|
||||
|
||||
public String mVmName = null;
|
||||
|
||||
public String mNetworkSpeed = EmulatorConfigTab.getSpeed(
|
||||
LaunchConfigDelegate.DEFAULT_SPEED);
|
||||
public String mNetworkDelay = EmulatorConfigTab.getDelay(
|
||||
@@ -258,12 +262,8 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
}
|
||||
|
||||
try {
|
||||
mSkin = config.getAttribute(LaunchConfigDelegate.ATTR_SKIN, mSkin);
|
||||
if (mSkin == null) {
|
||||
mSkin = SdkConstants.SKIN_DEFAULT;
|
||||
}
|
||||
mVmName = config.getAttribute(LaunchConfigDelegate.ATTR_VM_NAME, mVmName);
|
||||
} catch (CoreException e) {
|
||||
mSkin = SdkConstants.SKIN_DEFAULT;
|
||||
}
|
||||
|
||||
int index = LaunchConfigDelegate.DEFAULT_SPEED;
|
||||
@@ -526,11 +526,14 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
// set the launch mode to default.
|
||||
wc.setAttribute(LaunchConfigDelegate.ATTR_LAUNCH_ACTION,
|
||||
LaunchConfigDelegate.DEFAULT_LAUNCH_ACTION);
|
||||
|
||||
|
||||
// set default target mode
|
||||
wc.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE,
|
||||
LaunchConfigDelegate.DEFAULT_TARGET_MODE);
|
||||
|
||||
// default VM: None
|
||||
wc.setAttribute(LaunchConfigDelegate.ATTR_VM_NAME, (String)null);
|
||||
|
||||
// set the default network speed
|
||||
wc.setAttribute(LaunchConfigDelegate.ATTR_SPEED,
|
||||
LaunchConfigDelegate.DEFAULT_SPEED);
|
||||
@@ -539,9 +542,6 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
wc.setAttribute(LaunchConfigDelegate.ATTR_DELAY,
|
||||
LaunchConfigDelegate.DEFAULT_DELAY);
|
||||
|
||||
// default skin
|
||||
wc.setAttribute(LaunchConfigDelegate.ATTR_SKIN, SdkConstants.SKIN_DEFAULT);
|
||||
|
||||
// default wipe data mode
|
||||
wc.setAttribute(LaunchConfigDelegate.ATTR_WIPE_DATA,
|
||||
LaunchConfigDelegate.DEFAULT_WIPE_DATA);
|
||||
@@ -627,32 +627,171 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
// set the debug mode
|
||||
launchInfo.mDebugMode = mode.equals(ILaunchManager.DEBUG_MODE);
|
||||
|
||||
// device chooser response.
|
||||
// get the SDK
|
||||
Sdk currentSdk = Sdk.getCurrent();
|
||||
VmManager vmManager = currentSdk.getVmManager();
|
||||
|
||||
// get the project target
|
||||
final IAndroidTarget projectTarget = currentSdk.getTarget(project);
|
||||
|
||||
// FIXME: check errors on missing sdk, vm manager, or project target.
|
||||
|
||||
// device chooser response object.
|
||||
final DeviceChooserResponse response = new DeviceChooserResponse();
|
||||
|
||||
/*
|
||||
* Launch logic:
|
||||
* - Manually Mode
|
||||
* Always display a UI that lets a user see the current running emulators/devices.
|
||||
* The UI must show which devices are compatibles, and allow launching new emulators
|
||||
* with compatible (and not yet running) VM.
|
||||
* - Automatic Way
|
||||
* * Preferred VM set.
|
||||
* If Preferred VM is not running: launch it.
|
||||
* Launch the application on the preferred VM.
|
||||
* * No preferred VM.
|
||||
* Count the number of compatible emulators/devices.
|
||||
* If != 1, display a UI similar to manual mode.
|
||||
* If == 1, launch the application on this VM/device.
|
||||
*/
|
||||
|
||||
if (config.mTargetMode == AndroidLaunchConfiguration.AUTO_TARGET_MODE) {
|
||||
// if we are in automatic target mode, we need to find the current devices
|
||||
Device[] devices = AndroidDebugBridge.getBridge().getDevices();
|
||||
|
||||
// depending on the number of devices, we'll simulate an automatic choice
|
||||
// from the device chooser or simply show up the device chooser.
|
||||
if (devices.length == 0) {
|
||||
// if zero devices, we launch the device.
|
||||
AdtPlugin.printToConsole(project, "Automatic Target Mode: launching new emulator.");
|
||||
// first check if we have a preferred VM name, and if it actually exists, and is valid
|
||||
// (ie able to run the project).
|
||||
// We need to check this in case the VM was recreated with a different target that is
|
||||
// not compatible.
|
||||
VmInfo preferredVm = null;
|
||||
if (config.mVmName != null) {
|
||||
preferredVm = vmManager.getVm(config.mVmName);
|
||||
if (projectTarget.isCompatibleBaseFor(preferredVm.getTarget()) == false) {
|
||||
preferredVm = null;
|
||||
|
||||
AdtPlugin.printErrorToConsole(project, String.format(
|
||||
"Preferred VM '%1$s' is not compatible with the project target '%2$s'. Looking for a compatible VM...",
|
||||
config.mVmName, projectTarget.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
if (preferredVm != null) {
|
||||
// look for a matching device
|
||||
for (Device d : devices) {
|
||||
String deviceVm = d.getVmName();
|
||||
if (deviceVm != null && deviceVm.equals(config.mVmName)) {
|
||||
response.mustContinue = true;
|
||||
response.mustLaunchEmulator = false;
|
||||
response.deviceToUse = d;
|
||||
|
||||
AdtPlugin.printToConsole(project, String.format(
|
||||
"Automatic Target Mode: Preferred VM '%1$s' is available on emulator '%2$s'",
|
||||
config.mVmName, d));
|
||||
|
||||
continueLaunch(response, project, launch, launchInfo, config);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// at this point we have a valid preferred VM that is not running.
|
||||
// We need to start it.
|
||||
response.mustContinue = true;
|
||||
response.mustLaunchEmulator = true;
|
||||
response.vmToLaunch = preferredVm;
|
||||
|
||||
AdtPlugin.printToConsole(project, String.format(
|
||||
"Automatic Target Mode: Preferred VM '%1$s' is not available. Launching new emulator.",
|
||||
config.mVmName));
|
||||
|
||||
continueLaunch(response, project, launch, launchInfo, config);
|
||||
return;
|
||||
} else if (devices.length == 1) {
|
||||
}
|
||||
|
||||
// no (valid) preferred VM? look for one.
|
||||
HashMap<Device, VmInfo> compatibleRunningVms = new HashMap<Device, VmInfo>();
|
||||
boolean hasDevice = false; // if there's 1+ device running, we may force manual mode,
|
||||
// as we cannot always detect proper compatibility with
|
||||
// devices. This is the case if the project target is not
|
||||
// a standard platform
|
||||
for (Device d : devices) {
|
||||
String deviceVm = d.getVmName();
|
||||
if (deviceVm != null) { // physical devices return null.
|
||||
VmInfo info = vmManager.getVm(deviceVm);
|
||||
if (info != null && projectTarget.isCompatibleBaseFor(info.getTarget())) {
|
||||
compatibleRunningVms.put(d, info);
|
||||
}
|
||||
} else {
|
||||
if (projectTarget.isPlatform()) { // means this can run on any device as long
|
||||
// as api level is high enough
|
||||
String apiString = d.getProperty(SdkManager.PROP_VERSION_SDK);
|
||||
try {
|
||||
int apiNumber = Integer.parseInt(apiString);
|
||||
if (apiNumber >= projectTarget.getApiVersionNumber()) {
|
||||
// device is compatible with project
|
||||
compatibleRunningVms.put(d, null);
|
||||
continue;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// do nothing, we'll consider it a non compatible device below.
|
||||
}
|
||||
}
|
||||
hasDevice = true;
|
||||
}
|
||||
}
|
||||
|
||||
// depending on the number of devices, we'll simulate an automatic choice
|
||||
// from the device chooser or simply show up the device chooser.
|
||||
if (hasDevice == false && compatibleRunningVms.size() == 0) {
|
||||
// if zero emulators/devices, we launch an emulator.
|
||||
// We need to figure out which VM first.
|
||||
|
||||
// we are going to take the closest VM. ie a compatible VM that has the API level
|
||||
// closest to the project target.
|
||||
VmInfo[] vms = vmManager.getVms();
|
||||
VmInfo defaultVm = null;
|
||||
for (VmInfo vm : vms) {
|
||||
if (projectTarget.isCompatibleBaseFor(vm.getTarget())) {
|
||||
if (defaultVm == null ||
|
||||
vm.getTarget().getApiVersionNumber() <
|
||||
defaultVm.getTarget().getApiVersionNumber()) {
|
||||
defaultVm = vm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultVm != null) {
|
||||
response.mustContinue = true;
|
||||
response.mustLaunchEmulator = true;
|
||||
response.vmToLaunch = defaultVm;
|
||||
|
||||
AdtPlugin.printToConsole(project, String.format(
|
||||
"Automatic Target Mode: launching new emulator with compatible VM '%1$s'",
|
||||
defaultVm.getName()));
|
||||
|
||||
continueLaunch(response, project, launch, launchInfo, config);
|
||||
return;
|
||||
} else {
|
||||
// FIXME: ask the user if he wants to create a VM.
|
||||
// we found no compatible VM.
|
||||
AdtPlugin.printErrorToConsole(project, String.format(
|
||||
"Failed to find a VM compatible with target '%1$s'. Launch aborted.",
|
||||
projectTarget.getName()));
|
||||
launch.stopLaunch();
|
||||
return;
|
||||
}
|
||||
} else if (hasDevice == false && compatibleRunningVms.size() == 1) {
|
||||
Entry<Device, VmInfo> e = compatibleRunningVms.entrySet().iterator().next();
|
||||
response.mustContinue = true;
|
||||
response.mustLaunchEmulator = false;
|
||||
response.deviceToUse = devices[0];
|
||||
response.deviceToUse = e.getKey();
|
||||
|
||||
if (response.deviceToUse.isEmulator()) {
|
||||
message = String.format("Automatic Target Mode: using existing emulator: %1$s",
|
||||
response.deviceToUse);
|
||||
// get the VmInfo, if null, the device is a physical device.
|
||||
VmInfo vmInfo = e.getValue();
|
||||
if (vmInfo != null) {
|
||||
message = String.format("Automatic Target Mode: using existing emulator '%1$s' running compatible VM '%2$s'",
|
||||
response.deviceToUse, e.getValue().getName());
|
||||
} else {
|
||||
message = String.format("Automatic Target Mode: using existing device: %1$s",
|
||||
message = String.format("Automatic Target Mode: using device '%1$s'",
|
||||
response.deviceToUse);
|
||||
}
|
||||
AdtPlugin.printToConsole(project, message);
|
||||
@@ -662,8 +801,13 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
}
|
||||
|
||||
// if more than one device, we'll bring up the DeviceChooser dialog below.
|
||||
AdtPlugin.printToConsole(project,
|
||||
"Automatic Target Mode: user selection for 2+ devices.");
|
||||
if (compatibleRunningVms.size() >= 2) {
|
||||
message = "Automatic Target Mode: Several compatible targets. Please select a target device.";
|
||||
} else if (hasDevice) {
|
||||
message = "Automatic Target Mode: Unable to detect device compatibility. Please select a target device.";
|
||||
}
|
||||
|
||||
AdtPlugin.printToConsole(project, message);
|
||||
}
|
||||
|
||||
// bring up the device chooser.
|
||||
@@ -671,7 +815,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
public void run() {
|
||||
DeviceChooserDialog dialog = new DeviceChooserDialog(
|
||||
AdtPlugin.getDisplay().getActiveShell());
|
||||
dialog.open(response, project, launch, launchInfo, config);
|
||||
dialog.open(response, project, projectTarget, launch, launchInfo, config);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -705,7 +849,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
synchronized (sListLock) {
|
||||
mWaitingForEmulatorLaunches.add(launchInfo);
|
||||
AdtPlugin.printToConsole(project, "Launching a new emulator.");
|
||||
boolean status = launchEmulator(config);
|
||||
boolean status = launchEmulator(config, response.vmToLaunch);
|
||||
|
||||
if (status == false) {
|
||||
// launching the emulator failed!
|
||||
@@ -775,9 +919,6 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
* the device requires it and it is not set in the manifest, the launch will be forced to
|
||||
* "release" mode instead of "debug"</li>
|
||||
* <ul>
|
||||
* @param launchInfo
|
||||
* @param device
|
||||
* @return
|
||||
*/
|
||||
private boolean checkBuildInfo(DelayedLaunchInfo launchInfo, Device device) {
|
||||
if (device != null) {
|
||||
@@ -1122,7 +1263,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
/**
|
||||
* launches an application on a device or emulator
|
||||
*
|
||||
* @param classToLaunch the fully-qualified name of the activity to launch
|
||||
* @param info the {@link DelayedLaunchInfo} that indicates the activity to launch
|
||||
* @param device the device or emulator to launch the application on
|
||||
*/
|
||||
private void launchApp(final DelayedLaunchInfo info, Device device) {
|
||||
@@ -1182,7 +1323,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
}
|
||||
}
|
||||
|
||||
private boolean launchEmulator(AndroidLaunchConfiguration config) {
|
||||
private boolean launchEmulator(AndroidLaunchConfiguration config, VmInfo vmToLaunch) {
|
||||
|
||||
// split the custom command line in segments
|
||||
ArrayList<String> customArgs = new ArrayList<String>();
|
||||
@@ -1212,10 +1353,8 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
ArrayList<String> list = new ArrayList<String>();
|
||||
|
||||
list.add(AdtPlugin.getOsAbsoluteEmulator());
|
||||
if (config.mSkin != null) {
|
||||
list.add(FLAG_SKIN);
|
||||
list.add(config.mSkin);
|
||||
}
|
||||
list.add(FLAG_VM);
|
||||
list.add(vmToLaunch.getName());
|
||||
|
||||
if (config.mNetworkSpeed != null) {
|
||||
list.add(FLAG_NETSPEED);
|
||||
@@ -1329,7 +1468,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
* @param debugPort The port to connect the debugger to
|
||||
* @param androidLaunch The associated AndroidLaunch object.
|
||||
* @param monitor A Progress monitor
|
||||
* @see connectRemoveDebugger()
|
||||
* @see #connectRemoteDebugger(int, AndroidLaunch, IProgressMonitor)
|
||||
*/
|
||||
public static void launchRemoteDebugger( final int debugPort, final AndroidLaunch androidLaunch,
|
||||
final IProgressMonitor monitor) {
|
||||
@@ -1352,7 +1491,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
* This is sent from a non UI thread.
|
||||
* @param bridge the new {@link AndroidDebugBridge} object.
|
||||
*
|
||||
* @see IDebugBridgeChangeListener#serverChanged(AndroidDebugBridge)
|
||||
* @see IDebugBridgeChangeListener#bridgeChanged(AndroidDebugBridge)
|
||||
*/
|
||||
public void bridgeChanged(AndroidDebugBridge bridge) {
|
||||
// The adb server has changed. We cancel any pending launches.
|
||||
@@ -1447,7 +1586,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
* @param device the device that was updated.
|
||||
* @param changeMask the mask indicating what changed.
|
||||
*
|
||||
* @see IDeviceChangeListener#deviceChanged(Device)
|
||||
* @see IDeviceChangeListener#deviceChanged(Device, int)
|
||||
*/
|
||||
public void deviceChanged(Device device, int changeMask) {
|
||||
// We could check if any starting device we care about is now ready, but we can wait for
|
||||
@@ -1622,7 +1761,6 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
|
||||
* Get the stderr/stdout outputs of a process and return when the process is done.
|
||||
* Both <b>must</b> be read or the process will block on windows.
|
||||
* @param process The process to get the ouput from
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private void grabEmulatorOutput(final Process process) {
|
||||
// read the lines as they come. if null is returned, it's
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.ide.eclipse.adt.debug.launching;
|
||||
import com.android.ddmlib.AndroidDebugBridge;
|
||||
import com.android.ddmlib.Client;
|
||||
import com.android.ddmlib.Device;
|
||||
import com.android.ddmlib.IDevice;
|
||||
import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
|
||||
import com.android.ddmlib.Device.DeviceState;
|
||||
import com.android.ddmuilib.IImageLoader;
|
||||
@@ -27,7 +28,10 @@ import com.android.ddmuilib.TableHelper;
|
||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||
import com.android.ide.eclipse.adt.debug.launching.AndroidLaunchController.AndroidLaunchConfiguration;
|
||||
import com.android.ide.eclipse.adt.debug.launching.AndroidLaunchController.DelayedLaunchInfo;
|
||||
import com.android.ide.eclipse.adt.sdk.Sdk;
|
||||
import com.android.ide.eclipse.ddms.DdmsPlugin;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.vm.VmManager.VmInfo;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.jface.preference.IPreferenceStore;
|
||||
@@ -67,19 +71,26 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
||||
|
||||
private final static String PREFS_COL_SERIAL = "deviceChooser.serial"; //$NON-NLS-1$
|
||||
private final static String PREFS_COL_STATE = "deviceChooser.state"; //$NON-NLS-1$
|
||||
private final static String PREFS_COL_BUILD = "deviceChooser.build"; //$NON-NLS-1$
|
||||
private final static String PREFS_COL_VM = "deviceChooser.vm"; //$NON-NLS-1$
|
||||
private final static String PREFS_COL_TARGET = "deviceChooser.target"; //$NON-NLS-1$
|
||||
private final static String PREFS_COL_DEBUG = "deviceChooser.debug"; //$NON-NLS-1$
|
||||
|
||||
private Table mDeviceTable;
|
||||
private TableViewer mViewer;
|
||||
|
||||
private Image mDeviceImage;
|
||||
private Image mEmulatorImage;
|
||||
private Image mMatchImage;
|
||||
private Image mNoMatchImage;
|
||||
private Image mWarningImage;
|
||||
|
||||
private Button mOkButton;
|
||||
private Button mCreateButton;
|
||||
|
||||
private DeviceChooserResponse mResponse;
|
||||
private DelayedLaunchInfo mLaunchInfo;
|
||||
private IAndroidTarget mProjectTarget;
|
||||
private Sdk mSdk;
|
||||
|
||||
/**
|
||||
* Basic Content Provider for a table full of {@link Device} objects. The input is
|
||||
@@ -111,13 +122,44 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
||||
private class LabelProvider implements ITableLabelProvider {
|
||||
|
||||
public Image getColumnImage(Object element, int columnIndex) {
|
||||
if (columnIndex == 0 && element instanceof Device) {
|
||||
if (((Device)element).isEmulator()) {
|
||||
return mEmulatorImage;
|
||||
if (element instanceof Device) {
|
||||
Device device = (Device)element;
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return device.isEmulator() ? mEmulatorImage : mDeviceImage;
|
||||
|
||||
case 2:
|
||||
// check for compatibility.
|
||||
if (device.isEmulator() == false) { // physical device
|
||||
// get the api level of the device
|
||||
try {
|
||||
String apiValue = device.getProperty(
|
||||
IDevice.PROP_BUILD_VERSION_NUMBER);
|
||||
int api = Integer.parseInt(apiValue);
|
||||
if (api >= mProjectTarget.getApiVersionNumber()) {
|
||||
// if the project is compiling against an add-on, the optional
|
||||
// API may be missing from the device.
|
||||
return mProjectTarget.isPlatform() ?
|
||||
mMatchImage : mWarningImage;
|
||||
} else {
|
||||
return mNoMatchImage;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// lets consider the device non compatible
|
||||
return mNoMatchImage;
|
||||
}
|
||||
} else {
|
||||
// get the VmInfo
|
||||
VmInfo info = mSdk.getVmManager().getVm(device.getVmName());
|
||||
if (info == null) {
|
||||
return mWarningImage;
|
||||
}
|
||||
return mProjectTarget.isCompatibleBaseFor(info.getTarget()) ?
|
||||
mMatchImage : mNoMatchImage;
|
||||
}
|
||||
}
|
||||
|
||||
return mDeviceImage;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -128,15 +170,30 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
||||
case 0:
|
||||
return device.getSerialNumber();
|
||||
case 1:
|
||||
return getStateString(device);
|
||||
case 2:
|
||||
String debuggable = device.getProperty(Device.PROP_DEBUGGABLE);
|
||||
String version = device.getProperty(Device.PROP_BUILD_VERSION);
|
||||
if (debuggable != null && debuggable.equals("1")) { //$NON-NLS-1$
|
||||
return String.format("%1$s (debug)", version); //$NON-NLS-1$
|
||||
if (device.isEmulator()) {
|
||||
return device.getVmName();
|
||||
} else {
|
||||
return String.format("%1$s", version); //$NON-NLS-1$
|
||||
return "N/A"; // devices don't have VM names.
|
||||
}
|
||||
case 2:
|
||||
if (device.isEmulator()) {
|
||||
VmInfo info = mSdk.getVmManager().getVm(device.getVmName());
|
||||
if (info == null) {
|
||||
return "?";
|
||||
}
|
||||
return info.getTarget().getFullName();
|
||||
} else {
|
||||
return device.getProperty(IDevice.PROP_BUILD_VERSION);
|
||||
}
|
||||
case 3:
|
||||
String debuggable = device.getProperty(IDevice.PROP_DEBUGGABLE);
|
||||
if (debuggable != null && debuggable.equals("1")) { //$NON-NLS-1$
|
||||
return "Yes";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
case 4:
|
||||
return getStateString(device);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +221,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
||||
public static class DeviceChooserResponse {
|
||||
public boolean mustContinue;
|
||||
public boolean mustLaunchEmulator;
|
||||
public VmInfo vmToLaunch;
|
||||
public Device deviceToUse;
|
||||
}
|
||||
|
||||
@@ -175,14 +233,18 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
||||
* Prepare and display the dialog.
|
||||
* @param response
|
||||
* @param project
|
||||
* @param projectTarget
|
||||
* @param launch
|
||||
* @param launchInfo
|
||||
* @param config
|
||||
*/
|
||||
public void open(DeviceChooserResponse response, IProject project,
|
||||
AndroidLaunch launch, DelayedLaunchInfo launchInfo, AndroidLaunchConfiguration config) {
|
||||
IAndroidTarget projectTarget, AndroidLaunch launch, DelayedLaunchInfo launchInfo,
|
||||
AndroidLaunchConfiguration config) {
|
||||
mResponse = response;
|
||||
mProjectTarget = projectTarget;
|
||||
mLaunchInfo = launchInfo;
|
||||
mSdk = Sdk.getCurrent();
|
||||
|
||||
Shell parent = getParent();
|
||||
Shell shell = new Shell(parent, getStyle());
|
||||
@@ -218,6 +280,9 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
||||
|
||||
mEmulatorImage.dispose();
|
||||
mDeviceImage.dispose();
|
||||
mMatchImage.dispose();
|
||||
mNoMatchImage.dispose();
|
||||
mWarningImage.dispose();
|
||||
|
||||
AndroidLaunchController.getInstance().continueLaunch(response, project, launch,
|
||||
launchInfo, config);
|
||||
@@ -249,14 +314,22 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
||||
SWT.LEFT, "AAA+AAAAAAAAAAAAAAAAAAA", //$NON-NLS-1$
|
||||
PREFS_COL_SERIAL, store);
|
||||
|
||||
TableHelper.createTableColumn(mDeviceTable, "VM Name",
|
||||
SWT.LEFT, "engineering", //$NON-NLS-1$
|
||||
PREFS_COL_VM, store);
|
||||
|
||||
TableHelper.createTableColumn(mDeviceTable, "Target",
|
||||
SWT.LEFT, "AAA+Android 9.9.9", //$NON-NLS-1$
|
||||
PREFS_COL_TARGET, store);
|
||||
|
||||
TableHelper.createTableColumn(mDeviceTable, "Debug",
|
||||
SWT.LEFT, "Debug", //$NON-NLS-1$
|
||||
PREFS_COL_DEBUG, store);
|
||||
|
||||
TableHelper.createTableColumn(mDeviceTable, "State",
|
||||
SWT.LEFT, "bootloader", //$NON-NLS-1$
|
||||
PREFS_COL_STATE, store);
|
||||
|
||||
TableHelper.createTableColumn(mDeviceTable, "Build Info",
|
||||
SWT.LEFT, "engineering", //$NON-NLS-1$
|
||||
PREFS_COL_BUILD, store);
|
||||
|
||||
// create the viewer for it
|
||||
mViewer = new TableViewer(mDeviceTable);
|
||||
mViewer.setContentProvider(new ContentProvider());
|
||||
@@ -357,20 +430,42 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
||||
}
|
||||
|
||||
private void loadImages() {
|
||||
IImageLoader loader = DdmsPlugin.getImageLoader();
|
||||
IImageLoader ddmsLoader = DdmsPlugin.getImageLoader();
|
||||
Display display = DdmsPlugin.getDisplay();
|
||||
IImageLoader adtLoader = AdtPlugin.getImageLoader();
|
||||
|
||||
if (mDeviceImage == null) {
|
||||
mDeviceImage = ImageHelper.loadImage(loader, display,
|
||||
mDeviceImage = ImageHelper.loadImage(ddmsLoader, display,
|
||||
"device.png", //$NON-NLS-1$
|
||||
ICON_WIDTH, ICON_WIDTH,
|
||||
display.getSystemColor(SWT.COLOR_RED));
|
||||
}
|
||||
if (mEmulatorImage == null) {
|
||||
mEmulatorImage = ImageHelper.loadImage(loader, display,
|
||||
mEmulatorImage = ImageHelper.loadImage(ddmsLoader, display,
|
||||
"emulator.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$
|
||||
display.getSystemColor(SWT.COLOR_BLUE));
|
||||
}
|
||||
|
||||
if (mMatchImage == null) {
|
||||
mMatchImage = ImageHelper.loadImage(adtLoader, display,
|
||||
"match.png", //$NON-NLS-1$
|
||||
ICON_WIDTH, ICON_WIDTH,
|
||||
display.getSystemColor(SWT.COLOR_GREEN));
|
||||
}
|
||||
|
||||
if (mNoMatchImage == null) {
|
||||
mNoMatchImage = ImageHelper.loadImage(adtLoader, display,
|
||||
"error.png", //$NON-NLS-1$
|
||||
ICON_WIDTH, ICON_WIDTH,
|
||||
display.getSystemColor(SWT.COLOR_RED));
|
||||
}
|
||||
|
||||
if (mWarningImage == null) {
|
||||
mWarningImage = ImageHelper.loadImage(adtLoader, display,
|
||||
"warning.png", //$NON-NLS-1$
|
||||
ICON_WIDTH, ICON_WIDTH,
|
||||
display.getSystemColor(SWT.COLOR_YELLOW));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -438,7 +533,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
|
||||
* @param device the device that was updated.
|
||||
* @param changeMask the mask indicating what changed.
|
||||
*
|
||||
* @see IDeviceChangeListener#deviceChanged(Device)
|
||||
* @see IDeviceChangeListener#deviceChanged(Device, int)
|
||||
*/
|
||||
public void deviceChanged(final Device device, int changeMask) {
|
||||
if ((changeMask & (Device.CHANGE_STATE | Device.CHANGE_BUILD_INFO)) != 0) {
|
||||
|
||||
@@ -80,9 +80,8 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
|
||||
*/
|
||||
public static final String ATTR_ACTIVITY = AdtPlugin.PLUGIN_ID + ".activity"; //$NON-NLS-1$
|
||||
|
||||
/** Skin to be used to launch the emulator */
|
||||
public static final String ATTR_SKIN = AdtPlugin.PLUGIN_ID + ".skin"; //$NON-NLS-1$
|
||||
|
||||
public static final String ATTR_VM_NAME = AdtPlugin.PLUGIN_ID + ".vm"; //$NON-NLS-1$
|
||||
|
||||
public static final String ATTR_SPEED = AdtPlugin.PLUGIN_ID + ".speed"; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
@@ -317,6 +316,10 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
|
||||
1 /* code, unused */, "Can't find the project!", null /* exception */));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws CoreException
|
||||
*/
|
||||
@Override
|
||||
public ILaunch getLaunch(ILaunchConfiguration configuration, String mode)
|
||||
throws CoreException {
|
||||
@@ -406,8 +409,6 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
|
||||
|
||||
/**
|
||||
* Returns the name of the activity.
|
||||
* @param configuration
|
||||
* @return
|
||||
*/
|
||||
private String getActivityName(ILaunchConfiguration configuration) {
|
||||
String empty = "";
|
||||
|
||||
@@ -22,7 +22,9 @@ import com.android.ide.eclipse.adt.sdk.Sdk;
|
||||
import com.android.ide.eclipse.common.project.BaseProjectHelper;
|
||||
import com.android.ide.eclipse.ddms.DdmsPlugin;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
import com.android.sdklib.vm.VmManager;
|
||||
import com.android.sdklib.vm.VmManager.VmInfo;
|
||||
import com.android.sdkuilib.VmSelector;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
@@ -70,6 +72,11 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
||||
{ "UMTS", "umts" }, //$NON-NLS-2$
|
||||
};
|
||||
|
||||
private Button mAutoTargetButton;
|
||||
private Button mManualTargetButton;
|
||||
|
||||
private VmSelector mPreferredVmSelector;
|
||||
|
||||
private Combo mSpeedCombo;
|
||||
|
||||
private Combo mDelayCombo;
|
||||
@@ -78,18 +85,10 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
||||
|
||||
private Text mEmulatorCLOptions;
|
||||
|
||||
private Combo mSkinCombo;
|
||||
|
||||
private Button mAutoTargetButton;
|
||||
|
||||
private Button mManualTargetButton;
|
||||
|
||||
private Button mWipeDataButton;
|
||||
|
||||
private Button mNoBootAnimButton;
|
||||
|
||||
private IAndroidTarget mTarget;
|
||||
|
||||
/**
|
||||
* Returns the emulator ready speed option value.
|
||||
* @param value The index of the combo selection.
|
||||
@@ -147,6 +146,11 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
||||
targetModeGroup.setLayout(layout);
|
||||
targetModeGroup.setFont(font);
|
||||
|
||||
mManualTargetButton = new Button(targetModeGroup, SWT.RADIO);
|
||||
mManualTargetButton.setText("Manual");
|
||||
// Since there are only 2 radio buttons, we can put a listener on only one (they
|
||||
// are both called on select and unselect event.
|
||||
|
||||
// add the radio button
|
||||
mAutoTargetButton = new Button(targetModeGroup, SWT.RADIO);
|
||||
mAutoTargetButton.setText("Automatic");
|
||||
@@ -159,11 +163,16 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
||||
}
|
||||
});
|
||||
|
||||
mManualTargetButton = new Button(targetModeGroup, SWT.RADIO);
|
||||
mManualTargetButton.setText("Manual");
|
||||
// Since there are only 2 radio buttons, we can put a listener on only
|
||||
// one (they
|
||||
// are both called on select and unselect event.
|
||||
new Label(targetModeGroup, SWT.NONE).setText("Preferred VM");
|
||||
VmInfo[] vms = new VmInfo[0];
|
||||
mPreferredVmSelector = new VmSelector(targetModeGroup, vms,
|
||||
false /*allowMultipleSelection*/);
|
||||
mPreferredVmSelector.setSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
updateLaunchConfigurationDialog();
|
||||
}
|
||||
});
|
||||
|
||||
// emulator size
|
||||
mEmulatorOptionsGroup = new Group(topComp, SWT.NONE);
|
||||
@@ -174,17 +183,6 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
||||
mEmulatorOptionsGroup.setLayout(layout);
|
||||
mEmulatorOptionsGroup.setFont(font);
|
||||
|
||||
new Label(mEmulatorOptionsGroup, SWT.NONE).setText("Screen Size:");
|
||||
|
||||
mSkinCombo = new Combo(mEmulatorOptionsGroup, SWT.READ_ONLY);
|
||||
mSkinCombo.addSelectionListener(new SelectionAdapter() {
|
||||
// called when selection changes
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
updateLaunchConfigurationDialog();
|
||||
}
|
||||
});
|
||||
|
||||
// network options
|
||||
new Label(mEmulatorOptionsGroup, SWT.NONE).setText("Network Speed:");
|
||||
|
||||
@@ -279,8 +277,9 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
||||
* @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(org.eclipse.debug.core.ILaunchConfiguration)
|
||||
*/
|
||||
public void initializeFrom(ILaunchConfiguration configuration) {
|
||||
boolean value = LaunchConfigDelegate.DEFAULT_TARGET_MODE; // true ==
|
||||
// automatic
|
||||
VmManager vmManager = Sdk.getCurrent().getVmManager();
|
||||
|
||||
boolean value = LaunchConfigDelegate.DEFAULT_TARGET_MODE; // true == automatic
|
||||
try {
|
||||
value = configuration.getAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE, value);
|
||||
} catch (CoreException e) {
|
||||
@@ -290,11 +289,12 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
||||
mManualTargetButton.setSelection(!value);
|
||||
|
||||
// look for the project name to get its target.
|
||||
String projectName = "";
|
||||
String stringValue = "";
|
||||
try {
|
||||
projectName = configuration.getAttribute(
|
||||
IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, projectName);
|
||||
stringValue = configuration.getAttribute(
|
||||
IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, stringValue);
|
||||
} catch (CoreException ce) {
|
||||
// let's not do anything here, we'll use the default value
|
||||
}
|
||||
|
||||
IProject project = null;
|
||||
@@ -304,25 +304,41 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
||||
if (projects != null) {
|
||||
// look for the project whose name we read from the configuration.
|
||||
for (IJavaProject p : projects) {
|
||||
if (p.getElementName().equals(projectName)) {
|
||||
if (p.getElementName().equals(stringValue)) {
|
||||
project = p.getProject();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mSkinCombo.removeAll();
|
||||
// update the VM list
|
||||
VmInfo[] vms = null;
|
||||
if (vmManager != null) {
|
||||
vms = vmManager.getVms();
|
||||
}
|
||||
|
||||
IAndroidTarget projectTarget = null;
|
||||
if (project != null) {
|
||||
mTarget = Sdk.getCurrent().getTarget(project);
|
||||
if (mTarget != null) {
|
||||
String[] skins = mTarget.getSkins();
|
||||
if (skins != null) {
|
||||
for (String skin : skins) {
|
||||
mSkinCombo.add(skin);
|
||||
}
|
||||
mSkinCombo.pack();
|
||||
}
|
||||
}
|
||||
projectTarget = Sdk.getCurrent().getTarget(project);
|
||||
} else {
|
||||
vms = null; // no project? we don't want to display any "compatible" VMs.
|
||||
}
|
||||
|
||||
mPreferredVmSelector.setVms(vms, projectTarget);
|
||||
|
||||
stringValue = "";
|
||||
try {
|
||||
stringValue = configuration.getAttribute(LaunchConfigDelegate.ATTR_VM_NAME,
|
||||
stringValue);
|
||||
} catch (CoreException e) {
|
||||
// let's not do anything here, we'll use the default value
|
||||
}
|
||||
|
||||
if (stringValue != null && stringValue.length() > 0 && vmManager != null) {
|
||||
VmInfo targetVm = vmManager.getVm(stringValue);
|
||||
mPreferredVmSelector.setSelection(targetVm);
|
||||
} else {
|
||||
mPreferredVmSelector.setSelection(null);
|
||||
}
|
||||
|
||||
value = LaunchConfigDelegate.DEFAULT_WIPE_DATA;
|
||||
@@ -342,23 +358,6 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
||||
mNoBootAnimButton.setSelection(value);
|
||||
|
||||
int index = -1;
|
||||
try {
|
||||
String skin = configuration.getAttribute(LaunchConfigDelegate.ATTR_SKIN, (String)null);
|
||||
if (skin == null) {
|
||||
skin = SdkConstants.SKIN_DEFAULT;
|
||||
}
|
||||
|
||||
index = getSkinIndex(skin);
|
||||
} catch (CoreException e) {
|
||||
index = getSkinIndex(SdkConstants.SKIN_DEFAULT);
|
||||
}
|
||||
|
||||
if (index == -1) {
|
||||
mSkinCombo.select(0);
|
||||
updateLaunchConfigurationDialog();
|
||||
} else {
|
||||
mSkinCombo.select(index);
|
||||
}
|
||||
|
||||
index = LaunchConfigDelegate.DEFAULT_SPEED;
|
||||
try {
|
||||
@@ -405,8 +404,12 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
||||
public void performApply(ILaunchConfigurationWorkingCopy configuration) {
|
||||
configuration.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE,
|
||||
mAutoTargetButton.getSelection());
|
||||
configuration.setAttribute(LaunchConfigDelegate.ATTR_SKIN,
|
||||
getSkinNameByIndex(mSkinCombo.getSelectionIndex()));
|
||||
VmInfo vm = mPreferredVmSelector.getFirstSelected();
|
||||
if (vm != null) {
|
||||
configuration.setAttribute(LaunchConfigDelegate.ATTR_VM_NAME, vm.getName());
|
||||
} else {
|
||||
configuration.setAttribute(LaunchConfigDelegate.ATTR_VM_NAME, (String)null);
|
||||
}
|
||||
configuration.setAttribute(LaunchConfigDelegate.ATTR_SPEED,
|
||||
mSpeedCombo.getSelectionIndex());
|
||||
configuration.setAttribute(LaunchConfigDelegate.ATTR_DELAY,
|
||||
@@ -425,8 +428,6 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
||||
public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
|
||||
configuration.setAttribute(LaunchConfigDelegate.ATTR_TARGET_MODE,
|
||||
LaunchConfigDelegate.DEFAULT_TARGET_MODE);
|
||||
configuration.setAttribute(LaunchConfigDelegate.ATTR_SKIN,
|
||||
SdkConstants.SKIN_DEFAULT);
|
||||
configuration.setAttribute(LaunchConfigDelegate.ATTR_SPEED,
|
||||
LaunchConfigDelegate.DEFAULT_SPEED);
|
||||
configuration.setAttribute(LaunchConfigDelegate.ATTR_DELAY,
|
||||
@@ -440,33 +441,4 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
|
||||
String emuOptions = store.getString(AdtPlugin.PREFS_EMU_OPTIONS);
|
||||
configuration.setAttribute(LaunchConfigDelegate.ATTR_COMMANDLINE, emuOptions);
|
||||
}
|
||||
|
||||
private String getSkinNameByIndex(int index) {
|
||||
if (mTarget != null && index > 0) {
|
||||
String[] skins = mTarget.getSkins();
|
||||
if (skins != null && index < skins.length) {
|
||||
return skins[index];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private int getSkinIndex(String name) {
|
||||
if (mTarget != null) {
|
||||
String[] skins = mTarget.getSkins();
|
||||
if (skins != null) {
|
||||
int index = 0;
|
||||
for (String skin : skins) {
|
||||
if (skin.equalsIgnoreCase(name)) {
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -398,11 +398,13 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab {
|
||||
config.setMappedResources(resources);
|
||||
}
|
||||
|
||||
/** Loads the ui with the activities of the specified project, and store the
|
||||
* activities in <code>mActivities</code>
|
||||
/**
|
||||
* Loads the ui with the activities of the specified project, and stores the
|
||||
* activities in <code>mActivities</code>.
|
||||
* <p/>
|
||||
* First activity is selected by default if present.
|
||||
* @param project The project to load the activities from
|
||||
* @return The array of activities or null if none could be found.
|
||||
*
|
||||
* @param project The project to load the activities from.
|
||||
*/
|
||||
private void loadActivities(IProject project) {
|
||||
if (project != null) {
|
||||
|
||||
@@ -199,7 +199,7 @@ public class BuildPreferencePage extends FieldEditorPreferencePage implements
|
||||
*/
|
||||
private void handleException(Throwable t) {
|
||||
String msg = t.getMessage();
|
||||
if (t == null) {
|
||||
if (msg == null) {
|
||||
Throwable cause = t.getCause();
|
||||
if (cause != null) {
|
||||
handleException(cause);
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.project;
|
||||
|
||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||
import com.android.ide.eclipse.common.AndroidConstants;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
|
||||
import org.eclipse.core.resources.IFolder;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
@@ -53,13 +54,13 @@ public class FolderDecorator implements ILightweightLabelDecorator {
|
||||
// check the folder is directly under the project.
|
||||
if (folder.getParent().getType() == IResource.PROJECT) {
|
||||
String name = folder.getName();
|
||||
if (name.equals(AndroidConstants.FD_ASSETS)) {
|
||||
if (name.equals(SdkConstants.FD_ASSETS)) {
|
||||
decorate(decoration, " [Android assets]");
|
||||
decoration.addOverlay(mDescriptor, IDecoration.TOP_RIGHT);
|
||||
} else if (name.equals(AndroidConstants.FD_RESOURCES)) {
|
||||
} else if (name.equals(SdkConstants.FD_RESOURCES)) {
|
||||
decorate(decoration, " [Android resources]");
|
||||
decoration.addOverlay(mDescriptor, IDecoration.TOP_RIGHT);
|
||||
} else if (name.equals(AndroidConstants.FD_NATIVE_LIBS)) {
|
||||
} else if (name.equals(SdkConstants.FD_NATIVE_LIBS)) {
|
||||
decorate(decoration, " [Native Libraries]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,7 +493,7 @@ public final class ExportWizard extends Wizard implements IExportWizard {
|
||||
}
|
||||
|
||||
// no more cause and still no message. display the first exception.
|
||||
return cause.getClass().getCanonicalName();
|
||||
return t.getClass().getCanonicalName();
|
||||
}
|
||||
|
||||
return message;
|
||||
|
||||
@@ -256,7 +256,6 @@ final class ProjectCheckPage extends ExportWizardPage {
|
||||
|
||||
/**
|
||||
* Checks the parameters for correctness, and update the error message and buttons.
|
||||
* @return the current IProject of this launch config.
|
||||
*/
|
||||
private void handleProjectNameChange() {
|
||||
setPageComplete(false);
|
||||
|
||||
@@ -28,8 +28,12 @@ import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.core.runtime.jobs.Job;
|
||||
import org.eclipse.jdt.core.ClasspathContainerInitializer;
|
||||
import org.eclipse.jdt.core.IAccessRule;
|
||||
import org.eclipse.jdt.core.IClasspathAttribute;
|
||||
@@ -125,7 +129,7 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
|
||||
*/
|
||||
private static IClasspathContainer allocateAndroidContainer(String containerId,
|
||||
IJavaProject javaProject) {
|
||||
IProject iProject = javaProject.getProject();
|
||||
final IProject iProject = javaProject.getProject();
|
||||
|
||||
// remove potential MARKER_TARGETs.
|
||||
try {
|
||||
@@ -139,7 +143,9 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
|
||||
}
|
||||
|
||||
|
||||
// first we check if the SDK has been loaded
|
||||
// First we check if the SDK has been loaded.
|
||||
// By passing the javaProject to getSdkLoadStatus(), we ensure that, should the SDK
|
||||
// not be loaded yet, the classpath container will be resolved again once the SDK is loaded.
|
||||
boolean sdkIsLoaded = AdtPlugin.getDefault().getSdkLoadStatus(javaProject) ==
|
||||
LoadStatus.LOADED;
|
||||
|
||||
@@ -172,8 +178,14 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
|
||||
String message = null;
|
||||
boolean outputToConsole = true;
|
||||
if (hashString == null || hashString.length() == 0) {
|
||||
message = String.format(
|
||||
"Project has no target set. Edit the project properties to set one.");
|
||||
// if there is no hash string we only show this if the SDK is loaded.
|
||||
// For a project opened at start-up with no target, this would be displayed twice,
|
||||
// once when the project is opened, and once after the SDK has finished loading.
|
||||
// By testing the sdk is loaded, we only show this once in the console.
|
||||
if (sdkIsLoaded) {
|
||||
message = String.format(
|
||||
"Project has no target set. Edit the project properties to set one.");
|
||||
}
|
||||
} else if (sdkIsLoaded) {
|
||||
message = String.format(
|
||||
"Unable to resolve target '%s'", hashString);
|
||||
@@ -187,23 +199,41 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
|
||||
// and it's expected. (we do keep the error marker though).
|
||||
outputToConsole = false;
|
||||
}
|
||||
|
||||
if (message != null) {
|
||||
// log the error and put the marker on the project if we can.
|
||||
if (outputToConsole) {
|
||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_ALWAYS, iProject, message);
|
||||
}
|
||||
|
||||
try {
|
||||
BaseProjectHelper.addMarker(iProject, AdtConstants.MARKER_TARGET, message, -1,
|
||||
IMarker.SEVERITY_ERROR, IMarker.PRIORITY_HIGH);
|
||||
} catch (CoreException e) {
|
||||
// In some cases, the workspace may be locked for modification when we pass here.
|
||||
// We schedule a new job to put the marker after.
|
||||
final String fmessage = message;
|
||||
Job markerJob = new Job("Android SDK: Resolving error markers") {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected IStatus run(IProgressMonitor monitor) {
|
||||
try {
|
||||
BaseProjectHelper.addMarker(iProject, AdtConstants.MARKER_TARGET,
|
||||
fmessage, -1, IMarker.SEVERITY_ERROR, IMarker.PRIORITY_HIGH);
|
||||
} catch (CoreException e2) {
|
||||
return e2.getStatus();
|
||||
}
|
||||
|
||||
// log the error and put the marker on the project
|
||||
if (outputToConsole) {
|
||||
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_ALWAYS, iProject, message);
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
};
|
||||
|
||||
// build jobs are run after other interactive jobs
|
||||
markerJob.setPriority(Job.BUILD);
|
||||
markerJob.schedule();
|
||||
}
|
||||
}
|
||||
IMarker marker = BaseProjectHelper.addMarker(iProject, AdtConstants.MARKER_TARGET, message,
|
||||
IMarker.SEVERITY_ERROR);
|
||||
|
||||
// add a marker priority as this is an more important error than the error that will
|
||||
// spring from the lack of library
|
||||
try {
|
||||
marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
|
||||
} catch (CoreException e) {
|
||||
// just log the error
|
||||
AdtPlugin.log(e, "Error changing target marker priority.");
|
||||
}
|
||||
|
||||
|
||||
// return a dummy container to replace the one we may have had before.
|
||||
return new IClasspathContainer() {
|
||||
public IClasspathEntry[] getClasspathEntries() {
|
||||
|
||||
@@ -37,7 +37,8 @@ import javax.management.InvalidAttributeValueException;
|
||||
public class AndroidJarLoader extends ClassLoader implements IAndroidClassLoader {
|
||||
|
||||
/**
|
||||
* Wrapper around a {@link Class} to provide the methods of {@link IClassDescriptor}.
|
||||
* Wrapper around a {@link Class} to provide the methods of
|
||||
* {@link IAndroidClassLoader.IClassDescriptor}.
|
||||
*/
|
||||
public final static class ClassWrapper implements IClassDescriptor {
|
||||
private Class<?> mClass;
|
||||
@@ -416,7 +417,7 @@ public class AndroidJarLoader extends ClassLoader implements IAndroidClassLoader
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link IClass} by its fully-qualified name.
|
||||
* Returns a {@link IAndroidClassLoader.IClassDescriptor} by its fully-qualified name.
|
||||
* @param className the fully-qualified name of the class to return.
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
|
||||
@@ -82,11 +82,8 @@ public final class AndroidTargetParser {
|
||||
|
||||
/**
|
||||
* Parses the framework, collects all interesting information and stores them in the
|
||||
* {@link FrameworkResourceManager} given to the constructor.
|
||||
* {@link IAndroidTarget} given to the constructor.
|
||||
*
|
||||
* @param osSdkPath the OS path of the SDK directory.
|
||||
* @param resourceManager the {@link FrameworkResourceManager} that will store the parsed
|
||||
* resources.
|
||||
* @param monitor A progress monitor. Can be null. Caller is responsible for calling done.
|
||||
* @return True if the SDK path was valid and parsing has been attempted.
|
||||
*/
|
||||
@@ -400,7 +397,6 @@ public final class AndroidTargetParser {
|
||||
* Loads and collects the action and category default values from the framework.
|
||||
* The values are added to the <code>actions</code> and <code>categories</code> lists.
|
||||
*
|
||||
* @param osLibPath The OS path to the SDK tools/lib folder, ending with a separator.
|
||||
* @param activityActions the list which will receive the activity action values.
|
||||
* @param broadcastActions the list which will receive the broadcast action values.
|
||||
* @param serviceActions the list which will receive the service action values.
|
||||
|
||||
@@ -64,7 +64,7 @@ public interface IAndroidClassLoader {
|
||||
throws IOException, InvalidAttributeValueException, ClassFormatError;
|
||||
|
||||
/**
|
||||
* Returns a {@link IClass} by its fully-qualified name.
|
||||
* Returns a {@link IClassDescriptor} by its fully-qualified name.
|
||||
* @param className the fully-qualified name of the class to return.
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
|
||||
@@ -18,17 +18,17 @@ package com.android.ide.eclipse.adt.sdk;
|
||||
|
||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||
import com.android.ide.eclipse.adt.project.internal.AndroidClasspathContainerInitializer;
|
||||
import com.android.prefs.AndroidLocation.AndroidLocationException;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.ISdkLog;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
import com.android.sdklib.SdkManager;
|
||||
import com.android.sdklib.project.ProjectProperties;
|
||||
import com.android.sdklib.project.ProjectProperties.PropertyType;
|
||||
import com.android.sdklib.vm.VmManager;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IProjectDescription;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
|
||||
@@ -46,21 +46,20 @@ import java.util.HashMap;
|
||||
* To start using an SDK, call {@link #loadSdk(String)} which returns the instance of
|
||||
* the Sdk object.
|
||||
*
|
||||
* To get the list of platforms present in the SDK, call {@link #getPlatforms()}.
|
||||
* To get the list of add-ons present in the SDK, call {@link #getAddons()}.
|
||||
*
|
||||
* To get the list of platforms or add-ons present in the SDK, call {@link #getTargets()}.
|
||||
*/
|
||||
public class Sdk {
|
||||
private final static String PROPERTY_PROJECT_TARGET = "androidTarget"; //$NON-NLS-1$
|
||||
|
||||
private static Sdk sCurrentSdk = null;
|
||||
|
||||
private final SdkManager mManager;
|
||||
private final VmManager mVmManager;
|
||||
|
||||
private final HashMap<IProject, IAndroidTarget> mProjectMap =
|
||||
new HashMap<IProject, IAndroidTarget>();
|
||||
private final HashMap<IAndroidTarget, AndroidTargetData> mTargetMap =
|
||||
new HashMap<IAndroidTarget, AndroidTargetData>();
|
||||
private final String mDocBaseUrl;
|
||||
|
||||
|
||||
/**
|
||||
* Loads an SDK and returns an {@link Sdk} object if success.
|
||||
@@ -74,18 +73,33 @@ public class Sdk {
|
||||
|
||||
final ArrayList<String> logMessages = new ArrayList<String>();
|
||||
ISdkLog log = new ISdkLog() {
|
||||
public void error(String errorFormat, Object... arg) {
|
||||
logMessages.add(String.format(errorFormat, arg));
|
||||
public void error(Throwable throwable, String errorFormat, Object... arg) {
|
||||
if (errorFormat != null) {
|
||||
logMessages.add(String.format(errorFormat, arg));
|
||||
}
|
||||
|
||||
if (throwable != null) {
|
||||
logMessages.add(throwable.getMessage());
|
||||
}
|
||||
}
|
||||
public void warning(String warningFormat, Object... arg) {
|
||||
logMessages.add(String.format(warningFormat, arg));
|
||||
}
|
||||
public void printf(String msgFormat, Object... arg) {
|
||||
logMessages.add(String.format(msgFormat, arg));
|
||||
}
|
||||
};
|
||||
|
||||
// get an SdkManager object for the location
|
||||
SdkManager manager = SdkManager.createManager(sdkLocation, log);
|
||||
if (manager != null) {
|
||||
sCurrentSdk = new Sdk(manager);
|
||||
VmManager vmManager = null;
|
||||
try {
|
||||
vmManager = new VmManager(manager, log);
|
||||
} catch (AndroidLocationException e) {
|
||||
log.error(e, "Error parsing the VMs");
|
||||
}
|
||||
sCurrentSdk = new Sdk(manager, vmManager);
|
||||
return sCurrentSdk;
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder("Error Loading the SDK:\n");
|
||||
@@ -105,6 +119,13 @@ public class Sdk {
|
||||
return sCurrentSdk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location (OS path) of the current SDK.
|
||||
*/
|
||||
public String getSdkLocation() {
|
||||
return mManager.getLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL to the local documentation.
|
||||
* Can return null if no documentation is found in the current SDK.
|
||||
@@ -181,7 +202,8 @@ public class Sdk {
|
||||
*/
|
||||
public static String getProjectTargetHashString(IProject project) {
|
||||
// load the default.properties from the project folder.
|
||||
ProjectProperties properties = ProjectProperties.load(project.getLocation().toOSString());
|
||||
ProjectProperties properties = ProjectProperties.load(project.getLocation().toOSString(),
|
||||
PropertyType.DEFAULT);
|
||||
if (properties == null) {
|
||||
AdtPlugin.log(IStatus.ERROR, "Failed to load properties file for project '%s'",
|
||||
project.getName());
|
||||
@@ -200,10 +222,12 @@ public class Sdk {
|
||||
public static void setProjectTargetHashString(IProject project, String targetHashString) {
|
||||
// because we don't want to erase other properties from default.properties, we first load
|
||||
// them
|
||||
ProjectProperties properties = ProjectProperties.load(project.getLocation().toOSString());
|
||||
ProjectProperties properties = ProjectProperties.load(project.getLocation().toOSString(),
|
||||
PropertyType.DEFAULT);
|
||||
if (properties == null) {
|
||||
// doesn't exist yet? we create it.
|
||||
properties = ProjectProperties.create(project.getLocation().toOSString());
|
||||
properties = ProjectProperties.create(project.getLocation().toOSString(),
|
||||
PropertyType.DEFAULT);
|
||||
}
|
||||
|
||||
// add/change the target hash string.
|
||||
@@ -218,7 +242,7 @@ public class Sdk {
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Return the {@link PlatformData} for a given {@link IAndroidTarget}.
|
||||
* Return the {@link AndroidTargetData} for a given {@link IAndroidTarget}.
|
||||
*/
|
||||
public AndroidTargetData getTargetData(IAndroidTarget target) {
|
||||
synchronized (mTargetMap) {
|
||||
@@ -226,8 +250,17 @@ public class Sdk {
|
||||
}
|
||||
}
|
||||
|
||||
private Sdk(SdkManager manager) {
|
||||
/**
|
||||
* Returns the {@link VmManager}. If the VmManager failed to parse the VM folder, this could
|
||||
* be <code>null</code>.
|
||||
*/
|
||||
public VmManager getVmManager() {
|
||||
return mVmManager;
|
||||
}
|
||||
|
||||
private Sdk(SdkManager manager, VmManager vmManager) {
|
||||
mManager = manager;
|
||||
mVmManager = vmManager;
|
||||
|
||||
// pre-compute some paths
|
||||
mDocBaseUrl = getDocumentationBaseUrl(mManager.getLocation() +
|
||||
|
||||
@@ -323,7 +323,7 @@ public final class WidgetClassLoader implements IAndroidClassLoader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link IClass} by its fully-qualified name.
|
||||
* Returns a {@link IAndroidClassLoader.IClassDescriptor} by its fully-qualified name.
|
||||
* @param className the fully-qualified name of the class to return.
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.android.ide.eclipse.adt.sdk.Sdk;
|
||||
import com.android.ide.eclipse.common.AndroidConstants;
|
||||
import com.android.ide.eclipse.common.project.AndroidManifestHelper;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
import com.android.sdkuilib.SdkTargetSelector;
|
||||
|
||||
import org.eclipse.core.filesystem.URIUtil;
|
||||
@@ -64,9 +65,11 @@ import java.util.regex.Pattern;
|
||||
* NewAndroidProjectCreationPage is a project creation page that provides the
|
||||
* following fields:
|
||||
* <ul>
|
||||
* <li> Project name
|
||||
* <li> SDK Target
|
||||
* <li> Application name
|
||||
* <li> Package name
|
||||
* <li> Activity name
|
||||
* <li> Location of the SDK
|
||||
* </ul>
|
||||
* Note: this class is public so that it can be accessed from unit tests.
|
||||
* It is however an internal class. Its API may change without notice.
|
||||
@@ -93,13 +96,14 @@ public class NewProjectCreationPage extends WizardPage {
|
||||
private static final Pattern sProjectNamePattern = Pattern.compile("^[\\w][\\w. -]*$"); //$NON-NLS-1$
|
||||
/** Last user-browsed location, static so that it be remembered for the whole session */
|
||||
private static String sCustomLocationOsPath = ""; //$NON-NLS-1$
|
||||
private static boolean sAutoComputeCustomLocation = true;
|
||||
|
||||
private final int MSG_NONE = 0;
|
||||
private final int MSG_WARNING = 1;
|
||||
private final int MSG_ERROR = 2;
|
||||
|
||||
private String mUserPackageName = ""; //$NON-NLS-1$
|
||||
private String mUserActivityName = ""; //$NON-NLS-1$
|
||||
private String mUserActivityName = ""; //$NON-NLS-1$
|
||||
private boolean mUserCreateActivityCheck = INITIAL_CREATE_ACTIVITY;
|
||||
private String mSourceFolder = ""; //$NON-NLS-1$
|
||||
|
||||
@@ -114,6 +118,8 @@ public class NewProjectCreationPage extends WizardPage {
|
||||
private Text mLocationPathField;
|
||||
private Button mBrowseButton;
|
||||
private Button mCreateActivityCheck;
|
||||
private Text mMinSdkVersionField;
|
||||
private SdkTargetSelector mSdkTargetSelector;
|
||||
|
||||
private boolean mInternalLocationPathUpdate;
|
||||
protected boolean mInternalProjectNameUpdate;
|
||||
@@ -122,7 +128,7 @@ public class NewProjectCreationPage extends WizardPage {
|
||||
private boolean mInternalActivityNameUpdate;
|
||||
protected boolean mProjectNameModifiedByUser;
|
||||
protected boolean mApplicationNameModifiedByUser;
|
||||
private SdkTargetSelector mSdkTargetSelector;
|
||||
private boolean mInternalMinSdkVersionUpdate;
|
||||
|
||||
|
||||
/**
|
||||
@@ -133,13 +139,6 @@ public class NewProjectCreationPage extends WizardPage {
|
||||
public NewProjectCreationPage(String pageName) {
|
||||
super(pageName);
|
||||
setPageComplete(false);
|
||||
if (sCustomLocationOsPath == null ||
|
||||
sCustomLocationOsPath.length() == 0 ||
|
||||
!new File(sCustomLocationOsPath).isDirectory()) {
|
||||
// FIXME location of samples is pretty much impossible here.
|
||||
//sCustomLocationOsPath = AdtPlugin.getOsSdkSamplesFolder();
|
||||
sCustomLocationOsPath = File.listRoots()[0].getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
// --- Getters used by NewProjectWizard ---
|
||||
@@ -170,6 +169,11 @@ public class NewProjectCreationPage extends WizardPage {
|
||||
return mActivityNameField == null ? INITIAL_NAME : mActivityNameField.getText().trim();
|
||||
}
|
||||
|
||||
/** Returns the value of the min sdk version field with spaces trimmed. */
|
||||
public String getMinSdkVersion() {
|
||||
return mMinSdkVersionField == null ? "" : mMinSdkVersionField.getText().trim();
|
||||
}
|
||||
|
||||
/** Returns the value of the application name field with spaces trimmed. */
|
||||
public String getApplicationName() {
|
||||
// Return the name of the activity as default application name.
|
||||
@@ -200,7 +204,7 @@ public class NewProjectCreationPage extends WizardPage {
|
||||
* "src" constant. */
|
||||
public String getSourceFolder() {
|
||||
if (isNewProject() || mSourceFolder == null || mSourceFolder.length() == 0) {
|
||||
return AndroidConstants.FD_SOURCES;
|
||||
return SdkConstants.FD_SOURCES;
|
||||
} else {
|
||||
return mSourceFolder;
|
||||
}
|
||||
@@ -389,9 +393,16 @@ public class NewProjectCreationPage extends WizardPage {
|
||||
}
|
||||
|
||||
mSdkTargetSelector = new SdkTargetSelector(group, targets, false /*multi-selection*/);
|
||||
|
||||
// If there's only one target, select it
|
||||
if (targets != null && targets.length == 1) {
|
||||
mSdkTargetSelector.setSelection(targets[0]);
|
||||
}
|
||||
|
||||
mSdkTargetSelector.setSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent e) {
|
||||
updateLocationPathField(null);
|
||||
setPageComplete(validatePage());
|
||||
}
|
||||
});
|
||||
@@ -506,6 +517,25 @@ public class NewProjectCreationPage extends WizardPage {
|
||||
onActivityNameFieldModified();
|
||||
}
|
||||
});
|
||||
|
||||
// min sdk version label
|
||||
label = new Label(group, SWT.NONE);
|
||||
label.setText("Min SDK Version:");
|
||||
label.setFont(parent.getFont());
|
||||
label.setToolTipText("The minimum SDK version number that the application requires. Must be an integer > 0. It can be empty.");
|
||||
|
||||
// min sdk version entry field
|
||||
mMinSdkVersionField = new Text(group, SWT.BORDER);
|
||||
data = new GridData(GridData.FILL_HORIZONTAL);
|
||||
label.setToolTipText("The minimum SDK version number that the application requires. Must be an integer > 0. It can be empty.");
|
||||
mMinSdkVersionField.setLayoutData(data);
|
||||
mMinSdkVersionField.setFont(parent.getFont());
|
||||
mMinSdkVersionField.addListener(SWT.Modify, new Listener() {
|
||||
public void handleEvent(Event event) {
|
||||
onMinSdkVersionFieldModified();
|
||||
setPageComplete(validatePage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -588,7 +618,29 @@ public class NewProjectCreationPage extends WizardPage {
|
||||
mInternalLocationPathUpdate = true;
|
||||
if (custom_location) {
|
||||
if (abs_dir != null) {
|
||||
// We get here if the user selected a directory with the "Browse" button.
|
||||
// Disable auto-compute of the custom location unless the user selected
|
||||
// the exact same path.
|
||||
sAutoComputeCustomLocation = sAutoComputeCustomLocation &&
|
||||
abs_dir.equals(sCustomLocationOsPath);
|
||||
sCustomLocationOsPath = TextProcessor.process(abs_dir);
|
||||
} else if (sAutoComputeCustomLocation ||
|
||||
!new File(sCustomLocationOsPath).isDirectory()) {
|
||||
// By default select the samples directory of the current target
|
||||
IAndroidTarget target = getSdkTarget();
|
||||
if (target != null) {
|
||||
sCustomLocationOsPath = target.getPath(IAndroidTarget.SAMPLES);
|
||||
}
|
||||
|
||||
// If we don't have a target, select the base directory of the
|
||||
// "universal sdk". If we don't even have that, use a root drive.
|
||||
if (sCustomLocationOsPath == null || sCustomLocationOsPath.length() == 0) {
|
||||
if (Sdk.getCurrent() != null) {
|
||||
sCustomLocationOsPath = Sdk.getCurrent().getSdkLocation();
|
||||
} else {
|
||||
sCustomLocationOsPath = File.listRoots()[0].getAbsolutePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!mLocationPathField.getText().equals(sCustomLocationOsPath)) {
|
||||
mLocationPathField.setText(sCustomLocationOsPath);
|
||||
@@ -615,8 +667,13 @@ public class NewProjectCreationPage extends WizardPage {
|
||||
private void onLocationPathFieldModified() {
|
||||
if (!mInternalLocationPathUpdate) {
|
||||
// When the updates doesn't come from updateLocationPathField, it must be the user
|
||||
// editing the field manually, in which case we want to save the value internally.
|
||||
sCustomLocationOsPath = getLocationPathFieldValue();
|
||||
// editing the field manually, in which case we want to save the value internally
|
||||
// and we disable auto-compute of the custom location (to avoid overriding the user
|
||||
// value)
|
||||
String newPath = getLocationPathFieldValue();
|
||||
sAutoComputeCustomLocation = sAutoComputeCustomLocation &&
|
||||
newPath.equals(sCustomLocationOsPath);
|
||||
sCustomLocationOsPath = newPath;
|
||||
extractNamesFromAndroidManifest();
|
||||
setPageComplete(validatePage());
|
||||
}
|
||||
@@ -664,6 +721,31 @@ public class NewProjectCreationPage extends WizardPage {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the min sdk version field has been modified.
|
||||
*
|
||||
* Ignore the internal modifications. When modified by the user, try to match
|
||||
* a target with the same API level.
|
||||
*/
|
||||
private void onMinSdkVersionFieldModified() {
|
||||
if (mInternalMinSdkVersionUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
int version = Integer.parseInt(getMinSdkVersion());
|
||||
|
||||
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
|
||||
if (target.getApiVersionNumber() == version) {
|
||||
mSdkTargetSelector.setSelection(target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the radio buttons are changed between the "create new project" and the
|
||||
* "use existing source" mode. This reverts the fields to whatever the user manually
|
||||
@@ -697,89 +779,132 @@ public class NewProjectCreationPage extends WizardPage {
|
||||
* can actually be found in the custom user directory.
|
||||
*/
|
||||
private void extractNamesFromAndroidManifest() {
|
||||
if (!isNewProject()) {
|
||||
File f = new File(getProjectLocation());
|
||||
if (f.isDirectory()) {
|
||||
Path path = new Path(f.getPath());
|
||||
String osPath = path.append(AndroidConstants.FN_ANDROID_MANIFEST).toOSString();
|
||||
AndroidManifestHelper manifest = new AndroidManifestHelper(osPath);
|
||||
if (manifest.exists()) {
|
||||
String packageName = null;
|
||||
String activityName = null;
|
||||
try {
|
||||
packageName = manifest.getPackageName();
|
||||
activityName = manifest.getActivityName(1);
|
||||
} catch (Exception e) {
|
||||
// pass
|
||||
}
|
||||
if (isNewProject()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String projectLocation = getProjectLocation();
|
||||
File f = new File(projectLocation);
|
||||
if (!f.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Path path = new Path(f.getPath());
|
||||
String osPath = path.append(AndroidConstants.FN_ANDROID_MANIFEST).toOSString();
|
||||
AndroidManifestHelper manifest = new AndroidManifestHelper(osPath);
|
||||
if (!manifest.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String packageName = null;
|
||||
String activityName = null;
|
||||
String minSdkVersion = null;
|
||||
try {
|
||||
packageName = manifest.getPackageName();
|
||||
activityName = manifest.getActivityName(1);
|
||||
minSdkVersion = manifest.getMinSdkVersion();
|
||||
} catch (Exception e) {
|
||||
// ignore exceptions
|
||||
}
|
||||
|
||||
|
||||
if (packageName != null && packageName.length() > 0) {
|
||||
mPackageNameField.setText(packageName);
|
||||
}
|
||||
if (packageName != null && packageName.length() > 0) {
|
||||
mPackageNameField.setText(packageName);
|
||||
}
|
||||
|
||||
if (activityName != null && activityName.length() > 0) {
|
||||
mInternalActivityNameUpdate = true;
|
||||
mInternalCreateActivityUpdate = true;
|
||||
mActivityNameField.setText(activityName);
|
||||
mCreateActivityCheck.setSelection(true);
|
||||
mInternalCreateActivityUpdate = false;
|
||||
mInternalActivityNameUpdate = false;
|
||||
if (activityName != null && activityName.length() > 0) {
|
||||
mInternalActivityNameUpdate = true;
|
||||
mInternalCreateActivityUpdate = true;
|
||||
mActivityNameField.setText(activityName);
|
||||
mCreateActivityCheck.setSelection(true);
|
||||
mInternalCreateActivityUpdate = false;
|
||||
mInternalActivityNameUpdate = 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 (activityName.indexOf('.') != -1) {
|
||||
String[] ids = activityName.split(AndroidConstants.RE_DOT);
|
||||
activityName = ids[ids.length - 1];
|
||||
}
|
||||
if (mProjectNameField.getText().length() == 0 ||
|
||||
!mProjectNameModifiedByUser) {
|
||||
mInternalProjectNameUpdate = true;
|
||||
mProjectNameField.setText(activityName);
|
||||
mInternalProjectNameUpdate = false;
|
||||
}
|
||||
if (mApplicationNameField.getText().length() == 0 ||
|
||||
!mApplicationNameModifiedByUser) {
|
||||
mInternalApplicationNameUpdate = true;
|
||||
mApplicationNameField.setText(activityName);
|
||||
mInternalApplicationNameUpdate = false;
|
||||
}
|
||||
} else {
|
||||
mInternalActivityNameUpdate = true;
|
||||
mInternalCreateActivityUpdate = true;
|
||||
mActivityNameField.setText("");
|
||||
mCreateActivityCheck.setSelection(false);
|
||||
mInternalCreateActivityUpdate = false;
|
||||
mInternalActivityNameUpdate = false;
|
||||
|
||||
// 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 (packageName != null && packageName.length() > 0) {
|
||||
// Package name is a java identifier, so it's most suitable for
|
||||
// an application name.
|
||||
// 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 (activityName.indexOf('.') != -1) {
|
||||
String[] ids = activityName.split(AndroidConstants.RE_DOT);
|
||||
activityName = ids[ids.length - 1];
|
||||
}
|
||||
if (mProjectNameField.getText().length() == 0 ||
|
||||
!mProjectNameModifiedByUser) {
|
||||
mInternalProjectNameUpdate = true;
|
||||
mProjectNameField.setText(activityName);
|
||||
mInternalProjectNameUpdate = false;
|
||||
}
|
||||
if (mApplicationNameField.getText().length() == 0 ||
|
||||
!mApplicationNameModifiedByUser) {
|
||||
mInternalApplicationNameUpdate = true;
|
||||
mApplicationNameField.setText(activityName);
|
||||
mInternalApplicationNameUpdate = false;
|
||||
}
|
||||
} else {
|
||||
mInternalActivityNameUpdate = true;
|
||||
mInternalCreateActivityUpdate = true;
|
||||
mActivityNameField.setText(""); //$NON-NLS-1$
|
||||
mCreateActivityCheck.setSelection(false);
|
||||
mInternalCreateActivityUpdate = false;
|
||||
mInternalActivityNameUpdate = false;
|
||||
|
||||
// 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 (packageName != null && packageName.length() > 0) {
|
||||
// Package name is a java identifier, so it's most suitable for
|
||||
// an application name.
|
||||
|
||||
if (mApplicationNameField.getText().length() == 0 ||
|
||||
!mApplicationNameModifiedByUser) {
|
||||
mInternalApplicationNameUpdate = true;
|
||||
mApplicationNameField.setText(packageName);
|
||||
mInternalApplicationNameUpdate = false;
|
||||
}
|
||||
if (mApplicationNameField.getText().length() == 0 ||
|
||||
!mApplicationNameModifiedByUser) {
|
||||
mInternalApplicationNameUpdate = true;
|
||||
mApplicationNameField.setText(packageName);
|
||||
mInternalApplicationNameUpdate = false;
|
||||
}
|
||||
|
||||
// For the project name, remove any dots
|
||||
packageName = packageName.replace('.', '_');
|
||||
if (mProjectNameField.getText().length() == 0 ||
|
||||
!mProjectNameModifiedByUser) {
|
||||
mInternalProjectNameUpdate = true;
|
||||
mProjectNameField.setText(packageName);
|
||||
mInternalProjectNameUpdate = false;
|
||||
}
|
||||
|
||||
}
|
||||
// For the project name, remove any dots
|
||||
packageName = packageName.replace('.', '_');
|
||||
if (mProjectNameField.getText().length() == 0 ||
|
||||
!mProjectNameModifiedByUser) {
|
||||
mInternalProjectNameUpdate = true;
|
||||
mProjectNameField.setText(packageName);
|
||||
mInternalProjectNameUpdate = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Select the target matching the manifest's sdk, if any
|
||||
boolean foundTarget = false;
|
||||
if (minSdkVersion != null) {
|
||||
try {
|
||||
int sdkVersion = Integer.parseInt(minSdkVersion);
|
||||
|
||||
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
|
||||
if (target.getApiVersionNumber() == sdkVersion) {
|
||||
mSdkTargetSelector.setSelection(target);
|
||||
foundTarget = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch(NumberFormatException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundTarget) {
|
||||
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
|
||||
if (projectLocation.startsWith(target.getLocation())) {
|
||||
mSdkTargetSelector.setSelection(target);
|
||||
foundTarget = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundTarget) {
|
||||
mInternalMinSdkVersionUpdate = true;
|
||||
mMinSdkVersionField.setText(minSdkVersion == null ? "" : minSdkVersion); //$NON-NLS-1$
|
||||
mInternalMinSdkVersionUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -804,6 +929,9 @@ public class NewProjectCreationPage extends WizardPage {
|
||||
if ((status & MSG_ERROR) == 0) {
|
||||
status |= validateActivityField();
|
||||
}
|
||||
if ((status & MSG_ERROR) == 0) {
|
||||
status |= validateMinSdkVersionField();
|
||||
}
|
||||
if ((status & MSG_ERROR) == 0) {
|
||||
status |= validateSourceFolder();
|
||||
}
|
||||
@@ -949,6 +1077,38 @@ public class NewProjectCreationPage extends WizardPage {
|
||||
return MSG_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the sdk target choice.
|
||||
*
|
||||
* @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE.
|
||||
*/
|
||||
private int validateMinSdkVersionField() {
|
||||
|
||||
// If the min sdk version is empty, it is always accepted.
|
||||
if (getMinSdkVersion().length() == 0) {
|
||||
return MSG_NONE;
|
||||
}
|
||||
|
||||
int version = -1;
|
||||
try {
|
||||
// If not empty, it must be a valid integer > 0
|
||||
version = Integer.parseInt(getMinSdkVersion());
|
||||
} catch (NumberFormatException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
if (version < 1) {
|
||||
return setStatus("Min SDK Version must be an integer > 0.", MSG_ERROR);
|
||||
}
|
||||
|
||||
if (getSdkTarget() != null && getSdkTarget().getApiVersionNumber() != version) {
|
||||
return setStatus("The API level for the selected SDK target does not match the Min SDK version.",
|
||||
MSG_WARNING);
|
||||
}
|
||||
|
||||
return MSG_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the activity name field.
|
||||
*
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.android.ide.eclipse.adt.project.ProjectHelper;
|
||||
import com.android.ide.eclipse.adt.sdk.Sdk;
|
||||
import com.android.ide.eclipse.common.AndroidConstants;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
|
||||
import org.eclipse.core.resources.IContainer;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
@@ -85,32 +86,36 @@ public class NewProjectWizard extends Wizard implements INewWizard {
|
||||
private static final String PARAM_IS_NEW_PROJECT = "IS_NEW_PROJECT"; //$NON-NLS-1$
|
||||
private static final String PARAM_SRC_FOLDER = "SRC_FOLDER"; //$NON-NLS-1$
|
||||
private static final String PARAM_SDK_TARGET = "SDK_TARGET"; //$NON-NLS-1$
|
||||
private static final String PARAM_MIN_SDK_VERSION = "MIN_SDK_VERSION"; //$NON-NLS-1$
|
||||
|
||||
private static final String PH_ACTIVITIES = "ACTIVITIES"; //$NON-NLS-1$
|
||||
private static final String PH_USES_SDK = "USES-SDK"; //$NON-NLS-1$
|
||||
private static final String PH_INTENT_FILTERS = "INTENT_FILTERS"; //$NON-NLS-1$
|
||||
private static final String PH_STRINGS = "STRINGS"; //$NON-NLS-1$
|
||||
|
||||
private static final String BIN_DIRECTORY =
|
||||
AndroidConstants.FD_BINARIES + AndroidConstants.WS_SEP;
|
||||
SdkConstants.FD_OUTPUT + AndroidConstants.WS_SEP;
|
||||
private static final String RES_DIRECTORY =
|
||||
AndroidConstants.FD_RESOURCES + AndroidConstants.WS_SEP;
|
||||
SdkConstants.FD_RESOURCES + AndroidConstants.WS_SEP;
|
||||
private static final String ASSETS_DIRECTORY =
|
||||
AndroidConstants.FD_ASSETS + AndroidConstants.WS_SEP;
|
||||
SdkConstants.FD_ASSETS + AndroidConstants.WS_SEP;
|
||||
private static final String DRAWABLE_DIRECTORY =
|
||||
AndroidConstants.FD_DRAWABLE + AndroidConstants.WS_SEP;
|
||||
SdkConstants.FD_DRAWABLE + AndroidConstants.WS_SEP;
|
||||
private static final String LAYOUT_DIRECTORY =
|
||||
AndroidConstants.FD_LAYOUT + AndroidConstants.WS_SEP;
|
||||
SdkConstants.FD_LAYOUT + AndroidConstants.WS_SEP;
|
||||
private static final String VALUES_DIRECTORY =
|
||||
AndroidConstants.FD_VALUES + AndroidConstants.WS_SEP;
|
||||
SdkConstants.FD_VALUES + AndroidConstants.WS_SEP;
|
||||
|
||||
private static final String TEMPLATES_DIRECTORY = "templates/"; //$NON-NLS-1$
|
||||
private static final String TEMPLATE_MANIFEST = TEMPLATES_DIRECTORY
|
||||
+ "AndroidManifest.template"; //$NON-NLS-1$
|
||||
private static final String TEMPLATE_ACTIVITIES = TEMPLATES_DIRECTORY
|
||||
+ "activity.template"; //$NON-NLS-1$
|
||||
private static final String TEMPLATE_USES_SDK = TEMPLATES_DIRECTORY
|
||||
+ "uses-sdk.template"; //$NON-NLS-1$
|
||||
private static final String TEMPLATE_INTENT_LAUNCHER = TEMPLATES_DIRECTORY
|
||||
+ "launcher_intent_filter.template"; //$NON-NLS-1$
|
||||
|
||||
|
||||
private static final String TEMPLATE_STRINGS = TEMPLATES_DIRECTORY
|
||||
+ "strings.template"; //$NON-NLS-1$
|
||||
private static final String TEMPLATE_STRING = TEMPLATES_DIRECTORY
|
||||
@@ -235,6 +240,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
|
||||
parameters.put(PARAM_IS_NEW_PROJECT, mMainPage.isNewProject());
|
||||
parameters.put(PARAM_SRC_FOLDER, mMainPage.getSourceFolder());
|
||||
parameters.put(PARAM_SDK_TARGET, mMainPage.getSdkTarget());
|
||||
parameters.put(PARAM_MIN_SDK_VERSION, mMainPage.getMinSdkVersion());
|
||||
|
||||
if (mMainPage.isCreateActivity()) {
|
||||
// An activity name can be of the form ".package.Class" or ".Class".
|
||||
@@ -449,6 +455,15 @@ public class NewProjectWizard extends Wizard implements INewWizard {
|
||||
// remove the activity(ies) from the manifest
|
||||
manifestTemplate = manifestTemplate.replaceAll(PH_ACTIVITIES, "");
|
||||
}
|
||||
|
||||
String minSdkVersion = (String) parameters.get(PARAM_MIN_SDK_VERSION);
|
||||
if (minSdkVersion != null && minSdkVersion.length() > 0) {
|
||||
String usesSdkTemplate = AdtPlugin.readEmbeddedTextFile(TEMPLATE_USES_SDK);
|
||||
String usesSdk = replaceParameters(usesSdkTemplate, parameters);
|
||||
manifestTemplate = manifestTemplate.replaceAll(PH_USES_SDK, usesSdk);
|
||||
} else {
|
||||
manifestTemplate = manifestTemplate.replaceAll(PH_USES_SDK, "");
|
||||
}
|
||||
|
||||
// Save in the project as UTF-8
|
||||
InputStream stream = new ByteArrayInputStream(
|
||||
|
||||
@@ -130,48 +130,14 @@ public class AndroidConstants {
|
||||
public final static String FN_TRACEVIEW = (CURRENT_PLATFORM == PLATFORM_WINDOWS) ?
|
||||
"traceview.exe" : "traceview"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
/** Folder Names for Android Projects . */
|
||||
|
||||
/* Resources folder name, i.e. "res". */
|
||||
public final static String FD_RESOURCES = "res"; //$NON-NLS-1$
|
||||
/** Assets folder name, i.e. "assets" */
|
||||
public final static String FD_ASSETS = "assets"; //$NON-NLS-1$
|
||||
/** Default source folder name, i.e. "src" */
|
||||
public final static String FD_SOURCES = "src"; //$NON-NLS-1$
|
||||
/** Default native library folder name inside the project, i.e. "libs"
|
||||
* While the folder inside the .apk is "lib", we call that one libs because
|
||||
* that's what we use in ant for both .jar and .so and we need to make the 2 development ways
|
||||
* compatible. */
|
||||
public final static String FD_NATIVE_LIBS = "libs"; //$NON-NLS-1$
|
||||
/** Native lib folder inside the APK: "lib" */
|
||||
public final static String FD_APK_NATIVE_LIBS = "lib"; //$NON-NLS-1$
|
||||
/** Default bin folder name, i.e. "bin" */
|
||||
public final static String FD_BINARIES = "bin"; //$NON-NLS-1$
|
||||
/** Default anim resource folder name, i.e. "anim" */
|
||||
public final static String FD_ANIM = "anim"; //$NON-NLS-1$
|
||||
/** Default color resource folder name, i.e. "color" */
|
||||
public final static String FD_COLOR = "color"; //$NON-NLS-1$
|
||||
/** Default drawable resource folder name, i.e. "drawable" */
|
||||
public final static String FD_DRAWABLE = "drawable"; //$NON-NLS-1$
|
||||
/** Default layout resource folder name, i.e. "layout" */
|
||||
public final static String FD_LAYOUT = "layout"; //$NON-NLS-1$
|
||||
/** Default menu resource folder name, i.e. "menu" */
|
||||
public final static String FD_MENU = "menu"; //$NON-NLS-1$
|
||||
/** Default values resource folder name, i.e. "values" */
|
||||
public final static String FD_VALUES = "values"; //$NON-NLS-1$
|
||||
/** Default xml resource folder name, i.e. "xml" */
|
||||
public final static String FD_XML = "xml"; //$NON-NLS-1$
|
||||
/** Default raw resource folder name, i.e. "raw" */
|
||||
public final static String FD_RAW = "raw"; //$NON-NLS-1$
|
||||
|
||||
/** Absolute path of the workspace root, i.e. "/" */
|
||||
public final static String WS_ROOT = WS_SEP;
|
||||
|
||||
/** Absolute path of the resource folder, eg "/res".<br> This is a workspace path. */
|
||||
public final static String WS_RESOURCES = WS_SEP + FD_RESOURCES;
|
||||
public final static String WS_RESOURCES = WS_SEP + SdkConstants.FD_RESOURCES;
|
||||
|
||||
/** Absolute path of the resource folder, eg "/assets".<br> This is a workspace path. */
|
||||
public final static String WS_ASSETS = WS_SEP + FD_ASSETS;
|
||||
public final static String WS_ASSETS = WS_SEP + SdkConstants.FD_ASSETS;
|
||||
|
||||
/** Leaf of the javaDoc folder. Does not start with a separator. */
|
||||
public final static String WS_JAVADOC_FOLDER_LEAF = SdkConstants.FD_DOCS + "/reference"; //$NON-NLS-1$
|
||||
|
||||
@@ -97,7 +97,7 @@ public class AndroidManifestHelper {
|
||||
*/
|
||||
public String getPackageName() {
|
||||
try {
|
||||
return getPackageNameInternal(mXPath, getSource());
|
||||
return mXPath.evaluate("/manifest/@package", getSource()); //$NON-NLS-1$
|
||||
} catch (XPathExpressionException e1) {
|
||||
// If the XPath failed to evaluate, we'll return null.
|
||||
} catch (Exception e) {
|
||||
@@ -110,18 +110,40 @@ public class AndroidManifestHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minSdkVersion defined in the manifest file.
|
||||
*
|
||||
* @return A String object with the package or null if any error happened.
|
||||
*/
|
||||
public String getMinSdkVersion() {
|
||||
try {
|
||||
return mXPath.evaluate("/manifest/uses-sdk/@" //$NON-NLS-1$
|
||||
+ AndroidXPathFactory.DEFAULT_NS_PREFIX
|
||||
+ ":minSdkVersion", getSource()); //$NON-NLS-1$
|
||||
} catch (XPathExpressionException e1) {
|
||||
// If the XPath failed to evaluate, we'll return null.
|
||||
} catch (Exception e) {
|
||||
// if this happens this is due to the resource being out of sync.
|
||||
// so we must refresh it and do it again
|
||||
|
||||
// for any other kind of exception we must return null as well;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Returns the i-th activity defined in the manifest file.
|
||||
*
|
||||
* @param manifest The manifest's IFile object.
|
||||
* @param index The 1-based index of the activity to return.
|
||||
* @param xpath An optional xpath object. If null is provided a new one will
|
||||
* be created.
|
||||
* @return A String object with the activity or null if any error happened.
|
||||
*/
|
||||
public String getActivityName(int index) {
|
||||
try {
|
||||
return getActivityNameInternal(index, mXPath, getSource());
|
||||
return mXPath.evaluate("/manifest/application/activity[" //$NON-NLS-1$
|
||||
+ index
|
||||
+ "]/@" //$NON-NLS-1$
|
||||
+ AndroidXPathFactory.DEFAULT_NS_PREFIX +":name", //$NON-NLS-1$
|
||||
getSource());
|
||||
} catch (XPathExpressionException e1) {
|
||||
// If the XPath failed to evaluate, we'll return null.
|
||||
} catch (Exception e) {
|
||||
@@ -216,26 +238,4 @@ public class AndroidManifestHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual XPath evaluation to get the package name.
|
||||
* Extracted so that we can share it with AndroidManifestFromProject.
|
||||
*/
|
||||
private static String getPackageNameInternal(XPath xpath, InputSource source)
|
||||
throws XPathExpressionException {
|
||||
return xpath.evaluate("/manifest/@package", source); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual XPath evaluation to get the activity name.
|
||||
* Extracted so that we can share it with AndroidManifestFromProject.
|
||||
*/
|
||||
private static String getActivityNameInternal(int index, XPath xpath, InputSource source)
|
||||
throws XPathExpressionException {
|
||||
return xpath.evaluate("/manifest/application/activity[" //$NON-NLS-1$
|
||||
+ index
|
||||
+ "]/@" //$NON-NLS-1$
|
||||
+ AndroidXPathFactory.DEFAULT_NS_PREFIX +":name", //$NON-NLS-1$
|
||||
source);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ public class AndroidManifestParser {
|
||||
* @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException)
|
||||
*/
|
||||
@Override
|
||||
public void error(SAXParseException e) throws SAXException {
|
||||
public void error(SAXParseException e) {
|
||||
if (mMarkErrors) {
|
||||
handleError(e, e.getLineNumber());
|
||||
}
|
||||
@@ -329,7 +329,7 @@ public class AndroidManifestParser {
|
||||
* @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException)
|
||||
*/
|
||||
@Override
|
||||
public void fatalError(SAXParseException e) throws SAXException {
|
||||
public void fatalError(SAXParseException e) {
|
||||
if (mMarkErrors) {
|
||||
handleError(e, e.getLineNumber());
|
||||
}
|
||||
@@ -348,7 +348,6 @@ public class AndroidManifestParser {
|
||||
/**
|
||||
* Processes the activity node.
|
||||
* @param attributes the attributes for the activity node.
|
||||
* @throws CoreException
|
||||
*/
|
||||
private void processActivityNode(Attributes attributes) {
|
||||
// lets get the activity name, and add it to the list
|
||||
@@ -381,7 +380,6 @@ public class AndroidManifestParser {
|
||||
* @param attributes the attributes for the activity node.
|
||||
* @param superClassName the fully qualified name of the super class that this
|
||||
* node is representing
|
||||
* @throws CoreException
|
||||
*/
|
||||
private void processNode(Attributes attributes, String superClassName) {
|
||||
// lets get the class name, and check it if required.
|
||||
@@ -567,12 +565,11 @@ public class AndroidManifestParser {
|
||||
/**
|
||||
* Parses the manifest file, collects data, and checks for errors.
|
||||
* @param javaProject The java project. Required.
|
||||
* @param manifestFile
|
||||
* @param manifestFile The manifest file to parse.
|
||||
* @param errorListener the {@link XmlErrorListener} object being notified of the presence
|
||||
* of errors. Optional.
|
||||
* @return an {@link AndroidManifestParser} or null if the parsing failed.
|
||||
* @throws CoreException
|
||||
* @see {@link #parse(IJavaProject, IFile, XmlErrorListener, boolean, boolean)}
|
||||
*/
|
||||
public static AndroidManifestParser parseForError(IJavaProject javaProject, IFile manifestFile,
|
||||
XmlErrorListener errorListener) throws CoreException {
|
||||
@@ -581,12 +578,9 @@ public class AndroidManifestParser {
|
||||
|
||||
/**
|
||||
* Parses the manifest file, and collects data.
|
||||
* @param manifestFile
|
||||
* @param errorListener the {@link XmlErrorListener} object being notified of the presence
|
||||
* of errors. Optional.
|
||||
* @param manifestFile The manifest file to parse.
|
||||
* @return an {@link AndroidManifestParser} or null if the parsing failed.
|
||||
* @throws CoreException
|
||||
* @see {@link #parse(IJavaProject, IFile, XmlErrorListener, boolean, boolean)}
|
||||
*/
|
||||
public static AndroidManifestParser parseForData(IFile manifestFile) throws CoreException {
|
||||
return parse(null /* javaProject */, manifestFile, null /* errorListener */,
|
||||
|
||||
@@ -39,7 +39,7 @@ public class AndroidXPathFactory {
|
||||
|
||||
/**
|
||||
* Construct the context with the prefix associated with the android namespace.
|
||||
* @param prefix the Prefix
|
||||
* @param androidPrefix the Prefix
|
||||
*/
|
||||
public AndroidNamespaceContext(String androidPrefix) {
|
||||
mAndroidPrefix = androidPrefix;
|
||||
@@ -71,7 +71,7 @@ public class AndroidXPathFactory {
|
||||
/**
|
||||
* Creates a new XPath object, specifying which prefix in the query is used for the
|
||||
* android namespace.
|
||||
* @param prefix The namespace prefix.
|
||||
* @param androidPrefix The namespace prefix.
|
||||
*/
|
||||
public static XPath newXPath(String androidPrefix) {
|
||||
XPath xpath = sFactory.newXPath();
|
||||
|
||||
@@ -82,11 +82,13 @@ public final class BaseProjectHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a marker to a file on a specific line
|
||||
* Adds a marker to a file on a specific line. This methods catches thrown
|
||||
* {@link CoreException}, and returns null instead.
|
||||
* @param file the file to be marked
|
||||
* @param markerId The id of the marker to add.
|
||||
* @param message the message associated with the mark
|
||||
* @param lineNumber the line number where to put the mark
|
||||
* @param lineNumber the line number where to put the mark. If line is < 1, it puts the marker
|
||||
* on line 1.
|
||||
* @param severity the severity of the marker.
|
||||
* @return the IMarker that was added or null if it failed to add one.
|
||||
*/
|
||||
@@ -96,7 +98,7 @@ public final class BaseProjectHelper {
|
||||
IMarker marker = file.createMarker(markerId);
|
||||
marker.setAttribute(IMarker.MESSAGE, message);
|
||||
marker.setAttribute(IMarker.SEVERITY, severity);
|
||||
if (lineNumber == -1) {
|
||||
if (lineNumber < 1) {
|
||||
lineNumber = 1;
|
||||
}
|
||||
marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
|
||||
@@ -108,7 +110,7 @@ public final class BaseProjectHelper {
|
||||
|
||||
return marker;
|
||||
} catch (CoreException e) {
|
||||
AdtPlugin.log(e, "Failed to add marker '%1$s' to '%2$s'",
|
||||
AdtPlugin.log(e, "Failed to add marker '%1$s' to '%2$s'", //$NON-NLS-1$
|
||||
markerId, file.getFullPath());
|
||||
}
|
||||
|
||||
@@ -116,7 +118,8 @@ public final class BaseProjectHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a marker to a resource.
|
||||
* Adds a marker to a resource. This methods catches thrown {@link CoreException},
|
||||
* and returns null instead.
|
||||
* @param resource the file to be marked
|
||||
* @param markerId The id of the marker to add.
|
||||
* @param message the message associated with the mark
|
||||
@@ -129,7 +132,7 @@ public final class BaseProjectHelper {
|
||||
IMarker marker = resource.createMarker(markerId);
|
||||
marker.setAttribute(IMarker.MESSAGE, message);
|
||||
marker.setAttribute(IMarker.SEVERITY, severity);
|
||||
|
||||
|
||||
// on Windows, when adding a marker to a project, it takes a refresh for the marker
|
||||
// to show. In order to fix this we're forcing a refresh of elements receiving
|
||||
// markers (and only the element, not its children), to force the marker display.
|
||||
@@ -137,13 +140,43 @@ public final class BaseProjectHelper {
|
||||
|
||||
return marker;
|
||||
} catch (CoreException e) {
|
||||
AdtPlugin.log(e, "Failed to add marker '%1$s' to '%2$s'",
|
||||
AdtPlugin.log(e, "Failed to add marker '%1$s' to '%2$s'", //$NON-NLS-1$
|
||||
markerId, resource.getFullPath());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a marker to a resource. This method does not catch {@link CoreException} and instead
|
||||
* throw them.
|
||||
* @param resource the file to be marked
|
||||
* @param markerId The id of the marker to add.
|
||||
* @param message the message associated with the mark
|
||||
* @param lineNumber the line number where to put the mark if != -1.
|
||||
* @param severity the severity of the marker.
|
||||
* @param priority the priority of the marker
|
||||
* @return the IMarker that was added.
|
||||
* @throws CoreException
|
||||
*/
|
||||
public final static IMarker addMarker(IResource resource, String markerId,
|
||||
String message, int lineNumber, int severity, int priority) throws CoreException {
|
||||
IMarker marker = resource.createMarker(markerId);
|
||||
marker.setAttribute(IMarker.MESSAGE, message);
|
||||
marker.setAttribute(IMarker.SEVERITY, severity);
|
||||
if (lineNumber != -1) {
|
||||
marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
|
||||
}
|
||||
marker.setAttribute(IMarker.PRIORITY, priority);
|
||||
|
||||
// on Windows, when adding a marker to a project, it takes a refresh for the marker
|
||||
// to show. In order to fix this we're forcing a refresh of elements receiving
|
||||
// markers (and only the element, not its children), to force the marker display.
|
||||
resource.refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor());
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a class name is valid for usage in the manifest.
|
||||
* <p/>
|
||||
|
||||
@@ -62,6 +62,7 @@ public class XmlErrorHandler extends DefaultHandler {
|
||||
/**
|
||||
* Xml Error call back
|
||||
* @param exception the parsing exception
|
||||
* @throws SAXException
|
||||
*/
|
||||
@Override
|
||||
public void error(SAXParseException exception) throws SAXException {
|
||||
@@ -71,6 +72,7 @@ public class XmlErrorHandler extends DefaultHandler {
|
||||
/**
|
||||
* Xml Fatal Error call back
|
||||
* @param exception the parsing exception
|
||||
* @throws SAXException
|
||||
*/
|
||||
@Override
|
||||
public void fatalError(SAXParseException exception) throws SAXException {
|
||||
@@ -80,6 +82,7 @@ public class XmlErrorHandler extends DefaultHandler {
|
||||
/**
|
||||
* Xml Warning call back
|
||||
* @param exception the parsing exception
|
||||
* @throws SAXException
|
||||
*/
|
||||
@Override
|
||||
public void warning(SAXParseException exception) throws SAXException {
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.android.ide.eclipse.adt.AdtPlugin;
|
||||
import com.android.ide.eclipse.common.resources.DeclareStyleableInfo.AttributeInfo;
|
||||
import com.android.ide.eclipse.common.resources.DeclareStyleableInfo.AttributeInfo.Format;
|
||||
import com.android.ide.eclipse.common.resources.ViewClassInfo.LayoutParamsInfo;
|
||||
import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils;
|
||||
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.w3c.dom.Document;
|
||||
@@ -228,7 +229,7 @@ public final class AttrsXmlParser {
|
||||
}
|
||||
mStyleMap.put(name, style);
|
||||
if (lastComment != null) {
|
||||
style.setJavaDoc(formatJavadoc(lastComment.getNodeValue()));
|
||||
style.setJavaDoc(parseJavadoc(lastComment.getNodeValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -263,14 +264,15 @@ public final class AttrsXmlParser {
|
||||
}
|
||||
if (info != null) {
|
||||
if (lastComment != null) {
|
||||
info.setJavaDoc(formatJavadoc(lastComment.getNodeValue()));
|
||||
info.setJavaDoc(parseJavadoc(lastComment.getNodeValue()));
|
||||
info.setDeprecatedDoc(parseDeprecatedDoc(lastComment.getNodeValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds all the attributes for a particular style node,
|
||||
* e.g. a declare-styleable of name "TextView" or "LinearLayout_Layout".
|
||||
@@ -431,16 +433,23 @@ public final class AttrsXmlParser {
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the javadoc.
|
||||
* Parses the javadoc comment.
|
||||
* Only keeps the first sentence.
|
||||
* Removes and simplifies links and references.
|
||||
* <p/>
|
||||
* This does not remove nor simplify links and references. Such a transformation
|
||||
* is done later at "display" time in {@link DescriptorsUtils#formatTooltip(String)} and co.
|
||||
*/
|
||||
private String formatJavadoc(String comment) {
|
||||
private String parseJavadoc(String comment) {
|
||||
if (comment == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// sanitize & collapse whitespace
|
||||
comment = comment.replaceAll("\\s+", " "); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
// Explicitly remove any @deprecated tags since they are handled separately.
|
||||
comment = comment.replaceAll("(?:\\{@deprecated[^}]*\\}|@deprecated[^@}]*)", "");
|
||||
|
||||
// take everything up to the first dot that is followed by a space or the end of the line.
|
||||
// I love regexps :-). For the curious, the regexp is:
|
||||
// - start of line
|
||||
@@ -456,6 +465,41 @@ public final class AttrsXmlParser {
|
||||
// - followed by a space (?= non-capturing zero-width positive look-ahead)
|
||||
// - anything else is ignored
|
||||
comment = comment.replaceFirst("^\\s*(.*?(?:$|(?<![a-zA-Z]\\.[a-zA-Z])\\.(?=\\s))).*", "$1"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
return comment;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parses the javadoc and extract the first @deprecated tag, if any.
|
||||
* Returns null if there's no @deprecated tag.
|
||||
* The deprecated tag can be of two forms:
|
||||
* - {+@deprecated ...text till the next bracket }
|
||||
* Note: there should be no space or + between { and @. I need one in this comment otherwise
|
||||
* this method will be tagged as deprecated ;-)
|
||||
* - @deprecated ...text till the next @tag or end of the comment.
|
||||
* In both cases the comment can be multi-line.
|
||||
*/
|
||||
private String parseDeprecatedDoc(String comment) {
|
||||
// Skip if we can't even find the tag in the comment.
|
||||
if (comment == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// sanitize & collapse whitespace
|
||||
comment = comment.replaceAll("\\s+", " "); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
int pos = comment.indexOf("{@deprecated");
|
||||
if (pos >= 0) {
|
||||
comment = comment.substring(pos + 12 /* len of {@deprecated */);
|
||||
comment = comment.replaceFirst("^([^}]*).*", "$1");
|
||||
} else if ((pos = comment.indexOf("@deprecated")) >= 0) {
|
||||
comment = comment.substring(pos + 11 /* len of @deprecated */);
|
||||
comment = comment.replaceFirst("^(.*?)(?:@.*|$)", "$1");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
return comment.trim();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +55,10 @@ public class DeclareStyleableInfo {
|
||||
private String[] mEnumValues;
|
||||
/** Values for flag. null for other types. */
|
||||
private String[] mFlagValues;
|
||||
/** Short javadoc */
|
||||
/** Short javadoc (i.e. the first sentence). */
|
||||
private String mJavaDoc;
|
||||
/** Documentation for deprecated attributes. Null if not deprecated. */
|
||||
private String mDeprecatedDoc;
|
||||
|
||||
/**
|
||||
* @param name The XML Name of the attribute
|
||||
@@ -74,6 +76,7 @@ public class DeclareStyleableInfo {
|
||||
mEnumValues = info.mEnumValues;
|
||||
mFlagValues = info.mFlagValues;
|
||||
mJavaDoc = info.mJavaDoc;
|
||||
mDeprecatedDoc = info.mDeprecatedDoc;
|
||||
}
|
||||
|
||||
/** Returns the XML Name of the attribute */
|
||||
@@ -93,10 +96,14 @@ public class DeclareStyleableInfo {
|
||||
public String[] getFlagValues() {
|
||||
return mFlagValues;
|
||||
}
|
||||
/** Returns a short javadoc */
|
||||
/** Returns a short javadoc, .i.e. the first sentence. */
|
||||
public String getJavaDoc() {
|
||||
return mJavaDoc;
|
||||
}
|
||||
/** Returns the documentation for deprecated attributes. Null if not deprecated. */
|
||||
public String getDeprecatedDoc() {
|
||||
return mDeprecatedDoc;
|
||||
}
|
||||
|
||||
/** Sets the values for enums. null for other types. */
|
||||
public void setEnumValues(String[] values) {
|
||||
@@ -106,10 +113,14 @@ public class DeclareStyleableInfo {
|
||||
public void setFlagValues(String[] values) {
|
||||
mFlagValues = values;
|
||||
}
|
||||
/** Sets a short javadoc */
|
||||
/** Sets a short javadoc, .i.e. the first sentence. */
|
||||
public void setJavaDoc(String javaDoc) {
|
||||
mJavaDoc = javaDoc;
|
||||
}
|
||||
/** Sets the documentation for deprecated attributes. Null if not deprecated. */
|
||||
public void setDeprecatedDoc(String deprecatedDoc) {
|
||||
mDeprecatedDoc = deprecatedDoc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,12 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
|
||||
|
||||
/**
|
||||
* Constructor for AndroidContentAssist
|
||||
* @param rootElementDescriptors The valid root elements of the XML hierarchy
|
||||
* @param descriptorId An id for {@link AndroidTargetData#getDescriptorProvider(int)}.
|
||||
* The Id can be one of {@link AndroidTargetData#DESCRIPTOR_MANIFEST},
|
||||
* {@link AndroidTargetData#DESCRIPTOR_LAYOUT},
|
||||
* {@link AndroidTargetData#DESCRIPTOR_MENU},
|
||||
* or {@link AndroidTargetData#DESCRIPTOR_XML}.
|
||||
* All other values will throw an {@link IllegalArgumentException} later at runtime.
|
||||
*/
|
||||
public AndroidContentAssist(int descriptorId) {
|
||||
mDescriptorId = descriptorId;
|
||||
@@ -723,7 +728,6 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
|
||||
|
||||
/**
|
||||
* Computes (if needed) and returns the root descriptor.
|
||||
* @return
|
||||
*/
|
||||
private ElementDescriptor getRootDescriptor() {
|
||||
if (mRootDescriptor == null) {
|
||||
|
||||
@@ -722,7 +722,7 @@ public abstract class AndroidEditor extends FormEditor implements IResourceChang
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link PlatformData} for the edited file.
|
||||
* Returns the {@link AndroidTargetData} for the edited file.
|
||||
*/
|
||||
public AndroidTargetData getTargetData() {
|
||||
IProject project = getProject();
|
||||
|
||||
@@ -38,6 +38,7 @@ public abstract class AttributeDescriptor {
|
||||
private String mXmlLocalName;
|
||||
private ElementDescriptor mParent;
|
||||
private final String mNsUri;
|
||||
private boolean mDeprecated;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AttributeDescriptor}
|
||||
@@ -70,6 +71,14 @@ public abstract class AttributeDescriptor {
|
||||
return mParent;
|
||||
}
|
||||
|
||||
public void setDeprecated(boolean isDeprecated) {
|
||||
mDeprecated = isDeprecated;
|
||||
}
|
||||
|
||||
public boolean isDeprecated() {
|
||||
return mDeprecated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an optional icon for the attribute.
|
||||
* <p/>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.ide.eclipse.editors.descriptors;
|
||||
|
||||
import com.android.ide.eclipse.editors.IconFactory;
|
||||
import com.android.ide.eclipse.editors.uimodel.UiAbstractTextAttributeNode;
|
||||
|
||||
import org.eclipse.jface.viewers.ILabelProvider;
|
||||
@@ -35,6 +36,17 @@ public class AttributeDescriptorLabelProvider implements ILabelProvider {
|
||||
}
|
||||
|
||||
public Image getImage(Object element) {
|
||||
if (element instanceof UiAbstractTextAttributeNode) {
|
||||
UiAbstractTextAttributeNode node = (UiAbstractTextAttributeNode) element;
|
||||
if (node.getDescriptor().isDeprecated()) {
|
||||
String v = node.getCurrentValue();
|
||||
if (v != null && v.length() > 0) {
|
||||
IconFactory factory = IconFactory.getInstance();
|
||||
return factory.getIcon("warning"); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,8 +92,9 @@ public final class DescriptorsUtils {
|
||||
* @param nsUri The URI of the attribute. Can be null if attribute has no namespace.
|
||||
* See {@link AndroidConstants#NS_RESOURCES} for a common value.
|
||||
* @param infos The array of {@link AttributeInfo} to read and append to attributes
|
||||
* @param requiredAttributes An optional list of attributes to mark as "required" (i.e. append
|
||||
* a "*" to their UI name as a hint for the user.)
|
||||
* @param requiredAttributes An optional set of attributes to mark as "required" (i.e. append
|
||||
* a "*" to their UI name as a hint for the user.) If not null, must contains
|
||||
* entries in the form "elem-name/attr-name". Elem-name can be "*".
|
||||
* @param overrides A map [attribute name => TextAttributeDescriptor creator]. A creator
|
||||
* can either by a Class<? extends TextAttributeDescriptor> or an instance of
|
||||
* {@link ITextAttributeCreator} that instantiates the right TextAttributeDescriptor.
|
||||
@@ -101,16 +102,15 @@ public final class DescriptorsUtils {
|
||||
public static void appendAttributes(ArrayList<AttributeDescriptor> attributes,
|
||||
String elementXmlName,
|
||||
String nsUri, AttributeInfo[] infos,
|
||||
String[] requiredAttributes,
|
||||
Set<String> requiredAttributes,
|
||||
Map<String, Object> overrides) {
|
||||
for (AttributeInfo info : infos) {
|
||||
boolean required = false;
|
||||
if (requiredAttributes != null) {
|
||||
for(String attr_name : requiredAttributes) {
|
||||
if (attr_name.equals(info.getName())) {
|
||||
required = true;
|
||||
break;
|
||||
}
|
||||
String attr_name = info.getName();
|
||||
if (requiredAttributes.contains("*/" + attr_name) ||
|
||||
requiredAttributes.contains(elementXmlName + "/" + attr_name)) {
|
||||
required = true;
|
||||
}
|
||||
}
|
||||
appendAttribute(attributes, elementXmlName, nsUri, info, required, overrides);
|
||||
@@ -144,7 +144,26 @@ public final class DescriptorsUtils {
|
||||
if (required) {
|
||||
uiName += "*"; //$NON-NLS-1$
|
||||
}
|
||||
String tooltip = formatTooltip(info.getJavaDoc()); // tooltip
|
||||
|
||||
String tooltip = null;
|
||||
String rawTooltip = info.getJavaDoc();
|
||||
if (rawTooltip == null) {
|
||||
rawTooltip = "";
|
||||
}
|
||||
|
||||
String deprecated = info.getDeprecatedDoc();
|
||||
if (deprecated != null) {
|
||||
if (rawTooltip.length() > 0) {
|
||||
rawTooltip += "@@"; //$NON-NLS-1$ insert a break
|
||||
}
|
||||
rawTooltip += "* Deprecated";
|
||||
if (deprecated.length() != 0) {
|
||||
rawTooltip += ": " + deprecated; //$NON-NLS-1$
|
||||
}
|
||||
if (deprecated.length() == 0 || !deprecated.endsWith(".")) { //$NON-NLS-1$
|
||||
rawTooltip += "."; //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
|
||||
// Add the known types to the tooltip
|
||||
Format[] formats_list = info.getFormats();
|
||||
@@ -154,11 +173,14 @@ public final class DescriptorsUtils {
|
||||
HashSet<Format> formats_set = new HashSet<Format>();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (tooltip != null) {
|
||||
sb.append(tooltip);
|
||||
sb.append(" "); //$NON-NLS-1$
|
||||
if (rawTooltip != null && rawTooltip.length() > 0) {
|
||||
sb.append(rawTooltip);
|
||||
sb.append(" "); //$NON-NLS-1$
|
||||
}
|
||||
sb.append("["); //$NON-NLS-1$
|
||||
if (sb.length() > 0) {
|
||||
sb.append("@@"); //$NON-NLS-1$ @@ inserts a break before the types
|
||||
}
|
||||
sb.append("["); //$NON-NLS-1$
|
||||
for (int i = 0; i < flen; i++) {
|
||||
Format f = formats_list[i];
|
||||
formats_set.add(f);
|
||||
@@ -172,19 +194,21 @@ public final class DescriptorsUtils {
|
||||
sb.append("]"); //$NON-NLS-1$
|
||||
|
||||
if (required) {
|
||||
sb.append(". Required.");
|
||||
sb.append(".@@* "); //$NON-NLS-1$ @@ inserts a break.
|
||||
sb.append("Required.");
|
||||
}
|
||||
|
||||
// The extra space at the end makes the tooltip more readable on Windows.
|
||||
sb.append(" "); //$NON-NLS-1$
|
||||
|
||||
tooltip = sb.toString();
|
||||
rawTooltip = sb.toString();
|
||||
tooltip = formatTooltip(rawTooltip);
|
||||
|
||||
// Create a specialized attribute if we can
|
||||
if (overrides != null) {
|
||||
for (Entry<String, Object> entry: overrides.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String elements[] = key.split("/");
|
||||
String elements[] = key.split("/"); //$NON-NLS-1$
|
||||
String overrideAttrLocalName = null;
|
||||
if (elements.length < 1) {
|
||||
continue;
|
||||
@@ -193,7 +217,7 @@ public final class DescriptorsUtils {
|
||||
elements = null;
|
||||
} else {
|
||||
overrideAttrLocalName = elements[elements.length - 1];
|
||||
elements = elements[0].split(",");
|
||||
elements = elements[0].split(","); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
if (overrideAttrLocalName == null ||
|
||||
@@ -204,7 +228,8 @@ public final class DescriptorsUtils {
|
||||
boolean ok_element = elements.length < 1;
|
||||
if (!ok_element) {
|
||||
for (String element : elements) {
|
||||
if (element.equals("*") || element.equals(elementXmlName)) {
|
||||
if (element.equals("*") //$NON-NLS-1$
|
||||
|| element.equals(elementXmlName)) {
|
||||
ok_element = true;
|
||||
break;
|
||||
}
|
||||
@@ -271,8 +296,12 @@ public final class DescriptorsUtils {
|
||||
|
||||
// By default a simple text field is used
|
||||
if (attr == null) {
|
||||
if (tooltip == null) {
|
||||
tooltip = formatTooltip(rawTooltip);
|
||||
}
|
||||
attr = new TextAttributeDescriptor(xmlLocalName, uiName, nsUri, tooltip);
|
||||
}
|
||||
attr.setDeprecated(info.getDeprecatedDoc() != null);
|
||||
attributes.add(attr);
|
||||
}
|
||||
|
||||
@@ -582,6 +611,8 @@ public final class DescriptorsUtils {
|
||||
Pattern p_code = Pattern.compile("<code>(.+?)</code>(.*)"); //$NON-NLS-1$
|
||||
// Detects @blah@, used in hard-coded tooltip descriptors
|
||||
Pattern p_elem = Pattern.compile("@([\\w -]+)@(.*)"); //$NON-NLS-1$
|
||||
// Detects a buffer that starts by @@ (request for a break)
|
||||
Pattern p_break = Pattern.compile("@@(.*)"); //$NON-NLS-1$
|
||||
// Detects a buffer that starts by @ < or { (one that was not matched above)
|
||||
Pattern p_open = Pattern.compile("([@<\\{])(.*)"); //$NON-NLS-1$
|
||||
// Detects everything till the next potential separator, i.e. @ < or {
|
||||
@@ -616,6 +647,10 @@ public final class DescriptorsUtils {
|
||||
if (text != null) {
|
||||
currentLength += text.length() - 2;
|
||||
}
|
||||
} else if ((m = p_break.matcher(javadoc)).matches()) {
|
||||
spans.add(BREAK);
|
||||
currentLength = 0;
|
||||
javadoc = m.group(1);
|
||||
} else if ((m = p_open.matcher(javadoc)).matches()) {
|
||||
s = m.group(1);
|
||||
javadoc = m.group(2);
|
||||
|
||||
@@ -95,6 +95,10 @@ public class TextAttributeDescriptor extends AttributeDescriptor implements IPro
|
||||
}
|
||||
|
||||
public String getCategory() {
|
||||
if (isDeprecated()) {
|
||||
return "Deprecated";
|
||||
}
|
||||
|
||||
ElementDescriptor parent = getParent();
|
||||
if (parent != null) {
|
||||
return parent.getUiName();
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.android.layoutlib.api.IXmlPullParser;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
||||
@@ -178,7 +177,7 @@ public abstract class BasePullParser implements IXmlPullParser {
|
||||
return mParsingState;
|
||||
}
|
||||
|
||||
public int nextTag() throws XmlPullParserException, IOException {
|
||||
public int nextTag() throws XmlPullParserException {
|
||||
int eventType = next();
|
||||
if (eventType != START_TAG && eventType != END_TAG) {
|
||||
throw new XmlPullParserException("expected start or end tag", this, null);
|
||||
@@ -186,7 +185,7 @@ public abstract class BasePullParser implements IXmlPullParser {
|
||||
return eventType;
|
||||
}
|
||||
|
||||
public String nextText() throws XmlPullParserException, IOException {
|
||||
public String nextText() throws XmlPullParserException {
|
||||
if (getEventType() != START_TAG) {
|
||||
throw new XmlPullParserException("parser must be on START_TAG to read next text", this,
|
||||
null);
|
||||
@@ -208,7 +207,7 @@ public abstract class BasePullParser implements IXmlPullParser {
|
||||
}
|
||||
}
|
||||
|
||||
public int nextToken() throws XmlPullParserException, IOException {
|
||||
public int nextToken() throws XmlPullParserException {
|
||||
return next();
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +33,10 @@ import org.eclipse.core.runtime.IStatus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@@ -166,7 +168,13 @@ public final class AndroidManifestDescriptors implements IDescriptorProvider {
|
||||
"android", //$NON-NLS-1$
|
||||
AndroidConstants.NS_RESOURCES);
|
||||
|
||||
// -- setup the required attributes overrides --
|
||||
|
||||
Set<String> required = new HashSet<String>();
|
||||
required.add("provider/authorities"); //$NON-NLS-1$
|
||||
|
||||
// -- setup the various attribute format overrides --
|
||||
|
||||
// The key for each override is "element1,element2,.../attr-xml-local-name" or
|
||||
// "*/attr-xml-local-name" to match the attribute in any element.
|
||||
|
||||
@@ -181,7 +189,7 @@ public final class AndroidManifestDescriptors implements IDescriptorProvider {
|
||||
tooltip);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
overrides.put("*/theme", ThemeAttributeDescriptor.class); //$NON-NLS-1$
|
||||
overrides.put("*/permission", ListAttributeDescriptor.class); //$NON-NLS-1$
|
||||
overrides.put("*/targetPackage", PackageAttributeDescriptor.class); //$NON-NLS-1$
|
||||
@@ -212,8 +220,12 @@ public final class AndroidManifestDescriptors implements IDescriptorProvider {
|
||||
|
||||
// --
|
||||
|
||||
inflateElement(manifestMap, overrides, elementDescs,
|
||||
MANIFEST_ELEMENT, "AndroidManifest"); //$NON-NLS-1$
|
||||
inflateElement(manifestMap,
|
||||
overrides,
|
||||
required,
|
||||
elementDescs,
|
||||
MANIFEST_ELEMENT,
|
||||
"AndroidManifest"); //$NON-NLS-1$
|
||||
insertAttribute(MANIFEST_ELEMENT, PACKAGE_ATTR_DESC);
|
||||
|
||||
sanityCheck(manifestMap, MANIFEST_ELEMENT);
|
||||
@@ -312,16 +324,17 @@ public final class AndroidManifestDescriptors implements IDescriptorProvider {
|
||||
* "Inflates" the properties of an {@link ElementDescriptor} from the styleable declaration.
|
||||
* <p/>
|
||||
* This first creates all the attributes for the given ElementDescriptor.
|
||||
* It then find all children of the descriptor, inflate them recursively and set them
|
||||
* It then finds all children of the descriptor, inflate them recursively and set them
|
||||
* as child to this ElementDescriptor.
|
||||
*
|
||||
* @param styleMap The input styleable map for manifest elements & attributes
|
||||
* @param styleMap The input styleable map for manifest elements & attributes.
|
||||
* @param overrides A list of attribute overrides (to customize the type of the attribute
|
||||
* descriptors)
|
||||
* descriptors).
|
||||
* @param requiredAttributes Set of attributes to be marked as required.
|
||||
* @param existingElementDescs A map of already created element descriptors, keyed by
|
||||
* XML local name. This is used to use the static elements created initially by this
|
||||
* class, which are referenced directly by editors (so that reloading an SDK won't
|
||||
* break these references)
|
||||
* break these references).
|
||||
* @param elemDesc The current {@link ElementDescriptor} to inflate.
|
||||
* @param styleName The name of the {@link ElementDescriptor} to inflate. Its XML local name
|
||||
* will be guessed automatically from the style name.
|
||||
@@ -329,6 +342,7 @@ public final class AndroidManifestDescriptors implements IDescriptorProvider {
|
||||
private void inflateElement(
|
||||
Map<String, DeclareStyleableInfo> styleMap,
|
||||
Map<String, Object> overrides,
|
||||
Set<String> requiredAttributes,
|
||||
HashMap<String, ElementDescriptor> existingElementDescs,
|
||||
ElementDescriptor elemDesc,
|
||||
String styleName) {
|
||||
@@ -342,7 +356,9 @@ public final class AndroidManifestDescriptors implements IDescriptorProvider {
|
||||
DescriptorsUtils.appendAttributes(attrDescs,
|
||||
elemDesc.getXmlLocalName(),
|
||||
AndroidConstants.NS_RESOURCES,
|
||||
style.getAttributes(), null, overrides);
|
||||
style.getAttributes(),
|
||||
requiredAttributes,
|
||||
overrides);
|
||||
elemDesc.setTooltip(style.getJavaDoc());
|
||||
elemDesc.setAttributes(attrDescs.toArray(new AttributeDescriptor[attrDescs.size()]));
|
||||
}
|
||||
@@ -373,7 +389,12 @@ public final class AndroidManifestDescriptors implements IDescriptorProvider {
|
||||
}
|
||||
children.add(child);
|
||||
|
||||
inflateElement(styleMap, overrides, existingElementDescs, child, childStyleName);
|
||||
inflateElement(styleMap,
|
||||
overrides,
|
||||
requiredAttributes,
|
||||
existingElementDescs,
|
||||
child,
|
||||
childStyleName);
|
||||
}
|
||||
}
|
||||
elemDesc.setChildren(children.toArray(new ElementDescriptor[children.size()]));
|
||||
|
||||
@@ -66,7 +66,7 @@ public final class CountryCodeQualifier extends ResourceQualifier {
|
||||
/**
|
||||
* Returns the folder name segment for the given value. This is equivalent to calling
|
||||
* {@link #toString()} on a {@link CountryCodeQualifier} object.
|
||||
* @param value the value of the qualifier, as returned by {@link #getCode()}.
|
||||
* @param code the value of the qualifier, as returned by {@link #getCode()}.
|
||||
*/
|
||||
public static String getFolderSegment(int code) {
|
||||
if (code != DEFAULT_CODE && code >= 100 && code <=999) { // code is 3 digit.) {
|
||||
|
||||
@@ -66,7 +66,7 @@ public final class NetworkCodeQualifier extends ResourceQualifier {
|
||||
/**
|
||||
* Returns the folder name segment for the given value. This is equivalent to calling
|
||||
* {@link #toString()} on a {@link NetworkCodeQualifier} object.
|
||||
* @param value the value of the qualifier, as returned by {@link #getCode()}.
|
||||
* @param code the value of the qualifier, as returned by {@link #getCode()}.
|
||||
*/
|
||||
public static String getFolderSegment(int code) {
|
||||
if (code != DEFAULT_CODE && code >= 1 && code <= 999) { // code is 1-3 digit.
|
||||
|
||||
@@ -39,7 +39,7 @@ public final class PixelDensityQualifier extends ResourceQualifier {
|
||||
/**
|
||||
* Creates and returns a qualifier from the given folder segment. If the segment is incorrect,
|
||||
* <code>null</code> is returned.
|
||||
* @param segment the folder segment from which to create a qualifier.
|
||||
* @param folderSegment the folder segment from which to create a qualifier.
|
||||
* @return a new {@link CountryCodeQualifier} object or <code>null</code>
|
||||
*/
|
||||
public static PixelDensityQualifier getQualifier(String folderSegment) {
|
||||
@@ -66,7 +66,7 @@ public final class PixelDensityQualifier extends ResourceQualifier {
|
||||
/**
|
||||
* Returns the folder name segment for the given value. This is equivalent to calling
|
||||
* {@link #toString()} on a {@link NetworkCodeQualifier} object.
|
||||
* @param value the value of the qualifier, as returned by {@link #getCode()}.
|
||||
* @param value the value of the qualifier, as returned by {@link #getValue()}.
|
||||
*/
|
||||
public static String getFolderSegment(int value) {
|
||||
if (value != DEFAULT_DENSITY) {
|
||||
|
||||
@@ -132,7 +132,7 @@ public final class MultiResourceFile extends ResourceFile implements IValueResou
|
||||
/**
|
||||
* Adds a resource item to the list
|
||||
* @param resType The type of the resource
|
||||
* @param name The name of the resource.
|
||||
* @param value The value of the resource.
|
||||
*/
|
||||
public void addResourceValue(String resType, ResourceValue value) {
|
||||
ResourceType type = ResourceType.getEnum(resType);
|
||||
|
||||
@@ -107,7 +107,6 @@ public final class ProjectClassLoader extends ClassLoader {
|
||||
* @param parent the root of the file.
|
||||
* @param segments the segments containing the path of the file
|
||||
* @param index the offset at which to start looking into segments.
|
||||
* @return
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
private File getFile(File parent, String[] segments, int index)
|
||||
@@ -168,8 +167,6 @@ public final class ProjectClassLoader extends ClassLoader {
|
||||
|
||||
/**
|
||||
* Loads a class from the 3rd party jar present in the project
|
||||
* @param name
|
||||
* @return
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
private Class<?> loadClassFromJar(String name) throws ClassNotFoundException {
|
||||
|
||||
@@ -393,8 +393,6 @@ public class ProjectResources implements IResourceRepository {
|
||||
|
||||
/**
|
||||
* Resolves a compiled resource id of type int[] into the resource name.
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public String resolveResourceValue(int[] id) {
|
||||
if (mStyleableValueToNameMap != null) {
|
||||
@@ -407,9 +405,6 @@ public class ProjectResources implements IResourceRepository {
|
||||
|
||||
/**
|
||||
* Returns the value of a resource by its type and name.
|
||||
* @param type
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
public Integer getResourceValue(String type, String name) {
|
||||
if (mResourceValueMap != null) {
|
||||
@@ -444,8 +439,7 @@ public class ProjectResources implements IResourceRepository {
|
||||
|
||||
/**
|
||||
* Returns the list of regions used in the resources with the given language.
|
||||
* @param currentLanguage the current language the region must be associated with
|
||||
* @return
|
||||
* @param currentLanguage the current language the region must be associated with.
|
||||
*/
|
||||
public Set<String> getRegions(String currentLanguage) {
|
||||
Set<String> set = new HashSet<String>();
|
||||
|
||||
@@ -185,7 +185,7 @@ public final class ResourceFolder extends Resource {
|
||||
|
||||
/**
|
||||
* Returns the {@link ResourceFile} matching a given name.
|
||||
* @param file The name of the file to return.
|
||||
* @param filename The name of the file to return.
|
||||
* @return the {@link ResourceFile} or <code>null</code> if no match was found.
|
||||
*/
|
||||
public ResourceFile getFile(String filename) {
|
||||
|
||||
@@ -16,21 +16,21 @@
|
||||
|
||||
package com.android.ide.eclipse.editors.resources.manager;
|
||||
|
||||
import com.android.ide.eclipse.common.AndroidConstants;
|
||||
import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
|
||||
/**
|
||||
* Enum representing a type of resource folder.
|
||||
*/
|
||||
public enum ResourceFolderType {
|
||||
ANIM(AndroidConstants.FD_ANIM),
|
||||
COLOR(AndroidConstants.FD_COLOR),
|
||||
DRAWABLE(AndroidConstants.FD_DRAWABLE),
|
||||
LAYOUT(AndroidConstants.FD_LAYOUT),
|
||||
MENU(AndroidConstants.FD_MENU),
|
||||
RAW(AndroidConstants.FD_RAW),
|
||||
VALUES(AndroidConstants.FD_VALUES),
|
||||
XML(AndroidConstants.FD_XML);
|
||||
ANIM(SdkConstants.FD_ANIM),
|
||||
COLOR(SdkConstants.FD_COLOR),
|
||||
DRAWABLE(SdkConstants.FD_DRAWABLE),
|
||||
LAYOUT(SdkConstants.FD_LAYOUT),
|
||||
MENU(SdkConstants.FD_MENU),
|
||||
RAW(SdkConstants.FD_RAW),
|
||||
VALUES(SdkConstants.FD_VALUES),
|
||||
XML(SdkConstants.FD_XML);
|
||||
|
||||
private final String mName;
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.android.ide.eclipse.editors.resources.manager.files.IAbstractFolder;
|
||||
import com.android.ide.eclipse.editors.resources.manager.files.IFileWrapper;
|
||||
import com.android.ide.eclipse.editors.resources.manager.files.IFolderWrapper;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
|
||||
import org.eclipse.core.resources.IContainer;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
@@ -269,8 +270,7 @@ public final class ResourceManager implements IProjectListener, IFolderListener,
|
||||
|
||||
/**
|
||||
* Loads and returns the resources for a given {@link IAndroidTarget}
|
||||
* @param osFilePath the path to the folder containing all the versions of the framework
|
||||
* resources
|
||||
* @param androidTarget the target from which to load the framework resources
|
||||
*/
|
||||
public ProjectResources loadFrameworkResources(IAndroidTarget androidTarget) {
|
||||
String osResourcesPath = androidTarget.getPath(IAndroidTarget.RESOURCES);
|
||||
@@ -329,7 +329,7 @@ public final class ResourceManager implements IProjectListener, IFolderListener,
|
||||
return;
|
||||
}
|
||||
|
||||
IFolder resourceFolder = project.getFolder(AndroidConstants.FD_RESOURCES);
|
||||
IFolder resourceFolder = project.getFolder(SdkConstants.FD_RESOURCES);
|
||||
|
||||
ProjectResources projectResources = mMap.get(project);
|
||||
if (projectResources == null) {
|
||||
@@ -478,7 +478,7 @@ public final class ResourceManager implements IProjectListener, IFolderListener,
|
||||
* @return true if the path is under /project res/
|
||||
*/
|
||||
private boolean isInResFolder(IPath path) {
|
||||
return AndroidConstants.FD_RESOURCES.equalsIgnoreCase(path.segment(1));
|
||||
return SdkConstants.FD_RESOURCES.equalsIgnoreCase(path.segment(1));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -115,8 +115,6 @@ public class SingleResourceFile extends ResourceFile {
|
||||
|
||||
/**
|
||||
* Returns the name of the resources.
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
private String getResourceName(ResourceType type) {
|
||||
// get the name from the filename.
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.android.ide.eclipse.editors.resources.manager.files;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@@ -45,7 +44,7 @@ public class FileWrapper implements IAbstractFile {
|
||||
mFile = file;
|
||||
}
|
||||
|
||||
public InputStream getContents() throws CoreException {
|
||||
public InputStream getContents() {
|
||||
try {
|
||||
return new FileInputStream(mFile);
|
||||
} catch (FileNotFoundException e) {
|
||||
@@ -74,7 +73,7 @@ public class FileWrapper implements IAbstractFile {
|
||||
}
|
||||
|
||||
if (obj instanceof File) {
|
||||
return mFile.equals((File)obj);
|
||||
return mFile.equals(obj);
|
||||
}
|
||||
|
||||
return super.equals(obj);
|
||||
|
||||
@@ -59,7 +59,7 @@ public class FolderWrapper implements IAbstractFolder {
|
||||
}
|
||||
|
||||
if (obj instanceof File) {
|
||||
return mFolder.equals((File)obj);
|
||||
return mFolder.equals(obj);
|
||||
}
|
||||
|
||||
return super.equals(obj);
|
||||
|
||||
@@ -55,7 +55,7 @@ public class IFileWrapper implements IAbstractFile {
|
||||
}
|
||||
|
||||
if (obj instanceof IFile) {
|
||||
return mFile.equals((IFile)obj);
|
||||
return mFile.equals(obj);
|
||||
}
|
||||
|
||||
return super.equals(obj);
|
||||
|
||||
@@ -61,7 +61,7 @@ public class IFolderWrapper implements IAbstractFolder {
|
||||
}
|
||||
|
||||
if (obj instanceof IFolder) {
|
||||
return mFolder.equals((IFolder)obj);
|
||||
return mFolder.equals(obj);
|
||||
}
|
||||
|
||||
return super.equals(obj);
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.android.ide.eclipse.editors.ui.tree;
|
||||
|
||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||
import com.android.ide.eclipse.common.AndroidConstants;
|
||||
import com.android.ide.eclipse.editors.descriptors.ElementDescriptor;
|
||||
import com.android.ide.eclipse.editors.layout.descriptors.ViewElementDescriptor;
|
||||
import com.android.ide.eclipse.editors.uimodel.UiElementNode;
|
||||
|
||||
@@ -79,8 +79,7 @@ import java.util.HashMap;
|
||||
* To use this, instantiate somewhere in the UI and then:
|
||||
* <ul>
|
||||
* <li>Use {@link #setConfiguration(String)} or {@link #setConfiguration(FolderConfiguration)}.
|
||||
* <li>Retrieve the configuration using {@link #getConfiguration(FolderConfiguration)} and
|
||||
* test it using {@link FolderConfiguration#isValid()}.
|
||||
* <li>Retrieve the configuration using {@link #getConfiguration(FolderConfiguration)}.
|
||||
* </ul>
|
||||
*/
|
||||
public class ConfigurationSelector extends Composite {
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.android.ide.eclipse.editors.resources.descriptors.ResourcesDescriptor
|
||||
import com.android.ide.eclipse.editors.resources.manager.ResourceFolderType;
|
||||
import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.ConfigurationState;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
@@ -243,7 +244,7 @@ class NewXmlFileCreationPage extends WizardPage {
|
||||
/** Absolute destination folder root, e.g. "/res/" */
|
||||
private static String sResFolderAbs = AndroidConstants.WS_RESOURCES + AndroidConstants.WS_SEP;
|
||||
/** Relative destination folder root, e.g. "res/" */
|
||||
private static String sResFolderRel = AndroidConstants.FD_RESOURCES + AndroidConstants.WS_SEP;
|
||||
private static String sResFolderRel = SdkConstants.FD_RESOURCES + AndroidConstants.WS_SEP;
|
||||
|
||||
private IProject mProject;
|
||||
private Text mProjectTextField;
|
||||
@@ -629,7 +630,7 @@ class NewXmlFileCreationPage extends WizardPage {
|
||||
// Disregard this folder selection if it doesn't point to /res/something
|
||||
if (wsFolderPath != null &&
|
||||
wsFolderPath.segmentCount() > 1 &&
|
||||
AndroidConstants.FD_RESOURCES.equals(wsFolderPath.segment(0))) {
|
||||
SdkConstants.FD_RESOURCES.equals(wsFolderPath.segment(0))) {
|
||||
score += 2;
|
||||
} else {
|
||||
wsFolderPath = null;
|
||||
@@ -1002,7 +1003,7 @@ class NewXmlFileCreationPage extends WizardPage {
|
||||
String fileName = getFileName();
|
||||
if (fileName == null || fileName.length() == 0) {
|
||||
error = "A destination file name is required.";
|
||||
} else if (fileName != null && !fileName.endsWith(AndroidConstants.DOT_XML)) {
|
||||
} else if (!fileName.endsWith(AndroidConstants.DOT_XML)) {
|
||||
error = String.format("The filename must end with %1$s.", AndroidConstants.DOT_XML);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package com.android.ide.eclipse.editors.wizards;
|
||||
|
||||
import com.android.ide.eclipse.adt.AdtPlugin;
|
||||
import com.android.ide.eclipse.common.AndroidConstants;
|
||||
import com.android.ide.eclipse.common.resources.IResourceRepository;
|
||||
import com.android.ide.eclipse.common.resources.ResourceItem;
|
||||
import com.android.ide.eclipse.common.resources.ResourceType;
|
||||
|
||||
@@ -6,4 +6,5 @@
|
||||
<application android:icon="@drawable/icon" android:label="APPLICATION_NAME">
|
||||
ACTIVITIES
|
||||
</application>
|
||||
USES-SDK
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<uses-sdk android:minSdkVersion="MIN_SDK_VERSION" />
|
||||
Reference in New Issue
Block a user