This article assumes that you, the reader, already has basic knowledge of the lifecycle (the whole init-activate-deactivate-destroy thing). If you don’t, I’d highly suggest reading up on it first. These lines (shamelessly stolen from Penlets.com) should summarize it:
Starting from the top, our penlet class extends Penlet . This is the parent class of all penlets, providing access to context information and lifecycle events.
These lifecycle events are handled by four abstract methods of Penlet that we need to implement. In order these event handlers are initApp , which will be called once to initialize the penlet. In this basic template we call context.getDisplay() to get a handle to the pen’s OLED display. We also create a new ScrollLabel instance. A ScrollLabel is a subclass of Canvas , which is a class that allows you to render text and graphics on the OLED display. The ScrollLabel in particular is used to render text on the OLED, and if the text is too long to fit on the display it will scroll the text so that the entire message can be read.
The next handler is activateApp , which is called when the penlet is activated. Typically this is when the penlet is selected on the pen’s menu, just like the demo apps that come with the pen. In this method you will typically want to change what is displayed on the OLED or perhaps play an audio clip. In this basic penlet we take that ScrollLabel we created and set that as the current display. And we set the message in the ScrollLabel to say “Hello World”.
Now eventually your penlet will be deactivated. This could be due to the user quitting the application, or maybe they just turned off the pen. This is handled by the deactivateApp handler, which also receives a code that specified the reason for the deactivation. All of the reason codes are available as static constants of the Penlet superclass. These include DEACTIVATED_BY_MENU , DEACTIVATED_BY_SHUTDOWN , and others. You will typically use this handler to free up resources that you created in activateApp . For example, you may have registered one or more event listeners like the StrokeListener or the PenTipListener that you want to unregister.
Last but not least, eventually the pen will completely shutdown the penlet, typically when the pen is powered down. This event is captured by destroyApp , allowing you to do any final cleanup that may be required.
Back to the matter at hand: how do you control the lifecycle of a penlet?
Initially you might think something like this would cause the application to deactivate:
This is, of course, wrong.
deactivateApp, along with the other abstract lifecycle methods, is strictly an event handler. At no point in time should the penlet call the methods; they are meant to be called by the JVM (Java Virtual Machine) as and when they’re needed.
Does this mean that it’s impossible to control the lifecycle (apart from tapping left on the Nav Menu to exit)? Nope.
As of this writing, only 3 methods (all found in the PenletContext class) have any effect on the lifecycle:
boolean notifyStateChange(boolean requestActive)
void notifyDataOnDisplay(boolean valid)
boolean requestActivation(long delay)
notifyStateChange
This method is the only one that allows you to directly influence the lifecycle. Unfortunately, you can only use it to activate or deactivate a penlet, which will be determined by the boolean parameter.
The method returns a boolean which describes whether or not the pen will entertain your request.
To deactivate a penlet, for example, use the following code in the penlet:
boolean willDeactivate = this.context.notifyStateChange(false);
this.logger.debug("Will the penlet deactivate? " + willDeactivate);
Deactivating a penlet this way should also cause its termination, though there is a special case.
Generally, you should only need to use notifyStateChange(false) since there’s no way you can run code while a penlet is deactivated.
notifyDataOnDisplay
This method forces a penlet to delay its termination after it’s been deactivated due to Notes Mode. What does this mean?
Basically, if a penlet’s not expecting handwriting or even tapping, it exits to Notes Mode when you put your pen on Open Paper (AKA any basic Livescribe notebook). Notes Mode is the pen’s “basic mode”, just FYI.
Since the penlet terminates immediately, you lose anything that’s on the display immediately too. If, however, you want to give the user the opportunity to write down the result on Open Paper, the method lets you freeze the screen and delay the penlet’s termination.
Simply supply a boolean value of true to activate this feature:
!#java
this.context.notifyDataOnDisplay(true);
Do note that this is actually included as part of the Livescribe Smartpen Open Paper Certification, under the test named INT.LIVESCRIBE.DOD.01. If you ever run into this situation, do take this into account.
requestActivation
This method trudges into advanced penlet programming territory. What it does is let you reactivate an already deactivated penlet after a set amount of time.
The catch? The penlet cannot be terminated.
Officially, only one penlet is capable of staying resident in memory, and it’s the Paper Replay penlet. In fact, Paper Replay uses this exact method to perform its “snapback” feature, which lets it take over the penlet when it’s idle after 10 seconds if a recording is running. I’ve seen enough debug messages in the Smartpen Emulator to confirm this.
Is it possible, unofficially? Well, yes, but only through a certain caveat.
Normally, a penlet immediately terminates after it exits. However, I’ve found that if the following factors are present, the penlet won’t deactivate immediately:
- The penlet starts due to the user tapping on one of its regions.
- The penlet deactivates when it calls
notifyStateChange.
I won’t fully illustrate how to achieve this; if you’re really willing to find out more, you should be able to code up a simple app using the pointers above. In any case though, you simply call the method with the delay (in milliseconds) as its parameter:
boolean willReactivate = this.context.requestActivation(5000);
this.logger.debug("Will it reactivate? " + willReactivate);
Similar to notifyStateChange, this method returns a boolean describing whether the pen will reactivate the penlet later as instructed.
I wouldn’t advise trying it in your commercial penlet, though. You’re not supposed to interfere with the way Paper Replay works; in fact, your penlet must be able to support Paper Replay recording in the background (or simply refuse to run) to be certified.
Oh well. ( –_–)y