For implementing the UI, the MIDlet contains the following classes, each of which creates a separate screen:
The CameraScreen
class creates the form for capturing an image. The actual capture
operation runs in its own thread. Once the image has been captured,
the MIDlet calls the imageCaptured
method of the
main class.
To implement the CameraScreen
class:
Create the CameraScreen.java
class file.
Import the required classes.
import java.io.IOException; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Graphics; import javax.microedition.media.Manager; import javax.microedition.media.MediaException; import javax.microedition.media.Player; import javax.microedition.media.control.VideoControl;
Set CameraScreen
to extend Canvas
and implement CommandListener
.
// The CameraScreen class shows the live view // of the camera using the MMAPI and gives // commands to capture the contents of the camera class CameraScreen extends Canvas implements CommandListener {
Create the required
variables, and create the CameraScreen
class constructor.
private final MMSMIDlet midlet; private final Command exitCommand; private Player player = null; private Command captureCommand = null; private VideoControl videoControl = null; CameraScreen(MMSMIDlet midlet) { this.midlet = midlet; // Builds the user interface exitCommand = new Command("Exit", Command.EXIT, 1); addCommand(exitCommand); captureCommand = new Command("Capture", Command.SCREEN, 1); addCommand(captureCommand); setCommandListener(this); }
Implement the paint
method for drawing on the canvas. The method paints
the canvas background black.
// Paint the canvas' background in black public void paint(Graphics g) { // black background g.setColor(0x0000000); g.fillRect(0, 0, getWidth(), getHeight()); }
Implement the commandAction
method for detecting command invocations.
public void commandAction(Command c, Displayable d) { if (c == exitCommand) { midlet.exitApplication(); } else if (c == captureCommand) { captureImage(); } }
Create a method for detecting key presses.
public void keyPressed(int keyCode) { if (getGameAction(keyCode) == FIRE) { captureImage(); } }
Create a method for building and starting the video player.
// Creates and starts the video player synchronized void start() { try { // Newer phones need to be initialized to image mode try { player = Manager.createPlayer("capture://image"); // Older phones don't support this, so we start them // in video mode. } catch (Exception ce) { player = Manager.createPlayer("capture://video"); } player.realize(); // Get VideoControl for the viewfinder videoControl = (VideoControl) player.getControl("VideoControl"); if (videoControl == null) { discardPlayer(); midlet.showError("Cannot get the video control.\n" + "Capture may not be supported."); player = null; } else { // Set up the viewfinder on the screen. videoControl.initDisplayMode(VideoControl.USE_DIRECT_VIDEO, this); int canvasWidth = getWidth(); int canvasHeight = getHeight(); int displayWidth = videoControl.getDisplayWidth(); int displayHeight = videoControl.getDisplayHeight(); int x = (canvasWidth - displayWidth) / 2; int y = (canvasHeight - displayHeight) / 2; videoControl.setDisplayLocation(x, y); player.start(); videoControl.setVisible(true); } } catch (IOException ioe) { discardPlayer(); midlet.showError("IOException: " + ioe.getMessage()); } catch (MediaException me) { midlet.showError("MediaException: " + me.getMessage()); } catch (SecurityException se) { midlet.showError("SecurityException: " + se.getMessage()); } }
Create methods for stopping and discarding the video player.
// Stops the video player synchronized void stop() { if (player != null) { try { videoControl.setVisible(false); player.stop(); } catch (MediaException me) { midlet.showError("MediaException: " + me.getMessage()); } } } // this method will discard the video player private void discardPlayer() { if (player != null) { player.deallocate(); player.close(); player = null; } videoControl = null; }
Create a method for capturing the image in a new thread.
// captures the image from the video player // in a separate thread private void captureImage() { if (player != null) { // Capture image in a new thread. new Thread() { public void run() { try { //For Devices that support jpg image encoding, mostly Symbian byte[] jpgImage = videoControl.getSnapshot("encoding=image/jpg&width=270&height=360"); midlet.imageCaptured(jpgImage); discardPlayer(); } catch (MediaException me) { try{ //For Devices that do not support jpg image encoding, mostly Series 40 byte[] jpgImage = videoControl.getSnapshot(null); midlet.imageCaptured(jpgImage); discardPlayer(); } catch(Exception e) { midlet.showError("Exception: "+e.getMessage()); } } catch (SecurityException se) { midlet.showError("SecurityException: " + se.getMessage()); } } }.start(); } } }
The InfoScreen
class
creates a form for displaying information and error messages.
To implement the InfoScreen
class:
Create the InfoScreen.java
class file.
Import the required classes.
import javax.microedition.lcdui.Alert; import javax.microedition.lcdui.AlertType; import javax.microedition.lcdui.Display;
Set InfoScreen
to extend Alert
, and create
the class constructor.
// Utility class used to show some information to the user class InfoScreen extends Alert { InfoScreen() { super("InfoScreen"); }
Create methods for showing the INFO and ERROR alert types.
void showInfo(String message, Display display) { setTitle("Info"); setType(AlertType.INFO); setTimeout(3000); setString(message); display.setCurrent(this); } void showError(String message, Display display) { setTitle("Error"); setType(AlertType.ERROR); setTimeout(5000); setString(message); display.setCurrent(this); } }
The ReceiveScreen
class creates a form for displaying a received message. The screen
is activated when a new message arrives. The MIDlet main class reads
the incoming MMS message and passes it to the ReceiveScreen
class for parsing.
To implement the ReceiveScreen
class:
Create the ReceiveScreen.java
class file.
Import the required classes.
import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Form; import javax.microedition.lcdui.Image; import javax.microedition.lcdui.ImageItem; import javax.microedition.lcdui.Item; import javax.microedition.lcdui.StringItem; import javax.wireless.messaging.Message; import javax.wireless.messaging.MessagePart; import javax.wireless.messaging.MultipartMessage;
Set ReceiveScreen
to extend Form
and implement CommandListener
.
// Form used to display the contents of a received message class ReceiveScreen extends Form implements CommandListener {
Create the required
variables, and create the ReceiveScreen
class constructor.
private final MMSMIDlet midlet; private final Command commandClose = new Command("Close", Command.ITEM, 1); ReceiveScreen(MMSMIDlet midlet) { super(null); this.midlet = midlet; }
Create a method
for initializing the Message
object that is to be
displayed on the ReceiveScreen
. The method checks
that the Message
object is not null
and, if it is not, passes it to the createForm
method, which builds the form
used to display the message.
public void setMessage(Message mmsMessage) { if (mmsMessage != null) { createForm(mmsMessage); } }
Implement the commandAction
method for detecting command invocations.
public void commandAction(Command c, Displayable d) { if (c == commandClose) { midlet.resumeDisplay(); } }
Create the method for building the form used to display the message.
The getAddress
method returns the address associated
with the message, and the getTimestamp
method returns the timestamp
indicating when the message has been sent.
private void createForm(Message mmsMessage) { deleteAll(); setTitle("Received MMS Message"); if (mmsMessage instanceof MultipartMessage) { MultipartMessage multipartMessage = (MultipartMessage) mmsMessage; // Display message header. StringItem messageHeader = new StringItem(null, "From: " + mmsMessage.getAddress() + "\n" + "Sent: " + multipartMessage.getTimestamp().toString()); messageHeader.setLayout(Item.LAYOUT_NEWLINE_AFTER); append(messageHeader);
The getMessageParts
method returns an array of all MessageParts
of
the message.
MessagePart[] messageParts = multipartMessage.getMessageParts();
To display the message, the getMIMEType
method
returns the mime type and the getContentLocation
method
the content location of the MessagePart
, whereas
the getContent
method returns the content of the MessagePart
as an array of bytes.
// Display all parts of the message. for (int i = 0; i < messageParts.length; i++) { MessagePart messagePart = messageParts[i]; String mimeType = messagePart.getMIMEType(); String contentLocation = messagePart.getContentLocation(); byte[] part = messagePart.getContent(); if (mimeType.equals("image/jpeg")) { // Message contains an image. Image image = Image.createImage(part, 0, part.length); ImageItem imageItem = new ImageItem(null, image, Item.LAYOUT_CENTER + Item.LAYOUT_NEWLINE_AFTER, contentLocation); append(imageItem); } if (mimeType.equals("text/plain")) { // Message contains text. StringItem stringItem = new StringItem(null, new String( part)); stringItem.setLayout(Item.LAYOUT_CENTER); append(stringItem); } // Unknown MIME-types are ignored } } addCommand(commandClose); setCommandListener(this); } }
The SendScreen
class
creates a form for composing the message to be sent. When the user
selects Send, the class creates the image and text parts of
the message and delegates the sending to the MIDlet main class.
To implement the SendScreen
class:
Create the SendScreen.java
class file.
Import the required classes.
import java.io.UnsupportedEncodingException; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Form; import javax.microedition.lcdui.Image; import javax.microedition.lcdui.ImageItem; import javax.microedition.lcdui.Item; import javax.microedition.lcdui.TextField; import javax.wireless.messaging.MessagePart; import javax.wireless.messaging.SizeExceededException;
Set SendScreen
to extend Form
and implement CommandListener
.
// This form displays the content of the captured image // and fields to add the recipient address and the // text of the message class SendScreen extends Form implements CommandListener {
Create the required
variables, and create the SendScreen
class constructor.
private final MMSMIDlet midlet; private final Command commandSend = new Command("Send", Command.ITEM, 1); private final Command commandBack = new Command("Back", Command.BACK, 0); private TextField messageText; private TextField recipientPhone; private byte[] messageImage; SendScreen(MMSMIDlet midlet) { super("MMS Message"); this.midlet = midlet; addCommand(commandSend); addCommand(commandBack); setCommandListener(this); }
Create a method for initializing the message composing area.
void initializeComposeCanvas(byte[] pngImage) { messageText = new TextField("Text: ", null, 256, TextField.ANY); recipientPhone = new TextField("To: ", null, 256, TextField.PHONENUMBER); messageImage = pngImage; Image tempImage = Image.createImage(pngImage, 0, pngImage.length); ImageItem imageItem = new ImageItem(null, tempImage, Item.LAYOUT_CENTER, null); deleteAll(); append(messageText); append(recipientPhone); append(imageItem); midlet.showSendScreen(); }
Implement the commandAction
method for detecting command invocations.
public void commandAction(Command c, Displayable d) { if (c == commandBack) { midlet.showCameraScreen(); } if (c == commandSend) { sendMMS(); } }
Create a method for defining the MMS content and sending the MMS to the recipient.
private void sendMMS() { String recipientAddress = "mms://" + recipientPhone.getString() + ":" + midlet.getApplicationID(); try { // get the byte content of the message and // the captured image byte[] textBytes = messageText.getString().getBytes("UTF-8"); byte[] imageBytes = messageImage; // Create the message part containting the image // and give the appropriate MIME-type and id MessagePart imagePart = new MessagePart(imageBytes, 0, imageBytes.length, "image/jpeg", "id0", "snapshot image", null); // Create the message part containting the text // and give the appropriate MIME-type and id MessagePart textPart = new MessagePart(textBytes, 0, textBytes.length, "text/plain", "id1", "message text", "UTF-8"); midlet.showInfo("Sending message..."); midlet.sendMessage(recipientAddress, imagePart, textPart); } catch (UnsupportedEncodingException uee) { midlet.showError("Encoding not supported. " + uee.getMessage()); } catch (SizeExceededException see) { midlet.showError("Message part is too big. " + see.getMessage()); } } }
The UnsupportedEncodingException
indicates that
the selected character encoding is not supported, while the SizeExceededException
indicates that an operation
is not executable due to insufficient system resources.