package com.bitrazor.tivo.trafficcam; import java.awt.Button; import java.awt.Image; import java.awt.MediaTracker; import java.awt.Toolkit; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import javax.swing.ImageIcon; import com.tivo.hme.bananas.BApplication; import com.tivo.hme.bananas.BScreen; import com.tivo.hme.sdk.Application; import com.tivo.hme.sdk.Resource; import com.tivo.hme.sdk.View; import com.tivo.hme.sdk.util.Ticker; /** * Create a screen that rotates through a number of images. Each image is a URL, * and is displayed for some number of seconds. Each image is faded out as the * new image is faded in. * * @see Pictures,java, TiVo HME SDK v1.1 samples * @see http://javaalmanac.com/egs/java.net/GetImage.html?l=rel * * @author David Staas, bitrazor.com */ public class ViewScreen extends BScreen implements Ticker.Client { private Application theApp; // A handle to the app private ArrayList list; // Will hold the list of URLs for images private int index; // Will hold the index into list final static int SHOW_TIME = 6000; // how long the pictures is shown final static int FADE_TIME = 1250; // how long to perform the fade in/out // the media tracker reqires a component, so we use this button final static Button mediaTrackerComp = new Button(); View fg, bg; // the foreground and background pictures /** * The constructor gets the URLs for the cameras, then kicks off the Ticker * to periodically rotate through them. * * @param app * A handle to the application. */ public ViewScreen(BApplication app) { super(app); theApp = app; list = new ArrayList(); // delete Image image; // delete ImageResource iRes; index = -1; bg = this.getBelow(); // this.below points to the current view's // background fg = this.getAbove(); // ... and foreground getCameraURLs(); // Ticker is part of the HME utils, and allows timed actions to happen. Ticker.master.add(this, System.currentTimeMillis(), null); } /** * Populates the ArrayList list with URLs, each representing the image from * a road cam. This routine could be replaced to read the URLs from a config * file, URL, etc. for more flexibility. */ public void getCameraURLs() { list.add("http://www.springsgov.com/trafficeng/monument.jpg"); list.add("http://www.springsgov.com/trafficeng/Interquest.jpg"); list.add("http://www.springsgov.com/trafficeng/Briargate.jpg"); list.add("http://www.springsgov.com/trafficeng/woodmen.jpg"); } /** * Wait SHOW_TIME seconds, then show the next picture. This routine must be * implemented for classes that implement Ticker.Client. */ public long tick(long tm, Object arg1) { // If context is null, the app has quit. if (theApp.getContext() == null) { return -1; } // advance to the next picture and show it index = (index + 1) % list.size(); showPicture((String) list.get(index)); // Since tick is called from another thread call flush to force HME to // write out any pending commands. flush(); // tick again to advance to the next frame return System.currentTimeMillis() + SHOW_TIME; } /** * Fade from one image to the next. getScaledImage() is called to get a * correctly sized image for display. * * @param path * The URL of the image to show. */ void showPicture(String path) { // turn painting off while we twiddle things theApp.getRoot().setPainting(false); try { // move the current image to the background view for fading out bg.setResource(fg.getResource(), RSRC_IMAGE_BESTFIT); // get a scaled instance of the image. Width and height refer // to the View's width and height. Image img = getScaledImage(path, getWidth(), getHeight()); // stuff the scaled image into the fg fg.setResource(createImage(img), RSRC_IMAGE_BESTFIT); // Perform the cross-fade animation Resource anim = getResource("*" + FADE_TIME); fg.setTransparency(1.0f); // start transparent, then fade IN fg.setTransparency(0.0f, anim); bg.setTransparency(0.0f); // start opaque, then fade OUT bg.setTransparency(1.0f, anim); } finally { theApp.getRoot().setPainting(true); } } /** * Gets an image from a URL, sized for the TiVo screen. */ public static Image getScaledImage(String path, int width, int height) { URL url = null; try { url = new URL(path); } catch (MalformedURLException e1) { // TODO: replace this with something more graceful e1.printStackTrace(); } // create an awt Image from a URL using this trick Image urlImage = Toolkit.getDefaultToolkit().createImage(url); // use the swing imageIcon class to synchronously load the image ImageIcon icon = new ImageIcon(urlImage); Image img = icon.getImage(); int imgW = icon.getIconWidth(); int imgH = icon.getIconHeight(); // // figure out the scale factor and the new size // float scale = Math.min((float) width / imgW, (float) height / imgH); if (scale > 1.0f) { scale = 1.0f; } int scaleW = (int) (imgW * scale); int scaleH = (int) (imgH * scale); // Perform scaling if the image must be shrunk. We will send smaller // images over and let the receiver scale them up. if (scale < 1.0f) { img = img.getScaledInstance(scaleW, scaleH, Image.SCALE_FAST); try { MediaTracker mt = new MediaTracker(mediaTrackerComp); mt.addImage(img, 0); mt.waitForAll(); } catch (InterruptedException e) { } } return img; } // If the left key is pressed, return to the calling screen. public boolean handleKeyPress(int code, long rawcode) { switch (code) { case KEY_LEFT: getBApp().pop(); return true; } return super.handleKeyPress(code, rawcode); } public String toString() { return "View Traffic Cameras"; } }