Screensaver on J2ME or Back to the past. Part one

Good day!

Introduction


Outside the third of January, and the soul of the matter requires to write some program. Without thinking, I remembered that once offered adjustment the author of a topic Splash Screen on J2ME, and then doubts about what to write, finally dispelled. Today I invite you to plunge into the world of "normal dialer" and to write the application — it would just be a screensaver.


so let's get started


For a start you should install necessary software development. I think no need to explain what you need to put yourself on a PC to compile and run our application, because on the Internet this manual can be found in five seconds. Here, for example. Personally, I compile all source code applications for J2ME on "private dialer". Yes, Yes, there are craftsmen in the Russian land, who ported the compiler preverification on the J2ME platform.
After everything is installed, it would be nice to remember the theory itself, ranging from J2ME device application and ending with the directives of the Manifesto of our application. However, if you don't know what it is, don't worry — a bit of theory on the development of J2ME applications will be reviewed in this topic.

Anatomy of J2ME applications


Generally, the application in J2ME is called a MIDlet. Why so you will learn next.

javax.microedition.midlet.MIDlet

App for J2ME is nothing but a class inherited from the class MIDlet from the package javax.microedition.midlet. This class is the "heart" MIDlet'a. In our class we have to declare three methods, necessary for the functioning of our application:
the
 
public void startApp() { 
// this method is called at startup of our application 
} 

public void pauseApp() { 
// this method is called when our device receives a call, SMS, etc. 
} 

public void destroyApp(boolean unconditional) { 
// this method is called when it is invoked. 
// now explain... 
} 

The fact that this method is specified as necessary for implementation in a time as practical use it carries. Methods startApp() and pauseApp() used by most AMS, and destroyApp() — no. Traditionally, typically the block of this function looks like the following:
the
 
public void destroyApp(boolean unconditional) { 
notifyDestroyed(); // this method closes our app 
} 

As you can see, end of life cycle of applications manages the notifyDestroyed(), not destroyApp(). Anyway, the purpose of the past will remain a mystery. Not to digress, and move on.

javax.microedition.lcdui.Display

The next step in the implementation of our application is to obtain a reference to the object Display package javax.microedition.lcdui. As you might guess, this is done to be able to operate the screen forms (the javax.microedition.lcdui.Form) or canvas (the javax.microedition.lcdui.Canvas) and switch between them. Get a link we can as follows:
the
 
Display dsp = Display.getDisplay(this); // like this... 

It's done, move on to the next step.

javax.microedition.lcdui.game.GameCanvas

Immediately want to note that with the advent of class GameCanvas — he's started to replace normal Canvas due to the impossibility of double bufferization out of the box, as such the last. Therefore, as a canvas, I suggest to use GameCanvas. No sooner said than done.
GameCanvas and Canvas differ just only in two ways: the first has already been specified (this is double buffersize), and the second is the need for a method Declaration paint in the latter. For clarity, we give the following implementation code of the canvas using the Canvas:
the
 
import javax.microedition.lcdui.Canvas; 
import javax.microedition.lcdui.Graphics; 

public class OurCanvas extends Canvas { // inherit from the Canvas 

public void paint(Graphics g) { 

int w = getWidth(); // get the screen height 


g.setColor(0xffffff); // set the color of the brush 
g.fillRect(0,0,w,h); // fill the selected area with specified color 
} 
} 

In the method paint() we perform the entire rendering of graphics primitives. This approach is not particularly effective for many reasons, one of which is the desire to separate the logic.
GameCanvas allows us to put the logic in other methods, classes etc. like this:
the
 
import javax.microedition.lcdui.Canvas; 
import javax.microedition.lcdui.Graphics; 

public class OurCanvas extends GameCanvas implements Runnable { // inherited from GameCanvas and implement Runnable interface that is used by the Thread class 

public void run() { 

Graphics g = getGraphics(); // get a reference to the Graphics object 
// with which we draw these graphics primitives 

int w = getWidth(); // get the screen height 
int h = getHeight(); // about the width, do not forget 

g.setColor(0xffffff); // set the color of the brush 
g.fillRect(0,0,w,h); // fill the selected area with specified color 
} 
} 

Then I made a mistake: did not declare the object Graphics somewhere inside the Declaration of the class itself in place of variable declarations, i.e. the code should look like the following:
the
 
import javax.microedition.lcdui.Canvas; 
import javax.microedition.lcdui.Graphics; 

public class OurCanvas extends GameCanvas implements Runnable { 
Graphics g = getGraphics(); 
int w = getWidth(); 
int h = getHeight(); 

public void run() { 
g.setColor(0xffffff); 
g.fillRect(0,0,w,h); 
isSomethingDone(); 
} 

public void isSomethingDone() { 
g.setColor(0xababab); 
g.drawLine(25,25,125,125); 
} 
} 

Something like that. That's it — the necessary knowledge base to implement the plan we have. Go!

Go to design


Our application will consist of several classes:
Welcome! midlet.java:
the
 
import javax.microedition.midlet.MIDlet; 
import javax.microedition.lcdui.*; 
import java.util.Timer; 

public class midlet extends MIDlet { 
Timer timer; 
midletTimerTask task; 
midletCanvas canvas; 

public midlet () { 
canvas = new midletCanvas(this); // create the canvas 
timer = new Timer (); 
task = new midletTimerTask (canvas); // and the task to be executed 
timer.scheduleAtFixedRate(task,10,10); // every 10 milliseconds 
// 10 MS - very little. So we cause the repaint method will check 
// finished drawing the previous screen, use the flag in 
} 

protected void startApp() { // directly pass control to the canvas 
Display.getDisplay(this).setCurrent (canvas); 
} 

protected void pauseApp() {} 

protected void destroyApp(boolean unconditional) {} 

public void exitMIDlet() { 
notifyDestroyed(); 
} 
} 

Then the canvas midletCanvas.java:
the
 
import javax.microedition.lcdui.*; 

midletCanvas class extends Canvas { 
midlet midlet; 
random random; 
static int [] PlasmaTab = { //color table plasma - 256 elements 
32,32,33,34,35,35,36,37,38,39,39,40,41,42,42,43, 
44,45,45,46,47,47,48,49,49,50,51,51,52,52,53,54, 
54,55,55,56,56,57,57,58,58,59,59,59,60,60,60,61, 
61,61,62,62,62,62,63,63,63,63,63,63,63,63,63,63, 
63,63,63,63,63,63,63,63,63,63,62,62,62,62,62,61, 
61,61,60,60,60,59,59,58,58,58,57,57,56,56,55,54, 
54,53,53,52,52,51,50,50,49,48,48,47,46,46,45,44, 
43,43,42,41,40,40,39,38,37,37,36,35,34,33,33,32, 
31,30,30,29,28,27,26,26,25,24,23,23,22,21,20,20, 
19,18,17,17,16,15,15,14,13,13,12,11,11,10,10, 9, 
9, 8, 7, 7, 6, 6, 5, 5, 5, 4, 4, 3, 3, 3, 2, 2, 
2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 
2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 
9,10,11,11,12,12,13,14,14,15,16,16,17,18,18,19, 
20,21,21,22,23,24,24,25,26,27,28,28,29,30,31,31 
}; 
//Of course, I have not manually filled the table, and the received 
//according to the law 32* (1+ sin (x*(2*pi/255)), bringing everything to whole numbers 

static int Delta = 6; //cell size of the plasma pixels 

static int Yold_pos=0, Yold_asp=0, Xold_pos=0, Xold_asp=0; 
int Ynew_pos, Ynew_asp, Xnew_pos, Xnew_asp, x, y, Color; 
static int Width, Height; //Width and height of the screen 
static boolean in = false; //redraw 
Graphics gbuffer; //and this is for 
Image screen; //double buffering 

public midletCanvas (midlet midlet) { 
this.midlet = midlet; 
Random = new random (); 
setFullScreenMode (true); //the Only operator profile MIDP 2.0 
Width = getWidth (); 
Height = getHeight (); 
screen=Image.createImage(Width,Height); 
gbuffer=screen.getGraphics(); //draw gbuffer going on, 
draw (gbuffer); //and then simultaneously display it on a canvas! 
} 

void draw (Graphics g) { //draw to another buffer the plasma state 
in = true; 
Ynew_pos = Yold_pos; 
Ynew_asp = Yold_asp; 
for (y=0; y<Height; y+=Delta) { 
Xnew_pos = Xold_pos; 
Xnew_asp = Xold_asp; 
for (x=0; x<Width; x+=Delta) { 
Color = PlasmaTab[Ynew_pos]+ PlasmaTab[Ynew_asp]+ 
PlasmaTab[Xnew_pos]+ PlasmaTab[Xnew_asp]; 
g.setColor(((255-Color)<<16 | Color<<8 | 128+(Color>>1))); 
g.fillRect (x,y,Delta,Delta); 
Xnew_pos += 1; 
if (Xnew_pos > 255) Xnew_pos=0; 
Xnew_asp += 7; 
if (Xnew_asp > 255) Xnew_asp=0; 

Ynew_pos += 2; 
if (Ynew_pos > 255) Ynew_pos=0; 
Ynew_asp += 1; 
if (Ynew_asp > 255) Ynew_asp=0; 
} 
Xold_pos -= 2; 
if (Xold_pos<0) Xold_pos=255; 
Xold_asp += Random.get(8); 
if (Xold_asp > 255) Xold_asp=0; 
Yold_pos += 4; 
if (Yold_pos > 255) Yold_pos=0; 
Yold_asp -= Random.get(6); 
if (Yold_asp<0) Yold_asp=255; 
in = false; 
} 

protected void paint (Graphics g) { 
if (in == true) return; //If we still can redraw 
g.drawImage(screen,0,0,0); 
draw (gbuffer); 
} 

public void keyPressed(int keyCode) { 
switch (keyCode) { //Exit button # 
case Canvas.KEY_POUND: 
midlet.exitMIDlet(); 
break; 
} 
} 
} 

Next is the timer midletTimerTask.java:
the
 
import java.util.TimerTask; 
import javax.microedition.midlet.MIDlet; 

class midletTimerTask extends TimerTask { 
midletCanvas canvas; 

public midletTimerTask (midletCanvas canvas) { 
this.canvas = canvas; 
} 

public final void run() { 
canvas.repaint(); 
} 
} 

And finally, the implementation of the selection of random numbers random.java
the
 
import java.util.Date; 
import java.util.Random; 

class random { //a Class that wraps a random number generator 
private Random r; 
private Date d; 

public random () { 
d = new Date (); 
r = new Random (d.getTime()); 
} 

public int get (int max) { //a random number from the range [0,max-1] 
int n=r.nextInt()%max; 
return (n<0 ? -n : n); 
} 
} 


the Scandals, intrigues, investigation


My sources don't want to compile. Rather, they are compiled, but is not what I want. Late at night, so yours truly had to take not their source. I apologize for the code formatting — corrected tomorrow.

Next trick


Compilation and preverification. This step I leave to you.

MANIFEST.MF


I suggest you Tinker with that file and it is located in the directory META-INF. After all, if we make a screensaver, then it needs to conduct himself accordingly. Unfortunately, this behavior is only available phones from Sony Ericsson. Let's add the following line:
the
SEMC StandbyApplication: Y


What we do


We made it possible to download our screensaver as a background image. For this you need to throw the MIDlet in the phone. Then go to "Applications", find our. The next step is pressing the right soft key and select "As background. the picture". Choose to eat. You will see the following

Here's what happened






All you need


The source code you can take on Pastebin. here they are:
midlet.java
midletCanvas.java
midletTimerTask.java
random.java

Opinion


That's all. Just for a few steps we have written a MIDlet. In our days J2ME gradually goes nowhere and perhaps you have already left a similar tube, but so far Oracle does support — who knows, whether there will be. I hope you found it interesting.

See you soon!
Article based on information from habrahabr.ru

Комментарии

Популярные сообщения из этого блога

Vkontakte sync with address book for iPhone. How it was done

Automatically create Liquibase migrations for PostgreSQL

What part of the archived web