Home | History | Annotate | Download | only in view
      1 /*
      2 * Copyright (C) 2012 The Android Open Source Project
      3 *
      4 * Licensed under the Apache License, Version 2.0 (the "License");
      5 * you may not use this file except in compliance with the License.
      6 * You may obtain a copy of the License at
      7 *
      8 *      http://www.apache.org/licenses/LICENSE-2.0
      9 *
     10 * Unless required by applicable law or agreed to in writing, software
     11 * distributed under the License is distributed on an "AS IS" BASIS,
     12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 * See the License for the specific language governing permissions and
     14 * limitations under the License.
     15 */
     16 package com.motorola.studio.android.emulator.ui.view;
     17 
     18 import static com.motorola.studio.android.common.log.StudioLogger.debug;
     19 import static com.motorola.studio.android.common.log.StudioLogger.error;
     20 import static com.motorola.studio.android.common.log.StudioLogger.info;
     21 
     22 import java.util.ArrayList;
     23 import java.util.Collection;
     24 import java.util.HashSet;
     25 import java.util.LinkedHashMap;
     26 import java.util.LinkedHashSet;
     27 import java.util.List;
     28 import java.util.Map;
     29 import java.util.Set;
     30 import java.util.concurrent.locks.Lock;
     31 import java.util.concurrent.locks.ReentrantReadWriteLock;
     32 
     33 import org.eclipse.core.runtime.IProgressMonitor;
     34 import org.eclipse.core.runtime.IStatus;
     35 import org.eclipse.core.runtime.NullProgressMonitor;
     36 import org.eclipse.core.runtime.Platform;
     37 import org.eclipse.core.runtime.Status;
     38 import org.eclipse.core.runtime.jobs.ISchedulingRule;
     39 import org.eclipse.core.runtime.jobs.Job;
     40 import org.eclipse.jface.action.IContributionItem;
     41 import org.eclipse.jface.action.IMenuListener;
     42 import org.eclipse.jface.action.IMenuManager;
     43 import org.eclipse.jface.action.IToolBarManager;
     44 import org.eclipse.jface.action.MenuManager;
     45 import org.eclipse.jface.dialogs.ProgressMonitorDialog;
     46 import org.eclipse.jface.operation.IRunnableWithProgress;
     47 import org.eclipse.osgi.util.NLS;
     48 import org.eclipse.sequoyah.device.framework.model.IInstance;
     49 import org.eclipse.sequoyah.vnc.protocol.PluginProtocolActionDelegate;
     50 import org.eclipse.sequoyah.vnc.protocol.lib.ProtocolHandle;
     51 import org.eclipse.sequoyah.vnc.protocol.lib.ProtocolMessage;
     52 import org.eclipse.sequoyah.vnc.vncviewer.graphics.IRemoteDisplay;
     53 import org.eclipse.sequoyah.vnc.vncviewer.graphics.swt.SWTRemoteDisplay;
     54 import org.eclipse.swt.SWT;
     55 import org.eclipse.swt.events.DisposeEvent;
     56 import org.eclipse.swt.events.DisposeListener;
     57 import org.eclipse.swt.events.FocusAdapter;
     58 import org.eclipse.swt.events.FocusEvent;
     59 import org.eclipse.swt.events.KeyListener;
     60 import org.eclipse.swt.events.MouseEvent;
     61 import org.eclipse.swt.events.MouseListener;
     62 import org.eclipse.swt.events.MouseMoveListener;
     63 import org.eclipse.swt.events.SelectionAdapter;
     64 import org.eclipse.swt.events.SelectionEvent;
     65 import org.eclipse.swt.graphics.GC;
     66 import org.eclipse.swt.widgets.Canvas;
     67 import org.eclipse.swt.widgets.Composite;
     68 import org.eclipse.swt.widgets.Control;
     69 import org.eclipse.swt.widgets.Event;
     70 import org.eclipse.swt.widgets.Listener;
     71 import org.eclipse.swt.widgets.Shell;
     72 import org.eclipse.swt.widgets.TabFolder;
     73 import org.eclipse.swt.widgets.TabItem;
     74 import org.eclipse.ui.IActionBars;
     75 import org.eclipse.ui.IPartListener2;
     76 import org.eclipse.ui.IPerspectiveDescriptor;
     77 import org.eclipse.ui.IPerspectiveListener;
     78 import org.eclipse.ui.IViewPart;
     79 import org.eclipse.ui.IViewSite;
     80 import org.eclipse.ui.IWorkbench;
     81 import org.eclipse.ui.IWorkbenchListener;
     82 import org.eclipse.ui.IWorkbenchPage;
     83 import org.eclipse.ui.IWorkbenchPartReference;
     84 import org.eclipse.ui.PartInitException;
     85 import org.eclipse.ui.PlatformUI;
     86 import org.eclipse.ui.part.ViewPart;
     87 
     88 import com.motorola.studio.android.common.preferences.DialogWithToggleUtils;
     89 import com.motorola.studio.android.common.utilities.EclipseUtils;
     90 import com.motorola.studio.android.common.utilities.PluginUtils;
     91 import com.motorola.studio.android.emulator.EmulatorPlugin;
     92 import com.motorola.studio.android.emulator.core.devfrm.DeviceFrameworkManager;
     93 import com.motorola.studio.android.emulator.core.exception.InstanceStopException;
     94 import com.motorola.studio.android.emulator.core.exception.SkinException;
     95 import com.motorola.studio.android.emulator.core.exception.StartCancelledException;
     96 import com.motorola.studio.android.emulator.core.model.IAndroidEmulatorInstance;
     97 import com.motorola.studio.android.emulator.core.model.IEmulatorView;
     98 import com.motorola.studio.android.emulator.core.skin.IAndroidSkin;
     99 import com.motorola.studio.android.emulator.i18n.EmulatorNLS;
    100 import com.motorola.studio.android.emulator.logic.AbstractStartAndroidEmulatorLogic;
    101 import com.motorola.studio.android.emulator.logic.AbstractStartAndroidEmulatorLogic.LogicMode;
    102 import com.motorola.studio.android.emulator.logic.IAndroidLogicInstance;
    103 import com.motorola.studio.android.emulator.logic.StartVncServerLogic;
    104 import com.motorola.studio.android.emulator.logic.stop.AndroidEmulatorStopper;
    105 import com.motorola.studio.android.emulator.ui.IUIHelpConstants;
    106 import com.motorola.studio.android.emulator.ui.controls.IAndroidComposite;
    107 import com.motorola.studio.android.emulator.ui.controls.RemoteCLIDisplay;
    108 import com.motorola.studio.android.emulator.ui.controls.nativewindow.NativeWindowComposite;
    109 import com.motorola.studio.android.nativeos.IDevicePropertiesOSConstants;
    110 import com.motorola.studio.android.nativeos.NativeUIUtils;
    111 
    112 /**
    113  * DESCRIPTION:
    114  * This class represents the Android Emulator view. It provides the
    115  * generic methods of the Emulator Views. The specific ones must be defined
    116  * by the classes that extend it.
    117  *
    118  * RESPONSIBILITY:
    119  * - Show the viewers to the end user
    120  *
    121  * COLABORATORS:
    122  * None.
    123  *
    124  * USAGE:
    125  * The public interface provides static and dynamic methods:
    126  * STATIC METHODS:
    127  *  - Call getActiveInstance to retrieve the instance that corresponds to
    128  *  the emulator running at the active tab
    129  *  - Call updateActiveViewers to guarantee that the active viewer of all views
    130  *  is up to date in all emulator views opened, but do not make further verifications.
    131  * DYNAMIC METHODS:
    132  *  - Call refreshView to updates all viewers including creation of viewers
    133  *  for started instances and removal of viewers
    134  *  - Call updateActiveViewer to guarantee that the active viewer is up to
    135  *  date in all  emulator views opened, but do not make further verifications
    136  */
    137 public abstract class AbstractAndroidView extends ViewPart implements IEmulatorView
    138 {
    139     private final MenuManager menuManager;
    140 
    141     public static final String POPUP_MENU_ID = "com.motorola.studio.android.emulator.view.popup";
    142 
    143     private MouseListener mouseClickListener;
    144 
    145     /**
    146      * Preference key of the Question Dialog about stopping the emulators by closing view
    147      */
    148     private static String STOP_BY_CLOSING_VIEW_KEY_PREFERENCE = "stop.by.closing.view";
    149 
    150     /**
    151      * Preference key of the Question Dialog about displaying all emulators in the IDE
    152      *
    153      */
    154     private static String SHOW_EMULATOR_IN_THE_IDE_KEY_PREFERENCE =
    155             "show.view.for.started.emulators";
    156 
    157     /**
    158      * Preference key of the Question Dialog about stopping all emulators in shutdown
    159      *
    160      */
    161     private static String STOP_ALL_EMULATORS_IN_SHUTDOWN_KEY_PREFERENCE =
    162             "stop.all.emulators.in.shutdown";
    163 
    164     /**
    165      * All event types handled by the listeners in this class
    166      */
    167     public static final int[] SWT_EVENT_TYPES = new int[]
    168     {
    169             SWT.KeyDown, SWT.KeyUp, SWT.MouseDown, SWT.MouseUp, SWT.MouseMove, SWT.MouseDoubleClick
    170     };
    171 
    172     /**
    173      * All possible Layout Operations
    174      */
    175     public enum LayoutOpp
    176     {
    177         KEEP, NEXT
    178     };
    179 
    180     /**
    181      * Tab folder where to place each instance tab
    182      */
    183     private TabFolder tabFolder;
    184 
    185     Listener listener = new Listener()
    186     {
    187         public void handleEvent(Event event)
    188         {
    189             if (tabFolder.getItemCount() > 0)
    190             {
    191                 TabItem activeTabItem = getActiveTabItem();
    192 
    193                 if ((activeTabItem != null) && (activeTabItem.getControl() != null))
    194                 {
    195                     info("Setting focus to Android Emulator " + activeTabItem.getData());
    196                     activeTabItem.getControl().setFocus();
    197                 }
    198             }
    199         }
    200     };
    201 
    202     /**
    203      *  Map to collect the emulator AndroidViewData committed to its emulator instance.
    204      */
    205     private final Map<IAndroidEmulatorInstance, AndroidViewData> instanceDataMap =
    206             new LinkedHashMap<IAndroidEmulatorInstance, AndroidViewData>();
    207 
    208     /**
    209      * Listener required to code the work-around for Sticky Views on perspectiveChanged method.
    210      */
    211     private PerspectiveListenerImpl perspectiveListenerImpl;
    212 
    213     /**
    214      * Listener necessary to determine when the view is closed.
    215      */
    216     private PartListenerImpl partListenerImpl;
    217 
    218     /**
    219      * Listener used to know if the view is being closed due to workbench shutdown.
    220      */
    221     private static WorkbenchListenerImpl workbenchListenerImpl;
    222 
    223     // the view is being closed during the Studio shutdown.
    224     private boolean closingOnShutdown = false;
    225 
    226     // Collection of the ids of the opened views that overwrite this class
    227     private static final List<String> childrenIDs = new ArrayList<String>();
    228 
    229     // the instance being currently active at the emulator views
    230     private static IAndroidEmulatorInstance activeInstance;
    231 
    232     /**
    233      * Listeners of tab switch event
    234      */
    235     private static final Collection<Listener> tabSwitchListeners = new ArrayList<Listener>();
    236 
    237     /**
    238      * Lock to assure that only the first thread will display the show view question
    239      */
    240     private static Lock showViewLock = new ReentrantReadWriteLock().writeLock();
    241 
    242     /**
    243      * Add a listener to be called when the tab selection changes
    244      *
    245      * @param listener the listener to be added
    246      */
    247     public static void addTabSwitchListener(Listener listener)
    248     {
    249         tabSwitchListeners.add(listener);
    250     }
    251 
    252     /**
    253      * Remove a listener that listen to tab switch events
    254      *
    255      * @param listener  the listener to be removed
    256      */
    257     public static void removeTabSwitchListener(Listener listener)
    258     {
    259         tabSwitchListeners.remove(listener);
    260     }
    261 
    262     /**
    263      * Call listeners of tab switch events
    264      */
    265     protected void handleTabSwitchEvent()
    266     {
    267         for (Listener listener : tabSwitchListeners)
    268         {
    269             listener.handleEvent(null);
    270         }
    271     }
    272 
    273     /**
    274      * Returns the View Identification.
    275      * @return the unique ViewId
    276      */
    277     protected abstract String getViewId();
    278 
    279     /**
    280      * Creates the graphical elements representing the emulator that will be
    281      * shown by the viewer in its tab item.
    282      *
    283      * @param tab the tab item that will hold the graphical elements that
    284      * represents the emulator
    285      * @param instance the emulator instance
    286      * @param emulatorData the object to be defined with the elements created.
    287      * @throws SkinException if the AVD configured skin does not exists
    288      */
    289     protected abstract void createWidgets(TabItem tab, final IAndroidEmulatorInstance instance,
    290             final AndroidViewData emulatorData) throws SkinException;
    291 
    292     /**
    293      * Forces the refreshing of the menu elements.
    294      */
    295     protected abstract void refreshMenuElements();
    296 
    297     /**
    298      * Retrieves the instance being currently active at the emulator views.
    299      *
    300      * @return The active instance, or null if there is no active instance
    301      */
    302     public static IAndroidEmulatorInstance getActiveInstance()
    303     {
    304         return activeInstance;
    305     }
    306 
    307     /**
    308      * Retrieves the instance being currently active at the emulator views.
    309      *
    310      * @return The active instance, or null if there is no active instance
    311      */
    312     public static void setInstance(IAndroidEmulatorInstance emulatorInstance)
    313     {
    314         if (!childrenIDs.isEmpty())
    315         {
    316             AbstractAndroidView view =
    317                     (AbstractAndroidView) EclipseUtils.getActiveView(childrenIDs.get(0));
    318             if (view != null)
    319             {
    320                 view.setActiveInstanceId(emulatorInstance.getInstanceIdentifier());
    321                 activeInstance = emulatorInstance;
    322             }
    323         }
    324     }
    325 
    326     /**
    327      * Retrieves the information about the viewer used to display the given emulator instance
    328      * and returns null if there is no AndroidViewData for the given emulator instance.
    329      * viewer.
    330      * @param the emulator instance whose Android Viewer data need to be retrieved.
    331      * @return the AndroidViewerData for the given Emulator instance (null if none is available).
    332      */
    333     public AndroidViewData getViewData(IAndroidEmulatorInstance instance)
    334     {
    335         AndroidViewData viewData = instanceDataMap.get(instance);
    336         return viewData;
    337     }
    338 
    339     public IAndroidSkin getSkin(IAndroidEmulatorInstance instance)
    340     {
    341         IAndroidSkin skin = null;
    342         AndroidViewData viewData = getViewData(instance);
    343         if (viewData != null)
    344         {
    345             skin = viewData.getSkin();
    346         }
    347         return skin;
    348     }
    349 
    350     /**
    351      * Gets the layout to set, if opp is NEXT or PREVIOUS
    352      *
    353      * @param viewId The view that is currently active
    354      * @param opp The layout operation to perform
    355      */
    356     public static String getPreviousOrNextLayout(String viewId, LayoutOpp opp)
    357     {
    358         String prevNextLayout = null;
    359         AbstractAndroidView view = (AbstractAndroidView) EclipseUtils.getActiveView(viewId);
    360         if (view != null)
    361         {
    362             prevNextLayout = view.getPreviousOrNextLayout(opp);
    363         }
    364 
    365         return prevNextLayout;
    366     }
    367 
    368     /**
    369      * Gets the layout to set, if opp is NEXT or PREVIOUS
    370      *
    371      * @param opp The layout operation to perform
    372      */
    373     @SuppressWarnings("incomplete-switch")
    374     private String getPreviousOrNextLayout(LayoutOpp opp)
    375     {
    376         String prevNextLayout = null;
    377         if (activeInstance != null)
    378         {
    379             String referenceLayout = activeInstance.getCurrentLayout();
    380             AndroidViewData viewData = instanceDataMap.get(activeInstance);
    381             if (viewData != null)
    382             {
    383                 IAndroidComposite androidComposite = viewData.getComposite();
    384                 if ((androidComposite != null))
    385                 {
    386                     IAndroidSkin androidSkin = viewData.getSkin();
    387 
    388                     if (androidSkin != null)
    389                     {
    390                         switch (opp)
    391                         {
    392                             case NEXT:
    393                                 prevNextLayout = androidSkin.getNextLayout(referenceLayout);
    394                                 break;
    395                         }
    396                     }
    397                 }
    398             }
    399         }
    400 
    401         return prevNextLayout;
    402     }
    403 
    404     /**
    405      * Updates the zoom action that needs to be checked in all emulator views.
    406      * This method must be called every time the focus changes to another
    407      * viewer.
    408      *
    409      * @param layoutName The layout name to set
    410      */
    411     public static void changeLayout(String layoutName)
    412     {
    413         for (String viewId : childrenIDs)
    414         {
    415             AbstractAndroidView view = (AbstractAndroidView) EclipseUtils.getActiveView(viewId);
    416             if (view != null)
    417             {
    418                 view.updateActiveViewer(layoutName);
    419             }
    420         }
    421     }
    422 
    423     /**
    424      * Gets the help ID to be used for attaching
    425      * context sensitive help.
    426      *
    427      * Classes that extends this class and want to set
    428      * their on help should override this method
    429      */
    430     protected String getHelpId()
    431     {
    432         return IUIHelpConstants.EMULATOR_VIEW_HELP;
    433     }
    434 
    435     /**
    436      * @see org.eclipse.ui.IWorkbenchPart#createPartControl(Composite)
    437      */
    438     @Override
    439     public void createPartControl(Composite parent)
    440     {
    441         PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, getHelpId());
    442 
    443         this.tabFolder = new TabFolder(parent, SWT.BORDER | SWT.BACKGROUND);
    444         IViewSite viewSite = getViewSite();
    445 
    446         // Add listeners
    447         tabFolder.addSelectionListener(new SelectionAdapter()
    448         {
    449             @Override
    450             public void widgetSelected(SelectionEvent event)
    451             {
    452                 setActiveInstanceId();
    453                 updateMenuAndToolbars();
    454                 handleTabSwitchEvent();
    455             }
    456         });
    457 
    458         tabFolder.addFocusListener(new FocusAdapter()
    459         {
    460 
    461             @Override
    462             public void focusGained(FocusEvent e)
    463             {
    464                 handleTabSwitchEvent();
    465             }
    466 
    467         });
    468 
    469         perspectiveListenerImpl = new PerspectiveListenerImpl();
    470         viewSite.getWorkbenchWindow().addPerspectiveListener(perspectiveListenerImpl);
    471 
    472         partListenerImpl = new PartListenerImpl();
    473         viewSite.getPage().addPartListener(partListenerImpl);
    474 
    475         if (workbenchListenerImpl == null)
    476         {
    477             workbenchListenerImpl = new WorkbenchListenerImpl();
    478             viewSite.getWorkbenchWindow().getWorkbench()
    479                     .addWorkbenchListener(workbenchListenerImpl);
    480         }
    481 
    482         // Update UI
    483         refreshView();
    484 
    485         IActionBars actionBars = viewSite.getActionBars();
    486         if (actionBars != null)
    487         {
    488             IMenuManager menuManager = actionBars.getMenuManager();
    489             if (menuManager != null)
    490             {
    491                 menuManager.addMenuListener(new IMenuListener()
    492                 {
    493                     public void menuAboutToShow(IMenuManager manager)
    494                     {
    495                         // Calls the manager update method to guarantee that the command have its handler
    496                         // initialized. Otherwise, the next command will not work properly
    497                         if (manager != null)
    498                         {
    499                             manager.update(true);
    500                         }
    501                         updateMenuAndToolbars();
    502                     }
    503                 });
    504             }
    505         }
    506 
    507         //register the popup menu
    508         viewSite.registerContextMenu(POPUP_MENU_ID, menuManager, null);
    509 
    510         //create listener
    511         if (Platform.getOS().contains(Platform.OS_MACOSX))
    512         {
    513             mouseClickListener = new MouseListener()
    514             {
    515 
    516                 public void mouseDoubleClick(MouseEvent e)
    517                 {
    518                     //do nothing
    519                 }
    520 
    521                 public void mouseDown(MouseEvent e)
    522                 {
    523                     if ((e.button == 1) && (e.stateMask == SWT.CONTROL))
    524                     {
    525                         menuManager.getMenu().setVisible(true);
    526                     }
    527                 }
    528 
    529                 public void mouseUp(MouseEvent e)
    530                 {
    531                     //do nothing
    532                 }
    533 
    534             };
    535         }
    536         else
    537         {
    538             mouseClickListener = new MouseListener()
    539             {
    540 
    541                 public void mouseDoubleClick(MouseEvent e)
    542                 {
    543                     //do nothing
    544                 }
    545 
    546                 public void mouseDown(MouseEvent e)
    547                 {
    548                     if (e.button == 3)
    549                     {
    550                         menuManager.getMenu().setVisible(true);
    551                     }
    552                 }
    553 
    554                 public void mouseUp(MouseEvent e)
    555                 {
    556                     //do nothing
    557                 }
    558 
    559             };
    560 
    561         }
    562 
    563     }
    564 
    565     /**
    566      * Constructor default
    567      */
    568     public AbstractAndroidView()
    569     {
    570         childrenIDs.add(getViewId());
    571         menuManager = new MenuManager("", POPUP_MENU_ID);
    572         addTabSwitchListener(listener);
    573     }
    574 
    575     /**
    576      * @see org.eclipse.ui.IWorkbenchPart#setFocus()
    577      */
    578     @Override
    579     public void setFocus()
    580     {
    581         if (tabFolder.getItemCount() > 0)
    582         {
    583             TabItem activeTabItem = getActiveTabItem();
    584 
    585             if ((activeTabItem != null) && (activeTabItem.getControl() != null))
    586             {
    587                 info("Setting focus to Android Emulator " + activeTabItem.getData());
    588                 activeTabItem.getControl().setFocus();
    589             }
    590             else
    591             {
    592                 info("Setting focus to Android Emulator View");
    593                 tabFolder.setFocus();
    594             }
    595         }
    596         else
    597         {
    598             info("Setting focus to Android Emulator View");
    599             tabFolder.setFocus();
    600         }
    601 
    602         updateMenuAndToolbars();
    603     }
    604 
    605     /**
    606      * @see org.eclipse.ui.IWorkbenchPart#dispose()
    607      */
    608     @Override
    609     public void dispose()
    610     {
    611         removeTabSwitchListener(listener);
    612         debug("Disposing View: " + getClass());
    613         getViewSite().getWorkbenchWindow().removePerspectiveListener(perspectiveListenerImpl);
    614         getViewSite().getPage().removePartListener(partListenerImpl);
    615         perspectiveListenerImpl = null;
    616         partListenerImpl = null;
    617         instanceDataMap.clear();
    618         tabFolder.dispose();
    619         childrenIDs.remove(getViewId());
    620         super.dispose();
    621     }
    622 
    623     /**
    624      * This method rebuilds the skin, adding a new tab in the Android Emulator View
    625      * to show it.
    626      *
    627      * It should be used when the Android Emulator view is being created when the Android Emulator
    628      * instance is not stopped.
    629      */
    630     public void refreshView()
    631     {
    632         Job refreshViews = new Job("Refresh Emulator View")
    633         {
    634             @Override
    635             protected IStatus run(IProgressMonitor monitor)
    636             {
    637 
    638                 info("Updating Android Emulator viewers");
    639 
    640                 final DeviceFrameworkManager framework = DeviceFrameworkManager.getInstance();
    641 
    642                 Collection<IAndroidEmulatorInstance> startedInstances =
    643                         framework.getAllStartedInstances();
    644 
    645                 for (final IAndroidEmulatorInstance instance : startedInstances)
    646                 {
    647                     if (instance
    648                             .getProperties()
    649                             .getProperty(IDevicePropertiesOSConstants.useVnc,
    650                                     NativeUIUtils.getDefaultUseVnc()).equals("true"))
    651                     {
    652                         if (!instance.isConnected())
    653                         {
    654                             IStatus returnStatus = null;
    655                             returnStatus = connectVNC(instance, monitor);
    656                             if (returnStatus.isOK())
    657                             {
    658                                 PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
    659                                 {
    660                                     public void run()
    661                                     {
    662                                         createViewer(instance);
    663                                     }
    664                                 });
    665                             }
    666                         }
    667                     }
    668                 }
    669 
    670                 PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
    671                 {
    672                     public void run()
    673                     {
    674 
    675                         Collection<IAndroidEmulatorInstance> connectedInstances =
    676                                 framework.getAllConnectedInstances();
    677 
    678                         Collection<IAndroidEmulatorInstance> instancesWithViewerCollection =
    679                                 getInstancesWithViewer();
    680 
    681                         for (IAndroidEmulatorInstance instance : connectedInstances)
    682                         {
    683                             if (!instancesWithViewerCollection.contains(instance))
    684                             {
    685                                 createViewer(instance);
    686                             }
    687                             else
    688                             {
    689                                 // update the collection for removing the stopped instances
    690                                 instancesWithViewerCollection.remove(instance);
    691                             }
    692                         }
    693 
    694                         // Remove not started instances from viewer
    695                         for (IAndroidEmulatorInstance instance : instancesWithViewerCollection)
    696                         {
    697                             disposeViewer(instance);
    698                             info("Disposed viewer of " + instance);
    699                         }
    700 
    701                         // Update the active instance variable after any creation/disposal is
    702                         // made. Update the active viewer only if the active viewer is new
    703                         activeInstance = getActiveInstanceFromCurrentView();
    704                         if (activeInstance != null)
    705                         {
    706                             setActiveInstanceId();
    707                             handleTabSwitchEvent();
    708                         }
    709 
    710                         updateMenuAndToolbars();
    711                     }
    712 
    713                 });
    714 
    715                 return Status.OK_STATUS;
    716             }
    717         };
    718         refreshViews.setRule(new RefreshRule());
    719         refreshViews.schedule();
    720     }
    721 
    722     class RefreshRule implements ISchedulingRule
    723     {
    724         public boolean contains(ISchedulingRule rule)
    725         {
    726             return this == rule;
    727         }
    728 
    729         public boolean isConflicting(ISchedulingRule rule)
    730         {
    731             return rule instanceof RefreshRule;
    732         }
    733     }
    734 
    735     /**
    736      * Updates the zoom action that needs to be checked.
    737      * This method must be called every time the focus changes to another
    738      * viewer.
    739      */
    740     public void updateActiveViewer()
    741     {
    742         updateActiveViewer(null);
    743     }
    744 
    745     /**
    746      * Updates the zoom action that needs to be checked, after performing a layout operation
    747      *
    748      * @param layoutName The name of the layout to set if opp is SETLAYOUT
    749      */
    750     public void updateActiveViewer(String layoutName)
    751     {
    752         info("Updating Android Emulator view");
    753 
    754         if (activeInstance != null)
    755         {
    756             AndroidViewData viewData = instanceDataMap.get(activeInstance);
    757             if (viewData != null)
    758             {
    759                 IAndroidComposite androidComposite = viewData.getComposite();
    760                 if ((androidComposite != null))
    761                 {
    762                     if ((activeInstance.getProperties().getProperty(
    763                             IDevicePropertiesOSConstants.useVnc, NativeUIUtils.getDefaultUseVnc()))
    764                             .equals("true"))
    765                     {
    766                         IAndroidSkin androidSkin = viewData.getSkin();
    767 
    768                         if (androidSkin != null)
    769                         {
    770                             if (layoutName != null)
    771                             {
    772                                 activeInstance.setCurrentLayout(layoutName);
    773                             }
    774 
    775                             boolean isNeeded =
    776                                     androidSkin.isSwapWidthHeightNeededAtLayout(activeInstance
    777                                             .getCurrentLayout());
    778                             IRemoteDisplay.Rotation rotation =
    779                                     (isNeeded
    780                                             ? IRemoteDisplay.Rotation.ROTATION_90DEG_COUNTERCLOCKWISE
    781                                             : IRemoteDisplay.Rotation.ROTATION_0DEG);
    782                             viewData.getMainDisplay().setRotation(rotation);
    783                             androidComposite.applyLayout(activeInstance.getCurrentLayout());
    784                         }
    785                     }
    786                     androidComposite.applyZoomFactor();
    787                 }
    788 
    789             }
    790         }
    791 
    792         updateMenuAndToolbars();
    793 
    794         info("Updated Android Emulator view");
    795     }
    796 
    797     public void changeToNextLayout()
    798     {
    799         AndroidViewData viewData = instanceDataMap.get(activeInstance);
    800         IAndroidComposite androidComposite = viewData.getComposite();
    801         if (androidComposite instanceof NativeWindowComposite)
    802         {
    803             ((NativeWindowComposite) androidComposite).changeToNextLayout();
    804         }
    805     }
    806 
    807     /**
    808      * Retrieves the instance being currently displayed at this view.
    809      *
    810      * @return The active instance, or null if there is no active instance
    811      */
    812     private IAndroidEmulatorInstance getActiveInstanceFromCurrentView()
    813     {
    814         TabItem activeInstanceItem = getActiveTabItem();
    815         IAndroidEmulatorInstance instance = null;
    816         if (activeInstanceItem != null)
    817         {
    818             instance = (IAndroidEmulatorInstance) (activeInstanceItem.getData());
    819         }
    820         else
    821         {
    822             debug("No active instance being shown at emulator view");
    823         }
    824 
    825         return instance;
    826     }
    827 
    828     /**
    829      * Executes the procedure to connect to the VNC
    830      *
    831      * @param androidDevice
    832      *            The device being connected
    833      */
    834     public IStatus connectVNC(final IAndroidEmulatorInstance instance, IProgressMonitor monitor)
    835     {
    836         IStatus statusToReturn = Status.OK_STATUS;
    837 
    838         try
    839         {
    840             IAndroidLogicInstance logicInstance = (IAndroidLogicInstance) instance;
    841             AbstractStartAndroidEmulatorLogic startLogic = logicInstance.getStartLogic();
    842 
    843             startLogic.execute(logicInstance, LogicMode.TRANSFER_AND_CONNECT_VNC,
    844                     logicInstance.getTimeout(), monitor);
    845         }
    846         catch (StartCancelledException e1)
    847         {
    848             info("The user canceled the transfer/connect to VNC phase.");
    849             statusToReturn = Status.CANCEL_STATUS;
    850         }
    851         catch (Exception e1)
    852         {
    853             error("Could not establish VNC Connection to " + instance);
    854             statusToReturn =
    855                     new Status(IStatus.ERROR, EmulatorPlugin.PLUGIN_ID, NLS.bind(
    856                             EmulatorNLS.ERR_CannotConnectToVNC, instance.getName()));
    857         }
    858         return statusToReturn;
    859     }
    860 
    861     /**
    862      * Shows the Android Emulator view, if not being shown
    863      */
    864     public static void showView()
    865     {
    866         info("Open and move focus to the emulator view");
    867 
    868         boolean emulatorViewOpened =
    869                 !EclipseUtils.getAllOpenedViewsWithId(AndroidView.ANDROID_VIEW_ID).isEmpty();
    870 
    871         try
    872         {
    873             // if emulator view is opened previously or if no emulator view is opened,
    874             // show / refresh the emulator view.
    875             if (emulatorViewOpened)
    876             {
    877                 EclipseUtils.showView(AndroidView.ANDROID_VIEW_ID);
    878             }
    879             else
    880             {
    881                 // Make sure only one open view (due to the transition to online) will occur at the same time.
    882                 // e.g. if the "question open dialog" is already opened, it is not needed one
    883 
    884                 if (showViewLock.tryLock())
    885                 {
    886                     try
    887                     {
    888 
    889                         boolean openEmulatorView =
    890                                 DialogWithToggleUtils
    891                                         .showQuestion(
    892                                                 SHOW_EMULATOR_IN_THE_IDE_KEY_PREFERENCE,
    893                                                 EmulatorNLS.QUESTION_AbstractAndroidView_OpenViewForStartedEmulatorsTitle,
    894                                                 EmulatorNLS.QUESTION_AbstractAndroidView_OpenViewForStartedEmulatorsMessage);
    895                         if (openEmulatorView)
    896                         {
    897                             EclipseUtils.showView(AndroidView.ANDROID_VIEW_ID);
    898                         }
    899                     }
    900                     finally
    901                     {
    902                         showViewLock.unlock();
    903                     }
    904                 }
    905             }
    906         }
    907         catch (PartInitException e)
    908         {
    909             error("The Android Emulator View could not be opened programatically");
    910             EclipseUtils.showErrorDialog(EmulatorNLS.GEN_Error,
    911                     EmulatorNLS.EXC_AbstractAndroidView_ViewNotAccessibleProgramatically);
    912         }
    913     }
    914 
    915     /**
    916      * Creates a viewer for the provided instance
    917      *
    918      * @param instance The instance that will have a viewer created at this view
    919      */
    920     private void createViewer(final IAndroidEmulatorInstance instance)
    921     {
    922         if (instance != null)
    923         {
    924             info("Creating tab for " + instance + " on " + getClass());
    925 
    926             Set<IAndroidEmulatorInstance> currentInstancesWithTab =
    927                     getInstancesWithAtLeastOneViewer();
    928 
    929             // Creates a tab item to hold the skin at the view
    930             TabItem newTabItem = new TabItem(tabFolder, SWT.NONE);
    931 
    932             // Set parameters at the tab item
    933             newTabItem.setText(instance.getFullName());
    934             newTabItem.setData(instance);
    935             AndroidViewData emulatorData = new AndroidViewData();
    936             instanceDataMap.put(instance, emulatorData);
    937 
    938             try
    939             {
    940                 createWidgets(newTabItem, instance, emulatorData);
    941                 tabFolder.setSelection(newTabItem);
    942                 setActiveInstanceId();
    943 
    944                 //add popup menu
    945                 if (newTabItem.getControl() != null)
    946                 {
    947                     menuManager.createContextMenu(newTabItem.getControl());
    948                     newTabItem.getControl().addMouseListener(mouseClickListener);
    949                 }
    950 
    951                 ProtocolMessage setEncodingMsg = new ProtocolMessage(2);
    952                 setEncodingMsg.setFieldValue("padding", 0);
    953                 setEncodingMsg.setFieldValue("number-of-encodings", 1);
    954                 setEncodingMsg.setFieldValue("encoding-type", "encoding-types", 0, 0);
    955                 PluginProtocolActionDelegate.sendMessageToServer(instance.getProtocolHandle(),
    956                         setEncodingMsg);
    957 
    958                 info("Created tab for " + instance);
    959 
    960                 if (instance
    961                         .getProperties()
    962                         .getProperty(IDevicePropertiesOSConstants.useVnc,
    963                                 NativeUIUtils.getDefaultUseVnc()).toString().equals("true"))
    964                 {
    965                     startVncDisplays(instance);
    966                     info("Started displays for " + instance);
    967 
    968                     // overwrite original tml listeners
    969                     addListenersToMainDisplay(emulatorData);
    970                 }
    971                 else
    972                 {
    973                     IAndroidComposite parentComposite = emulatorData.getComposite();
    974                     ((NativeWindowComposite) parentComposite).addMouseListener(mouseClickListener);
    975                 }
    976 
    977                 IAndroidComposite androidComposite = emulatorData.getComposite();
    978                 if (androidComposite != null)
    979                 {
    980                     androidComposite.applyZoomFactor();
    981                 }
    982 
    983                 // If this is the first view to be opened, guarantee that the screen orientation is
    984                 // synchronized with the current layout  (only when using VNC)
    985                 if (!currentInstancesWithTab.contains(instance)
    986                         && instance
    987                                 .getProperties()
    988                                 .getProperty(IDevicePropertiesOSConstants.useVnc,
    989                                         NativeUIUtils.getDefaultUseVnc()).toString().equals("true"))
    990                 {
    991                     IAndroidSkin skin = getSkin(instance);
    992                     if (skin != null)
    993                     {
    994                         instance.changeOrientation(skin.getLayoutScreenCommand(instance
    995                                 .getCurrentLayout()));
    996                     }
    997                 }
    998 
    999                 updateActiveViewer();
   1000 
   1001                 info("Created tab for Android Emulator " + instance);
   1002             }
   1003             catch (SkinException e)
   1004             {
   1005                 error("The skin associated to this instance (" + instance.getName()
   1006                         + ") is not installed or is corrupted.");
   1007                 EclipseUtils.showErrorDialog(e);
   1008 
   1009                 try
   1010                 {
   1011                     instance.stop(true);
   1012                     disposeViewer(instance);
   1013                 }
   1014                 catch (InstanceStopException e1)
   1015                 {
   1016                     error("Error while running service for stopping virtual machine");
   1017                     EclipseUtils.showErrorDialog(EmulatorNLS.GEN_Error,
   1018                             EmulatorNLS.EXC_General_CannotRunStopService);
   1019                 }
   1020             }
   1021         }
   1022     }
   1023 
   1024     private void addListenersToMainDisplay(AndroidViewData emulatorData)
   1025     {
   1026         // TmL registers listeners during start, and unregisters all of them during
   1027         // stop. To adapt the listeners to Studio needs, we are including the following
   1028         // operations after the start display call from TmL. With this we are achieving:
   1029         //
   1030         // 1. TmL registers several listeners at its canvas (TmL start method)
   1031         // 2. Studio unregisters the TmL listeners (this method)
   1032         // 3. Studio registers new listeners to replace the TmL ones (this method)
   1033         // 4. TmL unregisters Studio listeners instead of its own (TmL stop method)
   1034 
   1035         SWTRemoteDisplay remoteDisplay = emulatorData.getMainDisplay();
   1036         final Canvas canvas = remoteDisplay.getCanvas();
   1037         IAndroidComposite parentComposite = emulatorData.getComposite();
   1038 
   1039         for (int eventType : SWT_EVENT_TYPES)
   1040         {
   1041             for (Listener listener : canvas.getListeners(eventType))
   1042             {
   1043                 canvas.removeListener(eventType, listener);
   1044             }
   1045         }
   1046 
   1047         KeyListener keyListener = parentComposite.getKeyListener();
   1048         final MouseListener mouseListener = parentComposite.getMouseListener();
   1049         MouseMoveListener mouseMoveListener = parentComposite.getMouseMoveListener();
   1050 
   1051         canvas.addKeyListener(keyListener);
   1052         canvas.addMouseListener(mouseListener);
   1053         canvas.addMouseMoveListener(mouseMoveListener);
   1054 
   1055         // Due to the differences in listener registration between TmL and Studio, it will
   1056         // remain a registered listener when the viewer is disposed. For this reason, the
   1057         // following dispose listener is being registered.
   1058         DisposeListener disposeListener = new DisposeListener()
   1059         {
   1060             public void widgetDisposed(DisposeEvent arg0)
   1061             {
   1062                 canvas.removeMouseListener(mouseListener);
   1063                 canvas.removeMouseListener(mouseClickListener);
   1064             }
   1065         };
   1066         emulatorData.setDisposeListener(disposeListener);
   1067         canvas.addDisposeListener(disposeListener);
   1068         canvas.addMouseListener(mouseClickListener);
   1069     }
   1070 
   1071     /**
   1072      * Disposes the viewer of the provided instance
   1073      *
   1074      * @param instance The instance that will have a viewer disposed from this view
   1075      */
   1076     private void disposeViewer(final IAndroidEmulatorInstance instance)
   1077     {
   1078         info("Disposing tab of Android Emulator at " + instance);
   1079 
   1080         TabItem item = getTabItem(instance);
   1081         if (item != null)
   1082         {
   1083 
   1084             stopVncDisplays(instance);
   1085 
   1086             //if there are no other viewers, we can stop protocol and vnc server
   1087             if ((childrenIDs.size() == 1)
   1088                     && (instance
   1089                             .getProperties()
   1090                             .getProperty(IDevicePropertiesOSConstants.useVnc,
   1091                                     NativeUIUtils.getDefaultUseVnc()).toString().equals("true")))
   1092             {
   1093                 info("There is only one view opened, stop VNC protocol and VNC Server");
   1094                 stopVncProtocol((IAndroidLogicInstance) instance);
   1095                 stopVncServer(instance);
   1096             }
   1097 
   1098             AndroidViewData data = instanceDataMap.get(instance);
   1099             if (data != null)
   1100             {
   1101                 SWTRemoteDisplay mainDisplay = data.getMainDisplay();
   1102                 if (mainDisplay != null)
   1103                 {
   1104                     Canvas canvas = mainDisplay.getCanvas();
   1105 
   1106                     if (canvas != null)
   1107                     {
   1108                         canvas.removeDisposeListener(data.getDisposeListener());
   1109                     }
   1110                 }
   1111             }
   1112 
   1113             Control c = item.getControl();
   1114             if (c != null)
   1115             {
   1116                 c.dispose();
   1117             }
   1118             item.setControl(null);
   1119 
   1120             item.dispose();
   1121             instanceDataMap.remove(instance);
   1122             updateMenuAndToolbars();
   1123             info("Disposed tab of Android Emulator at " + instance);
   1124         }
   1125 
   1126     }
   1127 
   1128     /**
   1129      * Gets the list of instances with viewers associated.
   1130      * @return the collection of instances
   1131      */
   1132     private Collection<IAndroidEmulatorInstance> getInstancesWithViewer()
   1133     {
   1134         final Collection<IAndroidEmulatorInstance> instancesWithViewer =
   1135                 new LinkedHashSet<IAndroidEmulatorInstance>();
   1136 
   1137         if (!tabFolder.isDisposed())
   1138         {
   1139             final TabItem[] allItems = tabFolder.getItems();
   1140 
   1141             for (TabItem item : allItems)
   1142             {
   1143                 if (!item.isDisposed())
   1144                 {
   1145                     instancesWithViewer.add((IAndroidEmulatorInstance) item.getData());
   1146                 }
   1147             }
   1148         }
   1149 
   1150         return instancesWithViewer;
   1151     }
   1152 
   1153     private static Set<IAndroidEmulatorInstance> getInstancesWithAtLeastOneViewer()
   1154     {
   1155         Set<IAndroidEmulatorInstance> instancesSet = new HashSet<IAndroidEmulatorInstance>();
   1156         for (String viewId : childrenIDs)
   1157         {
   1158             AbstractAndroidView view = (AbstractAndroidView) EclipseUtils.getActiveView(viewId);
   1159             if (view != null)
   1160             {
   1161                 instancesSet.addAll(view.getInstancesWithViewer());
   1162             }
   1163         }
   1164 
   1165         return instancesSet;
   1166     }
   1167 
   1168     /**
   1169      * Gets the tab item related to the instance
   1170      * @param instance the emulator instance
   1171      * @return the tab item
   1172      */
   1173     private TabItem getTabItem(IAndroidEmulatorInstance instance)
   1174     {
   1175         TabItem result = null;
   1176         if (!tabFolder.isDisposed())
   1177         {
   1178             TabItem[] allItems = tabFolder.getItems();
   1179 
   1180             for (TabItem item : allItems)
   1181             {
   1182                 if (instance.equals(item.getData()))
   1183                 {
   1184                     result = item;
   1185                     break;
   1186                 }
   1187             }
   1188         }
   1189 
   1190         return result;
   1191     }
   1192 
   1193     /**
   1194      * Gets the tab item related to the instance
   1195      * @param instance the emulator instance
   1196      * @return the tab item
   1197      */
   1198     private TabItem getTabItem(IInstance instance)
   1199     {
   1200         TabItem result = null;
   1201         if (!tabFolder.isDisposed())
   1202         {
   1203             TabItem[] allItems = tabFolder.getItems();
   1204 
   1205             for (TabItem item : allItems)
   1206             {
   1207                 if (instance.getName()
   1208                         .equals(((IAndroidEmulatorInstance) item.getData()).getName()))
   1209                 {
   1210                     result = item;
   1211                     break;
   1212                 }
   1213             }
   1214         }
   1215 
   1216         return result;
   1217     }
   1218 
   1219     /**
   1220      * Retrieves the active tab at view
   1221      *
   1222      * @return The active tab, or null of there is no tab at tab folder
   1223      */
   1224     private TabItem getActiveTabItem()
   1225     {
   1226         int activeInstanceIndex = this.tabFolder.getSelectionIndex();
   1227 
   1228         TabItem activeTabItem = null;
   1229 
   1230         if (activeInstanceIndex >= 0)
   1231         {
   1232             activeTabItem = this.tabFolder.getItem(activeInstanceIndex);
   1233         }
   1234 
   1235         return activeTabItem;
   1236     }
   1237 
   1238     /**
   1239      * Updates the zoom action that needs to be checked.
   1240      * This method must be called every time the focus changes to another
   1241      * viewer
   1242      */
   1243     private void updateMenuAndToolbars()
   1244     {
   1245         IViewSite viewSite = getViewSite();
   1246 
   1247         if (viewSite != null)
   1248         {
   1249             IActionBars actionBars = viewSite.getActionBars();
   1250 
   1251             if (actionBars != null)
   1252             {
   1253                 IMenuManager menuManager = actionBars.getMenuManager();
   1254                 updateMenuManager(menuManager, viewSite);
   1255 
   1256                 IToolBarManager toolbarManager = actionBars.getToolBarManager();
   1257                 if (toolbarManager != null)
   1258                 {
   1259                     IContributionItem[] items = toolbarManager.getItems();
   1260                     for (IContributionItem item : items)
   1261                     {
   1262                         item.update();
   1263                     }
   1264                 }
   1265             }
   1266 
   1267             refreshMenuElements();
   1268         }
   1269     }
   1270 
   1271     /**
   1272      * Recursive method to update items at menus. The recursion helps to update submenus
   1273      *
   1274      * @param manager The manager that holds a menu items
   1275      * @param viewSite The current view site.
   1276      */
   1277     private void updateMenuManager(IMenuManager manager, IViewSite viewSite)
   1278     {
   1279         // Update the items in menu manager
   1280         if (manager != null)
   1281         {
   1282             IContributionItem[] items = manager.getItems();
   1283             for (IContributionItem item : items)
   1284             {
   1285                 if (item instanceof IMenuManager)
   1286                 {
   1287                     updateMenuManager((IMenuManager) item, viewSite);
   1288                 }
   1289                 else
   1290                 {
   1291                     item.update();
   1292                 }
   1293             }
   1294         }
   1295     }
   1296 
   1297     /**
   1298      * Stops all emulator instances with the Progress Monitor opened.
   1299      */
   1300     private void stopEmulatorInstances()
   1301     {
   1302         // defines the runnable object for stopping emulator instances.
   1303         final IRunnableWithProgress stopRunnable = new IRunnableWithProgress()
   1304         {
   1305             public void run(IProgressMonitor monitor)
   1306             {
   1307                 Collection<IAndroidEmulatorInstance> startedInstances =
   1308                         DeviceFrameworkManager.getInstance().getAllStartedInstances();
   1309                 boolean errorsHappened = false;
   1310 
   1311                 for (IAndroidEmulatorInstance instance : startedInstances)
   1312                 {
   1313                     try
   1314                     {
   1315                         instance.stop(true);
   1316                     }
   1317                     catch (InstanceStopException e)
   1318                     {
   1319                         errorsHappened = true;
   1320                     }
   1321                 }
   1322 
   1323                 // if closing on shutdown, use a progress bar and stall UI
   1324                 if (closingOnShutdown)
   1325                 {
   1326                     // start a progress monitor
   1327                     monitor.beginTask("", IProgressMonitor.UNKNOWN);
   1328 
   1329                     // make sure the stop instance job finished
   1330                     Job[] jobs = Job.getJobManager().find(null); // get all jobs
   1331                     for (Job job : jobs)
   1332                     {
   1333                         if (job.getName()
   1334                                 .equals(EmulatorNLS.UI_AbstractAndroidView_StopInstanceJob))
   1335                         {
   1336                             // when job result is not null, it has finished
   1337                             while (job.getResult() == null)
   1338                             {
   1339                                 try
   1340                                 {
   1341                                     // sleep a little so the waiting is not too busy
   1342                                     Thread.sleep(1000);
   1343                                 }
   1344                                 catch (InterruptedException e)
   1345                                 {
   1346                                     // do nothing
   1347                                 }
   1348                             }
   1349                         }
   1350                     }
   1351                 }
   1352 
   1353                 if (errorsHappened)
   1354                 {
   1355                     EclipseUtils.showErrorDialog(EmulatorNLS.GEN_Error,
   1356                             EmulatorNLS.EXC_AncroidView_CannotRunMultipleStopServices);
   1357                 }
   1358 
   1359             }
   1360         };
   1361 
   1362         // executes the runnable defined above.
   1363         PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
   1364         {
   1365             public void run()
   1366             {
   1367                 Shell currentShell = getViewSite().getShell();
   1368                 ProgressMonitorDialog dialog = new ProgressMonitorDialog(currentShell);
   1369                 try
   1370                 {
   1371                     dialog.run(true, false, stopRunnable);
   1372                 }
   1373                 catch (Exception e)
   1374                 {
   1375                     // Should not have exceptions.
   1376                     // The runnable is not interrupted and it handles exceptions internally
   1377                     // Log runtime exceptions
   1378                     error("Runtime exception was thrown: " + e.getClass().getSimpleName());
   1379                 }
   1380             }
   1381         });
   1382     }
   1383 
   1384     /**
   1385      * Sets the identifier of the instance being currently displayed at view
   1386      */
   1387     private void setActiveInstanceId(String activeHost)
   1388     {
   1389         for (String viewId : childrenIDs)
   1390         {
   1391             Collection<IViewPart> viewsToUpdateMenu = EclipseUtils.getAllOpenedViewsWithId(viewId);
   1392             for (IViewPart view : viewsToUpdateMenu)
   1393             {
   1394                 AbstractAndroidView emulatorView = (AbstractAndroidView) view;
   1395                 emulatorView.setSelection(activeHost);
   1396             }
   1397 
   1398         }
   1399     }
   1400 
   1401     /**
   1402      * Sets the identifier of the instance being currently displayed at view
   1403      */
   1404     private void setActiveInstanceId()
   1405     {
   1406         TabItem activeInstanceItem = getActiveTabItem();
   1407         if ((activeInstanceItem != null) && (activeInstanceItem.getData() != null))
   1408         {
   1409 
   1410             activeInstance = (IAndroidEmulatorInstance) activeInstanceItem.getData();
   1411 
   1412             String activeId =
   1413                     ((IAndroidEmulatorInstance) activeInstanceItem.getData())
   1414                             .getInstanceIdentifier();
   1415 
   1416             setActiveInstanceId(activeId);
   1417         }
   1418         else
   1419         {
   1420             debug("No active instance being shown at emulator view");
   1421         }
   1422 
   1423     }
   1424 
   1425     /**
   1426      * Starts the main display associating it to the protocol.
   1427      * @param handle the protocol handle
   1428      * @param mainDisplay the main display object
   1429      */
   1430     private void startDisplay(ProtocolHandle handle, SWTRemoteDisplay mainDisplay)
   1431     {
   1432         // Stop any running screens
   1433         if ((mainDisplay.isActive()) && (!mainDisplay.isDisposed()))
   1434         {
   1435             mainDisplay.stop();
   1436         }
   1437 
   1438         try
   1439         {
   1440             info("Starting main display refresh");
   1441             mainDisplay.start(handle);
   1442         }
   1443         catch (Exception e)
   1444         {
   1445             error("Viewers could not be started.");
   1446             EclipseUtils.showErrorDialog(EmulatorNLS.GEN_Error,
   1447                     EmulatorNLS.EXC_AndroidView_ErrorStartingScreens);
   1448 
   1449             GC gc = new GC(mainDisplay.getCanvas());
   1450             gc.fillRectangle(0, 0, mainDisplay.getScreenWidth(), mainDisplay.getScreenHeight());
   1451             gc.dispose();
   1452         }
   1453     }
   1454 
   1455     /**
   1456      * Starts viewer (main display and CLI display) of the emulator instance.
   1457      * @param instance the emulator instance
   1458      */
   1459     protected void startVncDisplays(final IAndroidEmulatorInstance instance)
   1460     {
   1461         AndroidViewData viewData = instanceDataMap.get(instance);
   1462         if (viewData != null)
   1463         {
   1464             if (viewData.getMainDisplay() != null)
   1465             {
   1466                 startDisplay(instance.getProtocolHandle(), viewData.getMainDisplay());
   1467             }
   1468             if ((viewData.getCliDisplay() != null) && instance.getHasCli())
   1469             {
   1470                 viewData.getCliDisplay().start();
   1471             }
   1472         }
   1473     }
   1474 
   1475     /**
   1476      * Stops viewer (main display and CLI display) of the emulator instance.
   1477      */
   1478     private void stopVncDisplays(final IAndroidEmulatorInstance instance)
   1479     {
   1480         info("Stop the VNC Display " + getViewId() + " for " + instance);
   1481         AndroidViewData viewData = instanceDataMap.get(instance);
   1482 
   1483         if ((viewData != null))
   1484         {
   1485             SWTRemoteDisplay mainDisplay = viewData.getMainDisplay();
   1486             if ((mainDisplay != null) && mainDisplay.isActive() && !mainDisplay.isDisposed())
   1487             {
   1488                 mainDisplay.stop();
   1489                 if ((mainDisplay.getBackground() != null)
   1490                         && !mainDisplay.getBackground().isDisposed())
   1491                 {
   1492                     mainDisplay.getBackground().dispose();
   1493                 }
   1494             }
   1495 
   1496             RemoteCLIDisplay cliDisplay = viewData.getCliDisplay();
   1497             if ((cliDisplay != null) && cliDisplay.isDisplayActive() && !cliDisplay.isDisposed())
   1498             {
   1499                 cliDisplay.stop();
   1500                 if ((cliDisplay.getBackground() != null)
   1501                         && !cliDisplay.getBackground().isDisposed())
   1502                 {
   1503                     cliDisplay.getBackground().dispose();
   1504                 }
   1505             }
   1506         }
   1507     }
   1508 
   1509     /**
   1510      * @param instance
   1511      */
   1512     private void stopVncProtocol(IAndroidLogicInstance instance)
   1513     {
   1514         AndroidEmulatorStopper.stopInstance(instance, true, false, new NullProgressMonitor());
   1515 
   1516     }
   1517 
   1518     /**
   1519      * Stops the execution of the vnc server if it is running on the given instance.
   1520      * This acts as if the Control+C was pressed in the shell where the vnc server is executing...
   1521      * @param instance
   1522      */
   1523     private void stopVncServer(IAndroidEmulatorInstance instance)
   1524     {
   1525         StartVncServerLogic.cancelCurrentVncServerJobs(instance);
   1526     }
   1527 
   1528     /**
   1529      * Class to implement the IPerspectiveListener that you be used as ParListener2 of
   1530      * current page when the Emulator View is opened. It is required to code the
   1531      * work-around for Sticky Views on perspectiveChanged method.
   1532      */
   1533     private class PerspectiveListenerImpl implements IPerspectiveListener
   1534     {
   1535 
   1536         public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective)
   1537         {
   1538             // Nothing to do.
   1539         }
   1540 
   1541         public void perspectiveChanged(IWorkbenchPage page, IPerspectiveDescriptor perspective,
   1542                 String changeId)
   1543         {
   1544             if (changeId.equals(IWorkbenchPage.CHANGE_VIEW_HIDE))
   1545             {
   1546 
   1547                 // if the emulator view was hidden
   1548                 if (page.findView(getViewId()) == null)
   1549                 {
   1550 
   1551                     // This is a "sticky view" so when it is hidden or shown for one
   1552                     // perspective, its state is remembered for the other ones.
   1553                     // However, the view reference count is just updated when
   1554                     // the current active perspective is changed. The code below
   1555                     // forces the perspective changing in order to dispose the view
   1556                     // immediately after it is hidden.
   1557                     for (IPerspectiveDescriptor pd : page.getOpenPerspectives())
   1558                     {
   1559                         if (!pd.equals(perspective))
   1560                         {
   1561                             page.setPerspective(pd);
   1562                         }
   1563                     }
   1564                     page.setPerspective(perspective);
   1565                 }
   1566             }
   1567         }
   1568     }
   1569 
   1570     /**
   1571      * Class to implement IPartListener2 that you be used as ParListener2 of current page
   1572      * when the Emulator View is opened. It is necessary to determine when the view is
   1573      * closed.
   1574      */
   1575     private class PartListenerImpl implements IPartListener2
   1576     {
   1577 
   1578         public void partActivated(IWorkbenchPartReference partRef)
   1579         {
   1580             // Nothing to do.
   1581         }
   1582 
   1583         public void partBroughtToTop(IWorkbenchPartReference partRef)
   1584         {
   1585             // Nothing to do.
   1586         }
   1587 
   1588         public void partClosed(final IWorkbenchPartReference partRef)
   1589         {
   1590 
   1591             // if view that is being closed is not THIS view.
   1592             if (!partRef.getId().equals(getViewId()))
   1593             {
   1594                 return;
   1595             }
   1596 
   1597             // executed on async mode to avoid UI blocking
   1598             PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
   1599             {
   1600                 public void run()
   1601                 {
   1602                     boolean openedViewsExist = false;
   1603 
   1604                     for (String viewId : childrenIDs)
   1605                     {
   1606                         if (!getViewId().equals(viewId)
   1607                                 && (partRef.getPage().findView(viewId) != null))
   1608                         {
   1609                             openedViewsExist = true;
   1610                             break;
   1611                         }
   1612                     }
   1613 
   1614                     // stops all viewers and clear the tabs list
   1615                     Collection<IAndroidEmulatorInstance> instances = getInstancesWithViewer();
   1616                     for (IAndroidEmulatorInstance instance : instances)
   1617                     {
   1618                         disposeViewer(instance);
   1619                     }
   1620 
   1621                     // if the tool is not being closed and there is no other emulator
   1622                     // view opened.
   1623                     if (!closingOnShutdown && !openedViewsExist)
   1624                     {
   1625 
   1626                         Collection<IAndroidEmulatorInstance> startedInstances =
   1627                                 DeviceFrameworkManager.getInstance().getAllStartedInstances();
   1628 
   1629                         boolean oneInstanceStarted = (startedInstances.size() > 0);
   1630 
   1631                         if (oneInstanceStarted
   1632                                 && (DialogWithToggleUtils
   1633                                         .showQuestion(
   1634                                                 STOP_BY_CLOSING_VIEW_KEY_PREFERENCE,
   1635                                                 EmulatorNLS.QUESTION_AndroidView_StopAllInstancesOnDisposeTitle,
   1636                                                 EmulatorNLS.QUESTION_AndroidView_StopAllInstancesOnDisposeMessage)))
   1637                         {
   1638 
   1639                             stopEmulatorInstances();
   1640                         }
   1641                     }
   1642 
   1643                 }
   1644 
   1645             });
   1646         }
   1647 
   1648         public void partDeactivated(IWorkbenchPartReference partRef)
   1649         {
   1650             // Nothing to do.
   1651         }
   1652 
   1653         public void partHidden(IWorkbenchPartReference partRef)
   1654         {
   1655             // Nothing to do.
   1656         }
   1657 
   1658         public void partInputChanged(IWorkbenchPartReference partRef)
   1659         {
   1660             // Nothing to do.
   1661         }
   1662 
   1663         public void partOpened(IWorkbenchPartReference partRef)
   1664         {
   1665            // Nothing to do.
   1666         }
   1667 
   1668         public void partVisible(IWorkbenchPartReference partRef)
   1669         {
   1670             if (partRef.getId().equals(getViewId()))
   1671             {
   1672                 refreshView();
   1673             }
   1674         }
   1675     }
   1676 
   1677     /**
   1678      * Class to implement the IWorkbenchListener that you be used as WorkbenchListener of
   1679      * workbench when the Emulator View is opened. It is used to know if the view
   1680      * is being closed due to workbench shutdown.
   1681      */
   1682     private class WorkbenchListenerImpl implements IWorkbenchListener
   1683     {
   1684 
   1685         public void postShutdown(IWorkbench workbench)
   1686         {
   1687             // Nothing to do.
   1688         }
   1689 
   1690         public boolean preShutdown(IWorkbench workbench, boolean forced)
   1691         {
   1692             closingOnShutdown = true;
   1693 
   1694             Collection<IAndroidEmulatorInstance> startedInstances =
   1695                     DeviceFrameworkManager.getInstance().getAllStartedInstances();
   1696 
   1697             if (startedInstances.size() > 0)
   1698             {
   1699 
   1700                 boolean stopEmulatorInstances = false;
   1701                 if (PluginUtils.getOS() != PluginUtils.OS_LINUX)
   1702                 {
   1703                     stopEmulatorInstances =
   1704                             DialogWithToggleUtils.showQuestion(
   1705                                     STOP_ALL_EMULATORS_IN_SHUTDOWN_KEY_PREFERENCE,
   1706                                     EmulatorNLS.QUESTION_RunningInstancesOnClose_Title,
   1707                                     EmulatorNLS.QUESTION_RunningInstancesOnClose_Text);
   1708                 }
   1709                 else
   1710                 {
   1711                     DialogWithToggleUtils.showWarning(
   1712                             STOP_ALL_EMULATORS_IN_SHUTDOWN_KEY_PREFERENCE,
   1713                             EmulatorNLS.WARN_RunningInstancesOnClose_Linux_Title,
   1714                             EmulatorNLS.WARN_RunningInstancesOnClose_Linux_Text);
   1715                     //stopEmulatorInstances = true;
   1716                 }
   1717 
   1718                 if (stopEmulatorInstances)
   1719                 {
   1720                     stopEmulatorInstances();
   1721                 }
   1722 
   1723             }
   1724 
   1725             return true;
   1726         }
   1727     }
   1728 
   1729     /**
   1730      * Selects the tab that has this data host and set the activeHost
   1731      * @param host IP address
   1732      */
   1733     private void setSelection(final String host)
   1734     {
   1735 
   1736         PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
   1737         {
   1738             public void run()
   1739             {
   1740                 TabItem selectedTab = null;
   1741 
   1742                 TabItem[] tabArray = tabFolder.getItems();
   1743 
   1744                 for (TabItem tabItem : tabArray)
   1745                 {
   1746                     String tabItemHost =
   1747                             ((IAndroidEmulatorInstance) tabItem.getData()).getInstanceIdentifier();
   1748                     if ((host != null) && (host.equals(tabItemHost)))
   1749                     {
   1750                         selectedTab = tabItem;
   1751                         break;
   1752                     }
   1753                 }
   1754 
   1755                 if (selectedTab != null)
   1756                 {
   1757                     tabFolder.setSelection(selectedTab);
   1758                     updateMenuAndToolbars();
   1759                 }
   1760 
   1761             }
   1762         });
   1763 
   1764     }
   1765 
   1766     public static void updateInstanceName(final IInstance instance)
   1767     {
   1768         PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable()
   1769         {
   1770             public void run()
   1771             {
   1772                 if (!childrenIDs.isEmpty())
   1773                 {
   1774                     AbstractAndroidView view =
   1775                             (AbstractAndroidView) EclipseUtils.getActiveView(childrenIDs.get(0));
   1776                     if (view != null)
   1777                     {
   1778                         if ((instance != null))
   1779                         {
   1780                             TabItem tabItem = view.getTabItem(instance);
   1781                             if (tabItem != null)
   1782                             {
   1783                                 tabItem.setText(((IAndroidEmulatorInstance) tabItem.getData())
   1784                                         .getFullName());
   1785                             }
   1786                         }
   1787                     }
   1788                 }
   1789             }
   1790         });
   1791     }
   1792 
   1793     /**
   1794      * Sets the skin zoom factor
   1795      *
   1796      * @param instance the emulator instance
   1797      * @param zoom the zoom factor
   1798      */
   1799     public final void setZoomFactor(IAndroidEmulatorInstance instance, double zoom)
   1800     {
   1801         try
   1802         {
   1803             AndroidViewData viewData = instanceDataMap.get(instance);
   1804             if (viewData != null)
   1805             {
   1806                 IAndroidComposite composite = viewData.getComposite();
   1807                 if (composite != null)
   1808                 {
   1809                     composite.setZoomFactor(zoom);
   1810                 }
   1811             }
   1812         }
   1813         catch (Exception e)
   1814         {
   1815             error("Detached zoom could not be set.");
   1816         }
   1817     }
   1818 
   1819     /**
   1820      * Gets the skin zoom factor
   1821      *
   1822      * @param instance the emulator instance
   1823      * @return the zoom factor
   1824      */
   1825     public final double getZoomFactor(IAndroidEmulatorInstance instance)
   1826     {
   1827         double zoomFactor = 0.0;
   1828         AndroidViewData viewData = instanceDataMap.get(instance);
   1829         if (viewData != null)
   1830         {
   1831             IAndroidComposite composite = viewData.getComposite();
   1832             if (composite != null)
   1833             {
   1834                 zoomFactor = composite.getZoomFactor();
   1835             }
   1836         }
   1837         return zoomFactor;
   1838     }
   1839 }