summaryrefslogtreecommitdiff
path: root/src/plugins/emulator/src/com/motorola/studio/android/emulator/ui/view/AbstractAndroidView.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/emulator/src/com/motorola/studio/android/emulator/ui/view/AbstractAndroidView.java')
-rw-r--r--src/plugins/emulator/src/com/motorola/studio/android/emulator/ui/view/AbstractAndroidView.java1839
1 files changed, 1839 insertions, 0 deletions
diff --git a/src/plugins/emulator/src/com/motorola/studio/android/emulator/ui/view/AbstractAndroidView.java b/src/plugins/emulator/src/com/motorola/studio/android/emulator/ui/view/AbstractAndroidView.java
new file mode 100644
index 0000000..cf6cb0f
--- /dev/null
+++ b/src/plugins/emulator/src/com/motorola/studio/android/emulator/ui/view/AbstractAndroidView.java
@@ -0,0 +1,1839 @@
+/*
+* 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;
+ }
+} \ No newline at end of file