aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
diff options
context:
space:
mode:
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.java2045
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;
- }
-}