== 9. Adding Send Email Functionality ==
9.1 Lets first add . Add the api which we will need for Send email option to the email functionalitymenu and implement it: <source lang="java"> import net // Send email to student ImageMenuItem emailItem = new ImageMenuItem("Email Student", 400, 4, MENU_EMAIL); emailItem.rim.blackberry.apisetCommand(new Command(new CommandHandler() { public void execute(ReadOnlyCommandMetadata metadata, Object context) { Student student = (Student) _keywordFilterField.mailgetSelectedElement();</source>
9 if (student != null) { try { ComposeScreen composeScreen = new ComposeScreen(null, _store, student.getEmail()); pushScreen(composeScreen); } catch(Exception ex) { Dialog.2 In order to add send email functionality to our application, we must have the appropriate menu option in our applicationalert("composing screen: " + ex.getMessage()); }
} } })); _mainScreen.addMenuItem(emailItem); </source lang=">9.2 Add four new Screen classes and a helper class to the project:* <code>ComposeScreen.java</code> - start screen where email is composed* <code>MessageScreen.java</code> - screen showing the email* <code>MessagesViewScreen.java</code> - to view the created email* <code>MessageListField.java</code> - handles the drawing of the list of messages* <code>FoldersViewScreen.java"</code>- view emails in the Outbox folderThe main functionality is taken from the Sample provided with blackberry plug-in: <code>BlackBerryMailDemo</code><br/ Email selected student>9.3. Following is the modified code to accommodate the application:<br/>MenuItem emailStudent <code>ComposeScreen.java</code> <source lang= new MenuItem(new StringProvider("Email Studentjava"), 500, 5);>editItem package cs.ecl.setCommand(new Command(new CommandHandler(){team1.project;
public void execute(ReadOnlyCommandMetadata metadata, Object context) { import java.util.*;// TODO Auto-generated method stub import net.rim.blackberry.api.mail.*; import net.rim.device.api.command.*; import net.rim.device.api.ui.component.*; import net.rim.device.api.ui.*; import net.rim.device.api.util.*;
}
}
));
< /source>** * The ComposeScreen is a screen which displays either a new or saved message. * It adds the functionality of saving and sending messages to its parent class, * MessageScreen. */public final class ComposeScreen extends MessageScreen{ private static final int FIRST = 0; private static final int SEND_MENU_ITEM_INDEX = 0; private Store _store; private MessagesViewScreen _messagesViewScreen;
9.3 Now lets get /** * Creates a new ComposeScreen object * @param message A message in the students email address and nameprocess of being composed, or null if a new message is to be composed * @param store The message store for this application */ <source lang="java"> Student student = public ComposeScreen(StudentMessage message, Store store, String email) _keywordFilterField.getSelectedElement { super(message, true, email); String studentEmail _store = store; _messagesViewScreen = student.getEmailnew MessagesViewScreen(); String studentName // If a new message is to be created, indicate this in the title if( message == student.getnamenull ) { setTitle("New Message");</source> }
9.4 Now we must set up a new message // Create and content. Here we create a new message in add menu items specific to the SENT folder of the device and fill it with a predefined bodyCompose action (addTo,<source lang="java"> Store store = Session // addBcc, addCc, etc..getDefaultInstance().getStore(); Folder sentFolder = store.list(Folder.SENT); Message msg AddHeaderFieldAction addToMenuItem = new AddHeaderFieldAction(Message(sentFolder.RecipientType.TO, "Add To: ", "To: "); // Set up recipients Address recipients AddHeaderFieldAction addCcMenuItem = new Address(studentEmail, studentName); //Add the recipient to the message msg.addRecipientsAddHeaderFieldAction(Message.RecipientType.TOCC, "Add Cc: ", recipients); //set a subject for the message msg.setSubject(“Team 1 test email”); //sets the body of the message msg.setContent(“This is a test email sent to"Cc: ” + studentName"); //sets priority msg.setPriority AddHeaderFieldAction addBccMenuItem = new AddHeaderFieldAction(Message.PriorityRecipientType.HIGH); //send the message Transport.send(msgBCC, "Add Bcc: ", "Bcc: ");</source>
9 // MenuItem to save a message MenuItem saveMenuItem = new MenuItem(new StringProvider("Save Message"), 0x230020, 1); saveMenuItem.setCommand(new Command(new CommandHandler() { /** * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata, Object) */ public void execute(ReadOnlyCommandMetadata metadata, Object context) { // If the save is completed, then discard this screen if( onSave() ) { close(); } else // If the message could not be saved, alert the user { UiApplication.getUiApplication().invokeLater(new Runnable() { public void run() { Dialog.alert("Message could not be saved"); } }); } } })); // MenuItem to send a message MenuItem sendMenuItem = new MenuItem(new StringProvider("Send Message"), 0x230010, 0); sendMenuItem.setCommand(new Command(new CommandHandler() { /** * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata, Object) */ public void execute(ReadOnlyCommandMetadata metadata, Object context) { // If the save is completed, then discard this screen try { _message = getMessage(); if( _message != null ) { // Send the message Transport.send(_message); UiApplication.getUiApplication().pushScreen(_messagesViewScreen); close(); } } catch( MessagingException e ) { ViewStudentApp.errorDialog("Transport.send(Message) threw " + e.toString()); } } })); addMenuItem(sendMenuItem); addMenuItem(saveMenuItem); addMenuItem(addToMenuItem); addMenuItem(addCcMenuItem); addMenuItem(addBccMenuItem); } /** * Overrides MessageScreen.displayMessage(). The message's 'sent' properties * are not displayed since the message is still in the process of editing. */ void displayMessage(String email) { // If the message does not exist then compose a new message if( _message == null ) { // Add a To line EditField toField = new EditField("To: ", email, 40, BasicEditField.FILTER_EMAIL); addTextFieldToTableAndScreen(toField, Message.RecipientType.TO); // Add a subject line EditField subjectField = new EditField("Subject: ", ""); addTextFieldToTableAndScreen(subjectField, SUBJECT); // Add a separator between the body and the headers add(new SeparatorField()); // Add a body field EditField bodyField = new EditField(); addTextFieldToTableAndScreen(bodyField, BODY); } else // The message exists so display it { displayHeader(); add(new SeparatorField()); displayMessageBody(); } } /** * Gets a message for sending or saving * @return A new message */ Message getMessage() { // Find an outbox folder and use it to construct a new message Folder outbox = _store.findFolder("Outbox")[ FIRST ]; Message message = new Message(outbox); // Add all the current headers for( int keyNo = 0; keyNo < HEADER_KEYS.length; keyNo++ ) { Vector fieldsByType = (Vector) _fieldTable.get(HEADER_KEYS[ keyNo ]); if( fieldsByType != null ) { // Build a vector of all the addresses Vector addressVector = new Vector(); int size = fieldsByType.size(); for( int fieldNo = 0; fieldNo < size; fieldNo++ ) { TextField addressField = (TextField) fieldsByType.elementAt(fieldNo); // Try to create a new address object wrapping the email // address and add it to the address vector. try { addressVector.addElement(new Address(addressField.getText(), "")); } catch( AddressException e ) // Invalid address { ViewStudentApp.errorDialog("Address(String, String) threw " + e.toString()); } } // Dump the vector of addresses into an array to send the message Address[] addresses = new Address[ addressVector.size() ]; addressVector.copyInto(addresses); // Try to add the addresses to the message's list of recipients try { message.addRecipients(HEADER_KEYS[ keyNo ], addresses); } catch( MessagingException e ) { ViewStudentApp.errorDialog("Message#addRecipients(int, Address[]) threw " + e.toString()); } } } // Add the subject Vector subjectFields = (Vector) _fieldTable.get(SUBJECT); TextField subjectField = (TextField) subjectFields.elementAt(FIRST); if( subjectFields != null && subjectFields.size() > 0 ) { message.setSubject(subjectField.getText()); } // Add the body by adding all the body fields into one multipart Vector bodyFields = (Vector) _fieldTable.get(BODY); if( bodyFields != null ) { int size = bodyFields.size(); Multipart content = new Multipart(); for( int fieldNo = 0; fieldNo < size; fieldNo++ ) { TextField body = (TextField) bodyFields.elementAt(fieldNo); content.addBodyPart(new TextBodyPart(content, body.getText())); } try { message.5 Lets setContent(content); } catch any exceptions ( MessagingException e ) { ViewStudentApp.errorDialog("Message#setContent(Object) threw " + e.toString()); } } else { ViewStudentApp.errorDialog("Error: no body field available"); return null; } // Set the date message.setSentDate(Calendar.getInstance().getTime()); return message; } /** * @see net.rim.device.api.ui.Screen#onSave() */ protected boolean onSave() { // Save the message to the outbox try { Message newMessage = getMessage(); if( newMessage != null ) { // Retrieve an outbox to save the message in Store store = Session.waitForDefaultSession().getStore(); Folder[] allOutboxFolders = store.list(Folder.OUTBOX); Folder outbox = null; for( int i = allOutboxFolders.length - 1; i >= 0 ; --i ) { if( allOutboxFolders[ i ].getParent().getName().startsWith("Mailbox") ) { outbox = allOutboxFolders[ i ]; break; } } // Save the new message and notify replace the user old one if it exists outbox.appendMessage(newMessage); if ( _message != null ) { outbox.deleteMessage(_message, true); } _message = newMessage; // Set the status to composing and flag that it has been saved _message.setStatus(Message.Status.TX_COMPOSING, Message.Status.TX_ERROR); _message.setFlag(Message.Flag.SAVED, true); return true; } return false; } catch( MessagingException e ) { return false; } } /** * Make "Send" the default menu item. * * @see net.rim.device.api.ui.container.MainScreen#makeMenu(Menu,int) */ protected void makeMenu(Menu menu, int instance) { super.makeMenu(menu, instance); // menu.setDefault(SEND_MENU_ITEM_INDEX); } /** * This class is responsible for adding the various header fields to the * compose screen (To, Bcc, CC). */ private final class AddHeaderFieldAction extends MenuItem { private String _fieldLabelText; private int _headerType; /** * Constructs a menu item which adds a header of a specified type to the * compose screen. * * @param headerType One of the Message.RecipientType fields * @param menuItemText String to use for the menu item * @param fieldLabelText String to use for the label of this field */ AddHeaderFieldAction(int headerType, String menuItemText, String fieldLabelText) { super(new StringProvider(menuItemText), 0x240010, 2); _fieldLabelText = fieldLabelText; _headerType = headerType; this.setCommand(new Command(new CommandHandler() { /** * Adds a new header field to the message . The field is placed so that * the header types are grouped together and the most recently added one * is closest to the bottom. * @see net.rim.device.api.command.CommandHandler#execute(ReadOnlyCommandMetadata, Object) */ public void execute(ReadOnlyCommandMetadata metadata, Object context) { EditField newField = new EditField(_fieldLabelText, ""); // Find out where the last field of this type was added to the // screen. Vector fieldsByType = (Vector) _fieldTable.get(_headerType); int lastInsertedIndex; if( fieldsByType == null ) { // If a field of _headerType was sentnot made yet, then create the // vector which contains all of the fields of _headerType. fieldsByType = new Vector(); _fieldTable.put(_headerType, fieldsByType); lastInsertedIndex = getIndexForNewFieldType(); } else { lastInsertedIndex = getIndexOfLastFieldOfType(_headerType); } // Add the new field to both the screen and the vector keeping track // of all the fields of the same type. ComposeScreen.this.insert(newField, lastInsertedIndex + 1); fieldsByType.addElement(newField); newField.setFocus(); } })); } /** * Given the existing field type of this instance of the class, * determine where to place new header fields in the screen. * * @return The index at which to insert the new header field */ private int getIndexForNewFieldType() { // Note: we don't handle TO here since there ALWAYS must be one TO // field. switch( _headerType ) { // Find the last TO field and use the next index as the // insertion point. case Message.RecipientType.CC: return getIndexOfLastFieldOfType(Message.RecipientType.TO); // Try to find the last CC field and use it as the next // insertion point. If no CC field exists then find the last // TO field and use its index as the insertion point. case Message.RecipientType.BCC: int index = getIndexOfLastFieldOfType(Message.RecipientType.CC); if( index == -1 ) return getIndexOfLastFieldOfType(Message.RecipientType.TO); return index; default: throw new IllegalStateException("Mail Demo: Unrecognized recipient type"); } } /** * Retrieves the index of the last field added of a specified type. * * @param type The type of header field to retrieve the last index of * @return The index of the most recently added field of the specified * type, -1 if a field of the specified type has not been added * yet. */ private int getIndexOfLastFieldOfType(int type) { Vector fields = (Vector) _fieldTable.get(type); if( fields == null ) { return -1; } Field field = (Field) fields.lastElement(); return field.getIndex(); } } } </source><code>MessageScreen.java</code> <source lang="java"> package cs.ecl.team1.project; import net.rim.device.api.ui.container.*; import net.rim.device.api.ui.component.*; import net.rim.device.api.util.IntHashtable; import javax.microedition.pim.Contact; import java.util.*; import net.rim.blackberry.api.mail.*; /** * The MessageScreen class allows a user to view a selected message and * edit the message if the screen is marked editable. It manages the different * TextFields using a hashtable where the type of information that is held * in a given TextField is the key while the value is a Vector of TextFields * associated with that information type. This class supports displaying * plain text, Mime, supported and unsupported attachments and pdap contacts. */ public class MessageScreen extends MainScreen { // Constants public final static String NO_SUBJECT = "<No Subject>"; public final static String UNKNOWN_NAME = "<?>"; protected final static int SUBJECT = 0; protected final static int BODY = 1; protected final static int INFO = 2; protected final static int[] HEADER_KEYS = { Message.RecipientType.TO, Message.RecipientType.CC, Message.RecipientType.BCC }; protected final static String[] HEADER_NAMES = { "To: ", "Cc: ", "Bcc: " }; private final static int MAX_CHARS = 128; protected IntHashtable _fieldTable; protected Message _message; private boolean _editable; /** * Creates a new MessageScreen object * @param message The message to display * @param editable True is the message is editable, otherwise false */ public MessageScreen(Message message, boolean editable, String email) { _fieldTable = new IntHashtable(); _editable = editable; // Set the message and display its subject as the title if the // message exists. _message = message; if( _message != null ) setTitle(_message.getSubject()); displayMessage(email); } /** * Displays the message */ void displayMessage(String email) { displayMessageInformation(); add(new SeparatorField()); displayHeader(); add(new SeparatorField()); displayMessageBody(); } /** * Displays information about the message's send and recieve properties */ protected void displayMessageInformation() { // Add a field describing the source service ServiceConfiguration sc = _message.getFolder().getStore().getServiceConfiguration(); EditField service = new EditField("Service: ", sc.getName(), MAX_CHARS, EditField.READONLY | EditField.NON_FOCUSABLE); addTextFieldToTableAndScreen(service, INFO); // Add the folder field EditField folder = new EditField("Folder: ", _message.getFolder().getName(), MAX_CHARS, EditField.READONLY | EditField.NON_FOCUSABLE); addTextFieldToTableAndScreen(folder, INFO); // Add the status of the message String statusString = getStatusString(_message); EditField status = new EditField("Status: ", statusString, MAX_CHARS, EditField.READONLY | EditField.NON_FOCUSABLE); addTextFieldToTableAndScreen(status, INFO); } /** * Displays information about the destination and source of the message as * well as its subject. */ protected void displayHeader() { // Assign the appropriate EditField style property long editableStyle = _editable ? EditField.EDITABLE : EditField.READONLY; // Display the headers (To:, Cc:, Bcc:) for( int key = 0; key < HEADER_KEYS.length; key++ ) { try { Address[] addresses = _message.getRecipients(HEADER_KEYS[ key ]); for( int index = 0; index < addresses.length; index++ ) { // Retrieve the name String name = addresses[ index ].getName(); if( name == null || name.length() == 0 ) { name = addresses[ index ].getAddr(); } // Create the edit field, associate the address to the field // and add it to the screen and collection of fields. EditField headerField = new EditField(HEADER_NAMES[ key ], name, EditField.DEFAULT_MAXCHARS, editableStyle); headerField.setCookie(addresses[ index ]); addTextFieldToTableAndScreen(headerField, HEADER_KEYS[ key ]); } } catch (Exception meMessagingException e ) { ViewStudentApp.errorDialog("Error: could not retrieve message header."); close(); } } // Display the 'Sent' date if it is available Date sent = _message.getSentDate(); if( sent != null ) { EditField sentDate = new EditField("Sent: ", Util.getDateAsString(sent), EditField.DEFAULT_MAXCHARS, EditField.READONLY | EditField.NON_FOCUSABLE); // Change the label to "Saved: " if the message hasn't been sent yet if( _message.getStatus() == Message.Status.TX_COMPOSING ) sentDate.setLabel("Saved: "); add(sentDate); } // Display the subject field String subject = _message.getSubject(); if( subject == null ) subject = NO_SUBJECT; EditField subjectField = new EditField("Subject: ", subject, EditField.DEFAULT_MAXCHARS, editableStyle); addTextFieldToTableAndScreen(subjectField, SUBJECT); } /** * Displays the message body */ protected void displayMessageBody() { // Retrieve the parent of the message body Object obj = _message.getContent(); Multipart parent = null; if( obj instanceof MimeBodyPart || obj instanceof TextBodyPart ) { BodyPart bp = (BodyPart) obj; parent = bp.getParent(); } else { parent = (Multipart) obj; } // Display the message body String mpType = parent.getContentType(); if( mpType.equals(BodyPart.ContentType.TYPE_MULTIPART_ALTERNATIVE_STRING) || mpType.equals(BodyPart.ContentType.TYPE_MULTIPART_MIXED_STRING) ) { displayMultipart(parent); } // Ensure there is at least one body field if nothing was displayed Vector bodyVector = (Vector) _fieldTable.get(BODY); if( bodyVector == null || bodyVector.size() == 0 ) { if( _editable ) { addTextFieldToTableAndScreen(new EditField("", ""), BODY) ; } else { addTextFieldToTableAndScreen(new RichTextField(""), BODY); } } } /** * Processes a multi-part message by displaying its body parts. Text body * parts are displayed before attachments and if a multi body part is * encountered, then it is processed through recursion by calling this method * on it. * * @param multipart The multi-part to display * @param editable True if this multi-part is editable */ Systemprotected void displayMultipart(Multipart multipart) { // This vector stores fields which are to be displayed only after all // of the body fields are displayed. (Attachments and Contacts). Vector delayedFields = new Vector(); // Process each part of the multi-part, taking the appropriate action // depending on the part's type. This loop should: display text and // html body parts, recursively display multi-parts and store // attachments and contacts to display later. for( int index = 0; index < multipart.getCount(); index++ ) { BodyPart bodyPart = multipart.getBodyPart(index); // If this body part is text then display all of it if( bodyPart instanceof TextBodyPart ) { TextBodyPart textBodyPart = (TextBodyPart) bodyPart; // If there are missing parts of the text, try to retrieve the // rest of it. if( textBodyPart.errhasMore() ) { try { Transport.printlnmore(metextBodyPart, true); } catch( Exception e ) { Dialog ViewStudentApp.errorDialog("Transport.alertmore(studentName BodyPart, boolean) threw " + e.toString()); } } String plainText = (String) textBodyPart.getContent(); // Display the plain text, using an EditField if the message is // editable or a RichTextField if it is not editable. Note: this // does not add any empty fields. if( plainText.length() != 0 ) { if( _editable ) { addTextFieldToTableAndScreen(new EditField(" ", plainText), BODY); } else { addTextFieldToTableAndScreen(new RichTextField(plainText), BODY); } } } else if( bodyPart instanceof MimeBodyPart ) { MimeBodyPart mimeBodyPart = (MimeBodyPart) bodyPart; // If the content is text then display it String contentType = mimeBodyPart.getContentType(); if( contentType.startsWith(BodyPart.ContentType.TYPE_TEXT_HTML_STRING) ) { Object obj = mimeBodyPart.getContent(); if( obj != null ) { String htmlText = new String((byte[]) obj); addTextFieldToTableAndScreen(new RichTextField(htmlText), BODY); } } else if( contentType.equals(BodyPart.ContentType.TYPE_MULTIPART_ALTERNATIVE_STRING) ) { // If the body part is a multi-part and it has the the // content type of TYPE_MULTIPART_ALTERNATIVE_STRING, then // recursively display the multi-part. Object obj = mimeBodyPart.getContent(); if( obj instanceof Multipart ) { Multipart childMultipart = (Multipart) obj; String childMultipartType = childMultipart.getContentType(); if( childMultipartType.equals(BodyPart.ContentType.TYPE_MULTIPART_ALTERNATIVE_STRING) ) { displayMultipart(childMultipart); } } } } else if( bodyPart instanceof SupportedAttachmentPart || bodyPart instanceof UnsupportedAttachmentPart ) { // Extract the content type and name from the attachments String contentType = bodyPart.getContentType(); String name; if( bodyPart instanceof UnsupportedAttachmentPart ) { UnsupportedAttachmentPart uap = (UnsupportedAttachmentPart) bodyPart; name = uap.getName(); } else // The bodyPart is a SupportedAttachmentPart { SupportedAttachmentPart sap = (SupportedAttachmentPart) bodyPart; name = sap.getName(); } // Format the content type and name to display and store // the field. StringBuffer sb = new StringBuffer(contentType.length() + name.length() + 2); sb.append(contentType); sb.append('['); sb.append(name); sb.append(']'); delayedFields.addElement(new RichTextField(sb.toString())); } else if( bodyPart instanceof PDAPContactAttachmentPart ) { Contact contact = (Contact) bodyPart.getContent(); // Build the contact name StringBuffer sb = new StringBuffer("Contact: "); if( contact.countValues(Contact.NAME) > 0 ) { String[] name = contact.getStringArray(Contact.NAME, 0); if( name[ Contact.NAME_PREFIX ] != null ) { sb.append(name[ Contact.NAME_PREFIX ]); sb.append(' '); } if( name[ Contact.NAME_GIVEN ] != null ) { sb.append(name[ Contact.NAME_GIVEN ]); sb.append(' '); } if( name[ Contact.NAME_FAMILY ] != null ) { sb.append(name[ Contact.NAME_FAMILY ]); } // Trim the last space of the name if it exists int lastChar = sb.length() - 1; if( sb.charAt(lastChar) == ' ' ) sb.deleteCharAt(lastChar); } else { sb.append(UNKNOWN_NAME); } // Create the contact attachment field and store it RichTextField contactAttachment = new RichTextField(sb.toString()); contactAttachment.setCookie(contact); delayedFields.addElement(contactAttachment); } } // Now that the body parts have been emaileddisplayed, display the queued // fields while separating them by inserting a separator field. for( int index = 0; index < delayedFields.size(); index++ ) { add(new SeparatorField()); addTextFieldToTableAndScreen((TextField) delayedFields.elementAt(index), BODY); } } /** * Compiles the status of a message into a readable string. * * @param message The message whose status is to be compiled into a string * @return The string displaying the status of the message */ public static String getStatusString(Message message) { StringBuffer statusStrBuffer = new StringBuffer(); // Add any errors to the status string if it applies int status = message.getStatus(); if( status == Message.Status.RX_ERROR ) { statusStrBuffer.append("RX ERROR, "); } if( status == Message.Status.TX_GENERAL_FAILURE ) { statusStrBuffer.append("RX ERROR, "); } if( status == Message.Status.TX_ERROR ) { statusStrBuffer.append("TX ERROR, "); } // Use the flags to add any message statuses int flags = message.getFlags(); if( 0 != (flags & Message.Flag.OPENED) ) { statusStrBuffer.append("Opened, "); } if( 0 != (flags & Message.Flag.SAVED) ) { statusStrBuffer.append("Saved, "); } if( 0 != (flags & Message.Flag.FILED) ) { statusStrBuffer.append("Filed, "); } // Check if the message has a high or low priority byte messagePriority = message.getPriority(); if( messagePriority == Message.Priority.HIGH ) { statusStrBuffer.append("High Priority, "); } else if( messagePriority == Message.Priority.LOW ) { statusStrBuffer.append("Low Priority, "); } // If there are any characters in the status string then delete the last // two characters if there are any characters to delete. Should be // either ", " or " ". statusStrBuffer.delete(statusStrBuffer.length() - 2, statusStrBuffer.length()); return statusStrBuffer.toString(); } /** * Add a new field to the hashtable of TextFields and to the screen * * @param field The field to add * @param type The type of field to add */ protected void addTextFieldToTableAndScreen(TextField field, int type) { Vector fieldsByType = (Vector) _fieldTable.get(type); // If the vector of fields associated with the type is not made yet, // initialize one and put it into the fields collection. if( fieldsByType == null ) { fieldsByType = new Vector(1); _fieldTable.put(type, fieldsByType); } fieldsByType.addElement(field); add(field); } /** * @see net.rim.device.api.ui.Screen#onClose() */ public boolean onClose() { // If the message status is "received", mark it "read" if( _message != null && _message.getStatus() == Message.Status.RX_RECEIVED ) { _message.setStatus(Message.Status.TX_READ, Message.Status.TX_ERROR); _message.setFlag(Message.Flag.OPENED, true); } return super.onClose(); } } </source>Other classes stay unchanged.<br/>9.4. Run the application, select a user from the list, and select Email Student from the menu:<br/>[[Image: BB_email1.png | 300px]][[Image: BB_email2.png | 300px]]<br/>9.5. Type in the subject and some text in the body, and select Send Email from the menu:<br/>[[Image: BB_email3.png | 300px]]<br/>9.6. The messageList screen is displayed showing the created email. Select Folder View from the menu to see the Outbox folder:<br/>[[Image: BB_email4.png | 300px]][[Image: BB_email5.png | 300px]]