FileDocCategorySizeDatePackage
AdtPlugin.javaAPI DocAndroid 1.5 API56319Wed May 06 22:41:10 BST 2009com.android.ide.eclipse.adt

AdtPlugin

public class AdtPlugin extends org.eclipse.ui.plugin.AbstractUIPlugin
The activator class controls the plug-in life cycle

Fields Summary
public static final String
PLUGIN_ID
The plug-in ID
public static final String
PREFS_SDK_DIR
public static final String
PREFS_RES_AUTO_REFRESH
public static final String
PREFS_BUILD_VERBOSITY
public static final String
PREFS_DEFAULT_DEBUG_KEYSTORE
public static final String
PREFS_CUSTOM_DEBUG_KEYSTORE
public static final String
PREFS_HOME_PACKAGE
public static final String
PREFS_EMU_OPTIONS
private static AdtPlugin
sPlugin
singleton instance
private static org.eclipse.swt.graphics.Image
sAndroidLogo
private static org.eclipse.jface.resource.ImageDescriptor
sAndroidLogoDesc
private org.eclipse.jface.preference.IPreferenceStore
mStore
default store, provided by eclipse
private String
mOsSdkLocation
cached location for the sdk folder
private org.eclipse.ui.console.MessageConsole
mAndroidConsole
The global android console
private org.eclipse.ui.console.MessageConsoleStream
mAndroidConsoleStream
Stream to write in the android console
private org.eclipse.ui.console.MessageConsoleStream
mAndroidConsoleErrorStream
Stream to write error messages to the android console
private com.android.ide.eclipse.ddms.ImageLoader
mLoader
Image loader object
private int
mBuildVerbosity
Verbosity of the build
private org.eclipse.swt.graphics.Color
mRed
Color used in the error console
private com.android.ide.eclipse.adt.sdk.LoadStatus
mSdkIsLoaded
Load status of the SDK. Any access MUST be in a synchronized(mPostLoadProjects) block
private final ArrayList
mPostLoadProjectsToResolve
Project to update once the SDK is loaded. Any access MUST be in a synchronized(mPostLoadProjectsToResolve) block
private final ArrayList
mPostLoadProjectsToCheck
Project to check validity of cache vs actual once the SDK is loaded. Any access MUST be in a synchronized(mPostLoadProjectsToResolve) block
private com.android.ide.eclipse.editors.resources.manager.ResourceMonitor
mResourceMonitor
private ArrayList
mTargetChangeListeners
protected boolean
mSdkIsLoading
Constructors Summary
public AdtPlugin()
The constructor

        sPlugin = this;
    
Methods Summary
public voidaddTargetListener(com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener listener)
Adds a new {@link ITargetChangeListener} to be notified when a new SDK is loaded, or when a project has its target changed.

        mTargetChangeListeners.add(listener);
    
private booleancheckFile(java.lang.String osPath)
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.

        File file = new File(osPath);
        if (file.isFile() == false) {
            return false;
        }

        return true;
    
private booleancheckSdkLocationAndId()
Checks the location of the SDK is valid and if it is, grab the SDK API version from the SDK.

return
false if the location is not correct.

        if (mOsSdkLocation == null || mOsSdkLocation.length() == 0) {
            displayError(Messages.Dialog_Title_SDK_Location, Messages.SDK_Not_Setup);
            return false;
        }

        return checkSdkLocationAndId(mOsSdkLocation, new CheckSdkErrorHandler() {
            @Override
            public boolean handleError(String message) {
                AdtPlugin.displayError(Messages.Dialog_Title_SDK_Location,
                        String.format(Messages.Error_Check_Prefs, message));
                return false;
            }

            @Override
            public boolean handleWarning(String message) {
                AdtPlugin.displayWarning(Messages.Dialog_Title_SDK_Location, message);
                return true;
            }
        });
    
public booleancheckSdkLocationAndId(java.lang.String osSdkLocation, com.android.ide.eclipse.adt.AdtPlugin$CheckSdkErrorHandler errorHandler)
Internal helper to perform the actual sdk location and id check.

param
osSdkLocation The sdk directory, an OS path.
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.

        if (osSdkLocation.endsWith(File.separator) == false) {
            osSdkLocation = osSdkLocation + File.separator;
        }

        File osSdkFolder = new File(osSdkLocation);
        if (osSdkFolder.isDirectory() == false) {
            return errorHandler.handleError(
                    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(
                    String.format(Messages.Could_Not_Find_Folder_In_SDK,
                            SdkConstants.FD_TOOLS, osSdkLocation));
        }

        // check the path to various tools we use
        String[] filesToCheck = new String[] {
                osSdkLocation + getOsRelativeAdb(),
                osSdkLocation + getOsRelativeEmulator()
        };
        for (String file : filesToCheck) {
            if (checkFile(file) == false) {
                return errorHandler.handleError(String.format(Messages.Could_Not_Find, file));
            }
        }

        // check the SDK build id/version and the plugin version.
        return VersionCheck.checkVersion(osSdkLocation, errorHandler);
    
private org.eclipse.core.runtime.jobs.JobcreatePingUsageServerJob()
Creates a job than can ping the usage server.

        // In order to not block the plugin loading, so we spawn another thread.
        Job job = new Job("Android SDK Ping") {  // Job name, visible in progress view
            @Override
            protected IStatus run(IProgressMonitor monitor) {
                try {

                    // get the version of the plugin
                    String versionString = (String) getBundle().getHeaders().get(
                            Constants.BUNDLE_VERSION);
                    Version version = new Version(versionString);
                    
                    SdkStatsHelper.pingUsageServer("adt", version); //$NON-NLS-1$
                    
                    return Status.OK_STATUS;
                } catch (Throwable t) {
                    log(t, "pingUsageServer failed"); //$NON-NLS-1$
                    return new Status(IStatus.ERROR, PLUGIN_ID,
                            "pingUsageServer failed", t);
                }
            }
        };
        return job;
    
public static final voiddisplayError(java.lang.String title, java.lang.String message)
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

        // get the current Display
        final Display display = getDisplay();

        // dialog box only run in ui thread..
        display.asyncExec(new Runnable() {
            public void run() {
                Shell shell = display.getActiveShell();
                MessageDialog.openError(shell, title, message);
            }
        });
    
public static final booleandisplayPrompt(java.lang.String title, java.lang.String 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.

        // 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() {
            public void run() {
                Shell shell = display.getActiveShell();
                result[0] = MessageDialog.openQuestion(shell, title, message);
            }
        });
        return result[0];
    
public static final voiddisplayWarning(java.lang.String title, java.lang.String 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

        // get the current Display
        final Display display = getDisplay();

        // dialog box only run in ui thread..
        display.asyncExec(new Runnable() {
            public void run() {
                Shell shell = display.getActiveShell();
                MessageDialog.openWarning(shell, title, message);
            }
        });
    
public org.eclipse.ui.console.MessageConsolegetAndroidConsole()
Returns the global android console

        return mAndroidConsole;
    
public static org.eclipse.swt.graphics.ImagegetAndroidLogo()
Returns an Image for the small Android logo. Callers should not dispose it.

        return sAndroidLogo;
    
public static org.eclipse.jface.resource.ImageDescriptorgetAndroidLogoDesc()
Returns an {@link ImageDescriptor} for the small Android logo. Callers should not dispose it.

        return sAndroidLogoDesc;
    
public static synchronized booleangetAutoResRefresh()

        if (sPlugin == null) {
            return false;
        }
        return sPlugin.mStore.getBoolean(PREFS_RES_AUTO_REFRESH);
    
public static synchronized intgetBuildVerbosity()

        if (sPlugin != null) {
            return sPlugin.mBuildVerbosity;
        }
        
        return 0;
    
public static synchronized com.android.ide.eclipse.adt.AdtPlugingetDefault()
Returns the shared instance

return
the shared instance

        return sPlugin;
    
public static org.eclipse.swt.widgets.DisplaygetDisplay()

        IWorkbench bench = null;
        synchronized (AdtPlugin.class) {
            bench = sPlugin.getWorkbench();
        }

        if (bench != null) {
            return bench.getDisplay();
        }
        return null;
    
public static synchronized java.io.PrintStreamgetErrPrintStream(org.eclipse.core.resources.IProject project, java.lang.String prefix)
Returns an error PrintStream object for a specific project.
This PrintStream will add a date/project at the beginning of every println() output.

param
project The project object
param
prefix The prefix to be added to the message. Can be null.
return
a new PrintStream

        if (sPlugin != null) {
            return new AndroidPrintStream(project, prefix, sPlugin.mAndroidConsoleErrorStream);
        }
        
        return null;
    
public static synchronized java.io.OutputStreamgetErrorStream()

        return sPlugin.mAndroidConsoleErrorStream;
    
public static org.eclipse.jface.resource.ImageDescriptorgetImageDescriptor(java.lang.String path)
Returns an image descriptor for the image file at the given plug-in relative path

param
path the path
return
the image descriptor

    	return imageDescriptorFromPlugin(PLUGIN_ID, path);
    
public static synchronized com.android.ide.eclipse.ddms.ImageLoadergetImageLoader()
Return the image loader for the plugin

        if (sPlugin != null) {
            return sPlugin.mLoader;
        }
        return null;
    
public static java.lang.StringgetOsAbsoluteAdb()
Returns the absolute adb path

        return getOsSdkFolder() + getOsRelativeAdb();
    
public static java.lang.StringgetOsAbsoluteEmulator()
Returns the absolute emulator path

        return getOsSdkFolder() + getOsRelativeEmulator();
    
public static java.lang.StringgetOsAbsoluteTraceview()
Returns the absolute traceview path

        return getOsSdkFolder() + SdkConstants.OS_SDK_TOOLS_FOLDER +
                AndroidConstants.FN_TRACEVIEW;
    
public static java.lang.StringgetOsRelativeAdb()
Returns the adb path relative to the sdk folder

        return SdkConstants.OS_SDK_TOOLS_FOLDER + AndroidConstants.FN_ADB;
    
public static java.lang.StringgetOsRelativeEmulator()
Returns the emulator path relative to the sdk folder

        return SdkConstants.OS_SDK_TOOLS_FOLDER + AndroidConstants.FN_EMULATOR;
    
public static synchronized java.lang.StringgetOsSdkFolder()
Returns the SDK folder. Guaranteed to be terminated by a platform-specific path separator.

        if (sPlugin == null) {
            return null;
        }

        if (sPlugin.mOsSdkLocation == null) {
            sPlugin.mOsSdkLocation = sPlugin.mStore.getString(PREFS_SDK_DIR);
        }
        return sPlugin.mOsSdkLocation;
    
public static java.lang.StringgetOsSdkToolsFolder()

        return getOsSdkFolder() + SdkConstants.OS_SDK_TOOLS_FOLDER;
    
public static synchronized java.io.PrintStreamgetOutPrintStream(org.eclipse.core.resources.IProject project, java.lang.String prefix)
Returns an standard PrintStream object for a specific project.
This PrintStream will add a date/project at the beginning of every println() output.

param
project The project object
param
prefix The prefix to be added to the message. Can be null.
return
a new PrintStream

        if (sPlugin != null) {
            return new AndroidPrintStream(project, prefix, sPlugin.mAndroidConsoleStream);
        }
        
        return null;
    
public com.android.ide.eclipse.editors.resources.manager.ResourceMonitorgetResourceMonitor()
Returns the ResourceMonitor object.

        return mResourceMonitor;
    
public final com.android.ide.eclipse.adt.sdk.LoadStatusgetSdkLoadStatus()
Returns whether the Sdk has been loaded.

        synchronized (getSdkLockObject()) {
            return mSdkIsLoaded;
        }
    
public final java.lang.ObjectgetSdkLockObject()
Returns the lock object for SDK loading. If you wish to do things while the SDK is loading, you must synchronize on this object.

        return mPostLoadProjectsToResolve;
    
public static java.lang.StringgetUrlDoc()
Returns a Url file path to the javaDoc folder.

        return ProjectHelper.getJavaDocPath(
                getOsSdkFolder() + AndroidConstants.WS_JAVADOC_FOLDER_LEAF);
    
public static voidlog(int severity, java.lang.String format, java.lang.Object args)
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...)}.

        String message = String.format(format, args);
        Status status = new Status(severity, PLUGIN_ID, message);
        getDefault().getLog().log(status);
    
public static voidlog(java.lang.Throwable exception, java.lang.String format, java.lang.Object args)
Logs an exception to the default Eclipse log.

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...)}.

        String message = String.format(format, args);
        Status status = new Status(IStatus.ERROR, PLUGIN_ID, message, exception);
        getDefault().getLog().log(status);
    
public static synchronized voidlogAndPrintError(java.lang.Throwable exception, java.lang.String tag, java.lang.String format, java.lang.Object args)
This is a mix between log(Throwable) and printErrorToConsole.

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...)}.

        if (sPlugin != null) {
            String message = String.format(format, args);
            Status status = new Status(IStatus.ERROR, PLUGIN_ID, message, exception);
            getDefault().getLog().log(status);
            StreamHelper.printToStream(sPlugin.mAndroidConsoleErrorStream, tag, message);
            showAndroidConsole();
        }
    
private voidparseSdkContent()
Parses the SDK resources.

        // 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 (mSdkIsLoading) {
                        return new Status(IStatus.WARNING, PLUGIN_ID,
                                "An Android SDK is already being loaded. Please try again later.");
                    }
                    
                    mSdkIsLoading = true;
                    
                    SubMonitor progress = SubMonitor.convert(monitor,
                            "Initialize SDK Manager", 100);
                    
                    Sdk sdk = Sdk.loadSdk(mOsSdkLocation);
                    
                    if (sdk != null) {
                        
                        progress.setTaskName(Messages.AdtPlugin_Parsing_Resources);
                        
                        int n = sdk.getTargets().length;
                        if (n > 0) {
                            int w = 60 / n;
                            for (IAndroidTarget target : sdk.getTargets()) {
                                SubMonitor p2 = progress.newChild(w);
                                IStatus status = new AndroidTargetParser(target).run(p2);
                                if (status.getCode() != IStatus.OK) {
                                    synchronized (getSdkLockObject()) {
                                        mSdkIsLoaded = LoadStatus.FAILED;
                                        mPostLoadProjectsToResolve.clear();
                                    }
                                    return status;
                                }
                            }
                        }

                        synchronized (getSdkLockObject()) {
                            mSdkIsLoaded = LoadStatus.LOADED;

                            progress.setTaskName("Check Projects");
                            
                            ArrayList<IJavaProject> list = new ArrayList<IJavaProject>();
                            for (IJavaProject javaProject : mPostLoadProjectsToResolve) {
                                if (javaProject.getProject().isOpen()) {
                                    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()]);
                                AndroidClasspathContainerInitializer.updateProjects(array);
                            }
                            
                            progress.worked(10);
                        }
                    }
                        
                    // Notify resource changed listeners
                    progress.setTaskName("Refresh UI");
                    progress.setWorkRemaining(mTargetChangeListeners.size());
                    
                    // Clone the list before iterating, to avoid Concurrent Modification
                    // exceptions
                    final List<ITargetChangeListener> listeners =
                            (List<ITargetChangeListener>)mTargetChangeListeners.clone();
                    final SubMonitor progress2 = progress;
                    AdtPlugin.getDisplay().syncExec(new Runnable() {
                        public void run() {
                            for (ITargetChangeListener listener : listeners) {
                                try {
                                    listener.onTargetsLoaded();
                                } catch (Exception e) {
                                    AdtPlugin.log(e, "Failed to update a TargetChangeListener.");  //$NON-NLS-1$
                                } finally {
                                    progress2.worked(1);
                                }
                            }
                        }
                    });
                } finally {
                    mSdkIsLoading = false;
                    if (monitor != null) {
                        monitor.done();
                    }
                }

                return Status.OK_STATUS;
            }
        };
        job.setPriority(Job.BUILD); // build jobs are run after other interactive jobs
        job.schedule();
    
public static synchronized voidprintBuildToConsole(int level, org.eclipse.core.resources.IProject project, java.lang.Object objects)
Prints one or more build messages to the android console, filtered by Build output verbosity.

param
level Verbosity 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 toString method.
see
AdtConstants#BUILD_ALWAYS
see
AdtConstants#BUILD_NORMAL
see
AdtConstants#BUILD_VERBOSE

        if (sPlugin != null) {
            if (level <= sPlugin.mBuildVerbosity) {
                String tag = project != null ? project.getName() : null;
                StreamHelper.printToStream(sPlugin.mAndroidConsoleStream, tag, objects);
            }
        }
    
public static synchronized voidprintErrorToConsole(java.lang.String tag, java.lang.Object objects)
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 toString method.

        if (sPlugin != null) {
            StreamHelper.printToStream(sPlugin.mAndroidConsoleErrorStream, tag, objects);
    
            showAndroidConsole();
        }
    
public static voidprintErrorToConsole(java.lang.Object objects)
Prints one or more error message to the android console.

param
objects the objects to print through their toString method.

        printErrorToConsole((String)null, objects);
    
public static voidprintErrorToConsole(org.eclipse.core.resources.IProject project, java.lang.Object 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 toString method.

        String tag = project != null ? project.getName() : null;
        printErrorToConsole(tag, objects);
    
public static synchronized voidprintToConsole(java.lang.String tag, java.lang.Object 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 toString method.

        if (sPlugin != null) {
            StreamHelper.printToStream(sPlugin.mAndroidConsoleStream, tag, objects);
        }
    
public static voidprintToConsole(org.eclipse.core.resources.IProject project, java.lang.Object 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 toString method.

        String tag = project != null ? project.getName() : null;
        printToConsole(tag, objects);
    
public static byte[]readEmbeddedFile(java.lang.String filepath)
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

        Bundle bundle = null;
        synchronized (AdtPlugin.class) {
            if (sPlugin != null) {
                bundle = sPlugin.getBundle();
            } else {
                return null;
            }
        }

        // attempt to get a file to one of the template.
        try {
            URL url = bundle.getEntry(AndroidConstants.WS_SEP + filepath);
            if (url != null) {
                // create a buffered reader to facilitate reading.
                BufferedInputStream stream = new BufferedInputStream(
                        url.openStream());

                // 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;
            }
        } catch (MalformedURLException e) {
            // we'll just return null.
        } catch (IOException e) {
            // we'll just return null;.
        }

        return null;
    
public static java.lang.StringreadEmbeddedTextFile(java.lang.String filepath)
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

        Bundle bundle = null;
        synchronized (AdtPlugin.class) {
            if (sPlugin != null) {
                bundle = sPlugin.getBundle();
            } else {
                return null;
            }
        }
        
        // attempt to get a file to one of the template.
        try {
            URL url = bundle.getEntry(AndroidConstants.WS_SEP + filepath);
            if (url != null) {
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(url.openStream()));

                String line;
                StringBuilder total = new StringBuilder(reader.readLine());
                while ((line = reader.readLine()) != null) {
                    total.append('\n");
                    total.append(line);
                }

                return total.toString();
            }
        } catch (MalformedURLException e) {
            // we'll just return null.
        } catch (IOException e) {
            // we'll just return null.
        }

        return null;
    
public voidremoveTargetListener(com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener listener)
Removes an existing {@link ITargetChangeListener}.

see
#addTargetListener(ITargetChangeListener)

        mTargetChangeListeners.remove(listener);
    
public final voidsetProjectToCheck(org.eclipse.jdt.core.IJavaProject 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.

        // only lock on 
        synchronized (getSdkLockObject()) {
            mPostLoadProjectsToCheck.add(javaProject);
        }
    
public final voidsetProjectToResolve(org.eclipse.jdt.core.IJavaProject javaProject)
Sets the given {@link IJavaProject} to have its target resolved again once the SDK finishes to load.

        synchronized (getSdkLockObject()) {
            mPostLoadProjectsToResolve.add(javaProject);
        }
    
public voidsetupDefaultEditor(com.android.ide.eclipse.editors.resources.manager.ResourceMonitor monitor)
Sets up the editor to register default editors for resource files when needed. This is called by the {@link AdtPlugin} during initialization.

param
monitor The main Resource Monitor object.

        monitor.addFileListener(new IFileListener() {

            private static final String UNKNOWN_EDITOR = "unknown-editor"; //$NON-NLS-1$
            
            /* (non-Javadoc)
             * Sent when a file changed.
             * @param file The file that changed.
             * @param markerDeltas The marker deltas for the file.
             * @param kind The change kind. This is equivalent to
             * {@link IResourceDelta#accept(IResourceDeltaVisitor)}
             * 
             * @see IFileListener#fileChanged
             */
            public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) {
                if (AndroidConstants.EXT_XML.equals(file.getFileExtension())) {
                    // 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 actual ResourceFolder
                            ProjectResources resources = ResourceManager.getInstance().
                                getProjectResources(file.getProject());

                            // This happens when importing old Android projects in Eclipse
                            // that lack the container (probably because resources fail to build
                            // properly.)
                            if (resources == null) {
                                log(IStatus.INFO,
                                        "getProjectResources failed for path %1$s in project %2$s", //$NON-NLS-1$
                                        file.getFullPath().toOSString(),
                                        file.getProject().getName());
                                return;
                            }

                            ResourceFolder resFolder = resources.getResourceFolder(
                                (IFolder)file.getParent());
                        
                            if (resFolder != null) {
                                if (kind == IResourceDelta.ADDED) {
                                    resourceAdded(file, resFolder.getType());
                                } else if (kind == IResourceDelta.CHANGED) {
                                    resourceChanged(file, resFolder.getType());
                                }
                            } 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(AndroidConstants.EDITORS_NAMESPACE)) {
                                    // reset the default editor.
                                    IDE.setDefaultEditor(file, null);
                                }
                            }
                        }
                    }
                }
            }

            private void resourceAdded(IFile file, ResourceFolderType type) {
                // set the default editor based on the type.
                if (type == ResourceFolderType.LAYOUT) {
                    IDE.setDefaultEditor(file, LayoutEditor.ID);
                } else if (type == ResourceFolderType.DRAWABLE
                        || type == ResourceFolderType.VALUES) {
                    IDE.setDefaultEditor(file, ResourcesEditor.ID);
                } else if (type == ResourceFolderType.MENU) {
                    IDE.setDefaultEditor(file, MenuEditor.ID);
                } else if (type == ResourceFolderType.XML) {
                    if (XmlEditor.canHandleFile(file)) {
                        IDE.setDefaultEditor(file, XmlEditor.ID);
                    } else {
                        // set a property to determine later if the XML can be handled
                        QualifiedName qname = new QualifiedName(
                                AdtPlugin.PLUGIN_ID,
                                UNKNOWN_EDITOR);
                        try {
                            file.setPersistentProperty(qname, "1"); //$NON-NLS-1$
                        } catch (CoreException e) {
                            // pass
                        }
                    }
                }
            }

            private void resourceChanged(IFile file, ResourceFolderType type) {
                if (type == ResourceFolderType.XML) {
                    IEditorDescriptor ed = IDE.getDefaultEditor(file);
                    if (ed == null || ed.getId() != XmlEditor.ID) {
                        QualifiedName qname = new QualifiedName(
                                AdtPlugin.PLUGIN_ID,
                                UNKNOWN_EDITOR);
                        String prop = null;
                        try {
                            prop = file.getPersistentProperty(qname);
                        } catch (CoreException e) {
                            // pass
                        }
                        if (prop != null && XmlEditor.canHandleFile(file)) {
                            try {
                                // remove the property & set editor
                                file.setPersistentProperty(qname, null);
                                IWorkbenchPage page = PlatformUI.getWorkbench().
                                                        getActiveWorkbenchWindow().getActivePage();
                                
                                IEditorPart oldEditor = page.findEditor(new FileEditorInput(file));
                                if (oldEditor != null &&
                                        AdtPlugin.displayPrompt("Android XML Editor",
                                            String.format("The file you just saved as been recognized as a file that could be better handled using the Android XML Editor. Do you want to edit '%1$s' using the Android XML editor instead?",
                                                    file.getFullPath()))) {
                                    IDE.setDefaultEditor(file, XmlEditor.ID);
                                    IEditorPart newEditor = page.openEditor(
                                            new FileEditorInput(file),
                                            XmlEditor.ID,
                                            true, /* activate */
                                            IWorkbenchPage.MATCH_NONE);
                                
                                    if (newEditor != null) {
                                        page.closeEditor(oldEditor, true /* save */);
                                    }
                                }
                            } catch (CoreException e) {
                                // setPersistentProperty or page.openEditor may have failed
                            }
                        }
                    }
                }
            }

        }, IResourceDelta.ADDED | IResourceDelta.CHANGED);
    
public static voidshowAndroidConsole()
Force the display of the android console

        // 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());
    
public voidstart(org.osgi.framework.BundleContext context)

        super.start(context);

        Display display = getDisplay();

        // 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();
        mRed = new Color(display, 0xFF, 0x00, 0x00);

        // because this can be run, in some cases, by a non ui thread, and beccause
        // changing the console properties update the ui, we need to make this change
        // in the ui thread.
        display.asyncExec(new Runnable() {
            public void run() {
                mAndroidConsoleErrorStream.setColor(mRed);
            }
        });

        // set up the ddms console to use this objects
        DdmConsole.setConsole(new IDdmConsole() {
            public void printErrorToConsole(String message) {
                AdtPlugin.printErrorToConsole((String)null, message);
            }
            public void printErrorToConsole(String[] messages) {
                AdtPlugin.printErrorToConsole((String)null, (Object[])messages);
            }
            public void printToConsole(String message) {
                AdtPlugin.printToConsole((String)null, message);
            }
            public void printToConsole(String[] messages) {
                AdtPlugin.printToConsole((String)null, (Object[])messages);
            }
        });

        // get the eclipse store
        mStore = getPreferenceStore();

        // set the listener for the preference change
        Preferences prefs = getPluginPreferences();
        prefs.addPropertyChangeListener(new IPropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent event) {
                // get the name of the property that changed.
                String property = event.getProperty();

                // if the SDK changed, we update the cached version
                if (PREFS_SDK_DIR.equals(property)) {

                    // get the new one from the preferences
                    mOsSdkLocation = (String)event.getNewValue();

                    // make sure it ends with a separator
                    if (mOsSdkLocation.endsWith(File.separator) == false) {
                        mOsSdkLocation = mOsSdkLocation + File.separator;
                    }

                    // finally restart adb, in case it's a different version
                    DdmsPlugin.setAdb(getOsAbsoluteAdb(), true /* startAdb */);

                    // get the SDK location and build id.
                    if (checkSdkLocationAndId()) {
                        // if sdk if valid, reparse it
                        
                        // add all the opened Android projects to the list of projects to be updated
                        // after the SDK is reloaded
                        synchronized (getSdkLockObject()) {
                            // get the project to refresh.
                            IJavaProject[] androidProjects = BaseProjectHelper.getAndroidProjects();
                            mPostLoadProjectsToResolve.addAll(Arrays.asList(androidProjects));
                        }
    
                        // parse the SDK resources at the new location
                        parseSdkContent();
                    }
                } else if (PREFS_BUILD_VERBOSITY.equals(property)) {
                    mBuildVerbosity = BuildPreferencePage.getBuildLevel(
                            mStore.getString(PREFS_BUILD_VERBOSITY));
                }
            }
        });

        mOsSdkLocation = mStore.getString(PREFS_SDK_DIR);

        // make sure it ends with a separator. Normally this is done when the preference
        // is set. But to make sure older version still work, we fix it here as well.
        if (mOsSdkLocation.length() > 0 && mOsSdkLocation.endsWith(File.separator) == false) {
            mOsSdkLocation = mOsSdkLocation + File.separator;
        }

        // check the location of SDK
        final boolean isSdkLocationValid = checkSdkLocationAndId();
        
        mBuildVerbosity = BuildPreferencePage.getBuildLevel(
                mStore.getString(PREFS_BUILD_VERBOSITY));

        // create the loader that's able to load the images
        mLoader = new ImageLoader(this);

        // start the DdmsPlugin by setting the adb location, only if it is set already.
        if (mOsSdkLocation.length() > 0) {
            DdmsPlugin.setAdb(getOsAbsoluteAdb(), true);
        }

        // and give it the debug launcher for android projects
        DdmsPlugin.setRunningAppDebugLauncher(new DdmsPlugin.IDebugLauncher() {
            public boolean debug(String appName, int port) {
                // search for an android project matching the process name 
                IProject project = ProjectHelper.findAndroidProjectByAppName(appName);
                if (project != null) {
                    AndroidLaunchController.debugRunningApp(project, port);
                    return true;
                } else {
                    return false;
                }
            }
        });
        
        StackTracePanel.setSourceRevealer(new ISourceRevealer() {
            public void reveal(String applicationName, String className, int line) {
                IProject project = ProjectHelper.findAndroidProjectByAppName(applicationName);
                if (project != null) {
                    BaseProjectHelper.revealSource(project, className, line);
                }
            }
        });
        
        // setup export callback for editors
        ExportHelper.setCallback(new IExportCallback() {
            public void startExportWizard(IProject project) {
                StructuredSelection selection = new StructuredSelection(project);
                
                ExportWizard wizard = new ExportWizard();
                wizard.init(PlatformUI.getWorkbench(), selection);
                WizardDialog dialog = new WizardDialog(getDisplay().getActiveShell(),
                        wizard);
                dialog.open();
            }
        });
        
        // initialize editors
        startEditors();

        // Ping the usage server and parse the SDK content.
        // This is deferred in separate jobs to avoid blocking the bundle start.
        // We also serialize them to avoid too many parallel jobs when Eclipse starts.
        Job pingJob = createPingUsageServerJob();
        pingJob.addJobChangeListener(new JobChangeAdapter() {
           @Override
            public void done(IJobChangeEvent event) {
                super.done(event);
    
                // Once the ping job is finished, start the SDK parser
                if (isSdkLocationValid) {
                    // parse the SDK resources.
                    parseSdkContent();
                }
            } 
        });
        // build jobs are run after other interactive jobs
        pingJob.setPriority(Job.BUILD); 
        // Wait 2 seconds before starting the ping job. This leaves some time to the
        // other bundles to initialize.
        pingJob.schedule(2000 /*milliseconds*/);
    
public voidstartEditors()

        sAndroidLogoDesc = imageDescriptorFromPlugin(AdtPlugin.PLUGIN_ID,
                "/icons/android.png"); //$NON-NLS-1$
        sAndroidLogo = sAndroidLogoDesc.createImage();
        
        // get the stream to write in the android console.
        MessageConsole androidConsole = AdtPlugin.getDefault().getAndroidConsole();
        mAndroidConsoleStream = androidConsole.newMessageStream();

        mAndroidConsoleErrorStream = androidConsole.newMessageStream();
        mRed = new Color(getDisplay(), 0xFF, 0x00, 0x00);

        // because this can be run, in some cases, by a non ui thread, and beccause
        // changing the console properties update the ui, we need to make this change
        // in the ui thread.
        getDisplay().asyncExec(new Runnable() {
            public void run() {
                mAndroidConsoleErrorStream.setColor(mRed);
            }
        });

        // Add a resource listener to handle compiled resources.
        IWorkspace ws = ResourcesPlugin.getWorkspace();
        mResourceMonitor = ResourceMonitor.startMonitoring(ws);

        if (mResourceMonitor != null) {
            try {
                setupDefaultEditor(mResourceMonitor);
                ResourceManager.setup(mResourceMonitor);
            } catch (Throwable t) {
                log(t, "ResourceManager.setup failed"); //$NON-NLS-1$
            }
        }
    
public voidstop(org.osgi.framework.BundleContext context)

        super.stop(context);
        
        stopEditors();
        
        mRed.dispose();
        synchronized (AdtPlugin.class) {
            sPlugin = null;
        }
    
public voidstopEditors()
The AbstractUIPlugin implementation of this Plugin 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 last. A try-finally statement should be used where necessary to ensure that super.shutdown() is always done.

see
org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)

        sAndroidLogo.dispose();
        
        IconFactory.getInstance().Dispose();
        
        // Remove the resource listener that handles compiled resources.
        IWorkspace ws = ResourcesPlugin.getWorkspace();
        ResourceMonitor.stopMonitoring(ws);

        mRed.dispose();
    
public voidupdateTargetListener(org.eclipse.core.resources.IProject project)
Updates all the {@link ITargetChangeListener} that a target has changed for a given project.

Only editors related to that project should reload.

        final List<ITargetChangeListener> listeners =
            (List<ITargetChangeListener>)mTargetChangeListeners.clone();

        AdtPlugin.getDisplay().asyncExec(new Runnable() {
            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$
                    }
                }
            }
        });