This is a quick post on timers in a LiveScribe pen penlet (pen application). I had asked in the forums about how to track the pen position as it moved across the page. The following is my take on the response I got.
Sample Code
In this case, I am going to start with code and then describe it.
package com.wordpress.alankent.livescribe.play; import com.livescribe.penlet.Penlet; import com.livescribe.penlet.PenletStateChangeException; import com.livescribe.penlet.Region; import com.livescribe.storage.StrokeStorage; import com.livescribe.ui.ScrollLabel; import com.livescribe.util.Timer; import com.livescribe.util.TimerTask; import com.livescribe.afp.PageInstance; import com.livescribe.display.Display; import com.livescribe.event.PenTipListener; import com.livescribe.geom.Point; public class TrackPenPosition extends Penlet implements PenTipListener { private Display display; private ScrollLabel label; private PollTask pollTask; private Timer pollTimer; public TrackPenPosition() { } public void initApp() throws PenletStateChangeException { display = this.context.getDisplay(); label = new ScrollLabel(); label.enableFlickScrub(false); } public void activateApp(int reason, Object[] args) { context.addPenTipListener(this); if (reason == Penlet.ACTIVATED_BY_MENU) { this.label.draw("Here is my scrolling label", true); this.label.enableFlickScrub(false); this.display.setCurrent(this.label); } } public void deactivateApp(int reason) { } public void destroyApp() throws PenletStateChangeException { } public void penDown(long time, Region region, PageInstance page) { System.out.println(">>> PEN DOWN <<<"); StrokeStorage ss = new StrokeStorage(page); pollTask = new PollTask(ss); pollTimer = new Timer(); pollTimer.schedule(pollTask, 10, 15); } public void penUp(long time, Region region, PageInstance page) { System.out.println(">>> PEN UP <<<"); pollTimer.cancel(); } public static class PollTask extends TimerTask { StrokeStorage ss; public PollTask(StrokeStorage ss) { this.ss = ss; } public void run() { Point p = ss.getLastCoord(); // Do work with the new coordinate System.out.println("Coord = " + p.toString()); } } public void doubleTap(long time, int x, int y) { } public void singleTap(long time, int x, int y) { } }
Description
What the above code does is create a new Timer instance when the pen goes down. It also creates a new class that is called when the timer expires. You can used a non-static inner class giving it full access to the parent penlet class, although you might prefer to use a separate class and pass all the required information across in the constructor.
Timers can issue multiple events, which I have used in this case. The Timer.schedule() method takes the callback class to use, the initial timeout, and the time between subsequent timeouts as arguments.
To get the current pen position, in the timer it asks the stroke storage for the last coordinate. See StrokeStorage.getLastCoord().
The end result is you get told about when each pen move occurs.
Beware however that you may need to use synchroized methods to protect penlet class variables. The Timer class uses a separate thread. Its not uncommon in real code to require a synchronized keyword on all the Penlet methods as soon as Timer instances are introduced in order to make sure that any code triggered by the Timer is thread safe with respect to the main Penlet class. Its too big a job to describe synchronization and thread safety here – its important to understand however if you are going to use Timers safely.