com.motorola.studio.android.emulator.ui.view.AbstractAndroidView.java Source code

Java tutorial

Introduction

Here is the source code for com.motorola.studio.android.emulator.ui.view.AbstractAndroidView.java

Source

/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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.motorola.studio.android.emulator.ui.view;

import static com.motorola.studio.android.common.log.StudioLogger.debug;
import static com.motorola.studio.android.common.log.StudioLogger.error;
import static com.motorola.studio.android.common.log.StudioLogger.info;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.osgi.util.NLS;
import org.eclipse.sequoyah.device.framework.model.IInstance;
import org.eclipse.sequoyah.vnc.protocol.PluginProtocolActionDelegate;
import org.eclipse.sequoyah.vnc.protocol.lib.ProtocolHandle;
import org.eclipse.sequoyah.vnc.protocol.lib.ProtocolMessage;
import org.eclipse.sequoyah.vnc.vncviewer.graphics.IRemoteDisplay;
import org.eclipse.sequoyah.vnc.vncviewer.graphics.swt.SWTRemoteDisplay;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.IPerspectiveListener;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchListener;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;

import com.motorola.studio.android.common.preferences.DialogWithToggleUtils;
import com.motorola.studio.android.common.utilities.EclipseUtils;
import com.motorola.studio.android.common.utilities.PluginUtils;
import com.motorola.studio.android.emulator.EmulatorPlugin;
import com.motorola.studio.android.emulator.core.devfrm.DeviceFrameworkManager;
import com.motorola.studio.android.emulator.core.exception.InstanceStopException;
import com.motorola.studio.android.emulator.core.exception.SkinException;
import com.motorola.studio.android.emulator.core.exception.StartCancelledException;
import com.motorola.studio.android.emulator.core.model.IAndroidEmulatorInstance;
import com.motorola.studio.android.emulator.core.model.IEmulatorView;
import com.motorola.studio.android.emulator.core.skin.IAndroidSkin;
import com.motorola.studio.android.emulator.i18n.EmulatorNLS;
import com.motorola.studio.android.emulator.logic.AbstractStartAndroidEmulatorLogic;
import com.motorola.studio.android.emulator.logic.AbstractStartAndroidEmulatorLogic.LogicMode;
import com.motorola.studio.android.emulator.logic.IAndroidLogicInstance;
import com.motorola.studio.android.emulator.logic.StartVncServerLogic;
import com.motorola.studio.android.emulator.logic.stop.AndroidEmulatorStopper;
import com.motorola.studio.android.emulator.ui.IUIHelpConstants;
import com.motorola.studio.android.emulator.ui.controls.IAndroidComposite;
import com.motorola.studio.android.emulator.ui.controls.RemoteCLIDisplay;
import com.motorola.studio.android.emulator.ui.controls.nativewindow.NativeWindowComposite;
import com.motorola.studio.android.nativeos.IDevicePropertiesOSConstants;
import com.motorola.studio.android.nativeos.NativeUIUtils;

/**
 * DESCRIPTION:
 * This class represents the Android Emulator view. It provides the 
 * generic methods of the Emulator Views. The specific ones must be defined 
 * by the classes that extend it. 
 *
 * RESPONSIBILITY:
 * - Show the viewers to the end user
 *
 * COLABORATORS: 
 * None.
 *
 * USAGE:
 * The public interface provides static and dynamic methods:
 * STATIC METHODS:
 *  - Call getActiveInstance to retrieve the instance that corresponds to
 *  the emulator running at the active tab
 *  - Call updateActiveViewers to guarantee that the active viewer of all views 
 *  is up to date in all emulator views opened, but do not make further verifications.
 * DYNAMIC METHODS:
 *  - Call refreshView to updates all viewers including creation of viewers 
 *  for started instances and removal of viewers
 *  - Call updateActiveViewer to guarantee that the active viewer is up to 
 *  date in all  emulator views opened, but do not make further verifications 
 */
public abstract class AbstractAndroidView extends ViewPart implements IEmulatorView {
    private final MenuManager menuManager;

    public static final String POPUP_MENU_ID = "com.motorola.studio.android.emulator.view.popup";

    private MouseListener mouseClickListener;

    /**
     * Preference key of the Question Dialog about stopping the emulators by closing view
     */
    private static String STOP_BY_CLOSING_VIEW_KEY_PREFERENCE = "stop.by.closing.view";

    /**
     * Preference key of the Question Dialog about displaying all emulators in the IDE
     * 
     */
    private static String SHOW_EMULATOR_IN_THE_IDE_KEY_PREFERENCE = "show.view.for.started.emulators";

    /**
     * Preference key of the Question Dialog about stopping all emulators in shutdown
     * 
     */
    private static String STOP_ALL_EMULATORS_IN_SHUTDOWN_KEY_PREFERENCE = "stop.all.emulators.in.shutdown";

    /**
     * All event types handled by the listeners in this class
     */
    public static final int[] SWT_EVENT_TYPES = new int[] { SWT.KeyDown, SWT.KeyUp, SWT.MouseDown, SWT.MouseUp,
            SWT.MouseMove, SWT.MouseDoubleClick };

    /**
     * All possible Layout Operations
     */
    public enum LayoutOpp {
        KEEP, NEXT
    };

    /**
     * Tab folder where to place each instance tab
     */
    private TabFolder tabFolder;

    Listener listener = new Listener() {
        public void handleEvent(Event event) {
            if (tabFolder.getItemCount() > 0) {
                TabItem activeTabItem = getActiveTabItem();

                if ((activeTabItem != null) && (activeTabItem.getControl() != null)) {
                    info("Setting focus to Android Emulator " + activeTabItem.getData());
                    activeTabItem.getControl().setFocus();
                }
            }
        }
    };

    /**
     *  Map to collect the emulator AndroidViewData committed to its emulator instance. 
     */
    private final Map<IAndroidEmulatorInstance, AndroidViewData> instanceDataMap = new LinkedHashMap<IAndroidEmulatorInstance, AndroidViewData>();

    /**
     * Listener required to code the work-around for Sticky Views on perspectiveChanged method.
     */
    private PerspectiveListenerImpl perspectiveListenerImpl;

    /**
     * Listener necessary to determine when the view is closed. 
     */
    private PartListenerImpl partListenerImpl;

    /**
     * Listener used to know if the view is being closed due to workbench shutdown.
     */
    private static WorkbenchListenerImpl workbenchListenerImpl;

    // the view is being closed during the Studio shutdown.
    private boolean closingOnShutdown = false;

    // Collection of the ids of the opened views that overwrite this class  
    private static final List<String> childrenIDs = new ArrayList<String>();

    // the instance being currently active at the emulator views
    private static IAndroidEmulatorInstance activeInstance;

    /**
     * Listeners of tab switch event
     */
    private static final Collection<Listener> tabSwitchListeners = new ArrayList<Listener>();

    /**
     * Lock to assure that only the first thread will display the show view question
     */
    private static Lock showViewLock = new ReentrantReadWriteLock().writeLock();

    /**
     * Add a listener to be called when the tab selection changes
     * 
     * @param listener the listener to be added
     */
    public static void addTabSwitchListener(Listener listener) {
        tabSwitchListeners.add(listener);
    }

    /**
     * Remove a listener that listen to tab switch events
     * 
     * @param listener  the listener to be removed
     */
    public static void removeTabSwitchListener(Listener listener) {
        tabSwitchListeners.remove(listener);
    }

    /**
     * Call listeners of tab switch events
     */
    protected void handleTabSwitchEvent() {
        for (Listener listener : tabSwitchListeners) {
            listener.handleEvent(null);
        }
    }

    /**
     * Returns the View Identification.
     * @return the unique ViewId
     */
    protected abstract String getViewId();

    /**
     * Creates the graphical elements representing the emulator that will be 
     * shown by the viewer in its tab item.
     * 
     * @param tab the tab item that will hold the graphical elements that 
     * represents the emulator
     * @param instance the emulator instance
     * @param emulatorData the object to be defined with the elements created.
     * @throws SkinException if the AVD configured skin does not exists 
     */
    protected abstract void createWidgets(TabItem tab, final IAndroidEmulatorInstance instance,
            final AndroidViewData emulatorData) throws SkinException;

    /**
     * Forces the refreshing of the menu elements. 
     */
    protected abstract void refreshMenuElements();

    /**
     * Retrieves the instance being currently active at the emulator views.
     *
     * @return The active instance, or null if there is no active instance
     */
    public static IAndroidEmulatorInstance getActiveInstance() {
        return activeInstance;
    }

    /**
     * Retrieves the instance being currently active at the emulator views.
     *
     * @return The active instance, or null if there is no active instance
     */
    public static void setInstance(IAndroidEmulatorInstance emulatorInstance) {
        if (!childrenIDs.isEmpty()) {
            AbstractAndroidView view = (AbstractAndroidView) EclipseUtils.getActiveView(childrenIDs.get(0));
            if (view != null) {
                view.setActiveInstanceId(emulatorInstance.getInstanceIdentifier());
                activeInstance = emulatorInstance;
            }
        }
    }

    /**
     * Retrieves the information about the viewer used to display the given emulator instance
     * and returns null if there is no AndroidViewData for the given emulator instance.
     * viewer.
     * @param the emulator instance whose Android Viewer data need to be retrieved.
     * @return the AndroidViewerData for the given Emulator instance (null if none is available).
     */
    public AndroidViewData getViewData(IAndroidEmulatorInstance instance) {
        AndroidViewData viewData = instanceDataMap.get(instance);
        return viewData;
    }

    public IAndroidSkin getSkin(IAndroidEmulatorInstance instance) {
        IAndroidSkin skin = null;
        AndroidViewData viewData = getViewData(instance);
        if (viewData != null) {
            skin = viewData.getSkin();
        }
        return skin;
    }

    /**
     * Gets the layout to set, if opp is NEXT or PREVIOUS
     * 
     * @param viewId The view that is currently active
     * @param opp The layout operation to perform
     */
    public static String getPreviousOrNextLayout(String viewId, LayoutOpp opp) {
        String prevNextLayout = null;
        AbstractAndroidView view = (AbstractAndroidView) EclipseUtils.getActiveView(viewId);
        if (view != null) {
            prevNextLayout = view.getPreviousOrNextLayout(opp);
        }

        return prevNextLayout;
    }

    /**
     * Gets the layout to set, if opp is NEXT or PREVIOUS
     * 
     * @param opp The layout operation to perform
     */
    @SuppressWarnings("incomplete-switch")
    private String getPreviousOrNextLayout(LayoutOpp opp) {
        String prevNextLayout = null;
        if (activeInstance != null) {
            String referenceLayout = activeInstance.getCurrentLayout();
            AndroidViewData viewData = instanceDataMap.get(activeInstance);
            if (viewData != null) {
                IAndroidComposite androidComposite = viewData.getComposite();
                if ((androidComposite != null)) {
                    IAndroidSkin androidSkin = viewData.getSkin();

                    if (androidSkin != null) {
                        switch (opp) {
                        case NEXT:
                            prevNextLayout = androidSkin.getNextLayout(referenceLayout);
                            break;
                        }
                    }
                }
            }
        }

        return prevNextLayout;
    }

    /**
     * Updates the zoom action that needs to be checked in all emulator views.
     * This method must be called every time the focus changes to another
     * viewer.
     * 
     * @param layoutName The layout name to set
     */
    public static void changeLayout(String layoutName) {
        for (String viewId : childrenIDs) {
            AbstractAndroidView view = (AbstractAndroidView) EclipseUtils.getActiveView(viewId);
            if (view != null) {
                view.updateActiveViewer(layoutName);
            }
        }
    }

    /**
     * Gets the help ID to be used for attaching
     * context sensitive help. 
     * 
     * Classes that extends this class and want to set
     * their on help should override this method
     */
    protected String getHelpId() {
        return IUIHelpConstants.EMULATOR_VIEW_HELP;
    }

    /**
     * @see org.eclipse.ui.IWorkbenchPart#createPartControl(Composite)
     */
    @Override
    public void createPartControl(Composite parent) {
        PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, getHelpId());

        this.tabFolder = new TabFolder(parent, SWT.BORDER | SWT.BACKGROUND);
        IViewSite viewSite = getViewSite();

        // Add listeners
        tabFolder.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent event) {
                setActiveInstanceId();
                updateMenuAndToolbars();
                handleTabSwitchEvent();
            }
        });

        tabFolder.addFocusListener(new FocusAdapter() {

            @Override
            public void focusGained(FocusEvent e) {
                handleTabSwitchEvent();
            }

        });

        perspectiveListenerImpl = new PerspectiveListenerImpl();
        viewSite.getWorkbenchWindow().addPerspectiveListener(perspectiveListenerImpl);

        partListenerImpl = new PartListenerImpl();
        viewSite.getPage().addPartListener(partListenerImpl);

        if (workbenchListenerImpl == null) {
            workbenchListenerImpl = new WorkbenchListenerImpl();
            viewSite.getWorkbenchWindow().getWorkbench().addWorkbenchListener(workbenchListenerImpl);
        }

        // Update UI
        refreshView();

        IActionBars actionBars = viewSite.getActionBars();
        if (actionBars != null) {
            IMenuManager menuManager = actionBars.getMenuManager();
            if (menuManager != null) {
                menuManager.addMenuListener(new IMenuListener() {
                    public void menuAboutToShow(IMenuManager manager) {
                        // Calls the manager update method to guarantee that the command have its handler
                        // initialized. Otherwise, the next command will not work properly
                        if (manager != null) {
                            manager.update(true);
                        }
                        updateMenuAndToolbars();
                    }
                });
            }
        }

        //register the popup menu
        viewSite.registerContextMenu(POPUP_MENU_ID, menuManager, null);

        //create listener
        if (Platform.getOS().contains(Platform.OS_MACOSX)) {
            mouseClickListener = new MouseListener() {

                public void mouseDoubleClick(MouseEvent e) {
                    //do nothing
                }

                public void mouseDown(MouseEvent e) {
                    if ((e.button == 1) && (e.stateMask == SWT.CONTROL)) {
                        menuManager.getMenu().setVisible(true);
                    }
                }

                public void mouseUp(MouseEvent e) {
                    //do nothing
                }

            };
        } else {
            mouseClickListener = new MouseListener() {

                public void mouseDoubleClick(MouseEvent e) {
                    //do nothing
                }

                public void mouseDown(MouseEvent e) {
                    if (e.button == 3) {
                        menuManager.getMenu().setVisible(true);
                    }
                }

                public void mouseUp(MouseEvent e) {
                    //do nothing
                }

            };

        }

    }

    /**
     * Constructor default
     */
    public AbstractAndroidView() {
        childrenIDs.add(getViewId());
        menuManager = new MenuManager("", POPUP_MENU_ID);
        addTabSwitchListener(listener);
    }

    /**
     * @see org.eclipse.ui.IWorkbenchPart#setFocus()
     */
    @Override
    public void setFocus() {
        if (tabFolder.getItemCount() > 0) {
            TabItem activeTabItem = getActiveTabItem();

            if ((activeTabItem != null) && (activeTabItem.getControl() != null)) {
                info("Setting focus to Android Emulator " + activeTabItem.getData());
                activeTabItem.getControl().setFocus();
            } else {
                info("Setting focus to Android Emulator View");
                tabFolder.setFocus();
            }
        } else {
            info("Setting focus to Android Emulator View");
            tabFolder.setFocus();
        }

        updateMenuAndToolbars();
    }

    /**
     * @see org.eclipse.ui.IWorkbenchPart#dispose()
     */
    @Override
    public void dispose() {
        removeTabSwitchListener(listener);
        debug("Disposing View: " + getClass());
        getViewSite().getWorkbenchWindow().removePerspectiveListener(perspectiveListenerImpl);
        getViewSite().getPage().removePartListener(partListenerImpl);
        perspectiveListenerImpl = null;
        partListenerImpl = null;
        instanceDataMap.clear();
        tabFolder.dispose();
        childrenIDs.remove(getViewId());
        super.dispose();
    }

    /**
     * This method rebuilds the skin, adding a new tab in the Android Emulator View
     * to show it.
     *
     * It should be used when the Android Emulator view is being created when the Android Emulator
     * instance is not stopped.
     */
    public void refreshView() {
        Job refreshViews = new Job("Refresh Emulator View") {
            @Override
            protected IStatus run(IProgressMonitor monitor) {

                info("Updating Android Emulator viewers");

                final DeviceFrameworkManager framework = DeviceFrameworkManager.getInstance();

                Collection<IAndroidEmulatorInstance> startedInstances = framework.getAllStartedInstances();

                for (final IAndroidEmulatorInstance instance : startedInstances) {
                    if (instance.getProperties()
                            .getProperty(IDevicePropertiesOSConstants.useVnc, NativeUIUtils.getDefaultUseVnc())
                            .equals("true")) {
                        if (!instance.isConnected()) {
                            IStatus returnStatus = null;
                            returnStatus = connectVNC(instance, monitor);
                            if (returnStatus.isOK()) {
                                PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
                                    public void run() {
                                        createViewer(instance);
                                    }
                                });
                            }
                        }
                    }
                }

                PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
                    public void run() {

                        Collection<IAndroidEmulatorInstance> connectedInstances = framework
                                .getAllConnectedInstances();

                        Collection<IAndroidEmulatorInstance> instancesWithViewerCollection = getInstancesWithViewer();

                        for (IAndroidEmulatorInstance instance : connectedInstances) {
                            if (!instancesWithViewerCollection.contains(instance)) {
                                createViewer(instance);
                            } else {
                                // update the collection for removing the stopped instances
                                instancesWithViewerCollection.remove(instance);
                            }
                        }

                        // Remove not started instances from viewer
                        for (IAndroidEmulatorInstance instance : instancesWithViewerCollection) {
                            disposeViewer(instance);
                            info("Disposed viewer of " + instance);
                        }

                        // Update the active instance variable after any creation/disposal is
                        // made. Update the active viewer only if the active viewer is new
                        activeInstance = getActiveInstanceFromCurrentView();
                        if (activeInstance != null) {
                            setActiveInstanceId();
                            handleTabSwitchEvent();
                        }

                        updateMenuAndToolbars();
                    }

                });

                return Status.OK_STATUS;
            }
        };
        refreshViews.setRule(new RefreshRule());
        refreshViews.schedule();
    }

    class RefreshRule implements ISchedulingRule {
        public boolean contains(ISchedulingRule rule) {
            return this == rule;
        }

        public boolean isConflicting(ISchedulingRule rule) {
            return rule instanceof RefreshRule;
        }
    }

    /**
     * Updates the zoom action that needs to be checked.
     * This method must be called every time the focus changes to another
     * viewer.
     */
    public void updateActiveViewer() {
        updateActiveViewer(null);
    }

    /**
     * Updates the zoom action that needs to be checked, after performing a layout operation
     * 
     * @param layoutName The name of the layout to set if opp is SETLAYOUT
     */
    public void updateActiveViewer(String layoutName) {
        info("Updating Android Emulator view");

        if (activeInstance != null) {
            AndroidViewData viewData = instanceDataMap.get(activeInstance);
            if (viewData != null) {
                IAndroidComposite androidComposite = viewData.getComposite();
                if ((androidComposite != null)) {
                    if ((activeInstance.getProperties().getProperty(IDevicePropertiesOSConstants.useVnc,
                            NativeUIUtils.getDefaultUseVnc())).equals("true")) {
                        IAndroidSkin androidSkin = viewData.getSkin();

                        if (androidSkin != null) {
                            if (layoutName != null) {
                                activeInstance.setCurrentLayout(layoutName);
                            }

                            boolean isNeeded = androidSkin
                                    .isSwapWidthHeightNeededAtLayout(activeInstance.getCurrentLayout());
                            IRemoteDisplay.Rotation rotation = (isNeeded
                                    ? IRemoteDisplay.Rotation.ROTATION_90DEG_COUNTERCLOCKWISE
                                    : IRemoteDisplay.Rotation.ROTATION_0DEG);
                            viewData.getMainDisplay().setRotation(rotation);
                            androidComposite.applyLayout(activeInstance.getCurrentLayout());
                        }
                    }
                    androidComposite.applyZoomFactor();
                }

            }
        }

        updateMenuAndToolbars();

        info("Updated Android Emulator view");
    }

    public void changeToNextLayout() {
        AndroidViewData viewData = instanceDataMap.get(activeInstance);
        IAndroidComposite androidComposite = viewData.getComposite();
        if (androidComposite instanceof NativeWindowComposite) {
            ((NativeWindowComposite) androidComposite).changeToNextLayout();
        }
    }

    /**
     * Retrieves the instance being currently displayed at this view.
     *
     * @return The active instance, or null if there is no active instance
     */
    private IAndroidEmulatorInstance getActiveInstanceFromCurrentView() {
        TabItem activeInstanceItem = getActiveTabItem();
        IAndroidEmulatorInstance instance = null;
        if (activeInstanceItem != null) {
            instance = (IAndroidEmulatorInstance) (activeInstanceItem.getData());
        } else {
            debug("No active instance being shown at emulator view");
        }

        return instance;
    }

    /**
     * Executes the procedure to connect to the VNC
     * 
     * @param androidDevice
     *            The device being connected
     */
    public IStatus connectVNC(final IAndroidEmulatorInstance instance, IProgressMonitor monitor) {
        IStatus statusToReturn = Status.OK_STATUS;

        try {
            IAndroidLogicInstance logicInstance = (IAndroidLogicInstance) instance;
            AbstractStartAndroidEmulatorLogic startLogic = logicInstance.getStartLogic();

            startLogic.execute(logicInstance, LogicMode.TRANSFER_AND_CONNECT_VNC, logicInstance.getTimeout(),
                    monitor);
        } catch (StartCancelledException e1) {
            info("The user canceled the transfer/connect to VNC phase.");
            statusToReturn = Status.CANCEL_STATUS;
        } catch (Exception e1) {
            error("Could not establish VNC Connection to " + instance);
            statusToReturn = new Status(IStatus.ERROR, EmulatorPlugin.PLUGIN_ID,
                    NLS.bind(EmulatorNLS.ERR_CannotConnectToVNC, instance.getName()));
        }
        return statusToReturn;
    }

    /**
     * Shows the Android Emulator view, if not being shown
     */
    public static void showView() {
        info("Open and move focus to the emulator view");

        boolean emulatorViewOpened = !EclipseUtils.getAllOpenedViewsWithId(AndroidView.ANDROID_VIEW_ID).isEmpty();

        try {
            // if emulator view is opened previously or if no emulator view is opened,
            // show / refresh the emulator view.
            if (emulatorViewOpened) {
                EclipseUtils.showView(AndroidView.ANDROID_VIEW_ID);
            } else {
                // Make sure only one open view (due to the transition to online) will occur at the same time. 
                // e.g. if the "question open dialog" is already opened, it is not needed one 

                if (showViewLock.tryLock()) {
                    try {

                        boolean openEmulatorView = DialogWithToggleUtils.showQuestion(
                                SHOW_EMULATOR_IN_THE_IDE_KEY_PREFERENCE,
                                EmulatorNLS.QUESTION_AbstractAndroidView_OpenViewForStartedEmulatorsTitle,
                                EmulatorNLS.QUESTION_AbstractAndroidView_OpenViewForStartedEmulatorsMessage);
                        if (openEmulatorView) {
                            EclipseUtils.showView(AndroidView.ANDROID_VIEW_ID);
                        }
                    } finally {
                        showViewLock.unlock();
                    }
                }
            }
        } catch (PartInitException e) {
            error("The Android Emulator View could not be opened programatically");
            EclipseUtils.showErrorDialog(EmulatorNLS.GEN_Error,
                    EmulatorNLS.EXC_AbstractAndroidView_ViewNotAccessibleProgramatically);
        }
    }

    /**
     * Creates a viewer for the provided instance
     *
     * @param instance The instance that will have a viewer created at this view
     */
    private void createViewer(final IAndroidEmulatorInstance instance) {
        if (instance != null) {
            info("Creating tab for " + instance + " on " + getClass());

            Set<IAndroidEmulatorInstance> currentInstancesWithTab = getInstancesWithAtLeastOneViewer();

            // Creates a tab item to hold the skin at the view 
            TabItem newTabItem = new TabItem(tabFolder, SWT.NONE);

            // Set parameters at the tab item                        
            newTabItem.setText(instance.getFullName());
            newTabItem.setData(instance);
            AndroidViewData emulatorData = new AndroidViewData();
            instanceDataMap.put(instance, emulatorData);

            try {
                createWidgets(newTabItem, instance, emulatorData);
                tabFolder.setSelection(newTabItem);
                setActiveInstanceId();

                //add popup menu
                if (newTabItem.getControl() != null) {
                    menuManager.createContextMenu(newTabItem.getControl());
                    newTabItem.getControl().addMouseListener(mouseClickListener);
                }

                ProtocolMessage setEncodingMsg = new ProtocolMessage(2);
                setEncodingMsg.setFieldValue("padding", 0);
                setEncodingMsg.setFieldValue("number-of-encodings", 1);
                setEncodingMsg.setFieldValue("encoding-type", "encoding-types", 0, 0);
                PluginProtocolActionDelegate.sendMessageToServer(instance.getProtocolHandle(), setEncodingMsg);

                info("Created tab for " + instance);

                if (instance.getProperties()
                        .getProperty(IDevicePropertiesOSConstants.useVnc, NativeUIUtils.getDefaultUseVnc())
                        .toString().equals("true")) {
                    startVncDisplays(instance);
                    info("Started displays for " + instance);

                    // overwrite original tml listeners 
                    addListenersToMainDisplay(emulatorData);
                } else {
                    IAndroidComposite parentComposite = emulatorData.getComposite();
                    ((NativeWindowComposite) parentComposite).addMouseListener(mouseClickListener);
                }

                IAndroidComposite androidComposite = emulatorData.getComposite();
                if (androidComposite != null) {
                    androidComposite.applyZoomFactor();
                }

                // If this is the first view to be opened, guarantee that the screen orientation is 
                // synchronized with the current layout  (only when using VNC)                   
                if (!currentInstancesWithTab.contains(instance) && instance.getProperties()
                        .getProperty(IDevicePropertiesOSConstants.useVnc, NativeUIUtils.getDefaultUseVnc())
                        .toString().equals("true")) {
                    IAndroidSkin skin = getSkin(instance);
                    if (skin != null) {
                        instance.changeOrientation(skin.getLayoutScreenCommand(instance.getCurrentLayout()));
                    }
                }

                updateActiveViewer();

                info("Created tab for Android Emulator " + instance);
            } catch (SkinException e) {
                error("The skin associated to this instance (" + instance.getName()
                        + ") is not installed or is corrupted.");
                EclipseUtils.showErrorDialog(e);

                try {
                    instance.stop(true);
                    disposeViewer(instance);
                } catch (InstanceStopException e1) {
                    error("Error while running service for stopping virtual machine");
                    EclipseUtils.showErrorDialog(EmulatorNLS.GEN_Error,
                            EmulatorNLS.EXC_General_CannotRunStopService);
                }
            }
        }
    }

    private void addListenersToMainDisplay(AndroidViewData emulatorData) {
        // TmL registers listeners during start, and unregisters all of them during
        // stop. To adapt the listeners to Studio needs, we are including the following
        // operations after the start display call from TmL. With this we are achieving: 
        //
        // 1. TmL registers several listeners at its canvas (TmL start method)
        // 2. Studio unregisters the TmL listeners (this method)
        // 3. Studio registers new listeners to replace the TmL ones (this method)
        // 4. TmL unregisters Studio listeners instead of its own (TmL stop method)

        SWTRemoteDisplay remoteDisplay = emulatorData.getMainDisplay();
        final Canvas canvas = remoteDisplay.getCanvas();
        IAndroidComposite parentComposite = emulatorData.getComposite();

        for (int eventType : SWT_EVENT_TYPES) {
            for (Listener listener : canvas.getListeners(eventType)) {
                canvas.removeListener(eventType, listener);
            }
        }

        KeyListener keyListener = parentComposite.getKeyListener();
        final MouseListener mouseListener = parentComposite.getMouseListener();
        MouseMoveListener mouseMoveListener = parentComposite.getMouseMoveListener();

        canvas.addKeyListener(keyListener);
        canvas.addMouseListener(mouseListener);
        canvas.addMouseMoveListener(mouseMoveListener);

        // Due to the differences in listener registration between TmL and Studio, it will
        // remain a registered listener when the viewer is disposed. For this reason, the  
        // following dispose listener is being registered.
        DisposeListener disposeListener = new DisposeListener() {
            public void widgetDisposed(DisposeEvent arg0) {
                canvas.removeMouseListener(mouseListener);
                canvas.removeMouseListener(mouseClickListener);
            }
        };
        emulatorData.setDisposeListener(disposeListener);
        canvas.addDisposeListener(disposeListener);
        canvas.addMouseListener(mouseClickListener);
    }

    /**
     * Disposes the viewer of the provided instance
     *
     * @param instance The instance that will have a viewer disposed from this view
     */
    private void disposeViewer(final IAndroidEmulatorInstance instance) {
        info("Disposing tab of Android Emulator at " + instance);

        TabItem item = getTabItem(instance);
        if (item != null) {

            stopVncDisplays(instance);

            //if there are no other viewers, we can stop protocol and vnc server
            if ((childrenIDs.size() == 1) && (instance.getProperties()
                    .getProperty(IDevicePropertiesOSConstants.useVnc, NativeUIUtils.getDefaultUseVnc()).toString()
                    .equals("true"))) {
                info("There is only one view opened, stop VNC protocol and VNC Server");
                stopVncProtocol((IAndroidLogicInstance) instance);
                stopVncServer(instance);
            }

            AndroidViewData data = instanceDataMap.get(instance);
            if (data != null) {
                SWTRemoteDisplay mainDisplay = data.getMainDisplay();
                if (mainDisplay != null) {
                    Canvas canvas = mainDisplay.getCanvas();

                    if (canvas != null) {
                        canvas.removeDisposeListener(data.getDisposeListener());
                    }
                }
            }

            Control c = item.getControl();
            if (c != null) {
                c.dispose();
            }
            item.setControl(null);

            item.dispose();
            instanceDataMap.remove(instance);
            updateMenuAndToolbars();
            info("Disposed tab of Android Emulator at " + instance);
        }

    }

    /**
     * Gets the list of instances with viewers associated. 
     * @return the collection of instances
     */
    private Collection<IAndroidEmulatorInstance> getInstancesWithViewer() {
        final Collection<IAndroidEmulatorInstance> instancesWithViewer = new LinkedHashSet<IAndroidEmulatorInstance>();

        if (!tabFolder.isDisposed()) {
            final TabItem[] allItems = tabFolder.getItems();

            for (TabItem item : allItems) {
                if (!item.isDisposed()) {
                    instancesWithViewer.add((IAndroidEmulatorInstance) item.getData());
                }
            }
        }

        return instancesWithViewer;
    }

    private static Set<IAndroidEmulatorInstance> getInstancesWithAtLeastOneViewer() {
        Set<IAndroidEmulatorInstance> instancesSet = new HashSet<IAndroidEmulatorInstance>();
        for (String viewId : childrenIDs) {
            AbstractAndroidView view = (AbstractAndroidView) EclipseUtils.getActiveView(viewId);
            if (view != null) {
                instancesSet.addAll(view.getInstancesWithViewer());
            }
        }

        return instancesSet;
    }

    /**
     * Gets the tab item related to the instance 
     * @param instance the emulator instance
     * @return the tab item 
     */
    private TabItem getTabItem(IAndroidEmulatorInstance instance) {
        TabItem result = null;
        if (!tabFolder.isDisposed()) {
            TabItem[] allItems = tabFolder.getItems();

            for (TabItem item : allItems) {
                if (instance.equals(item.getData())) {
                    result = item;
                    break;
                }
            }
        }

        return result;
    }

    /**
     * Gets the tab item related to the instance 
     * @param instance the emulator instance
     * @return the tab item 
     */
    private TabItem getTabItem(IInstance instance) {
        TabItem result = null;
        if (!tabFolder.isDisposed()) {
            TabItem[] allItems = tabFolder.getItems();

            for (TabItem item : allItems) {
                if (instance.getName().equals(((IAndroidEmulatorInstance) item.getData()).getName())) {
                    result = item;
                    break;
                }
            }
        }

        return result;
    }

    /**
     * Retrieves the active tab at view
     *
     * @return The active tab, or null of there is no tab at tab folder
     */
    private TabItem getActiveTabItem() {
        int activeInstanceIndex = this.tabFolder.getSelectionIndex();

        TabItem activeTabItem = null;

        if (activeInstanceIndex >= 0) {
            activeTabItem = this.tabFolder.getItem(activeInstanceIndex);
        }

        return activeTabItem;
    }

    /**
     * Updates the zoom action that needs to be checked.
     * This method must be called every time the focus changes to another
     * viewer
     */
    private void updateMenuAndToolbars() {
        IViewSite viewSite = getViewSite();

        if (viewSite != null) {
            IActionBars actionBars = viewSite.getActionBars();

            if (actionBars != null) {
                IMenuManager menuManager = actionBars.getMenuManager();
                updateMenuManager(menuManager, viewSite);

                IToolBarManager toolbarManager = actionBars.getToolBarManager();
                if (toolbarManager != null) {
                    IContributionItem[] items = toolbarManager.getItems();
                    for (IContributionItem item : items) {
                        item.update();
                    }
                }
            }

            refreshMenuElements();
        }
    }

    /**
     * Recursive method to update items at menus. The recursion helps to update submenus
     * 
     * @param manager The manager that holds a menu items
     * @param viewSite The current view site. 
     */
    private void updateMenuManager(IMenuManager manager, IViewSite viewSite) {
        // Update the items in menu manager
        if (manager != null) {
            IContributionItem[] items = manager.getItems();
            for (IContributionItem item : items) {
                if (item instanceof IMenuManager) {
                    updateMenuManager((IMenuManager) item, viewSite);
                } else {
                    item.update();
                }
            }
        }
    }

    /**
     * Stops all emulator instances with the Progress Monitor opened. 
     */
    private void stopEmulatorInstances() {
        // defines the runnable object for stopping emulator instances.
        final IRunnableWithProgress stopRunnable = new IRunnableWithProgress() {
            public void run(IProgressMonitor monitor) {
                Collection<IAndroidEmulatorInstance> startedInstances = DeviceFrameworkManager.getInstance()
                        .getAllStartedInstances();
                boolean errorsHappened = false;

                for (IAndroidEmulatorInstance instance : startedInstances) {
                    try {
                        instance.stop(true);
                    } catch (InstanceStopException e) {
                        errorsHappened = true;
                    }
                }

                // if closing on shutdown, use a progress bar and stall UI
                if (closingOnShutdown) {
                    // start a progress monitor
                    monitor.beginTask("", IProgressMonitor.UNKNOWN);

                    // make sure the stop instance job finished
                    Job[] jobs = Job.getJobManager().find(null); // get all jobs
                    for (Job job : jobs) {
                        if (job.getName().equals(EmulatorNLS.UI_AbstractAndroidView_StopInstanceJob)) {
                            // when job result is not null, it has finished
                            while (job.getResult() == null) {
                                try {
                                    // sleep a little so the waiting is not too busy
                                    Thread.sleep(1000);
                                } catch (InterruptedException e) {
                                    // do nothing
                                }
                            }
                        }
                    }
                }

                if (errorsHappened) {
                    EclipseUtils.showErrorDialog(EmulatorNLS.GEN_Error,
                            EmulatorNLS.EXC_AncroidView_CannotRunMultipleStopServices);
                }

            }
        };

        // executes the runnable defined above.
        PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
            public void run() {
                Shell currentShell = getViewSite().getShell();
                ProgressMonitorDialog dialog = new ProgressMonitorDialog(currentShell);
                try {
                    dialog.run(true, false, stopRunnable);
                } catch (Exception e) {
                    // Should not have exceptions. 
                    // The runnable is not interrupted and it handles exceptions internally
                    // Log runtime exceptions
                    error("Runtime exception was thrown: " + e.getClass().getSimpleName());
                }
            }
        });
    }

    /**
     * Sets the identifier of the instance being currently displayed at view
     */
    private void setActiveInstanceId(String activeHost) {
        for (String viewId : childrenIDs) {
            Collection<IViewPart> viewsToUpdateMenu = EclipseUtils.getAllOpenedViewsWithId(viewId);
            for (IViewPart view : viewsToUpdateMenu) {
                AbstractAndroidView emulatorView = (AbstractAndroidView) view;
                emulatorView.setSelection(activeHost);
            }

        }
    }

    /**
     * Sets the identifier of the instance being currently displayed at view
     */
    private void setActiveInstanceId() {
        TabItem activeInstanceItem = getActiveTabItem();
        if ((activeInstanceItem != null) && (activeInstanceItem.getData() != null)) {

            activeInstance = (IAndroidEmulatorInstance) activeInstanceItem.getData();

            String activeId = ((IAndroidEmulatorInstance) activeInstanceItem.getData()).getInstanceIdentifier();

            setActiveInstanceId(activeId);
        } else {
            debug("No active instance being shown at emulator view");
        }

    }

    /**
     * Starts the main display associating it to the protocol. 
     * @param handle the protocol handle
     * @param mainDisplay the main display object
     */
    private void startDisplay(ProtocolHandle handle, SWTRemoteDisplay mainDisplay) {
        // Stop any running screens
        if ((mainDisplay.isActive()) && (!mainDisplay.isDisposed())) {
            mainDisplay.stop();
        }

        try {
            info("Starting main display refresh");
            mainDisplay.start(handle);
        } catch (Exception e) {
            error("Viewers could not be started.");
            EclipseUtils.showErrorDialog(EmulatorNLS.GEN_Error, EmulatorNLS.EXC_AndroidView_ErrorStartingScreens);

            GC gc = new GC(mainDisplay.getCanvas());
            gc.fillRectangle(0, 0, mainDisplay.getScreenWidth(), mainDisplay.getScreenHeight());
            gc.dispose();
        }
    }

    /**
     * Starts viewer (main display and CLI display) of the emulator instance. 
     * @param instance the emulator instance
     */
    protected void startVncDisplays(final IAndroidEmulatorInstance instance) {
        AndroidViewData viewData = instanceDataMap.get(instance);
        if (viewData != null) {
            if (viewData.getMainDisplay() != null) {
                startDisplay(instance.getProtocolHandle(), viewData.getMainDisplay());
            }
            if ((viewData.getCliDisplay() != null) && instance.getHasCli()) {
                viewData.getCliDisplay().start();
            }
        }
    }

    /**
     * Stops viewer (main display and CLI display) of the emulator instance. 
     */
    private void stopVncDisplays(final IAndroidEmulatorInstance instance) {
        info("Stop the VNC Display " + getViewId() + " for " + instance);
        AndroidViewData viewData = instanceDataMap.get(instance);

        if ((viewData != null)) {
            SWTRemoteDisplay mainDisplay = viewData.getMainDisplay();
            if ((mainDisplay != null) && mainDisplay.isActive() && !mainDisplay.isDisposed()) {
                mainDisplay.stop();
                if ((mainDisplay.getBackground() != null) && !mainDisplay.getBackground().isDisposed()) {
                    mainDisplay.getBackground().dispose();
                }
            }

            RemoteCLIDisplay cliDisplay = viewData.getCliDisplay();
            if ((cliDisplay != null) && cliDisplay.isDisplayActive() && !cliDisplay.isDisposed()) {
                cliDisplay.stop();
                if ((cliDisplay.getBackground() != null) && !cliDisplay.getBackground().isDisposed()) {
                    cliDisplay.getBackground().dispose();
                }
            }
        }
    }

    /**
     * @param instance
     */
    private void stopVncProtocol(IAndroidLogicInstance instance) {
        AndroidEmulatorStopper.stopInstance(instance, true, false, new NullProgressMonitor());

    }

    /**
     * Stops the execution of the vnc server if it is running on the given instance.
     * This acts as if the Control+C was pressed in the shell where the vnc server is executing...
     * @param instance
     */
    private void stopVncServer(IAndroidEmulatorInstance instance) {
        StartVncServerLogic.cancelCurrentVncServerJobs(instance);
    }

    /**
     * Class to implement the IPerspectiveListener that you be used as ParListener2 of 
     * current page when the Emulator View is opened. It is required to code the
     * work-around for Sticky Views on perspectiveChanged method. 
     */
    private class PerspectiveListenerImpl implements IPerspectiveListener {

        public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) {
            // Nothing to do.
        }

        public void perspectiveChanged(IWorkbenchPage page, IPerspectiveDescriptor perspective, String changeId) {
            if (changeId.equals(IWorkbenchPage.CHANGE_VIEW_HIDE)) {

                // if the emulator view was hidden  
                if (page.findView(getViewId()) == null) {

                    // This is a "sticky view" so when it is hidden or shown for one
                    // perspective, its state is remembered for the other ones. 
                    // However, the view reference count is just updated when 
                    // the current active perspective is changed. The code below 
                    // forces the perspective changing in order to dispose the view 
                    // immediately after it is hidden.
                    for (IPerspectiveDescriptor pd : page.getOpenPerspectives()) {
                        if (!pd.equals(perspective)) {
                            page.setPerspective(pd);
                        }
                    }
                    page.setPerspective(perspective);
                }
            }
        }
    }

    /**
     * Class to implement IPartListener2 that you be used as ParListener2 of current page
     * when the Emulator View is opened. It is necessary to determine when the view is
     * closed. 
     */
    private class PartListenerImpl implements IPartListener2 {

        public void partActivated(IWorkbenchPartReference partRef) {
            // Nothing to do.
        }

        public void partBroughtToTop(IWorkbenchPartReference partRef) {
            // Nothing to do.
        }

        public void partClosed(final IWorkbenchPartReference partRef) {

            // if view that is being closed is not THIS view. 
            if (!partRef.getId().equals(getViewId())) {
                return;
            }

            // executed on async mode to avoid UI blocking
            PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
                public void run() {
                    boolean openedViewsExist = false;

                    for (String viewId : childrenIDs) {
                        if (!getViewId().equals(viewId) && (partRef.getPage().findView(viewId) != null)) {
                            openedViewsExist = true;
                            break;
                        }
                    }

                    // stops all viewers and clear the tabs list
                    Collection<IAndroidEmulatorInstance> instances = getInstancesWithViewer();
                    for (IAndroidEmulatorInstance instance : instances) {
                        disposeViewer(instance);
                    }

                    // if the tool is not being closed and there is no other emulator 
                    // view opened. 
                    if (!closingOnShutdown && !openedViewsExist) {

                        Collection<IAndroidEmulatorInstance> startedInstances = DeviceFrameworkManager.getInstance()
                                .getAllStartedInstances();

                        boolean oneInstanceStarted = (startedInstances.size() > 0);

                        if (oneInstanceStarted
                                && (DialogWithToggleUtils.showQuestion(STOP_BY_CLOSING_VIEW_KEY_PREFERENCE,
                                        EmulatorNLS.QUESTION_AndroidView_StopAllInstancesOnDisposeTitle,
                                        EmulatorNLS.QUESTION_AndroidView_StopAllInstancesOnDisposeMessage))) {

                            stopEmulatorInstances();
                        }
                    }

                }

            });
        }

        public void partDeactivated(IWorkbenchPartReference partRef) {
            // Nothing to do.
        }

        public void partHidden(IWorkbenchPartReference partRef) {
            // Nothing to do.
        }

        public void partInputChanged(IWorkbenchPartReference partRef) {
            // Nothing to do.
        }

        public void partOpened(IWorkbenchPartReference partRef) {
            // Nothing to do.
        }

        public void partVisible(IWorkbenchPartReference partRef) {
            if (partRef.getId().equals(getViewId())) {
                refreshView();
            }
        }
    }

    /**
     * Class to implement the IWorkbenchListener that you be used as WorkbenchListener of 
     * workbench when the Emulator View is opened. It is used to know if the view 
     * is being closed due to workbench shutdown.  
     */
    private class WorkbenchListenerImpl implements IWorkbenchListener {

        public void postShutdown(IWorkbench workbench) {
            // Nothing to do.   
        }

        public boolean preShutdown(IWorkbench workbench, boolean forced) {
            closingOnShutdown = true;

            Collection<IAndroidEmulatorInstance> startedInstances = DeviceFrameworkManager.getInstance()
                    .getAllStartedInstances();

            if (startedInstances.size() > 0) {

                boolean stopEmulatorInstances = false;
                if (PluginUtils.getOS() != PluginUtils.OS_LINUX) {
                    stopEmulatorInstances = DialogWithToggleUtils.showQuestion(
                            STOP_ALL_EMULATORS_IN_SHUTDOWN_KEY_PREFERENCE,
                            EmulatorNLS.QUESTION_RunningInstancesOnClose_Title,
                            EmulatorNLS.QUESTION_RunningInstancesOnClose_Text);
                } else {
                    DialogWithToggleUtils.showWarning(STOP_ALL_EMULATORS_IN_SHUTDOWN_KEY_PREFERENCE,
                            EmulatorNLS.WARN_RunningInstancesOnClose_Linux_Title,
                            EmulatorNLS.WARN_RunningInstancesOnClose_Linux_Text);
                    //stopEmulatorInstances = true;
                }

                if (stopEmulatorInstances) {
                    stopEmulatorInstances();
                }

            }

            return true;
        }
    }

    /**
     * Selects the tab that has this data host and set the activeHost
     * @param host IP address
     */
    private void setSelection(final String host) {

        PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
            public void run() {
                TabItem selectedTab = null;

                TabItem[] tabArray = tabFolder.getItems();

                for (TabItem tabItem : tabArray) {
                    String tabItemHost = ((IAndroidEmulatorInstance) tabItem.getData()).getInstanceIdentifier();
                    if ((host != null) && (host.equals(tabItemHost))) {
                        selectedTab = tabItem;
                        break;
                    }
                }

                if (selectedTab != null) {
                    tabFolder.setSelection(selectedTab);
                    updateMenuAndToolbars();
                }

            }
        });

    }

    public static void updateInstanceName(final IInstance instance) {
        PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
            public void run() {
                if (!childrenIDs.isEmpty()) {
                    AbstractAndroidView view = (AbstractAndroidView) EclipseUtils.getActiveView(childrenIDs.get(0));
                    if (view != null) {
                        if ((instance != null)) {
                            TabItem tabItem = view.getTabItem(instance);
                            if (tabItem != null) {
                                tabItem.setText(((IAndroidEmulatorInstance) tabItem.getData()).getFullName());
                            }
                        }
                    }
                }
            }
        });
    }

    /**
     * Sets the skin zoom factor
     * 
     * @param instance the emulator instance
     * @param zoom the zoom factor
     */
    public final void setZoomFactor(IAndroidEmulatorInstance instance, double zoom) {
        try {
            AndroidViewData viewData = instanceDataMap.get(instance);
            if (viewData != null) {
                IAndroidComposite composite = viewData.getComposite();
                if (composite != null) {
                    composite.setZoomFactor(zoom);
                }
            }
        } catch (Exception e) {
            error("Detached zoom could not be set.");
        }
    }

    /**
     * Gets the skin zoom factor
     * 
     * @param instance the emulator instance
     * @return the zoom factor
     */
    public final double getZoomFactor(IAndroidEmulatorInstance instance) {
        double zoomFactor = 0.0;
        AndroidViewData viewData = instanceDataMap.get(instance);
        if (viewData != null) {
            IAndroidComposite composite = viewData.getComposite();
            if (composite != null) {
                zoomFactor = composite.getZoomFactor();
            }
        }
        return zoomFactor;
    }
}