www.pudn.com > Bluegammon蓝牙的应用编程.rar > AnimationEngine.java


// Copyright (c) 2005 Sony Ericsson Mobile Communications AB 
// 
// This software is provided "AS IS," without a warranty of any kind.  
// ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,  
// INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A  
// PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.  
// 
// THIS SOFTWARE IS COMPLEMENTARY OF JAYWAY AB (www.jayway.se) 
 
package bluegammon.gui.animation; 
 
 
import java.util.Vector; 
 
import javax.microedition.lcdui.Graphics; 
 
/** 
 * Animation engine, handles all animation logic. 
 * Works together with an implementation of a RepaintRequestable 
 * This animation engine uses a primitive mechanism when 
 * deciding what interval to update all animations - it uses the minimum 
 * interval value returned amongst all active animations in the engine. Hence, 
 * all animations should return a common least denominator in their  
 * getInterval(). 
 *  
 * @author Peter Andersson 
 */ 
public class AnimationEngine implements Runnable 
{ 
  /** Thread running flag */ 
  protected volatile boolean m_running = true; 
  /** Vector with current animations, also used as lock for animations */ 
  protected Vector m_animations = new Vector(); 
  /** Time in millis between each animation update */ 
  protected long m_animationInterval = Long.MAX_VALUE; 
  /** The graphics context */ 
  protected RepaintRequestable m_canvas; 
   
  /** 
   * Creates an animation engine for specified canvas. 
   * @param canvas	The canvas that will be animated upon. 
   */ 
  public AnimationEngine(RepaintRequestable canvas) 
  { 
    m_canvas = canvas; 
  } 
   
  /** 
   * Updates all animations. Only updates animations 
   * that has passed their interval time. 
   * @return if a repaint is requested or not. 
   */ 
  protected boolean animate() 
  { 
    Animation a; 
    boolean repaint = false; 
    synchronized (m_animations) 
    { 
      long t = System.currentTimeMillis(); 
      m_animationInterval = Long.MAX_VALUE; 
      for (int i = m_animations.size() - 1; i >= 0; i--) 
      { 
        a = (Animation) m_animations.elementAt(i); 
        long interval = a.getInterval(); 
        if (t - a.getLastInvoke() >= interval) 
        { 
          a.callNext(t); 
          repaint = true; 
        } 
        if (a.isFinished()) 
        { 
          a.onExit(); 
          m_animations.removeElement(a); 
        } 
        else 
        { 
          if (interval < m_animationInterval) 
            m_animationInterval = interval; 
        } 
      } 
    } 
    return repaint; 
  } 
 
  /** 
   * Adds an animation. 
   * @param a The animation to add 
   */ 
  public void addAnimation(Animation a) 
  { 
    synchronized (m_animations) 
    { 
      m_animations.insertElementAt(a, 0); 
      if (m_animationInterval > a.getInterval()) 
      { 
        m_animationInterval = a.getInterval(); 
      } 
      m_animations.notifyAll(); 
      a.onStart(); 
    } 
    m_canvas.repaint(); 
  } 
 
  /** 
   * Removes an animation. 
   * @param anim The animation to remove 
   */ 
  public void remove(Animation anim) 
  { 
    synchronized (m_animations) 
    { 
      m_animations.removeElement(anim); 
    } 
  } 
   
  /** 
   * Removes all animations 
   */ 
  public void removeAll() 
  { 
    synchronized (m_animations) 
    { 
      m_animations.removeAllElements(); 
    } 
  } 
   
  /** 
   * Shuts down the animation engine. 
   */ 
  public void shutdown() 
  { 
    m_running = false; 
  } 
 
  /** 
   * Paints all animations on specified graphics context 
   * @param g The graphics context 
   */ 
  public void paint(Graphics g) 
  { 
    synchronized (m_animations) 
    { 
      for (int i = m_animations.size() - 1; i >= 0; i--) 
      { 
        ((Animation) m_animations.elementAt(i)).paint(g); 
      } 
    } 
  } 
 
  // Runnable impl 
  /** 
   * Updates all animations in queue if needed, 
   * and waits minimum amount of time as declared 
   * by animations. 
   */ 
  public void run() 
  { 
    try 
    { 
      boolean repaintRequest = false; 
      while (m_running) 
      { 
        repaintRequest = false; 
        if (m_canvas.isShown() && !m_animations.isEmpty()) 
        { 
          repaintRequest = animate(); 
        } 
        else 
        { 
          synchronized (m_animations) 
          { 
            try 
            { 
              m_animations.wait(500); 
            } 
            catch (InterruptedException e1) 
            {} 
          } 
        } 
 
        if (m_canvas.isShown()) 
        { 
          if (repaintRequest) m_canvas.commitRepaint(); 
 
          synchronized (m_animations) 
          { 
            try 
            { 
              m_animations.wait(Math.min(m_animationInterval, 500)); 
            } 
            catch (InterruptedException e) 
            {} 
          } 
        } 
        if (!m_running) 
        { 
          m_animations = null; 
        } 
      } 
    } 
    catch (Throwable t) 
    { 
      System.err.println("Error in anim thread"); 
      t.printStackTrace(); 
    } 
  } 
}