gt:                         if(t != null) {
context: /*
   * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
   * particular file as subject to the "Classpath" exception as provided
   * by Oracle in the LICENSE file that accompanied this code.
   *
   * This code is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   * version 2 for more details (a copy is included in the LICENSE file that
   * accompanied this code).
   *
   * You should have received a copy of the GNU General Public License version
   * 2 along with this work; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores
   * CA 94065 USA or visit www.oracle.com if you need additional information or
   * have any questions.
   */
  package com.codename1.ui;
  
  import com.codename1.capture.VideoCaptureConstraints;
  import com.codename1.codescan.CodeScanner;
  import com.codename1.contacts.Contact;
  import com.codename1.contacts.ContactsManager;
  import com.codename1.db.Database;
  import com.codename1.location.LocationManager;
  import com.codename1.messaging.Message;
  import com.codename1.ui.animations.Animation;
  import com.codename1.ui.animations.CommonTransitions;
  import com.codename1.ui.animations.Transition;
  import com.codename1.ui.events.ActionEvent;
  import com.codename1.ui.events.ActionListener;
  import com.codename1.ui.geom.Dimension;
  import com.codename1.impl.ImplementationFactory;
  import com.codename1.impl.CodenameOneImplementation;
  import com.codename1.impl.CodenameOneThread;
  import com.codename1.impl.VirtualKeyboardInterface;
  import com.codename1.io.ConnectionRequest;
  import com.codename1.io.Log;
  import com.codename1.io.Preferences;
  import com.codename1.l10n.L10NManager;
  import com.codename1.media.Media;
  import com.codename1.media.MediaRecorderBuilder;
  import com.codename1.notifications.LocalNotification;
  import com.codename1.payment.Purchase;
  import com.codename1.system.CrashReport;
  import com.codename1.ui.events.MessageEvent;
  import com.codename1.ui.geom.Rectangle;
  import com.codename1.ui.plaf.UIManager;
  import com.codename1.ui.util.EventDispatcher;
  import com.codename1.ui.util.ImageIO;
  import com.codename1.util.AsyncResource;
  import com.codename1.util.RunnableWithResultSync;
  import java.io.IOException;
  import java.io.InputStream;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Enumeration;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Hashtable;
  import java.util.LinkedList;
  import java.util.Map;
  import java.util.Timer;
  import java.util.TimerTask;
  
  /**
   * Central class for the API that manages rendering/events and is used to place top
   * level components ({@link Form}) on the "display". 
   * <p>This class handles the main thread for the toolkit referenced here on as the EDT
   * (Event Dispatch Thread) similar to the Swing EDT. This thread encapsulates the platform
   * specific event delivery and painting semantics and enables threading features such as
   * animations etc...
   * <p>The EDT should not be blocked since paint operations and events would also be blocked
   * in much the same way as they would be in other platforms. In order to serialize calls back
   * into the EDT use the methods {@link Display#callSerially} &amp; {@link Display#callSeriallyAndWait}.
   * <p>Notice that all Codename One calls occur on the EDT (events, painting, animations etc...), Codename One
   * should normally be manipulated on the EDT as well (hence the {@link Display#callSerially} &amp;
   * {@link Display#callSeriallyAndWait} methods). Theoretically it should be possible to manipulate
   * some Codename One features from other threads but this can't be guaranteed to work for all use cases.
   *
   * @author Chen Fishbein, Shai Almog
   */
  public final class Display extends CN1Constants {
      private CrashReport crashReporter;
      private EventDispatcher errorHandler;
      boolean codenameOneExited;
      private boolean inNativeUI;
  
      private EventDispatcher messageListeners;
      
      /**
       * A common sound type that can be used with playBuiltinSound
       */
      public static final String SOUND_TYPE_ALARM = "alarm";
  
      /**
       * A common sound type that can be used with playBuiltinSound
       */
      public static final String SOUND_TYPE_CONFIRMATION = "confirmation";
  
      /**
       * A common sound type that can be used with playBuiltinSound
       */
      public static final String SOUND_TYPE_ERROR = "error";
  
      /**
       * A common sound type that can be used with playBuiltinSound
       */
      public static final String SOUND_TYPE_INFO = "info";
  
      /**
       * A common sound type that can be used with playBuiltinSound
       */
      public static final String SOUND_TYPE_WARNING = "warning";
  
      /**
       * A common sound type that can be used with playBuiltinSound
       */
      public static final String SOUND_TYPE_BUTTON_PRESS = "press";
  
      /**
       * Unknown keyboard type is the default indicating the software should try
       * to detect the keyboard type if necessary
       */
      public static final int KEYBOARD_TYPE_UNKNOWN = 0;
  
      /**
       * Numeric keypad keyboard type
       */
      public static final int KEYBOARD_TYPE_NUMERIC = 1;
  
      /**
       * Full QWERTY keypad keyboard type, even if a numeric keyboard also exists
       */
      public static final int KEYBOARD_TYPE_QWERTY = 2;
  
      /**
       * Touch device without a physical keyboard that should popup a keyboad
       */
      public static final int KEYBOARD_TYPE_VIRTUAL = 3;
  
      /**
       * Half QWERTY which needs software assistance for completion
       */
      public static final int KEYBOARD_TYPE_HALF_QWERTY = 4;
      
      private static final int POINTER_PRESSED = 1;
      private static final int POINTER_RELEASED = 2;
      private static final int POINTER_DRAGGED = 3;
      private static final int POINTER_HOVER = 8;
      private static final int POINTER_HOVER_RELEASED = 11;
      private static final int POINTER_HOVER_PRESSED = 12;
      private static final int KEY_PRESSED = 4;
      private static final int KEY_RELEASED = 5;
      private static final int KEY_LONG_PRESSED = 6;
      private static final int SIZE_CHANGED = 7;
      private static final int HIDE_NOTIFY = 9;
      private static final int SHOW_NOTIFY = 10;
      private static final int POINTER_PRESSED_MULTI = 21;
      private static final int POINTER_RELEASED_MULTI = 22;
      private static final int POINTER_DRAGGED_MULTI = 23;
      private boolean disableInvokeAndBlock;
      
      /**
       * Enable Async stack traces.  This is disabled by default, but will cause
       * stack traces of callSerially() calls to be stored, and logged if the 
       * Runnable throws an exception.
       */
      private boolean enableAsyncStackTraces;
      
      
      /**
       * A pure touch device has no focus showing when the user is using the touch
       * interface. Selection only shows when the user actually touches the screen
       * or suddenly switches to using a keypad/trackball. This sort of interface
       * is common in Android devices
       */
      private boolean pureTouch;
  
      private Graphics codenameOneGraphics;
  
      /**
       * Indicates whether this is a touch device
       */
      private boolean touchScreen;
  
      private HashMap<String, String> localProperties;
  
      /**
       * Indicates whether the edt should sleep between each loop
       */
      private boolean noSleep = false;
  
      /**
       * Normally Codename One folds the VKB when switching forms this field allows us
       * to block that behavior.
       */
      private boolean autoFoldVKBOnFormSwitch = true;
  
      /**
       * Indicates the maximum drawing speed of no more than 10 frames per second
       * by default (this can be increased or decreased) the advantage of limiting
       * framerate is to allow the CPU to perform other tasks besides drawing.
       * Notice that when no change is occurring on the screen no frame is drawn and
       * so a high/low FPS will have no effect then.
       */
      private int framerateLock = 15;
  
      /**
       * Game action for fire
       */
      public static final int GAME_FIRE = 8;
  
      /**
       * Game action for left key
       */
      public static final int GAME_LEFT = 2;
  
      /**
       * Game action for right key
       */
      public static final int GAME_RIGHT = 5;
  
      /**
       * Game action for UP key
       */
      public static final int GAME_UP = 1;
  
      /**
       * Game action for down key
       */
      public static final int GAME_DOWN = 6;
  
      /**
       * Special case game key used for media playback events
       */
      public static final int MEDIA_KEY_SKIP_FORWARD = 20;
  
      /**
       * Special case game key used for media playback events
       */
      public static final int MEDIA_KEY_SKIP_BACK = 21;
  
      /**
       * Special case game key used for media playback events
       */
      public static final int MEDIA_KEY_PLAY = 22;
  
      /**
       * Special case game key used for media playback events
       */
      public static final int MEDIA_KEY_STOP = 23;
  
      /**
       * Special case game key used for media playback events
       */
      public static final int MEDIA_KEY_PLAY_STOP = 24;
  
      /**
       * Special case game key used for media playback events
       */
      public static final int MEDIA_KEY_PLAY_PAUSE = 25;
  
      /**
       * Special case game key used for media playback events
       */
      public static final int MEDIA_KEY_FAST_FORWARD = 26;
  
      /**
       * Special case game key used for media playback events
       */
      public static final int MEDIA_KEY_FAST_BACKWARD = 27;
      
      /**
       * An attribute that encapsulates '#' int value.
       */
      public static final int KEY_POUND = '#';
  
      static final Display INSTANCE = new Display();
  
      static int transitionDelay = -1;
  
      static CodenameOneImplementation impl;
  
      private boolean codenameOneRunning = false;
  
  
      /**
       * Contains the call serially pending elements
       */
      private ArrayList<Runnable> pendingSerialCalls = new ArrayList<Runnable>();
  
      /**
       * Contains the call serially idle elements
       */
      private ArrayList<Runnable> pendingIdleSerialCalls = new ArrayList<Runnable>();
  
  
      /**
       * This is the instance of the EDT used internally to indicate whether
       * we are executing on the EDT or some arbitrary thread
       */
      private Thread edt;
  
      /**
       * Contains animations that must be played in full by the EDT before anything further
       * may be processed. This is useful for transitions/intro's etc... that animate without
       * user interaction.
       */
      private ArrayList<Animation> animationQueue;
  
      /**
       * Indicates whether the 3rd softbutton should be supported on this device
       */
      private boolean thirdSoftButton = false;
  
      /**
       * Ignore all calls to show occurring during edit, they are discarded immediately
       */
      public static final int SHOW_DURING_EDIT_IGNORE = 1;
  
      /**
       * If show is called while editing text in the native text box an exception is thrown
       */
      public static final int SHOW_DURING_EDIT_EXCEPTION = 2;
  
      /**
       * Allow show to occur during edit and discard all user input at this moment
       */
      public static final int SHOW_DURING_EDIT_ALLOW_DISCARD = 3;
  
      /**
       * Allow show to occur during edit and save all user input at this moment
       */
      public static final int SHOW_DURING_EDIT_ALLOW_SAVE = 4;
  
      /**
       * Show will update the current form to which the OK button of the text box
       * will return
       */
      public static final int SHOW_DURING_EDIT_SET_AS_NEXT = 5;
  
      private int showDuringEdit;
  
      static final Object lock = new Object();
  
      /**
       * Events to broadcast on the EDT, we are using a handcoded stack for maximum
       * performance and minimal synchronization. We are using the switching algorithm
       * where we only synchronize on the very minimal point of switching between the stacks
       * and adding to the active stack.
       */
      private int[] inputEventStack = new int[1000];
      private int inputEventStackPointer;
      private int[] inputEventStackTmp = new int[1000];
      private int inputEventStackPointerTmp;
  
      private boolean longPointerCharged;
      private boolean pointerPressedAndNotReleasedOrDragged;
      private boolean recursivePointerReleaseA;
      private boolean recursivePointerReleaseB;
      private int pointerX, pointerY;
      private boolean keyRepeatCharged;
      private boolean longPressCharged;
      private long longKeyPressTime;
      private int longPressInterval = 500;
      private long nextKeyRepeatEvent;
      private int keyRepeatValue;
      private int keyRepeatInitialIntervalTime = 800;
      private int keyRepeatNextIntervalTime = 10;
      private boolean lastInteractionWasKeypad;
      private boolean dragOccured;
      private boolean processingSerialCalls;
  
      private int PATHLENGTH;
      private float[] dragPathX;
      private float[] dragPathY;
      private long[] dragPathTime;
      private int dragPathOffset = 0;
      private int dragPathLength = 0;
      
      private Boolean darkMode;
  
       /**
       * Internally track display initialization time as a fixed point to allow tagging of pointer
       * events with an integer timestamp (System.currentTimeMillis() - displayInitTime)
       * and not a long value.
       */
      private long displayInitTime = 0;
  
  
      /**
       * Allows a Codename One application to minimize without forcing it to the front whenever
       * a new dialog is poped up
       */
      private boolean allowMinimizing;
  
      /**
       * Indicates that the Codename One implementation should decide internally the command
       * behavior most appropriate for this platform.
       */
      public static final int COMMAND_BEHAVIOR_DEFAULT = 1;
  
      /**
       * Indicates the classic Codename One command behavior where the commands are placed in
       * a list within a dialog. This is the most customizable approach for none touch devices.
       */
      public static final int COMMAND_BEHAVIOR_SOFTKEY = 2;
  
      /**
       * Indicates the touch menu dialog rendered by Codename One where commands are placed
       * into a scrollable dialog
       */
      public static final int COMMAND_BEHAVIOR_TOUCH_MENU = 3;
  
      /**
       * Indicates that commands should be added to an always visible bar at the
       * bottom of the form.
       */
      public static final int COMMAND_BEHAVIOR_BUTTON_BAR = 4;
  
      /**
       * Identical to the bar behavior, places the back command within the title bar
       * of the form/dialg
       */
      public static final int COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_BACK = 5;
  
      /**
       * Places all commands on the right side of the title bar with a uniform size
       * grid layout
       */
      public static final int COMMAND_BEHAVIOR_BUTTON_BAR_TITLE_RIGHT = 6;
  
      /**
       * Commands are placed in the same was as they are in the ice cream sandwich Android
       * OS update where the back button has a theme icon the application icon appears next
       * to the 
       */
      public static final int COMMAND_BEHAVIOR_ICS = 7;
  
      /**
       * Commands are placed in a side menu similar to Facebook/Google+ apps
       */
      public static final int COMMAND_BEHAVIOR_SIDE_NAVIGATION = 8;
      
      /**
       * Indicates that commands should try to add themselves to the native menus
       */
      public static final int COMMAND_BEHAVIOR_NATIVE = 10;
  
      private static String selectedVirtualKeyboard = null;
  
      private static Map<String, VirtualKeyboardInterface> virtualKeyboards = new HashMap<String, VirtualKeyboardInterface>();
  
      private boolean dropEvents;
      
      private ArrayList<Runnable> backgroundTasks;
      private Thread backgroundThread;
  
      private boolean multiKeyMode;
      
      private ActionListener virtualKeyboardListener;
      private EventDispatcher virtualKeyboardListeners;
      
      private int lastSizeChangeEventWH = -1;
      
  
      /**
       * Private constructor to prevent instanciation
       */
      private Display() {
      }
      
      /**
       * This is the INTERNAL Display initialization method, it will be removed in future versions of the API.
       * This method must be called before any Form is shown
       *
       * @param m platform specific object used by the implementation
       * @deprecated this method is invoked internally do not invoke it!
       */
      public static void init(Object m) {
          if(!INSTANCE.codenameOneRunning) {
              INSTANCE.codenameOneRunning = true;
              INSTANCE.displayInitTime = System.currentTimeMillis();
              
              //restore menu state from previous run if exists
              int commandBehaviour = COMMAND_BEHAVIOR_DEFAULT;
              if(INSTANCE.impl != null){
                  commandBehaviour = INSTANCE.impl.getCommandBehavior();
              }
              INSTANCE.impl = (CodenameOneImplementation)ImplementationFactory.getInstance().createImplementation();
  
              INSTANCE.impl.setDisplayLock(lock);
              INSTANCE.impl.initImpl(m);
              INSTANCE.codenameOneGraphics = new Graphics(INSTANCE.impl.getNativeGraphics());
              INSTANCE.codenameOneGraphics.paintPeersBehind = INSTANCE.impl.paintNativePeersBehind();
              INSTANCE.impl.setCodenameOneGraphics(INSTANCE.codenameOneGraphics);
  
              // only enable but never disable the third softbutton
              if(INSTANCE.impl.isThirdSoftButton()) {
                  INSTANCE.thirdSoftButton = true;
              }
              if(INSTANCE.impl.getSoftkeyCount() > 0) {
                  MenuBar.leftSK = INSTANCE.impl.getSoftkeyCode(0)[0];
                  if(INSTANCE.impl.getSoftkeyCount() > 1) {
                      MenuBar.rightSK = INSTANCE.impl.getSoftkeyCode(1)[0];
                      if(INSTANCE.impl.getSoftkeyCode(1).length > 1){
                          MenuBar.rightSK2 = INSTANCE.impl.getSoftkeyCode(1)[1];
                      }
                  }
              }
              MenuBar.backSK = INSTANCE.impl.getBackKeyCode();
              MenuBar.backspaceSK = INSTANCE.impl.getBackspaceKeyCode();
              MenuBar.clearSK = INSTANCE.impl.getClearKeyCode();
              
              INSTANCE.PATHLENGTH = INSTANCE.impl.getDragPathLength();
              INSTANCE.dragPathX = new float[INSTANCE.PATHLENGTH];
              INSTANCE.dragPathY = new float[INSTANCE.PATHLENGTH];
              INSTANCE.dragPathTime = new long[INSTANCE.PATHLENGTH];
              com.codename1.util.StringUtil.setImplementation(INSTANCE.impl);
              com.codename1.io.Util.setImplementation(INSTANCE.impl);
              
              // this can happen on some cases where an application was restarted etc...
              // generally its probably a bug but we can let it slide...
              if(INSTANCE.edt == null) {
                  INSTANCE.touchScreen = INSTANCE.impl.isTouchDevice();
                  // initialize the Codename One EDT which from now on will take all responsibility
                  // for the event delivery.
                  INSTANCE.edt = new CodenameOneThread(new RunnableWrapper(null, 3), "EDT");
                  INSTANCE.impl.setThreadPriority(INSTANCE.edt, INSTANCE.impl.getEDTThreadPriority());
                  INSTANCE.edt.start();
              }
              INSTANCE.impl.postInit();
              INSTANCE.setCommandBehavior(commandBehaviour);
          }else{
              INSTANCE.impl.confirmControlView();
          }
      }
  
      /**
       * Closes down the EDT and Codename One, under normal conditions this method is completely unnecessary
       * since exiting the application will shut down Codename One. However, if the application is minimized
       * and the user wishes to free all resources without exiting the application then this method can be used.
       * Once this method is used Codename One will no longer work and Display.init(Object) should be invoked
       * again for any further Codename One call!
       * Notice that minimize (being a Codename One method) MUST be invoked before invoking this method!
       */
      public static void deinitialize() {
          
          INSTANCE.codenameOneRunning = false;
          synchronized(lock) {
              lock.notifyAll();
          }
      }
      /**
       * This method returns true if the Display is initialized.
       *
       * @return true if the EDT is running
       */
      public static boolean isInitialized(){
          return INSTANCE.codenameOneRunning && (INSTANCE.impl == null ? false : INSTANCE.impl.isInitialized());
      }
  
      /**
       * Return the Display instance
       *
       * @return the Display instance
       */
      public static Display getInstance(){
          return INSTANCE;
      }
  
      /**
       * This method allows us to manipulate the drag started detection logic.
       * If the pointer was dragged for more than this percentage of the display size it
       * is safe to assume that a drag is in progress.
       *
       * @return motion percentage
       */
      public int getDragStartPercentage() {
          return getImplementation().getDragStartPercentage();
      }
  
      /**
       * This method allows us to manipulate the drag started detection logic.
       * If the pointer was dragged for more than this percentage of the display size it
       * is safe to assume that a drag is in progress.
       *
       * @param dragStartPercentage percentage of the screen required to initiate drag
       */
      public void setDragStartPercentage(int dragStartPercentage) {
          getImplementation().setDragStartPercentage(dragStartPercentage);
      }
  
      CodenameOneImplementation getImplementation() {
          return impl;
      }
  
      /**
       * Indicates the maximum frames the API will try to draw every second
       * by default this is set to 10. The advantage of limiting
       * framerate is to allow the CPU to perform other tasks besides drawing.
       * Notice that when no change is occurring on the screen no frame is drawn and
       * so a high/low FPS will have no effect then.
       * 10FPS would be very reasonable for a business application.
       *
       * @param rate the frame rate
       */
      public void setFramerate(int rate) {
          framerateLock = 1000 / rate;
      }
  
      /**
       * Vibrates the device for the given length of time, notice that this might ignore the time value completely 
       * on some OS's where this level of control isn't supported e.g. iOS see: https://github.com/codenameone/CodenameOne/issues/1904
       *
       * @param duration length of time to vibrate (might be ignored)
       */
      public void vibrate(int duration) {
          impl.vibrate(duration);
      }
  
      /**
       * Flash the backlight of the device for the given length of time
       *
       * @param duration length of time to flash the backlight
       * @deprecated this refers to functionality of devices that are no longer sold, not to the devices "flash"
       */
      public void flashBacklight(int duration) {
          impl.flashBacklight(duration);
      }
  
      /**
       * Invoking the show() method of a form/dialog while the user is editing
       * text in the native text box can have several behaviors: SHOW_DURING_EDIT_IGNORE,
       * SHOW_DURING_EDIT_EXCEPTION, SHOW_DURING_EDIT_ALLOW_DISCARD,
       * SHOW_DURING_EDIT_ALLOW_SAVE, SHOW_DURING_EDIT_SET_AS_NEXT
       *
       * @param showDuringEdit one of the following: SHOW_DURING_EDIT_IGNORE,
       * SHOW_DURING_EDIT_EXCEPTION, SHOW_DURING_EDIT_ALLOW_DISCARD,
       * SHOW_DURING_EDIT_ALLOW_SAVE, SHOW_DURING_EDIT_SET_AS_NEXT
       * @deprecated this method isn't applicable in modern devices
       */
      public void setShowDuringEditBehavior(int showDuringEdit) {
          this.showDuringEdit = showDuringEdit;
      }
  
      /**
       * Returns the status of the show during edit flag
       *
       * @return one of the following: SHOW_DURING_EDIT_IGNORE,
       * SHOW_DURING_EDIT_EXCEPTION, SHOW_DURING_EDIT_ALLOW_DISCARD,
       * SHOW_DURING_EDIT_ALLOW_SAVE, SHOW_DURING_EDIT_SET_AS_NEXT
       * @deprecated this method isn't applicable in modern devices
       */
      public int getShowDuringEditBehavior() {
          return showDuringEdit;
      }
  
      /**
       * Indicates the maximum frames the API will try to draw every second
       *
       * @return the frame rate
       */
      public int getFrameRate() {
          return 1000 / framerateLock;
      }
  
      /**
       * Returns true if we are currently in the event dispatch thread.
       * This is useful for generic code that can be used both with the
       * EDT and outside of it.
       *
       * @return true if we are currently in the event dispatch thread;
       * otherwise false
       */
      public boolean isEdt() {
          return edt == Thread.currentThread();
      }
  
      /**
       * Plays sound for the dialog
       */
      void playDialogSound(final int type) {
          impl.playDialogSound(type);
      }
  
      private DebugRunnable currentEdtContext;
  
      /**
       * Stops the remote control service.  This should be implemented in the platform
       * to handle unbinding the {@link RemoteControlListener} with the platform's remote control.
       * <p>This is executed when a new listener is registered using {@link MediaManager#setRemoteControlListener(com.codename1.media.RemoteControlListener) }</p>
       * @since 7.0
       */
      public void stopRemoteControl() {
          impl.stopRemoteControl();
      }
  
      /**
       * Starts the remote control service.  This should be implemented
       * in the platform to handle binding the {@link RemoteControlListener} with
       * the platform's remote control.
       * 
       * <p>This is executed when the user registers a new listener using {@link MediaManager#setRemoteControlListener(com.codename1.media.RemoteControlListener) }</p>
       * @since 7.0
       */
      public void startRemoteControl() {
          impl.startRemoteControl();
      }
  
      
      /**
       * Returns true if the platform is in dark mode, null is returned for
       * unknown status
       * 
       * @return true in case of dark mode
       */    
      public Boolean isDarkMode() {
          if(darkMode != null) {
              return darkMode;
          }
          return impl.isDarkMode();
      }
      
      /**
       * Override the default dark mode setting
       * @param darkMode can be set to null to reset to platform default
       */
      public void setDarkMode(Boolean darkMode) {
          this.darkMode = darkMode;
      }
      
      private class EdtException extends RuntimeException {
          private Throwable cause;
          private EdtException parent;
          public void setCause(Throwable t) {
              this.cause = t;
          }
  
          public synchronized Throwable getCause() {
              return cause;
          }
          
          private void throwRoot(Throwable cause) {
              HashSet<Throwable> circuitCheck = new HashSet<Throwable>();
              circuitCheck.add(cause);
              EdtException root = this;
              if (root != cause) {
                  root.setCause(cause);
                  circuitCheck.add(root);
              } else {
                  root = (EdtException)cause;
              }
              while (root.parent != null) {
                  if (circuitCheck.contains(root.parent)) {
                      break;
                  }
                  root.parent.setCause(root);
                  circuitCheck.add(root.parent);
                  root = root.parent;
              }
              throw root;
          }
          
      }
      
      private static final int MAX_ASYNC_EXCEPTION_DEPTH=10;
      
      /**
       * A wrapper around Runnable that records the stack trace so that
       * if an exception occurs, it is easier to track it back to the original
       * source.
       */
      private class DebugRunnable implements Runnable {
          private final Runnable internal;
          private EdtException exceptionWrapper;
          private DebugRunnable parentContext;
          private int depth;
          private int totalDepth;
          
          DebugRunnable(Runnable internal) {
              this.internal = internal;
              this.parentContext = currentEdtContext;
              if (parentContext != null) {
                  depth = parentContext.depth+1;
                  totalDepth = parentContext.totalDepth+1;
              }
              
              if (isEnableAsyncStackTraces()) {
                  exceptionWrapper = new EdtException();
                  
                  if (parentContext != null) {
                      if (depth < MAX_ASYNC_EXCEPTION_DEPTH) {
                          exceptionWrapper.parent = parentContext.exceptionWrapper;
                          parentContext = null;
                      } else {
                          depth = 0;
                      }
                  }
              } else {
                  exceptionWrapper = null;
                  parentContext = null;
              }
          }
          
          @Override
          public void run() {
              if (exceptionWrapper != null) {
                  try {
                      currentEdtContext = this;
                      internal.run();
                  } catch (RuntimeException t) {
                      exceptionWrapper.throwRoot(t);
                  }
              } else {
                  internal.run();
              }
          }
          
      }
      
      
      /**
       * Checks if async stack traces are enabled.  If enabled, the stack trace
       * at the point of {@link #callSerially(java.lang.Runnable) } calls will 
       * be recorded, and logged in the case that there is an uncaught exception.
       * <p>Currently this is only supported in the JavaSE/Simulator port.</p>
       * @return Whether async stack traces are enabled.  
       * @see #setEnableAsyncStackTraces(boolean) 
       * @since 7.0
       */
      public boolean isEnableAsyncStackTraces() {
          return enableAsyncStackTraces;
      }
  
      /**
       * Enables or disables async stack traces.  If enabled, the stack trace
       * at the point of {@link #callSerially(java.lang.Runnable) } calls will 
       * be recorded, and logged in the case that there is an uncaught exception.
       * 
       * <p>Currently this is only supported in the JavaSE/Simulator port.</p>
       * @param enableAsyncStackTraces True to enable async stack traces.  
       * @see #isEnableAsyncStackTraces() 
       * @since 7.0
       */
      public void setEnableAsyncStackTraces(boolean enableAsyncStackTraces) {
          this.enableAsyncStackTraces = enableAsyncStackTraces;
      }
      
      /**
       * Causes the runnable to be invoked on the event dispatch thread. This method
       * returns immediately and will not wait for the serial call to occur
       *
       * @param r runnable (NOT A THREAD!) that will be invoked on the EDT serial to
       * the paint and key handling events
       */
      public void callSerially(Runnable r){
          // otherwise this will fail in an odd locaiton. Better it fails here...
          if(r == null) {
              throw new NullPointerException();
          }
          if(codenameOneRunning) {
              synchronized(lock) {
                  pendingSerialCalls.add(isEnableAsyncStackTraces()?new DebugRunnable(r) : r);
                  lock.notifyAll();
              }
          } else {
              r.run();
          }
      }
  
      /**
       * Causes the runnable to be invoked on the event dispatch thread when the event 
       * dispatch thread is idle. This method returns immediately and will not wait for the serial call 
       * to occur. Notice this method is identical to call serially but will perform the runnable only when
       * the EDT is idle
       *
       * @param r runnable (NOT A THREAD!) that will be invoked on the EDT serial to
       * the paint and key handling events
       */
      public void callSeriallyOnIdle(Runnable r){
          if(codenameOneRunning) {
              synchronized(lock) {
                  pendingIdleSerialCalls.add(r);
                  lock.notifyAll();
              }
          } else {
              r.run();
          }
      }
  
      public String getLineSeparator() {
          return impl.getLineSeparator();
      }
      
      /**
       * Allows executing a background task in a separate low priority thread. Tasks are serialized
       * so they don't overload the CPU.
       * 
       * @param r the task to perform in the background
       */
      public void scheduleBackgroundTask(Runnable r) {
          synchronized(lock) {
              if(backgroundTasks == null) {
                  backgroundTasks = new ArrayList<Runnable>();
              }
              backgroundTasks.add(r);
              if(backgroundThread == null) {
                  backgroundThread = new CodenameOneThread(new Runnable() {
                      public void run() {
                          // using while true to avoid double lock optimization with synchronized block
                          while(true) {
                              Runnable nextTask = null;
                              synchronized(lock) {
                                  if(backgroundTasks.size() > 0) {
                                      nextTask = (Runnable)backgroundTasks.get(0);
                                  } else {
                                      backgroundThread = null;
                                      return;
                                  }
                                  backgroundTasks.remove(0);
                              }
                              //preent a runtime exception to crash the 
                              //backgroundThread
                              try {
                                  nextTask.run();                                
                              } catch (Throwable e) {
                                  Log.e(e);
                              }
                              try {
                                  Thread.sleep(10);
                              } catch (InterruptedException ex) {
                              }
                          }
                      }
                  }, "Task Thread");
                  backgroundThread.setPriority(Thread.MIN_PRIORITY + 1);
                  backgroundThread.start();
              }
          }
      }
      
  
      /**
       * Identical to callSerially with the added benefit of waiting for the Runnable method to complete.
       *
       * @param r runnable (NOT A THREAD!) that will be invoked on the EDT serial to
       * the paint and key handling events
       * @throws IllegalStateException if this method is invoked on the event dispatch thread (e.g. during
       * paint or event handling).
       */
      public void callSeriallyAndWait(Runnable r){
          if(isEdt()) {
              throw new RuntimeException("This method MUST NOT be invoked on the EDT");
          }
          RunnableWrapper c = new RunnableWrapper(r, 0);
          callSerially(c);
          flushEdt();
          synchronized(lock) {
              while(!c.isDone()) {
                  try {
                      // poll doneness to prevent potential race conditions
                      lock.wait(50);
                  } catch(InterruptedException err) {}
              }
          }
      }
      
      /**
       * Checks if this platform uses input modes.  No current platforms return true for this.  It is a holdover from J2ME.
       * @return True if the platform supports input modes.  Only true for J2ME and RIM.
       */
      public boolean platformUsesInputMode() {
          return impl.platformUsesInputMode();
      }
  
      /**
       * Identical to callSerially with the added benefit of waiting for the Runnable method to complete.
       *
       * @param r runnable (NOT A THREAD!) that will be invoked on the EDT serial to
       * the paint and key handling events
       * @param timeout timeout duration, on timeout the method just returns
       * @throws IllegalStateException if this method is invoked on the event dispatch thread (e.g. during
       * paint or event handling).
       */
      public void callSeriallyAndWait(Runnable r, int timeout){
          RunnableWrapper c = new RunnableWrapper(r, 0);
          callSerially(c);
          synchronized(lock) {
              long t = System.currentTimeMillis();
              while(!c.isDone()) {
                  try {
                      // poll doneness to prevent potential race conditions
                      lock.wait(20);
                  } catch(InterruptedException err) {}
                  if(System.currentTimeMillis() - t >= timeout) {
                      return;
                  }
              }
          }
      }
  
      /**
       * Allows us to "flush" the edt to allow any pending transitions and input to go
       * by before continuing with our other tasks.
       */
      void flushEdt() {
          if(!isEdt()){
              return;
          }
          while(!shouldEDTSleepNoFormAnimation()) {
              edtLoopImpl();
          }
          while(animationQueue != null && animationQueue.size() > 0){
              edtLoopImpl();
          }
      }
  
      /**
       * Restores the menu in the given form
       */
      private void restoreMenu(Form f) {
          if(f != null) {
              f.restoreMenu();
          }
      }
  
      /**
       * Returns true if the system is currently in the process of transitioning between
       * forms
       * 
       * @return true if in the middle of form transition
       */
      public boolean isInTransition() {
          if (animationQueue != null && animationQueue.size() > 0) {
              Animation ani = (Animation) animationQueue.get(0);
              return ani instanceof Transition;
          }
          return false;
      }
  
      private void paintTransitionAnimation() {
          Animation ani = (Animation) animationQueue.get(0);
          if (!ani.animate()) {
              animationQueue.remove(0);
              if (ani instanceof Transition) {
                  Form source = (Form) ((Transition)ani).getSource();
                  restoreMenu(source);
  
                  if (animationQueue.size() > 0) {
                      ani = (Animation) animationQueue.get(0);
                      if (ani instanceof Transition) {
                          ((Transition) ani).initTransition();
                      }
                  }else{
                      Form f = (Form) ((Transition)ani).getDestination();
                      restoreMenu(f);
                      if (source == null || source == impl.getCurrentForm() || source == getCurrent()) {
                          setCurrentForm(f);
                      }
                      ((Transition) ani).cleanup();
                  }
                  return;
              }
          }
          ani.paint(codenameOneGraphics);
          
          impl.flushGraphics();
  
          if(transitionDelay > 0) {
              // yield for a fraction, some devices don't "properly" implement
              // flush and so require the painting thread to get CPU too.
              try {
                  synchronized(lock){
                      lock.wait(transitionDelay);
                  }
              } catch (InterruptedException ex) {
                  ex.printStackTrace();
              }
          }
      }
  
      /**
       * This method represents the event thread for the UI library on which
       * all events are carried out. It differs from the MIDP event thread to
       * prevent blocking of actual input and drawing operations. This also
       * enables functionality such as "true" modal dialogs etc...
       */
      void mainEDTLoop() {
          impl.initEDT();
          UIManager.getInstance();
          try {
              // when there is no current form the EDT is useful only
              // for features such as call serially
              while(impl.getCurrentForm() == null) {
                  synchronized(lock){
                      breakOut2:
                      
                      if(shouldEDTSleep()) {
                          while(pendingIdleSerialCalls.size() > 0) {
                              Runnable r = pendingIdleSerialCalls.get(0);
                              pendingIdleSerialCalls.remove(0);
                              callSerially(r);
  
                              break breakOut2;
                          }
                          
                          lock.wait();
                      }
  
                      // paint transition or intro animations and don't do anything else if such
                      // animations are in progress...
                      if(animationQueue != null && animationQueue.size() > 0) {
                          paintTransitionAnimation();
                          continue;
                      }
                  }
                  processSerialCalls();
              }
          } catch(Throwable err) {
              Log.e(err);
              if(crashReporter != null) {
                  crashReporter.exception(err);
              }
              if(!impl.handleEDTException(err)) {
                  if(errorHandler != null) {
                      errorHandler.fireActionEvent(new ActionEvent(err,ActionEvent.Type.Exception));
                  } else {
                      Dialog.show("Error", "An internal application error occurred: " + err.toString(), "OK", null);
                  }
              }
          }
  
          while(codenameOneRunning) {
              try {
                  // wait indefinetly Lock surrounds the should method to prevent serial calls from
                  // getting "lost"
                   synchronized(lock){
                      breakOut1:
  
                      if(shouldEDTSleep()) {
                           while(pendingIdleSerialCalls.size() > 0) {
                              Runnable r = pendingIdleSerialCalls.get(0);
                              pendingIdleSerialCalls.remove(0);
                              callSerially(r);
                              break breakOut1;
                           }
                           impl.edtIdle(true);
                           lock.wait();
                           impl.edtIdle(false);
                       }
                   }
                   
  
                  edtLoopImpl();
              } catch(Throwable err) {
                  if(!codenameOneRunning) {
                      return;
                  }
                  Log.e(err);
                  if(crashReporter != null) {
                      CodenameOneThread.handleException(err);
                  }
                  if(!impl.handleEDTException(err)) {
                      if(errorHandler != null) {
                          errorHandler.fireActionEvent(new ActionEvent(err,ActionEvent.Type.Exception));
                      } else {
                          Dialog.show("Error", "An internal application error occurred: " + err.toString(), "OK", null);
                      }
                  }
              }
          }
          INSTANCE.impl.deinitialize();
          //INSTANCE.impl = null;
          //INSTANCE.codenameOneGraphics = null;
          INSTANCE.edt = null;
      }
  
      long time;
  
      /**
       * Implementation of the event dispatch loop content
       */
      void edtLoopImpl() {
          try {
              // transitions shouldn't be bound by framerate
              if(animationQueue == null || animationQueue.size() == 0) {
                  // prevents us from waking up the EDT too much and
                  // thus exhausting the systems resources. The + 1
                  // prevents us from ever waiting 0 milliseconds which
                  // is the same as waiting with no time limit
                  if(!noSleep){
                      synchronized(lock){
                          impl.edtIdle(true);
                          lock.wait(Math.max(1, framerateLock - (time)));
                          impl.edtIdle(false);
                      }
                  }
              } else {
                  // paint transition or intro animations and don't do anything else if such
                  // animations are in progress...
                  paintTransitionAnimation();
                  return;
              }
          } catch(Exception ignor) {
              Log.e(ignor);
          }
          long currentTime = System.currentTimeMillis();
          
          // minimal amount of sync, just flipping the stack pointers
          synchronized(lock) {
              inputEventStackPointerTmp = inputEventStackPointer;
              inputEventStackPointer = 0;
              lastDragOffset = -1;
              int[] qt = inputEventStackTmp;
              inputEventStackTmp = inputEventStack;
  
              // We have a special flag here for a case where the input event stack might still be processing this can 
              // happen if an event callback calls something like invokeAndBlock while processing and might reach
              // this code again
              if(qt[qt.length - 1] == Integer.MAX_VALUE) {
                  inputEventStack = new int[qt.length];
              } else {
                  inputEventStack = qt;
                  qt[qt.length - 1] = 0;
              }
          }
  
          // we copy the variables to the stack since the array might be replaced while we are working if the EDT
          // is nested into an "invokeAndBlock"
          int actualTmpPointer = inputEventStackPointerTmp;
          inputEventStackPointerTmp = 0;
          int[] actualStack = inputEventStackTmp;
          int offset = 0;
          actualStack[actualStack.length - 1] = Integer.MAX_VALUE;
          while(offset < actualTmpPointer) {            
              offset = handleEvent(offset, actualStack);
          }
          
          actualStack[actualStack.length - 1] = 0;
  
      if(!impl.isInitialized()){
              return;
          }
          codenameOneGraphics.setGraphics(impl.getNativeGraphics());
          impl.paintDirty();
  
          // draw the animations
          Form current = impl.getCurrentForm();
          if(current != null){
              current.repaintAnimations();
              // check key repeat events
              long t = System.currentTimeMillis();
              if(keyRepeatCharged && nextKeyRepeatEvent <= t) {
                  current.keyRepeated(keyRepeatValue);
                  nextKeyRepeatEvent = t + keyRepeatNextIntervalTime;
              }
              if(longPressCharged && longPressInterval <= t - longKeyPressTime) {
                  longPressCharged = false;
                  current.longKeyPress(keyRepeatValue);
              }
              if(longPointerCharged && longPressInterval <= t - longKeyPressTime) {
                  longPointerCharged = false;
                  current.longPointerPress(pointerX, pointerY);
              }
          }
          processSerialCalls();
          time = System.currentTimeMillis() - currentTime;
      }
  
      boolean hasNoSerialCallsPending() {
          return pendingSerialCalls.size() == 0;
      }
  
      /**
       * Called by the underlying implementation to indicate that editing in the native
       * system has completed and changes should propagate into Codename One
       *
       * @param c edited component
       * @param text new text for the component
       */
      public void onEditingComplete(final Component c, final String text) {
          if(!isEdt() && codenameOneRunning) {
              Display.getInstance().callSerially(new Runnable() {
                  public void run() {
                      onEditingComplete(c, text);
                  }
              });
              return;
          }
          c.onEditComplete(text);
          c.fireActionEvent();
      }
      
      private final LinkedList<Runnable> runningSerialCallsQueue = new LinkedList<Runnable>();
      /**
       * Used by the EDT to process all the calls submitted via call serially
       */
      void processSerialCalls() {
          processingSerialCalls = true;
          int size = pendingSerialCalls.size();
          if(size > 0) {
              //Runnable[] array = null;
              synchronized(lock) {
                  size = pendingSerialCalls.size();
                  //array = new Runnable[size];
  
                  // copy all elements to an array and remove them otherwise invokeAndBlock from
                  // within a callSerially() can cause an infinite loop...
                  //pendingSerialCalls.toArray(array);
                  runningSerialCallsQueue.addAll(pendingSerialCalls);
  
                  if(size == pendingSerialCalls.size()) {
                      // this is faster
                      pendingSerialCalls.clear();
                  } else {
                      // this can occur if an element was added during the loop
                      for(int iter = 0 ; iter < size ; iter++) {
                          pendingSerialCalls.remove(0);
                      }
                  }
              }
              while (!runningSerialCallsQueue.isEmpty()) {
                  runningSerialCallsQueue.remove(0).run();
              }
  
              // after finishing an event cycle there might be serial calls waiting
              // to return.
              synchronized(lock){
                  lock.notify();
              }
          }
          processingSerialCalls = false;
      }
  
      boolean isProcessingSerialCalls() {
          return processingSerialCalls;
      }
  
      void notifyDisplay(){
          synchronized (lock) {
              lock.notify();
          }
      }
  
      
      /**
       * Invokes a Runnable with blocking disabled.  If any attempt is made to block
       * (i.e. call {@link #invokeAndBlock(java.lang.Runnable) } from inside this Runnable,
       * it will result in a {@link BlockingDisallowedException} being thrown.
       * @param r Runnable to be run immediately.
       * @throws BlockingDisallowedException If {@link #invokeAndBlock(java.lang.Runnable) } is attempted
       * anywhere in the Runnable.
       * 
       * @since 7.0
       */
      public void invokeWithoutBlocking(Runnable r) {
          if (disableInvokeAndBlock || !isEdt()) {
              r.run();
          } else {
              disableInvokeAndBlock = true;
              try {
                  r.run();
              } finally {
                  disableInvokeAndBlock = false;
              }
          }
      }
      
      /**
       * Invokes a RunnableWithResultSync with blocking disabled.  If any attempt is made to block
       * (i.e. call {@link #invokeAndBlock(java.lang.Runnable) } from inside this Runnable,
       * it will result in a {@link BlockingDisallowedException} being thrown.
       * @param r RunnableWithResultSync to be run immediately.
       * @throws BlockingDisallowedException If {@link #invokeAndBlock(java.lang.Runnable) } is attempted
       * anywhere in the Runnable.
       * 
       * @since 7.0
       */
      public <T> T invokeWithoutBlockingWithResultSync(RunnableWithResultSync<T> r) {
          if (disableInvokeAndBlock || !isEdt()) {
              return r.run();
          } else {
              disableInvokeAndBlock = true;
              try {
                  return r.run();
              } finally {
                  disableInvokeAndBlock = false;
              }
          }
      }
      
      /**
       * Invokes runnable and blocks the current thread, if the current thread is the
       * EDT it will still be blocked in a way that doesn't break event dispatch .
       * <b>Important:</b> calling this method spawns a new thread that shouldn't access the UI!<br />
       * See <a href="https://www.codenameone.com/manual/edt.html#_invoke_and_block">
       * this section</a> in the developer guide for further information.
       * 
       * @param r runnable (NOT A THREAD!) that will be invoked synchronously by this method
       * @param dropEvents indicates if the display should drop all events
       * while this runnable is running
       * 
       * @throws BlockingDisallowedException if this method is called while blocking is disabled (i.e. we are running
       * inside a call to {@link #invokeWithoutBlocking(java.lang.Runnable) } on the EDT).
       */
      public void invokeAndBlock(Runnable r, boolean dropEvents){
          this.dropEvents = dropEvents;
          try {
              if(isEdt()) {
                  if (disableInvokeAndBlock) {
                      throw new BlockingDisallowedException();
                  }
                  // this class allows a runtime exception to propogate correctly out of the
                  // internal thread
                  RunnableWrapper w = new RunnableWrapper(r, 1);
                  RunnableWrapper.pushToThreadPool(w);
  
                  synchronized(lock) {
                      // prevent an invoke and block loop from breaking the ongoing event processing
                      if(inputEventStackPointerTmp > 0) {
                          inputEventStackPointerTmp = inputEventStackPointer;
                      }
                      try {
                          // yeald the CPU for a very short time to let the invoke thread
                          // get started
                          lock.wait(2);
                      } catch (InterruptedException ex) {
                          ex.printStackTrace();
                      }
                  }
                  
                  while (!runningSerialCallsQueue.isEmpty()) {
                      pendingSerialCalls.add(0, runningSerialCallsQueue.removeLast());
                  }
  
                  // loop over the EDT until the thread completes then return
                  while(!w.isDone() && codenameOneRunning) {
                       edtLoopImpl();
                       synchronized(lock){
                           if(shouldEDTSleep()) {
                               impl.edtIdle(true);
                               try {
                                  lock.wait(10);
                               } catch (InterruptedException ex) {
                               }
                               impl.edtIdle(false);
                           }
                       }
                  }
                  // if the thread thew an exception we need to throw it onwards
                  if(w.getErr() != null) {
                      throw w.getErr();
                  }
              } else {
                  r.run();
              }
          } catch(RuntimeException re) {
              if (!(re instanceof BlockingDisallowedException)) {
                  Log.e(re);
              }
              throw re;
          } finally {
              this.dropEvents = false;
          } 
      }
  
      /**
       * Invokes runnable and blocks the current thread, if the current thread is the
       * EDT it will still be blocked in a way that doesn't break event dispatch .
       * <b>Important:</b> calling this method spawns a new thread that shouldn't access the UI!<br />
       * See <a href="https://www.codenameone.com/manual/edt.html#_invoke_and_block">
       * this section</a> in the developer guide for further information.
       *
       * @param r runnable (NOT A THREAD!) that will be invoked synchroniously by this method
       */
      public void invokeAndBlock(Runnable r){
          invokeAndBlock(r, false);
      }
  
      /**
       * The name of this method is misleading due to it's legacy. It will return true on the desktop too where
       * the mouse sends pointer events.
       *
       * @return true if this device supports touch/pointer events
       */
      public boolean isTouchScreenDevice() {
          return touchScreen;
      }
  
      /**
       * Indicates if this is a touch screen device that will return pen events,
       * defaults to true if the device has pen events but can be overriden by
       * the developer.
       *
       * @param touchScreen false if this is not a touch screen device
       */
      public void setTouchScreenDevice(boolean touchScreen) {
          this.touchScreen = touchScreen;
      }
      /**
       * Calling this method with noSleep=true will cause the edt to run without sleeping.
       *
       * @param noSleep causes the edt to stop the sleeping periods between 2 cycles
       */
      public void setNoSleep(boolean noSleep){
          this.noSleep = noSleep;
      }
  
      /**
       * Displays the given Form on the screen.
       *
       * @param newForm the Form to Display
       */
      void setCurrent(final Form newForm, boolean reverse){
          if(edt == null) {
              throw new IllegalStateException("Initialize must be invoked before setCurrent!");
          }
          Form current = impl.getCurrentForm();
          
          
          if(autoFoldVKBOnFormSwitch && !(newForm instanceof Dialog)) {
              setShowVirtualKeyboard(false);
          }
  
          if(current == newForm){
              current.revalidateWithAnimationSafety();
              current.repaint();
              current.onShowCompletedImpl();
              return;
          }
          
          if(impl.isEditingText()) {
              switch(showDuringEdit) {
                  case SHOW_DURING_EDIT_ALLOW_DISCARD:
                      break;
                  case SHOW_DURING_EDIT_ALLOW_SAVE:
                      impl.saveTextEditingState();
                      break;
                  case SHOW_DURING_EDIT_EXCEPTION:
                      throw new IllegalStateException("Show during edit");
                  case SHOW_DURING_EDIT_IGNORE:
                      return;
                  case SHOW_DURING_EDIT_SET_AS_NEXT:
                      impl.setCurrentForm(newForm);
                      return;
              }
          }
  
          if(!isEdt()) {
              callSerially(new RunnableWrapper(newForm, null, reverse));
              return;
          }
  
          if(current != null){
              if(current.isInitialized()) {
                  current.deinitializeImpl();
              } else {
                  Form fg = getCurrentUpcoming();
                  if(fg != current) {
                      if(fg.isInitialized()) {
                          fg.deinitializeImpl();
                      }
                  }
              }
          }
          if(!newForm.isInitialized()) {
              newForm.initComponentImpl();
          }
  
          if(newForm.getWidth() != getDisplayWidth() || newForm.getHeight() != getDisplayHeight()) {
              newForm.setSize(new Dimension(getDisplayWidth(), getDisplayHeight()));
              newForm.setShouldCalcPreferredSize(true);
              newForm.layoutContainer();
              newForm.revalidateWithAnimationSafety();
          } else {
              // if shouldLayout is true
              newForm.layoutContainer();
              newForm.revalidateWithAnimationSafety();
              
          }
  
          boolean transitionExists = false;
          if(animationQueue != null && animationQueue.size() > 0) {
              Object o = animationQueue.get(animationQueue.size() - 1);
              if(o instanceof Transition) {
                  current = (Form)((Transition)o).getDestination();
                  impl.setCurrentForm(current);
              }
          }
  
          if(current != null) {
              // make sure the fold menu occurs as expected then set the current
              // to the correct parent!
              if(current instanceof Dialog && ((Dialog)current).isMenu()) {
                  Transition t = current.getTransitionOutAnimator();
                  if(t != null) {
                      // go back to the parent form first
                      if(((Dialog)current).getPreviousForm() != null) {
                          initTransition(t.copy(false), current, ((Dialog)current).getPreviousForm());
                      }
                  }
                  current = ((Dialog)current).getPreviousForm();
                  impl.setCurrentForm(current);
              }
  
              // prevent the transition from occurring from a form into itself
              if(newForm != current) {
                  if((current != null && current.getTransitionOutAnimator() != null) || newForm.getTransitionInAnimator() != null) {
                      if(animationQueue == null) {
                          animationQueue = new ArrayList<Animation>();
                      }
                      // prevent form transitions from breaking our dialog based
                      // transitions which are a bit sensitive
                      if(current != null && (!(newForm instanceof Dialog))) {
                          Transition t = current.getTransitionOutAnimator();
                          if(current != null && t != null) {
                              transitionExists = initTransition(t.copy(reverse), current, newForm);
                          }
                      }
                      if(current != null && !(current instanceof Dialog)) {
                          Transition t = newForm.getTransitionInAnimator();
  