diff options
Diffstat (limited to 'eclipse')
71 files changed, 1175 insertions, 542 deletions
diff --git a/eclipse/features/com.android.ide.eclipse.adt/feature.xml b/eclipse/features/com.android.ide.eclipse.adt/feature.xml index 191b76d..676a89e 100644 --- a/eclipse/features/com.android.ide.eclipse.adt/feature.xml +++ b/eclipse/features/com.android.ide.eclipse.adt/feature.xml @@ -40,6 +40,13 @@ <import plugin="org.eclipse.ui"/> <import plugin="org.eclipse.ui.ide"/> <import plugin="org.eclipse.ui.forms"/> + <import plugin="org.eclipse.gef"/> + <import plugin="org.eclipse.ui.browser"/> + <import plugin="org.eclipse.ui.views"/> + <import plugin="org.eclipse.wst.sse.core"/> + <import plugin="org.eclipse.wst.sse.ui"/> + <import plugin="org.eclipse.wst.xml.core"/> + <import plugin="org.eclipse.wst.xml.ui"/> </requires> <plugin diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java index 61b3f4d..7304e5e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java @@ -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. */ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java index d9c18cf..62bc7ed 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java @@ -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()); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java index 4d16120..e38419a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java @@ -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. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java index 47ef626..aec703d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkDeltaVisitor.java @@ -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) diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/BaseBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/BaseBuilder.java index f94bdc7..534c123 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/BaseBuilder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/BaseBuilder.java @@ -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); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java index 1a4aa8c..9fc4348 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java @@ -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) diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerDeltaVisitor.java index 33d5fa6..f4778d7 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerDeltaVisitor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerDeltaVisitor.java @@ -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. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java index 48ec7c3..2b7d01d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/AndroidLaunchController.java @@ -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 diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java index 2cb11c3..19ec9a7 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/DeviceChooserDialog.java @@ -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); + if (device.isEmulator()) { + return device.getVmName(); + } else { + return "N/A"; // devices don't have VM names. + } case 2: - String debuggable = device.getProperty(Device.PROP_DEBUGGABLE); - String version = device.getProperty(Device.PROP_BUILD_VERSION); + 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 String.format("%1$s (debug)", version); //$NON-NLS-1$ + return "Yes"; } else { - return String.format("%1$s", version); //$NON-NLS-1$ + 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) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/LaunchConfigDelegate.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/LaunchConfigDelegate.java index 5d3e349..68deec3 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/LaunchConfigDelegate.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/launching/LaunchConfigDelegate.java @@ -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 = ""; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/EmulatorConfigTab.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/EmulatorConfigTab.java index c7b340c..f4f5281 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/EmulatorConfigTab.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/EmulatorConfigTab.java @@ -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; - } - } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/MainLaunchConfigTab.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/MainLaunchConfigTab.java index af7f2bb..6a40ed0 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/MainLaunchConfigTab.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/debug/ui/MainLaunchConfigTab.java @@ -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) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/BuildPreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/BuildPreferencePage.java index 434269c..e64c2f4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/BuildPreferencePage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/BuildPreferencePage.java @@ -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); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/FolderDecorator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/FolderDecorator.java index 1ca89cd..7fc3318 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/FolderDecorator.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/FolderDecorator.java @@ -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]"); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/ExportWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/ExportWizard.java index de4b339..399eac9 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/ExportWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/ExportWizard.java @@ -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; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/ProjectCheckPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/ProjectCheckPage.java index 3614be3..e161e18 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/ProjectCheckPage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/export/ProjectCheckPage.java @@ -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); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java index 2cafa01..4da216c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java @@ -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; } - - // log the error and put the marker on the project - if (outputToConsole) { - AdtPlugin.printBuildToConsole(AdtConstants.BUILD_ALWAYS, iProject, message); - } - 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."); + 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(); + } + + return Status.OK_STATUS; + } + }; + + // build jobs are run after other interactive jobs + markerJob.setPriority(Job.BUILD); + markerJob.schedule(); + } } - + // return a dummy container to replace the one we may have had before. return new IClasspathContainer() { public IClasspathEntry[] getClasspathEntries() { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidJarLoader.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidJarLoader.java index fad4f19..1f6ebf1 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidJarLoader.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidJarLoader.java @@ -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 */ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java index 232b9e8..dfe876f 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java @@ -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. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/IAndroidClassLoader.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/IAndroidClassLoader.java index 50d319e..35057d1 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/IAndroidClassLoader.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/IAndroidClassLoader.java @@ -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 */ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java index 3b9d10e..19f8f45 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java @@ -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"); @@ -106,6 +120,13 @@ public class Sdk { } /** + * 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() + diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/WidgetClassLoader.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/WidgetClassLoader.java index 8db09f2..0e60f8a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/WidgetClassLoader.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/WidgetClassLoader.java @@ -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 */ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java index 8044bcb..7fc94ef 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java @@ -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()); } @@ -665,6 +722,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 * entered before. @@ -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; + } - if (packageName != null && packageName.length() > 0) { - mPackageNameField.setText(packageName); - } + 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 (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 (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; - } - - } + + 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 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; + } + + // 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; + } } /** @@ -805,6 +930,9 @@ public class NewProjectCreationPage extends WizardPage { status |= validateActivityField(); } if ((status & MSG_ERROR) == 0) { + status |= validateMinSdkVersionField(); + } + if ((status & MSG_ERROR) == 0) { status |= validateSourceFolder(); } if (status == MSG_NONE) { @@ -950,6 +1078,38 @@ public class NewProjectCreationPage extends WizardPage { } /** + * 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. * * @return The wizard message type, one of MSG_ERROR, MSG_WARNING or MSG_NONE. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectWizard.java index a582217..607159a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectWizard.java @@ -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( diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java index f3f7b79..0e780a9 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java @@ -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$ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestHelper.java index 2db9e9b..cd238d2 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestHelper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestHelper.java @@ -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) { @@ -111,17 +111,39 @@ public class AndroidManifestHelper { } /** + * 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); - } - } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java index cb98525..2866ce2 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java @@ -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 */, diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidXPathFactory.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidXPathFactory.java index 530c89e..8544b25 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidXPathFactory.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidXPathFactory.java @@ -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(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/BaseProjectHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/BaseProjectHelper.java index c69e875..bd8b444 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/BaseProjectHelper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/BaseProjectHelper.java @@ -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/> diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java index 26fbf42..fda55c4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java @@ -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 { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/AttrsXmlParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/AttrsXmlParser.java index 3176c8e..3875e81 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/AttrsXmlParser.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/AttrsXmlParser.java @@ -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(); + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/DeclareStyleableInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/DeclareStyleableInfo.java index 6cff62c..efa5981 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/DeclareStyleableInfo.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/resources/DeclareStyleableInfo.java @@ -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; + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java index d1b4547..50d3d28 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java @@ -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) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidEditor.java index 78e0401..dca7db0 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidEditor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidEditor.java @@ -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(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptor.java index 2c779b2..70d03a1 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptor.java @@ -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/> diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptorLabelProvider.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptorLabelProvider.java index 05ae922..2729565 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptorLabelProvider.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/AttributeDescriptorLabelProvider.java @@ -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; } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java index c84bf57..09f1478 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java @@ -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); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/TextAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/TextAttributeDescriptor.java index 632471d..a9d2b2e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/TextAttributeDescriptor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/TextAttributeDescriptor.java @@ -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(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/BasePullParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/BasePullParser.java index c512625..381539b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/BasePullParser.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/BasePullParser.java @@ -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(); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java index 87a14ad..a0b30ec 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java @@ -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()])); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/CountryCodeQualifier.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/CountryCodeQualifier.java index 1d01260..9a61d17 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/CountryCodeQualifier.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/CountryCodeQualifier.java @@ -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.) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/NetworkCodeQualifier.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/NetworkCodeQualifier.java index ce527a4..7e30901 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/NetworkCodeQualifier.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/NetworkCodeQualifier.java @@ -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. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/PixelDensityQualifier.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/PixelDensityQualifier.java index 0fd05bf..c47bb83 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/PixelDensityQualifier.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/configurations/PixelDensityQualifier.java @@ -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) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/MultiResourceFile.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/MultiResourceFile.java index 72438a6..3812791 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/MultiResourceFile.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/MultiResourceFile.java @@ -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); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectClassLoader.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectClassLoader.java index 183af27..8b6c3c1 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectClassLoader.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectClassLoader.java @@ -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 { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectResources.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectResources.java index b0881fa..40e4e3b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectResources.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ProjectResources.java @@ -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>(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFolder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFolder.java index 6db0d94..98f5b39 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFolder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFolder.java @@ -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) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFolderType.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFolderType.java index bd93301..5fc7393 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFolderType.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceFolderType.java @@ -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; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceManager.java index 9c5f0fc..6099008 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceManager.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/ResourceManager.java @@ -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)); } /** diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/SingleResourceFile.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/SingleResourceFile.java index 1211236..32b1107 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/SingleResourceFile.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/SingleResourceFile.java @@ -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. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/FileWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/FileWrapper.java index 0a14214..d99cb13 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/FileWrapper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/FileWrapper.java @@ -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); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/FolderWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/FolderWrapper.java index 8afea33..9ad7460 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/FolderWrapper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/FolderWrapper.java @@ -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); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IFileWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IFileWrapper.java index 441c65b..f0f5f2d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IFileWrapper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IFileWrapper.java @@ -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); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IFolderWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IFolderWrapper.java index 92b5c07..b1fa3ef 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IFolderWrapper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/files/IFolderWrapper.java @@ -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); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/NewItemSelectionDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/NewItemSelectionDialog.java index 772fb52..0729881 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/NewItemSelectionDialog.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/NewItemSelectionDialog.java @@ -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; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ConfigurationSelector.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ConfigurationSelector.java index b7dffdd..4a05b1e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ConfigurationSelector.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ConfigurationSelector.java @@ -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 { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java index b27dd4f..cc643be 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java @@ -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); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ReferenceChooserDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ReferenceChooserDialog.java index d3ff334..6913ce0 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ReferenceChooserDialog.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ReferenceChooserDialog.java @@ -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; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/templates/AndroidManifest.template b/eclipse/plugins/com.android.ide.eclipse.adt/templates/AndroidManifest.template index b4faae6..b43e75f 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/templates/AndroidManifest.template +++ b/eclipse/plugins/com.android.ide.eclipse.adt/templates/AndroidManifest.template @@ -6,4 +6,5 @@ <application android:icon="@drawable/icon" android:label="APPLICATION_NAME"> ACTIVITIES </application> +USES-SDK </manifest> diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/templates/uses-sdk.template b/eclipse/plugins/com.android.ide.eclipse.adt/templates/uses-sdk.template new file mode 100644 index 0000000..8adae71 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/templates/uses-sdk.template @@ -0,0 +1 @@ + <uses-sdk android:minSdkVersion="MIN_SDK_VERSION" /> diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/jar/example/Class1.java b/eclipse/plugins/com.android.ide.eclipse.tests/not_source_folder/jar/example/Class1.java index 3cf1027..3cf1027 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/jar/example/Class1.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/not_source_folder/jar/example/Class1.java diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/jar/example/Class2.java b/eclipse/plugins/com.android.ide.eclipse.tests/not_source_folder/jar/example/Class2.java index 4d15c47..4d15c47 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/jar/example/Class2.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/not_source_folder/jar/example/Class2.java diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/project/ProjectHelperTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/project/ProjectHelperTest.java index 4700821..5a89d01 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/project/ProjectHelperTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/project/ProjectHelperTest.java @@ -60,8 +60,9 @@ public class ProjectHelperTest extends TestCase { ProjectHelper.fixProjectClasspathEntries(javaProject); IClasspathEntry[] fixedEntries = javaProject.getRawClasspath(); - assertEquals(2, fixedEntries.length); + assertEquals(3, fixedEntries.length); assertEquals("Project/src", fixedEntries[0].getPath().toString()); - assertEquals(CONTAINER_ID, fixedEntries[1].getPath().toString()); + assertEquals(OLD_CONTAINER_ID, fixedEntries[1].getPath().toString()); + assertEquals(CONTAINER_ID, fixedEntries[2].getPath().toString()); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/sdk/AndroidJarLoaderTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/sdk/AndroidJarLoaderTest.java index f3d9b79..872938b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/sdk/AndroidJarLoaderTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/adt/sdk/AndroidJarLoaderTest.java @@ -45,6 +45,8 @@ public class AndroidJarLoaderTest extends TestCase { @Override public void tearDown() throws Exception { + mFrameworkClassLoader = null; + System.gc(); } /** Preloads classes. They should load just fine. */ @@ -74,8 +76,9 @@ public class AndroidJarLoaderTest extends TestCase { Class<?> c = _findClass(mFrameworkClassLoader, "jar.example.Class2"); //$NON-NLS-1$ assertEquals("jar.example.Class2", c.getName()); //$NON-NLS-1$ HashMap<String, Class<?>> map = getPrivateClassCache(); + assertTrue(map.containsKey("jar.example.Class1")); //$NON-NLS-1$ assertTrue(map.containsKey("jar.example.Class2")); //$NON-NLS-1$ - assertEquals(1, map.size()); + assertEquals(2, map.size()); } /** call the protected method findClass */ diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/resources/AttrsXmlParserTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/resources/AttrsXmlParserTest.java index 76ebfc3..8338453 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/resources/AttrsXmlParserTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/resources/AttrsXmlParserTest.java @@ -94,6 +94,33 @@ public class AttrsXmlParserTest extends TestCase { assertEquals(Integer.valueOf(0), valueMap.get("horizontal")); assertEquals(Integer.valueOf(1), valueMap.get("vertical")); } + + public final void testDeprecated() throws Exception { + mParser.preload(); + + DeclareStyleableInfo dep = mParser.getDeclareStyleableList().get("DeprecatedTest"); + assertNotNull(dep); + + AttributeInfo[] attrs = dep.getAttributes(); + assertEquals(4, attrs.length); + + assertEquals("deprecated-inline", attrs[0].getName()); + assertEquals("In-line deprecated.", attrs[0].getDeprecatedDoc()); + assertEquals("Deprecated comments using delimiters.", attrs[0].getJavaDoc()); + + assertEquals("deprecated-multiline", attrs[1].getName()); + assertEquals("Multi-line version of deprecated that works till the next tag.", + attrs[1].getDeprecatedDoc()); + assertEquals("Deprecated comments on their own line.", attrs[1].getJavaDoc()); + + assertEquals("deprecated-not", attrs[2].getName()); + assertEquals(null, attrs[2].getDeprecatedDoc()); + assertEquals("This attribute is not deprecated.", attrs[2].getJavaDoc()); + + assertEquals("deprecated-no-javadoc", attrs[3].getName()); + assertEquals("There is no other javadoc here.", attrs[3].getDeprecatedDoc()); + assertEquals("", attrs[3].getJavaDoc()); + } //---- access to private methods diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/descriptors/DescriptorsUtilsTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/descriptors/DescriptorsUtilsTest.java index 5506459..69c3ed8 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/descriptors/DescriptorsUtilsTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/descriptors/DescriptorsUtilsTest.java @@ -99,28 +99,26 @@ public class DescriptorsUtilsTest extends TestCase { ElementDescriptor desc = new ElementDescriptor("application"); desc.setSdkUrl(DescriptorsUtils.MANIFEST_SDK_URL + "TagApplication"); String docBaseUrl = "http://base"; - assertEquals("<form><p></p></form>", DescriptorsUtils.formatFormText("", desc, docBaseUrl)); + assertEquals("<form><li style=\"image\" value=\"image\"></li></form>", DescriptorsUtils.formatFormText("", desc, docBaseUrl)); - assertEquals("<form><p><a href=\"http://base/reference/android/R.styleable.html#TagApplication\">application</a></p></form>", + assertEquals("<form><li style=\"image\" value=\"image\"><a href=\"http://base/reference/android/R.styleable.html#TagApplication\">application</a></li></form>", DescriptorsUtils.formatFormText( "<code>application</code>", desc, docBaseUrl)); - assertEquals("<form><p><b>android.content.Intent</b></p></form>", + assertEquals("<form><li style=\"image\" value=\"image\"><b>android.content.Intent</b></li></form>", DescriptorsUtils.formatFormText( "{@link android.content.Intent}", desc, docBaseUrl)); - assertEquals("<form><p><a href=\"http://base/reference/android/R.styleable.html#AndroidManifestPermission\">AndroidManifestPermission</a></p></form>", + assertEquals("<form><li style=\"image\" value=\"image\"><a href=\"http://base/reference/android/R.styleable.html#AndroidManifestPermission\">AndroidManifestPermission</a></li></form>", DescriptorsUtils.formatFormText( "{@link #AndroidManifestPermission}", desc, docBaseUrl)); - assertEquals("<form><p><a href=\"http://base/reference/android/R.styleable.html#AndroidManifestPermission\">\"permission\"</a></p></form>", + assertEquals("<form><li style=\"image\" value=\"image\"><a href=\"http://base/reference/android/R.styleable.html#AndroidManifestPermission\">\"permission\"</a></li></form>", DescriptorsUtils.formatFormText( "{@link #AndroidManifestPermission <permission>}", desc, docBaseUrl)); - } - } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/resources/configurations/TextInputMethodQualifierTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/resources/configurations/TextInputMethodQualifierTest.java index 9e01081..28f7871 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/resources/configurations/TextInputMethodQualifierTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/resources/configurations/TextInputMethodQualifierTest.java @@ -54,11 +54,11 @@ public class TextInputMethodQualifierTest extends TestCase { } public void testNoKey() { - assertEquals(true, timq.checkAndSet("nokey", config)); //$NON-NLS-1$ + assertEquals(true, timq.checkAndSet("nokeys", config)); //$NON-NLS-1$ assertTrue(config.getTextInputMethodQualifier() != null); assertEquals(TextInputMethodQualifier.TextInputMethod.NOKEY, config.getTextInputMethodQualifier().getValue()); - assertEquals("nokey", config.getTextInputMethodQualifier().toString()); //$NON-NLS-1$ + assertEquals("nokeys", config.getTextInputMethodQualifier().toString()); //$NON-NLS-1$ } public void testFailures() { diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/resources/manager/ConfigMatchTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/resources/manager/ConfigMatchTest.java index 0c1a508..25a86c3 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/resources/manager/ConfigMatchTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/editors/resources/manager/ConfigMatchTest.java @@ -41,7 +41,7 @@ public class ConfigMatchTest extends TestCase { private static final String MISC2_FILENAME = "bar.xml"; //$NON-NLS-1$ private ProjectResources mResources; - private ArrayList<ResourceQualifier> mQualifierList; + private ResourceQualifier[] mQualifierList; private FolderConfiguration config4; private FolderConfiguration config3; private FolderConfiguration config2; @@ -60,7 +60,7 @@ public class ConfigMatchTest extends TestCase { qualifierListField.setAccessible(true); // get the actual list. - mQualifierList = (ArrayList<ResourceQualifier>)qualifierListField.get(manager); + mQualifierList = (ResourceQualifier[])qualifierListField.get(manager); // create the project resources. mResources = new ProjectResources(false /* isFrameworkRepository */); @@ -191,10 +191,10 @@ public class ConfigMatchTest extends TestCase { FolderConfiguration config = new FolderConfiguration(); // those must be of the same length - assertEquals(qualifierValues.length, mQualifierList.size()); + assertEquals(qualifierValues.length, mQualifierList.length); int index = 0; - + for (ResourceQualifier qualifier : mQualifierList) { String value = qualifierValues[index++]; if (value != null) { diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/data/mock_attrs.xml b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/data/mock_attrs.xml index e51604c..aa9a1f7 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/data/mock_attrs.xml +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/data/mock_attrs.xml @@ -18,7 +18,7 @@ --> <resources> <!-- WARNING !!! THIS IS A MOCK FILE. DO NOT USE FOR DOCUMENTATION PURPOSES. - This file has been trimmed down to only extract a number of interest cases + This file has been trimmed down to only extract a number of interesting cases for unit tests. What this contains: @@ -314,5 +314,27 @@ <attr name="collapseColumns" format="string" /> </declare-styleable> + <!-- Test for deprecated attributes. --> + <declare-styleable name="DeprecatedTest"> + <!-- Deprecated comments using delimiters. + Ignored. {@deprecated In-line deprecated.} {@ignore Ignored}. + --> + <attr name="deprecated-inline" /> + + <!-- Deprecated comments on their own line. + @deprecated Multi-line version of deprecated + that works till the next tag. + @ignore This tag must be ignored + --> + <attr name="deprecated-multiline" /> + + <!-- This attribute is not deprecated. --> + <attr name="deprecated-not" /> + + <!-- {@deprecated There is no other javadoc here. } --> + <attr name="deprecated-no-javadoc" format="boolean" /> + + </declare-styleable> + </resources> diff --git a/eclipse/scripts/create_test_symlinks.sh b/eclipse/scripts/create_test_symlinks.sh index 1479e04..931dce8 100755 --- a/eclipse/scripts/create_test_symlinks.sh +++ b/eclipse/scripts/create_test_symlinks.sh @@ -11,32 +11,38 @@ function back() { echo $1 | sed 's@[^/]*@..@g' } +HOST=`uname` +if [ "${HOST:0:6}" == "CYGWIN" ]; then + # We can't use symlinks under Cygwin + function cpdir() { # $1=dest $2=source + rsync -avW --delete-after $2 $1 + } + +else + # For all other systems which support symlinks + function cpdir() { # $1=dest $2=source + ln -svf `back $1`/$2 $1 + } +fi + BASE="development/tools/eclipse/plugins/com.android.ide.eclipse.tests" DEST=$BASE BACK=`back $DEST` - HOST=`uname` if [ "$HOST" == "Linux" ]; then - DIR="ln -svf" ln -svf $BACK/out/host/linux-x86/framework/kxml2-2.3.0.jar "$DEST/" elif [ "$HOST" == "Darwin" ]; then - DIR="ln -svf" ln -svf $BACK/out/host/darwin-x86/framework/kxml2-2.3.0.jar "$DEST/" elif [ "${HOST:0:6}" == "CYGWIN" ]; then - DIR="rsync -avW --delete-after" - JAR="kxml2-2.3.0.jar" - if [ ! -f "$DEST/$JAR" ]; then - # Get the jar from ADT if we can, otherwise download it. - if [ -f "$DEST/../com.android.ide.eclipse.adt/$JAR" ]; then - cp "$DEST/../com.android.ide.eclipse.adt/$JAR" "$DEST/$JAR" - else - wget -O "$DEST/$JAR" "http://internap.dl.sourceforge.net/sourceforge/kxml/$JAR" - fi - chmod a+rx "$DEST/$JAR" + + if [ ! -f "$DEST/kxml2-2.3.0.jar" ]; then + cp -v "prebuilt/common/kxml2/kxml2-2.3.0.jar" "$DEST/" + chmod -v a+rx "$DEST"/*.jar fi + else echo "Unsupported platform ($HOST). Nothing done." fi @@ -44,5 +50,5 @@ fi # create link to ddmlib tests DEST=$BASE/unittests/com/android BACK=`back $DEST` -$DIR $BACK/development/tools/ddms/libs/ddmlib/tests/src/com/android/ddmlib $DEST/ +cpdir $DEST development/tools/ddms/libs/ddmlib/tests/src/com/android/ddmlib |