/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.codename1.impl.blackberry;
import com.codename1.codescan.CodeScanner;
import com.codename1.contacts.Contact;
import com.codename1.ui.Component;
import com.codename1.ui.Dialog;
import com.codename1.ui.Display;
import com.codename1.ui.Form;
import com.codename1.ui.PeerComponent;
import com.codename1.ui.TextArea;
import com.codename1.ui.animations.Animation;
import com.codename1.ui.events.ActionEvent;
import com.codename1.ui.events.ActionListener;
import com.codename1.ui.geom.Dimension;
import com.codename1.impl.CodenameOneImplementation;
import com.codename1.impl.blackberry.codescan.CodeScannerImpl;
import com.codename1.impl.blackberry.codescan.MultimediaManager;
import com.codename1.ui.plaf.UIManager;
import com.codename1.ui.util.EventDispatcher;
import com.codename1.ui.util.Resources;
import javax.microedition.io.ConnectionNotFoundException;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.midlet.MIDlet;
import net.rim.device.api.ui.Screen;
import net.rim.device.api.system.Application;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.GPRSInfo;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FocusChangeListener;
import net.rim.device.api.ui.Font;
import net.rim.device.api.ui.FontFamily;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Keypad;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.Ui;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.XYRect;
import net.rim.device.api.ui.component.ActiveAutoTextEditField;
import net.rim.device.api.ui.component.BasicEditField;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.component.NullField;
import net.rim.device.api.ui.component.PasswordEditField;
import net.rim.device.api.ui.container.PopupScreen;
import net.rim.device.api.ui.container.VerticalFieldManager;
import com.codename1.io.BufferedInputStream;
import com.codename1.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import javax.microedition.io.Connection;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.io.file.FileConnection;
import javax.microedition.io.file.FileSystemRegistry;
import javax.microedition.rms.RecordEnumeration;
import javax.microedition.rms.RecordStore;
import javax.microedition.rms.RecordStoreException;
import net.rim.device.api.servicebook.ServiceBook;
import net.rim.device.api.servicebook.ServiceRecord;
import com.codename1.io.NetworkManager;
// requires signing
import com.codename1.l10n.L10NManager;
import com.codename1.location.LocationManager;
import com.codename1.media.Media;
import com.codename1.messaging.Message;
import com.codename1.ui.Image;
import java.util.Date;
import javax.microedition.io.Datagram;
import javax.microedition.io.DatagramConnection;
import javax.microedition.media.Manager;
import javax.wireless.messaging.MessageConnection;
import javax.wireless.messaging.TextMessage;
import net.rim.blackberry.api.invoke.CameraArguments;
import net.rim.blackberry.api.invoke.Invoke;
import net.rim.blackberry.api.invoke.MessageArguments;
import net.rim.blackberry.api.invoke.PhoneArguments;
import net.rim.blackberry.api.mail.Address;
import net.rim.blackberry.api.mail.Folder;
import net.rim.blackberry.api.mail.Multipart;
import net.rim.blackberry.api.mail.Session;
import net.rim.blackberry.api.mail.SupportedAttachmentPart;
import net.rim.blackberry.api.mail.TextBodyPart;
import net.rim.device.api.system.CodeModuleGroup;
import net.rim.device.api.system.CodeModuleGroupManager;
import net.rim.blackberry.api.phone.Phone;
import net.rim.device.api.applicationcontrol.ApplicationPermissions;
import net.rim.device.api.applicationcontrol.ApplicationPermissionsManager;
import net.rim.device.api.i18n.DateFormat;
import net.rim.device.api.i18n.Locale;
import net.rim.device.api.io.IOUtilities;
import net.rim.device.api.io.file.FileSystemJournal;
import net.rim.device.api.io.file.FileSystemJournalEntry;
import net.rim.device.api.io.file.FileSystemJournalListener;
import net.rim.device.api.system.*;
/**
* The implementation of the blackberry platform delegates the work to the underlying UI
* application to allow for deep BB integration
*
* @author Shai Almog, Thorsten Schemm
*/
public class BlackBerryImplementation extends CodenameOneImplementation {
public static boolean nativeBrowser = false;
protected static BlackBerryImplementation instance;
private static CodeModuleGroup group;
static Hashtable fieldComponentMap = new Hashtable();
static final int INVOKE_LATER_confirmControlView = 1;
static final int INVOKE_LATER_finishEdit = 2;
static final int INVOKE_LATER_initComponent = 3;
static final int INVOKE_LATER_deinitialize = 4;
static final int INVOKE_LATER_showNativeScreen = 5;
static final int INVOKE_AND_WAIT_calcPreferredSize = 6;
static final int INVOKE_AND_WAIT_setFocus = 7;
static final int INVOKE_LATER_dirty = 8;
static final int INVOKE_LATER_startMedia = 9;
private static boolean minimizeOnEnd = true;
// blackberry sometimes "breaks" the drawing color... No idea why this might happen...
private int color;
static final int MENU_SOFT_KEY = Keypad.KEY_MENU;
static final int GAME_KEY_CODE_FIRE = -90;
static final int GAME_KEY_CODE_UP = -91;
static final int GAME_KEY_CODE_DOWN = -92;
static final int GAME_KEY_CODE_LEFT = -93;
static final int GAME_KEY_CODE_RIGHT = -94;
BasicEditField nativeEdit;
TextArea lightweightEdit;
private BlackBerryCanvas canvas = createCanvas();
CodenameOneUiApplication app;
private boolean initGetProperty = true;
private static EventDispatcher volumeListener;
private NullField nullFld;
private String currentAccessPoint;
private boolean deviceSide;
/**
* The File Allocation Table assigns user based file names to RMS storage
*/
private Hashtable fat = new Hashtable();
private short currentKey = 1;
//protected ActionListener camResponse;
protected EventDispatcher captureCallback;
//by default don't ask for permissions
private static boolean askForPermission = false;
BlackBerryCanvas createCanvas() {
return new BlackBerryCanvas(this);
}
public static void setAskPermission(boolean ask) {
askForPermission = ask;
}
public void init(Object m) {
instance = this;
app = (CodenameOneUiApplication) m;
if(askForPermission) {
app.invokeAndWait(new Runnable() {
public void run() {
ApplicationPermissions permRequest = new ApplicationPermissions();
permRequest.addPermission(ApplicationPermissions.PERMISSION_EMAIL);
permRequest.addPermission(ApplicationPermissions.PERMISSION_FILE_API);
permRequest.addPermission(ApplicationPermissions.PERMISSION_WIFI);
try {
//ApplicationPermissions.PERMISSION_CROSS_APPLICATION_COMMUNICATION
permRequest.addPermission(11);
} catch (Exception e) {
}
try {
//ApplicationPermissions.PERMISSION_MEDIA
permRequest.addPermission(21);
} catch (Exception e) {
}
try {
//ApplicationPermissions.PERMISSION_INPUT_SIMULATION
permRequest.addPermission(6);
} catch (Exception e) {
}
try {
//ApplicationPermissions.PERMISSION_LOCATION_DATA
permRequest.addPermission(14);
} catch (Exception e) {
}
try {
//ApplicationPermissions.PERMISSION_ORGANIZER_DATA
permRequest.addPermission(16);
} catch (Exception e) {
}
try {
//ApplicationPermissions.PERMISSION_INTERNET
permRequest.addPermission(7);
} catch (Exception e) {
}
try {
//ApplicationPermissions.PERMISSION_RECORDING
permRequest.addPermission(17);
} catch (Exception e) {
}
ApplicationPermissionsManager apm = ApplicationPermissionsManager.getInstance();
if (!apm.invokePermissionsRequest(permRequest)) {
exitApplication();
return;
}
}
});
}
app.enableKeyUpEvents(true);
if (!app.isHandlingEvents()) {
new Thread() {
public void run() {
app.enterEventDispatcher();
}
}.start();
}
Dialog.setCommandsAsButtons(true);
UIManager.getInstance().addThemeRefreshListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
Hashtable themeProps = new Hashtable();
themeProps.put("SoftButton.margin", "0,0,0,0");
themeProps.put("SoftButton.padding", "0,0,0,0");
UIManager.getInstance().addThemeProps(themeProps);
}
});
RecordEnumeration e = null;
RecordStore r = null;
try {
r = RecordStore.openRecordStore("FAT", true);
if (r.getNumRecords() > 0) {
e = r.enumerateRecords(null, null, false);
while (e.hasNextElement()) {
byte[] rec = e.nextRecord();
ByteArrayInputStream bi = new ByteArrayInputStream(rec);
DataInputStream di = new DataInputStream(bi);
String name = di.readUTF();
short key = di.readShort();
di.close();
bi.close();
fat.put(name, new Short(key));
if (key >= currentKey) {
currentKey += key;
}
}
e.destroy();
e = null;
}
r.closeRecordStore();
r = null;
} catch (Exception ex) {
ex.printStackTrace();
cleanup(r);
cleanup(e);
}
}
public void confirmControlView() {
InvokeLaterWrapper i = new InvokeLaterWrapper(INVOKE_LATER_confirmControlView);
i.fld = canvas;
app.invokeLater(i);
}
protected void keyPressed(final int keyCode) {
// expose the method to the canvas
super.keyPressed(keyCode);
}
protected void keyReleased(final int keyCode) {
// expose the method to the canvas
super.keyReleased(keyCode);
}
public int getDisplayWidth() {
// the alternative undeprecated API requires a signature
return net.rim.device.api.ui.Graphics.getScreenWidth();
}
public int getDisplayHeight() {
// the alternative undeprecated API requires a signature
return net.rim.device.api.ui.Graphics.getScreenHeight();
}
public void editString(final Component cmp, final int maxSize, final int constraint, final String text, int keyCode) {
TextArea txtCmp = (TextArea) cmp;
String edit = (String) txtCmp.getClientProperty("RIM.nativePopup");
if(edit != null){
EditPopup editpop = new EditPopup(txtCmp, maxSize);
editpop.startEdit();
}else{
nativeEdit(txtCmp, txtCmp.getMaxSize(), txtCmp.getConstraint(), txtCmp.getText(), keyCode);
}
}
public void nativeEdit(final Component cmp, final int maxSize, final int constraint, String text, int keyCode) {
if (nativeEdit != null) {
finishEdit(true);
}
lightweightEdit = (TextArea) cmp;
if (keyCode > 0 && getKeyboardType() == Display.KEYBOARD_TYPE_QWERTY) {
//if this is a number
if ((constraint & TextArea.DECIMAL) == TextArea.DECIMAL
|| (constraint & TextArea.NUMERIC) == TextArea.NUMERIC
|| (constraint & TextArea.PHONENUMBER) == TextArea.PHONENUMBER) {
if(keyCode == 119){
text += "1";
}else if(keyCode == 101){
text += "2";
}else if(keyCode == 114){
text += "3";
}else if(keyCode == 115){
text += "4";
}else if(keyCode == 100){
text += "5";
}else if(keyCode == 102){
text += "6";
}else if(keyCode == 122){
text += "7";
}else if(keyCode == 120){
text += "8";
}else if(keyCode == 99){
text += "9";
}
}else{
text += ((char) keyCode);
}
lightweightEdit.setText(text);
}
class LightweightEdit implements Runnable, Animation {
public void run() {
long type = 0;
TextArea lightweightEditTmp = lightweightEdit;
if (lightweightEditTmp == null) {
return;
}
int constraint = lightweightEditTmp.getConstraint();
if ((constraint & TextArea.DECIMAL) == TextArea.DECIMAL) {
type = BasicEditField.FILTER_REAL_NUMERIC;
} else if ((constraint & TextArea.EMAILADDR) == TextArea.EMAILADDR) {
type = BasicEditField.FILTER_EMAIL;
} else if ((constraint & TextArea.NUMERIC) == TextArea.NUMERIC) {
type = BasicEditField.FILTER_NUMERIC;
}
if ((constraint & TextArea.PHONENUMBER) == TextArea.PHONENUMBER) {
type = BasicEditField.FILTER_PHONE;
}
if ((constraint & TextArea.NON_PREDICTIVE) == TextArea.NON_PREDICTIVE) {
type |= BasicEditField.NO_COMPLEX_INPUT;
}
if (lightweightEditTmp.isSingleLineTextArea()) {
type |= BasicEditField.NO_NEWLINE;
}
if ((constraint & TextArea.PASSWORD) == TextArea.PASSWORD) {
nativeEdit = new BBPasswordEditField(lightweightEditTmp, type, maxSize);
} else {
nativeEdit = new BBEditField(lightweightEditTmp, type, maxSize);
}
nativeEdit.setEditable(true);
Font f = nativeEdit.getFont();
if (f.getHeight() > lightweightEditTmp.getStyle().getFont().getHeight()) {
nativeEdit.setFont(f.derive(f.getStyle(), lightweightEditTmp.getStyle().getFont().getHeight()));
}
canvas.add(nativeEdit);
nativeEdit.setCursorPosition(lightweightEditTmp.getText().length());
try {
nativeEdit.setFocus();
} catch (Throwable t) {
// no idea why this throws an exception sometimes
//t.printStackTrace();
}
}
public boolean animate() {
BasicEditField ef = nativeEdit;
Component lw = lightweightEdit;
if (lw == null || lw.getComponentForm() != Display.getInstance().getCurrent()) {
Display.getInstance().getCurrent().deregisterAnimated(this);
finishEdit(false);
} else {
if (ef != null) {
if (ef.isDirty()) {
lw.repaint();
}
}
}
return false;
}
public void paint(com.codename1.ui.Graphics g) {
}
}
LightweightEdit lw = new LightweightEdit();
Display.getInstance().getCurrent().registerAnimated(lw);
Application.getApplication().invokeLater(lw);
}
public void setCurrentForm(Form f) {
super.setCurrentForm(f);
nullFld = null;
synchronized (UiApplication.getEventLock()) {
while (canvas.getFieldCount() > 0) {
canvas.delete(canvas.getField(0));
}
}
}
protected void disableBlockFolding() {
}
void finishEdit(final boolean canceled) {
// assigning the field here prevents a null pointer exception in the layout
BasicEditField be = nativeEdit;
if (be != null) {
if (!Application.isEventDispatchThread()) {
InvokeLaterWrapper i = new InvokeLaterWrapper(INVOKE_LATER_finishEdit);
Application.getApplication().invokeLater(i);
return;
}
if (!canceled && lightweightEdit != null) {
Display.getInstance().onEditingComplete(lightweightEdit, be.getText());
}
lightweightEdit = null;
nativeEdit = null;
canvas.delete(be);
flushGraphics();
disableBlockFolding();
Display.getInstance().setShowVirtualKeyboard(false);
}
}
public void setNativeCommands(Vector commands) {
canvas.setNativeCommands(commands);
}
public void flushGraphics(int x, int y, int width, int height) {
canvas.flush(x, y, width, height, app);
}
public void flushGraphics() {
canvas.flush(0, 0, getDisplayWidth(), getDisplayHeight(), app);
}
public void getRGB(Object nativeImage, int[] arr, int offset, int x, int y, int width, int height) {
Bitmap b = (Bitmap) nativeImage;
b.getARGB(arr, offset, width, x, y, width, height);
}
public Object createImage(int[] rgb, int width, int height) {
Bitmap image = new Bitmap(width, height);
image.setARGB(rgb, 0, width, 0, 0, width, height);
return image;
}
public Object createImage(String path) throws IOException {
if (path.startsWith("file:") && exists(path)) {
InputStream is = null;
try {
is = openInputStream(path);
return createImage(is);
} finally {
is.close();
}
}
try {
return createImage(com.codename1.ui.Image.class.getResourceAsStream(path));
} catch (RuntimeException err) {
throw new IOException(err.toString());
}
}
public Object createImage(InputStream i) throws IOException {
java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream();
byte[] buf = new byte[2048];
int len;
while ((len = i.read(buf)) > -1) {
out.write(buf, 0, len);
}
out.close();
i.close();
byte[] b = out.toByteArray();
return Bitmap.createBitmapFromBytes(b, 0, b.length, 1);
}
public boolean isAlphaMutableImageSupported() {
return true;
}
public Object createMutableImage(int width, int height, int fillColor) {
Bitmap b = new Bitmap(width, height);
Graphics g = new Graphics(b);
if ((fillColor & 0xff000000) != 0xff000000) {
g.setColor(fillColor & 0xffffff);
int oldAlpha = g.getGlobalAlpha();
g.setGlobalAlpha((fillColor >> 24) & 0xff);
g.clear();
g.setGlobalAlpha(oldAlpha);
} else {
g.setColor(fillColor & 0xffffff);
g.fillRect(0, 0, width, height);
}
return b;
}
public Object createImage(byte[] bytes, int offset, int len) {
return Bitmap.createBitmapFromBytes(bytes, offset, len, 1);
}
public int getImageWidth(Object i) {
return ((Bitmap) i).getWidth();
}
public int getImageHeight(Object i) {
return ((Bitmap) i).getHeight();
}
/**
* @inheritDoc
*/
public Object scale(Object nativeImage, int width, int height) {
Bitmap image = (Bitmap) nativeImage;
int srcWidth = image.getWidth();
int srcHeight = image.getHeight();
// no need to scale
if (srcWidth == width && srcHeight == height) {
return image;
}
int[] currentArray = new int[srcWidth];
int[] destinationArray = new int[width * height];
scaleArray(image, srcWidth, srcHeight, height, width, currentArray, destinationArray);
return createImage(destinationArray, width, height);
}
private void scaleArray(Bitmap currentImage, int srcWidth, int srcHeight, int height, int width, int[] currentArray, int[] destinationArray) {
// Horizontal Resize
int yRatio = (srcHeight << 16) / height;
int xRatio = (srcWidth << 16) / width;
int xPos = xRatio / 2;
int yPos = yRatio / 2;
// if there is more than 16bit color there is no point in using mutable
// images since they won't save any memory
for (int y = 0; y < height; y++) {
int srcY = yPos >> 16;
getRGB(currentImage, currentArray, 0, 0, srcY, srcWidth, 1);
for (int x = 0; x < width; x++) {
int srcX = xPos >> 16;
int destPixel = x + y * width;
if ((destPixel >= 0 && destPixel < destinationArray.length) && (srcX < currentArray.length)) {
destinationArray[destPixel] = currentArray[srcX];
}
xPos += xRatio;
}
yPos += yRatio;
xPos = xRatio / 2;
}
}
public int getSoftkeyCount() {
return 1;
}
public int[] getSoftkeyCode(int index) {
return new int[]{MENU_SOFT_KEY};
}
public int getClearKeyCode() {
return Keypad.KEY_DELETE;
}
public int getBackspaceKeyCode() {
return Keypad.KEY_BACKSPACE;
}
public int getBackKeyCode() {
return Keypad.KEY_ESCAPE;
}
public int getGameAction(int keyCode) {
switch (keyCode) {
// the enter key should also map to fire
case '\n':
case GAME_KEY_CODE_FIRE:
return Display.GAME_FIRE;
case GAME_KEY_CODE_UP:
return Display.GAME_UP;
case GAME_KEY_CODE_DOWN:
return Display.GAME_DOWN;
case GAME_KEY_CODE_LEFT:
return Display.GAME_LEFT;
case GAME_KEY_CODE_RIGHT:
return Display.GAME_RIGHT;
}
return 0;
}
public int getKeyCode(int gameAction) {
switch (gameAction) {
case Display.GAME_FIRE:
return GAME_KEY_CODE_FIRE;
case Display.GAME_UP:
return GAME_KEY_CODE_UP;
case Display.GAME_DOWN:
return GAME_KEY_CODE_DOWN;
case Display.GAME_LEFT:
return GAME_KEY_CODE_LEFT;
case Display.GAME_RIGHT:
return GAME_KEY_CODE_RIGHT;
}
return 0;
}
public boolean isTouchDevice() {
return canvas.isTouchDevice();
}
public int getColor(Object graphics) {
if (graphics == canvas.getGlobalGraphics()) {
// make sure color wasn't broken...
((Graphics) graphics).setColor(color);
return color;
}
return ((Graphics) graphics).getColor() & 0xffffff;
}
public void setColor(Object graphics, int RGB) {
if (graphics == canvas.getGlobalGraphics()) {
color = RGB;
}
((Graphics) graphics).setColor(RGB);
}
public boolean isAlphaGlobal() {
return true;
}
public void setAlpha(Object graphics, int alpha) {
((Graphics) graphics).setGlobalAlpha(alpha);
}
public int getAlpha(Object graphics) {
return ((Graphics) graphics).getGlobalAlpha();
}
public void setNativeFont(Object graphics, Object font) {
((Graphics) graphics).setFont(font(font));
}
public int getClipX(Object graphics) {
XYRect r = new XYRect();
((Graphics) graphics).getAbsoluteClippingRect(r);
return r.x;
}
public int getClipY(Object graphics) {
XYRect r = new XYRect();
((Graphics) graphics).getAbsoluteClippingRect(r);
return r.y;
}
public int getClipWidth(Object graphics) {
XYRect r = new XYRect();
((Graphics) graphics).getAbsoluteClippingRect(r);
return r.width;
}
public int getClipHeight(Object graphics) {
XYRect r = new XYRect();
((Graphics) graphics).getAbsoluteClippingRect(r);
return r.height;
}
public void setClip(Object graphics, int x, int y, int width, int height) {
Graphics g = (net.rim.device.api.ui.Graphics) graphics;
net.rim.device.api.ui.Font oldFont = g.getFont();
int oldColor = g.getColor();
int oldAlpha = g.getGlobalAlpha();
while (g.getContextStackSize() > 1) {
g.popContext();
}
g.pushRegion(x, y, width, height, 0, 0);
g.translate(-g.getTranslateX(), -g.getTranslateY());
/**
* applying a clip will automatically
* reset some information that we need to keep track of
* manually (it seems).
*/
g.setFont(oldFont == null ? (net.rim.device.api.ui.Font) getDefaultFont() : oldFont);
g.setColor(oldColor);
g.setGlobalAlpha(oldAlpha);
}
public void clipRect(Object graphics, int x, int y, int width, int height) {
Graphics g = (Graphics) graphics;
g.pushRegion(x, y, width, height, 0, 0);
g.translate(-g.getTranslateX(), -g.getTranslateY());
}
public void drawLine(Object graphics, int x1, int y1, int x2, int y2) {
((Graphics) graphics).drawLine(x1, y1, x2, y2);
}
public void fillRect(Object graphics, int x, int y, int width, int height) {
((Graphics) graphics).fillRect(x, y, width, height);
}
public void drawRect(Object graphics, int x, int y, int width, int height) {
((Graphics) graphics).drawRect(x, y, width, height);
}
public void drawRoundRect(Object graphics, int x, int y, int width, int height, int arcWidth, int arcHeight) {
((Graphics) graphics).drawRoundRect(x, y, width, height, arcWidth, arcHeight);
}
public void fillRoundRect(Object graphics, int x, int y, int width, int height, int arcWidth, int arcHeight) {
((Graphics) graphics).fillRoundRect(x, y, width, height, arcWidth, arcHeight);
}
public void fillArc(Object graphics, int x, int y, int width, int height, int startAngle, int arcAngle) {
((Graphics) graphics).fillArc(x, y, width, height, startAngle, arcAngle);
}
public void drawArc(Object graphics, int x, int y, int width, int height, int startAngle, int arcAngle) {
((Graphics) graphics).drawArc(x, y, width, height, startAngle, arcAngle);
}
public void drawString(Object graphics, String str, int x, int y) {
((Graphics) graphics).drawText(str, x, y);
}
// /**
// * @inheritDoc
// */
// public VideoComponent createVideoPeer(String url) throws IOException {
// try {
// Player p = Manager.createPlayer(url);
// p.realize();
// VideoControl vidc = (VideoControl) p.getControl("VideoControl");
// Field f = (Field) vidc.initDisplayMode(VideoControl.USE_GUI_PRIMITIVE, "net.rim.device.api.ui.Field");
// RIMVideoComponent r = new RIMVideoComponent(f, p, vidc);
// r.putClientProperty("VideoControl", vidc);
// r.putClientProperty("Player", p);
// return r;
// } catch (MediaException ex) {
// ex.printStackTrace();
// throw new IOException(ex.toString());
// }
// }
/**
* Plays the sound in the given URI which is partially platform specific.
*
* @param uri the platform specific location for the sound
* @param onCompletion invoked when the audio file finishes playing, may be null
* @return a handle that can be used to control the playback of the audio
* @throws java.io.IOException if the URI access fails
*/
public Media createMedia(String uri, boolean isVideo, Runnable onCompletion) throws IOException {
MMAPIPlayer player = MMAPIPlayer.createPlayer(uri, onCompletion);
if (isVideo) {
VideoMainScreen video = new VideoMainScreen(player, this);
return video;
}
return player;
}
/**
* Plays the sound in the given stream
*
* @param stream the stream containing the media data
* @param mimeType the type of the data in the stream
* @param onCompletion invoked when the audio file finishes playing, may be null
* @return a handle that can be used to control the playback of the audio
* @throws java.io.IOException if the URI access fails
*/
public Media createMedia(InputStream stream, String mimeType, Runnable onCompletion) throws IOException {
MMAPIPlayer player = MMAPIPlayer.createPlayer(stream, mimeType, onCompletion);
if (mimeType.indexOf("video") > -1) {
VideoMainScreen video = new VideoMainScreen(player, this);
return video;
}
return player;
}
/**
* This method returns the platform Location Control
* @return LocationControl Object
*/
public LocationManager getLocationManager() {
return new RIMLocationManager();
}
public void drawImage(Object graphics, Object img, int x, int y) {
Bitmap b = (Bitmap) img;
((Graphics) graphics).drawBitmap(x, y, b.getWidth(), b.getHeight(), b, 0, 0);
}
public void drawRGB(Object graphics, int[] rgbData, int offset, int x, int y, int w, int h, boolean processAlpha) {
Graphics nativeGraphics = (Graphics) graphics;
int rgbX = x;
int rgbY = y;
//if the x or y are positive simply redirect the call to midp Graphics
if (rgbX >= 0) {
if (processAlpha) {
nativeGraphics.drawARGB(rgbData, offset, w, rgbX, rgbY, w, h);
} else {
nativeGraphics.drawRGB(rgbData, offset, w, rgbX, rgbY, w, h);
}
return;
}
//if the translate causes us to paint out of the bounds
//we will paint only the relevant rows row by row to avoid some devices bugs
//such as BB that fails to paint if the coordinates are negative.
if (rgbX < 0) {
if (rgbX + w > 0) {
if (w < rgbData.length) {
for (int i = 1; i <= rgbData.length / w; i++) {
offset = -rgbX + (w * (i - 1));
rgbY++;
if (rgbY >= 0) {
nativeGraphics.drawARGB(rgbData, offset, (w + rgbX), 0, rgbY, w + rgbX, 1);
}
}
}
}
}
}
public Object getNativeGraphics() {
return canvas.getGlobalGraphics();
}
public Object getNativeGraphics(Object image) {
return new Graphics((Bitmap) image);
}
public boolean isAntiAliasingSupported() {
return true;
}
public void setAntiAliased(Object graphics, boolean a) {
((Graphics) graphics).setDrawingStyle(Graphics.DRAWSTYLE_AALINES, a);
((Graphics) graphics).setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, a);
}
public boolean isAntiAliased(Object graphics) {
return ((Graphics) graphics).isDrawingStyleSet(Graphics.DRAWSTYLE_AALINES);
}
public boolean isAntiAliasedTextSupported() {
return false;
}
public void setAntiAliasedText(Object graphics, boolean a) {
// this method uses undocumented behavior so it won't compile on different JDE versions
/*Graphics g = (Graphics)graphics;
Font f = g.getFont();
if(a) {
if(f.getAntialiasMode() != Font.ANTIALIAS_SUBPIXEL) {
f = f.derive(f.getStyle(), f.getHeight(), Ui.UNITS_px, Font.ANTIALIAS_SUBPIXEL, f.getEffects());
g.setFont(f);
}
} else {
if(f.getAntialiasMode() == Font.ANTIALIAS_SUBPIXEL) {
f = f.derive(f.getStyle(), f.getHeight(), Ui.UNITS_px, Font.ANTIALIAS_NONE, f.getEffects());
g.setFont(f);
}
}*/
}
public boolean isAntiAliasedText(Object graphics) {
// this method uses undocumented behavior so it won't compile on different JDE versions
/*Graphics g = (Graphics)graphics;
Font f = g.getFont();
return f.getAntialiasMode() == Font.ANTIALIAS_SUBPIXEL;*/
return false;
}
public int charsWidth(Object nativeFont, char[] ch, int offset, int length) {
return font(nativeFont).getAdvance(ch, offset, length);
}
private Font font(Object nativeFont) {
if (nativeFont == null) {
return Font.getDefault();
}
return (Font) nativeFont;
}
public int stringWidth(Object nativeFont, String str) {
return font(nativeFont).getAdvance(str);
}
public int charWidth(Object nativeFont, char ch) {
return font(nativeFont).getAdvance(ch);
}
public int getHeight(Object nativeFont) {
return font(nativeFont).getHeight();
}
public int getFontAscent(Object nativeFont) {
return Math.abs(font(nativeFont).getAscent());
}
public int getFontDescent(Object nativeFont) {
return Math.abs(font(nativeFont).getDescent());
}
public boolean isBaselineTextSupported() {
return true;
}
public Object getDefaultFont() {
return Font.getDefault();
}
public int getFace(Object nativeFont) {
Font nf = (Font) font(nativeFont);
int s = nf.getStyle();
int result = 0;
if ((s & Font.BOLD) == Font.BOLD) {
result |= com.codename1.ui.Font.STYLE_BOLD;
}
if ((s & Font.ITALIC) == Font.ITALIC) {
result |= com.codename1.ui.Font.STYLE_ITALIC;
}
if ((s & Font.UNDERLINED) == Font.UNDERLINED) {
result |= com.codename1.ui.Font.STYLE_UNDERLINED;
}
return result;
}
public int getSize(Object nativeFont) {
Font nf = (Font) font(nativeFont);
int bbSize = Font.getDefault().getHeight();
int diff = Font.getDefault().getHeight() / 3;
if (nf.getHeight() == bbSize - diff) {
return com.codename1.ui.Font.SIZE_SMALL;
}
if (nf.getHeight() == bbSize + diff) {
return com.codename1.ui.Font.SIZE_LARGE;
}
return com.codename1.ui.Font.SIZE_MEDIUM;
}
public int getStyle(Object nativeFont) {
Font nf = (Font) font(nativeFont);
int s = nf.getStyle();
if ((s & FontFamily.MONO_BITMAP_FONT) == FontFamily.MONO_BITMAP_FONT) {
return com.codename1.ui.Font.FACE_MONOSPACE;
}
if ((s & FontFamily.SCALABLE_FONT) == FontFamily.SCALABLE_FONT) {
return com.codename1.ui.Font.FACE_PROPORTIONAL;
}
return com.codename1.ui.Font.FACE_SYSTEM;
}
public Object createFont(int face, int style, int size) {
Font font = Font.getDefault();
int bbSize = Font.getDefault().getHeight();
int diff = Font.getDefault().getHeight() / 3;
switch (size) {
case com.codename1.ui.Font.SIZE_SMALL:
bbSize -= diff;
break;
case com.codename1.ui.Font.SIZE_LARGE:
bbSize += diff;
break;
}
int bbStyle = Font.PLAIN;
switch (style) {
case com.codename1.ui.Font.STYLE_BOLD:
bbStyle = Font.BOLD;
break;
case com.codename1.ui.Font.STYLE_ITALIC:
bbStyle = Font.ITALIC;
break;
case com.codename1.ui.Font.STYLE_PLAIN:
bbStyle = Font.PLAIN;
break;
case com.codename1.ui.Font.STYLE_UNDERLINED:
bbStyle = Font.UNDERLINED;
break;
default:
// probably bold/italic
bbStyle = Font.BOLD | Font.ITALIC;
break;
}
switch (face) {
case com.codename1.ui.Font.FACE_MONOSPACE:
font = font.getFontFamily().getFont(bbStyle | FontFamily.MONO_BITMAP_FONT, bbSize);
break;
case com.codename1.ui.Font.FACE_PROPORTIONAL:
font = font.getFontFamily().getFont(bbStyle | FontFamily.SCALABLE_FONT, bbSize);
break;
case com.codename1.ui.Font.FACE_SYSTEM:
font = font.derive(bbStyle, bbSize, Ui.UNITS_px, Font.ANTIALIAS_SUBPIXEL, font.getEffects());
break;
}
return font;
}
public boolean isNativeInputSupported() {
return true;
}
public int getKeyboardType() {
int keyT = Keypad.getHardwareLayout();
switch (keyT) {
case Keypad.HW_LAYOUT_LEGACY:
case Keypad.HW_LAYOUT_32:
case Keypad.HW_LAYOUT_39:
case Keypad.HW_LAYOUT_PHONE:
return Display.KEYBOARD_TYPE_QWERTY;
case Keypad.HW_LAYOUT_REDUCED:
case Keypad.HW_LAYOUT_REDUCED_24:
return Display.KEYBOARD_TYPE_HALF_QWERTY;
case 1230263636: // HW_LAYOUT_ITUT
return Display.KEYBOARD_TYPE_NUMERIC;
}
return Display.KEYBOARD_TYPE_QWERTY;
}
public boolean isMultiTouch() {
return canvas.isMultiTouch();
}
public boolean isClickTouchScreen() {
return canvas.isClickTouchScreen();
}
protected void pointerDragged(final int[] x, final int[] y) {
super.pointerDragged(x, y);
}
protected void pointerPressed(final int[] x, final int[] y) {
super.pointerPressed(x, y);
}
protected void pointerReleased(final int[] x, final int[] y) {
super.pointerReleased(x, y);
}
protected void pointerHover(final int[] x, final int[] y) {
super.pointerHover(x, y);
}
protected void pointerHoverPressed(final int[] x, final int[] y) {
super.pointerHoverPressed(x, y);
}
protected void pointerHoverPressed(final int x, final int y) {
super.pointerHoverPressed(x, y);
}
protected void pointerDragged(final int x, final int y) {
super.pointerDragged(x, y);
}
protected void pointerPressed(final int x, final int y) {
super.pointerPressed(x, y);
}
protected void pointerReleased(final int x, final int y) {
super.pointerReleased(x, y);
}
protected void pointerHoverReleased(final int x, final int y) {
super.pointerHoverReleased(x, y);
}
protected void pointerHoverReleased(final int[] x, final int[] y) {
super.pointerHoverReleased(x, y);
}
protected void pointerHover(final int x, final int y) {
super.pointerHover(x, y);
}
protected void sizeChanged(int w, int h) {
super.sizeChanged(w, h);
}
public boolean minimizeApplication() {
app.requestBackground();
return true;
}
public void restoreMinimizedApplication() {
app.requestForeground();
}
public boolean isThirdSoftButton() {
return false;
}
/**
* Indicates whether the application should minimize or exit when the end key is pressed
*
* @return the minimizeOnEnd
*/
public static boolean isMinimizeOnEnd() {
return minimizeOnEnd;
}
/**
* Indicates whether the application should minimize or exit when the end key is pressed
*
* @param aMinimizeOnEnd the minimizeOnEnd to set
*/
public static void setMinimizeOnEnd(boolean aMinimizeOnEnd) {
minimizeOnEnd = aMinimizeOnEnd;
}
/**
* Volume listener is invoked when the volume up/down buttons on the blackberry
* device are pressed. The key event would be either Characters.CONTROL_VOLUME_UP
* or Characters.CONTROL_VOLUME_DOWN
*
* @param al action listener callback
*/
public static void addVolumeListener(ActionListener al) {
if (volumeListener == null) {
volumeListener = new EventDispatcher();
}
volumeListener.addListener(al);
}
/**
* Remove the volume listener instance
*
* @param al action listener to remove
*/
public static void removeVolumeListener(ActionListener al) {
if (volumeListener != null) {
volumeListener.removeListener(al);
if (volumeListener.getListenerVector() == null || volumeListener.getListenerVector().size() == 0) {
volumeListener = null;
}
}
}
static EventDispatcher getVolumeListener() {
return volumeListener;
}
class FinishEditFocus implements FocusChangeListener {
public void focusChanged(Field field, int eventType) {
if (lightweightEdit != null) {
finishEdit(false);
}
}
}
class PeerFocus implements FocusChangeListener {
private Field fld;
private PeerComponent p;
PeerFocus(Field fld, PeerComponent p) {
this.fld = fld;
this.p = p;
}
public void focusChanged(Field field, int eventType) {
if (p.getNativePeer() == fld && eventType == FocusChangeListener.FOCUS_LOST) {
fld.setFocusListener(null);
nullFld.setFocus();
canvas.eventTarget = null;
canvas.repeatLastNavigation();
}
}
}
/**
* @inheritDoc
*/
public PeerComponent createNativePeer(Object nativeComponent) {
if (nativeComponent instanceof Field) {
if (nullFld == null) {
nullFld = new NullField();
nullFld.setFocusListener(new FinishEditFocus());
synchronized (UiApplication.getEventLock()) {
canvas.add(nullFld);
}
}
final Field fld = (Field) nativeComponent;
final PeerComponent peer = new PeerComponent(fld) {
public boolean isFocusable() {
if (fld != null) {
return fld.isFocusable();
}
return super.isFocusable();
}
public void setFocus(boolean b) {
if (hasFocus() == b) {
return;
}
if (b) {
canvas.eventTarget = fld;
fld.setFocusListener(new PeerFocus(fld, this));
} else {
fld.setFocusListener(null);
if (canvas.eventTarget == fld) {
canvas.eventTarget = null;
}
}
if (isInitialized()) {
InvokeLaterWrapper i = new InvokeLaterWrapper(INVOKE_AND_WAIT_setFocus);
i.val = b;
i.fld = fld;
app.invokeAndWait(i);
} else {
super.setFocus(b);
}
}
public boolean animate() {
if (fld.isDirty()) {
repaint();
}
return super.animate();
}
protected Dimension calcPreferredSize() {
InvokeLaterWrapper i = new InvokeLaterWrapper(INVOKE_AND_WAIT_calcPreferredSize);
i.dim = new Dimension();
i.fld = fld;
app.invokeAndWait(i);
return i.dim;
}
protected void onPositionSizeChange() {
InvokeLaterWrapper i = new InvokeLaterWrapper(INVOKE_LATER_dirty);
i.fld = fld;
app.invokeLater(i);
}
protected void initComponent() {
fieldComponentMap.put(fld, this);
InvokeLaterWrapper i = new InvokeLaterWrapper(INVOKE_LATER_initComponent);
i.fld = fld;
app.invokeLater(i);
setFocus(super.hasFocus());
if (hasFocus()) {
canvas.eventTarget = fld;
}
getComponentForm().registerAnimated(this);
}
protected void deinitialize() {
getComponentForm().deregisterAnimated(this);
canvas.eventTarget = null;
InvokeLaterWrapper i = new InvokeLaterWrapper(INVOKE_LATER_deinitialize);
i.fld = fld;
app.invokeLater(i);
fieldComponentMap.remove(fld);
}
};
fieldComponentMap.put(fld, peer);
return peer;
}
throw new IllegalArgumentException(nativeComponent.getClass().getName());
}
/**
* @inheritDoc
*/
public void showNativeScreen(Object nativeFullScreenPeer) {
InvokeLaterWrapper i = new InvokeLaterWrapper(INVOKE_LATER_showNativeScreen);
i.fld = (Screen) nativeFullScreenPeer;
app.invokeLater(i);
}
/**
* #######################################################################
* #######################################################################
*
* see editString() method
*/
private class EditPopup extends PopupScreen implements FocusChangeListener, Runnable {
protected final TextArea lightweightEdit;
private boolean finished = false;
private boolean cancel = false;
private String okString;
private String cancelString;
protected final BasicEditField nativeEdit;
protected EditPopup(TextArea lightweightEdit, int maxSize) {
super(new VerticalFieldManager(VerticalFieldManager.VERTICAL_SCROLL), Field.FOCUSABLE | Field.EDITABLE | Screen.DEFAULT_MENU);
UIManager m = UIManager.getInstance();
okString = m.localize("ok", "OK");
cancelString = m.localize("cancel", "Cancel");
this.lightweightEdit = lightweightEdit;
long type = 0;
int constraint = lightweightEdit.getConstraint();
if ((constraint & TextArea.DECIMAL) == TextArea.DECIMAL) {
type = BasicEditField.FILTER_REAL_NUMERIC;
} else if ((constraint & TextArea.EMAILADDR) == TextArea.EMAILADDR) {
type = BasicEditField.FILTER_EMAIL;
} else if ((constraint & TextArea.NUMERIC) == TextArea.NUMERIC) {
type = BasicEditField.FILTER_NUMERIC;
} else if ((constraint & TextArea.PHONENUMBER) == TextArea.PHONENUMBER) {
type = BasicEditField.FILTER_PHONE;
} else if ((constraint & TextArea.NON_PREDICTIVE) == TextArea.NON_PREDICTIVE) {
type = BasicEditField.NO_COMPLEX_INPUT;
}
if (lightweightEdit.isSingleLineTextArea()) {
type |= BasicEditField.NO_NEWLINE;
}
if ((constraint & TextArea.PASSWORD) == TextArea.PASSWORD) {
nativeEdit = new BBPasswordEditField(lightweightEdit, type, maxSize, 0, 0xffffff);
} else {
nativeEdit = new BBEditField(lightweightEdit, type, maxSize, 0, 0xffffff);
}
// using Field.EDITABLE flag now because of bug with DevTrack ID 354265 at
// https://www.blackberry.com/jira/browse/JAVAAPI-101
//nativeEdit.setEditable(true);
net.rim.device.api.ui.Font f = nativeEdit.getFont();
if (f.getHeight() > lightweightEdit.getStyle().getFont().getHeight()) {
nativeEdit.setFont(f.derive(f.getStyle(),
lightweightEdit.getStyle().getFont().getHeight()));
}
add(nativeEdit);
nativeEdit.setFocus();
nativeEdit.setFocusListener(this);
}
protected void makeMenu(Menu menu, int arg1) {
menu.add(new MenuItem(okString, 0, 99) {
public void run() {
finishEdit();
}
});
menu.add(new MenuItem(cancelString, 1, 100) {
public void run() {
EditPopup.this.cancel = true;
finishEdit();
}
});
super.makeMenu(menu, arg1);
}
protected void onMenuDismissed(Menu arg0) {
super.onMenuDismissed(arg0);
/**
* at this point the EDT is still blocked, so we repaint the
* screen with our old buffer and request some fresh paint
* for the textfield.
*/
this.invalidate();
}
protected void onExposed() {
super.onExposed();
/**
* we reach this if the context menu opened another dialog
* on top.
*
* at this point the EDT is still blocked, so we repaint the
* screen with our old buffer and request some fresh paint
* for the textfield.
*/
this.invalidate();
}
protected boolean keyDown(int keycode, int time) {
if (Keypad.key(keycode) == Keypad.KEY_ESCAPE) {
this.cancel = true;
finishEdit();
return true;
}
if (Keypad.key(keycode) == Keypad.KEY_ENTER) {
/**
* single line text field accept input.
*/
if (this.lightweightEdit.isSingleLineTextArea()) {
finishEdit();
return true;
}
}
return super.keyDown(keycode, time);
}
public void focusChanged(Field field, int type) {
if (field == this.nativeEdit && type == FOCUS_LOST) {
finishEdit();
}
}
protected void startEdit() {
BlackBerryImplementation.this.app.invokeAndWait(this);
}
public void run() {
UiApplication.getUiApplication().pushScreen(this);
}
protected void finishEdit() {
if (this.finished) {
return;
}
this.finished = true;
if (!this.cancel) {
Display.getInstance().onEditingComplete(lightweightEdit, nativeEdit.getText());
}
if (isTouchDevice()) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Display.getInstance().setShowVirtualKeyboard(false);
}
});
}
UiApplication.getUiApplication().popScreen(this);
}
}
/**
* #######################################################################
* #######################################################################
*
* see editString() method
*/
private class BBEditField extends ActiveAutoTextEditField {
private TextArea lightweightEdit = null;
private NativeEditCallback callback = new NativeEditCallback();
private int bgColor;
private int fgColor;
public BBEditField(TextArea lightweightEdit, long type, int maxSize, int fgColor, int bgColor) {
this(lightweightEdit, type, maxSize);
this.fgColor = fgColor;
this.bgColor = bgColor;
}
public BBEditField(TextArea lightweightEdit, long type, int maxSize) {
super("", lightweightEdit.getText(), maxSize, Field.EDITABLE | Field.FOCUSABLE | Field.SPELLCHECKABLE | type);
this.lightweightEdit = lightweightEdit;
this.fgColor = lightweightEdit.getSelectedStyle().getFgColor();
this.bgColor = lightweightEdit.getSelectedStyle().getBgColor();
}
public void paintBackground(net.rim.device.api.ui.Graphics g) {
int originalBGColor = g.getBackgroundColor();
int originalColor = g.getColor();
g.setBackgroundColor(bgColor);
g.setColor(bgColor);
super.paintBackground(g);
g.setColor(bgColor);
g.fillRect(0, 0, this.getWidth(),
this.getHeight());
g.setBackgroundColor(originalBGColor);
g.setColor(originalColor);
}
public void paint(net.rim.device.api.ui.Graphics g) {
int originalBGColor = g.getBackgroundColor();
int originalColor = g.getColor();
g.setBackgroundColor(bgColor);
g.setColor(fgColor);
super.paint(g);
g.setBackgroundColor(originalBGColor);
g.setColor(originalColor);
}
protected boolean keyDown(int keycode, int time) {
if (Keypad.key(keycode) == Keypad.KEY_ESCAPE) {
finishEdit(true);
return true;
}
if (Keypad.key(keycode) == Keypad.KEY_ENTER) {
if (lightweightEdit.isSingleLineTextArea()) {
finishEdit(false);
return true;
}
}
return super.keyDown(keycode, time);
}
protected boolean keyUp(int keycode, int time) {
boolean b = super.keyUp(keycode, time);
callback.onChanged();
return b;
}
protected boolean navigationMovement(int dx, int dy, int status, int time) {
boolean b = super.navigationMovement(dx, dy, status, time);
callback.onChanged();
return b;
}
protected void update(int i) {
super.update(i);
lightweightEdit.setText(getText());
callback.onChanged();
}
}
public static char passwordChar = '\u25CF';
private static String getPasswordsChars(String text){
String retVal = "";
for (int i = 0; i < text.length(); i++) {
retVal += passwordChar;
}
return retVal;
}
/**
* #######################################################################
* #######################################################################
*
* see editString() method
*/
private class BBPasswordEditField extends net.rim.device.api.ui.component.EditField {
private TextArea lightweightEdit = null;
private NativeEditCallback callback = new NativeEditCallback();
private int bgColor;
private int fgColor;
public BBPasswordEditField(TextArea lightweightEdit, long type, int maxSize, int fgColor, int bgColor) {
this(lightweightEdit, type, maxSize);
this.fgColor = fgColor;
this.bgColor = bgColor;
}
public BBPasswordEditField(TextArea lightweightEdit, long type, int maxSize) {
super("", lightweightEdit.getText(), maxSize, NO_COMPLEX_INPUT | Field.EDITABLE | Field.FOCUSABLE | type);
this.lightweightEdit = lightweightEdit;
this.fgColor = lightweightEdit.getSelectedStyle().getFgColor();
this.bgColor = lightweightEdit.getSelectedStyle().getBgColor();
}
public void paintBackground(net.rim.device.api.ui.Graphics g) {
int originalBGColor = g.getBackgroundColor();
int originalColor = g.getColor();
g.setBackgroundColor(bgColor);
g.setColor(bgColor);
super.paintBackground(g);
g.setColor(bgColor);
g.fillRect(0, 0, this.getWidth(),
this.getHeight());
g.setBackgroundColor(originalBGColor);
g.setColor(originalColor);
}
public void paint(net.rim.device.api.ui.Graphics g) {
int originalBGColor = g.getBackgroundColor();
int originalColor = g.getColor();
g.setBackgroundColor(bgColor);
g.setColor(fgColor);
g.drawText(getPasswordsChars(super.getText()), 0, 0);
g.setBackgroundColor(originalBGColor);
g.setColor(originalColor);
}
protected boolean keyDown(int keycode, int time) {
if (Keypad.key(keycode) == Keypad.KEY_ESCAPE) {
finishEdit(true);
return true;
}
if (Keypad.key(keycode) == Keypad.KEY_ENTER) {
if (lightweightEdit.isSingleLineTextArea()) {
finishEdit(false);
return true;
}
}
return super.keyDown(keycode, time);
}
protected boolean keyUp(int keycode, int time) {
boolean b = super.keyUp(keycode, time);
callback.onChanged();
return b;
}
protected boolean navigationMovement(int dx, int dy, int status, int time) {
boolean b = super.navigationMovement(dx, dy, status, time);
callback.onChanged();
return b;
}
protected void update(int delta) {
super.update(delta);
lightweightEdit.setText(getText());
callback.onChanged();
}
}
class NativeEditCallback implements Runnable {
private String text;
private int cursorLocation;
public void onChanged() {
if (nativeEdit != null) {
text = nativeEdit.getText();
cursorLocation = nativeEdit.getCursorPosition();
Display.getInstance().callSerially(this);
}
}
public void run() {
// prevent a race condition by copying the global scope
TextArea t = lightweightEdit;
if (t != null) {
Dimension d = t.getPreferredSize();
t.setText(text);
Dimension current = t.getPreferredSize();
Form f = t.getComponentForm();
// allows the lightweight text area to grow to fill up the screen
if (d.getHeight() != current.getHeight() || d.getWidth() != current.getWidth()) {
f.getComponentForm().revalidate();
}
int currentLineLength = 0;
int numOfChars = 0;
int currentY = 0;
while (numOfChars <= cursorLocation && currentY < t.getLines()) {
String currentLine = t.getTextAt(currentY);
currentLineLength = currentLine.length();
if (numOfChars + currentLineLength < text.length()
&& (text.charAt(numOfChars + currentLineLength) == '\n'
|| text.charAt(numOfChars + currentLineLength) == ' ')) {
currentLineLength++;
}
numOfChars += currentLineLength;
currentY++;
}
int cursorY = Math.max(0, currentY - 1);
com.codename1.ui.Font textFont = t.getStyle().getFont();
int rowsGap = t.getRowsGap();
int lineHeight = textFont.getHeight() + rowsGap;
t.scrollRectToVisible(t.getScrollX(), cursorY * lineHeight, t.getWidth(), lineHeight, t);
app.invokeLater(new Runnable() {
public void run() {
canvas.updateRIMLayout();
}
});
}
}
}
protected int getFieldWidth(Field fld) {
return Math.max(fld.getWidth(), fld.getPreferredWidth());
}
protected int getFieldHeight(Field fld) {
return Math.max(fld.getHeight(), fld.getPreferredHeight());
}
/**
* This class is here to unify multiple invocations of invoke later
*/
class InvokeLaterWrapper implements Runnable {
public Field fld;
public Dimension dim;
public boolean val;
private int i;
public Player v;
public InvokeLaterWrapper(int i) {
this.i = i;
}
public void run() {
try {
switch (i) {
case INVOKE_LATER_confirmControlView:
if (app.getActiveScreen() != canvas) {
app.pushScreen(canvas);
}
break;
case INVOKE_LATER_finishEdit:
finishEdit(val);
break;
case INVOKE_LATER_initComponent:
canvas.add(fld);
break;
case INVOKE_LATER_deinitialize:
canvas.delete(fld);
break;
case INVOKE_LATER_showNativeScreen:
if (app.getActiveScreen() != fld) {
app.pushScreen((Screen) fld);
}
break;
case INVOKE_AND_WAIT_calcPreferredSize:
dim.setWidth(getFieldWidth(fld));
dim.setHeight(getFieldHeight(fld));
break;
case INVOKE_AND_WAIT_setFocus:
try {
// Not sure why an exception is thrown here during a touch event...
if (val) {
fld.setFocus();
} else {
nullFld.setFocus();
}
} catch (Throwable t) {
//t.printStackTrace();
}
break;
case INVOKE_LATER_dirty:
if (fld.getScreen() == canvas) {
fld.setDirty(true);
canvas.updateRIMLayout();
}
break;
case INVOKE_LATER_startMedia:
try {
v.start();
} catch (MediaException ex) {
ex.printStackTrace();
}
break;
}
} catch (Exception e) {
}
}
}
public void execute(String url) {
app.setWaitingForReply(true);
// requires signing
net.rim.blackberry.api.browser.BrowserSession browserSession = net.rim.blackberry.api.browser.Browser.getDefaultSession();
browserSession.displayPage(url);
browserSession.showBrowser();
}
public void exitApplication() {
System.exit(0);
}
public String getProperty(String key, String defaultValue) {
String val = null;
if ("OS".equals(key)) {
return "RIM";
}
if("encodedImageScaling".equals(key)) {
return "false";
}
if ("IMEI".equals(key)) {
if(RadioInfo.getNetworkType() == RadioInfo.NETWORK_CDMA) {
// Do something specific for CDMA
return new String(CDMAInfo.getIMSI());
}else{
return GPRSInfo.imeiToString(GPRSInfo.getIMEI());
}
}
//requires signing
if ("MSISDN".equals(key)) {
return Phone.getDevicePhoneNumber(true);
}
if ("AppVersion".equals(key)) {
return ApplicationDescriptor.currentApplicationDescriptor().getVersion();
}
if("AppName".equals(key)) {
return ApplicationDescriptor.currentApplicationDescriptor().getName();
}
if (initGetProperty) {
initGetProperty = false;
ApplicationDescriptor ad = ApplicationDescriptor.currentApplicationDescriptor();
if (ad != null) {
String moduleName = ad.getModuleName();
if (moduleName != null) {
CodeModuleGroup[] allGroups = CodeModuleGroupManager.loadAll();
if (allGroups != null) {
for (int i = 0; i < allGroups.length; i++) {
if (allGroups[i].containsModule(moduleName)) {
group = allGroups[i];
break;
}
}
}
}
}
}
if (group != null) {
val = group.getProperty(key);
}
if (val == null) {
return defaultValue;
}
return val;
}
/**
* @inheritDoc
*/
public void playBuiltinSound(String soundIdentifier) {
if (!playUserSound(soundIdentifier)) {
// todo...
}
}
/**
* @inheritDoc
*/
protected void playNativeBuiltinSound(Object data) {
try {
try {
Media m = createMedia(new ByteArrayInputStream((byte[]) data), "audio/mpeg", null);
m.play();
} catch (Exception err) {
// some simulators take issue with the audio/mpeg string but the mp3 string
// works fine
Media m = createMedia(new ByteArrayInputStream((byte[]) data), "audio/mp3", null);
m.play();
}
} catch (IOException ex) {
// not likely since the stream is a byte array input stream
ex.printStackTrace();
}
}
/**
* @inheritDoc
*/
public boolean isBuiltinSoundAvailable(String soundIdentifier) {
if (soundIdentifier.equals(Display.SOUND_TYPE_ALARM)) {
return true;
}
if (soundIdentifier.equals(Display.SOUND_TYPE_CONFIRMATION)) {
return true;
}
if (soundIdentifier.equals(Display.SOUND_TYPE_ERROR)) {
return true;
}
if (soundIdentifier.equals(Display.SOUND_TYPE_INFO)) {
return true;
}
if (soundIdentifier.equals(Display.SOUND_TYPE_WARNING)) {
return true;
}
return super.isBuiltinSoundAvailable(soundIdentifier);
}
private boolean testedNativeTheme;
private boolean nativeThemeAvailable;
public boolean hasNativeTheme() {
if (!testedNativeTheme) {
testedNativeTheme = true;
try {
InputStream is = getResourceAsStream(getClass(), "/blackberry_theme.res");
nativeThemeAvailable = is != null;
if (is != null) {
is.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return nativeThemeAvailable;
}
/**
* Installs the native theme, this is only applicable if hasNativeTheme() returned true. Notice that this method
* might replace the DefaultLookAndFeel instance and the default transitions.
*/
public void installNativeTheme() {
if (nativeThemeAvailable) {
try {
InputStream is = getResourceAsStream(getClass(), "/blackberry_theme.res");
Resources r = Resources.open(is);
UIManager.getInstance().setThemeProps(r.getTheme(r.getThemeResourceNames()[0]));
is.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
/**
* @inheritDoc
*/
public boolean isAPSupported() {
return true;
}
private Vector getValidSBEntries() {
Vector v = new Vector();
ServiceBook bk = ServiceBook.getSB();
ServiceRecord[] recs = bk.getRecords();
for (int iter = 0; iter < recs.length; iter++) {
ServiceRecord sr = recs[iter];
if (sr.isValid() && !sr.isDisabled() && sr.getUid() != null
&& sr.getUid().length() != 0) {
v.addElement(sr);
}
}
return v;
}
/**
* @inheritDoc
*/
public String[] getAPIds() {
Vector v = getValidSBEntries();
String[] s = new String[v.size()];
for (int iter = 0; iter < s.length; iter++) {
s[iter] = "" + ((ServiceRecord) v.elementAt(iter)).getUid();
}
return s;
}
/**
* @inheritDoc
*/
public int getAPType(String id) {
Vector v = getValidSBEntries();
for (int iter = 0; iter < v.size(); iter++) {
ServiceRecord r = (ServiceRecord) v.elementAt(iter);
if (("" + r.getUid()).equals(id)) {
if (r.getUid().toLowerCase().indexOf("wifi") > -1) {
return NetworkManager.ACCESS_POINT_TYPE_WLAN;
}
// wap2
if (r.getCid().toLowerCase().indexOf("wptcp") > -1) {
return NetworkManager.ACCESS_POINT_TYPE_NETWORK3G;
}
return NetworkManager.ACCESS_POINT_TYPE_UNKNOWN;
}
}
return NetworkManager.ACCESS_POINT_TYPE_UNKNOWN;
}
/**
* @inheritDoc
*/
public String getAPName(String id) {
Vector v = getValidSBEntries();
for (int iter = 0; iter < v.size(); iter++) {
ServiceRecord r = (ServiceRecord) v.elementAt(iter);
if (("" + r.getUid()).equals(id)) {
return r.getName();
}
}
return null;
}
/**
* @inheritDoc
*/
public String getCurrentAccessPoint() {
if (currentAccessPoint != null) {
return currentAccessPoint;
}
return null;
}
/**
* @inheritDoc
*/
public void setCurrentAccessPoint(String id) {
currentAccessPoint = id;
int t = getAPType(id);
deviceSide = t == NetworkManager.ACCESS_POINT_TYPE_NETWORK3G ||
t == NetworkManager.ACCESS_POINT_TYPE_NETWORK2G ||
t == NetworkManager.ACCESS_POINT_TYPE_WLAN;
}
/**
* @inheritDoc
*/
public boolean shouldAutoDetectAccessPoint() {
return false;
}
/**
* @inheritDoc
*/
public Object connect(String url, boolean read, boolean write) throws IOException {
if (currentAccessPoint != null) {
url += ";ConnectionUID=" + currentAccessPoint;
if (deviceSide) {
url += ";deviceside=true";
}
} else {
URLFactory uu = new URLFactory(url);
TransportDetective td = new TransportDetective();
int tr = td.getBestTransportForActiveCoverage();
switch(tr) {
case TransportDetective.TRANSPORT_TCP_WIFI:
url = uu.getHttpTcpWiFiUrl();
break;
case TransportDetective.TRANSPORT_MDS:
url = uu.getHttpMdsUrl(false);
break;
case TransportDetective.TRANSPORT_BIS_B:
url = uu.getHttpBisUrl();
break;
case TransportDetective.TCP_CELLULAR_APN_SERVICE_BOOK:
case TransportDetective.TRANSPORT_TCP_CELLULAR:
url = uu.getHttpTcpCellularUrl(null, null, null);
break;
}
}
return connectImpl(url, read, write);
}
private Object connectImpl(String url, boolean read, boolean write) throws IOException {
//BB known bug http://www.coderholic.com/blackberry-os-45-connection-not-writeable-error/
//Connections must be read and write
return Connector.open(url, Connector.READ_WRITE);
}
/**
* @inheritDoc
*/
public void setHeader(Object connection, String key, String val) {
try {
((HttpConnection) connection).setRequestProperty(key, val);
} catch (IOException err) {
// this exception doesn't make sense since at this point no connection is in place
err.printStackTrace();
}
}
/**
* @inheritDoc
*/
public int getContentLength(Object connection) {
return (int) ((HttpConnection) connection).getLength();
}
/**
* @inheritDoc
*/
public void cleanup(Object o) {
try {
if (o != null) {
if (o instanceof Connection) {
((Connection) o).close();
return;
}
if (o instanceof RecordEnumeration) {
((RecordEnumeration) o).destroy();
return;
}
if (o instanceof RecordStore) {
((RecordStore) o).closeRecordStore();
return;
}
super.cleanup(o);
}
} catch (Throwable ex) {
ex.printStackTrace();
}
}
/**
* @inheritDoc
*/
public OutputStream openOutputStream(Object connection) throws IOException {
if (connection instanceof String) {
FileConnection fc = (FileConnection) Connector.open((String) connection, Connector.READ_WRITE);
if (!fc.exists()) {
fc.create();
}
BufferedOutputStream o = new BufferedOutputStream(fc.openOutputStream(), (String) connection);
o.setConnection(fc);
return o;
}
OutputStream os = new BlackBerryOutputStream(((HttpConnection) connection).openOutputStream());
return new BufferedOutputStream(os, ((HttpConnection) connection).getURL());
}
/**
* @inheritDoc
*/
public OutputStream openOutputStream(Object connection, int offset) throws IOException {
FileConnection fc = (FileConnection) Connector.open((String) connection, Connector.READ_WRITE);
if (!fc.exists()) {
fc.create();
}
BufferedOutputStream o = new BufferedOutputStream(fc.openOutputStream(offset), (String) connection);
o.setConnection(fc);
return o;
}
/**
* @inheritDoc
*/
public InputStream openInputStream(Object connection) throws IOException {
if (connection instanceof String) {
FileConnection fc = (FileConnection) Connector.open((String) connection, Connector.READ);
BufferedInputStream o = new BufferedInputStream(fc.openInputStream(), (String) connection);
o.setConnection(fc);
return o;
}
return new BufferedInputStream(((HttpConnection) connection).openInputStream(), ((HttpConnection) connection).getURL());
}
/**
* @inheritDoc
*/
public void setHttpMethod(Object connection, String method) throws IOException {
((HttpConnection)connection).setRequestMethod(method);
}
/**
* @inheritDoc
*/
public void setPostRequest(Object connection, boolean p) {
try {
if (p) {
((HttpConnection) connection).setRequestMethod(HttpConnection.POST);
} else {
((HttpConnection) connection).setRequestMethod(HttpConnection.GET);
}
} catch (IOException err) {
// an exception here doesn't make sense
err.printStackTrace();
}
}
/**
* @inheritDoc
*/
public int getResponseCode(Object connection) throws IOException {
return ((HttpConnection) connection).getResponseCode();
}
/**
* @inheritDoc
*/
public String getResponseMessage(Object connection) throws IOException {
return ((HttpConnection) connection).getResponseMessage();
}
/**
* @inheritDoc
*/
public String getHeaderField(String name, Object connection) throws IOException {
return ((HttpConnection) connection).getHeaderField(name);
}
/**
* @inheritDoc
*/
public String[] getHeaderFieldNames(Object connection) throws IOException {
HttpConnection c = (HttpConnection)connection;
Vector r = new Vector();
int i = 0;
String key = c.getHeaderFieldKey(i);
while (key != null) {
if(r.indexOf(key) < 0) {
r.addElement(key);
}
i++;
key = c.getHeaderFieldKey(i);
}
if(r.size() == 0) {
return null;
}
String[] response = new String[r.size()];
for(int iter = 0 ; iter < response.length ; iter++) {
response[iter] = (String)r.elementAt(iter);
}
return response;
}
/**
* @inheritDoc
*/
public String[] getHeaderFields(String name, Object connection) throws IOException {
HttpConnection c = (HttpConnection) connection;
Vector r = new Vector();
int i = 0;
while (c.getHeaderFieldKey(i) != null) {
if (c.getHeaderFieldKey(i).equalsIgnoreCase(name)) {
String val = c.getHeaderField(i);
r.addElement(val);
}
i++;
}
if (r.size() == 0) {
return null;
}
String[] response = new String[r.size()];
for (int iter = 0; iter < response.length; iter++) {
response[iter] = (String) r.elementAt(iter);
}
return response;
}
/**
* @inheritDoc
*/
public void deleteStorageFile(String name) {
Short key = (Short) fat.get(name);
fat.remove(name);
resaveFat();
if (key != null) {
try {
for (char c = 'A'; c < 'Z'; c++) {
RecordStore.deleteRecordStore("" + c + key);
}
} catch (RecordStoreException e) {
}
}
}
private void resaveFat() {
RecordStore r = null;
RecordEnumeration e = null;
try {
r = RecordStore.openRecordStore("FAT", true);
Vector keys = new Vector();
Enumeration fatKeys = fat.keys();
while (fatKeys.hasMoreElements()) {
keys.addElement(fatKeys.nextElement());
}
e = r.enumerateRecords(null, null, false);
while (e.hasNextElement()) {
int recordId = e.nextRecordId();
byte[] rec = r.getRecord(recordId);
ByteArrayInputStream bi = new ByteArrayInputStream(rec);
DataInputStream di = new DataInputStream(bi);
String name = di.readUTF();
short key = di.readShort();
di.close();
bi.close();
Short fatKey = (Short) fat.get(name);
if (fatKey == null) {
// we need to remove this record...
r.deleteRecord(recordId);
} else {
// we need to update the record
if (fatKey.shortValue() != key) {
byte[] bd = toRecord(name, fatKey.shortValue());
r.setRecord(recordId, bd, 0, bd.length);
}
}
keys.removeElement(name);
}
e.destroy();
e = null;
Enumeration remainingKeys = keys.elements();
while (remainingKeys.hasMoreElements()) {
String name = (String) remainingKeys.nextElement();
Short key = (Short) fat.get(name);
byte[] bd = toRecord(name, key.shortValue());
r.addRecord(bd, 0, bd.length);
}
r.closeRecordStore();
} catch (Exception err) {
// This might be a valid exception and some platforms (e..g. RIM) don't respond well to PST
//err.printStackTrace();
cleanup(e);
cleanup(r);
}
}
private byte[] toRecord(String name, short key) throws IOException {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
DataOutputStream d = new DataOutputStream(bo);
d.writeUTF(name);
d.writeShort(key);
d.close();
bo.close();
return bo.toByteArray();
}
/**
* @inheritDoc
*/
public OutputStream openFileOutputStream(String file) throws IOException {
return openOutputStream(file);
}
/**
* @inheritDoc
*/
public InputStream openFileInputStream(String file) throws IOException {
return openInputStream(file);
}
private class RMSOutputStream extends OutputStream {
private short key;
private char letter = 'A';
private ByteArrayOutputStream cache;
private int offset;
public RMSOutputStream(short key) {
this.key = key;
// first we need to cleanup existing files
try {
for (char c = 'A'; c < 'Z'; c++) {
RecordStore.deleteRecordStore("" + c + key);
}
} catch (RecordStoreException e) {
}
cache = new ByteArrayOutputStream();
}
public void close() throws IOException {
flush();
cache = null;
}
public void flush() throws IOException {
if (cache != null) {
byte[] data = cache.toByteArray();
if (data.length > 0) {
RecordStore r = null;
try {
r = RecordStore.openRecordStore("" + letter + key, true);
r.addRecord(data, 0, data.length);
r.closeRecordStore();
if (letter == 'Z') {
letter = 'a';
} else {
letter++;
}
cache.reset();
} catch (RecordStoreException ex) {
ex.printStackTrace();
cleanup(r);
throw new IOException(ex.toString());
}
}
}
}
public void write(byte[] arg0) throws IOException {
cache.write(arg0);
if (cache.size() > 32536) {
flush();
}
}
public void write(byte[] arg0, int arg1, int arg2) throws IOException {
cache.write(arg0, arg1, arg2);
if (cache.size() > 32536) {
flush();
}
}
public void write(int arg0) throws IOException {
cache.write(arg0);
if (cache.size() > 32536) {
flush();
}
}
}
private class RMSInputStream extends InputStream {
private InputStream current;
private int offset;
private short key;
public RMSInputStream(short key) throws IOException {
this.key = key;
RecordStore r = null;
RecordEnumeration e = null;
char letter = 'A';
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
r = open("" + letter + key);
while (r != null) {
e = r.enumerateRecords(null, null, false);
while (e.hasNextElement()) {
byte[] data = e.nextRecord();
os.write(data);
}
e.destroy();
r.closeRecordStore();
letter++;
r = open("" + letter + key);
if (letter == 'Z') {
letter = 'a' - ((char) 1);
}
}
os.close();
current = new ByteArrayInputStream(os.toByteArray());
} catch (RecordStoreException ex) {
ex.printStackTrace();
cleanup(r);
cleanup(e);
throw new IOException(ex.toString());
}
}
private RecordStore open(String s) {
try {
return RecordStore.openRecordStore(s, false);
} catch (RecordStoreException ex) {
return null;
}
}
public long skip(long n) throws IOException {
return super.skip(n);
}
public void close() throws IOException {
current.close();
}
public int read(byte[] arg0) throws IOException {
int r = current.read(arg0);
offset += r;
return r;
}
public int read(byte[] arg0, int arg1, int arg2) throws IOException {
int r = current.read(arg0, arg1, arg2);
offset += r;
return r;
}
public int read() throws IOException {
offset++;
return current.read();
}
}
/**
* @inheritDoc
*/
public OutputStream createStorageOutputStream(String name) throws IOException {
RecordStore r = null;
RMSOutputStream os = null;
DataOutputStream out = null;
try {
Short key = (Short) fat.get(name);
if (key == null) {
// need to add a key to the FAT
key = new Short(currentKey);
fat.put(name, key);
r = RecordStore.openRecordStore("FAT", true);
byte[] data = toRecord(name, currentKey);
currentKey++;
r.addRecord(data, 0, data.length);
r.closeRecordStore();
r = null;
}
os = new RMSOutputStream(key.shortValue());
return os;
} catch (Exception err) {
cleanup(r);
cleanup(os);
cleanup(out);
throw new IOException(err.getMessage());
}
}
/**
* @inheritDoc
*/
public InputStream createStorageInputStream(String name) throws IOException {
Short key = (Short) fat.get(name);
if (key == null) {
return null;
}
try {
return new RMSInputStream(key.shortValue());
} catch (Exception err) {
err.printStackTrace();
}
return null;
}
/**
* @inheritDoc
*/
public boolean storageFileExists(String name) {
if (name == null) {
return false;
}
return fat.containsKey(name);
}
/**
* @inheritDoc
*/
public String[] listStorageEntries() {
String[] a = new String[fat.size()];
Enumeration e = fat.keys();
int i = 0;
while (e.hasMoreElements()) {
a[i] = (String) e.nextElement();
i++;
}
return a;
}
/**
* @inheritDoc
*/
public String[] listFilesystemRoots() {
String[] res = enumToStringArr(FileSystemRegistry.listRoots());
for (int iter = 0; iter < res.length; iter++) {
res[iter] = "file:///" + res[iter];
}
return res;
}
private String[] enumToStringArr(Enumeration e) {
Vector v = new Vector();
while (e.hasMoreElements()) {
v.addElement(e.nextElement());
}
String[] response = new String[v.size()];
for (int iter = 0; iter < response.length; iter++) {
response[iter] = (String) v.elementAt(iter);
}
return response;
}
/**
* @inheritDoc
*/
public String[] listFiles(String directory) throws IOException {
FileConnection fc = null;
try {
fc = (FileConnection) Connector.open(directory, Connector.READ);
return enumToStringArr(fc.list());
} finally {
cleanup(fc);
}
}
/**
* @inheritDoc
*/
public long getRootSizeBytes(String root) {
FileConnection fc = null;
try {
fc = (FileConnection) Connector.open(root, Connector.READ);
return fc.totalSize();
} catch (IOException err) {
err.printStackTrace();
return -1;
} finally {
cleanup(fc);
}
}
/**
* @inheritDoc
*/
public long getRootAvailableSpace(String root) {
FileConnection fc = null;
try {
fc = (FileConnection) Connector.open(root, Connector.READ);
return fc.availableSize();
} catch (IOException err) {
err.printStackTrace();
return -1;
} finally {
cleanup(fc);
}
}
/**
* @inheritDoc
*/
public void mkdir(String directory) {
FileConnection fc = null;
try {
if(!directory.endsWith("/")) {
directory += "/";
}
fc = (FileConnection) Connector.open(directory, Connector.READ_WRITE);
fc.mkdir();
} catch (IOException err) {
err.printStackTrace();
} finally {
cleanup(fc);
}
}
/**
* @inheritDoc
*/
public void deleteFile(String file) {
FileConnection fc = null;
try {
fc = (FileConnection) Connector.open(file, Connector.WRITE);
fc.delete();
} catch (IOException err) {
err.printStackTrace();
} finally {
cleanup(fc);
}
}
/**
* @inheritDoc
*/
public boolean isHidden(String file) {
FileConnection fc = null;
try {
fc = (FileConnection) Connector.open(file, Connector.READ);
return fc.isHidden();
} catch (IOException err) {
err.printStackTrace();
return false;
} finally {
cleanup(fc);
}
}
/**
* @inheritDoc
*/
public void setHidden(String file, boolean h) {
FileConnection fc = null;
try {
fc = (FileConnection) Connector.open(file, Connector.READ_WRITE);
fc.setHidden(h);
} catch (IOException err) {
err.printStackTrace();
} finally {
cleanup(fc);
}
}
/**
* @inheritDoc
*/
public long getFileLength(String file) {
FileConnection fc = null;
try {
fc = (FileConnection) Connector.open(file, Connector.READ);
return fc.fileSize();
} catch (IOException err) {
err.printStackTrace();
return -1;
} finally {
cleanup(fc);
}
}
/**
* @inheritDoc
*/
public long getFileLastModified(String file) {
FileConnection fc = null;
try {
fc = (FileConnection) Connector.open(file, Connector.READ);
return fc.lastModified();
} catch (IOException err) {
err.printStackTrace();
return -1;
} finally {
cleanup(fc);
}
}
/**
* @inheritDoc
*/
public boolean isDirectory(String file) {
FileConnection fc = null;
try {
fc = (FileConnection) Connector.open(file, Connector.READ);
return fc.isDirectory();
} catch (IOException err) {
err.printStackTrace();
return false;
} finally {
cleanup(fc);
}
}
/**
* @inheritDoc
*/
public char getFileSystemSeparator() {
return '/';
}
/**
* @inheritDoc
*/
public boolean exists(String file) {
FileConnection fc = null;
try {
fc = (FileConnection) Connector.open(file, Connector.READ);
return fc.exists();
} catch (IOException err) {
err.printStackTrace();
return false;
} finally {
cleanup(fc);
}
}
/**
* @inheritDoc
*/
public void rename(String file, String newName) {
FileConnection fc = null;
try {
fc = (FileConnection) Connector.open(file, Connector.READ_WRITE);
fc.rename(newName);
} catch (IOException err) {
err.printStackTrace();
} finally {
cleanup(fc);
}
}
public void capturePhoto(ActionListener response) {
EventLog.getInstance().logInformationEvent("capturePhoto");
captureCallback = new EventDispatcher();
captureCallback.addListener(response);
UiApplication.getUiApplication().addFileSystemJournalListener(new FileSystemJournalListener() {
private long lastUSN;
public void fileJournalChanged() {
long USN = FileSystemJournal.getNextUSN();
for (long i = USN - 1; i >= lastUSN; --i) {
FileSystemJournalEntry entry = FileSystemJournal.getEntry(i);
if (entry != null) {
if (entry.getEvent() == FileSystemJournalEntry.FILE_ADDED) {
if (entry.getPath().indexOf(".jpg") != -1) {
lastUSN = USN;
String path = entry.getPath();
//close the camera
UiApplication.getUiApplication().removeFileSystemJournalListener(this);
try {
EventInjector.KeyEvent inject = new EventInjector.KeyEvent(EventInjector.KeyEvent.KEY_DOWN, Characters.ESCAPE, 0, 200);
inject.post();
inject.post();
} catch (Exception e) {
//try to close the camera
}
EventLog.getInstance().logInformationEvent("path " + path);
captureCallback.fireActionEvent(new ActionEvent("file://" + path));
captureCallback = null;
}
}
}
}
lastUSN = USN;
}
});
app.setWaitingForReply(true);
synchronized (UiApplication.getEventLock()) {
Invoke.invokeApplication(Invoke.APP_TYPE_CAMERA, new CameraArguments());
}
}
public void captureVideo(ActionListener response) {
throw new RuntimeException("capture video is supported on RIM OS 5.0 and up");
}
public void captureAudio(ActionListener response) {
int h = CodeModuleManager.getModuleHandle("net_rim_bb_voicenotesrecorder");
if (h == 0) {
throw new RuntimeException("capture audio works only if Voice Notes is installed");
}
captureCallback = new EventDispatcher();
captureCallback.addListener(response);
UiApplication.getUiApplication().addFileSystemJournalListener(new FileSystemJournalListener() {
private long lastUSN;
public void fileJournalChanged() {
long USN = FileSystemJournal.getNextUSN();
for (long i = USN - 1; i >= lastUSN; --i) {
FileSystemJournalEntry entry = FileSystemJournal.getEntry(i);
if (entry != null) {
String path = entry.getPath();
if (entry.getEvent() == FileSystemJournalEntry.FILE_ADDED
&& path.endsWith(".amr")) {
UiApplication.getUiApplication().removeFileSystemJournalListener(this);
try {
EventInjector.KeyEvent inject = new EventInjector.KeyEvent(EventInjector.KeyEvent.KEY_DOWN, Characters.ESCAPE, 0, 200);
inject.post();
} catch (Exception e) {
//try to close the voicenotesrecorder
}
captureCallback.fireActionEvent(new ActionEvent("file://" + path));
captureCallback = null;
break;
}
}
}
lastUSN = USN;
}
});
app.setWaitingForReply(true);
ApplicationDescriptor desc = new ApplicationDescriptor(CodeModuleManager.getApplicationDescriptors(h)[0], null);
try {
ApplicationManager.getApplicationManager().runApplication(desc, true);
} catch (ApplicationManagerException e) {
EventLog.getInstance().logErrorEvent("err " + e.getMessage());
e.printStackTrace();
}
}
public void sendMessage(String[] recipients, String subject, Message msg) {
Folder folders[] = Session.getDefaultInstance().getStore().list(Folder.SENT);
net.rim.blackberry.api.mail.Message message = new net.rim.blackberry.api.mail.Message(folders[0]);
try {
Address toAdds[] = new Address[recipients.length];
for (int i = 0; i < recipients.length; i++) {
Address address = new Address(recipients[i], "");
toAdds[i] = address;
}
message.addRecipients(net.rim.blackberry.api.mail.Message.RecipientType.TO, toAdds);
message.setSubject(subject);
} catch (Exception e) {
EventLog.getInstance().logErrorEvent("err " + e.getMessage());
}
try {
if (msg.getAttachment() != null && msg.getAttachment().length() > 0) {
Multipart content = new Multipart();
TextBodyPart tbp = new TextBodyPart(content,msg.getContent());
content.addBodyPart(tbp);
InputStream stream = com.codename1.io.FileSystemStorage.getInstance().openInputStream(msg.getAttachment());
byte[] buf;
buf = IOUtilities.streamToBytes(stream);
stream.close();
String name = msg.getAttachment();
name = name.substring(name.lastIndexOf(getFileSystemSeparator()) + 1, name.length());
SupportedAttachmentPart sap = new SupportedAttachmentPart(content, msg.getAttachmentMimeType(), name, buf);
content.addBodyPart(sap);
message.setContent(content);
} else {
message.setContent(msg.getContent());
}
app.setWaitingForReply(true);
Invoke.invokeApplication(Invoke.APP_TYPE_MESSAGES, new MessageArguments(message));
} catch (Exception ex) {
EventLog.getInstance().logErrorEvent("err " + ex.getMessage());
}
}
public void dial(String phoneNumber) {
try {
PhoneArguments call = new PhoneArguments(PhoneArguments.ARG_CALL, phoneNumber);
app.setWaitingForReply(true);
Invoke.invokeApplication(Invoke.APP_TYPE_PHONE, call);
} catch (Exception e) {
EventLog.getInstance().logErrorEvent("unable to open dialer " + e.getMessage());
}
}
public void sendSMS(final String phoneNumber, final String message, boolean i) throws IOException {
//why on hell?? RIM has 2 different API's one for CDMA and
//one for GSM
if (!isCDMA()) {
String address = "sms://" + phoneNumber;
MessageConnection con = null;
try {
con = (MessageConnection) Connector.open(address);
TextMessage txtmessage =
(TextMessage) con.newMessage(MessageConnection.TEXT_MESSAGE);
txtmessage.setAddress(address);
txtmessage.setPayloadText(message);
con.send(txtmessage);
} catch (Exception e) {
throw new IOException("failed to send sms " + e.getMessage());
} finally {
if (con != null) {
try {
con.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
} else {
DatagramConnection connection = null;
try {
byte[] data = (message).getBytes("UTF-8");
connection = (DatagramConnection) Connector.open(
"sms://" + phoneNumber);
Datagram dg = connection.newDatagram(
connection.getMaximumLength());
dg.setData(data, 0, data.length);
connection.send(dg);
} catch (IOException e) {
throw new IOException("failed to send sms " + e.getMessage());
} finally {
try {
connection.close();
connection = null;
} catch (Exception e) {
}
}
}
}
boolean isCDMA() {
if ((RadioInfo.getActiveWAFs() & RadioInfo.WAF_CDMA)
== RadioInfo.WAF_CDMA) {
return true;
} else {
return false;
}
}
/**
* @inheritDoc
*/
public String [] getAllContacts(boolean withNumbers) {
return RIMContactsManager.getInstance().getAllContacts(withNumbers);
}
/**
* @inheritDoc
*/
public Contact getContactById(String id){
return RIMContactsManager.getInstance().getContactById(id);
}
/**
* @inheritDoc
*/
public Contact getContactById(String id, boolean includesFullName, boolean includesPicture,
boolean includesNumbers, boolean includesEmail, boolean includeAddress){
return RIMContactsManager.getInstance().getContactById(id, includesFullName, includesPicture,
includesNumbers, includesEmail, includeAddress);
}
public String createContact(String firstName, String familyName, String officePhone, String homePhone, String cellPhone, String email) {
return RIMContactsManager.getInstance().createContact(firstName, familyName, officePhone, homePhone, cellPhone, email);
}
public boolean deleteContact(String id) {
return RIMContactsManager.getInstance().deleteContact(id);
}
/**
* @inheritDoc
*/
public Media createMediaRecorder(String path, String mimeType) throws IOException {
return new MediaRecorder(path, mimeType);
}
/**
* @inheritDoc
*/
public String [] getAvailableRecordingMimeTypes(){
//The PCM format is not supported by BlackBerry devices on the CDMA network.
if(isCDMA()){
return new String[]{"audio/amr"};
}
return new String[]{"audio/amr", "audio/basic"};
}
/**
* @inheritDoc
*/
public String getPlatformName() {
return "rim";
}
/**
* @inheritDoc
*/
public String[] getPlatformOverrides() {
return new String[]{"phone", "rim"};
}
private L10NManager l10n;
/**
* @inheritDoc
*/
public L10NManager getLocalizationManager() {
if(l10n == null) {
Locale l = Locale.getDefault();
l10n = new L10NManager(l.getLanguage(), l.getCountry()) {
public String format(int number) {
return super.format(number);
}
public String format(double number) {
return super.format(number);
}
public String formatCurrency(double currency) {
return super.formatCurrency(currency);
}
public String formatDateLongStyle(Date d) {
return DateFormat.getInstance(DateFormat.DATE_LONG).format(d);
}
public String formatDateShortStyle(Date d) {
return DateFormat.getInstance(DateFormat.DATE_SHORT).format(d);
}
public String formatDateTime(Date d) {
String date = DateFormat.getInstance(DateFormat.DATE_FULL).format(d);
String time = DateFormat.getInstance(DateFormat.TIME_FULL).format(d);
return date + " " + time;
}
public String getCurrencySymbol() {
return super.getCurrencySymbol();
}
public void setLocale(String locale, String language) {
super.setLocale(locale, language);
Locale.setDefault(Locale.get(language, locale));
}
};
}
return l10n;
}
public void systemOut(String content){
EventLog.getInstance().logAlwaysEvent(content);
}
public CodeScanner getCodeScanner() {
return new CodeScannerImpl(new MultimediaManager());
}
public String getAppHomePath() {
String home = "file:///store/home/user/";
if (!exists(home)) {
return super.getAppHomePath();
}
String name = getProperty("AppName", "");
home = home + name + getFileSystemSeparator();
if(!exists(home)){
mkdir(home);
}
return home;
}
public boolean hasCamera() {
String capture = System.getProperty("supports.video.capture");
return "true".equals(capture);
}
}