Display.java
上传用户:haobig99
上传日期:2022-06-15
资源大小:369k
文件大小:58k
源码类别:

J2ME

开发平台:

Java

  1. /*
  2.  * Copyright 2008 Sun Microsystems, Inc.  All Rights Reserved.
  3.  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4.  *
  5.  * This code is free software; you can redistribute it and/or modify it
  6.  * under the terms of the GNU General Public License version 2 only, as
  7.  * published by the Free Software Foundation.  Sun designates this
  8.  * particular file as subject to the "Classpath" exception as provided
  9.  * by Sun in the LICENSE file that accompanied this code.
  10.  *
  11.  * This code is distributed in the hope that it will be useful, but WITHOUT
  12.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14.  * version 2 for more details (a copy is included in the LICENSE file that
  15.  * accompanied this code).
  16.  *
  17.  * You should have received a copy of the GNU General Public License version
  18.  * 2 along with this work; if not, write to the Free Software Foundation,
  19.  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20.  *
  21.  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22.  * CA 95054 USA or visit www.sun.com if you need additional information or
  23.  * have any questions.
  24.  */
  25. package com.sun.lwuit;
  26. import com.sun.lwuit.animations.Animation;
  27. import com.sun.lwuit.animations.CommonTransitions;
  28. import com.sun.lwuit.animations.Transition;
  29. import com.sun.lwuit.geom.Dimension;
  30. import com.sun.lwuit.impl.ImplementationFactory;
  31. import com.sun.lwuit.impl.LWUITImplementation;
  32. import java.io.InputStream;
  33. import java.util.Vector;
  34. /**
  35.  * Central class for the API that manages rendering/events and is used to place top
  36.  * level components ({@link Form}) on the "display". Before any Form is shown the Developer must
  37.  * invoke Display.init(Object m) in order to register the current MIDlet.
  38.  * <p>This class handles the main thread for the toolkit referenced here on as the EDT 
  39.  * (Event Dispatch Thread) similar to the Swing EDT. This thread encapsulates the platform
  40.  * specific event delivery and painting semantics and enables threading features such as
  41.  * animations etc...
  42.  * <p>The EDT should not be blocked since paint operations and events would also be blocked 
  43.  * in much the same way as they would be in other platforms. In order to serialize calls back
  44.  * into the EDT use the methods {@link Display#callSerially} &amp; {@link Display#callSeriallyAndWait}.
  45.  * <p>Notice that all LWUIT calls occur on the EDT (events, painting, animations etc...), LWUIT 
  46.  * should normally be manipulated on the EDT as well (hence the {@link Display#callSerially} &amp; 
  47.  * {@link Display#callSeriallyAndWait} methods). Theoretically it should be possible to manipulate
  48.  * some LWUIT features from other threads but this can't be guaranteed to work for all use cases.
  49.  * 
  50.  * @author Chen Fishbein, Shai Almog
  51.  */
  52. public final class Display {
  53.     /**
  54.      * Unknown keyboard type is the default indicating the software should try
  55.      * to detect the keyboard type if necessary
  56.      */
  57.     public static final int KEYBOARD_TYPE_UNKNOWN = 0;
  58.     /**
  59.      * Numeric keypad keyboard type
  60.      */
  61.     public static final int KEYBOARD_TYPE_NUMERIC = 1;
  62.     
  63.     /**
  64.      * Full QWERTY keypad keyboard type, even if a numeric keyboard also exists
  65.      */
  66.     public static final int KEYBOARD_TYPE_QWERTY = 2;
  67.     /**
  68.      * Touch device without a physical keyboard that should popup a keyboad
  69.      */
  70.     public static final int KEYBOARD_TYPE_VIRTUAL = 3;
  71.     /**
  72.      * Half QWERTY which needs software assistance for completion
  73.      */
  74.     public static final int KEYBOARD_TYPE_HALF_QWERTY = 4;
  75.     
  76.     private static final int POINTER_PRESSED = 1;
  77.     private static final int POINTER_RELEASED = 2;
  78.     private static final int POINTER_DRAGGED = 3;
  79.     private static final int POINTER_HOVER = 8;
  80.     private static final int POINTER_HOVER_RELEASED = 11;
  81.     private static final int KEY_PRESSED = 4;
  82.     private static final int KEY_RELEASED = 5;
  83.     private static final int KEY_LONG_PRESSED = 6;
  84.     private static final int SIZE_CHANGED = 7;
  85.     private static final int HIDE_NOTIFY = 9;
  86.     private static final int SHOW_NOTIFY = 10;
  87.     
  88.     
  89.     private Graphics lwuitGraphics;
  90.     /**
  91.      * Indicates whether this is a touch device
  92.      */
  93.     private boolean touchScreen;
  94.     /**
  95.      * Indicates the maximum drawing speed of no more than 10 frames per second
  96.      * by default (this can be increased or decreased) the advantage of limiting
  97.      * framerate is to allow the CPU to perform other tasks besides drawing.
  98.      * Notice that when no change is occurring on the screen no frame is drawn and
  99.      * so a high/low FPS will have no effect then.
  100.      */
  101.     private int framerateLock = 20;
  102.     
  103.     /**
  104.      * Light mode allows the UI to adapt and show less visual effects/lighter versions
  105.      * of these visual effects to work properly on low end devices.
  106.      */
  107.     private boolean lightMode;
  108.     
  109.     /**
  110.      * Game action for fire
  111.      */
  112.     public static final int GAME_FIRE = 8;
  113.     /**
  114.      * Game action for left key
  115.      */
  116.     public static final int GAME_LEFT = 2;
  117.     /**
  118.      * Game action for right key
  119.      */
  120.     public static final int GAME_RIGHT = 5;
  121.     /**
  122.      * Game action for UP key
  123.      */
  124.     public static final int GAME_UP = 1;
  125.     /**
  126.      * Game action for down key
  127.      */
  128.     public static final int GAME_DOWN = 6;
  129.     
  130.     /**
  131.      * An attribute that encapsulates '#' int value.
  132.      */
  133.     public static final int KEY_POUND = '#';
  134.     private static final Display INSTANCE = new Display();
  135.     
  136.     static int transitionDelay = -1;
  137.     private LWUITImplementation impl;
  138.     private boolean lwuitRunning = false;
  139.     
  140.     /**
  141.      * Contains the call serially pending elements
  142.      */
  143.     private Vector pendingSerialCalls = new Vector();
  144.     
  145.     /**
  146.      * This is the instance of the EDT used internally to indicate whether
  147.      * we are executing on the EDT or some arbitrary thread
  148.      */ 
  149.     private Thread edt; 
  150.     /**
  151.      * Contains animations that must be played in full by the EDT before anything further
  152.      * may be processed. This is useful for transitions/intro's etc... that animate without
  153.      * user interaction.
  154.      */
  155.     private Vector animationQueue;
  156.     /**
  157.      * Indicates whether the 3rd softbutton should be supported on this device
  158.      */
  159.     private boolean thirdSoftButton = false;
  160.     
  161.     private boolean editingText;
  162.     /**
  163.      * Ignore all calls to show occurring during edit, they are discarded immediately
  164.      */
  165.     public static final int SHOW_DURING_EDIT_IGNORE = 1;
  166.     /**
  167.      * If show is called while editing text in the native text box an exception is thrown
  168.      */
  169.     public static final int SHOW_DURING_EDIT_EXCEPTION = 2;
  170.     
  171.     /**
  172.      * Allow show to occur during edit and discard all user input at this moment
  173.      */
  174.     public static final int SHOW_DURING_EDIT_ALLOW_DISCARD = 3;
  175.     /**
  176.      * Allow show to occur during edit and save all user input at this moment
  177.      */
  178.     public static final int SHOW_DURING_EDIT_ALLOW_SAVE = 4;
  179.     /**
  180.      * Show will update the current form to which the OK button of the text box
  181.      * will return
  182.      */
  183.     public static final int SHOW_DURING_EDIT_SET_AS_NEXT = 5;
  184.      
  185.     private int showDuringEdit;
  186.     
  187.     static final Object lock = new Object();
  188.     
  189.     /**
  190.      * Events to broadcast on the EDT
  191.      */
  192.     private Vector inputEvents = new Vector();
  193.     private boolean longPointerCharged;
  194.     private int pointerX, pointerY;
  195.     private boolean keyRepeatCharged;
  196.     private boolean longPressCharged;
  197.     private long longKeyPressTime;
  198.     private int longPressInterval = 800;
  199.     private long nextKeyRepeatEvent;
  200.     private int keyRepeatValue;
  201.     private int keyRepeatInitialIntervalTime = 800;
  202.     private int keyRepeatNextIntervalTime = 10;
  203.     private boolean keyReleasedSinceEdit;
  204.     private boolean processingSerialCalls;
  205.     
  206.     private int PATHLENGTH;
  207.     private float[] dragPathX;
  208.     private float[] dragPathY;
  209.     private long[] dragPathTime;
  210.     private int dragPathOffset = 0;
  211.     private int dragPathLength = 0;
  212.     
  213.     /** 
  214.      * Private constructor to prevent instanciation
  215.      */
  216.     private Display() {
  217.     }
  218.     Vector getAnimationQueue() {
  219.         return animationQueue;
  220.     }
  221.     
  222.     /**
  223.      * This is the Display initialization method.
  224.      * This method must be called before any Form is shown
  225.      * 
  226.      * @param m the main running MIDlet
  227.      */
  228.     public static void init(Object m) {
  229.         if(INSTANCE.impl == null) {
  230.             INSTANCE.lwuitRunning = true;
  231.             INSTANCE.impl = ImplementationFactory.getInstance().createImplementation();
  232.             INSTANCE.impl.setDisplayLock(lock);
  233.             INSTANCE.impl.init(m);
  234.             INSTANCE.lwuitGraphics = new Graphics(INSTANCE.impl.getNativeGraphics());
  235.             INSTANCE.impl.setLWUITGraphics(INSTANCE.lwuitGraphics);
  236.             
  237.             // only enable but never disable the third softbutton
  238.             if(INSTANCE.impl.isThirdSoftButton()) {
  239.                 INSTANCE.thirdSoftButton = true;
  240.             }
  241.             if(INSTANCE.impl.getSoftkeyCount() > 0) {
  242.                 Form.leftSK = INSTANCE.impl.getSoftkeyCode(0)[0];
  243.                 if(INSTANCE.impl.getSoftkeyCount() > 1) {
  244.                     Form.rightSK = INSTANCE.impl.getSoftkeyCode(1)[0];
  245.                     if(INSTANCE.impl.getSoftkeyCode(1).length > 1){
  246.                         Form.rightSK2 = INSTANCE.impl.getSoftkeyCode(1)[1];
  247.                     }
  248.                 }
  249.                 Form.backSK = INSTANCE.impl.getBackKeyCode();
  250.                 Form.backspaceSK = INSTANCE.impl.getBackspaceKeyCode();
  251.                 Form.clearSK = INSTANCE.impl.getClearKeyCode();
  252.             }
  253.             
  254.             int width = INSTANCE.getDisplayWidth();
  255.             int height = INSTANCE.getDisplayHeight();
  256.             int colors = INSTANCE.numColors();
  257.             INSTANCE.PATHLENGTH = INSTANCE.impl.getDragPathLength();
  258.             INSTANCE.dragPathX = new float[INSTANCE.PATHLENGTH];
  259.             INSTANCE.dragPathY = new float[INSTANCE.PATHLENGTH];
  260.             INSTANCE.dragPathTime = new long[INSTANCE.PATHLENGTH];
  261.             
  262.             // if the resolution is very high and the amount of memory is very low while the device 
  263.             // itself has many colors (requiring 32 bits per pixel) then we should concerve memory
  264.             // by activating light mode.
  265.             INSTANCE.lightMode = colors > 65536 && width * height * 30 > Runtime.getRuntime().totalMemory();
  266.             // this can happen on some cases where an application was restarted etc...
  267.             // generally its probably a bug but we can let it slide...
  268.             if(INSTANCE.edt == null) {
  269.                 INSTANCE.touchScreen = INSTANCE.impl.isTouchDevice();
  270.                 // initialize the LWUIT EDT which from now on will take all responsibility
  271.                 // for the event delivery.
  272.                 INSTANCE.edt = new Thread(new RunnableWrapper(null, 3), "EDT");
  273.                 INSTANCE.edt.setPriority(Thread.NORM_PRIORITY + 1);
  274.                 INSTANCE.edt.start();
  275.             }
  276.         }
  277.     }
  278.     /**
  279.      * Closes down the EDT and LWUIT, under normal conditions this method is completely unnecessary
  280.      * since exiting the application will shut down LWUIT. However, if the application is minimized
  281.      * and the user wishes to free all resources without exiting the application then this method can be used.
  282.      * Once this method is used LWUIT will no longer work and Display.init(Object) should be invoked
  283.      * again for any further LWUIT call!
  284.      * Notice that minimize (being a LWUIT method) MUST be invoked before invoking this method!
  285.      */
  286.     public static void deinitialize() {
  287.         INSTANCE.lwuitRunning = false;
  288.         synchronized(lock) {
  289.             lock.notifyAll();
  290.         }
  291.     }
  292.     
  293.     /**
  294.      * Return the Display instance
  295.      * 
  296.      * @return the Display instance
  297.      */
  298.     public static Display getInstance(){
  299.         return INSTANCE;
  300.     }
  301.     /**
  302.      * This method allows us to manipulate the drag started detection logic.
  303.      * If the pointer was dragged for more than this percentage of the display size it
  304.      * is safe to assume that a drag is in progress.
  305.      *
  306.      * @return motion percentage
  307.      */
  308.     public int getDragStartPercentage() {
  309.         return getImplementation().getDragStartPercentage();
  310.     }
  311.     /**
  312.      * This method allows us to manipulate the drag started detection logic.
  313.      * If the pointer was dragged for more than this percentage of the display size it
  314.      * is safe to assume that a drag is in progress.
  315.      *
  316.      * @param dragStartPercentage percentage of the screen required to initiate drag
  317.      */
  318.     public void setDragStartPercentage(int dragStartPercentage) {
  319.         getImplementation().setDragStartPercentage(dragStartPercentage);
  320.     }
  321.     LWUITImplementation getImplementation() {
  322.         return impl;
  323.     }
  324.     
  325.     /**
  326.      * Indicates the maximum frames the API will try to draw every second
  327.      * by default this is set to 10. The advantage of limiting
  328.      * framerate is to allow the CPU to perform other tasks besides drawing.
  329.      * Notice that when no change is occurring on the screen no frame is drawn and
  330.      * so a high/low FPS will have no effect then.
  331.      * 10FPS would be very reasonable for a business application.
  332.      * 
  333.      * @param rate the frame rate
  334.      */
  335.     public void setFramerate(int rate) {
  336.         framerateLock = 1000 / rate;
  337.     }
  338.     
  339.     /**
  340.      * Vibrates the device for the given length of time
  341.      * 
  342.      * @param duration length of time to vibrate
  343.      */
  344.     public void vibrate(int duration) {
  345.         impl.vibrate(duration);
  346.     }
  347.     
  348.     /**
  349.      * Flash the backlight of the device for the given length of time
  350.      * 
  351.      * @param duration length of time to flash the backlight
  352.      */
  353.     public void flashBacklight(int duration) {
  354.         impl.flashBacklight(duration);
  355.     }
  356.     /**
  357.      * Invoking the show() method of a form/dialog while the user is editing
  358.      * text in the native text box can have several behaviors: SHOW_DURING_EDIT_IGNORE, 
  359.      * SHOW_DURING_EDIT_EXCEPTION, SHOW_DURING_EDIT_ALLOW_DISCARD, 
  360.      * SHOW_DURING_EDIT_ALLOW_SAVE, SHOW_DURING_EDIT_SET_AS_NEXT
  361.      * 
  362.      * @param showDuringEdit one of the following: SHOW_DURING_EDIT_IGNORE, 
  363.      * SHOW_DURING_EDIT_EXCEPTION, SHOW_DURING_EDIT_ALLOW_DISCARD, 
  364.      * SHOW_DURING_EDIT_ALLOW_SAVE, SHOW_DURING_EDIT_SET_AS_NEXT
  365.      */
  366.     public void setShowDuringEditBehavior(int showDuringEdit) {
  367.         this.showDuringEdit = showDuringEdit;
  368.     }
  369.     /**
  370.      * Returns the status of the show during edit flag
  371.      * 
  372.      * @return one of the following: SHOW_DURING_EDIT_IGNORE, 
  373.      * SHOW_DURING_EDIT_EXCEPTION, SHOW_DURING_EDIT_ALLOW_DISCARD, 
  374.      * SHOW_DURING_EDIT_ALLOW_SAVE, SHOW_DURING_EDIT_SET_AS_NEXT
  375.      */
  376.     public int getShowDuringEditBehavior() {
  377.         return showDuringEdit;
  378.     }
  379.     /**
  380.      * Indicates the maximum frames the API will try to draw every second
  381.      * 
  382.      * @return the frame rate
  383.      */
  384.     public int getFrameRate() {
  385.         return 1000 / framerateLock;
  386.     }
  387.         
  388.     /**
  389.      * Returns true if we are currently in the event dispatch thread.
  390.      * This is useful for generic code that can be used both with the
  391.      * EDT and outside of it.
  392.      * 
  393.      * @return true if we are currently in the event dispatch thread; 
  394.      * otherwise false
  395.      */
  396.     public boolean isEdt() {
  397.         return edt == Thread.currentThread();
  398.     }
  399.     
  400.     /**
  401.      * Plays sound for the dialog
  402.      */
  403.     void playDialogSound(final int type) {
  404.         impl.playDialogSound(type);
  405.     }
  406.     
  407.     /**
  408.      * Causes the runnable to be invoked on the event dispatch thread. This method
  409.      * returns immediately and will not wait for the serial call to occur 
  410.      * 
  411.      * @param r runnable (NOT A THREAD!) that will be invoked on the EDT serial to
  412.      * the paint and key handling events 
  413.      */
  414.     public void callSerially(Runnable r){
  415.         synchronized(lock) {
  416.             pendingSerialCalls.addElement(r);
  417.             lock.notify();
  418.         }
  419.     }
  420.     
  421.     
  422.     /**
  423.      * Identical to callSerially with the added benefit of waiting for the Runnable method to complete.
  424.      * 
  425.      * @param r runnable (NOT A THREAD!) that will be invoked on the EDT serial to
  426.      * the paint and key handling events 
  427.      * @throws IllegalStateException if this method is invoked on the event dispatch thread (e.g. during
  428.      * paint or event handling).
  429.      */
  430.     public void callSeriallyAndWait(Runnable r){
  431.         RunnableWrapper c = new RunnableWrapper(r, 0);
  432.         callSerially(c);
  433.         synchronized(lock) {
  434.             while(!c.isDone()) {
  435.                 try {
  436.                     // poll doneness to prevent potential race conditions
  437.                     lock.wait(50);
  438.                 } catch(InterruptedException err) {}
  439.             }
  440.         }
  441.     }
  442.     
  443.     /**
  444.      * Allows us to "flush" the edt to allow any pending transitions and input to go
  445.      * by before continuing with our other tasks.
  446.      */
  447.     void flushEdt() {
  448.         if(!isEdt()){
  449.             return;
  450.         }
  451.         while(!shouldEDTSleepNoFormAnimation()) {
  452.             edtLoopImpl();
  453.         }
  454.         while(animationQueue != null && animationQueue.size() > 0){
  455.             edtLoopImpl();
  456.         }
  457.     }
  458.     /**
  459.      * Restores the menu in the given form
  460.      */
  461.     private void restoreMenu(Form f) {
  462.         if(f != null) {
  463.             f.restoreMenu();
  464.         }
  465.     }
  466.     
  467.     private void paintTransitionAnimation() {
  468.         Animation ani = (Animation) animationQueue.elementAt(0);
  469.         if (!ani.animate()) {
  470.             animationQueue.removeElementAt(0);
  471.             if (ani instanceof Transition) {
  472.                 Form source = (Form) ((Transition)ani).getSource();
  473.                 restoreMenu(source);
  474.                 
  475.                 if (animationQueue.size() > 0) {
  476.                     ani = (Animation) animationQueue.elementAt(0);
  477.                     if (ani instanceof Transition) {
  478.                         ((Transition) ani).initTransition();
  479.                     }
  480.                 }else{
  481.                     Form f = (Form) ((Transition)ani).getDestination();
  482.                     restoreMenu(f);
  483.                     if (source == null || source == impl.getCurrentForm() || source == getCurrent()) {
  484.                         setCurrentForm(f);
  485.                     }
  486.                     ((Transition) ani).cleanup();
  487.                 }
  488.                 return;
  489.             }
  490.         }
  491.         ani.paint(lwuitGraphics);
  492.         impl.flushGraphics();
  493.         if(transitionDelay > 0) {
  494.             // yield for a fraction, some devices don't "properly" implement
  495.             // flush and so require the painting thread to get CPU too.
  496.             try {
  497.                 synchronized(lock){
  498.                     lock.wait(transitionDelay);
  499.                 }
  500.             } catch (InterruptedException ex) {
  501.                 ex.printStackTrace();
  502.             }
  503.         }
  504.     }
  505.     
  506.     /**
  507.      * This method represents the event thread for the UI library on which 
  508.      * all events are carried out. It differs from the MIDP event thread to 
  509.      * prevent blocking of actual input and drawing operations. This also
  510.      * enables functionality such as "true" modal dialogs etc...
  511.      */
  512.     void mainEDTLoop() {
  513.         try {
  514.             synchronized(lock){
  515.                 // when there is no current form the EDT is useful only
  516.                 // for features such as call serially
  517.                 while(impl.getCurrentForm() == null) {
  518.                     if(shouldEDTSleep()) {
  519.                         lock.wait();
  520.                     }
  521.                     // paint transition or intro animations and don't do anything else if such
  522.                     // animations are in progress...
  523.                     if(animationQueue != null && animationQueue.size() > 0) {
  524.                         paintTransitionAnimation();
  525.                         continue;
  526.                     }
  527.                     processSerialCalls();
  528.                 }
  529.             }
  530.         } catch(Throwable err) {
  531.             err.printStackTrace();
  532.             if(!impl.handleEDTException(err)) {
  533.                 Dialog.show("Error", "An internal application error occurred: " + err.toString(), "OK", null);
  534.             }
  535.         }
  536.         
  537.         while(lwuitRunning) {
  538.             try {
  539.                 // wait indefinetly but no more than the framerate if
  540.                 // there are no animations... If animations exist then
  541.                 // only wait for the framerate
  542.                 // Lock surrounds the should method to prevent serial calls from
  543.                 // getting "lost"
  544.                  synchronized(lock){
  545.                      if(shouldEDTSleep()) {
  546.                          impl.edtIdle(true);
  547.                          lock.wait();
  548.                          impl.edtIdle(false);
  549.                      }
  550.                  } 
  551.                 edtLoopImpl();
  552.             } catch(Throwable err) {
  553.                 err.printStackTrace();
  554.                 if(!impl.handleEDTException(err)) {
  555.                     Dialog.show("Error", "An internal application error occurred: " + err.toString(), "OK", null);
  556.                 }
  557.             }
  558.         }
  559.         INSTANCE.impl = null;
  560.         INSTANCE.lwuitGraphics = null;
  561.         INSTANCE.edt = null;
  562.     }
  563.     
  564.     long time;
  565.     
  566.     /**
  567.      * Implementation of the event dispatch loop content
  568.      */
  569.     void edtLoopImpl() {
  570.         try {
  571.             // transitions shouldn't be bound by framerate
  572.             if(animationQueue == null || animationQueue.size() == 0) {
  573.                 // prevents us from waking up the EDT too much and 
  574.                 // thus exhausting the systems resources. The + 1
  575.                 // prevents us from ever waiting 0 milliseconds which
  576.                 // is the same as waiting with no time limit
  577.                 synchronized(lock){
  578.                     lock.wait(Math.max(30, framerateLock - (time)));
  579.                 }
  580.                 
  581.             } else {
  582.                 // paint transition or intro animations and don't do anything else if such
  583.                 // animations are in progress...
  584.                 paintTransitionAnimation();
  585.                 return;
  586.             }
  587.         } catch(Exception ignor) {
  588.             ignor.printStackTrace();
  589.         }
  590.         long currentTime = System.currentTimeMillis();
  591.         while(inputEvents.size() > 0) {
  592.             int[] i = (int[])inputEvents.elementAt(0);
  593.             inputEvents.removeElementAt(0);
  594.             handleEvent(i);
  595.         }
  596.         lwuitGraphics.setGraphics(impl.getNativeGraphics());
  597.         impl.paintDirty();
  598.         // draw the animations
  599.         Form current = impl.getCurrentForm();
  600.         current.repaintAnimations();
  601.         
  602.         // check key repeat events
  603.         long t = System.currentTimeMillis();
  604.         if(keyRepeatCharged && nextKeyRepeatEvent <= t) {
  605.             current.keyRepeated(keyRepeatValue);
  606.             nextKeyRepeatEvent = t + keyRepeatNextIntervalTime;
  607.         }
  608.         if(longPressCharged && longPressInterval <= t - longKeyPressTime) {
  609.             longPressCharged = false;
  610.             current.longKeyPress(keyRepeatValue);
  611.         }
  612.         if(longPointerCharged && longPressInterval <= t - longKeyPressTime) {
  613.             longPointerCharged = false;
  614.             current.longPointerPress(pointerX, pointerY);
  615.         }
  616.         processSerialCalls();
  617.         time = System.currentTimeMillis() - currentTime;
  618.     }
  619.     
  620.     boolean hasNoSerialCallsPending() {
  621.         return pendingSerialCalls.size() == 0;
  622.     }
  623.     
  624.     /**
  625.      * Called by the underlying implementation to indicate that editing in the native
  626.      * system has completed and changes should propogate into LWUIT
  627.      * 
  628.      * @param c edited component
  629.      * @param text new text for the component
  630.      */
  631.     public void onEditingComplete(Component c, String text) {
  632.         c.onEditComplete(text);
  633.         c.fireActionEvent();
  634.     }
  635.     
  636.     /**
  637.      * Used by the EDT to process all the calls submitted via call serially
  638.      */
  639.     void processSerialCalls() {
  640.         processingSerialCalls = true;
  641.         int size = pendingSerialCalls.size();
  642.         if(size > 0) {
  643.             Runnable[] array = new Runnable[size];
  644.             // copy all elements to an array and remove them otherwise invokeAndBlock from
  645.             // within a callSerially() can cause an infinite loop...
  646.             for(int iter = 0 ; iter < size ; iter++) {
  647.                 array[iter] = (Runnable)pendingSerialCalls.elementAt(iter);
  648.             }
  649.             synchronized(lock) {
  650.                 if(size == pendingSerialCalls.size()) {
  651.                     // this is faster
  652.                     pendingSerialCalls.removeAllElements();
  653.                 } else {
  654.                     // this can occur if an element was added during the loop
  655.                     for(int iter = 0 ; iter < size ; iter++) {
  656.                         pendingSerialCalls.removeElementAt(0);
  657.                     }
  658.                 }
  659.             }
  660.             for(int iter = 0 ; iter < size ; iter++) {
  661.                 array[iter].run();
  662.             }
  663.             // after finishing an event cycle there might be serial calls waiting
  664.             // to return.
  665.             synchronized(lock){
  666.                 lock.notify();
  667.             }
  668.         }
  669.         processingSerialCalls = false;
  670.     }
  671.     boolean isProcessingSerialCalls() {
  672.         return processingSerialCalls;
  673.     }
  674.     
  675.     void notifyDisplay(){
  676.         synchronized (lock) {
  677.             lock.notify();
  678.         }
  679.     }
  680.     
  681.     /**
  682.      * Invokes runnable and blocks the current thread, if the current thread is the
  683.      * edt it will still be blocked however a separate thread would be launched
  684.      * to perform the duties of the EDT while it is blocked. Once blocking is finished
  685.      * the EDT would be restored to its original position. This is very similar to the
  686.      * "foxtrot" Swing toolkit and allows coding "simpler" logic that requires blocking
  687.      * code in the middle of event sensitive areas.
  688.      * 
  689.      * @param r runnable (NOT A THREAD!) that will be invoked synchroniously by this method
  690.      */
  691.     public void invokeAndBlock(Runnable r){
  692.         if(isEdt()) {
  693.             // this class allows a runtime exception to propogate correctly out of the
  694.             // internal thread
  695.             RunnableWrapper w = new RunnableWrapper(r, 1);
  696.             RunnableWrapper.pushToThreadPull(w);
  697.             // loop over the EDT until the thread completes then return
  698.             while(!w.isDone()) {
  699.                 try {
  700.                     edtLoopImpl();
  701.                     synchronized(lock) {
  702.                         lock.wait(framerateLock);
  703.                     }
  704.                 } catch (InterruptedException ex) {
  705.                     ex.printStackTrace();
  706.                 }
  707.             }
  708.             // if the thread thew an exception we need to throw it onwards
  709.             if(w.getErr() != null) {
  710.                 throw w.getErr();
  711.             }
  712.         } else {
  713.             r.run();
  714.         }
  715.     }
  716.     /**
  717.      * Indicates if this is a touch screen device that will return pen events,
  718.      * defaults to true if the device has pen events but can be overriden by
  719.      * the developer.
  720.      * 
  721.      * @return true if this device supports touch events
  722.      */
  723.     public boolean isTouchScreenDevice() {
  724.         return touchScreen;
  725.     }
  726.     
  727.     /**
  728.      * Indicates if this is a touch screen device that will return pen events,
  729.      * defaults to true if the device has pen events but can be overriden by
  730.      * the developer.
  731.      * 
  732.      * @param touchScreen false if this is not a touch screen device
  733.      */
  734.     public void setTouchScreenDevice(boolean touchScreen) {
  735.         this.touchScreen = touchScreen;
  736.     }
  737.     
  738.     /**
  739.      * Displays the given Form on the screen.
  740.      * 
  741.      * @param newForm the Form to Display
  742.      */
  743.     void setCurrent(final Form newForm, boolean reverse){
  744.         if(edt == null) {
  745.             throw new IllegalStateException("Initialize must be invoked before setCurrent!");
  746.         }
  747.         
  748.         if(isVirtualKeyboardShowingSupported()) {
  749.             setShowVirtualKeyboard(false);
  750.         }
  751.         
  752.         if(editingText) {
  753.             switch(showDuringEdit) {
  754.                 case SHOW_DURING_EDIT_ALLOW_DISCARD:
  755.                     break;
  756.                 case SHOW_DURING_EDIT_ALLOW_SAVE:
  757.                     impl.saveTextEditingState();
  758.                     break;
  759.                 case SHOW_DURING_EDIT_EXCEPTION:
  760.                     throw new IllegalStateException("Show during edit");
  761.                 case SHOW_DURING_EDIT_IGNORE:
  762.                     return;
  763.                 case SHOW_DURING_EDIT_SET_AS_NEXT:
  764.                     impl.setCurrentForm(newForm);
  765.                     return;
  766.             }
  767.         }
  768.         
  769.         if(!isEdt()) {
  770.             callSerially(new RunnableWrapper(newForm, null, reverse));
  771.             return;
  772.         }
  773.         
  774.         Form current = impl.getCurrentForm();
  775.         if(current != null){
  776.             if(current.isInitialized()) {
  777.                 current.deinitializeImpl();
  778.             }
  779.         }
  780.         if(!newForm.isInitialized()) {
  781.             newForm.initComponentImpl();
  782.         }
  783.         if(newForm.getWidth() != getDisplayWidth() || newForm.getHeight() != getDisplayHeight()) {
  784.             newForm.setShouldCalcPreferredSize(true);
  785.             newForm.layoutContainer();
  786.         }
  787.         synchronized(lock) {
  788.             boolean transitionExists = false;
  789.             if(animationQueue != null && animationQueue.size() > 0) {
  790.                 Object o = animationQueue.lastElement();
  791.                 if(o instanceof Transition) {
  792.                     current = (Form)((Transition)o).getDestination();
  793.                     impl.setCurrentForm(current);
  794.                 }
  795.             }
  796.             if(current != null) {
  797.                 // make sure the fold menu occurs as expected then set the current
  798.                 // to the correct parent!
  799.                 if(current instanceof Dialog && ((Dialog)current).isMenu()) {
  800.                     Transition t = current.getTransitionOutAnimator();
  801.                     if(t != null) {
  802.                         // go back to the parent form first
  803.                         if(((Dialog)current).getPreviousForm() != null) {
  804.                             initTransition(t.copy(false), current, ((Dialog)current).getPreviousForm());
  805.                         }
  806.                     }
  807.                     current = ((Dialog)current).getPreviousForm();
  808.                     impl.setCurrentForm(current);
  809.                 }
  810.                 // prevent the transition from occurring from a form into itself
  811.                 if(newForm != current) {
  812.                     if((current != null && current.getTransitionOutAnimator() != null) || newForm.getTransitionInAnimator() != null) {
  813.                         if(animationQueue == null) {
  814.                             animationQueue = new Vector();
  815.                         }
  816.                         // prevent form transitions from breaking our dialog based
  817.                         // transitions which are a bit sensitive
  818.                         if(current != null && (!(newForm instanceof Dialog))) {
  819.                             Transition t = current.getTransitionOutAnimator();
  820.                             if(current != null && t != null) {
  821.                                 initTransition(t.copy(reverse), current, newForm);
  822.                                 transitionExists = true;
  823.                             }
  824.                         }
  825.                         if(current != null && !(current instanceof Dialog)) {
  826.                             Transition t = newForm.getTransitionInAnimator();
  827.                             if(t != null) {
  828.                                 initTransition(t.copy(reverse), current, newForm);
  829.                                 transitionExists = true;
  830.                             }
  831.                         }
  832.                     }
  833.                 }
  834.             }
  835.             lock.notify();
  836.             
  837.             if(!transitionExists) {
  838.                 if(animationQueue == null || animationQueue.size() == 0) {
  839.                     setCurrentForm(newForm);
  840.                 } else {
  841.                     // we need to add an empty transition to "serialize" this
  842.                     // screen change...
  843.                     Transition t = CommonTransitions.createEmpty();
  844.                     initTransition(t, current, newForm);
  845.                 }
  846.             }
  847.         }
  848.     }
  849.     
  850.     /**
  851.      * Initialize the transition and add it to the queue
  852.      */
  853.     private void initTransition(Transition transition, Form source, Form dest) {
  854.         dest.setVisible(true);
  855.         transition.init(source, dest);
  856.         animationQueue.addElement(transition);
  857.         
  858.         if(animationQueue.size() == 1) {
  859.             transition.initTransition();
  860.         }
  861.     }
  862.     
  863.     void setCurrentForm(Form newForm){
  864.         Form current = impl.getCurrentForm();
  865.         if(current != null){
  866.             current.setVisible(false);
  867.         }
  868.         current = newForm;
  869.         impl.setCurrentForm(current);
  870.         current.setVisible(true);
  871.         impl.confirmControlView();
  872.         int w = current.getWidth();
  873.         int h = current.getHeight();
  874.         if(isEdt() && ( w != impl.getDisplayWidth() || h != impl.getDisplayHeight())){
  875.            current.setSize(new Dimension(impl.getDisplayWidth(), impl.getDisplayHeight()));
  876.            
  877.            current.setShouldCalcPreferredSize(true);
  878.            current.layoutContainer();
  879.         }
  880.         lastKeyPressed = 0;
  881.         repaint(current);
  882.         newForm.onShowCompleted();
  883.     }
  884.     
  885.     /**
  886.      * Indicate to the implementation whether the flush graphics bug exists on this
  887.      * device. By default the flushGraphics bug is set to "true" and only disabled
  888.      * on handsets known 100% to be safe
  889.      * 
  890.      * @param flushGraphicsBug true if the bug exists on this device (the safe choice)
  891.      * false for slightly higher performance.
  892.      * @deprecated this method is no longer supported use GameCanvasImplementation.setFlashGraphicsBug(f) instead
  893.      */
  894.     public void setFlashGraphicsBug(boolean flushGraphicsBug) {
  895.     }
  896.     
  897.     /**
  898.      * Indicates whether a delay should exist between calls to flush graphics during
  899.      * transition. In some devices flushGraphics is asynchronious causing it to be
  900.      * very slow with our background thread. The solution is to add a short wait allowing
  901.      * the implementation time to paint the screen. This value is set automatically by default
  902.      * but can be overriden for some devices.
  903.      * 
  904.      * @param transitionD -1 for no delay otherwise delay in milliseconds
  905.      */
  906.     public void setTransitionYield(int transitionD) {
  907.         transitionDelay = transitionD;
  908.     }
  909.     /**
  910.      * Encapsulates the editing code which is specific to the platform, some platforms
  911.      * would allow "in place editing" MIDP does not.
  912.      * 
  913.      * @param cmp the {@link TextArea} component
  914.      */
  915.     public void editString(Component cmp, int maxSize, int constraint, String text) {
  916.         editingText = true;
  917.         keyRepeatCharged = false;
  918.         longPressCharged = false;
  919.         keyReleasedSinceEdit = false;
  920.         lastKeyPressed = 0;
  921.         impl.editString(cmp, maxSize, constraint, text);
  922.         editingText = false;
  923.     }
  924.     /**
  925.      * Minimizes the current application if minimization is supported by the platform (may fail).
  926.      * Returns false if minimization failed.
  927.      *
  928.      * @return false if minimization failed true if it succeeded or seems to be successful
  929.      */
  930.     public boolean minimizeApplication() {
  931.         return getImplementation().minimizeApplication();
  932.     }
  933.     /**
  934.      * Indicates whether an application is minimized
  935.      *
  936.      * @return true if the application is minimized
  937.      */
  938.     public boolean isMinimized() {
  939.         return getImplementation().isMinimized();
  940.     }
  941.     /**
  942.      * Restore the minimized application if minimization is supported by the platform
  943.      */
  944.     public void restoreMinimizedApplication() {
  945.         getImplementation().restoreMinimizedApplication();
  946.     }
  947.     private void addInputEvent(int[] ev) {
  948.         synchronized(lock) {
  949.             inputEvents.addElement(ev);
  950.             lock.notify();
  951.         }
  952.     }
  953.     /**
  954.      * Creates a pointer event with the following properties
  955.      */
  956.     private int[] createPointerEvent(int[] x, int[] y, int eventType) {
  957.         if(x.length == 1) {
  958.             return new int[] {eventType, x[0], y[0]};
  959.         }
  960.         int[] arr = new int[1 + x.length * 2];
  961.         arr[0] = eventType;
  962.         int arrayOffset = 1;
  963.         for(int iter = 0 ; iter < x.length ; iter++) {
  964.             arr[arrayOffset] = x[iter];
  965.             arrayOffset++;
  966.             arr[arrayOffset] = y[iter];
  967.             arrayOffset++;
  968.         }
  969.         return arr;
  970.     }
  971.     private int[] createKeyEvent(int keyCode, boolean pressed) {
  972.         if(pressed) {
  973.             return new int[] {KEY_PRESSED, keyCode};
  974.         } else {
  975.             return new int[] {KEY_RELEASED, keyCode};
  976.         }
  977.     }
  978.     
  979.     private int lastKeyPressed;
  980.     
  981.     /**
  982.      * Pushes a key press event with the given keycode into LWUIT
  983.      * 
  984.      * @param keyCode keycode of the key event
  985.      */
  986.     public void keyPressed(final int keyCode){
  987.         if(impl.getCurrentForm() == null){
  988.             return;
  989.         }
  990.         addInputEvent(createKeyEvent(keyCode, true));
  991.         // this solves a Sony Ericsson bug where on slider open/close someone "brilliant" chose
  992.         // to send a keyPress with a -43/-44 keycode... Without ever sending a key release!
  993.         keyRepeatCharged = (keyCode >= 0 || getGameAction(keyCode) > 0);
  994.         longPressCharged = keyRepeatCharged;
  995.         longKeyPressTime = System.currentTimeMillis();
  996.         keyRepeatValue = keyCode;
  997.         nextKeyRepeatEvent = System.currentTimeMillis() + keyRepeatInitialIntervalTime;
  998.         lastKeyPressed = keyCode;
  999.     }
  1000.     /**
  1001.      * Pushes a key release event with the given keycode into LWUIT
  1002.      * 
  1003.      * @param keyCode keycode of the key event
  1004.      */
  1005.     public void keyReleased(final int keyCode){
  1006.         keyRepeatCharged = false;
  1007.         longPressCharged = false;
  1008.         if(impl.getCurrentForm() == null){
  1009.             return;
  1010.         }
  1011.         // this can happen when traversing from the native form to the current form
  1012.         // caused by a keypress
  1013.         if((!keyReleasedSinceEdit) && keyCode != lastKeyPressed) {
  1014.             return;
  1015.         }
  1016.         keyReleasedSinceEdit = true;
  1017.         addInputEvent(createKeyEvent(keyCode, false));
  1018.     }
  1019.     void keyRepeatedInternal(final int keyCode){
  1020.     }
  1021.     
  1022.     /**
  1023.      * Pushes a pointer drag event with the given coordinates into LWUIT
  1024.      * 
  1025.      * @param x the x position of the pointer
  1026.      * @param y the y position of the pointer
  1027.      */
  1028.     public void pointerDragged(final int[] x, final int[] y){
  1029.         if(impl.getCurrentForm() == null){
  1030.             return;
  1031.         }
  1032.         longPointerCharged = false;
  1033.         addInputEvent(createPointerEvent(x, y, POINTER_DRAGGED));
  1034.     }
  1035.     /**
  1036.      * Pushes a pointer hover event with the given coordinates into LWUIT
  1037.      * 
  1038.      * @param x the x position of the pointer
  1039.      * @param y the y position of the pointer
  1040.      */
  1041.     public void pointerHover(final int[] x, final int[] y){
  1042.         if(impl.getCurrentForm() == null){
  1043.             return;
  1044.         }
  1045.         addInputEvent(createPointerEvent(x, y, POINTER_HOVER));
  1046.     }
  1047.     /**
  1048.      * Pushes a pointer hover release event with the given coordinates into LWUIT
  1049.      *
  1050.      * @param x the x position of the pointer
  1051.      * @param y the y position of the pointer
  1052.      */
  1053.     public void pointerHoverReleased(final int[] x, final int[] y){
  1054.         if(impl.getCurrentForm() == null){
  1055.             return;
  1056.         }
  1057.         addInputEvent(createPointerEvent(x, y, POINTER_HOVER_RELEASED));
  1058.     }
  1059.     /**
  1060.      * Pushes a pointer press event with the given coordinates into LWUIT
  1061.      * 
  1062.      * @param x the x position of the pointer
  1063.      * @param y the y position of the pointer
  1064.      */
  1065.     public void pointerPressed(final int[] x,final int[] y){
  1066.         if(impl.getCurrentForm() == null){
  1067.             return;
  1068.         }
  1069.         longPointerCharged = true;
  1070.         longKeyPressTime = System.currentTimeMillis();
  1071.         pointerX = x[0];
  1072.         pointerY = y[0];
  1073.         addInputEvent(createPointerEvent(x, y, POINTER_PRESSED));
  1074.     }
  1075.     
  1076.     /**
  1077.      * Pushes a pointer release event with the given coordinates into LWUIT
  1078.      * 
  1079.      * @param x the x position of the pointer
  1080.      * @param y the y position of the pointer
  1081.      */
  1082.     public void pointerReleased(final int[] x, final int[] y){
  1083.         longPointerCharged = false;
  1084.         if(impl.getCurrentForm() == null){
  1085.             return;
  1086.         }
  1087.         addInputEvent(createPointerEvent(x, y, POINTER_RELEASED));
  1088.     }
  1089.     /**
  1090.      * Notifies LWUIT of display size changes, this method is invoked by the implementation
  1091.      * class and is for internal use
  1092.      * 
  1093.      * @param w the width of the drawing surface
  1094.      * @param h the height of the drawing surface
  1095.      */
  1096.     public void sizeChanged(int w, int h){
  1097.         Form current = impl.getCurrentForm();
  1098.         if(current == null) {
  1099.             return;
  1100.         }
  1101.         if(w == current.getWidth() && h == current.getHeight()) {
  1102.             return;
  1103.         }
  1104.             
  1105.         addInputEvent(createSizeChangedEvent(w, h));
  1106.     }
  1107.     private int[] createSizeChangedEvent(int w, int h) {
  1108.         return new int[] {SIZE_CHANGED, w, h};
  1109.     }
  1110.     public void hideNotify(){
  1111.         keyRepeatCharged = false;
  1112.         longPressCharged = false;
  1113.         longPointerCharged = false;
  1114.         addInputEvent(new int[]{HIDE_NOTIFY});
  1115.     }
  1116.     public void showNotify(){
  1117.         addInputEvent(new int[]{SHOW_NOTIFY});        
  1118.     }
  1119.     
  1120.     
  1121.     /**
  1122.      * Used by the flush functionality which doesn't care much about component
  1123.      * animations
  1124.      */
  1125.     boolean shouldEDTSleepNoFormAnimation() {
  1126.         synchronized(lock){
  1127.             return inputEvents.size() == 0 &&
  1128.                     hasNoSerialCallsPending() && 
  1129.                     (!keyRepeatCharged || !longPressCharged);
  1130.         }
  1131.     }
  1132.     private void updateDragSpeedStatus(int[] ev) {
  1133.             //save dragging input to calculate the dragging speed later
  1134.             dragPathX[dragPathOffset] = pointerEvent(1, ev)[0];
  1135.             dragPathY[dragPathOffset] = pointerEvent(2, ev)[0];
  1136.             dragPathTime[dragPathOffset] = System.currentTimeMillis();
  1137.             if (dragPathLength < PATHLENGTH) {
  1138.                 dragPathLength++;
  1139.             }
  1140.             dragPathOffset++;
  1141.             if (dragPathOffset >= PATHLENGTH) {
  1142.                 dragPathOffset = 0;
  1143.             }
  1144.     }
  1145.     /**
  1146.      * Invoked on the EDT to propagate the event
  1147.      */
  1148.     private void handleEvent(int[] ev) {
  1149.         Form f = getCurrentUpcomingForm(true);
  1150.         
  1151.         switch(ev[0]) {
  1152.         case KEY_PRESSED:
  1153.             f.keyPressed(ev[1]);
  1154.             break;
  1155.         case KEY_RELEASED:
  1156.             f.keyReleased(ev[1]);
  1157.             break;
  1158.         case POINTER_PRESSED:
  1159.             f.pointerPressed(pointerEvent(1, ev), pointerEvent(2, ev));
  1160.             break;
  1161.         case POINTER_RELEASED:
  1162.             f.pointerReleased(pointerEvent(1, ev), pointerEvent(2, ev));
  1163.             break;
  1164.         case POINTER_DRAGGED:
  1165.             updateDragSpeedStatus(ev);
  1166.             f.pointerDragged(pointerEvent(1, ev), pointerEvent(2, ev));
  1167.             break;
  1168.         case POINTER_HOVER:
  1169.             updateDragSpeedStatus(ev);
  1170.             f.pointerHover(pointerEvent(1, ev), pointerEvent(2, ev));
  1171.             break;
  1172.         case POINTER_HOVER_RELEASED:
  1173.             f.pointerHoverReleased(pointerEvent(1, ev), pointerEvent(2, ev));
  1174.             break;
  1175.         case SIZE_CHANGED:
  1176.             f.sizeChangedInternal(ev[1], ev[2]);
  1177.             break;
  1178.         case HIDE_NOTIFY:
  1179.             f.hideNotify();
  1180.             break;
  1181.         case SHOW_NOTIFY:
  1182.             f.showNotify();
  1183.             break;    
  1184.         }
  1185.     }
  1186.     
  1187.     private int[] pointerEvent(int off, int[] event) {
  1188.         int[] peX = new int[event.length / 2];
  1189.         int offset = 0;
  1190.         for(int iter = off ; iter < event.length ; iter+=2 ) {
  1191.             peX[offset] = event[iter];
  1192.             offset++;
  1193.         }
  1194.         return peX;
  1195.     }
  1196.     /**
  1197.      * Returns true for a case where the EDT has nothing at all to do
  1198.      */
  1199.     boolean shouldEDTSleep() {
  1200.         Form current = impl.getCurrentForm();
  1201.         return (current == null || (!current.hasAnimations())) &&
  1202.                 (animationQueue == null || animationQueue.size() == 0) &&
  1203.                 inputEvents.size() == 0 &&
  1204.                 (!impl.hasPendingPaints()) &&
  1205.                 hasNoSerialCallsPending() && !keyRepeatCharged 
  1206.                 && !longPointerCharged;
  1207.     }
  1208.     
  1209.     
  1210.    /**
  1211.     * Returns the video control for the media player
  1212.     * 
  1213.     * @param player the media player
  1214.     * @return the video control for the media player
  1215.     */
  1216.     Object getVideoControl(Object player) {
  1217.         return impl.getVideoControl(player);
  1218.     }
  1219.     
  1220.     Form getCurrentInternal() {
  1221.         return impl.getCurrentForm();
  1222.     }
  1223.         
  1224.     /**
  1225.      * Same as getCurrent with the added exception of looking into the future
  1226.      * transitions and returning the last current in the transition (the upcoming
  1227.      * value for current)
  1228.      * 
  1229.      * @return the form currently displayed on the screen or null if no form is
  1230.      * currently displayed
  1231.      */
  1232.     Form getCurrentUpcoming() {
  1233.         return getCurrentUpcomingForm(false);
  1234.     }
  1235.     private Form getCurrentUpcomingForm(boolean includeMenus) {
  1236.         Form upcoming = null;
  1237.         
  1238.         // we are in the middle of a transition so we should extract the next form
  1239.         if(animationQueue != null) {
  1240.             int size = animationQueue.size();
  1241.             for(int iter = 0 ; iter < size ; iter++) {
  1242.                 Object o = animationQueue.elementAt(iter);
  1243.                 if(o instanceof Transition) {
  1244.                     upcoming = (Form)((Transition)o).getDestination();
  1245.                 }
  1246.             }
  1247.         }
  1248.         if(upcoming == null) {
  1249.             if(includeMenus){
  1250.                 Form f = impl.getCurrentForm();
  1251.                 if(f instanceof Dialog) {
  1252.                     if(((Dialog)f).isDisposed()) {
  1253.                         return getCurrent();
  1254.                     }
  1255.                 }
  1256.                 return f;
  1257.             }else{
  1258.                 return getCurrent();
  1259.             }
  1260.         }
  1261.         return upcoming;
  1262.     }
  1263.     
  1264.     /**
  1265.      * Return the form currently displayed on the screen or null if no form is
  1266.      * currently displayed.
  1267.      * 
  1268.      * @return the form currently displayed on the screen or null if no form is
  1269.      * currently displayed
  1270.      */
  1271.     public Form getCurrent(){
  1272.         Form current = impl.getCurrentForm();
  1273.         if(current != null && current instanceof Dialog) {
  1274.             if(((Dialog)current).isMenu() || ((Dialog)current).isDisposed()) {
  1275.                 Form p = current.getPreviousForm();
  1276.                 if(p != null) {
  1277.                     return p;
  1278.                 }
  1279.                 // we are in the middle of a transition so we should extract the next form
  1280.                 int size = animationQueue.size();
  1281.                 for(int iter = 0 ; iter < size ; iter++) {
  1282.                     Object o = animationQueue.elementAt(iter);
  1283.                     if(o instanceof Transition) {
  1284.                         return (Form)((Transition)o).getDestination();
  1285.                     }
  1286.                 }
  1287.             }
  1288.         }
  1289.         return current;
  1290.     }
  1291.     
  1292.     /**
  1293.      * Return the number of alpha levels supported by the implementation.
  1294.      * 
  1295.      * @return the number of alpha levels supported by the implementation
  1296.      */
  1297.     public int numAlphaLevels(){
  1298.         return impl.numAlphaLevels();
  1299.     }
  1300.     /**
  1301.      * Returns the number of colors applicable on the device, note that the API
  1302.      * does not support gray scale devices.
  1303.      * 
  1304.      * @return the number of colors applicable on the device
  1305.      */
  1306.     public int numColors() {
  1307.         return impl.numColors();
  1308.     }
  1309.     /**
  1310.      * Light mode allows the UI to adapt and show less visual effects/lighter versions
  1311.      * of these visual effects to work properly on low end devices.
  1312.      * 
  1313.      * @return true if this is light mode
  1314.      * @deprecated this method is no longer used, it was too unreliable
  1315.      */
  1316.     public boolean isLightMode() {
  1317.         return lightMode;
  1318.     }
  1319.     /**
  1320.      * Light mode allows the UI to adapt and show less visual effects/lighter versions
  1321.      * of these visual effects to work properly on low end devices.
  1322.      * 
  1323.      * @param lightMode true to activate light mode
  1324.      * @deprecated this method is no longer used, it was too unreliable
  1325.      */
  1326.     public void setLightMode(boolean lightMode) {
  1327.         this.lightMode = lightMode;
  1328.     }
  1329.     
  1330.     
  1331.     /**
  1332.      * Return the width of the display
  1333.      * 
  1334.      * @return the width of the display
  1335.      */
  1336.     public int getDisplayWidth(){
  1337.         return impl.getDisplayWidth();
  1338.     }
  1339.     
  1340.     /**
  1341.      * Return the height of the display
  1342.      * 
  1343.      * @return the height of the display
  1344.      */
  1345.     public int getDisplayHeight(){
  1346.         return impl.getDisplayHeight();
  1347.     }
  1348.     
  1349.     /**
  1350.      * Causes the given component to repaint, used internally by Form
  1351.      * 
  1352.      * @param cmp the given component to repaint
  1353.      */
  1354.     void repaint(final Animation cmp){
  1355.         impl.repaint(cmp);
  1356.     }
  1357.      
  1358.     /**
  1359.      * Returns the game action code matching the given key combination
  1360.      * 
  1361.      * @param keyCode key code received from the event
  1362.      * @return game action matching this keycode
  1363.      */
  1364.     public int getGameAction(int keyCode){
  1365.         return impl.getGameAction(keyCode);
  1366.     }
  1367.     
  1368.     /**
  1369.      * Returns the keycode matching the given game action constant (the opposite of getGameAction).
  1370.      * On some devices getKeyCode returns numeric keypad values for game actions,
  1371.      * this breaks the code since we filter these values (to prevent navigation on '2'). 
  1372.      * We pick unused negative values for game keys and assign them to game keys for 
  1373.      * getKeyCode so they will work with getGameAction.
  1374.      * 
  1375.      * @param gameAction game action constant from this class
  1376.      * @return keycode matching this constant
  1377.      * @deprecated this method doesn't work properly across device and is mocked up here
  1378.      * mostly for the case of unit testing. Do not use it for anything other than that! Do
  1379.      * not rely on getKeyCode(GAME_*) == keyCodeFromKeyEvent, this will never actually happen!
  1380.      */
  1381.     public int getKeyCode(int gameAction){
  1382.         return impl.getKeyCode(gameAction);
  1383.     }
  1384.      
  1385.     /**
  1386.      * Allows overriding the softkeys initialized by the software to a different value.
  1387.      * This method MUST be invoked after init() has completed. 
  1388.      * <p>In order to maintain the default value 0 can be passed as a value for a softkey
  1389.      * thus resulting in no effect e.g. setSoftkeyCodes(0, 0, 0, -8); will only affect the back key.
  1390.      * @param left the left softkey code
  1391.      * @param right the right softkey code
  1392.      * @param clear the clear softkey code
  1393.      * @param back the back softkey code
  1394.      * 
  1395.      * @deprecated the fix for this is to work with the LWUITImplementation classes and GameCanvasImplementation,
  1396.      * extend those classes to return the values you want or alternatively use the JAD file attributes
  1397.      * where appropriate
  1398.      */
  1399.     public void setSoftkeyCodes(int left, int right, int clear, int back) {
  1400.     }
  1401.     
  1402.     
  1403.     /**
  1404.      * Indicates whether the 3rd softbutton should be supported on this device
  1405.      * 
  1406.      * @return true if a third softbutton should be used
  1407.      */
  1408.     public boolean isThirdSoftButton() {
  1409.         return thirdSoftButton;
  1410.     }
  1411.     /**
  1412.      * Indicates whether the 3rd softbutton should be supported on this device
  1413.      * 
  1414.      * @param thirdSoftButton true if a third softbutton should be used
  1415.      */
  1416.     public void setThirdSoftButton(boolean thirdSoftButton) {
  1417.         this.thirdSoftButton = thirdSoftButton;
  1418.     }
  1419.     
  1420.     /**
  1421.      * Displays the virtual keyboard on devices that support manually poping up
  1422.      * the vitual keyboard
  1423.      * 
  1424.      * @param show toggles the virtual keyboards visibility
  1425.      */
  1426.     public void setShowVirtualKeyboard(boolean show) {
  1427.         impl.setShowVirtualKeyboard(show);
  1428.     }
  1429.     /**
  1430.      * Indicates if the virtual keyboard is currently showing or not
  1431.      *
  1432.      * @return true if the virtual keyboard is showing
  1433.      */
  1434.     public boolean isVirtualKeyboardShowing() {
  1435.         return impl.isVirtualKeyboardShowing();
  1436.     }
  1437.     
  1438.     /**
  1439.      * Indicates whether showing a virtual keyboard programmatically is supported 
  1440.      * 
  1441.      * @return false by default
  1442.      */
  1443.     public boolean isVirtualKeyboardShowingSupported() {
  1444.         return impl.isVirtualKeyboardShowingSupported();
  1445.     }
  1446.     
  1447.     /**
  1448.      * Returns the type of the input device one of:
  1449.      * KEYBOARD_TYPE_UNKNOWN, KEYBOARD_TYPE_NUMERIC, KEYBOARD_TYPE_QWERTY, 
  1450.      * KEYBOARD_TYPE_VIRTUAL, KEYBOARD_TYPE_HALF_QWERTY
  1451.      * 
  1452.      * @return KEYBOARD_TYPE_UNKNOWN
  1453.      */
  1454.     public int getKeyboardType() {
  1455.         return impl.getKeyboardType();
  1456.     }
  1457.     
  1458.     /**
  1459.      * Indicates whether the device supports native in place editing in which case
  1460.      * lightweight input logic shouldn't be used for input.
  1461.      * 
  1462.      * @return false by default
  1463.      */
  1464.     public boolean isNativeInputSupported() {
  1465.         return false;
  1466.     }
  1467.     
  1468.     /**
  1469.      * Indicates whether the device supports multi-touch events, this is only
  1470.      * relevant when touch events are supported
  1471.      * 
  1472.      * @return false by default
  1473.      */
  1474.     public boolean isMultiTouch() {
  1475.         return impl.isMultiTouch();
  1476.     }
  1477.     
  1478.     /**
  1479.      * Indicates whether the device has a double layer screen thus allowing two
  1480.      * stages to touch events: click and hover. This is true for devices such 
  1481.      * as the storm but can also be true for a PC with a mouse pointer floating 
  1482.      * on top.
  1483.      * <p>A click touch screen will also send pointer hover events to the underlying
  1484.      * software and will only send the standard pointer events on click.
  1485.      * 
  1486.      * @return false by default
  1487.      */
  1488.     public boolean isClickTouchScreen() {
  1489.         return impl.isClickTouchScreen();
  1490.     }
  1491.     /**
  1492.      * This method returns the dragging speed based on the latest dragged
  1493.      * events
  1494.      * @param yAxis indicates what axis speed is required
  1495.      * @return the dragging speed
  1496.      */
  1497.     float getDragSpeed(boolean yAxis){
  1498.         float speed;
  1499.         if(yAxis){
  1500.             speed = impl.getDragSpeed(dragPathY, dragPathTime, dragPathOffset, dragPathLength);
  1501.         }else{
  1502.             speed = impl.getDragSpeed(dragPathX, dragPathTime, dragPathOffset, dragPathLength);
  1503.         }
  1504.         dragPathLength = 0;
  1505.         return speed;
  1506.     }
  1507.     /**
  1508.      * Indicates whether LWUIT should consider the bidi RTL algorithm
  1509.      * when drawing text or navigating with the text field cursor.
  1510.      *
  1511.      * @return true if the bidi algorithm should be considered
  1512.      */
  1513.     public boolean isBidiAlgorithm() {
  1514.         return impl.isBidiAlgorithm();
  1515.     }
  1516.     /**
  1517.      * Indicates whether LWUIT should consider the bidi RTL algorithm
  1518.      * when drawing text or navigating with the text field cursor.
  1519.      *
  1520.      * @param activate set to true to activate the bidi algorithm, false to
  1521.      * disable it
  1522.      */
  1523.     public void setBidiAlgorithm(boolean activate) {
  1524.         impl.setBidiAlgorithm(activate);
  1525.     }
  1526.     /**
  1527.      * Converts the given string from logical bidi layout to visual bidi layout so
  1528.      * it can be rendered properly on the screen. This method is only necessary
  1529.      * for devices/platforms that don't have "built in" bidi support such as
  1530.      * Sony Ericsson devices.
  1531.      * See <a href="http://www.w3.org/International/articles/inline-bidi-markup/#visual">this</a>
  1532.      * for more on visual vs. logical ordering.
  1533.      *
  1534.      *
  1535.      * @param s a "logical" string with RTL characters
  1536.      * @return a "visual" renderable string
  1537.      */
  1538.     public String convertBidiLogicalToVisual(String s) {
  1539.         return impl.convertBidiLogicalToVisual(s);
  1540.     }
  1541.     /**
  1542.      * Returns the index of the given char within the source string, the actual
  1543.      * index isn't necessarily the same when bidi is involved
  1544.      * See <a href="http://www.w3.org/International/articles/inline-bidi-markup/#visual">this</a>
  1545.      * for more on visual vs. logical ordering.
  1546.      *
  1547.      * @param source the string in which we are looking for the position
  1548.      * @param index the "logical" location of the cursor
  1549.      * @return the "visual" location of the cursor
  1550.      */
  1551. public int getCharLocation(String source, int index) {
  1552.         return impl.getCharLocation(source, index);
  1553.     }
  1554.     /**
  1555.      * Returns true if the given character is an RTL character
  1556.      *
  1557.      * @param c character to test
  1558.      * @return true if the charcter is an RTL character
  1559.      */
  1560. public boolean isRTL(char c) {
  1561.         return impl.isRTL(c);
  1562.     }
  1563.     /**
  1564.      * This method is essentially equivalent to cls.getResourceAsStream(String)
  1565.      * however some platforms might define unique ways in which to load resources
  1566.      * within the implementation.
  1567.      *
  1568.      * @param cls class to load the resource from
  1569.      * @param resource relative/absolute URL based on the Java convention
  1570.      * @return input stream for the resource or null if not found
  1571.      */
  1572.     public InputStream getResourceAsStream(Class cls, String resource) {
  1573.         return impl.getResourceAsStream(cls, resource);
  1574.     }
  1575. }