/* * Copyright © 2012 Nokia Corporation. All rights reserved. * Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation. * Oracle and Java are trademarks or registered trademarks of Oracle and/or its * affiliates. Other product and company names mentioned herein may be trademarks * or trade names of their respective owners. * See LICENSE.TXT for license information. */ package com.nokia.example.attractions.views; import com.nokia.example.attractions.Visual; import com.nokia.example.attractions.Main; import com.nokia.example.attractions.utils.ImageLoader; import com.nokia.example.attractions.utils.Sleeper; import java.io.IOException; import java.util.Vector; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Image; import javax.microedition.lcdui.game.GameCanvas; import javax.microedition.lcdui.game.Sprite; /** * Class for handling application views. Handles view switching and drawing. * Displaying is done using GameCanvas. */ public final class ViewMaster extends GameCanvas implements CommandListener { private static ViewMaster instance = null; private BaseView detailsView; private BaseView attractionsView; private BaseView guidesView; private BaseView buyGuidesView; private BaseView mapView; private BaseView aboutView; private BaseView helpView; private Image defaultThumbnailIcon; private Sprite defaultLoaderSprite; private BaseView activeView = null; private final Vector viewStack = new Vector(); private final Sleeper drawLock = new Sleeper(); private volatile boolean hidden = true; private volatile boolean canPaint = false; private volatile boolean refreshScreen = false; private PointerEventListener pointerEventListener = null; private ViewMaster() { super(false); this.setFullScreenMode(false); setTitle(""); } /** * @return ViewMaster singleton */ public static ViewMaster getInstance() { if (instance == null) { instance = new ViewMaster(); instance.initialize(); } return instance; } /** * Initializes the singleton. */ private void initialize() { this.setCommandListener(this); try { defaultThumbnailIcon = ImageLoader.getInstance().loadImage( "/thumbnail.png", null); } catch (IOException e) { } try { Image i = ImageLoader.getInstance().loadImage("/loader_content.png", null); defaultLoaderSprite = new Sprite(i, i.getWidth() / 24, i.getHeight()); } catch (IOException e) { } attractionsView = new AttractionsView(); detailsView = new DetailsView(); mapView = new MapView(); guidesView = new GuidesView(); aboutView = new AboutView(); helpView = new HelpView(); try { Class.forName("com.nokia.mid.payment.IAPClientPaymentListener"); Class c = Class.forName("com.nokia.example.attractions.views." + "BuyGuidesView"); buyGuidesView = (BaseView) (c.newInstance()); } catch (Exception e) { buyGuidesView = null; } } public final boolean isHidden() { return hidden; } public final boolean hasBuyGuidesView() { return buyGuidesView != null; } public final void showAboutView() { setView(aboutView); } public final void showAttractionsView() { setView(attractionsView); } public final void showBuyGuidesView() { setView(buyGuidesView); } public final void showDetailsView() { setView(detailsView); } public final void showGuidesView() { setView(guidesView); } public final void showHelpView() { setView(helpView); } public final void showMapView() { setView(mapView); } public final Sprite getDefaultLoaderSprite() { return defaultLoaderSprite; } public final Image getDefaultThumbnailIcon() { return defaultThumbnailIcon; } /** * @see GameCanvas#showNotify() */ protected final void showNotify() { hidden = false; Main.getInstance().refreshLocationFinder(); // S60 doesn't call sizeChanged on start-up so it has to be called here. sizeChanged(getWidth(), getHeight()); draw(); final Graphics g = getGraphics(); new Thread() { public void run() { while (!hidden) { if (refreshScreen && canPaint) { refreshScreen = false; if (activeView != null) { activeView.draw(g); flushGraphics(); } } drawLock.sleep(50); } } }.start(); new Thread() { public void run() { try { sleep(500); draw(); } catch (InterruptedException e) { } } }.start(); } /** * @see GameCanvas#paint(javax.microedition.lcdui.Graphics) */ public final void paint(Graphics g) { canPaint = true; forceDraw(); } /** * @see GameCanvas#hideNotify() */ protected final void hideNotify() { hidden = true; canPaint = false; Main.getInstance().refreshLocationFinder(); } /** * @see GameCanvas#sizeChanged(int, int) */ protected final void sizeChanged(int width, int height) { attractionsView.resize(0, 0, width, height); guidesView.resize(0, 0, width, height); if (buyGuidesView != null) { buyGuidesView.resize(0, 0, width, height); } detailsView.resize(0, 0, width, height); mapView.resize(0, 0, width, height); aboutView.resize(0, 0, width, height); helpView.resize(0, 0, width, height); draw(); } /** * Sets a view to be displayed. Transitions the previous view away. * @param view */ private void setView(final BaseView view) { Main.getInstance().callSerially(new Runnable() { public void run() { if (activeView != null) { if (activeView == view) { // Trying to activate a view that's already active. return; } else { activeView.deactivate(); } } activeView = view; synchronized (viewStack) { // Remove the view from viewstack. viewStack.removeElement(activeView); // Push the view into viewstack. viewStack.addElement(activeView); } activeView.activate(); forceDraw(); } }); } /** * Activate the previous view from the stack. * At least two views need to be there. */ public final void setPreviousView() { BaseView view = null; synchronized (viewStack) { if (viewStack.size() >= 2) { // First remove and forget the current view. viewStack.removeElement(viewStack.lastElement()); // Get the 2nd to last, which we want to activate. view = (BaseView) viewStack.lastElement(); } } // Activate the view. if (view != null) { setView(view); } } /** * Draws the active view immediately */ public final void forceDraw() { draw(); drawLock.wakeup(); } /** * Draws the active view. */ public final void draw() { refreshScreen = true; } /** * Key pressed event handler. * @param keyCode */ protected final void keyPressed(int keyCode) { if (activeView == null) { return; } activeView.keyPressed(keyCode); } /** * Key repeated event handler. * @param keyCode */ protected final void keyRepeated(int keyCode) { if (activeView == null) { return; } activeView.keyRepeated(keyCode); } /** * Key released event handler. * @param keyCode */ protected final void keyReleased(int keyCode) { if (activeView == null) { return; } activeView.keyReleased(keyCode); } /** * Utility to draw the background image. * This is used to draw the background and list highlights. * @param g * @param x * @param y * @param width * @param height * @param highlight Set to true to have a highlighted effect. */ public static void drawBackground(Graphics g, int x, int y, int width, int height, boolean highlight) { g.setColor(Visual.BACKGROUND_COLOR); g.fillRect(x, y, width, height); if (highlight) { drawDimmedBackground(g, x, y, width, height); } } /** * Render a part of the background dimmed. * Used for drawing list focus cursor. * @param g * @param x * @param y * @param width * @param height */ private static void drawDimmedBackground(Graphics g, int x, int y, int width, int height) { // This would be more optimized if the alpha mask were pregenerated. int[] pixels = new int[width * height]; for (int i = 0; i < width * height; i++) { //pixels[i] = 0xaa000000; pixels[i] = 0x55000000; } g.drawRGB(pixels, 0, width, x, y, width, height, true); pixels = null; } /** * @see GameCanvas#pointerPressed(int, int) */ protected final void pointerPressed(int x, int y) { if (pointerEventListener != null) { pointerEventListener.pointerPressed(x, y); } } /** * @see GameCanvas#pointerDragged(int, int) */ protected final void pointerDragged(int x, int y) { if (pointerEventListener != null) { pointerEventListener.pointerDragged(x, y); } } /** * @see GameCanvas#pointerReleased(int, int) */ protected final void pointerReleased(int x, int y) { if (pointerEventListener != null) { pointerEventListener.pointerReleased(x, y); } } /** * @see CommandListener#commandAction(javax.microedition.lcdui.Command, javax.microedition.lcdui.Displayable) */ public final void commandAction(Command cmd, Displayable dsplbl) { if (activeView != null) { activeView.commandAction(cmd); } } /** * Set pointer event listener. Can be set to null. * @param listener pointer event listener */ public final void setPointerEventListener(PointerEventListener listener) { pointerEventListener = listener; } /** * Interface for pointer event notifications */ public interface PointerEventListener { void pointerPressed(int x, int y); void pointerDragged(int x, int y); void pointerReleased(int x, int y); } }