diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-01-09 17:51:19 -0800 | 
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-01-09 17:51:19 -0800 | 
| commit | a1514dae8668c48feae5436285e3db0ba2133ec3 (patch) | |
| tree | 115c685f5c4c810cd317e8a6903e8d2d96749051 /eclipse | |
| parent | 9ca1c0b33cc3fc28c21a915730797ec01e71a152 (diff) | |
| download | sdk-a1514dae8668c48feae5436285e3db0ba2133ec3.zip sdk-a1514dae8668c48feae5436285e3db0ba2133ec3.tar.gz sdk-a1514dae8668c48feae5436285e3db0ba2133ec3.tar.bz2 | |
auto import from //branches/cupcake/...@125939
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 | 
