You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2013/01/22 02:57:59 UTC
[18/52] [partial] support for 2.4.0rc1. "vendored" the platform libs
in. added Gord and Braden as contributors. removed dependency on unzip and
axed the old download-cordova code.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ProgressDialog.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ProgressDialog.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ProgressDialog.java
new file mode 100644
index 0000000..842b97a
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ProgressDialog.java
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cordova.notification;
+
+import org.apache.cordova.api.PluginResult;
+import org.apache.cordova.json4j.JSONArray;
+import org.apache.cordova.json4j.JSONException;
+import org.apache.cordova.ui.SpacerField;
+
+import net.rim.device.api.system.Characters;
+import net.rim.device.api.ui.UiApplication;
+import net.rim.device.api.ui.component.GaugeField;
+import net.rim.device.api.ui.component.LabelField;
+import net.rim.device.api.ui.component.SeparatorField;
+import net.rim.device.api.ui.container.PopupScreen;
+import net.rim.device.api.ui.container.VerticalFieldManager;
+
+/**
+ * A Popup progress dialog box with an optional title and message and a progress
+ * bar with a range from 0 to 100 (percent).
+ */
+public final class ProgressDialog extends PopupScreen {
+ private static ProgressDialog dialog = null;
+ private GaugeField gauge = null;
+
+ /**
+ * Construct a progress dialog, with customizable title and message.
+ *
+ * @param title
+ * Title of the progress dialog
+ * @param message
+ * Message to print in the body of the dialog
+ */
+ private ProgressDialog(String title, String message) {
+ super(new VerticalFieldManager());
+
+ if (title != null && title.length() > 0) {
+ add(new LabelField(title));
+ add(new SeparatorField(SeparatorField.LINE_HORIZONTAL));
+ }
+
+ if (message != null && message.length() > 0) {
+ add(new SpacerField(0, 20));
+ add(new LabelField(message, FIELD_HCENTER | FIELD_VCENTER));
+ }
+ add(new SpacerField(0, 20));
+
+ gauge = new GaugeField(null, 0, 100, 0, GaugeField.PERCENT
+ | GaugeField.FIELD_HCENTER);
+ add(gauge);
+ add(new SpacerField(0, 20));
+ }
+
+ /**
+ * Changes the value displayed in the dialogs GaugeField.
+ *
+ * @param args
+ * JSONArray of arguments.
+ * @return a PluginResult indicating success or error.
+ */
+ static synchronized PluginResult setValue(JSONArray args) {
+ if (dialog != null) {
+ if (args.length() > 0 && !args.isNull(0)) {
+ int value = -1;
+ try {
+ value = args.getInt(0);
+ } catch (JSONException e) {
+ return new PluginResult(PluginResult.Status.JSON_EXCEPTION,
+ "JSONException: " + e.getMessage());
+ }
+
+ if (value >= 0 && value <= 100) {
+ dialog.setValue(value);
+ }
+ }
+ }
+ return new PluginResult(PluginResult.Status.OK, "");
+ }
+
+ /**
+ * Creates and displays the progress dialog.
+ *
+ * @param args
+ * JSONArray of arguments.
+ * @return a PluginResult indicating success or error.
+ */
+ static synchronized PluginResult start(JSONArray args) {
+ if (dialog == null) {
+ String message = null;
+ String title = null;
+
+ // Title and message are optional, grab the strings from the args
+ // if they are there.
+ if (args != null && args.length() > 0) {
+ try {
+ if (!args.isNull(0)) {
+ title = args.getString(0);
+ }
+ if (args.length() > 1 && !args.isNull(1)) {
+ message = args.getString(1);
+ }
+ } catch (JSONException e) {
+ return new PluginResult(PluginResult.Status.JSON_EXCEPTION,
+ "JSONException: " + e.getMessage());
+ }
+ }
+
+ dialog = new ProgressDialog(title, message);
+ final UiApplication uiApp = UiApplication.getUiApplication();
+ uiApp.invokeLater(new Runnable() {
+ public void run() {
+ uiApp.pushModalScreen(dialog);
+ }
+ });
+ }
+
+ return new PluginResult(PluginResult.Status.OK, "");
+ }
+
+ /**
+ * Closes the progress dialog.
+ *
+ * @return a PluginResult indicating success or error.
+ */
+ static synchronized PluginResult stop() {
+ if (dialog != null) {
+ final UiApplication uiApp = UiApplication.getUiApplication();
+ final ProgressDialog tmpDialog = dialog;
+ uiApp.invokeLater(new Runnable() {
+ public void run() {
+ uiApp.popScreen(tmpDialog);
+ }
+ });
+ dialog = null;
+ }
+
+ return new PluginResult(PluginResult.Status.OK, "");
+ }
+
+ /**
+ * @see net.rim.device.api.ui.Screen#keyChar(char, int, int)
+ */
+ protected boolean keyChar(char key, int status, int time) {
+ // If the user clicks back key while progress dialog is displayed, close
+ // the progress dialog.
+ if (key == Characters.ESCAPE) {
+ stop();
+ }
+
+ return super.keyChar(key, status, time);
+ }
+
+ /**
+ * Changes the value displayed in the GaugeField.
+ *
+ * @param value
+ * the value (percentage) to set in GaugeField.
+ */
+ private void setValue(final int value) {
+ UiApplication.getUiApplication().invokeLater(new Runnable() {
+ public void run() {
+ gauge.setValue(value);
+ }
+ });
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/VibrateAction.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/VibrateAction.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/VibrateAction.java
new file mode 100644
index 0000000..76a545f
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/VibrateAction.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cordova.notification;
+
+import org.apache.cordova.api.PluginResult;
+import org.apache.cordova.json4j.JSONArray;
+import org.apache.cordova.json4j.JSONException;
+
+import net.rim.device.api.system.Alert;
+
+/**
+ * Vibrate Action
+ *
+ * Vibrates the device for specified duration.
+ */
+public class VibrateAction {
+
+ private static final int DEFAULT_DURATION = 1000;
+
+ /**
+ * Vibrates the device for a given amount of time.
+ *
+ * @param args JSONArray formatted as [ duration ]
+ * duration: specifies the vibration length in milliseconds (default: 1000).
+ * @return A PluginResult object with the success or failure state for vibrating the device.
+ */
+ public static PluginResult execute(JSONArray args) {
+ PluginResult result = null;
+
+ if (Alert.isVibrateSupported()) {
+ try {
+ int duration = (args.length() >= 1) ? args.getInt(0) : DEFAULT_DURATION;
+
+ Alert.startVibrate(duration);
+ }
+ catch (JSONException e) {
+ result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, "JSONException: " + e.getMessage());
+ }
+
+ result = new PluginResult(PluginResult.Status.OK, "OK");
+ }
+ else {
+ result = new PluginResult(PluginResult.Status.ILLEGAL_ACCESS_EXCEPTION, "Vibrate not supported");
+ }
+
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/pim/Contact.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/pim/Contact.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/pim/Contact.java
new file mode 100644
index 0000000..3e8e6d7
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/pim/Contact.java
@@ -0,0 +1,430 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cordova.pim;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.microedition.io.Connector;
+import javax.microedition.io.HttpConnection;
+import javax.microedition.pim.PIM;
+import javax.microedition.pim.PIMException;
+import javax.microedition.pim.PIMItem;
+
+import org.apache.cordova.api.Plugin;
+import org.apache.cordova.api.PluginResult;
+import org.apache.cordova.http.HttpUtils;
+import org.apache.cordova.json4j.JSONArray;
+import org.apache.cordova.json4j.JSONException;
+import org.apache.cordova.util.FileUtils;
+import org.apache.cordova.util.Logger;
+
+import net.rim.blackberry.api.pdap.BlackBerryContact;
+import net.rim.blackberry.api.pdap.BlackBerryContactList;
+import net.rim.device.api.io.Base64InputStream;
+import net.rim.device.api.io.FileNotFoundException;
+import net.rim.device.api.io.IOUtilities;
+import net.rim.device.api.io.http.HttpProtocolConstants;
+import net.rim.device.api.math.Fixed32;
+import net.rim.device.api.system.Bitmap;
+import net.rim.device.api.system.EncodedImage;
+import net.rim.device.api.system.PNGEncodedImage;
+
+/**
+ * Performs operations on Contacts stored in the BlackBerry Contacts database.
+ */
+public class Contact extends Plugin {
+
+ /**
+ * Possible actions
+ */
+ public static final int ACTION_SET_PICTURE = 0;
+ public static final int ACTION_GET_PICTURE = 1;
+
+ /**
+ * Maximum object size is 64KB in contact database. The raw image is Base64
+ * encoded before insertion.
+ * Base64 = (Bytes + 2 - ((Bytes + 2) MOD 3)) / 3 * 4
+ */
+ private static final long MAX_BYTES = 46080L;
+
+ /**
+ * Executes the requested action and returns a PluginResult.
+ *
+ * @param action The action to execute.
+ * @param callbackId The callback ID to be invoked upon action completion.
+ * @param args JSONArry of arguments for the action.
+ * @return A PluginResult object with a status and message.
+ */
+ public PluginResult execute(String action, JSONArray args, String callbackId) {
+
+ PluginResult result = null;
+ int a = getAction(action);
+
+ // perform specified action
+ if (a == ACTION_SET_PICTURE) {
+ // get parameters
+ String uid;
+ String type;
+ String value;
+ try {
+ uid = args.isNull(0) ? null : args.getString(0);
+ type = args.isNull(1) ? null : args.getString(1).toLowerCase();
+ value = args.isNull(2) ? null : args.getString(2);
+ } catch (JSONException e) {
+ Logger.log(this.getClass().getName() + ": " + e);
+ return new PluginResult(PluginResult.Status.JSON_EXCEPTION,
+ "Invalid or missing photo parameters");
+ }
+
+ // get the raw image data
+ byte[] photo = null;
+ if ("base64".equals(type)) {
+ // decode the image string
+ try {
+ photo = decodeBase64(value.getBytes());
+ }
+ catch (Exception e) {
+ Logger.log(this.getClass().getName() + ": " + e);
+ return new PluginResult(PluginResult.Status.ERROR, "Unable to decode image.");
+ }
+ }
+ else {
+ // retrieve the photo from URL
+ try {
+ photo = getPhotoFromUrl(value);
+ }
+ catch (Exception e) {
+ Logger.log(this.getClass().getName() + ": " + e);
+ return new PluginResult(PluginResult.Status.ERROR, "Unable to retrieve image at " + value);
+ }
+ }
+
+ // set the contact picture
+ result = setPicture(uid, photo);
+ }
+ else if (a == ACTION_GET_PICTURE) {
+ // get required parameters
+ String uid = null;
+ try {
+ uid = args.getString(0);
+ } catch (JSONException e) {
+ Logger.log(this.getClass().getName() + ": " + e);
+ return new PluginResult(PluginResult.Status.JSON_EXCEPTION,
+ "Invalid or missing image URL");
+ }
+ result = getPictureURI(uid);
+ }
+ else {
+ // invalid action
+ result = new PluginResult(PluginResult.Status.INVALID_ACTION,
+ "Contact: invalid action " + action);
+ }
+
+ return result;
+ }
+
+ /**
+ * Decodes the base64 encoded data provided.
+ * @param data Base64 encoded data
+ * @return byte array containing decoded data
+ * @throws IllegalArgumentException if encodedData is null
+ * @throws IOException if there is an error decoding
+ */
+ protected byte[] decodeBase64(final byte[] encodedData) throws IllegalArgumentException, IOException {
+ if (encodedData == null) {
+ throw new IllegalArgumentException();
+ }
+ ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(encodedData, 0, encodedData.length);
+ Base64InputStream base64InputStream = new Base64InputStream(byteArrayInputStream);
+ byte[] raw = null;
+ try {
+ raw = IOUtilities.streamToBytes(base64InputStream);
+ }
+ finally {
+ base64InputStream.close();
+ }
+ return raw;
+ }
+
+ /**
+ * Sets the photo of the specified contact to the picture at the specified URL.
+ * Local file-based (file:///) and web-based (http://) URLs are supported.
+ * The specified photo is retrieved and a scaled down copy is created and stored
+ * in the contacts database.
+ * @param uid Unique identifier of contact
+ * @param url URL of the photo to use for contact photo
+ * @return PluginResult providing status of operation
+ */
+ protected PluginResult setPicture(final String uid, final byte[] photo) {
+ Logger.log(this.getClass().getName() + ": setting picture for contact " + uid);
+
+ // We need to ensure the image encoding is supported, and resize the image
+ // so that it will fit in the persistent store. Note: testing indicates
+ // that the max image size is 64KB, so we scale it down considerably.
+ byte[] thumbnail = null;
+ try {
+ thumbnail = resizeImage(photo);
+ }
+ catch (IllegalArgumentException e) {
+ // unsupported image format
+ Logger.log(this.getClass().getName() + ": " + e);
+ return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Unsupported image format.");
+ }
+
+ // lookup contact and save the photo
+ BlackBerryContactList contactList = null;
+ try {
+ // lookup the contact
+ contactList = (BlackBerryContactList) PIM.getInstance().openPIMList(
+ PIM.CONTACT_LIST, PIM.READ_WRITE);
+ BlackBerryContact contact = contactList.getByUID(uid);
+ if (contact == null) {
+ return new PluginResult(PluginResult.Status.ERROR, "Contact " + uid + " not found.");
+ }
+
+ // save photo image
+ if(contact.countValues(javax.microedition.pim.Contact.PHOTO) > 0) {
+ contact.setBinary(javax.microedition.pim.Contact.PHOTO, 0,
+ PIMItem.ATTR_NONE, thumbnail, 0, thumbnail.length);
+ }
+ else {
+ contact.addBinary(javax.microedition.pim.Contact.PHOTO,
+ PIMItem.ATTR_NONE, thumbnail, 0, thumbnail.length);
+ }
+
+ // commit contact record to persistent store
+ contact.commit();
+ }
+ catch (Exception e) {
+ Logger.log(this.getClass().getName() + ": " + e);
+ return new PluginResult(PluginResult.Status.ERROR, e.getMessage());
+ }
+ finally {
+ // be sure to close the contact list to avoid locking it up
+ if (contactList != null) {
+ try { contactList.close(); } catch (PIMException ignored) { }
+ }
+ }
+
+ return new PluginResult(PluginResult.Status.OK);
+ }
+
+ /**
+ * Returns the URI of the contact photo. The photo image is extracted from
+ * the Contacts database and saved to a temporary file system. The URI of
+ * the saved photo is returned.
+ * @param uid unique Contact identifier
+ * @return PluginResult containing photo URI
+ */
+ protected PluginResult getPictureURI(final String uid) {
+ Logger.log(this.getClass().getName() + ": retrieving picture for contact " + uid);
+ String photoPath = null;
+
+ // lookup contact
+ BlackBerryContactList contactList = null;
+ try {
+ // lookup the contact
+ contactList = (BlackBerryContactList) PIM.getInstance().openPIMList(
+ PIM.CONTACT_LIST, PIM.READ_WRITE);
+ BlackBerryContact contact = contactList.getByUID(uid);
+ if (contact == null) {
+ return new PluginResult(PluginResult.Status.ERROR, "Contact " + uid + " not found.");
+ }
+
+ // get photo
+ if(contact.countValues(javax.microedition.pim.Contact.PHOTO) > 0) {
+ // decode from base64
+ byte[] encPhoto = contact.getBinary(javax.microedition.pim.Contact.PHOTO, 0);
+ byte[] photo = Base64InputStream.decode(encPhoto, 0, encPhoto.length);
+
+ // save photo to file system and return file URI
+ saveImage(uid, photo);
+ }
+ }
+ catch (Exception e) {
+ Logger.log(this.getClass().getName() + ": " + e);
+ return new PluginResult(PluginResult.Status.ERROR, e.getMessage());
+ }
+ finally {
+ // be sure to close the contact list to avoid locking it up
+ if (contactList != null) {
+ try { contactList.close(); } catch (PIMException ignored) { }
+ }
+ }
+
+ return new PluginResult(PluginResult.Status.OK, photoPath);
+ }
+
+ /**
+ * Retrieves the raw image data from the URL provided.
+ * @param url URL of the image
+ * @return raw image data from the URL provided
+ * @throws FileNotFoundException - if file URL could not be found
+ * @throws IOException - if there was an error processing the image file
+ */
+ protected byte[] getPhotoFromUrl(final String url) throws FileNotFoundException, IOException {
+ byte[] photo = null;
+
+ // externally hosted image
+ if (url != null && url.startsWith("http")) {
+ // open connection
+ HttpConnection conn = HttpUtils.getHttpConnection(url);
+ if (conn == null) {
+ throw new IllegalArgumentException("Invalid URL: " + url);
+ }
+
+ // retrieve image
+ InputStream in = null;
+ try {
+ conn.setRequestMethod(HttpConnection.GET);
+ conn.setRequestProperty(
+ HttpProtocolConstants.HEADER_USER_AGENT,
+ System.getProperty("browser.useragent"));
+ conn.setRequestProperty(
+ HttpProtocolConstants.HEADER_KEEP_ALIVE, "300");
+ conn.setRequestProperty(
+ HttpProtocolConstants.HEADER_CONNECTION, "keep-alive");
+ conn.setRequestProperty(
+ HttpProtocolConstants.HEADER_CONTENT_TYPE,
+ HttpProtocolConstants.CONTENT_TYPE_IMAGE_STAR);
+
+ // send request and get response
+ int rc = conn.getResponseCode();
+ if (rc != HttpConnection.HTTP_OK) {
+ throw new IOException("HTTP connection error: " + rc);
+ }
+ in = conn.openDataInputStream();
+ photo = IOUtilities.streamToBytes(in, 64*1024);
+ in.close();
+ }
+ finally {
+ conn.close();
+ }
+ }
+ // local image file
+ else {
+ photo = FileUtils.readFile(url, Connector.READ);
+ }
+ return photo;
+ }
+
+ /**
+ * Saves the contact image to a temporary directory.
+ * @param uid unique contact identifier
+ * @param photo encoded photo image data
+ * @throws IOException
+ */
+ protected void saveImage(final String uid, final byte[] photo) throws IOException {
+ // create a temporary directory to store the contacts photos
+ String contactsDir = "Contacts";
+ String tempDir = FileUtils.getApplicationTempDirPath() + contactsDir;
+ if (!FileUtils.exists(tempDir)) {
+ FileUtils.createTempDirectory(contactsDir);
+ }
+
+ // save the photo image to the temporary directory, overwriting if necessary
+ String photoPath = tempDir + FileUtils.FILE_SEPARATOR + uid + ".png";
+ if (FileUtils.exists(photoPath)) {
+ FileUtils.delete(photoPath);
+ }
+ FileUtils.writeFile(photoPath, photo, 0);
+ }
+
+ /**
+ * Creates a scaled copy of the specified image.
+ * @param photo Raw image data
+ * @return a scaled-down copy of the image provided
+ * @throws IllegalArgumentException
+ */
+ protected byte[] resizeImage(byte[] data) throws IllegalArgumentException {
+ // create an EncodedImage to make sure the encoding is supported
+ EncodedImage image = EncodedImage.createEncodedImage(data, 0, data.length);
+
+ // we're limited to 64KB encoding size, do we need to scale?
+ if (data.length < MAX_BYTES) {
+ return data;
+ }
+
+ // if so, try to maintain aspect ratio of original image and set max resolution
+ int srcWidth = image.getWidth();
+ int srcHeight = image.getHeight();
+ int dstWidth, dstHeight;
+ int max_rez = 150;
+ if (srcWidth > srcHeight) {
+ dstWidth = max_rez;
+ dstHeight = (dstWidth * srcHeight)/srcWidth;
+ }
+ else if (srcWidth < srcHeight) {
+ dstHeight = max_rez;
+ dstWidth = (dstHeight * srcWidth)/srcHeight;
+ }
+ else {
+ dstWidth = max_rez;
+ dstHeight = max_rez;
+ }
+
+ // calculate scale factors
+ int currentWidthFixed32 = Fixed32.toFP(srcWidth);
+ int currentHeightFixed32 = Fixed32.toFP(srcHeight);
+ int requiredWidthFixed32 = Fixed32.toFP(dstWidth);
+ int requiredHeightFixed32 = Fixed32.toFP(dstHeight);
+ int scaleXFixed32 = Fixed32.div(currentWidthFixed32,
+ requiredWidthFixed32);
+ int scaleYFixed32 = Fixed32.div(currentHeightFixed32,
+ requiredHeightFixed32);
+
+ // scale image (must be redrawn)
+ EncodedImage thumbnail = image.scaleImage32(scaleXFixed32, scaleYFixed32);
+ Bitmap bitmap = thumbnail.getBitmap();
+
+ // convert back to bytes
+ PNGEncodedImage png = PNGEncodedImage.encode(bitmap);
+ byte[] thumbData = png.getData();
+ Logger.log(this.getClass().getName() + ": photo size reduced from " + data.length + " to " + thumbData.length);
+ return thumbData;
+ }
+
+ /**
+ * Returns action to perform.
+ * @param action action to perform
+ * @return action to perform
+ */
+ protected static int getAction(String action) {
+ if ("setPicture".equals(action)) return ACTION_SET_PICTURE;
+ if ("getPicture".equals(action)) return ACTION_GET_PICTURE;
+ return -1;
+ }
+
+ /**
+ * Identifies if action to be executed returns a value and should be run synchronously.
+ *
+ * @param action The action to execute
+ * @return T=returns value
+ */
+ public boolean isSynch(String action) {
+ if (getAction(action) == ACTION_GET_PICTURE) {
+ return true;
+ }
+ else {
+ return super.isSynch(action);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/ui/SpacerField.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/ui/SpacerField.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/ui/SpacerField.java
new file mode 100644
index 0000000..d739617
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/ui/SpacerField.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cordova.ui;
+
+import net.rim.device.api.ui.Field;
+import net.rim.device.api.ui.Graphics;
+
+/**
+ * Provides an empty spacer field that can be used to provide custom spacing
+ * between UI fields within a UI screen.
+ */
+public class SpacerField extends Field {
+
+ int width; // spacer width in pixels
+ int height; // space height in pixels
+
+ /**
+ * Constructor.
+ * @param width Width of the spacer in pixels.
+ * @param height Height of the spacer in pixels.
+ */
+ public SpacerField(int width, int height) {
+ super(NON_FOCUSABLE);
+ this.width = width;
+ this.height = height;
+ }
+
+ /**
+ * Sets the extent to the custom width and height of this spacer.
+ */
+ protected void layout(int width, int height) {
+ this.setExtent(this.width, this.height);
+ }
+
+ /**
+ * Paints the field.
+ */
+ protected void paint(Graphics graphics) {
+ // supposed to be empty. don't paint anything.
+ }
+
+ /**
+ * Returns the custom width of this spacer as the preferred field width.
+ */
+ public int getPreferredWidth() {
+ return this.width;
+ }
+
+ /**
+ * Returns the custom height of this spacer as the preferred field height.
+ */
+ public int getPreferredHeight() {
+ return this.height;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/ApplicationUtils.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/ApplicationUtils.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/ApplicationUtils.java
new file mode 100644
index 0000000..e9ed784
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/ApplicationUtils.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cordova.util;
+
+import org.apache.cordova.camera.Camera;
+
+import net.rim.device.api.system.ApplicationDescriptor;
+import net.rim.device.api.system.ApplicationManager;
+import net.rim.device.api.system.Characters;
+import net.rim.device.api.system.CodeModuleManager;
+import net.rim.device.api.system.ControlledAccessException;
+import net.rim.device.api.system.EventInjector;
+import net.rim.device.api.ui.UiApplication;
+
+public class ApplicationUtils {
+ /**
+ * Determines if the specified application is running in the foreground.
+ *
+ * @param handle
+ * the name of the application handle (e.g., net_rim_bb_camera")
+ * @return <code>true</code> if the application is running and in the
+ * foreground
+ */
+ public static boolean isApplicationInForeground(String handle) {
+ // determine if the specified application is running in the foreground
+ ApplicationManager manager = ApplicationManager.getApplicationManager();
+ int foregroundProcessId = manager.getForegroundProcessId();
+ ApplicationDescriptor descriptors[] = manager.getVisibleApplications();
+ for (int i = 0; i < descriptors.length; i++) {
+ if (descriptors[i].getModuleName().equals(handle)
+ && manager.getProcessId(descriptors[i]) == foregroundProcessId) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determines if the specified application is installed.
+ *
+ * @param handle
+ * the name of the application handle (e.g., net_rim_bb_camera")
+ * @return <code>true</code> if the application is installed on the device
+ */
+ public static boolean isModuleInstalled(String handle) {
+ return (CodeModuleManager.getModuleHandle(handle) != 0);
+ }
+
+ /**
+ * Use this method when another native application has been launched by this
+ * application, and you would like the application to be closed.
+ * <p>
+ * Unfortunately, the only way to do this programmatically is to simulate
+ * the Escape (back) key being pressed. We do this by injecting key events,
+ * which means the application permissions must have the key injection
+ * permissions enabled for it to work.
+ * <p>
+ * An alternative to closing the applications would be to simply request
+ * that our application be brought to the foreground; however, this just
+ * pushes all the applications we've launched to the background, leaving a
+ * mess for the user to cleanup after this application has been closed.
+ *
+ * @param repeat
+ * the number of times to press the Esc key
+ */
+ public static void injectEscKeyPress(final int repeat) {
+ // simulate escape characters (back button press)
+ Runnable escKeyPresser = new Runnable() {
+ public void run() {
+ try {
+ EventInjector.KeyEvent inject = new EventInjector.KeyEvent(
+ EventInjector.KeyEvent.KEY_DOWN, Characters.ESCAPE,
+ 0);
+ int count = 0;
+ while (count < repeat) {
+ inject.post();
+ count++;
+ }
+ }
+ catch (ControlledAccessException e) {
+ // the application doesn't have key injection
+ // permissions
+ Logger.log(Camera.class.getName() + ": "
+ + ApplicationDescriptor
+ .currentApplicationDescriptor().getName()
+ + " does not have key injection permissions.");
+ }
+ }
+ };
+ UiApplication.getUiApplication().invokeLater(escKeyPresser);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/FileUtils.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/FileUtils.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/FileUtils.java
new file mode 100644
index 0000000..2655ef6
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/FileUtils.java
@@ -0,0 +1,699 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cordova.util;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+
+import javax.microedition.io.Connector;
+import javax.microedition.io.file.FileConnection;
+import javax.microedition.io.file.FileSystemRegistry;
+
+import org.apache.cordova.CordovaExtension;
+import org.apache.cordova.file.File;
+
+import net.rim.device.api.io.FileNotFoundException;
+import net.rim.device.api.io.IOUtilities;
+import net.rim.device.api.io.MIMETypeAssociations;
+import net.rim.device.api.system.Application;
+
+/**
+ * Contains file utility methods.
+ */
+public class FileUtils {
+
+ public static final String FILE_SEPARATOR = System.getProperty("file.separator");
+ public static final String LOCAL_PROTOCOL = "local://";
+ public static final String FILE_PROTOCOL = "file://";
+
+ private static final String APP_TMP_DIR = "tmp" + CordovaExtension.getAppID();
+
+ /**
+ * Reads file as byte array.
+ * @param filePath Full path of the file to be read
+ * @param mode One of Connector.READ, READ_WRITE, WRITE
+ * @return file content as a byte array
+ */
+ public static byte[] readFile(String filePath, int mode) throws FileNotFoundException, IOException {
+ byte[] blob = null;
+ DataInputStream dis = null;
+ try {
+ dis = openDataInputStream(filePath, mode);
+ blob = IOUtilities.streamToBytes(dis);
+ }
+ finally {
+ try {
+ if (dis != null) dis.close();
+ }
+ catch (IOException ignored) {
+ }
+ }
+ return blob;
+ }
+
+ /**
+ * Utility function to open a DataInputStream from a file path.
+ *
+ * A file can be referenced with the following protocols:
+ * - System.getProperty("fileconn.dir.*")
+ * - local:/// references files bundled with the application
+ *
+ * @param filePath The full path to the file to open
+ * @param mode One of Connector.READ, READ_WRITE, WRITE
+ * @return Handle to the DataInputStream
+ */
+ private static DataInputStream openDataInputStream(final String filePath, int mode) throws FileNotFoundException, IOException {
+ FileConnection fconn = null;
+ DataInputStream dis = null;
+ try {
+ if (filePath.startsWith(LOCAL_PROTOCOL)) {
+ // Remove local:// from filePath but leave a leading /
+ dis = new DataInputStream(Application.class.getResourceAsStream(filePath.substring(8)));
+ }
+ else {
+ fconn = (FileConnection)Connector.open(filePath, mode);
+ if (!fconn.exists()) {
+ throw new FileNotFoundException(filePath + " not found");
+ }
+ dis = fconn.openDataInputStream();
+ }
+
+ if (dis == null) {
+ throw new FileNotFoundException(filePath + " not found");
+ }
+ }
+ finally {
+ try {
+ if (fconn != null) fconn.close();
+ }
+ catch (IOException ignored) {
+ }
+ }
+
+ return dis;
+ }
+
+ /**
+ * Writes data to the specified file.
+ *
+ * @param filePath
+ * Full path of file to be written to
+ * @param data
+ * Data to be written
+ * @param position
+ * Position at which to begin writing
+ * @return length of data written to file
+ * @throws SecurityException
+ * if the application does not have write access to the file
+ * @throws IOException
+ * if directory structure does not exist or an unspecified error
+ * occurs
+ */
+ public static int writeFile(String filePath, byte[] data, int position)
+ throws SecurityException, IOException {
+ FileConnection fconn = null;
+ OutputStream os = null;
+ try {
+ fconn = (FileConnection) Connector.open(filePath,
+ Connector.READ_WRITE);
+ if (!fconn.exists()) {
+ fconn.create();
+ } else {
+ // Originally, this did an overwrite in place and did not
+ // truncate. The truncate was added to match behavior on
+ // other platforms.
+ fconn.truncate(position);
+ }
+ os = fconn.openOutputStream(position);
+ os.write(data);
+ }
+ finally {
+ try {
+ if (os != null)
+ os.close();
+ if (fconn != null)
+ fconn.close();
+ }
+ catch (IOException ignored) {
+ }
+ }
+ return data.length;
+ }
+
+ /**
+ * Deletes the specified file or directory from file system. If the
+ * specified path is a directory, the deletion is recursive.
+ *
+ * @param path
+ * full path of file or directory to be deleted
+ * @throws IOException
+ */
+ public static void delete(String path) throws IOException {
+ FileConnection fconn = null;
+ try {
+ fconn = (FileConnection)Connector.open(path, Connector.READ_WRITE);
+ if (fconn.exists()) {
+ // file
+ if (!fconn.isDirectory()) {
+ fconn.delete();
+ Logger.log(FileUtils.class.getName() + ": " + path + " deleted");
+ }
+ // directory
+ else {
+ if (!path.endsWith(FILE_SEPARATOR)) {
+ path += FILE_SEPARATOR;
+ }
+
+ // recursively delete directory contents
+ Enumeration contents = fconn.list("*", true);
+ if (contents.hasMoreElements()) {
+ fconn.close();
+ while (contents.hasMoreElements()) {
+ delete(path + contents.nextElement().toString());
+ }
+ fconn = (FileConnection)Connector.open(path, Connector.READ_WRITE);
+ }
+ // now delete this directory
+ fconn.delete();
+ Logger.log(FileUtils.class.getName() + ": " + path + " deleted");
+ }
+ }
+ }
+ finally {
+ try {
+ if (fconn != null) fconn.close();
+ }
+ catch (IOException ignored) {
+ }
+ }
+ }
+
+ /**
+ * Creates a directory. Directories in the specified path are not created
+ * recursively. If the directory already exists, no action is taken.
+ *
+ * @param dirPath
+ * full path of directory to create
+ * @throws IOException
+ * if the target file system is not accessible, or an
+ * unspecified error occurs
+ */
+ public static void mkdir(String dirPath) throws IOException {
+ FileConnection fconn = null;
+ try {
+ fconn = (FileConnection)Connector.open(dirPath);
+ if (fconn.isDirectory()) {
+ // nothing to do
+ return;
+ }
+ fconn.mkdir();
+ }
+ finally {
+ try {
+ if (fconn != null) fconn.close();
+ }
+ catch (IOException ignored) {
+ }
+ }
+ }
+
+ /**
+ * Copies a file or directory to a new location. If copying a directory, the
+ * entire contents of the directory are copied recursively.
+ *
+ * @param srcPath
+ * the full path of the file or directory to be copied
+ * @param parent
+ * the full path of the target directory to which the file or
+ * directory should be copied
+ * @param newName
+ * the new name of the file or directory
+ * @throws IllegalArgumentException
+ * if an invalid source or destination path is provided
+ * @throws FileNotFoundException
+ * if the source path cannot be found on the file system
+ * @throws SecurityException
+ * if unable to create the new file or directory specified by
+ * destination path
+ * @throws IOException
+ * if an attempt is made to copy the contents of a directory
+ * into itself, or if the source and destination paths are
+ * identical, or if a general error occurs
+ */
+ public static void copy(String srcPath, String parent, String newName)
+ throws IllegalArgumentException, FileNotFoundException,
+ SecurityException, IOException {
+
+ FileConnection src = null;
+ FileConnection dst = null;
+ try {
+ src = (FileConnection)Connector.open(srcPath, Connector.READ_WRITE);
+
+ // ensure source exists
+ if (!src.exists()) {
+ throw new FileNotFoundException("Path not found: " + srcPath);
+ }
+
+ // ensure target parent directory exists
+ if (!isDirectory(parent)) {
+ throw new FileNotFoundException("Target directory not found: " + parent);
+ }
+
+ // form full destination path
+ if (!parent.endsWith(FileUtils.FILE_SEPARATOR)) {
+ parent += FileUtils.FILE_SEPARATOR;
+ }
+ String dstPath = parent + newName;
+
+ // source is a directory
+ if (src.isDirectory()) {
+ // target should also be directory; append file separator
+ if (!dstPath.endsWith(FILE_SEPARATOR)) {
+ dstPath += FILE_SEPARATOR;
+ }
+
+ // can't copy directory into itself
+ // file:///SDCard/tmp/ --> file:///SDCard/tmp/tmp/ ==> NO!
+ // file:///SDCard/tmp/ --> file:///SDCard/tmp/ ==> NO!
+ // file:///SDCard/tmp/ --> file:///SDCard/tmp2/ ==> OK
+ String srcURL = src.getURL();
+ if (dstPath.startsWith(srcURL)) {
+ throw new IOException("Cannot copy directory into itself.");
+ }
+
+ // create the destination directory
+ mkdir(dstPath);
+
+ // recursively copy directory contents
+ Enumeration contents = src.list("*", true);
+ if (contents.hasMoreElements()) {
+ src.close();
+ while (contents.hasMoreElements()) {
+ String name = contents.nextElement().toString();
+ copy(srcURL + name, dstPath, name);
+ }
+ }
+ }
+ // source is a file
+ else {
+ // can't copy file onto itself
+ if (dstPath.equals(srcPath)) {
+ throw new IOException("Cannot copy file onto itself.");
+ }
+
+ dst = (FileConnection) Connector.open(dstPath, Connector.READ_WRITE);
+
+ // replace existing file, but not directory
+ if (dst.exists()) {
+ if (dst.isDirectory()) {
+ throw new IOException(
+ "Cannot overwrite existing directory.");
+ }
+ else {
+ dst.delete();
+ }
+ }
+ dst.create();
+
+ // copy the contents - wish there was a better way
+ InputStream is = null;
+ OutputStream os = null;
+ try {
+ is = src.openInputStream();
+ os = dst.openOutputStream();
+ byte[] buf = new byte[1024];
+ int len;
+ while ((len = is.read(buf)) > 0) {
+ os.write(buf, 0, len);
+ }
+ }
+ finally {
+ if (is != null) is.close();
+ if (os != null) os.close();
+ }
+ }
+ }
+ finally {
+ try {
+ if (src != null) src.close();
+ if (dst != null) dst.close();
+ }
+ catch (IOException ignored) {
+ }
+ }
+ }
+
+ /**
+ * Creates an temporary directory for the application. The temporary
+ * directory is created in the following location:
+ * <code><root>/tmpGUID/</code> where <code><root>/</code>
+ * is the path of the writable directory on the file system (could be the SD
+ * card, if present, or the root file system on internal storage); and
+ * <code>tmpGUID/</code> is a application temporary directory that is
+ * created using the unique application GUID. If the application temporary
+ * directory does not exist, invoking this method will create it.
+ * <em>NOTE:</em> The <code><root>/tmpGUID/</code> application
+ * temporary directory and all its contents are deleted upon application
+ * exit.
+ *
+ * @return full path name of the application temporary directory
+ * @throws IOException
+ * if there are no file systems mounted, or an unspecified error
+ * occurs
+ */
+ public static String createApplicationTempDirectory() throws IOException {
+ // <root>/tmpGUID/
+ String tmpDir = getApplicationTempDirPath();
+ mkdir(tmpDir);
+
+ return tmpDir;
+ }
+
+ /**
+ * Creates a temporary directory on the writable storage area of the file
+ * system. The temporary directory is created in the following location:
+ * <code><root>/tmpGUID/dirName/</code> where
+ * <code><root>/tmpGUID/</code> is an application temporary
+ * directory that is created using the unique application GUID; and
+ * <code>dirName/</code> is an optional directory name to create beneath the
+ * application temporary directory. If the application temporary directory
+ * does not exist, invoking this method will create it. <em>NOTE:</em> The
+ * <code><root>/tmpGUID/</code> application temporary directory
+ * and all its contents are deleted upon application exit.
+ *
+ * @param dirName
+ * name of directory to be created beneath the application
+ * temporary directory
+ * @return full path name of the directory that was created
+ * @throws IOException
+ * if there are no file systems mounted, or an unspecified error
+ * occurs
+ */
+ public static String createTempDirectory(String dirName) throws IOException {
+ // create the application temp directory
+ String tmpDir = createApplicationTempDirectory();
+
+ // create specified sub-directory as "<root>/tmpGUID/dirName/"
+ dirName = (dirName == null) ? "" : dirName.trim();
+ if (dirName.length() > 0) {
+ if (!dirName.endsWith(FILE_SEPARATOR)) {
+ dirName += FILE_SEPARATOR;
+ }
+ tmpDir += dirName;
+ mkdir(tmpDir);
+ }
+ return tmpDir;
+ }
+
+ /**
+ * Attempts to delete the application temporary directory and all contents.
+ * The application temporary directory is:
+ * <code><root>/tmpGUID/</code>, where <code><root></code> is
+ * the file system root (could be the SD card or internal storage); and
+ * <code>tmpGUID</code> is the application temporary directory that is
+ * created using the unique application GUID. <em>NOTE:</em> The
+ * <code>tmpGUID</code> application temporary directory and all
+ * sub-directories are deleted upon application exit.
+ *
+ * @throws IOException
+ * if an unspecified error occurs
+ */
+ public synchronized static void deleteApplicationTempDirectory()
+ throws IOException {
+ String tmpDir = getApplicationTempDirPath();
+ delete(tmpDir);
+ }
+
+ /**
+ * Returns the full path of the application temporary directory. The path
+ * points to the following location: <code><root>/tmpGUID/</code>
+ * where <code><root>/</code> is the path of the writable directory on
+ * the file system (could be the SD card, if present, or the root file system
+ * on internal storage); and <code>tmpGUID/</code> is a application temporary
+ * directory that is created using the unique application GUID. The
+ * directory may not exist. Invoke
+ * <code>createApplicationTempDirectory</code> to create it.
+ *
+ * @return the full path name of the application temporary directory
+ */
+ public static String getApplicationTempDirPath() {
+ return getFileSystemRoot() + APP_TMP_DIR + FILE_SEPARATOR;
+ }
+
+ /**
+ * Returns the full path of a root file system. Will return the path of the
+ * SD card first, if it exists, or the root file system located on internal
+ * storage.
+ *
+ * @return full path that can be used to store files
+ */
+ public static String getFileSystemRoot() {
+ String root = null;
+ String sdcard = getSDCardPath();
+
+ // retrieve root list
+ Enumeration e = FileSystemRegistry.listRoots();
+ while (e.hasMoreElements()) {
+ root = "file:///" + (String) e.nextElement();
+ // system directory won't be writable
+ if (root.endsWith("system/")) {
+ continue;
+ }
+ // prefer the SDCard
+ else if (root.equals(sdcard)) {
+ break;
+ }
+ }
+ return root;
+ }
+
+ /**
+ * Returns the full path name to external storage (SD card, e.g.
+ * file:///SDCard/).
+ *
+ * @return full path name to the external storage (SD card)
+ */
+ public static String getSDCardPath() {
+ return System.getProperty("fileconn.dir.memorycard");
+ }
+
+ /**
+ * Returns the full path name of the user directory located on internal
+ * storage (e.g. file:///store/home/user/).
+ *
+ * @return full path name of the user directory
+ */
+ public static String getUserPath() {
+ // grab the music folder
+ String musicDir = System.getProperty("fileconn.dir.music");
+ // ignore trailing '/'
+ int i = musicDir.lastIndexOf('/', musicDir.length() - 2);
+ // strip off the last directory
+ return musicDir.substring(0, i + 1);
+ }
+
+ /**
+ * Returns the available size of the file system that the path resides on.
+ *
+ * @param path
+ * full path of a file system entry
+ * @return available size, in bytes, of the root file system
+ * @throws IllegalArgumentException
+ * if path is invalid
+ * @throws IOException
+ * if an error occurs
+ */
+ public static long availableSize(String path)
+ throws IllegalArgumentException, IOException {
+ long availableSize = 0;
+ FileConnection fconn = null;
+ try {
+ fconn = (FileConnection) Connector.open(path);
+ availableSize = fconn.availableSize();
+ }
+ finally {
+ try {
+ if (fconn != null)
+ fconn.close();
+ }
+ catch (IOException ignored) {
+ }
+ }
+ return availableSize;
+ }
+
+ /**
+ * Determines if the specified file system path exists.
+ * @param path full path of file or directory
+ * @return true if the file or directory exists
+ */
+ public static boolean exists(String path) {
+ boolean exists = false;
+ FileConnection fconn = null;
+ try {
+ fconn = (FileConnection)Connector.open(path);
+ exists = fconn.exists();
+ }
+ catch (IllegalArgumentException e) {
+ Logger.log(FileUtils.class.getName() + ": " + e);
+ }
+ catch (IOException e) {
+ Logger.log(FileUtils.class.getName() + ": " + e);
+ }
+ finally {
+ try {
+ if (fconn != null) fconn.close();
+ }
+ catch (IOException ignored) {
+ }
+ }
+ return exists;
+ }
+
+ /**
+ * Determines if the specified file system path refers to a directory.
+ * @param path full path of file or directory
+ * @return true if the file path exists, is accessible, and is a directory
+ */
+ public static boolean isDirectory(String path) {
+ boolean isDirectory = false;
+ FileConnection fconn = null;
+ try {
+ fconn = (FileConnection)Connector.open(path);
+ isDirectory = fconn.isDirectory();
+ }
+ catch (IllegalArgumentException e) {
+ Logger.log(FileUtils.class.getName() + ": " + e);
+ }
+ catch (IOException e) {
+ Logger.log(FileUtils.class.getName() + ": " + e);
+ }
+ finally {
+ try {
+ if (fconn != null) fconn.close();
+ }
+ catch (IOException ignored) {
+ }
+ }
+ return isDirectory;
+ }
+
+ /**
+ * Lists the contents of a directory. Lists both files and sub-directories.
+ *
+ * @param path
+ * full path of the directory to list
+ * @return Enumeration containing names of files and sub-directories.
+ * @throws FileNotFoundException
+ * if path is not found
+ * @throws IOException
+ * if an error occurs
+ */
+ public static Enumeration listDirectory(String path)
+ throws FileNotFoundException, IOException {
+ FileConnection fconn = null;
+ Enumeration listing = null;
+ try {
+ fconn = (FileConnection) Connector.open(path);
+ if (!fconn.exists()) {
+ throw new FileNotFoundException(path + " does not exist.");
+ }
+ listing = fconn.list();
+ }
+ finally {
+ try {
+ if (fconn != null)
+ fconn.close();
+ }
+ catch (IOException ignored) {
+ }
+ }
+ return listing;
+ }
+
+ public static File getFileProperties(String filePath) throws FileNotFoundException {
+ File file = new File(stripSeparator(filePath));
+ FileConnection fconn = null;
+ try {
+ fconn = (FileConnection)Connector.open(filePath);
+ if (!fconn.exists()) {
+ throw new FileNotFoundException();
+ }
+ file.setLastModifiedDate(fconn.lastModified());
+ file.setName(stripSeparator(fconn.getName()));
+ file.setType(MIMETypeAssociations.getMIMEType(filePath));
+ file.setSize(fconn.fileSize());
+ }
+ catch (IllegalArgumentException e) {
+ Logger.log(FileUtils.class.getName() + ": " + e);
+ }
+ catch (IOException e) {
+ Logger.log(FileUtils.class.getName() + ": " + e);
+ }
+ finally {
+ try {
+ if (fconn != null) fconn.close();
+ }
+ catch (IOException ignored) {
+ }
+ }
+ return file;
+ }
+
+ /**
+ * Strips the trailing slash from path names.
+ *
+ * @param path
+ * full or relative path name
+ * @return formatted path (without trailing slash)
+ */
+ public static String stripSeparator(String path) {
+ int len = FILE_SEPARATOR.length();
+ while (path.endsWith(FILE_SEPARATOR)) {
+ path = path.substring(0, path.length() - len);
+ }
+ return path;
+ }
+
+
+ /**
+ * If the specified file path does not have a URI prefix, prefix it with the
+ * file:/// prefix.
+ *
+ * @param filePath
+ * @return the prefixed URI.
+ */
+ public static String prefixFileURI(String filePath) {
+ if (!filePath.startsWith(LOCAL_PROTOCOL)
+ && !filePath.startsWith(FILE_PROTOCOL)
+ && !filePath.startsWith("http://")
+ && !filePath.startsWith("https://")) {
+ if (filePath.indexOf(FILE_SEPARATOR) != 0) {
+ filePath = FILE_PROTOCOL + FILE_SEPARATOR + filePath;
+ } else {
+ filePath = FILE_PROTOCOL + filePath;
+ }
+ }
+
+ return filePath;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/Log.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/Log.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/Log.java
new file mode 100644
index 0000000..54396e7
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/Log.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cordova.util;
+
+import net.rim.device.api.script.Scriptable;
+import net.rim.device.api.script.ScriptableFunction;
+
+/**
+ * Log provides a mechanism for JavaScript code to utilize the Event Log.
+ * Log represents an object in the script engine that can be accessed from the
+ * script environment using <code>cordova.Logger</code>.
+ *
+ * Log provides a function, <code>log(msg)</code>, that logs messages to the
+ * BlackBerry Event Log as well as to System.out.
+ *
+ * To use of the BlackBerry Event Log from JavaScript, you must first
+ * invoke the <code>enable()</code> method:
+ *
+ * <code>cordova.Logger.enable();</code>
+ * <code>cordova.Logger.log(msg);</code>
+ */
+public final class Log extends Scriptable {
+
+ /**
+ * Field used to log messages.
+ */
+ public static final String FIELD_LOG = "log";
+
+ /**
+ * Field used to enable message logging.
+ */
+ public static final String FIELD_ENABLE = "enable";
+
+ /**
+ * Logs messages to the BlackBerry Event Log and to <code>System.out</code>.
+ */
+ public final LogFunction logFunction; // logs to the Event Log
+
+ /**
+ * Constructor.
+ */
+ public Log() {
+ this.logFunction = new LogFunction();
+ }
+
+ /**
+ * The following fields are supported from the script environment:
+ *
+ * <code>cordova.Logger.enable</code> - Enables message logging.
+ * <code>cordova.Logger.log</code> - Logs the specified message.
+ */
+ public Object getField(String name) throws Exception {
+
+ if (name.equals(FIELD_LOG)) {
+ return this.logFunction;
+ }
+ else if (name.equals(FIELD_ENABLE)) {
+ return new ScriptableFunction() {
+ public Object invoke(Object obj, Object[] oargs) throws Exception {
+ Logger.enableLogging();
+ return null;
+ }
+ };
+ }
+ return super.getField(name);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/LogFunction.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/LogFunction.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/LogFunction.java
new file mode 100644
index 0000000..918371d
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/LogFunction.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cordova.util;
+
+import net.rim.device.api.script.ScriptableFunction;
+
+/**
+ * LogFunction represents a function that can be invoked from the script
+ * environment of the widget framework. Messages are logged to the BlackBerry
+ * Event Log. From JavaScript, invoke
+ *
+ * <code>cordova.Logger.log(msg);</code>
+ */
+public class LogFunction extends ScriptableFunction {
+
+ public Object invoke(Object obj, Object[] oargs) throws Exception {
+
+ if (oargs != null) {
+ String message = (String)oargs[0];
+ Logger.log(message);
+ }
+
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/Logger.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/Logger.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/Logger.java
new file mode 100644
index 0000000..c5c21ad
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/Logger.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cordova.util;
+
+import java.util.Date;
+
+import org.apache.cordova.CordovaExtension;
+
+import net.rim.device.api.i18n.SimpleDateFormat;
+import net.rim.device.api.system.EventLogger;
+
+/**
+ * Logger provides a mechanism to log the the BlackBerry Event Log. It uses
+ * the BlackBerry EventLogger class.
+ *
+ * The Event Log can be viewed on BlackBerry simulators using Tools > Show Event
+ * Log, or on physical devices by pressing the <code>Alt</code> key, followed by
+ * the <code>LGLG</code> key combination.
+ *
+ * To enable event logging, you must first call <code>enableLogging</code>.
+ *
+ * Logger also provides methods to write to <code>System.out</code> and
+ * <code>System.err</code>.
+ */
+public class Logger {
+
+ /**
+ * Application name
+ */
+ protected static String appName;
+
+ /**
+ * Application GUID
+ */
+ protected static long appID;
+
+ /**
+ * Used to format dates into a standard format
+ */
+ private static final SimpleDateFormat dateFormat =
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+
+ /**
+ * Invoke this method to enable logging to the BlackBerry Event Log.
+ */
+ public static void enableLogging() {
+ appID = CordovaExtension.getAppID();
+ appName = CordovaExtension.getAppName();
+ if (EventLogger.register(appID, appName, EventLogger.VIEWER_STRING)) {
+ log("Logger enabled: " + "GUID=" + appID + ", name=" + appName);
+ }
+ else {
+ log("EventLogger registration failed.");
+ }
+ }
+
+ /**
+ * Sets the minimum logging level.
+ */
+ public static void setMinimumLoggingLevel(int level) {
+ EventLogger.setMinimumLevel(level);
+ }
+
+ /**
+ * Logs formatted message to Event Log with ALWAYS_LOG level.
+ */
+ public static void log(String msg) {
+ logEvent(msg, EventLogger.ALWAYS_LOG);
+ }
+
+ /**
+ * Logs formatted message to Event Log with DEBUG_INFO level.
+ */
+ public static void debug(String msg) {
+ logEvent(msg, EventLogger.DEBUG_INFO);
+ }
+
+ /**
+ * Logs formatted message to Event Log with INFORMATION level.
+ */
+ public static void info(String msg) {
+ logEvent(msg, EventLogger.INFORMATION);
+ }
+
+ /**
+ * Logs formatted message to Event Log with WARNING level.
+ */
+ public static void warn(String msg) {
+ logEvent(msg, EventLogger.WARNING);
+ }
+
+ /**
+ * Logs formatted message to Event Log with ERROR level.
+ */
+ public static void error(String msg) {
+ logEvent(msg, EventLogger.ERROR);
+ }
+
+ /**
+ * Logs formatted message to Event Log with SEVERE_ERROR level.
+ */
+ public static void severe(String msg) {
+ logEvent(msg, EventLogger.SEVERE_ERROR);
+ }
+
+ /**
+ * Prints unformatted message to System.out.
+ */
+ public static void out(String msg) {
+ System.out.println(msg);
+ }
+
+ /**
+ * Prints unformatted message to System.err.
+ */
+ public static void err(String msg, Throwable t) {
+ System.err.println(msg);
+ t.printStackTrace();
+ }
+
+ /**
+ * Logs formatted message to Event Log (if enabled) and System.out.
+ */
+ private static void logEvent(String msg, int level) {
+ String message = formatMessage(msg);
+ EventLogger.logEvent(appID, message.getBytes(), level);
+ out(message);
+ }
+
+ private static String formatMessage(String msg) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(appName);
+ sb.append(" [");
+ sb.append(dateFormat.format(new Date()));
+ sb.append("]: ");
+ sb.append(msg);
+ return sb.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/StringUtils.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/StringUtils.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/StringUtils.java
new file mode 100644
index 0000000..0a4d45d
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/StringUtils.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Taken from Research in Motion knowledge base article:
+ *
+ * DB-00728: "How To - Implement a string splitter based on a given string delimiter", 24 March 2009.
+ * http://www.blackberry.com/knowledgecenterpublic/livelink.exe/fetch/2000/348583/800332/832062/How_To_-_Implement_a_string_splitter_based_on_a_given_string_delimiter.html?nodeid=1498848&vernum=0
+ */
+package org.apache.cordova.util;
+
+/**
+ * Provides various string utility methods.
+ */
+public class StringUtils {
+
+ //Identifies the substrings in a given string that are delimited
+ //by one or more characters specified in an array, and then
+ //places the substrings into a String array.
+ public static String[] split(String strString, String strDelimiter) {
+ String[] strArray;
+ int iOccurrences = 0;
+ int iIndexOfInnerString = 0;
+ int iIndexOfDelimiter = 0;
+ int iCounter = 0;
+
+ //Check for null input strings.
+ if (strString == null) {
+ throw new IllegalArgumentException("Input string cannot be null.");
+ }
+ //Check for null or empty delimiter strings.
+ if (strDelimiter.length() <= 0 || strDelimiter == null) {
+ throw new IllegalArgumentException("Delimeter cannot be null or empty.");
+ }
+
+ //strString must be in this format: (without {} )
+ //"{str[0]}{delimiter}str[1]}{delimiter} ...
+ // {str[n-1]}{delimiter}{str[n]}{delimiter}"
+
+ //If strString begins with delimiter then remove it in order
+ //to comply with the desired format.
+
+ if (strString.startsWith(strDelimiter)) {
+ strString = strString.substring(strDelimiter.length());
+ }
+
+ //If strString does not end with the delimiter then add it
+ //to the string in order to comply with the desired format.
+ if (!strString.endsWith(strDelimiter)) {
+ strString += strDelimiter;
+ }
+
+ //Count occurrences of the delimiter in the string.
+ //Occurrences should be the same amount of inner strings.
+ while((iIndexOfDelimiter = strString.indexOf(strDelimiter,
+ iIndexOfInnerString)) != -1) {
+ iOccurrences += 1;
+ iIndexOfInnerString = iIndexOfDelimiter +
+ strDelimiter.length();
+ }
+
+ //Declare the array with the correct size.
+ strArray = new String[iOccurrences];
+
+ //Reset the indices.
+ iIndexOfInnerString = 0;
+ iIndexOfDelimiter = 0;
+
+ //Walk across the string again and this time add the
+ //strings to the array.
+ while((iIndexOfDelimiter = strString.indexOf(strDelimiter,
+ iIndexOfInnerString)) != -1) {
+
+ //Add string to array.
+ strArray[iCounter] = strString.substring(iIndexOfInnerString,iIndexOfDelimiter);
+
+ //Increment the index to the next character after
+ //the next delimiter.
+ iIndexOfInnerString = iIndexOfDelimiter +
+ strDelimiter.length();
+
+ //Inc the counter.
+ iCounter += 1;
+ }
+
+ return strArray;
+ }
+}