aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java1620
1 files changed, 0 insertions, 1620 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
deleted file mode 100644
index 7ff06fc40..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
+++ /dev/null
@@ -1,1620 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Eclipse Public License, Version 1.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.eclipse.org/org/documents/epl-v10.php
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.ide.eclipse.adt.internal.sdk;
-
-import static com.android.SdkConstants.DOT_XML;
-import static com.android.SdkConstants.EXT_JAR;
-import static com.android.SdkConstants.FD_RES;
-
-import com.android.SdkConstants;
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.ddmlib.IDevice;
-import com.android.ide.common.rendering.LayoutLibrary;
-import com.android.ide.common.sdk.LoadStatus;
-import com.android.ide.eclipse.adt.AdtConstants;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.internal.build.DexWrapper;
-import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor;
-import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
-import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
-import com.android.ide.eclipse.adt.internal.project.LibraryClasspathContainerInitializer;
-import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
-import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor;
-import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IFileListener;
-import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IProjectListener;
-import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IResourceEventListener;
-import com.android.ide.eclipse.adt.internal.sdk.ProjectState.LibraryDifference;
-import com.android.ide.eclipse.adt.internal.sdk.ProjectState.LibraryState;
-import com.android.io.StreamException;
-import com.android.prefs.AndroidLocation.AndroidLocationException;
-import com.android.sdklib.AndroidVersion;
-import com.android.sdklib.BuildToolInfo;
-import com.android.sdklib.IAndroidTarget;
-import com.android.sdklib.SdkManager;
-import com.android.sdklib.devices.DeviceManager;
-import com.android.sdklib.internal.avd.AvdManager;
-import com.android.sdklib.internal.project.ProjectProperties;
-import com.android.sdklib.internal.project.ProjectProperties.PropertyType;
-import com.android.sdklib.internal.project.ProjectPropertiesWorkingCopy;
-import com.android.sdklib.repository.FullRevision;
-import com.android.utils.ILogger;
-import com.google.common.collect.Maps;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IFolder;
-import org.eclipse.core.resources.IMarker;
-import org.eclipse.core.resources.IMarkerDelta;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IResourceDelta;
-import org.eclipse.core.resources.IncrementalProjectBuilder;
-import org.eclipse.core.resources.ResourcesPlugin;
-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.QualifiedName;
-import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.jobs.Job;
-import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.ui.IEditorDescriptor;
-import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IEditorReference;
-import org.eclipse.ui.IFileEditorInput;
-import org.eclipse.ui.IWorkbenchPage;
-import org.eclipse.ui.IWorkbenchPartSite;
-import org.eclipse.ui.IWorkbenchWindow;
-import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.ide.IDE;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Central point to load, manipulate and deal with the Android SDK. Only one SDK can be used
- * at the same time.
- *
- * To start using an SDK, call {@link #loadSdk(String)} which returns the instance of
- * the Sdk object.
- *
- * To get the list of platforms or add-ons present in the SDK, call {@link #getTargets()}.
- */
-public final class Sdk {
- private final static boolean DEBUG = false;
-
- private final static Object LOCK = new Object();
-
- private static Sdk sCurrentSdk = null;
-
- /**
- * Map associating {@link IProject} and their state {@link ProjectState}.
- * <p/>This <b>MUST NOT</b> be accessed directly. Instead use {@link #getProjectState(IProject)}.
- */
- private final static HashMap<IProject, ProjectState> sProjectStateMap =
- new HashMap<IProject, ProjectState>();
-
- /**
- * Data bundled using during the load of Target data.
- * <p/>This contains the {@link LoadStatus} and a list of projects that attempted
- * to compile before the loading was finished. Those projects will be recompiled
- * at the end of the loading.
- */
- private final static class TargetLoadBundle {
- LoadStatus status;
- final HashSet<IJavaProject> projectsToReload = new HashSet<IJavaProject>();
- }
-
- private final SdkManager mManager;
- private final Map<String, DexWrapper> mDexWrappers = Maps.newHashMap();
- private final AvdManager mAvdManager;
- private final DeviceManager mDeviceManager;
-
- /** Map associating an {@link IAndroidTarget} to an {@link AndroidTargetData} */
- private final HashMap<IAndroidTarget, AndroidTargetData> mTargetDataMap =
- new HashMap<IAndroidTarget, AndroidTargetData>();
- /** Map associating an {@link IAndroidTarget} and its {@link TargetLoadBundle}. */
- private final HashMap<IAndroidTarget, TargetLoadBundle> mTargetDataStatusMap =
- new HashMap<IAndroidTarget, TargetLoadBundle>();
-
- /**
- * If true the target data will never load anymore. The only way to reload them is to
- * completely reload the SDK with {@link #loadSdk(String)}
- */
- private boolean mDontLoadTargetData = false;
-
- private final String mDocBaseUrl;
-
- /**
- * Classes implementing this interface will receive notification when targets are changed.
- */
- public interface ITargetChangeListener {
- /**
- * Sent when project has its target changed.
- */
- void onProjectTargetChange(IProject changedProject);
-
- /**
- * Called when the targets are loaded (either the SDK finished loading when Eclipse starts,
- * or the SDK is changed).
- */
- void onTargetLoaded(IAndroidTarget target);
-
- /**
- * Called when the base content of the SDK is parsed.
- */
- void onSdkLoaded();
- }
-
- /**
- * Basic abstract implementation of the ITargetChangeListener for the case where both
- * {@link #onProjectTargetChange(IProject)} and {@link #onTargetLoaded(IAndroidTarget)}
- * use the same code based on a simple test requiring to know the current IProject.
- */
- public static abstract class TargetChangeListener implements ITargetChangeListener {
- /**
- * Returns the {@link IProject} associated with the listener.
- */
- public abstract IProject getProject();
-
- /**
- * Called when the listener needs to take action on the event. This is only called
- * if {@link #getProject()} and the {@link IAndroidTarget} associated with the project
- * match the values received in {@link #onProjectTargetChange(IProject)} and
- * {@link #onTargetLoaded(IAndroidTarget)}.
- */
- public abstract void reload();
-
- @Override
- public void onProjectTargetChange(IProject changedProject) {
- if (changedProject != null && changedProject.equals(getProject())) {
- reload();
- }
- }
-
- @Override
- public void onTargetLoaded(IAndroidTarget target) {
- IProject project = getProject();
- if (target != null && target.equals(Sdk.getCurrent().getTarget(project))) {
- reload();
- }
- }
-
- @Override
- public void onSdkLoaded() {
- // do nothing;
- }
- }
-
- /**
- * Returns the lock object used to synchronize all operations dealing with SDK, targets and
- * projects.
- */
- @NonNull
- public static final Object getLock() {
- return LOCK;
- }
-
- /**
- * Loads an SDK and returns an {@link Sdk} object if success.
- * <p/>If the SDK failed to load, it displays an error to the user.
- * @param sdkLocation the OS path to the SDK.
- */
- @Nullable
- public static Sdk loadSdk(String sdkLocation) {
- synchronized (LOCK) {
- if (sCurrentSdk != null) {
- sCurrentSdk.dispose();
- sCurrentSdk = null;
- }
-
- final AtomicBoolean hasWarning = new AtomicBoolean();
- final AtomicBoolean hasError = new AtomicBoolean();
- final ArrayList<String> logMessages = new ArrayList<String>();
- ILogger log = new ILogger() {
- @Override
- public void error(@Nullable Throwable throwable, @Nullable String errorFormat,
- Object... arg) {
- hasError.set(true);
- if (errorFormat != null) {
- logMessages.add(String.format("Error: " + errorFormat, arg));
- }
-
- if (throwable != null) {
- logMessages.add(throwable.getMessage());
- }
- }
-
- @Override
- public void warning(@NonNull String warningFormat, Object... arg) {
- hasWarning.set(true);
- logMessages.add(String.format("Warning: " + warningFormat, arg));
- }
-
- @Override
- public void info(@NonNull String msgFormat, Object... arg) {
- logMessages.add(String.format(msgFormat, arg));
- }
-
- @Override
- public void verbose(@NonNull String msgFormat, Object... arg) {
- info(msgFormat, arg);
- }
- };
-
- // get an SdkManager object for the location
- SdkManager manager = SdkManager.createManager(sdkLocation, log);
- try {
- if (manager == null) {
- hasError.set(true);
- } else {
- // create the AVD Manager
- AvdManager avdManager = null;
- try {
- avdManager = AvdManager.getInstance(manager.getLocalSdk(), log);
- } catch (AndroidLocationException e) {
- log.error(e, "Error parsing the AVDs");
- }
- sCurrentSdk = new Sdk(manager, avdManager);
- return sCurrentSdk;
- }
- } finally {
- if (hasError.get() || hasWarning.get()) {
- StringBuilder sb = new StringBuilder(
- String.format("%s when loading the SDK:\n",
- hasError.get() ? "Error" : "Warning"));
- for (String msg : logMessages) {
- sb.append('\n');
- sb.append(msg);
- }
- if (hasError.get()) {
- AdtPlugin.printErrorToConsole("Android SDK", sb.toString());
- AdtPlugin.displayError("Android SDK", sb.toString());
- } else {
- AdtPlugin.printToConsole("Android SDK", sb.toString());
- }
- }
- }
- return null;
- }
- }
-
- /**
- * Returns the current {@link Sdk} object.
- */
- @Nullable
- public static Sdk getCurrent() {
- synchronized (LOCK) {
- return sCurrentSdk;
- }
- }
-
- /**
- * Returns the location of the current SDK as an OS path string.
- * Guaranteed to be terminated by a platform-specific path separator.
- * <p/>
- * Due to {@link File} canonicalization, this MAY differ from the string used to initialize
- * the SDK path.
- *
- * @return The SDK OS path or null if no SDK is setup.
- * @deprecated Consider using {@link #getSdkFileLocation()} instead.
- * @see #getSdkFileLocation()
- */
- @Deprecated
- @Nullable
- public String getSdkOsLocation() {
- String path = mManager == null ? null : mManager.getLocation();
- if (path != null) {
- // For backward compatibility make sure it ends with a separator.
- // This used to be the case when the SDK Manager was created from a String path
- // but now that a File is internally used the trailing dir separator is lost.
- if (path.length() > 0 && !path.endsWith(File.separator)) {
- path = path + File.separator;
- }
- }
- return path;
- }
-
- /**
- * Returns the location of the current SDK as a {@link File} or null.
- *
- * @return The SDK OS path or null if no SDK is setup.
- */
- @Nullable
- public File getSdkFileLocation() {
- if (mManager == null || mManager.getLocalSdk() == null) {
- return null;
- }
- return mManager.getLocalSdk().getLocation();
- }
-
- /**
- * Returns a <em>new</em> {@link SdkManager} that can parse the SDK located
- * at the current {@link #getSdkOsLocation()}.
- * <p/>
- * Implementation detail: The {@link Sdk} has its own internal manager with
- * a custom logger which is not designed to be useful for outsiders. Callers
- * who need their own {@link SdkManager} for parsing will often want to control
- * the logger for their own need.
- * <p/>
- * This is just a convenient method equivalent to writing:
- * <pre>SdkManager.createManager(Sdk.getCurrent().getSdkLocation(), log);</pre>
- *
- * @param log The logger for the {@link SdkManager}.
- * @return A new {@link SdkManager} parsing the same location.
- */
- public @Nullable SdkManager getNewSdkManager(@NonNull ILogger log) {
- return SdkManager.createManager(getSdkOsLocation(), log);
- }
-
- /**
- * Returns the URL to the local documentation.
- * Can return null if no documentation is found in the current SDK.
- *
- * @return A file:// URL on the local documentation folder if it exists or null.
- */
- @Nullable
- public String getDocumentationBaseUrl() {
- return mDocBaseUrl;
- }
-
- /**
- * Returns the list of targets that are available in the SDK.
- */
- public IAndroidTarget[] getTargets() {
- return mManager.getTargets();
- }
-
- /**
- * Queries the underlying SDK Manager to check whether the platforms or addons
- * directories have changed on-disk. Does not reload the SDK.
- * <p/>
- * This is a quick test based on the presence of the directories, their timestamps
- * and a quick checksum of the source.properties files. It's possible to have
- * false positives (e.g. if a file is manually modified in a platform) or false
- * negatives (e.g. if a platform data file is changed manually in a 2nd level
- * directory without altering the source.properties.)
- */
- public boolean haveTargetsChanged() {
- return mManager.hasChanged();
- }
-
- /**
- * Returns a target from a hash that was generated by {@link IAndroidTarget#hashString()}.
- *
- * @param hash the {@link IAndroidTarget} hash string.
- * @return The matching {@link IAndroidTarget} or null.
- */
- @Nullable
- public IAndroidTarget getTargetFromHashString(@NonNull String hash) {
- return mManager.getTargetFromHashString(hash);
- }
-
- @Nullable
- public BuildToolInfo getBuildToolInfo(@Nullable String buildToolVersion) {
- if (buildToolVersion != null) {
- try {
- return mManager.getBuildTool(FullRevision.parseRevision(buildToolVersion));
- } catch (Exception e) {
- // ignore, return null below.
- }
- }
-
- return null;
- }
-
- @Nullable
- public BuildToolInfo getLatestBuildTool() {
- return mManager.getLatestBuildTool();
- }
-
- /**
- * Initializes a new project with a target. This creates the <code>project.properties</code>
- * file.
- * @param project the project to initialize
- * @param target the project's target.
- * @throws IOException if creating the file failed in any way.
- * @throws StreamException if processing the project property file fails
- */
- public void initProject(@Nullable IProject project, @Nullable IAndroidTarget target)
- throws IOException, StreamException {
- if (project == null || target == null) {
- return;
- }
-
- synchronized (LOCK) {
- // check if there's already a state?
- ProjectState state = getProjectState(project);
-
- ProjectPropertiesWorkingCopy properties = null;
-
- if (state != null) {
- properties = state.getProperties().makeWorkingCopy();
- }
-
- if (properties == null) {
- IPath location = project.getLocation();
- if (location == null) { // can return null when the project is being deleted.
- // do nothing and return null;
- return;
- }
-
- properties = ProjectProperties.create(location.toOSString(), PropertyType.PROJECT);
- }
-
- // save the target hash string in the project persistent property
- properties.setProperty(ProjectProperties.PROPERTY_TARGET, target.hashString());
- properties.save();
- }
- }
-
- /**
- * Returns the {@link ProjectState} object associated with a given project.
- * <p/>
- * This method is the only way to properly get the project's {@link ProjectState}
- * If the project has not yet been loaded, then it is loaded.
- * <p/>Because this methods deals with projects, it's not linked to an actual {@link Sdk}
- * objects, and therefore is static.
- * <p/>The value returned by {@link ProjectState#getTarget()} will change as {@link Sdk} objects
- * are replaced.
- * @param project the request project
- * @return the ProjectState for the project.
- */
- @Nullable
- @SuppressWarnings("deprecation")
- public static ProjectState getProjectState(IProject project) {
- if (project == null) {
- return null;
- }
-
- synchronized (LOCK) {
- ProjectState state = sProjectStateMap.get(project);
- if (state == null) {
- // load the project.properties from the project folder.
- IPath location = project.getLocation();
- if (location == null) { // can return null when the project is being deleted.
- // do nothing and return null;
- return null;
- }
-
- String projectLocation = location.toOSString();
-
- ProjectProperties properties = ProjectProperties.load(projectLocation,
- PropertyType.PROJECT);
- if (properties == null) {
- // legacy support: look for default.properties and rename it if needed.
- properties = ProjectProperties.load(projectLocation,
- PropertyType.LEGACY_DEFAULT);
-
- if (properties == null) {
- AdtPlugin.log(IStatus.ERROR,
- "Failed to load properties file for project '%s'",
- project.getName());
- return null;
- } else {
- //legacy mode.
- // get a working copy with the new type "project"
- ProjectPropertiesWorkingCopy wc = properties.makeWorkingCopy(
- PropertyType.PROJECT);
- // and save it
- try {
- wc.save();
-
- // delete the old file.
- ProjectProperties.delete(projectLocation, PropertyType.LEGACY_DEFAULT);
-
- // make sure to use the new properties
- properties = ProjectProperties.load(projectLocation,
- PropertyType.PROJECT);
- } catch (Exception e) {
- AdtPlugin.log(IStatus.ERROR,
- "Failed to rename properties file to %1$s for project '%s2$'",
- PropertyType.PROJECT.getFilename(), project.getName());
- }
- }
- }
-
- state = new ProjectState(project, properties);
- sProjectStateMap.put(project, state);
-
- // try to resolve the target
- if (AdtPlugin.getDefault().getSdkLoadStatus() == LoadStatus.LOADED) {
- sCurrentSdk.loadTargetAndBuildTools(state);
- }
- }
-
- return state;
- }
- }
-
- /**
- * Returns the {@link IAndroidTarget} object associated with the given {@link IProject}.
- */
- @Nullable
- public IAndroidTarget getTarget(IProject project) {
- if (project == null) {
- return null;
- }
-
- ProjectState state = getProjectState(project);
- if (state != null) {
- return state.getTarget();
- }
-
- return null;
- }
-
- /**
- * Loads the {@link IAndroidTarget} and BuildTools for a given project.
- * <p/>This method will get the target hash string from the project properties, and resolve
- * it to an {@link IAndroidTarget} object and store it inside the {@link ProjectState}.
- * @param state the state representing the project to load.
- * @return the target that was loaded.
- */
- @Nullable
- public IAndroidTarget loadTargetAndBuildTools(ProjectState state) {
- IAndroidTarget target = null;
- if (state != null) {
- String hash = state.getTargetHashString();
- if (hash != null) {
- state.setTarget(target = getTargetFromHashString(hash));
- }
-
- String markerMessage = null;
- String buildToolInfoVersion = state.getBuildToolInfoVersion();
- if (buildToolInfoVersion != null) {
- BuildToolInfo buildToolsInfo = getBuildToolInfo(buildToolInfoVersion);
-
- if (buildToolsInfo != null) {
- state.setBuildToolInfo(buildToolsInfo);
- } else {
- markerMessage = String.format("Unable to resolve %s property value '%s'",
- ProjectProperties.PROPERTY_BUILD_TOOLS,
- buildToolInfoVersion);
- }
- } else {
- // this is ok, we'll use the latest one automatically.
- state.setBuildToolInfo(null);
- }
-
- handleBuildToolsMarker(state.getProject(), markerMessage);
- }
-
- return target;
- }
-
- /**
- * Adds or edit a build tools marker from the given project. This is done through a Job.
- * @param project the project
- * @param markerMessage the message. if null the marker is removed.
- */
- private void handleBuildToolsMarker(final IProject project, final String markerMessage) {
- Job markerJob = new Job("Android SDK: Build Tools Marker") {
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- try {
- if (project.isAccessible()) {
- // always delete existing marker first
- project.deleteMarkers(AdtConstants.MARKER_BUILD_TOOLS, true,
- IResource.DEPTH_ZERO);
-
- // add the new one if needed.
- if (markerMessage != null) {
- BaseProjectHelper.markProject(project,
- AdtConstants.MARKER_BUILD_TOOLS,
- markerMessage, IMarker.SEVERITY_ERROR,
- IMarker.PRIORITY_HIGH);
- }
- }
- } catch (CoreException e2) {
- AdtPlugin.log(e2, null);
- // Don't return e2.getStatus(); the job control will then produce
- // a popup with this error, which isn't very interesting for the
- // user.
- }
-
- return Status.OK_STATUS;
- }
- };
-
- // build jobs are run after other interactive jobs
- markerJob.setPriority(Job.BUILD);
- markerJob.setRule(ResourcesPlugin.getWorkspace().getRoot());
- markerJob.schedule();
- }
-
- /**
- * Checks and loads (if needed) the data for a given target.
- * <p/> The data is loaded in a separate {@link Job}, and opened editors will be notified
- * through their implementation of {@link ITargetChangeListener#onTargetLoaded(IAndroidTarget)}.
- * <p/>An optional project as second parameter can be given to be recompiled once the target
- * data is finished loading.
- * <p/>The return value is non-null only if the target data has already been loaded (and in this
- * case is the status of the load operation)
- * @param target the target to load.
- * @param project an optional project to be recompiled when the target data is loaded.
- * If the target is already loaded, nothing happens.
- * @return The load status if the target data is already loaded.
- */
- @NonNull
- public LoadStatus checkAndLoadTargetData(final IAndroidTarget target, IJavaProject project) {
- boolean loadData = false;
-
- synchronized (LOCK) {
- if (mDontLoadTargetData) {
- return LoadStatus.FAILED;
- }
-
- TargetLoadBundle bundle = mTargetDataStatusMap.get(target);
- if (bundle == null) {
- bundle = new TargetLoadBundle();
- mTargetDataStatusMap.put(target,bundle);
-
- // set status to loading
- bundle.status = LoadStatus.LOADING;
-
- // add project to bundle
- if (project != null) {
- bundle.projectsToReload.add(project);
- }
-
- // and set the flag to start the loading below
- loadData = true;
- } else if (bundle.status == LoadStatus.LOADING) {
- // add project to bundle
- if (project != null) {
- bundle.projectsToReload.add(project);
- }
-
- return bundle.status;
- } else if (bundle.status == LoadStatus.LOADED || bundle.status == LoadStatus.FAILED) {
- return bundle.status;
- }
- }
-
- if (loadData) {
- Job job = new Job(String.format("Loading data for %1$s", target.getFullName())) {
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- AdtPlugin plugin = AdtPlugin.getDefault();
- try {
- IStatus status = new AndroidTargetParser(target).run(monitor);
-
- IJavaProject[] javaProjectArray = null;
-
- synchronized (LOCK) {
- TargetLoadBundle bundle = mTargetDataStatusMap.get(target);
-
- if (status.getCode() != IStatus.OK) {
- bundle.status = LoadStatus.FAILED;
- bundle.projectsToReload.clear();
- } else {
- bundle.status = LoadStatus.LOADED;
-
- // Prepare the array of project to recompile.
- // The call is done outside of the synchronized block.
- javaProjectArray = bundle.projectsToReload.toArray(
- new IJavaProject[bundle.projectsToReload.size()]);
-
- // and update the UI of the editors that depend on the target data.
- plugin.updateTargetListeners(target);
- }
- }
-
- if (javaProjectArray != null) {
- ProjectHelper.updateProjects(javaProjectArray);
- }
-
- return status;
- } catch (Throwable t) {
- synchronized (LOCK) {
- TargetLoadBundle bundle = mTargetDataStatusMap.get(target);
- bundle.status = LoadStatus.FAILED;
- }
-
- AdtPlugin.log(t, "Exception in checkAndLoadTargetData."); //$NON-NLS-1$
- String message = String.format("Parsing Data for %1$s failed", target.hashString());
- if (t instanceof UnsupportedClassVersionError) {
- message = "To use this platform, run Eclipse with JDK 7 or later. (" + message + ")";
- }
- return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, message, t);
- }
- }
- };
- job.setPriority(Job.BUILD); // build jobs are run after other interactive jobs
- job.setRule(ResourcesPlugin.getWorkspace().getRoot());
- job.schedule();
- }
-
- // The only way to go through here is when the loading starts through the Job.
- // Therefore the current status of the target is LOADING.
- return LoadStatus.LOADING;
- }
-
- /**
- * Return the {@link AndroidTargetData} for a given {@link IAndroidTarget}.
- */
- @Nullable
- public AndroidTargetData getTargetData(IAndroidTarget target) {
- synchronized (LOCK) {
- return mTargetDataMap.get(target);
- }
- }
-
- /**
- * Return the {@link AndroidTargetData} for a given {@link IProject}.
- */
- @Nullable
- public AndroidTargetData getTargetData(IProject project) {
- synchronized (LOCK) {
- IAndroidTarget target = getTarget(project);
- if (target != null) {
- return getTargetData(target);
- }
- }
-
- return null;
- }
-
- /**
- * Returns a {@link DexWrapper} object to be used to execute dx commands. If dx.jar was not
- * loaded properly, then this will return <code>null</code>.
- */
- @Nullable
- public DexWrapper getDexWrapper(@Nullable BuildToolInfo buildToolInfo) {
- if (buildToolInfo == null) {
- return null;
- }
- synchronized (LOCK) {
- String dexLocation = buildToolInfo.getPath(BuildToolInfo.PathId.DX_JAR);
- DexWrapper dexWrapper = mDexWrappers.get(dexLocation);
-
- if (dexWrapper == null) {
- // load DX.
- dexWrapper = new DexWrapper();
- IStatus res = dexWrapper.loadDex(dexLocation);
- if (res != Status.OK_STATUS) {
- AdtPlugin.log(null, res.getMessage());
- dexWrapper = null;
- } else {
- mDexWrappers.put(dexLocation, dexWrapper);
- }
- }
-
- return dexWrapper;
- }
- }
-
- public void unloadDexWrappers() {
- synchronized (LOCK) {
- for (DexWrapper wrapper : mDexWrappers.values()) {
- wrapper.unload();
- }
- mDexWrappers.clear();
- }
- }
-
- /**
- * Returns the {@link AvdManager}. If the AvdManager failed to parse the AVD folder, this could
- * be <code>null</code>.
- */
- @Nullable
- public AvdManager getAvdManager() {
- return mAvdManager;
- }
-
- @Nullable
- public static AndroidVersion getDeviceVersion(@NonNull IDevice device) {
- try {
- Map<String, String> props = device.getProperties();
- String apiLevel = props.get(IDevice.PROP_BUILD_API_LEVEL);
- if (apiLevel == null) {
- return null;
- }
-
- return new AndroidVersion(Integer.parseInt(apiLevel),
- props.get((IDevice.PROP_BUILD_CODENAME)));
- } catch (NumberFormatException e) {
- return null;
- }
- }
-
- @NonNull
- public DeviceManager getDeviceManager() {
- return mDeviceManager;
- }
-
- /**
- * Returns a list of {@link ProjectState} representing projects depending, directly or
- * indirectly on a given library project.
- * @param project the library project.
- * @return a possibly empty list of ProjectState.
- */
- @NonNull
- public static Set<ProjectState> getMainProjectsFor(IProject project) {
- synchronized (LOCK) {
- // first get the project directly depending on this.
- Set<ProjectState> list = new HashSet<ProjectState>();
-
- // loop on all project and see if ProjectState.getLibrary returns a non null
- // project.
- for (Entry<IProject, ProjectState> entry : sProjectStateMap.entrySet()) {
- if (project != entry.getKey()) {
- LibraryState library = entry.getValue().getLibrary(project);
- if (library != null) {
- list.add(entry.getValue());
- }
- }
- }
-
- // now look for projects depending on the projects directly depending on the library.
- HashSet<ProjectState> result = new HashSet<ProjectState>(list);
- for (ProjectState p : list) {
- if (p.isLibrary()) {
- Set<ProjectState> set = getMainProjectsFor(p.getProject());
- result.addAll(set);
- }
- }
-
- return result;
- }
- }
-
- /**
- * Unload the SDK's target data.
- *
- * If <var>preventReload</var>, this effect is final until the SDK instance is changed
- * through {@link #loadSdk(String)}.
- *
- * The goal is to unload the targets to be able to replace existing targets with new ones,
- * before calling {@link #loadSdk(String)} to fully reload the SDK.
- *
- * @param preventReload prevent the data from being loaded again for the remaining live of
- * this {@link Sdk} instance.
- */
- public void unloadTargetData(boolean preventReload) {
- synchronized (LOCK) {
- mDontLoadTargetData = preventReload;
-
- // dispose of the target data.
- for (AndroidTargetData data : mTargetDataMap.values()) {
- data.dispose();
- }
-
- mTargetDataMap.clear();
- }
- }
-
- private Sdk(SdkManager manager, AvdManager avdManager) {
- mManager = manager;
- mAvdManager = avdManager;
-
- // listen to projects closing
- GlobalProjectMonitor monitor = GlobalProjectMonitor.getMonitor();
- // need to register the resource event listener first because the project listener
- // is called back during registration with project opened in the workspace.
- monitor.addResourceEventListener(mResourceEventListener);
- monitor.addProjectListener(mProjectListener);
- monitor.addFileListener(mFileListener,
- IResourceDelta.CHANGED | IResourceDelta.ADDED | IResourceDelta.REMOVED);
-
- // pre-compute some paths
- mDocBaseUrl = getDocumentationBaseUrl(manager.getLocation() +
- SdkConstants.OS_SDK_DOCS_FOLDER);
-
- mDeviceManager = DeviceManager.createInstance(manager.getLocalSdk().getLocation(),
- AdtPlugin.getDefault());
-
- // update whatever ProjectState is already present with new IAndroidTarget objects.
- synchronized (LOCK) {
- for (Entry<IProject, ProjectState> entry: sProjectStateMap.entrySet()) {
- loadTargetAndBuildTools(entry.getValue());
- }
- }
- }
-
- /**
- * Cleans and unloads the SDK.
- */
- private void dispose() {
- GlobalProjectMonitor monitor = GlobalProjectMonitor.getMonitor();
- monitor.removeProjectListener(mProjectListener);
- monitor.removeFileListener(mFileListener);
- monitor.removeResourceEventListener(mResourceEventListener);
-
- // the IAndroidTarget objects are now obsolete so update the project states.
- synchronized (LOCK) {
- for (Entry<IProject, ProjectState> entry: sProjectStateMap.entrySet()) {
- entry.getValue().setTarget(null);
- }
-
- // dispose of the target data.
- for (AndroidTargetData data : mTargetDataMap.values()) {
- data.dispose();
- }
-
- mTargetDataMap.clear();
- }
- }
-
- void setTargetData(IAndroidTarget target, AndroidTargetData data) {
- synchronized (LOCK) {
- mTargetDataMap.put(target, data);
- }
- }
-
- /**
- * Returns the URL to the local documentation.
- * Can return null if no documentation is found in the current SDK.
- *
- * @param osDocsPath Path to the documentation folder in the current SDK.
- * The folder may not actually exist.
- * @return A file:// URL on the local documentation folder if it exists or null.
- */
- private String getDocumentationBaseUrl(String osDocsPath) {
- File f = new File(osDocsPath);
-
- if (f.isDirectory()) {
- try {
- // Note: to create a file:// URL, one would typically use something like
- // f.toURI().toURL().toString(). However this generates a broken path on
- // Windows, namely "C:\\foo" is converted to "file:/C:/foo" instead of
- // "file:///C:/foo" (i.e. there should be 3 / after "file:"). So we'll
- // do the correct thing manually.
-
- String path = f.getAbsolutePath();
- if (File.separatorChar != '/') {
- path = path.replace(File.separatorChar, '/');
- }
-
- // For some reason the URL class doesn't add the mandatory "//" after
- // the "file:" protocol name, so it has to be hacked into the path.
- URL url = new URL("file", null, "//" + path); //$NON-NLS-1$ //$NON-NLS-2$
- String result = url.toString();
- return result;
- } catch (MalformedURLException e) {
- // ignore malformed URLs
- }
- }
-
- return null;
- }
-
- /**
- * Delegate listener for project changes.
- */
- private IProjectListener mProjectListener = new IProjectListener() {
- @Override
- public void projectClosed(IProject project) {
- onProjectRemoved(project, false /*deleted*/);
- }
-
- @Override
- public void projectDeleted(IProject project) {
- onProjectRemoved(project, true /*deleted*/);
- }
-
- private void onProjectRemoved(IProject removedProject, boolean deleted) {
- if (DEBUG) {
- System.out.println(">>> CLOSED: " + removedProject.getName());
- }
-
- // get the target project
- synchronized (LOCK) {
- // Don't use getProject() as it could create the ProjectState if it's not
- // there yet and this is not what we want. We want the current object.
- // Therefore, direct access to the map.
- ProjectState removedState = sProjectStateMap.get(removedProject);
- if (removedState != null) {
- // 1. clear the layout lib cache associated with this project
- IAndroidTarget target = removedState.getTarget();
- if (target != null) {
- // get the bridge for the target, and clear the cache for this project.
- AndroidTargetData data = mTargetDataMap.get(target);
- if (data != null) {
- LayoutLibrary layoutLib = data.getLayoutLibrary();
- if (layoutLib != null && layoutLib.getStatus() == LoadStatus.LOADED) {
- layoutLib.clearCaches(removedProject);
- }
- }
- }
-
- // 2. if the project is a library, make sure to update the
- // LibraryState for any project referencing it.
- // Also, record the updated projects that are libraries, to update
- // projects that depend on them.
- for (ProjectState projectState : sProjectStateMap.values()) {
- LibraryState libState = projectState.getLibrary(removedProject);
- if (libState != null) {
- // Close the library right away.
- // This remove links between the LibraryState and the projectState.
- // This is because in case of a rename of a project, projectClosed and
- // projectOpened will be called before any other job is run, so we
- // need to make sure projectOpened is closed with the main project
- // state up to date.
- libState.close();
-
- // record that this project changed, and in case it's a library
- // that its parents need to be updated as well.
- markProject(projectState, projectState.isLibrary());
- }
- }
-
- // now remove the project for the project map.
- sProjectStateMap.remove(removedProject);
- }
- }
-
- if (DEBUG) {
- System.out.println("<<<");
- }
- }
-
- @Override
- public void projectOpened(IProject project) {
- onProjectOpened(project);
- }
-
- @Override
- public void projectOpenedWithWorkspace(IProject project) {
- // no need to force recompilation when projects are opened with the workspace.
- onProjectOpened(project);
- }
-
- @Override
- public void allProjectsOpenedWithWorkspace() {
- // Correct currently open editors
- fixOpenLegacyEditors();
- }
-
- private void onProjectOpened(final IProject openedProject) {
-
- ProjectState openedState = getProjectState(openedProject);
- if (openedState != null) {
- if (DEBUG) {
- System.out.println(">>> OPENED: " + openedProject.getName());
- }
-
- synchronized (LOCK) {
- final boolean isLibrary = openedState.isLibrary();
- final boolean hasLibraries = openedState.hasLibraries();
-
- if (isLibrary || hasLibraries) {
- boolean foundLibraries = false;
- // loop on all the existing project and update them based on this new
- // project
- for (ProjectState projectState : sProjectStateMap.values()) {
- if (projectState != openedState) {
- // If the project has libraries, check if this project
- // is a reference.
- if (hasLibraries) {
- // ProjectState#needs() both checks if this is a missing library
- // and updates LibraryState to contains the new values.
- // This must always be called.
- LibraryState libState = openedState.needs(projectState);
-
- if (libState != null) {
- // found a library! Add the main project to the list of
- // modified project
- foundLibraries = true;
- }
- }
-
- // if the project is a library check if the other project depend
- // on it.
- if (isLibrary) {
- // ProjectState#needs() both checks if this is a missing library
- // and updates LibraryState to contains the new values.
- // This must always be called.
- LibraryState libState = projectState.needs(openedState);
-
- if (libState != null) {
- // There's a dependency! Add the project to the list of
- // modified project, but also to a list of projects
- // that saw one of its dependencies resolved.
- markProject(projectState, projectState.isLibrary());
- }
- }
- }
- }
-
- // if the project has a libraries and we found at least one, we add
- // the project to the list of modified project.
- // Since we already went through the parent, no need to update them.
- if (foundLibraries) {
- markProject(openedState, false /*updateParents*/);
- }
- }
- }
-
- // Correct file editor associations.
- fixEditorAssociations(openedProject);
-
- // Fix classpath entries in a job since the workspace might be locked now.
- Job fixCpeJob = new Job("Adjusting Android Project Classpath") {
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- try {
- ProjectHelper.fixProjectClasspathEntries(
- JavaCore.create(openedProject));
- } catch (JavaModelException e) {
- AdtPlugin.log(e, "error fixing classpath entries");
- // Don't return e2.getStatus(); the job control will then produce
- // a popup with this error, which isn't very interesting for the
- // user.
- }
-
- return Status.OK_STATUS;
- }
- };
-
- // build jobs are run after other interactive jobs
- fixCpeJob.setPriority(Job.BUILD);
- fixCpeJob.setRule(ResourcesPlugin.getWorkspace().getRoot());
- fixCpeJob.schedule();
-
-
- if (DEBUG) {
- System.out.println("<<<");
- }
- }
- }
-
- @Override
- public void projectRenamed(IProject project, IPath from) {
- // we don't actually care about this anymore.
- }
- };
-
- /**
- * Delegate listener for file changes.
- */
- private IFileListener mFileListener = new IFileListener() {
- @Override
- public void fileChanged(final @NonNull IFile file, @NonNull IMarkerDelta[] markerDeltas,
- int kind, @Nullable String extension, int flags, boolean isAndroidPRoject) {
- if (!isAndroidPRoject) {
- return;
- }
-
- if (SdkConstants.FN_PROJECT_PROPERTIES.equals(file.getName()) &&
- file.getParent() == file.getProject()) {
- try {
- // reload the content of the project.properties file and update
- // the target.
- IProject iProject = file.getProject();
-
- ProjectState state = Sdk.getProjectState(iProject);
-
- // get the current target and build tools
- IAndroidTarget oldTarget = state.getTarget();
- boolean oldRsSupportMode = state.getRenderScriptSupportMode();
-
- // get the current library flag
- boolean wasLibrary = state.isLibrary();
-
- LibraryDifference diff = state.reloadProperties();
-
- // load the (possibly new) target.
- IAndroidTarget newTarget = loadTargetAndBuildTools(state);
-
- // reload the libraries if needed
- if (diff.hasDiff()) {
- if (diff.added) {
- synchronized (LOCK) {
- for (ProjectState projectState : sProjectStateMap.values()) {
- if (projectState != state) {
- // need to call needs to do the libraryState link,
- // but no need to look at the result, as we'll compare
- // the result of getFullLibraryProjects()
- // this is easier to due to indirect dependencies.
- state.needs(projectState);
- }
- }
- }
- }
-
- markProject(state, wasLibrary || state.isLibrary());
- }
-
- // apply the new target if needed.
- if (newTarget != oldTarget ||
- oldRsSupportMode != state.getRenderScriptSupportMode()) {
- IJavaProject javaProject = BaseProjectHelper.getJavaProject(
- file.getProject());
- if (javaProject != null) {
- ProjectHelper.updateProject(javaProject);
- }
-
- // update the editors to reload with the new target
- AdtPlugin.getDefault().updateTargetListeners(iProject);
- }
- } catch (CoreException e) {
- // This can't happen as it's only for closed project (or non existing)
- // but in that case we can't get a fileChanged on this file.
- }
- } else if (kind == IResourceDelta.ADDED || kind == IResourceDelta.REMOVED) {
- // check if it's an add/remove on a jar files inside libs
- if (EXT_JAR.equals(extension) &&
- file.getProjectRelativePath().segmentCount() == 2 &&
- file.getParent().getName().equals(SdkConstants.FD_NATIVE_LIBS)) {
- // need to update the project and whatever depend on it.
-
- processJarFileChange(file);
- }
- }
- }
-
- private void processJarFileChange(final IFile file) {
- try {
- IProject iProject = file.getProject();
-
- if (iProject.hasNature(AdtConstants.NATURE_DEFAULT) == false) {
- return;
- }
-
- List<IJavaProject> projectList = new ArrayList<IJavaProject>();
- IJavaProject javaProject = BaseProjectHelper.getJavaProject(iProject);
- if (javaProject != null) {
- projectList.add(javaProject);
- }
-
- ProjectState state = Sdk.getProjectState(iProject);
-
- if (state != null) {
- Collection<ProjectState> parents = state.getFullParentProjects();
- for (ProjectState s : parents) {
- javaProject = BaseProjectHelper.getJavaProject(s.getProject());
- if (javaProject != null) {
- projectList.add(javaProject);
- }
- }
-
- ProjectHelper.updateProjects(
- projectList.toArray(new IJavaProject[projectList.size()]));
- }
- } catch (CoreException e) {
- // This can't happen as it's only for closed project (or non existing)
- // but in that case we can't get a fileChanged on this file.
- }
- }
- };
-
- /** List of modified projects. This is filled in
- * {@link IProjectListener#projectOpened(IProject)},
- * {@link IProjectListener#projectOpenedWithWorkspace(IProject)},
- * {@link IProjectListener#projectClosed(IProject)}, and
- * {@link IProjectListener#projectDeleted(IProject)} and processed in
- * {@link IResourceEventListener#resourceChangeEventEnd()}.
- */
- private final List<ProjectState> mModifiedProjects = new ArrayList<ProjectState>();
- private final List<ProjectState> mModifiedChildProjects = new ArrayList<ProjectState>();
-
- private void markProject(ProjectState projectState, boolean updateParents) {
- if (mModifiedProjects.contains(projectState) == false) {
- if (DEBUG) {
- System.out.println("\tMARKED: " + projectState.getProject().getName());
- }
- mModifiedProjects.add(projectState);
- }
-
- // if the project is resolved also add it to this list.
- if (updateParents) {
- if (mModifiedChildProjects.contains(projectState) == false) {
- if (DEBUG) {
- System.out.println("\tMARKED(child): " + projectState.getProject().getName());
- }
- mModifiedChildProjects.add(projectState);
- }
- }
- }
-
- /**
- * Delegate listener for resource changes. This is called before and after any calls to the
- * project and file listeners (for a given resource change event).
- */
- private IResourceEventListener mResourceEventListener = new IResourceEventListener() {
- @Override
- public void resourceChangeEventStart() {
- mModifiedProjects.clear();
- mModifiedChildProjects.clear();
- }
-
- @Override
- public void resourceChangeEventEnd() {
- if (mModifiedProjects.size() == 0) {
- return;
- }
-
- // first make sure all the parents are updated
- updateParentProjects();
-
- // for all modified projects, update their library list
- // and gather their IProject
- final List<IJavaProject> projectList = new ArrayList<IJavaProject>();
- for (ProjectState state : mModifiedProjects) {
- state.updateFullLibraryList();
- projectList.add(JavaCore.create(state.getProject()));
- }
-
- Job job = new Job("Android Library Update") { //$NON-NLS-1$
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- LibraryClasspathContainerInitializer.updateProjects(
- projectList.toArray(new IJavaProject[projectList.size()]));
-
- for (IJavaProject javaProject : projectList) {
- try {
- javaProject.getProject().build(IncrementalProjectBuilder.FULL_BUILD,
- monitor);
- } catch (CoreException e) {
- // pass
- }
- }
- return Status.OK_STATUS;
- }
- };
- job.setPriority(Job.BUILD);
- job.setRule(ResourcesPlugin.getWorkspace().getRoot());
- job.schedule();
- }
- };
-
- /**
- * Updates all existing projects with a given list of new/updated libraries.
- * This loops through all opened projects and check if they depend on any of the given
- * library project, and if they do, they are linked together.
- */
- private void updateParentProjects() {
- if (mModifiedChildProjects.size() == 0) {
- return;
- }
-
- ArrayList<ProjectState> childProjects = new ArrayList<ProjectState>(mModifiedChildProjects);
- mModifiedChildProjects.clear();
- synchronized (LOCK) {
- // for each project for which we must update its parent, we loop on the parent
- // projects and adds them to the list of modified projects. If they are themselves
- // libraries, we add them too.
- for (ProjectState state : childProjects) {
- if (DEBUG) {
- System.out.println(">>> Updating parents of " + state.getProject().getName());
- }
- List<ProjectState> parents = state.getParentProjects();
- for (ProjectState parent : parents) {
- markProject(parent, parent.isLibrary());
- }
- if (DEBUG) {
- System.out.println("<<<");
- }
- }
- }
-
- // done, but there may be parents that are also libraries. Need to update their parents.
- updateParentProjects();
- }
-
- /**
- * Fix editor associations for the given project, if not already done.
- * <p/>
- * Eclipse has a per-file setting for which editor should be used for each file
- * (see {@link IDE#setDefaultEditor(IFile, String)}).
- * We're using this flag to pick between the various XML editors (layout, drawable, etc)
- * since they all have the same file name extension.
- * <p/>
- * Unfortunately, the file setting can be "wrong" for two reasons:
- * <ol>
- * <li> The editor type was added <b>after</b> a file had been seen by the IDE.
- * For example, we added new editors for animations and for drawables around
- * ADT 12, but any file seen by ADT in earlier versions will continue to use
- * the vanilla Eclipse XML editor instead.
- * <li> A bug in ADT 14 and ADT 15 (see issue 21124) meant that files created in new
- * folders would end up with wrong editor associations. Even though that bug
- * is fixed in ADT 16, the fix only affects new files, it cannot retroactively
- * fix editor associations that were set incorrectly by ADT 14 or 15.
- * </ol>
- * <p/>
- * This method attempts to fix the editor bindings retroactively by scanning all the
- * resource XML files and resetting the editor associations.
- * Since this is a potentially slow operation, this is only done "once"; we use a
- * persistent project property to avoid looking repeatedly. In the future if we add
- * additional editors, we can rev the scanned version value.
- */
- private void fixEditorAssociations(final IProject project) {
- QualifiedName KEY = new QualifiedName(AdtPlugin.PLUGIN_ID, "editorbinding"); //$NON-NLS-1$
-
- try {
- String value = project.getPersistentProperty(KEY);
- int currentVersion = 0;
- if (value != null) {
- try {
- currentVersion = Integer.parseInt(value);
- } catch (Exception ingore) {
- }
- }
-
- // The target version we're comparing to. This must be incremented each time
- // we change the processing here so that a new version of the plugin would
- // try to fix existing user projects.
- final int targetVersion = 2;
-
- if (currentVersion >= targetVersion) {
- return;
- }
-
- // Set to specific version such that we can rev the version in the future
- // to trigger further scanning
- project.setPersistentProperty(KEY, Integer.toString(targetVersion));
-
- // Now update the actual editor associations.
- Job job = new Job("Update Android editor bindings") { //$NON-NLS-1$
- @Override
- protected IStatus run(IProgressMonitor monitor) {
- try {
- for (IResource folderResource : project.getFolder(FD_RES).members()) {
- if (folderResource instanceof IFolder) {
- IFolder folder = (IFolder) folderResource;
-
- for (IResource resource : folder.members()) {
- if (resource instanceof IFile &&
- resource.getName().endsWith(DOT_XML)) {
- fixXmlFile((IFile) resource);
- }
- }
- }
- }
-
- // TODO change AndroidManifest.xml ID too
-
- } catch (CoreException e) {
- AdtPlugin.log(e, null);
- }
-
- return Status.OK_STATUS;
- }
-
- /**
- * Attempt to fix the editor ID for the given /res XML file.
- */
- private void fixXmlFile(final IFile file) {
- // Fix the default editor ID for this resource.
- // This has no effect on currently open editors.
- IEditorDescriptor desc = IDE.getDefaultEditor(file);
-
- if (desc == null || !CommonXmlEditor.ID.equals(desc.getId())) {
- IDE.setDefaultEditor(file, CommonXmlEditor.ID);
- }
- }
- };
- job.setPriority(Job.BUILD);
- job.schedule();
- } catch (CoreException e) {
- AdtPlugin.log(e, null);
- }
- }
-
- /**
- * Tries to fix all currently open Android legacy editors.
- * <p/>
- * If an editor is found to match one of the legacy ids, we'll try to close it.
- * If that succeeds, we try to reopen it using the new common editor ID.
- * <p/>
- * This method must be run from the UI thread.
- */
- private void fixOpenLegacyEditors() {
-
- AdtPlugin adt = AdtPlugin.getDefault();
- if (adt == null) {
- return;
- }
-
- final IPreferenceStore store = adt.getPreferenceStore();
- int currentValue = store.getInt(AdtPrefs.PREFS_FIX_LEGACY_EDITORS);
- // The target version we're comparing to. This must be incremented each time
- // we change the processing here so that a new version of the plugin would
- // try to fix existing editors.
- final int targetValue = 1;
-
- if (currentValue >= targetValue) {
- return;
- }
-
- // To be able to close and open editors we need to make sure this is done
- // in the UI thread, which this isn't invoked from.
- PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
- @Override
- public void run() {
- HashSet<String> legacyIds =
- new HashSet<String>(Arrays.asList(CommonXmlEditor.LEGACY_EDITOR_IDS));
-
- for (IWorkbenchWindow win : PlatformUI.getWorkbench().getWorkbenchWindows()) {
- for (IWorkbenchPage page : win.getPages()) {
- for (IEditorReference ref : page.getEditorReferences()) {
- try {
- IEditorInput input = ref.getEditorInput();
- if (input instanceof IFileEditorInput) {
- IFile file = ((IFileEditorInput)input).getFile();
- IEditorPart part = ref.getEditor(true /*restore*/);
- if (part != null) {
- IWorkbenchPartSite site = part.getSite();
- if (site != null) {
- String id = site.getId();
- if (legacyIds.contains(id)) {
- // This editor matches one of legacy editor IDs.
- fixEditor(page, part, input, file, id);
- }
- }
- }
- }
- } catch (Exception e) {
- // ignore
- }
- }
- }
- }
-
- // Remember that we managed to do fix all editors
- store.setValue(AdtPrefs.PREFS_FIX_LEGACY_EDITORS, targetValue);
- }
-
- private void fixEditor(
- IWorkbenchPage page,
- IEditorPart part,
- IEditorInput input,
- IFile file,
- String id) {
- IDE.setDefaultEditor(file, CommonXmlEditor.ID);
-
- boolean ok = page.closeEditor(part, true /*save*/);
-
- AdtPlugin.log(IStatus.INFO,
- "Closed legacy editor ID %s for %s: %s", //$NON-NLS-1$
- id,
- file.getFullPath(),
- ok ? "Success" : "Failed");//$NON-NLS-1$ //$NON-NLS-2$
-
- if (ok) {
- // Try to reopen it with the new ID
- try {
- page.openEditor(input, CommonXmlEditor.ID);
- } catch (PartInitException e) {
- AdtPlugin.log(e,
- "Failed to reopen %s", //$NON-NLS-1$
- file.getFullPath());
- }
- }
- }
- });
- }
-}