ColorCanvas.java

/*
 * Copyright © 2011 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.
 */

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.midlet.MIDlet;

/**
 *  Multipoint touch enabled Canvas.
 *
 * Pointer pressed event is shown as rectangle, pointer drags is represented
 * by circles, pointer released event draws large circle.
 *
 */
public class ColorCanvas extends Canvas {

    class Point {

        public int x;
        public int y;
        public int state;
        public static final int PRESSED = 1;
        public static final int DRAGGED = 2;
        public static final int RELEASED = 3;

        public Point(int x, int y, int state) {
            this.x = x;
            this.y = y;
            this.state = state;
        }
    }
    protected MultipointTouchEventsExample parent = null;
    protected MIDlet midlet;
    private int[] colors;
    private Point[][] currentPoints = new Point[6][25];
    private final int markerSize = 30;
    private Image exitImage;
    private Image exitPressedImage;
    private boolean exitButtonPointerDown = false;
    private int[] inactivityCounter = new int[6];
    private Timer inactivityTimer;

    public ColorCanvas(MIDlet midlet) {
        super();
        this.setFullScreenMode(true);
        this.midlet = midlet;
        this.colors = new int[]{
            0xFFFA05, 0x0004FF, 0xFF2A00, 0x19FF00, 0xACFF9E, 0xffffff
        };
        try {
            // Create background image
            this.exitImage = Image.createImage("/images/Exit.png");
            this.exitPressedImage = Image.createImage("/images/ExitPressed.png");
        } catch (IOException e) {
            Display.getDisplay(this.midlet).setCurrent(
                    new Alert("Cannot create graphics."), this);
            e.printStackTrace();
        }

        this.inactivityTimer = new Timer();
        this.inactivityTimer.schedule(
                new TimerTask() {

                    public void run() {
                        for (int i = 0; i < inactivityCounter.length; i++) {
                            if (inactivityCounter[i] <= markerSize) {
                                inactivityCounter[i]++;
                            }
                        }
                        repaint();
                    }
                },
                0,
                20);

    }

    protected void paint(Graphics graphics) {
        graphics.setColor(0x000000);
        graphics.fillRect(0, 0, this.getWidth(), this.getHeight());

        for (int i = 0; i < this.currentPoints.length; i++) {
            for (int j = 0; j < this.currentPoints[i].length; j++) {
                Point pt = this.currentPoints[i][j];
                if (pt != null) {
                    graphics.setColor(this.colors[i]);
                    int size = this.markerSize - j - this.inactivityCounter[i];
                    if (size > 0) {
                        int actualSize = size;
                        switch (pt.state) {
                            case Point.PRESSED:
                                actualSize = 18 * size / 10;
                                graphics.fillRect(
                                        pt.x - actualSize / 2, pt.y - actualSize / 2,
                                        actualSize, actualSize);
                                break;
                            case Point.DRAGGED:
                                graphics.fillArc(
                                        pt.x - actualSize / 2, pt.y - actualSize / 2,
                                        actualSize, actualSize,
                                        0, 360);
                                break;
                            case Point.RELEASED:
                                actualSize = 2 * size;
                                graphics.fillArc(
                                        pt.x - actualSize / 2, pt.y - actualSize / 2,
                                        actualSize, actualSize,
                                        0, 360);
                                break;
                        }
                    } else {
                        this.currentPoints[i][j] = null;
                    }
                } else {
                    break;
                }
            }
        }

        graphics.drawImage(
                this.exitButtonPointerDown ? this.exitPressedImage : this.exitImage,
                this.getWidth(), 0,
                Graphics.RIGHT | Graphics.TOP);
    }

    public void sizeChanged(int w, int h) {
        for (int i = 0; i < this.currentPoints.length; i++) {
            for (int j = 0; j < this.currentPoints[i].length; j++) {
                this.currentPoints[i][j] = null;
            }
        }
    }

    public void setParent(MultipointTouchEventsExample parent) {
        this.parent = parent;
    }

    protected void pointerPressed(int x, int y) {
        int pointerId = this.getPointerEventId();
        this.addPoint(pointerId, new Point(x, y, Point.PRESSED));
        this.exitButtonPointerDown = this.exitButtonHitTest(x, y);
        this.inactivityCounter[pointerId] = 0;
    }

    protected void pointerDragged(int x, int y) {
        int pointerId = this.getPointerEventId();
        this.addPoint(pointerId, new Point(x, y, Point.DRAGGED));
        this.exitButtonPointerDown = this.exitButtonHitTest(x, y);
        this.inactivityCounter[pointerId] = 0;
    }

    protected void pointerReleased(int x, int y) {
        int pointerId = this.getPointerEventId();
        this.addPoint(pointerId, new Point(x, y, Point.RELEASED));
        if (this.exitButtonPointerDown && this.exitButtonHitTest(x, y)) {
            this.inactivityTimer.cancel();
            Display.getDisplay(this.midlet).setCurrent(null);
            this.midlet.notifyDestroyed();
        } else {
            this.exitButtonPointerDown = false;
        }
        this.inactivityCounter[pointerId] = 0;
    }

    private void addPoint(int pointerNumber, Point newPoint) {
        for (int pointIndex = this.currentPoints[pointerNumber].length - 2; pointIndex >= 0; pointIndex--) {
            this.currentPoints[pointerNumber][pointIndex + 1] = this.currentPoints[pointerNumber][pointIndex];
        }
        this.currentPoints[pointerNumber][0] = newPoint;
    }

    private boolean exitButtonHitTest(int x, int y) {
        return this.getPointerEventId() == 0
                && x > (this.getWidth() - this.exitImage.getWidth())
                && y < this.exitImage.getHeight();
    }

    private int getPointerEventId() {
        String idString = System.getProperty("com.nokia.pointer.number");
        int id = 0;
        if (idString != null) {
            id = Integer.parseInt(idString);
        }
        return id;
    }
}