diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java | 2045 |
1 files changed, 0 insertions, 2045 deletions
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 deleted file mode 100644 index f7ef41fe3..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java +++ /dev/null @@ -1,2045 +0,0 @@ -/* - * Copyright (C) 2007 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; - -import static com.android.SdkConstants.CURRENT_PLATFORM; -import static com.android.SdkConstants.PLATFORM_DARWIN; -import static com.android.SdkConstants.PLATFORM_LINUX; -import static com.android.SdkConstants.PLATFORM_WINDOWS; - -import com.android.SdkConstants; -import com.android.annotations.NonNull; -import com.android.annotations.Nullable; -import com.android.ide.common.resources.ResourceFile; -import com.android.ide.common.sdk.LoadStatus; -import com.android.ide.eclipse.adt.AdtPlugin.CheckSdkErrorHandler.Solution; -import com.android.ide.eclipse.adt.internal.VersionCheck; -import com.android.ide.eclipse.adt.internal.actions.SdkManagerAction; -import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; -import com.android.ide.eclipse.adt.internal.editors.IconFactory; -import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor; -import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder; -import com.android.ide.eclipse.adt.internal.lint.LintDeltaProcessor; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; -import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; -import com.android.ide.eclipse.adt.internal.project.AndroidClasspathContainerInitializer; -import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; -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.ResourceManager; -import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.internal.sdk.Sdk.ITargetChangeListener; -import com.android.ide.eclipse.adt.internal.ui.EclipseUiHelper; -import com.android.ide.eclipse.ddms.DdmsPlugin; -import com.android.io.StreamException; -import com.android.resources.ResourceFolderType; -import com.android.sdklib.IAndroidTarget; -import com.android.utils.ILogger; -import com.google.common.collect.Sets; -import com.google.common.io.Closeables; - -import org.eclipse.core.commands.Command; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IMarkerDelta; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResourceDelta; -import org.eclipse.core.resources.IWorkspace; -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.SubMonitor; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.ui.JavaUI; -import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.preference.PreferenceDialog; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.text.IRegion; -import org.eclipse.jface.util.IPropertyChangeListener; -import org.eclipse.jface.util.PropertyChangeEvent; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.ui.IEditorDescriptor; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.browser.IWebBrowser; -import org.eclipse.ui.browser.IWorkbenchBrowserSupport; -import org.eclipse.ui.commands.ICommandService; -import org.eclipse.ui.console.ConsolePlugin; -import org.eclipse.ui.console.IConsole; -import org.eclipse.ui.console.IConsoleConstants; -import org.eclipse.ui.console.MessageConsole; -import org.eclipse.ui.console.MessageConsoleStream; -import org.eclipse.ui.dialogs.PreferencesUtil; -import org.eclipse.ui.handlers.IHandlerService; -import org.eclipse.ui.ide.IDE; -import org.eclipse.ui.plugin.AbstractUIPlugin; -import org.eclipse.ui.texteditor.AbstractTextEditor; -import org.eclipse.wb.internal.core.DesignerPlugin; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.Reader; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Set; - -/** - * The activator class controls the plug-in life cycle - */ -public class AdtPlugin extends AbstractUIPlugin implements ILogger { - /** The plug-in ID */ - public static final String PLUGIN_ID = "com.android.ide.eclipse.adt"; //$NON-NLS-1$ - - /** singleton instance */ - private static AdtPlugin sPlugin; - - private static Image sAndroidLogo; - private static ImageDescriptor sAndroidLogoDesc; - - /** The global android console */ - private MessageConsole mAndroidConsole; - - /** Stream to write in the android console */ - private MessageConsoleStream mAndroidConsoleStream; - - /** Stream to write error messages to the android console */ - private MessageConsoleStream mAndroidConsoleErrorStream; - - /** Color used in the error console */ - private Color mRed; - - /** Load status of the SDK. Any access MUST be in a synchronized(mPostLoadProjects) block */ - private LoadStatus mSdkLoadedStatus = LoadStatus.LOADING; - /** Project to update once the SDK is loaded. - * Any access MUST be in a synchronized(mPostLoadProjectsToResolve) block */ - private final Set<IJavaProject> mPostLoadProjectsToResolve = Sets.newHashSet(); - /** Project to check validity of cache vs actual once the SDK is loaded. - * Any access MUST be in a synchronized(mPostLoadProjectsToResolve) block */ - private final ArrayList<IJavaProject> mPostLoadProjectsToCheck = new ArrayList<IJavaProject>(); - - private GlobalProjectMonitor mResourceMonitor; - private ArrayList<ITargetChangeListener> mTargetChangeListeners = - new ArrayList<ITargetChangeListener>(); - - /** - * This variable indicates that the job inside parseSdkContent() is currently - * trying to load the SDK, to avoid re-entrance. - * To check whether this succeeds or not, please see {@link #getSdkLoadStatus()}. - */ - private volatile boolean mParseSdkContentIsRunning; - - /** - * An error handler for checkSdkLocationAndId() that will handle the generated error - * or warning message. Each method must return a boolean that will in turn be returned by - * checkSdkLocationAndId. - */ - public static abstract class CheckSdkErrorHandler { - - public enum Solution { - NONE, - OPEN_SDK_MANAGER, - OPEN_ANDROID_PREFS, - OPEN_P2_UPDATE - } - - /** - * Handle an error message during sdk location check. Returns whatever - * checkSdkLocationAndId() should returns. - */ - public abstract boolean handleError(Solution solution, String message); - - /** - * Handle a warning message during sdk location check. Returns whatever - * checkSdkLocationAndId() should returns. - */ - public abstract boolean handleWarning(Solution solution, String message); - } - - /** - * The constructor - */ - public AdtPlugin() { - sPlugin = this; - } - - /* - * (non-Javadoc) - * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) - */ - @Override - public void start(BundleContext context) throws Exception { - super.start(context); - - // set the default android console. - mAndroidConsole = new MessageConsole("Android", null); //$NON-NLS-1$ - ConsolePlugin.getDefault().getConsoleManager().addConsoles( - new IConsole[] { mAndroidConsole }); - - // get the stream to write in the android console. - mAndroidConsoleStream = mAndroidConsole.newMessageStream(); - mAndroidConsoleErrorStream = mAndroidConsole.newMessageStream(); - - // get the eclipse store - IPreferenceStore eclipseStore = getPreferenceStore(); - AdtPrefs.init(eclipseStore); - - // set the listener for the preference change - eclipseStore.addPropertyChangeListener(new IPropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent event) { - // load the new preferences - AdtPrefs.getPrefs().loadValues(event); - - // if the SDK changed, we have to do some extra work - if (AdtPrefs.PREFS_SDK_DIR.equals(event.getProperty())) { - - // finally restart adb, in case it's a different version - DdmsPlugin.setToolsLocation(getOsAbsoluteAdb(), true /* startAdb */, - getOsAbsoluteHprofConv(), getOsAbsoluteTraceview()); - - // get the SDK location and build id. - if (checkSdkLocationAndId()) { - // if sdk if valid, reparse it - - reparseSdk(); - } - } - } - }); - - // load preferences. - AdtPrefs.getPrefs().loadValues(null /*event*/); - - // initialize property-sheet library - DesignerPlugin.initialize( - this, - PLUGIN_ID, - CURRENT_PLATFORM == PLATFORM_WINDOWS, - CURRENT_PLATFORM == PLATFORM_DARWIN, - CURRENT_PLATFORM == PLATFORM_LINUX); - - // initialize editors - startEditors(); - - // Listen on resource file edits for updates to file inclusion - IncludeFinder.start(); - } - - /* - * (non-Javadoc) - * - * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) - */ - @Override - public void stop(BundleContext context) throws Exception { - super.stop(context); - - stopEditors(); - IncludeFinder.stop(); - - DesignerPlugin.dispose(); - - if (mRed != null) { - mRed.dispose(); - mRed = null; - } - - synchronized (AdtPlugin.class) { - sPlugin = null; - } - } - - /** Called when the workbench has been started */ - public void workbenchStarted() { - // Parse the SDK content. - // This is deferred in separate jobs to avoid blocking the bundle start. - final boolean isSdkLocationValid = checkSdkLocationAndId(); - if (isSdkLocationValid) { - // parse the SDK resources. - // Wait 2 seconds before starting the job. This leaves some time to the - // other bundles to initialize. - parseSdkContent(2000 /*milliseconds*/); - } - - Display display = getDisplay(); - mRed = new Color(display, 0xFF, 0x00, 0x00); - - // because this can be run, in some cases, by a non ui thread, and because - // changing the console properties update the ui, we need to make this change - // in the ui thread. - display.asyncExec(new Runnable() { - @Override - public void run() { - mAndroidConsoleErrorStream.setColor(mRed); - } - }); - } - - /** - * Returns the shared instance - * - * @return the shared instance - */ - public static synchronized AdtPlugin getDefault() { - return sPlugin; - } - - /** - * Returns the current display, if any - * - * @return the display - */ - @NonNull - public static Display getDisplay() { - synchronized (AdtPlugin.class) { - if (sPlugin != null) { - IWorkbench bench = sPlugin.getWorkbench(); - if (bench != null) { - Display display = bench.getDisplay(); - if (display != null) { - return display; - } - } - } - } - - Display display = Display.getCurrent(); - if (display != null) { - return display; - } - - return Display.getDefault(); - } - - /** - * Returns the shell, if any - * - * @return the shell, if any - */ - @Nullable - public static Shell getShell() { - Display display = AdtPlugin.getDisplay(); - Shell shell = display.getActiveShell(); - if (shell == null) { - Shell[] shells = display.getShells(); - if (shells.length > 0) { - shell = shells[0]; - } - } - - return shell; - } - - /** Returns the adb path relative to the sdk folder */ - public static String getOsRelativeAdb() { - return SdkConstants.OS_SDK_PLATFORM_TOOLS_FOLDER + SdkConstants.FN_ADB; - } - - /** Returns the emulator path relative to the sdk folder */ - public static String getOsRelativeEmulator() { - return SdkConstants.OS_SDK_TOOLS_FOLDER + SdkConstants.FN_EMULATOR; - } - - /** Returns the adb path relative to the sdk folder */ - public static String getOsRelativeProguard() { - return SdkConstants.OS_SDK_TOOLS_PROGUARD_BIN_FOLDER + SdkConstants.FN_PROGUARD; - } - - /** Returns the absolute adb path */ - public static String getOsAbsoluteAdb() { - return getOsSdkFolder() + getOsRelativeAdb(); - } - - /** Returns the absolute traceview path */ - public static String getOsAbsoluteTraceview() { - return getOsSdkFolder() + SdkConstants.OS_SDK_TOOLS_FOLDER + - AdtConstants.FN_TRACEVIEW; - } - - /** Returns the absolute emulator path */ - public static String getOsAbsoluteEmulator() { - return getOsSdkFolder() + getOsRelativeEmulator(); - } - - public static String getOsAbsoluteHprofConv() { - return getOsSdkFolder() + SdkConstants.OS_SDK_PLATFORM_TOOLS_FOLDER + - AdtConstants.FN_HPROF_CONV; - } - - /** Returns the absolute proguard path */ - public static String getOsAbsoluteProguard() { - return getOsSdkFolder() + getOsRelativeProguard(); - } - - /** - * Returns a Url file path to the javaDoc folder. - */ - public static String getUrlDoc() { - return ProjectHelper.getJavaDocPath( - getOsSdkFolder() + AdtConstants.WS_JAVADOC_FOLDER_LEAF); - } - - /** - * Returns the SDK folder. - * Guaranteed to be terminated by a platform-specific path separator. - */ - public static synchronized String getOsSdkFolder() { - if (sPlugin == null) { - return null; - } - - return AdtPrefs.getPrefs().getOsSdkFolder(); - } - - public static String getOsSdkToolsFolder() { - return getOsSdkFolder() + SdkConstants.OS_SDK_TOOLS_FOLDER; - } - - /** - * Returns an image descriptor for the image file at the given - * plug-in relative path - * - * @param path the path - * @return the image descriptor - */ - public static ImageDescriptor getImageDescriptor(String path) { - return imageDescriptorFromPlugin(PLUGIN_ID, path); - } - - /** - * Reads the contents of an {@link IFile} and return it as a String - * - * @param file the file to be read - * @return the String read from the file, or null if there was an error - */ - @SuppressWarnings("resource") // Eclipse doesn't understand Closeables.closeQuietly yet - @Nullable - public static String readFile(@NonNull IFile file) { - InputStream contents = null; - InputStreamReader reader = null; - try { - contents = file.getContents(); - String charset = file.getCharset(); - reader = new InputStreamReader(contents, charset); - return readFile(reader); - } catch (CoreException e) { - // pass -- ignore files we can't read - } catch (IOException e) { - // pass -- ignore files we can't read. - - // Note that IFile.getContents() indicates it throws a CoreException but - // experience shows that if the file does not exists it really throws - // IOException. - // New InputStreamReader() throws UnsupportedEncodingException - // which is handled by this IOException catch. - - } finally { - Closeables.closeQuietly(reader); - Closeables.closeQuietly(contents); - } - - return null; - } - - /** - * Reads the contents of an {@link File} and return it as a String - * - * @param file the file to be read - * @return the String read from the file, or null if there was an error - */ - public static String readFile(File file) { - try { - return readFile(new FileReader(file)); - } catch (FileNotFoundException e) { - AdtPlugin.log(e, "Can't read file %1$s", file); //$NON-NLS-1$ - } - - return null; - } - - /** - * Writes the given content out to the given {@link File}. The file will be deleted if - * it already exists. - * - * @param file the target file - * @param content the content to be written into the file - */ - public static void writeFile(File file, String content) { - if (file.exists()) { - file.delete(); - } - FileWriter fw = null; - try { - fw = new FileWriter(file); - fw.write(content); - } catch (IOException e) { - AdtPlugin.log(e, null); - } finally { - if (fw != null) { - try { - fw.close(); - } catch (IOException e) { - AdtPlugin.log(e, null); - } - } - } - } - - /** - * Returns true iff the given file contains the given String. - * - * @param file the file to look for the string in - * @param string the string to be searched for - * @return true if the file is found and contains the given string anywhere within it - */ - @SuppressWarnings("resource") // Closed by streamContains - public static boolean fileContains(IFile file, String string) { - InputStream contents = null; - try { - contents = file.getContents(); - String charset = file.getCharset(); - return streamContains(new InputStreamReader(contents, charset), string); - } catch (Exception e) { - AdtPlugin.log(e, "Can't read file %1$s", file); //$NON-NLS-1$ - } - - return false; - } - - /** - * Returns true iff the given file contains the given String. - * - * @param file the file to look for the string in - * @param string the string to be searched for - * @return true if the file is found and contains the given string anywhere within it - */ - public static boolean fileContains(File file, String string) { - try { - return streamContains(new FileReader(file), string); - } catch (Exception e) { - AdtPlugin.log(e, "Can't read file %1$s", file); //$NON-NLS-1$ - } - - return false; - } - - /** - * Returns true iff the given input stream contains the given String. - * - * @param r the stream to look for the string in - * @param string the string to be searched for - * @return true if the file is found and contains the given string anywhere within it - */ - public static boolean streamContains(Reader r, String string) { - if (string.length() == 0) { - return true; - } - - PushbackReader reader = null; - try { - reader = new PushbackReader(r, string.length()); - char first = string.charAt(0); - while (true) { - int c = reader.read(); - if (c == -1) { - return false; - } else if (c == first) { - boolean matches = true; - for (int i = 1; i < string.length(); i++) { - c = reader.read(); - if (c == -1) { - return false; - } else if (string.charAt(i) != (char)c) { - matches = false; - // Back up the characters that did not match - reader.backup(i-1); - break; - } - } - if (matches) { - return true; - } - } - } - } catch (Exception e) { - AdtPlugin.log(e, "Can't read stream"); //$NON-NLS-1$ - } finally { - try { - if (reader != null) { - reader.close(); - } - } catch (IOException e) { - AdtPlugin.log(e, "Can't read stream"); //$NON-NLS-1$ - } - } - - return false; - - } - - /** - * A special reader that allows backing up in the input (up to a predefined maximum - * number of characters) - * <p> - * NOTE: This class ONLY works with the {@link #read()} method!! - */ - private static class PushbackReader extends BufferedReader { - /** - * Rolling/circular buffer. Can be a char rather than int since we never store EOF - * in it. - */ - private char[] mStorage; - - /** Points to the head of the queue. When equal to the tail, the queue is empty. */ - private int mHead; - - /** - * Points to the tail of the queue. This will move with each read of the actual - * wrapped reader, and the characters previous to it in the circular buffer are - * the most recently read characters. - */ - private int mTail; - - /** - * Creates a new reader with a given maximum number of backup characters - * - * @param reader the reader to wrap - * @param max the maximum number of characters to allow rollback for - */ - public PushbackReader(Reader reader, int max) { - super(reader); - mStorage = new char[max + 1]; - } - - @Override - public int read() throws IOException { - // Have we backed up? If so we should serve characters - // from the storage - if (mHead != mTail) { - char c = mStorage[mHead]; - mHead = (mHead + 1) % mStorage.length; - return c; - } - assert mHead == mTail; - - // No backup -- read the next character, but stash it into storage - // as well such that we can retrieve it if we must. - int c = super.read(); - mStorage[mHead] = (char) c; - mHead = mTail = (mHead + 1) % mStorage.length; - return c; - } - - /** - * Backs up the reader a given number of characters. The next N reads will yield - * the N most recently read characters prior to this backup. - * - * @param n the number of characters to be backed up - */ - public void backup(int n) { - if (n >= mStorage.length) { - throw new IllegalArgumentException("Exceeded backup limit"); - } - assert n < mStorage.length; - mHead -= n; - if (mHead < 0) { - mHead += mStorage.length; - } - } - } - - /** - * Reads the contents of a {@link ResourceFile} and returns it as a String - * - * @param file the file to be read - * @return the contents as a String, or null if reading failed - */ - public static String readFile(ResourceFile file) { - InputStream contents = null; - try { - contents = file.getFile().getContents(); - return readFile(new InputStreamReader(contents)); - } catch (StreamException e) { - // pass -- ignore files we can't read - } finally { - try { - if (contents != null) { - contents.close(); - } - } catch (IOException e) { - AdtPlugin.log(e, "Can't read layout file"); //$NON-NLS-1$ - } - } - - return null; - } - - /** - * Reads the contents of a {@link Reader} and return it as a String. This - * method will close the input reader. - * - * @param reader the reader to be read from - * @return the String read from reader, or null if there was an error - */ - public static String readFile(Reader reader) { - BufferedReader bufferedReader = null; - try { - bufferedReader = new BufferedReader(reader); - StringBuilder sb = new StringBuilder(2000); - while (true) { - int c = bufferedReader.read(); - if (c == -1) { - return sb.toString(); - } else { - sb.append((char)c); - } - } - } catch (IOException e) { - // pass -- ignore files we can't read - } finally { - try { - if (bufferedReader != null) { - bufferedReader.close(); - } - } catch (IOException e) { - AdtPlugin.log(e, "Can't read input stream"); //$NON-NLS-1$ - } - } - - return null; - } - - /** - * Reads and returns the content of a text file embedded in the plugin jar - * file. - * @param filepath the file path to the text file - * @return null if the file could not be read - */ - public static String readEmbeddedTextFile(String filepath) { - try { - InputStream is = readEmbeddedFileAsStream(filepath); - if (is != null) { - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - try { - String line; - StringBuilder total = new StringBuilder(reader.readLine()); - while ((line = reader.readLine()) != null) { - total.append('\n'); - total.append(line); - } - - return total.toString(); - } finally { - reader.close(); - } - } - } catch (IOException e) { - // we'll just return null - AdtPlugin.log(e, "Failed to read text file '%s'", filepath); //$NON-NLS-1$ - } - - return null; - } - - /** - * Reads and returns the content of a binary file embedded in the plugin jar - * file. - * @param filepath the file path to the text file - * @return null if the file could not be read - */ - public static byte[] readEmbeddedFile(String filepath) { - try { - InputStream is = readEmbeddedFileAsStream(filepath); - if (is != null) { - // create a buffered reader to facilitate reading. - BufferedInputStream stream = new BufferedInputStream(is); - try { - // get the size to read. - int avail = stream.available(); - - // create the buffer and reads it. - byte[] buffer = new byte[avail]; - stream.read(buffer); - - // and return. - return buffer; - } finally { - stream.close(); - } - } - } catch (IOException e) { - // we'll just return null;. - AdtPlugin.log(e, "Failed to read binary file '%s'", filepath); //$NON-NLS-1$ - } - - return null; - } - - /** - * Reads and returns the content of a binary file embedded in the plugin jar - * file. - * @param filepath the file path to the text file - * @return null if the file could not be read - */ - public static InputStream readEmbeddedFileAsStream(String filepath) { - // attempt to read an embedded file - try { - URL url = getEmbeddedFileUrl(AdtConstants.WS_SEP + filepath); - if (url != null) { - return url.openStream(); - } - } catch (MalformedURLException e) { - // we'll just return null. - AdtPlugin.log(e, "Failed to read stream '%s'", filepath); //$NON-NLS-1$ - } catch (IOException e) { - // we'll just return null;. - AdtPlugin.log(e, "Failed to read stream '%s'", filepath); //$NON-NLS-1$ - } - - return null; - } - - /** - * Returns the URL of a binary file embedded in the plugin jar file. - * @param filepath the file path to the text file - * @return null if the file was not found. - */ - public static URL getEmbeddedFileUrl(String filepath) { - Bundle bundle = null; - synchronized (AdtPlugin.class) { - if (sPlugin != null) { - bundle = sPlugin.getBundle(); - } else { - AdtPlugin.log(IStatus.WARNING, "ADT Plugin is missing"); //$NON-NLS-1$ - return null; - } - } - - // attempt to get a file to one of the template. - String path = filepath; - if (!path.startsWith(AdtConstants.WS_SEP)) { - path = AdtConstants.WS_SEP + path; - } - - URL url = bundle.getEntry(path); - - if (url == null) { - AdtPlugin.log(IStatus.INFO, "Bundle file URL not found at path '%s'", path); //$NON-NLS-1$ - } - - return url; - } - - /** - * Displays an error dialog box. This dialog box is ran asynchronously in the ui thread, - * therefore this method can be called from any thread. - * @param title The title of the dialog box - * @param message The error message - */ - public final static void displayError(final String title, final String message) { - // get the current Display - final Display display = getDisplay(); - - // dialog box only run in ui thread.. - display.asyncExec(new Runnable() { - @Override - public void run() { - Shell shell = display.getActiveShell(); - MessageDialog.openError(shell, title, message); - } - }); - } - - /** - * Displays a warning dialog box. This dialog box is ran asynchronously in the ui thread, - * therefore this method can be called from any thread. - * @param title The title of the dialog box - * @param message The warning message - */ - public final static void displayWarning(final String title, final String message) { - // get the current Display - final Display display = getDisplay(); - - // dialog box only run in ui thread.. - display.asyncExec(new Runnable() { - @Override - public void run() { - Shell shell = display.getActiveShell(); - MessageDialog.openWarning(shell, title, message); - } - }); - } - - /** - * Display a yes/no question dialog box. This dialog is opened synchronously in the ui thread, - * therefore this message can be called from any thread. - * @param title The title of the dialog box - * @param message The error message - * @return true if OK was clicked. - */ - public final static boolean displayPrompt(final String title, final String message) { - // get the current Display and Shell - final Display display = getDisplay(); - - // we need to ask the user what he wants to do. - final boolean[] result = new boolean[1]; - display.syncExec(new Runnable() { - @Override - public void run() { - Shell shell = display.getActiveShell(); - result[0] = MessageDialog.openQuestion(shell, title, message); - } - }); - return result[0]; - } - - /** - * Logs a message to the default Eclipse log. - * - * @param severity The severity code. Valid values are: {@link IStatus#OK}, - * {@link IStatus#ERROR}, {@link IStatus#INFO}, {@link IStatus#WARNING} or - * {@link IStatus#CANCEL}. - * @param format The format string, like for {@link String#format(String, Object...)}. - * @param args The arguments for the format string, like for - * {@link String#format(String, Object...)}. - */ - public static void log(int severity, String format, Object ... args) { - if (format == null) { - return; - } - - String message = String.format(format, args); - Status status = new Status(severity, PLUGIN_ID, message); - - if (getDefault() != null) { - getDefault().getLog().log(status); - } else { - // During UnitTests, we generally don't have a plugin object. It's ok - // to log to stdout or stderr in this case. - (severity < IStatus.ERROR ? System.out : System.err).println(status.toString()); - } - } - - /** - * Logs an exception to the default Eclipse log. - * <p/> - * The status severity is always set to ERROR. - * - * @param exception the exception to log. - * @param format The format string, like for {@link String#format(String, Object...)}. - * @param args The arguments for the format string, like for - * {@link String#format(String, Object...)}. - */ - public static void log(Throwable exception, String format, Object ... args) { - String message = null; - if (format != null) { - message = String.format(format, args); - } else { - message = ""; - } - Status status = new Status(IStatus.ERROR, PLUGIN_ID, message, exception); - - if (getDefault() != null) { - getDefault().getLog().log(status); - } else { - // During UnitTests, we generally don't have a plugin object. It's ok - // to log to stderr in this case. - System.err.println(status.toString()); - } - } - - /** - * This is a mix between log(Throwable) and printErrorToConsole. - * <p/> - * This logs the exception with an ERROR severity and the given printf-like format message. - * The same message is then printed on the Android error console with the associated tag. - * - * @param exception the exception to log. - * @param format The format string, like for {@link String#format(String, Object...)}. - * @param args The arguments for the format string, like for - * {@link String#format(String, Object...)}. - */ - public static synchronized void logAndPrintError(Throwable exception, String tag, - String format, Object ... args) { - if (sPlugin != null) { - String message = String.format(format, args); - Status status = new Status(IStatus.ERROR, PLUGIN_ID, message, exception); - getDefault().getLog().log(status); - printToStream(sPlugin.mAndroidConsoleErrorStream, tag, message); - showAndroidConsole(); - } - } - - /** - * Prints one or more error message to the android console. - * @param tag A tag to be associated with the message. Can be null. - * @param objects the objects to print through their <code>toString</code> method. - */ - public static synchronized void printErrorToConsole(String tag, Object... objects) { - if (sPlugin != null) { - printToStream(sPlugin.mAndroidConsoleErrorStream, tag, objects); - - showAndroidConsole(); - } - } - - /** - * Prints one or more error message to the android console. - * @param objects the objects to print through their <code>toString</code> method. - */ - public static void printErrorToConsole(Object... objects) { - printErrorToConsole((String)null, objects); - } - - /** - * Prints one or more error message to the android console. - * @param project The project to which the message is associated. Can be null. - * @param objects the objects to print through their <code>toString</code> method. - */ - public static void printErrorToConsole(IProject project, Object... objects) { - String tag = project != null ? project.getName() : null; - printErrorToConsole(tag, objects); - } - - /** - * Prints one or more build messages to the android console, filtered by Build output verbosity. - * @param level {@link BuildVerbosity} level of the message. - * @param project The project to which the message is associated. Can be null. - * @param objects the objects to print through their <code>toString</code> method. - * @see BuildVerbosity#ALWAYS - * @see BuildVerbosity#NORMAL - * @see BuildVerbosity#VERBOSE - */ - public static synchronized void printBuildToConsole(BuildVerbosity level, IProject project, - Object... objects) { - if (sPlugin != null) { - if (level.getLevel() <= AdtPrefs.getPrefs().getBuildVerbosity().getLevel()) { - String tag = project != null ? project.getName() : null; - printToStream(sPlugin.mAndroidConsoleStream, tag, objects); - } - } - } - - /** - * Prints one or more message to the android console. - * @param tag The tag to be associated with the message. Can be null. - * @param objects the objects to print through their <code>toString</code> method. - */ - public static synchronized void printToConsole(String tag, Object... objects) { - if (sPlugin != null) { - printToStream(sPlugin.mAndroidConsoleStream, tag, objects); - } - } - - /** - * Prints one or more message to the android console. - * @param project The project to which the message is associated. Can be null. - * @param objects the objects to print through their <code>toString</code> method. - */ - public static void printToConsole(IProject project, Object... objects) { - String tag = project != null ? project.getName() : null; - printToConsole(tag, objects); - } - - /** Force the display of the android console */ - public static void showAndroidConsole() { - // first make sure the console is in the workbench - EclipseUiHelper.showView(IConsoleConstants.ID_CONSOLE_VIEW, true); - - // now make sure it's not docked. - ConsolePlugin.getDefault().getConsoleManager().showConsoleView( - AdtPlugin.getDefault().getAndroidConsole()); - } - - /** - * Returns whether the {@link IAndroidTarget}s have been loaded from the SDK. - */ - public final LoadStatus getSdkLoadStatus() { - synchronized (Sdk.getLock()) { - return mSdkLoadedStatus; - } - } - - /** - * Sets the given {@link IJavaProject} to have its target resolved again once the SDK finishes - * to load. - */ - public final void setProjectToResolve(IJavaProject javaProject) { - synchronized (Sdk.getLock()) { - mPostLoadProjectsToResolve.add(javaProject); - } - } - - /** - * Sets the given {@link IJavaProject} to have its target checked for consistency - * once the SDK finishes to load. This is used if the target is resolved using cached - * information while the SDK is loading. - */ - public final void setProjectToCheck(IJavaProject javaProject) { - // only lock on - synchronized (Sdk.getLock()) { - mPostLoadProjectsToCheck.add(javaProject); - } - } - - /** - * Checks the location of the SDK in the prefs is valid. - * If it is not, display a warning dialog to the user and try to display - * some useful link to fix the situation (setup the preferences, perform an - * update, etc.) - * - * @return True if the SDK location points to an SDK. - * If false, the user has already been presented with a modal dialog explaining that. - */ - public boolean checkSdkLocationAndId() { - String sdkLocation = AdtPrefs.getPrefs().getOsSdkFolder(); - - return checkSdkLocationAndId(sdkLocation, new CheckSdkErrorHandler() { - private String mTitle = "Android SDK"; - - /** - * Handle an error, which is the case where the check did not find any SDK. - * This returns false to {@link AdtPlugin#checkSdkLocationAndId()}. - */ - @Override - public boolean handleError(Solution solution, String message) { - displayMessage(solution, message, MessageDialog.ERROR); - return false; - } - - /** - * Handle an warning, which is the case where the check found an SDK - * but it might need to be repaired or is missing an expected component. - * - * This returns true to {@link AdtPlugin#checkSdkLocationAndId()}. - */ - @Override - public boolean handleWarning(Solution solution, String message) { - displayMessage(solution, message, MessageDialog.WARNING); - return true; - } - - private void displayMessage( - final Solution solution, - final String message, - final int dialogImageType) { - final Display disp = getDisplay(); - disp.asyncExec(new Runnable() { - @Override - public void run() { - Shell shell = disp.getActiveShell(); - if (shell == null) { - shell = AdtPlugin.getShell(); - } - if (shell == null) { - return; - } - - String customLabel = null; - switch(solution) { - case OPEN_ANDROID_PREFS: - customLabel = "Open Preferences"; - break; - case OPEN_P2_UPDATE: - customLabel = "Check for Updates"; - break; - case OPEN_SDK_MANAGER: - customLabel = "Open SDK Manager"; - break; - } - - String btnLabels[] = new String[customLabel == null ? 1 : 2]; - btnLabels[0] = customLabel; - btnLabels[btnLabels.length - 1] = IDialogConstants.CLOSE_LABEL; - - MessageDialog dialog = new MessageDialog( - shell, // parent - mTitle, - null, // dialogTitleImage - message, - dialogImageType, - btnLabels, - btnLabels.length - 1); - int index = dialog.open(); - - if (customLabel != null && index == 0) { - switch(solution) { - case OPEN_ANDROID_PREFS: - openAndroidPrefs(); - break; - case OPEN_P2_UPDATE: - openP2Update(); - break; - case OPEN_SDK_MANAGER: - openSdkManager(); - break; - } - } - } - }); - } - - private void openSdkManager() { - // Open the standalone external SDK Manager since we know - // that ADT on Windows is bound to be locking some SDK folders. - // - // Also when this is invoked because SdkManagerAction.run() fails, this - // test will fail and we'll fallback on using the internal one. - if (SdkManagerAction.openExternalSdkManager()) { - return; - } - - // Otherwise open the regular SDK Manager bundled within ADT - if (!SdkManagerAction.openAdtSdkManager()) { - // We failed because the SDK location is undefined. In this case - // let's open the preferences instead. - openAndroidPrefs(); - } - } - - private void openP2Update() { - Display disp = getDisplay(); - if (disp == null) { - return; - } - disp.asyncExec(new Runnable() { - @Override - public void run() { - String cmdId = "org.eclipse.equinox.p2.ui.sdk.update"; //$NON-NLS-1$ - IWorkbench wb = PlatformUI.getWorkbench(); - if (wb == null) { - return; - } - - ICommandService cs = (ICommandService) wb.getService(ICommandService.class); - IHandlerService is = (IHandlerService) wb.getService(IHandlerService.class); - if (cs == null || is == null) { - return; - } - - Command cmd = cs.getCommand(cmdId); - if (cmd != null && cmd.isDefined()) { - try { - is.executeCommand(cmdId, null/*event*/); - } catch (Exception ignore) { - AdtPlugin.log(ignore, "Failed to execute command %s", cmdId); - } - } - } - }); - } - - private void openAndroidPrefs() { - PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn( - getDisplay().getActiveShell(), - "com.android.ide.eclipse.preferences.main", //$NON-NLS-1$ preferencePageId - null, // displayedIds - null); // data - dialog.open(); - } - }); - } - - /** - * Internal helper to perform the actual sdk location and id check. - * <p/> - * This is useful for callers who want to override what happens when the check - * fails. Otherwise consider calling {@link #checkSdkLocationAndId()} that will - * present a modal dialog to the user in case of failure. - * - * @param osSdkLocation The sdk directory, an OS path. Can be null. - * @param errorHandler An checkSdkErrorHandler that can display a warning or an error. - * @return False if there was an error or the result from the errorHandler invocation. - */ - public boolean checkSdkLocationAndId(@Nullable String osSdkLocation, - @NonNull CheckSdkErrorHandler errorHandler) { - if (osSdkLocation == null || osSdkLocation.trim().length() == 0) { - return errorHandler.handleError( - Solution.OPEN_ANDROID_PREFS, - "Location of the Android SDK has not been setup in the preferences."); - } - - if (!osSdkLocation.endsWith(File.separator)) { - osSdkLocation = osSdkLocation + File.separator; - } - - File osSdkFolder = new File(osSdkLocation); - if (osSdkFolder.isDirectory() == false) { - return errorHandler.handleError( - Solution.OPEN_ANDROID_PREFS, - String.format(Messages.Could_Not_Find_Folder, osSdkLocation)); - } - - String osTools = osSdkLocation + SdkConstants.OS_SDK_TOOLS_FOLDER; - File toolsFolder = new File(osTools); - if (toolsFolder.isDirectory() == false) { - return errorHandler.handleError( - Solution.OPEN_ANDROID_PREFS, - String.format(Messages.Could_Not_Find_Folder_In_SDK, - SdkConstants.FD_TOOLS, osSdkLocation)); - } - - // first check the min plug-in requirement as its error message is easier to figure - // out for the user - if (VersionCheck.checkVersion(osSdkLocation, errorHandler) == false) { - return false; - } - - // check that we have both the tools component and the platform-tools component. - String platformTools = osSdkLocation + SdkConstants.OS_SDK_PLATFORM_TOOLS_FOLDER; - if (checkFolder(platformTools) == false) { - return errorHandler.handleWarning( - Solution.OPEN_SDK_MANAGER, - "SDK Platform Tools component is missing!\n" + - "Please use the SDK Manager to install it."); - } - - String tools = osSdkLocation + SdkConstants.OS_SDK_TOOLS_FOLDER; - if (checkFolder(tools) == false) { - return errorHandler.handleError( - Solution.OPEN_SDK_MANAGER, - "SDK Tools component is missing!\n" + - "Please use the SDK Manager to install it."); - } - - // check the path to various tools we use to make sure nothing is missing. This is - // not meant to be exhaustive. - String[] filesToCheck = new String[] { - osSdkLocation + getOsRelativeAdb(), - osSdkLocation + getOsRelativeEmulator() - }; - for (String file : filesToCheck) { - if (checkFile(file) == false) { - return errorHandler.handleError( - Solution.OPEN_ANDROID_PREFS, - String.format(Messages.Could_Not_Find, file)); - } - } - - return true; - } - - /** - * Checks if a path reference a valid existing file. - * @param osPath the os path to check. - * @return true if the file exists and is, in fact, a file. - */ - private boolean checkFile(String osPath) { - File file = new File(osPath); - if (file.isFile() == false) { - return false; - } - - return true; - } - - /** - * Checks if a path reference a valid existing folder. - * @param osPath the os path to check. - * @return true if the folder exists and is, in fact, a folder. - */ - private boolean checkFolder(String osPath) { - File file = new File(osPath); - if (file.isDirectory() == false) { - return false; - } - - return true; - } - - /** - * Parses the SDK resources. - */ - private void parseSdkContent(long delay) { - // Perform the update in a thread (here an Eclipse runtime job) - // since this should never block the caller (especially the start method) - Job job = new Job(Messages.AdtPlugin_Android_SDK_Content_Loader) { - @SuppressWarnings("unchecked") - @Override - protected IStatus run(IProgressMonitor monitor) { - try { - - if (mParseSdkContentIsRunning) { - return new Status(IStatus.WARNING, PLUGIN_ID, - "An Android SDK is already being loaded. Please try again later."); - } - - mParseSdkContentIsRunning = true; - - SubMonitor progress = SubMonitor.convert(monitor, - "Initialize SDK Manager", 100); - - Sdk sdk = Sdk.loadSdk(AdtPrefs.getPrefs().getOsSdkFolder()); - - if (sdk != null) { - ArrayList<IJavaProject> list = new ArrayList<IJavaProject>(); - synchronized (Sdk.getLock()) { - mSdkLoadedStatus = LoadStatus.LOADED; - - progress.setTaskName("Check Projects"); - - for (IJavaProject javaProject : mPostLoadProjectsToResolve) { - IProject iProject = javaProject.getProject(); - if (iProject.isOpen()) { - // project that have been resolved before the sdk was loaded - // will have a ProjectState where the IAndroidTarget is null - // so we load the target now that the SDK is loaded. - sdk.loadTargetAndBuildTools(Sdk.getProjectState(iProject)); - list.add(javaProject); - } - } - - // done with this list. - mPostLoadProjectsToResolve.clear(); - } - - // check the projects that need checking. - // The method modifies the list (it removes the project that - // do not need to be resolved again). - AndroidClasspathContainerInitializer.checkProjectsCache( - mPostLoadProjectsToCheck); - - list.addAll(mPostLoadProjectsToCheck); - - // update the project that needs recompiling. - if (list.size() > 0) { - IJavaProject[] array = list.toArray( - new IJavaProject[list.size()]); - ProjectHelper.updateProjects(array); - } - - progress.worked(10); - } else { - // SDK failed to Load! - // Sdk#loadSdk() has already displayed an error. - synchronized (Sdk.getLock()) { - mSdkLoadedStatus = LoadStatus.FAILED; - } - } - - // Notify resource changed listeners - progress.setTaskName("Refresh UI"); - progress.setWorkRemaining(mTargetChangeListeners.size()); - - // Clone the list before iterating, to avoid ConcurrentModification - // exceptions - final List<ITargetChangeListener> listeners = - (List<ITargetChangeListener>)mTargetChangeListeners.clone(); - final SubMonitor progress2 = progress; - AdtPlugin.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - for (ITargetChangeListener listener : listeners) { - try { - listener.onSdkLoaded(); - } catch (Exception e) { - AdtPlugin.log(e, "Failed to update a TargetChangeListener."); //$NON-NLS-1$ - } finally { - progress2.worked(1); - } - } - } - }); - } catch (Throwable t) { - log(t, "Unknown exception in parseSdkContent."); //$NON-NLS-1$ - return new Status(IStatus.ERROR, PLUGIN_ID, - "parseSdkContent failed", t); //$NON-NLS-1$ - - } finally { - mParseSdkContentIsRunning = false; - if (monitor != null) { - monitor.done(); - } - } - - return Status.OK_STATUS; - } - }; - job.setPriority(Job.BUILD); // build jobs are run after other interactive jobs - job.setRule(ResourcesPlugin.getWorkspace().getRoot()); - if (delay > 0) { - job.schedule(delay); - } else { - job.schedule(); - } - } - - /** Returns the global android console */ - public MessageConsole getAndroidConsole() { - return mAndroidConsole; - } - - // ----- Methods for Editors ------- - - public void startEditors() { - sAndroidLogoDesc = imageDescriptorFromPlugin(AdtPlugin.PLUGIN_ID, - "/icons/android.png"); //$NON-NLS-1$ - sAndroidLogo = sAndroidLogoDesc.createImage(); - - // Add a resource listener to handle compiled resources. - IWorkspace ws = ResourcesPlugin.getWorkspace(); - mResourceMonitor = GlobalProjectMonitor.startMonitoring(ws); - - if (mResourceMonitor != null) { - try { - setupEditors(mResourceMonitor); - ResourceManager.setup(mResourceMonitor); - LintDeltaProcessor.startListening(mResourceMonitor); - } catch (Throwable t) { - log(t, "ResourceManager.setup failed"); //$NON-NLS-1$ - } - } - } - - /** - * The <code>AbstractUIPlugin</code> implementation of this <code>Plugin</code> - * method saves this plug-in's preference and dialog stores and shuts down - * its image registry (if they are in use). Subclasses may extend this - * method, but must send super <b>last</b>. A try-finally statement should - * be used where necessary to ensure that <code>super.shutdown()</code> is - * always done. - * - * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) - */ - public void stopEditors() { - sAndroidLogo.dispose(); - - IconFactory.getInstance().dispose(); - - LintDeltaProcessor.stopListening(mResourceMonitor); - - // Remove the resource listener that handles compiled resources. - IWorkspace ws = ResourcesPlugin.getWorkspace(); - GlobalProjectMonitor.stopMonitoring(ws); - - if (mRed != null) { - mRed.dispose(); - mRed = null; - } - } - - /** - * Returns an Image for the small Android logo. - * - * Callers should not dispose it. - */ - public static Image getAndroidLogo() { - return sAndroidLogo; - } - - /** - * Returns an {@link ImageDescriptor} for the small Android logo. - * - * Callers should not dispose it. - */ - public static ImageDescriptor getAndroidLogoDesc() { - return sAndroidLogoDesc; - } - - /** - * Returns the ResourceMonitor object. - */ - public GlobalProjectMonitor getResourceMonitor() { - return mResourceMonitor; - } - - /** - * Sets up the editor resource listener. - * <p> - * The listener handles: - * <ul> - * <li> Discovering newly created files, and ensuring that if they are in an Android - * project, they default to the right XML editor. - * <li> Discovering deleted files, and closing the corresponding editors if necessary. - * This is only done for XML files, since other editors such as Java editors handles - * it on their own. - * <ul> - * - * This is called by the {@link AdtPlugin} during initialization. - * - * @param monitor The main Resource Monitor object. - */ - public void setupEditors(GlobalProjectMonitor monitor) { - monitor.addFileListener(new IFileListener() { - @Override - public void fileChanged(@NonNull IFile file, @NonNull IMarkerDelta[] markerDeltas, - int kind, @Nullable String extension, int flags, boolean isAndroidProject) { - if (!isAndroidProject) { - return; - } - if (flags == IResourceDelta.MARKERS || !SdkConstants.EXT_XML.equals(extension)) { - // ONLY the markers changed, or not XML file: not relevant to this listener - return; - } - - if (kind == IResourceDelta.REMOVED) { - AdtUtils.closeEditors(file, false /*save*/); - return; - } - - // The resources files must have a file path similar to - // project/res/.../*.xml - // There is no support for sub folders, so the segment count must be 4 - if (file.getFullPath().segmentCount() == 4) { - // check if we are inside the res folder. - String segment = file.getFullPath().segment(1); - if (segment.equalsIgnoreCase(SdkConstants.FD_RESOURCES)) { - // we are inside a res/ folder, get the ResourceFolderType of the - // parent folder. - String[] folderSegments = file.getParent().getName().split( - SdkConstants.RES_QUALIFIER_SEP); - - // get the enum for the resource type. - ResourceFolderType type = ResourceFolderType.getTypeByName( - folderSegments[0]); - - if (type != null) { - if (kind == IResourceDelta.ADDED) { - // A new file {@code /res/type-config/some.xml} was added. - // All the /res XML files are handled by the same common editor now. - IDE.setDefaultEditor(file, CommonXmlEditor.ID); - } - } else { - // if the res folder is null, this means the name is invalid, - // in this case we remove whatever android editors that was set - // as the default editor. - IEditorDescriptor desc = IDE.getDefaultEditor(file); - String editorId = desc.getId(); - if (editorId.startsWith(AdtConstants.EDITORS_NAMESPACE)) { - // reset the default editor. - IDE.setDefaultEditor(file, null); - } - } - } - } - } - }, IResourceDelta.ADDED | IResourceDelta.REMOVED); - - monitor.addProjectListener(new IProjectListener() { - @Override - public void projectClosed(IProject project) { - // Close any editors referencing this project - AdtUtils.closeEditors(project, true /*save*/); - } - - @Override - public void projectDeleted(IProject project) { - // Close any editors referencing this project - AdtUtils.closeEditors(project, false /*save*/); - } - - @Override - public void projectOpenedWithWorkspace(IProject project) { - } - - @Override - public void allProjectsOpenedWithWorkspace() { - } - - @Override - public void projectOpened(IProject project) { - } - - @Override - public void projectRenamed(IProject project, IPath from) { - } - }); - } - - /** - * Adds a new {@link ITargetChangeListener} to be notified when a new SDK is loaded, or when - * a project has its target changed. - */ - public void addTargetListener(ITargetChangeListener listener) { - mTargetChangeListeners.add(listener); - } - - /** - * Removes an existing {@link ITargetChangeListener}. - * @see #addTargetListener(ITargetChangeListener) - */ - public void removeTargetListener(ITargetChangeListener listener) { - mTargetChangeListeners.remove(listener); - } - - /** - * Updates all the {@link ITargetChangeListener}s that a target has changed for a given project. - * <p/>Only editors related to that project should reload. - */ - @SuppressWarnings("unchecked") - public void updateTargetListeners(final IProject project) { - final List<ITargetChangeListener> listeners = - (List<ITargetChangeListener>)mTargetChangeListeners.clone(); - - AdtPlugin.getDisplay().asyncExec(new Runnable() { - @Override - public void run() { - for (ITargetChangeListener listener : listeners) { - try { - listener.onProjectTargetChange(project); - } catch (Exception e) { - AdtPlugin.log(e, "Failed to update a TargetChangeListener."); //$NON-NLS-1$ - } - } - } - }); - } - - /** - * Updates all the {@link ITargetChangeListener}s that a target data was loaded. - * <p/>Only editors related to a project using this target should reload. - */ - @SuppressWarnings("unchecked") - public void updateTargetListeners(final IAndroidTarget target) { - final List<ITargetChangeListener> listeners = - (List<ITargetChangeListener>)mTargetChangeListeners.clone(); - - Display display = AdtPlugin.getDisplay(); - if (display == null || display.isDisposed()) { - return; - } - display.asyncExec(new Runnable() { - @Override - public void run() { - for (ITargetChangeListener listener : listeners) { - try { - listener.onTargetLoaded(target); - } catch (Exception e) { - AdtPlugin.log(e, "Failed to update a TargetChangeListener."); //$NON-NLS-1$ - } - } - } - }); - } - - public static synchronized OutputStream getOutStream() { - return sPlugin.mAndroidConsoleStream; - } - - public static synchronized OutputStream getErrorStream() { - return sPlugin.mAndroidConsoleErrorStream; - } - - /** - * Sets the named persistent property for the given file to the given value - * - * @param file the file to associate the property with - * @param qname the name of the property - * @param value the new value, or null to clear the property - */ - public static void setFileProperty(IFile file, QualifiedName qname, String value) { - try { - file.setPersistentProperty(qname, value); - } catch (CoreException e) { - log(e, "Cannot set property %1$s to %2$s", qname, value); - } - } - - /** - * Gets the named persistent file property from the given file - * - * @param file the file to look up properties for - * @param qname the name of the property to look up - * @return the property value, or null - */ - public static String getFileProperty(IFile file, QualifiedName qname) { - try { - return file.getPersistentProperty(qname); - } catch (CoreException e) { - log(e, "Cannot get property %1$s", qname); - } - - return null; - } - - /** - * Conditionally reparses the content of the SDK if it has changed on-disk - * and updates opened projects. - * <p/> - * The operation is asynchronous and happens in a background eclipse job. - * <p/> - * This operation is called in multiple places and should be reasonably - * cheap and conservative. The goal is to automatically refresh the SDK - * when it is obvious it has changed so when not sure the code should - * tend to not reload and avoid reloading too often (which is an expensive - * operation that has a lot of user impact.) - */ - public void refreshSdk() { - // SDK can't have changed if we haven't loaded it yet. - final Sdk sdk = Sdk.getCurrent(); - if (sdk == null) { - return; - } - - Job job = new Job("Check Android SDK") { - @Override - protected IStatus run(IProgressMonitor monitor) { - // SDK has changed if its location path is different. - File location = sdk.getSdkFileLocation(); - boolean changed = location == null || !location.isDirectory(); - - if (!changed) { - assert location != null; - File prefLocation = new File(AdtPrefs.getPrefs().getOsSdkFolder()); - changed = !location.equals(prefLocation); - - if (changed) { - // Basic file path comparison indicates they are not the same. - // Let's dig a bit deeper. - try { - location = location.getCanonicalFile(); - prefLocation = prefLocation.getCanonicalFile(); - changed = !location.equals(prefLocation); - } catch (IOException ignore) { - // There's no real reason for the canonicalization to fail - // if the paths map to actual directories. And if they don't - // this should have been caught above. - } - } - } - - if (!changed) { - // Check whether the target directories has potentially changed. - changed = sdk.haveTargetsChanged(); - } - - if (changed) { - monitor.setTaskName("Reload Android SDK"); - reparseSdk(); - } - - monitor.done(); - return Status.OK_STATUS; - } - }; - job.setRule(ResourcesPlugin.getWorkspace().getRoot()); - job.setPriority(Job.SHORT); // a short background job, not interactive. - job.schedule(); - } - - /** - * Reparses the content of the SDK and updates opened projects. - * The operation is asynchronous and happens in a background eclipse job. - * <p/> - * This reloads the SDK all the time. To only perform this when it has potentially - * changed, call {@link #refreshSdk()} instead. - */ - public void reparseSdk() { - // add all the opened Android projects to the list of projects to be updated - // after the SDK is reloaded - synchronized (Sdk.getLock()) { - // get the project to refresh. - IJavaProject[] androidProjects = BaseProjectHelper.getAndroidProjects(null /*filter*/); - mPostLoadProjectsToResolve.addAll(Arrays.asList(androidProjects)); - } - - // parse the SDK resources at the new location - parseSdkContent(0 /*immediately*/); - } - - /** - * Prints messages, associated with a project to the specified stream - * @param stream The stream to write to - * @param tag The tag associated to the message. Can be null - * @param objects The objects to print through their toString() method (or directly for - * {@link String} objects. - */ - public static synchronized void printToStream(MessageConsoleStream stream, String tag, - Object... objects) { - String dateTag = AndroidPrintStream.getMessageTag(tag); - - for (Object obj : objects) { - stream.print(dateTag); - stream.print(" "); //$NON-NLS-1$ - if (obj instanceof String) { - stream.println((String)obj); - } else if (obj == null) { - stream.println("(null)"); //$NON-NLS-1$ - } else { - stream.println(obj.toString()); - } - } - } - - // --------- ILogger methods ----------- - - @Override - public void error(@Nullable Throwable t, @Nullable String format, Object... args) { - if (t != null) { - log(t, format, args); - } else { - log(IStatus.ERROR, format, args); - } - } - - @Override - public void info(@NonNull String format, Object... args) { - log(IStatus.INFO, format, args); - } - - @Override - public void verbose(@NonNull String format, Object... args) { - log(IStatus.INFO, format, args); - } - - @Override - public void warning(@NonNull String format, Object... args) { - log(IStatus.WARNING, format, args); - } - - /** - * Opens the given URL in a browser tab - * - * @param url the URL to open in a browser - */ - public static void openUrl(URL url) { - IWorkbenchBrowserSupport support = PlatformUI.getWorkbench().getBrowserSupport(); - IWebBrowser browser; - try { - browser = support.createBrowser(PLUGIN_ID); - browser.openURL(url); - } catch (PartInitException e) { - log(e, null); - } - } - - /** - * Opens a Java class for the given fully qualified class name - * - * @param project the project containing the class - * @param fqcn the fully qualified class name of the class to be opened - * @return true if the class was opened, false otherwise - */ - public static boolean openJavaClass(IProject project, String fqcn) { - if (fqcn == null) { - return false; - } - - // Handle inner classes - if (fqcn.indexOf('$') != -1) { - fqcn = fqcn.replaceAll("\\$", "."); //$NON-NLS-1$ //$NON-NLS-2$ - } - - try { - if (project.hasNature(JavaCore.NATURE_ID)) { - IJavaProject javaProject = JavaCore.create(project); - IJavaElement result = javaProject.findType(fqcn); - if (result != null) { - return JavaUI.openInEditor(result) != null; - } - } - } catch (Throwable e) { - log(e, "Can't open class %1$s", fqcn); //$NON-NLS-1$ - } - - return false; - } - - /** - * For a stack trace entry, specifying a class, method, and optionally - * fileName and line number, open the corresponding line in the editor. - * - * @param fqcn the fully qualified name of the class - * @param method the method name - * @param fileName the file name, or null - * @param lineNumber the line number or -1 - * @return true if the target location could be opened, false otherwise - */ - public static boolean openStackTraceLine(@Nullable String fqcn, - @Nullable String method, @Nullable String fileName, int lineNumber) { - return new SourceRevealer().revealMethod(fqcn + '.' + method, fileName, lineNumber, null); - } - - /** - * Opens the given file and shows the given (optional) region in the editor (or - * if no region is specified, opens the editor tab.) - * - * @param file the file to be opened - * @param region an optional region which if set will be selected and shown to the - * user - * @throws PartInitException if something goes wrong - */ - public static void openFile(IFile file, IRegion region) throws PartInitException { - openFile(file, region, true); - } - - // TODO: Make an openEditor which does the above, and make the above pass false for showEditor - - /** - * Opens the given file and shows the given (optional) region - * - * @param file the file to be opened - * @param region an optional region which if set will be selected and shown to the - * user - * @param showEditorTab if true, front the editor tab after opening the file - * @return the editor that was opened, or null if no editor was opened - * @throws PartInitException if something goes wrong - */ - public static IEditorPart openFile(IFile file, IRegion region, boolean showEditorTab) - throws PartInitException { - IWorkbenchPage page = AdtUtils.getActiveWorkbenchPage(); - if (page == null) { - return null; - } - IEditorPart targetEditor = IDE.openEditor(page, file, true); - if (targetEditor instanceof AndroidXmlEditor) { - AndroidXmlEditor editor = (AndroidXmlEditor) targetEditor; - if (region != null) { - editor.show(region.getOffset(), region.getLength(), showEditorTab); - } else if (showEditorTab) { - editor.setActivePage(AndroidXmlEditor.TEXT_EDITOR_ID); - } - } else if (targetEditor instanceof AbstractTextEditor) { - AbstractTextEditor editor = (AbstractTextEditor) targetEditor; - if (region != null) { - editor.setHighlightRange(region.getOffset(), region.getLength(), - true /* moveCursor*/); - } - } - - return targetEditor; - } -} |