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
[19/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/media/AudioPlayer.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/media/AudioPlayer.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/media/AudioPlayer.java
new file mode 100644
index 0000000..9958cf0
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/media/AudioPlayer.java
@@ -0,0 +1,654 @@
+/*
+ * 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.media;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import javax.microedition.io.Connector;
+import javax.microedition.io.file.FileConnection;
+import javax.microedition.media.Manager;
+import javax.microedition.media.MediaException;
+import javax.microedition.media.Player;
+import javax.microedition.media.PlayerListener;
+import javax.microedition.media.control.RecordControl;
+import javax.microedition.media.control.VolumeControl;
+import javax.microedition.media.protocol.DataSource;
+
+import net.rim.device.api.media.protocol.ByteArrayInputStreamDataSource;
+
+import org.apache.cordova.util.FileUtils;
+import org.apache.cordova.util.Logger;
+
+/**
+ * This class implements the audio playback and recording capabilities used by
+ * Cordova. It is called by the Media Cordova class. Only one file can be played
+ * or recorded per class instance.
+ *
+ * Supports playing audio locally and remotely. Files located within the
+ * application package must be prefixed with "local:///". If no URI prefix
+ * (file, http, local) is found, file is assumed to be on device and "file:///"
+ * prefix added.
+ */
+public class AudioPlayer implements PlayerListener {
+
+ private static final String LOG_TAG = "AudioPlayer: ";
+
+ // Media states
+ public static final int MEDIA_NONE = 0;
+ public static final int MEDIA_STARTING = 1;
+ public static final int MEDIA_RUNNING = 2;
+ public static final int MEDIA_PAUSED = 3;
+ public static final int MEDIA_STOPPED = 4;
+
+ // Media message ids
+ private static final int MEDIA_STATE = 1;
+ private static final int MEDIA_DURATION = 2;
+ private static final int MEDIA_POSITION = 3;
+ private static final int MEDIA_ERROR = 9;
+
+ // Media error codes
+ private static final int MEDIA_ERR_NONE_ACTIVE = 0;
+ private static final int MEDIA_ERR_ABORTED = 1;
+ private static final int MEDIA_ERR_NETWORK = 2;
+ private static final int MEDIA_ERR_DECODE = 3;
+ private static final int MEDIA_ERR_NONE_SUPPORTED = 4;
+
+ private final Media handler;
+ private final String id;
+ private int state = MEDIA_NONE; // State of recording or playback
+ private String audioFile = null; // File name to play or record to
+ private float duration = -1; // Duration of audio
+
+ private Player recorder = null; // Audio recording object
+ private RecordControl recorderControl = null;
+ private ByteArrayOutputStream recorderOutput = null;
+
+ private Player player = null; // Audio player object
+ private boolean prepareOnly = false;
+
+ private long prevPos = 0;
+ private long adjustTime = 0;
+ private long previousTime = 0;
+
+ private long lastPlay = System.currentTimeMillis();
+
+ private boolean buffering = false;
+
+ /**
+ * Constructor.
+ *
+ * @param handler
+ * The audio handler object
+ * @param id
+ * The id of this audio player
+ */
+ public AudioPlayer(Media handler, String id) {
+ this.handler = handler;
+ this.id = id;
+ }
+
+ /**
+ * Destroy stop audio playing or recording and free resources.
+ */
+ public synchronized void destroy() {
+ // Stop any play or record
+ destroyPlayer();
+ if (recorder != null) {
+ stopRecording();
+ }
+ }
+
+ /**
+ * Stop and free the player.
+ */
+ private void destroyPlayer() {
+ if (player != null) {
+ if (state == MEDIA_RUNNING || state == MEDIA_PAUSED) {
+ stopPlaying();
+ }
+ player.removePlayerListener(this);
+ player.close();
+ player = null;
+ }
+ }
+
+ /**
+ * Get current position of playback.
+ *
+ * @return position as a floating point number indicating number of seconds
+ * or -1 if not playing
+ */
+ public synchronized float getCurrentPosition() {
+ // Current position is only valid when running, paused or buffering.
+ if (state == MEDIA_RUNNING || state == MEDIA_PAUSED || buffering) {
+ // The time returned by getMediaTime() is only updated every second.
+ // Keep track of time between updates in order to provide
+ // millisecond granularity.
+ long curPos = player.getMediaTime();
+
+ // Media time is within the 1 second granularity window so add time
+ // since last update.
+ if (curPos == prevPos && state == MEDIA_RUNNING) {
+ if (previousTime == 0) {
+ previousTime = System.currentTimeMillis();
+ } else {
+ long newTime = System.currentTimeMillis();
+ // Convert from milliseconds to microseconds.
+ adjustTime += ((newTime - previousTime) * 1000);
+ previousTime = newTime;
+ curPos += adjustTime;
+ }
+ } else {
+ prevPos = curPos;
+ previousTime = System.currentTimeMillis();
+ adjustTime = 0;
+ }
+
+ // Convert from microseconds to floating point seconds.
+ float time = curPos / 1000000.0f;
+ sendStatus(MEDIA_POSITION, time);
+ return time;
+ } else {
+ return -1;
+ }
+ }
+
+ /**
+ * Get the duration of the audio file.
+ *
+ * @param file
+ * The name of the audio file.
+ * @return duration as a floating point number indicating number of seconds
+ * or -1 = can't be determined or -2 = not allowed
+ */
+ public synchronized float getDuration(String file) {
+ // Can't get duration of recording
+ if (recorder != null) {
+ return (-2); // not allowed
+ }
+
+ // If audio file already loaded and started, then return duration
+ if (player != null) {
+ return duration;
+ }
+
+ // If no player yet, then create one
+ else {
+ prepareOnly = true;
+ startPlaying(file);
+ // This will only return value for local, since streaming
+ // file hasn't been read yet.
+ return duration;
+ }
+ }
+
+ /**
+ * Get the audio state.
+ *
+ * @return int
+ */
+ public synchronized int getState() {
+ return state;
+ }
+
+ /**
+ * Pause playing.
+ */
+ public synchronized void pausePlaying() {
+ // If playing, then pause
+ if (state == MEDIA_RUNNING) {
+ try {
+ player.stop();
+ setState(MEDIA_PAUSED);
+ } catch (MediaException e) {
+ Logger.log(LOG_TAG + "pausePlaying() Error: " + e.getMessage());
+ sendError(MEDIA_ERR_ABORTED);
+ }
+ } else {
+ Logger.log(LOG_TAG
+ + "pausePlaying() Error: called during invalid state: "
+ + state);
+ sendError(MEDIA_ERR_NONE_ACTIVE);
+ }
+ }
+
+ /**
+ * PlayerListener interface callback when an event occurs in the player.
+ *
+ * @see javax.microedition.media.PlayerListener#playerUpdate(javax.microedition.media.Player,
+ * java.lang.String, java.lang.Object)
+ */
+ public void playerUpdate(Player player, String event, Object eventData) {
+ if (BUFFERING_STARTED.equals(event)) {
+ buffering = true;
+ } else if (BUFFERING_STOPPED.equals(event)) {
+ buffering = false;
+ setState(MEDIA_RUNNING);
+ } else if (DURATION_UPDATED.equals(event)) {
+ if (eventData != null && eventData instanceof Long) {
+ // Convert duration from microseconds to seconds.
+ duration = ((Long) eventData).longValue() / 1000000.0f;
+ sendStatus(MEDIA_DURATION, duration);
+ }
+ } else if (END_OF_MEDIA.equals(event)) {
+ // Update the final position before stopping the player.
+ if (eventData != null && eventData instanceof Long) {
+ sendStatus(MEDIA_POSITION,
+ ((Long) eventData).longValue() / 1000000.0f);
+ }
+ stopPlaying();
+ } else if (ERROR.equals(event)) {
+ // Send error notification to JavaScript
+ if (eventData != null && eventData instanceof String) {
+ try {
+ int code = Integer.parseInt((String) eventData);
+ sendError(code);
+ } catch (NumberFormatException ne) {
+ Logger.log(LOG_TAG + "playerUpdate(): Player id(" + id + ") received error: "
+ + eventData);
+ }
+ } else {
+ Logger.log(LOG_TAG + "playerUpdate(): Player id(" + id + ") received error: " + eventData);
+ }
+ destroy();
+ }
+ }
+
+ /**
+ * Seek or jump to a new time in the track.
+ *
+ * @throws MediaException
+ */
+ public synchronized void seekToPlaying(int milliseconds) {
+ if (player != null) {
+ try {
+ // Convert milliseconds to microseconds.
+ player.setMediaTime(milliseconds > 0 ? milliseconds * 1000
+ : milliseconds);
+ sendStatus(MEDIA_POSITION, milliseconds / 1000.0f);
+ } catch (MediaException e) {
+ Logger.log(LOG_TAG + "seekToPlaying() Error: " + e.getMessage());
+ sendError(MEDIA_ERR_ABORTED);
+ }
+ }
+ }
+
+ /**
+ * Set the volume for audio player
+ *
+ * @param volume
+ * volume level 0.0-1.0
+ */
+ public synchronized void setVolume(float volume) {
+ if (player != null) {
+ if (player.getState() >= Player.REALIZED) {
+ VolumeControl vc = (VolumeControl) player
+ .getControl("VolumeControl");
+ // Native volume level range is 0-100
+ vc.setLevel((int) (volume * 100));
+ }
+ }
+ }
+
+ /**
+ * Start or resume playing audio file.
+ *
+ * @param file
+ * The name of the audio file.
+ */
+ public synchronized void startPlaying(String file) {
+ try {
+ if (recorder != null) {
+ Logger.log(LOG_TAG
+ + "startPlaying() Error: Can't play in record mode.");
+ sendError(MEDIA_ERR_ABORTED);
+ }
+
+ // If this is a new request to play audio, or stopped
+ else if (player == null || state == MEDIA_STOPPED) {
+ setState(MEDIA_STARTING);
+
+ if (file == null || file.length() == 0) {
+ Logger.log(LOG_TAG
+ + "startPlaying(): Input file not specified.");
+ sendError(MEDIA_ERR_ABORTED);
+ setState(MEDIA_NONE);
+ destroy();
+ return;
+ }
+
+ // If the player was previously used, need to check if it needs
+ // recreated to pick up file changes. Cases when the player
+ // needs recreated:
+ // 1. New source file was specified.
+ // 2. File is local and has been modified since last play.
+ if (player != null) {
+ if (!file.equals(audioFile)) {
+ destroyPlayer();
+ } else if (!isStreaming(file)) {
+ // File needs to follow the local or file URI protocol
+ // so if neither prefix exists assume a file URI and add
+ // the "file:///" prefix.
+ file = FileUtils.prefixFileURI(file);
+ FileConnection fconn = null;
+ try {
+ fconn = (FileConnection) Connector.open(file,
+ Connector.READ);
+ if (fconn.exists()) {
+ if (fconn.lastModified() > lastPlay) {
+ destroyPlayer();
+ }
+ }
+ } catch (Exception e) {
+ // Ignore
+ } finally {
+ try {
+ if (fconn != null) {
+ fconn.close();
+ }
+ } catch (IOException ignored) {
+ }
+ }
+ }
+ }
+
+ // At this point if player is not null then the file previously
+ // played is still valid so just reset the current position.
+ if (player != null) {
+ player.setMediaTime(0);
+ }
+ // Otherwise, create a new one
+ else {
+ // If streaming file
+ if (isStreaming(file)) {
+ player = Manager.createPlayer(file);
+ } else {
+ // File needs to follow the local or file URI protocol
+ // so if neither prefix exists assume a file URI and add
+ // the "file:///" prefix.
+ file = FileUtils.prefixFileURI(file);
+
+ String contentType = "audio/mp3";
+ if (file.endsWith(".amr")) {
+ contentType = "audio/amr";
+ } else if (file.endsWith(".wav")) {
+ contentType = "audio/wav";
+ }
+
+ DataSource dataSource = new ByteArrayInputStreamDataSource(
+ new ByteArrayInputStream(FileUtils.readFile(
+ file, Connector.READ)), contentType);
+ player = Manager.createPlayer(dataSource);
+ }
+ audioFile = file;
+ player.addPlayerListener(this);
+ }
+
+ lastPlay = System.currentTimeMillis();
+ player.realize();
+ player.prefetch();
+
+ // Get duration as floating point seconds.
+ duration = player.getDuration() == Player.TIME_UNKNOWN ? Player.TIME_UNKNOWN
+ : player.getDuration() / 1000000.0f;
+
+ sendStatus(MEDIA_DURATION, duration);
+
+ if (!prepareOnly) {
+ player.start();
+ }
+ prepareOnly = false;
+ }
+
+ // If previously existing player is still valid.
+ else {
+ // If player has been paused, then resume playback
+ if (state == MEDIA_PAUSED || state == MEDIA_STARTING) {
+ player.start();
+ setState(MEDIA_RUNNING);
+ } else {
+ Logger.log(LOG_TAG
+ + "Error: startPlaying() called during invalid state: "
+ + state);
+ sendError(MEDIA_ERR_ABORTED);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ Logger.log(LOG_TAG + "startPlaying() Error: " + e.getMessage());
+ sendError(MEDIA_ERR_ABORTED);
+ }
+ }
+
+ /**
+ * Start recording the specified file.
+ *
+ * @param file
+ * The name of the file
+ */
+ public synchronized void startRecording(String file) {
+ try {
+ if (player != null) {
+ Logger.log(LOG_TAG
+ + "startRecording() Error: Can't record in play mode.");
+ sendError(MEDIA_ERR_ABORTED);
+ } else if (recorder == null) {
+
+ if (file == null || file.length() == 0) {
+ Logger.log(LOG_TAG
+ + "startRecording() Error: Output file not specified.");
+ sendError(MEDIA_ERR_ABORTED);
+ return;
+ }
+ setState(MEDIA_STARTING);
+ file = FileUtils.prefixFileURI(file);
+
+ recorder = Manager.createPlayer("capture://audio");
+ recorder.addPlayerListener(this);
+ recorder.realize();
+ recorderControl = (RecordControl) recorder
+ .getControl("RecordControl");
+ recorderOutput = new ByteArrayOutputStream();
+ recorderControl.setRecordStream(recorderOutput);
+ recorderControl.startRecord();
+ recorder.start();
+ audioFile = file;
+ setState(MEDIA_RUNNING);
+
+ } else {
+ Logger.log(LOG_TAG
+ + "startRecording() Error: Already recording.");
+ sendError(MEDIA_ERR_ABORTED);
+ }
+ } catch (Exception e) {
+ Logger.log(LOG_TAG
+ + "startRecording() Error: Failed to start recording. "
+ + e.getMessage());
+ if (recorder != null) {
+ recorder.removePlayerListener(this);
+ recorder.close();
+ recorder = null;
+ }
+ if (recorderControl != null) {
+ try {
+ recorderControl.reset();
+ } catch (IOException e1) {
+ // Ignore
+ }
+ recorderControl = null;
+ }
+ if (recorderOutput != null) {
+ try {
+ recorderOutput.close();
+ } catch (IOException e1) {
+ // Ignore
+ }
+ recorderOutput = null;
+ }
+
+ setState(MEDIA_NONE);
+ }
+ }
+
+ /**
+ * Stop playing the audio file.
+ */
+ public synchronized void stopPlaying() {
+ if (state == MEDIA_RUNNING || state == MEDIA_PAUSED) {
+ try {
+ player.stop();
+ player.setMediaTime(0);
+ } catch (MediaException e) {
+ Logger.log(LOG_TAG + "stopPlaying() Error: " + e.getMessage());
+ sendError(MEDIA_ERR_ABORTED);
+ }
+ setState(MEDIA_STOPPED);
+ } else {
+ Logger.log(LOG_TAG + "stopPlaying() called during invalid state: "
+ + state);
+ sendError(MEDIA_ERR_NONE_ACTIVE);
+ }
+ }
+
+ /**
+ * Stop recording and save to the file specified when recording started.
+ */
+ public synchronized void stopRecording() {
+ DataOutputStream output = null;
+ FileConnection conn = null;
+
+ try {
+ if (recorder != null) {
+ if (state == MEDIA_RUNNING) {
+ recorderControl.commit();
+ byte data[] = recorderOutput.toByteArray();
+
+ conn = (FileConnection) Connector.open(audioFile,
+ Connector.READ_WRITE);
+ if (conn.exists()) {
+ conn.delete();
+ conn.close();
+ conn = (FileConnection) Connector.open(audioFile,
+ Connector.READ_WRITE);
+ }
+ conn.create();
+ output = conn.openDataOutputStream();
+ output.write(data);
+ output.flush();
+ }
+ }
+ } catch (IOException e) {
+ // Ignore
+ Logger.log(LOG_TAG + "stopRecording() Error: " + e.getMessage());
+ } finally {
+ if (recorderOutput != null) {
+ try {
+ recorderOutput.close();
+ } catch (IOException e) {
+ // Ignore
+ Logger.log(LOG_TAG
+ + "stopRecording() Failed to close recorder output. "
+ + e.getMessage());
+ }
+ recorderOutput = null;
+ }
+ if (recorder != null) {
+ recorder.removePlayerListener(this);
+ recorder.close();
+ recorder = null;
+ }
+
+ if (recorderControl != null) {
+ recorderControl.stopRecord();
+ recorderControl = null;
+ }
+
+ if (output != null) {
+ try {
+ output.close();
+ } catch (IOException e) {
+ // Ignore
+ Logger.log(LOG_TAG
+ + "stopRecording() Failed to close output file. "
+ + e.getMessage());
+ }
+ output = null;
+ }
+
+ if (conn != null) {
+ try {
+ conn.close();
+ } catch (IOException e) {
+ // Ignore
+ Logger.log(LOG_TAG
+ + "stopRecording() Failed to close connection. "
+ + e.getMessage());
+ }
+ }
+ setState(MEDIA_STOPPED);
+ }
+ }
+
+ /**
+ * Determine if playback file is streaming or local. It is streaming if file
+ * name starts with "http://"
+ *
+ * @param file
+ * The file name
+ * @return T=streaming, F=local
+ */
+ private boolean isStreaming(String file) {
+ if (file.startsWith("http://") || file.startsWith("https://")) {
+ return true;
+ }
+ return false;
+ }
+
+ private void sendError(int code) {
+ handler.invokeScript("cordova.require('cordova/plugin/Media').onStatus('"
+ + id + "', " + MEDIA_ERROR + ", { \"code\":" + code + "});");
+ }
+
+ private void sendStatus(int msg, float value) {
+ handler.invokeScript("cordova.require('cordova/plugin/Media').onStatus('"
+ + id + "', " + msg + ", " + value + ");");
+ }
+
+ private void sendStatus(int msg, int value) {
+ handler.invokeScript("cordova.require('cordova/plugin/Media').onStatus('"
+ + id + "', " + msg + ", " + value + ");");
+ }
+
+ /**
+ * Set the state and send it to JavaScript.
+ *
+ * @param state
+ */
+ private synchronized void setState(int state) {
+ // Only send state back to JavaScript if it has changed.
+ if (this.state != state) {
+ sendStatus(MEDIA_STATE, state);
+ }
+
+ this.state = state;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/media/Media.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/media/Media.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/media/Media.java
new file mode 100644
index 0000000..f1e2b27
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/media/Media.java
@@ -0,0 +1,344 @@
+/*
+ * 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.media;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.cordova.api.Plugin;
+import org.apache.cordova.api.PluginResult;
+import org.apache.cordova.json4j.JSONArray;
+import org.apache.cordova.json4j.JSONException;
+import org.apache.cordova.util.Logger;
+
+/**
+ * This plugin provides the ability to play and record audio. The file can be
+ * local or over a network using http.
+ *
+ * Audio formats supported (tested): .mp3, .wav, .amr
+ *
+ * Supports playing audio locally and remotely. Files located within the
+ * application package must be prefixed with "local:///". If no URI prefix
+ * (file, http, local) is found, file is assumed to be on device and "file:///"
+ * prefix added.
+ */
+public class Media extends Plugin {
+
+ private static final String LOG_TAG = "Media: ";
+ private final Hashtable players = new Hashtable();
+
+ // Cross-platform defined actions
+ private static final String CREATE = "create";
+ private static final String START_RECORDING = "startRecordingAudio";
+ private static final String STOP_RECORDING = "stopRecordingAudio";
+ private static final String START_PLAYING = "startPlayingAudio";
+ private static final String STOP_PLAYING = "stopPlayingAudio";
+ private static final String SEEK_TO = "seekToAudio";
+ private static final String PAUSE_PLAYING = "pausePlayingAudio";
+ private static final String SET_VOLUME = "setVolume";
+ private static final String GET_POSITION = "getCurrentPositionAudio";
+ private static final String GET_DURATION = "getDurationAudio";
+ private static final String RELEASE = "release";
+
+ /**
+ * Executes the request and returns PluginResult.
+ *
+ * @param action
+ * The action to execute.
+ * @param args
+ * JSONArry of arguments for the plugin.
+ * @param callbackId
+ * The callback id used when calling back into JavaScript.
+ * @return A PluginResult object with a status and message.
+ */
+ public PluginResult execute(String action, JSONArray args, String callbackId) {
+ PluginResult.Status status = PluginResult.Status.NO_RESULT;
+
+ try {
+ if (CREATE.equals(action)) {
+ createMedia(args.getString(0), args.getString(1));
+ return new PluginResult(PluginResult.Status.OK, "");
+ } else if (START_RECORDING.equals(action)) {
+ startRecordingAudio(args.getString(0), args.getString(1));
+ } else if (STOP_RECORDING.equals(action)) {
+ stopRecordingAudio(args.getString(0));
+ } else if (START_PLAYING.equals(action)) {
+ startPlayingAudio(args.getString(0), args.getString(1));
+ } else if (SEEK_TO.equals(action)) {
+ seekToAudio(args.getString(0), args.getInt(1));
+ } else if (PAUSE_PLAYING.equals(action)) {
+ pausePlayingAudio(args.getString(0));
+ } else if (STOP_PLAYING.equals(action)) {
+ stopPlayingAudio(args.getString(0));
+ } else if (SET_VOLUME.equals(action)) {
+ try {
+ float level = Float.parseFloat(args.getString(1));
+ setVolume(args.getString(0), level);
+ } catch (NumberFormatException nfe) {
+ Logger.log(LOG_TAG + "execute(): Failed to convert volume level: "
+ + args.getString(1) + " " + nfe.getMessage());
+ return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
+ }
+ } else if (GET_POSITION.equals(action)) {
+ float f = getCurrentPositionAudio(args.getString(0));
+ return new PluginResult(PluginResult.Status.OK, f);
+ } else if (GET_DURATION.equals(action)) {
+ float f = getDurationAudio(args.getString(0), args.getString(1));
+ return new PluginResult(PluginResult.Status.OK, f);
+ } else if (RELEASE.equals(action)) {
+ boolean b = release(args.getString(0));
+ return new PluginResult(PluginResult.Status.OK, b);
+ } else {
+ Logger.log(LOG_TAG + "execute(): Invalid action: " + action);
+ return new PluginResult(PluginResult.Status.INVALID_ACTION,
+ "Invalid action: " + action);
+ }
+ return new PluginResult(status, "");
+ } catch (JSONException e) {
+ Logger.log(LOG_TAG + "execute() Error: " + e.getMessage());
+ return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
+ }
+ }
+
+ /**
+ * 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 (CREATE.equals(action) || GET_POSITION.equals(action)
+ || GET_DURATION.equals(action) || RELEASE.equals(action)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Stop all audio players and recorders.
+ */
+ public void onDestroy() {
+ Enumeration keys = players.keys();
+ while (keys.hasMoreElements()) {
+ AudioPlayer audio = (AudioPlayer) players.get(keys.nextElement());
+ if (audio != null) {
+ audio.destroy();
+ }
+ }
+
+ players.clear();
+ }
+
+ /**
+ * Start or resume playing audio file.
+ *
+ * @param id
+ * The id of the audio player
+ * @param file
+ * The name of the audio file.
+ */
+ private void createMedia(String id, String file) {
+ AudioPlayer audio = (AudioPlayer) players.get(id);
+ if (audio == null) {
+ audio = new AudioPlayer(this, id);
+ players.put(id, audio);
+ }
+ }
+
+ /**
+ * Get current position of playback.
+ *
+ * @param id
+ * The id of the audio player
+ * @return position in msec
+ */
+ private float getCurrentPositionAudio(String id) {
+ AudioPlayer audio = (AudioPlayer) players.get(id);
+ if (audio != null) {
+ return (audio.getCurrentPosition());
+ }
+ return -1;
+ }
+
+ /**
+ * Get the duration of the audio file.
+ *
+ * @param id
+ * The id of the audio player
+ * @param file
+ * The name of the audio file.
+ * @return The duration in msec.
+ */
+ private float getDurationAudio(String id, String file) {
+ // Get audio file
+ AudioPlayer audio = (AudioPlayer) players.get(id);
+ if (audio != null) {
+ return (audio.getDuration(file));
+ }
+
+ // If not already open, then open the file
+ audio = new AudioPlayer(this, id);
+ players.put(id, audio);
+ return (audio.getDuration(file));
+ }
+
+ /**
+ * Pause playing.
+ *
+ * @param id
+ * The id of the audio player
+ */
+ private void pausePlayingAudio(String id) {
+ AudioPlayer audio = (AudioPlayer) players.get(id);
+ if (audio != null) {
+ audio.pausePlaying();
+ } else {
+ Logger.log(LOG_TAG
+ + "pausePlayingAudio() Error: Unknown Audio Player " + id);
+ }
+ }
+
+ /**
+ * Release the audio player instance to save memory.
+ *
+ * @param id
+ * The id of the audio player
+ */
+ private boolean release(String id) {
+ if (!players.containsKey(id)) {
+ Logger.log(LOG_TAG + "release() Error: Unknown Audio Player " + id);
+ return false;
+ }
+
+ AudioPlayer audio = (AudioPlayer) players.get(id);
+ players.remove(id);
+ audio.destroy();
+ return true;
+ }
+
+ /**
+ * Seek to a location.
+ *
+ * @param id
+ * The id of the audio player
+ * @param miliseconds
+ * int: number of milliseconds to skip 1000 = 1 second
+ */
+ private void seekToAudio(String id, int milliseconds) {
+ AudioPlayer audio = (AudioPlayer) players.get(id);
+ if (audio != null) {
+ audio.seekToPlaying(milliseconds);
+ } else {
+ Logger.log(LOG_TAG + "seekToAudio() Error: Unknown Audio Player "
+ + id);
+ }
+ }
+
+ /**
+ * Set the volume for an audio device
+ *
+ * @param id
+ * The id of the audio player
+ * @param volume
+ * Volume to adjust to 0 - 1
+ */
+ private void setVolume(String id, float volume) {
+ AudioPlayer audio = (AudioPlayer) players.get(id);
+ if (audio != null) {
+ audio.setVolume(volume);
+ } else {
+ Logger.log(LOG_TAG + "setVolume() Error: Unknown Audio Player "
+ + id);
+ }
+ }
+
+ /**
+ * Start or resume playing audio file.
+ *
+ * @param id
+ * The id of the audio player
+ * @param file
+ * The name of the audio file.
+ */
+ private void startPlayingAudio(String id, String file) {
+ AudioPlayer audio = (AudioPlayer) players.get(id);
+ if (audio == null) {
+ audio = new AudioPlayer(this, id);
+ players.put(id, audio);
+ }
+ audio.startPlaying(file);
+ }
+
+ /**
+ * Start recording and save the specified file.
+ *
+ * @param id
+ * The id of the audio player
+ * @param file
+ * The name of the file
+ */
+ private void startRecordingAudio(String id, String file) {
+ AudioPlayer audio = (AudioPlayer) players.get(id);
+ if (audio == null) {
+ audio = new AudioPlayer(this, id);
+ players.put(id, audio);
+ }
+
+ int state = audio.getState();
+ if (state == AudioPlayer.MEDIA_NONE
+ || state == AudioPlayer.MEDIA_STOPPED) {
+ audio.startRecording(file);
+ }
+ }
+
+ /**
+ * Stop playing the audio file.
+ *
+ * @param id
+ * The id of the audio player
+ */
+ private void stopPlayingAudio(String id) {
+ AudioPlayer audio = (AudioPlayer) players.get(id);
+ if (audio != null) {
+ audio.stopPlaying();
+ } else {
+ Logger.log(LOG_TAG
+ + "stopPlayingAudio() Error: Unknown Audio Player " + id);
+ }
+ }
+
+ /**
+ * Stop recording and save to the file specified when recording started.
+ *
+ * @param id
+ * The id of the audio player
+ */
+ private void stopRecordingAudio(String id) {
+ AudioPlayer audio = (AudioPlayer) players.get(id);
+ if (audio != null) {
+ audio.stopRecording();
+ players.remove(id);
+ } else {
+ Logger.log(LOG_TAG
+ + "stopRecordingAudio() Error: Unknown Audio Player " + id);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/network/ConnectionInfoAction.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/network/ConnectionInfoAction.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/network/ConnectionInfoAction.java
new file mode 100644
index 0000000..2a280e6
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/network/ConnectionInfoAction.java
@@ -0,0 +1,355 @@
+/*
+ * 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.network;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.cordova.CordovaExtension;
+import org.apache.cordova.api.PluginResult;
+import org.apache.cordova.util.Logger;
+
+import net.rim.device.api.system.Application;
+import net.rim.device.api.system.CoverageInfo;
+import net.rim.device.api.system.CoverageStatusListener;
+import net.rim.device.api.system.RadioInfo;
+import net.rim.device.api.system.RadioStatusListener;
+import net.rim.device.api.system.WLANConnectionListener;
+import net.rim.device.api.system.WLANInfo;
+
+/**
+ * Determines the current network data connection type and listens for changes
+ * to network coverage. This class is intended for use through the Network
+ * plug-in.
+ */
+public class ConnectionInfoAction {
+ // Return types
+ private static final String TYPE_UNKNOWN = "unknown";
+ private static final String TYPE_ETHERNET = "ethernet";
+ private static final String TYPE_WIFI = "wifi";
+ private static final String TYPE_2G = "2g";
+ private static final String TYPE_3G = "3g";
+ private static final String TYPE_4G = "4g";
+ private static final String TYPE_NONE = "none";
+
+ // Network status event values
+ private static final String OFFLINE = "offline";
+ private static final String ONLINE = "online";
+
+ // Network service support constants
+ private static final int DATA = RadioInfo.NETWORK_SERVICE_DATA;
+ private static final int TWO_G = RadioInfo.NETWORK_SERVICE_DATA
+ | RadioInfo.NETWORK_SERVICE_EDGE;
+ private static final int THREE_G = RadioInfo.NETWORK_SERVICE_EVDO_REV0
+ | RadioInfo.NETWORK_SERVICE_EVDO_REV0_ONLY
+ | RadioInfo.NETWORK_SERVICE_EVDO_REVA
+ | RadioInfo.NETWORK_SERVICE_EVDO_REVA_ONLY
+ | RadioInfo.NETWORK_SERVICE_UMTS;
+
+ // Listeners used to detect network changes
+ private RadioStatusListener radioListener = null;
+ private WLANConnectionListener wlanListener = null;
+ private CoverageStatusListener coverageListener = null;
+
+ // Variable indicating whether the user has disabled mobile data
+ private Boolean dataDisabled = Boolean.FALSE;
+
+ // The set of call back IDs to send results to. Using Hashtable because
+ // BlackBerry does not support Collections. There should only ever be one
+ // call back ID, but this allows multiple.
+ private Hashtable callbackIds = new Hashtable();
+
+ private String prevType = TYPE_NONE;
+ private String prevEvent = OFFLINE;
+
+ /**
+ * Determines the current network data connection type. Listeners are
+ * registered to return additional results when network state changes.
+ *
+ * @param callbackId
+ * The success call back ID to receive network type results.
+ * @return A PluginResult object with the success or failure result of the
+ * operation. A success result includes information about the
+ * currently active network type.
+ */
+ protected PluginResult getConnectionInfo(String callbackId) {
+
+ // Ensure that the dataDisabled variable is initialized.
+ setDataDisabled(CoverageInfo.getCoverageStatus(), false);
+
+ // Add the network change listeners if they have not been added.
+ addListeners(callbackId);
+
+ // Retrieve the current active connection type and build the return
+ // result.
+ PluginResult result = new PluginResult(PluginResult.Status.OK,
+ getConnectionType(true, true));
+
+ // Need to keep the call back since listeners have been registered to
+ // fire events on the specified call back ID.
+ result.setKeepCallback(true);
+
+ return result;
+ }
+
+ /**
+ * Removes all coverage listeners and clears the list of call back IDs. This
+ * method should be invoked when the Network plug-in's onDestroy is called.
+ */
+ protected synchronized void shutdown() {
+ if (radioListener != null) {
+ Application.getApplication().removeRadioListener(radioListener);
+ radioListener = null;
+ }
+
+ if (wlanListener != null) {
+ WLANInfo.removeListener(wlanListener);
+ wlanListener = null;
+ }
+
+ if (coverageListener != null) {
+ CoverageInfo.removeListener(coverageListener);
+ coverageListener = null;
+ }
+
+ callbackIds.clear();
+ }
+
+ /**
+ * Adds a RadioStatusListener, WLANConnectionListener and
+ * CoverageStatusListener to listen for various network change events. The
+ * listeners are only registered if they have not already been added. Each
+ * listener is used to detect different types of network change events.
+ *
+ * RadioStatusListener - Detects changes in cellular data coverage.
+ * WLANConnectionListener - Detects changes in wifi coverage.
+ * CoverageStatusListener - Used to detect changes in the mobile data config
+ *
+ * @param callbackId
+ * The reference point to call back when a listener event occurs.
+ */
+ private synchronized void addListeners(String callbackId) {
+ callbackIds.put(callbackId, callbackId);
+
+ if (radioListener == null) {
+ radioListener = new RadioStatusListener() {
+ public void baseStationChange() {}
+ public void networkScanComplete(boolean success) {}
+
+ public void networkServiceChange(int networkId, int service) {
+ // Cellular data change detected. If the user hasn't
+ // disabled mobile data and wifi is not currently in use
+ // return a result indicating the cellular data coverage
+ // change.
+ if (dataDisabled == Boolean.FALSE
+ && WLANInfo.getWLANState() != WLANInfo.WLAN_STATE_CONNECTED) {
+ if ((service & DATA) == 0) {
+ sendResult(TYPE_NONE, OFFLINE);
+ } else {
+ // In the case where cell data and wifi was turned
+ // off and then the user disabled mobile data
+ // configuration, the mobile data config disablement
+ // by the user isn't detected by the coverage status
+ // listener so dataDisabled may not be accurate.
+ // When service data is activated, have to make sure
+ // that dataDisabled is properly set.
+ setDataDisabled(CoverageInfo.getCoverageStatus(),
+ false);
+ if (dataDisabled == Boolean.FALSE) {
+ sendResult(getConnectionType(false, true),
+ ONLINE);
+ }
+ }
+ }
+ }
+
+ public void networkStarted(int networkId, int service) {}
+ public void networkStateChange(int state) {}
+ public void pdpStateChange(int apn, int state, int cause) {}
+ public void radioTurnedOff() {}
+ public void signalLevel(int level) {}
+ };
+ Application.getApplication().addRadioListener(radioListener);
+ }
+
+ if (wlanListener == null) {
+ wlanListener = new WLANConnectionListener() {
+ public void networkConnected() {
+ if (dataDisabled == Boolean.FALSE) {
+ sendResult(TYPE_WIFI, ONLINE);
+ }
+ }
+
+ public void networkDisconnected(int reason) {
+ // Wifi was disconnected, if the user hasn't disabled mobile
+ // data, check if cellular data coverage exists.
+ if (dataDisabled == Boolean.FALSE) {
+ String type = getConnectionType(false, true);
+ String event = OFFLINE;
+ if (!TYPE_NONE.equals(type)) {
+ event = ONLINE;
+ }
+ sendResult(type, event);
+ }
+ }
+ };
+ WLANInfo.addListener(wlanListener);
+ }
+
+ if (coverageListener == null) {
+ coverageListener = new CoverageStatusListener() {
+ public void coverageStatusChanged(int newCoverage) {
+ // When coverage changes, check to determine if it is due
+ // to the user disabling mobile data through configuration
+ // flag.
+ setDataDisabled(newCoverage, true);
+ }
+ };
+ CoverageInfo.addListener(coverageListener);
+ }
+ }
+
+ /**
+ * Determine the type of connection currently being used for data
+ * transmission on the device. If the user has disabled mobile data then
+ * TYPE_NONE is returned regardless of cellular or wifi radio state as this
+ * is the way the browser behaves. Otherwise, wifi and/or cellular radios
+ * are queried for state based on the passed in parameters.
+ *
+ * @param checkWLAN
+ * Determines whether wifi radio state is queried or not.
+ * @param checkCell
+ * Determines whether cellular radio state is queried or not.
+ * @return A string indicating one of the defined network connections types.
+ */
+ private String getConnectionType(boolean checkWLAN, boolean checkCell) {
+ String networkType = TYPE_NONE;
+
+ if (dataDisabled == Boolean.FALSE) {
+ // Detect if wifi is active and connected. If wifi is active it
+ // takes precedence over cellular data transmission.
+ if (checkWLAN
+ && WLANInfo.getWLANState() == WLANInfo.WLAN_STATE_CONNECTED) {
+ networkType = TYPE_WIFI;
+ }
+
+ if (checkCell && TYPE_NONE.equals(networkType)
+ && RadioInfo.isDataServiceOperational()) {
+
+ int activeServices = RadioInfo.getNetworkService();
+ networkType = TYPE_UNKNOWN;
+ if ((activeServices & THREE_G) != 0) {
+ networkType = TYPE_3G;
+ } else if ((activeServices & TWO_G) != 0) {
+ networkType = TYPE_2G;
+ }
+ }
+ }
+
+ return networkType;
+ }
+
+ /**
+ * Helper function to build and send the PluginResult to the saved call back
+ * IDs.
+ *
+ * @param type
+ * The network connection type. This value should be null if the
+ * specified event is "offline".
+ * @param event
+ * The network event.
+ */
+ private void sendResult(String type, String event) {
+
+ // Only send the event if it is different then the last sent event.
+ synchronized (prevType) {
+ if (prevType != null && prevEvent != null && prevType.equals(type)
+ && prevEvent.equals(event)) {
+ return;
+ } else {
+ prevType = type;
+ prevEvent = event;
+ }
+ }
+
+ PluginResult result = new PluginResult(PluginResult.Status.OK,
+ type);
+
+ // Must keep the call back active for future events.
+ result.setKeepCallback(true);
+
+ // Iterate through the saved call back IDs. Really should only ever be
+ // one.
+ for (Enumeration callbacks = this.callbackIds.elements(); callbacks
+ .hasMoreElements();) {
+ String callbackId = (String) callbacks.nextElement();
+ CordovaExtension.invokeSuccessCallback(callbackId, result);
+ }
+
+ }
+
+ /**
+ * Determines if the user has disabled mobile data through the user level
+ * configuration panels and optionally returns an "online" or "offline"
+ * result.
+ *
+ * @param newCoverage
+ * A bit mask of CoverageInfo.COVERAGE_* flags indicating the
+ * current coverage.
+ * @param returnResult
+ * If true, return a result based on the value of the mobile data
+ * configuration.
+ */
+ private void setDataDisabled(int newCoverage, boolean returnResult) {
+
+ boolean isRadioData = (RadioInfo.getNetworkService() & DATA) != 0;
+ boolean wlanConnected = WLANInfo.getWLANState() == WLANInfo.WLAN_STATE_CONNECTED;
+ boolean eventDetected = false;
+ String event = OFFLINE;
+
+ // Note: To detect that mobile data has been disabled through
+ // configuration, determine if the current coverage is
+ // CoverageInfo.COVERAGE_NONE AND that either cellular or wifi radios
+ // are currently connected. This is because the low level radio routines
+ // will return a connected state even when mobile data is disabled
+ // through configuration.
+ synchronized (dataDisabled) {
+ if (newCoverage == CoverageInfo.COVERAGE_NONE
+ && (isRadioData || wlanConnected)) {
+ if (dataDisabled == Boolean.FALSE) {
+ Logger.log("Mobile data was disabled by the user through configuration.");
+ dataDisabled = Boolean.TRUE;
+ eventDetected = true;
+ }
+ } else if (dataDisabled == Boolean.TRUE) {
+ Logger.log("Mobile data was enabled by the user.");
+ dataDisabled = Boolean.FALSE;
+ event = ONLINE;
+ eventDetected = true;
+ }
+ }
+
+ if (returnResult && eventDetected) {
+ // The user has enabled/disabled mobile data. Return a result
+ // indicating the current network state.
+ String type = getConnectionType(true, true);
+ sendResult(type, event);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/network/Network.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/network/Network.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/network/Network.java
new file mode 100644
index 0000000..86e5ac6
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/network/Network.java
@@ -0,0 +1,66 @@
+/*
+ * 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.network;
+
+import org.apache.cordova.api.Plugin;
+import org.apache.cordova.api.PluginResult;
+import org.apache.cordova.json4j.JSONArray;
+
+/**
+ * The Network command interface.
+ *
+ * The Network class can invoke the following actions:
+ *
+ * - getConnectionInfo(callback)
+ *
+ */
+public class Network extends Plugin {
+ // Supported actions
+ public static final String ACTION_CONNECTION_INFO = "getConnectionInfo";
+
+ private ConnectionInfoAction connectionInfo = new ConnectionInfoAction();
+
+ /**
+ * Executes the request and returns CommandResult.
+ *
+ * @param action The command to execute.
+ * @param callbackId The callback ID to be invoked upon action completion
+ * @param args JSONArry of arguments for the command.
+ * @return A CommandResult object with a status and message.
+ */
+ public PluginResult execute(String action, JSONArray args, String callbackId) {
+ PluginResult result = null;
+
+ if (action.equals(ACTION_CONNECTION_INFO)) {
+ result = connectionInfo.getConnectionInfo(callbackId);
+ }
+ else {
+ result = new PluginResult(PluginResult.Status.INVALID_ACTION, "Network: Invalid action: " + action);
+ }
+
+ return result;
+ }
+
+ /**
+ * Called when Plugin is destroyed.
+ */
+ public void onDestroy() {
+ connectionInfo.shutdown();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ActivityDialog.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ActivityDialog.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ActivityDialog.java
new file mode 100644
index 0000000..710f61e
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ActivityDialog.java
@@ -0,0 +1,146 @@
+/*
+ * 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.Bitmap;
+import net.rim.device.api.system.Characters;
+import net.rim.device.api.ui.UiApplication;
+import net.rim.device.api.ui.component.BitmapField;
+import net.rim.device.api.ui.component.LabelField;
+import net.rim.device.api.ui.component.SeparatorField;
+import net.rim.device.api.ui.container.HorizontalFieldManager;
+import net.rim.device.api.ui.container.PopupScreen;
+import net.rim.device.api.ui.container.VerticalFieldManager;
+
+/**
+ * A Popup activity dialog box with an optional title and message.
+ */
+public final class ActivityDialog extends PopupScreen {
+ private static ActivityDialog dialog = null;
+
+ /**
+ * Construct an activity dialog, with customizable title and message.
+ *
+ * @param title
+ * Title of the activity dialog
+ * @param message
+ * Message to print in the body of the dialog
+ */
+ private ActivityDialog(String title, String message) {
+ super(new VerticalFieldManager());
+
+ if (title != null && title.length() > 0) {
+ add(new LabelField(title));
+ add(new SeparatorField(SeparatorField.LINE_HORIZONTAL));
+ }
+ add(new SpacerField(0, 20));
+
+ HorizontalFieldManager hfm = new HorizontalFieldManager();
+
+ Bitmap hourglass = Bitmap.getPredefinedBitmap(Bitmap.HOURGLASS);
+
+ BitmapField bitmap = new BitmapField(hourglass);
+ hfm.add(bitmap);
+
+ if (message != null && message.length() > 0) {
+ hfm.add(new LabelField(message, FIELD_HCENTER | FIELD_VCENTER));
+ }
+
+ add(hfm);
+ add(new SpacerField(0, 20));
+ }
+
+ /**
+ * Creates and displays the activity 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 ActivityDialog(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 activity dialog.
+ *
+ * @return a PluginResult indicating success or error.
+ */
+ static synchronized PluginResult stop() {
+ if (dialog != null) {
+ final UiApplication uiApp = UiApplication.getUiApplication();
+ final ActivityDialog 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);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/AlertAction.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/AlertAction.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/AlertAction.java
new file mode 100644
index 0000000..c04a3cb
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/AlertAction.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.notification;
+
+import org.apache.cordova.api.PluginResult;
+import org.apache.cordova.json4j.JSONArray;
+import org.apache.cordova.json4j.JSONException;
+
+import net.rim.device.api.ui.UiApplication;
+
+/**
+ * Alert Action
+ *
+ * Displays and interacts with a dialog box.
+ *
+ */
+public class AlertAction {
+
+ private static final String DEFAULT_MESSAGE = "";
+ private static final String DEFAULT_TITLE = "Alert";
+ private static final String DEFAULT_BUTTON = "OK";
+
+ /**
+ * Displays a custom alert.
+ *
+ * @param args JSONArray formatted as [ message, title, buttonLabel ]
+ * message: the message to display in the dialog body (default: "").
+ * title: the title to display at the top of the dialog (default: "Alert").
+ * buttonLabel: the button text (default: "OK").
+ * @return A PluginResult object with the success or failure state for displaying the dialog box.
+ */
+ public static PluginResult execute(JSONArray args) {
+
+ PluginResult result = null;
+
+ try {
+ String message = DEFAULT_MESSAGE;
+ String title = DEFAULT_TITLE;
+ String buttonLabel = DEFAULT_BUTTON;
+ if (args.length() > 0 && !args.isNull(0))
+ message = args.getString(0);
+ if (args.length() > 1 && !args.isNull(1))
+ title = args.getString(1);
+ if (args.length() > 2 && !args.isNull(2))
+ buttonLabel = args.getString(2);
+
+ // construct the dialog
+ final AlertDialog dialog = new AlertDialog(message, title, buttonLabel);
+
+ // ask the event dispatch thread to show dialog
+ Runnable runnable = new Runnable() {
+ public void run() {
+ UiApplication ui = UiApplication.getUiApplication();
+ ui.pushModalScreen(dialog);
+ }
+ };
+ UiApplication.getUiApplication().invokeAndWait(runnable);
+
+ result = new PluginResult(PluginResult.Status.OK);
+ }
+ catch (JSONException e) {
+ result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, "JSONException: " + e.getMessage());
+ }
+
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/AlertDialog.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/AlertDialog.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/AlertDialog.java
new file mode 100644
index 0000000..a32666b
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/AlertDialog.java
@@ -0,0 +1,68 @@
+/*
+ * 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.ui.SpacerField;
+
+import net.rim.device.api.ui.Field;
+import net.rim.device.api.ui.FieldChangeListener;
+import net.rim.device.api.ui.component.ButtonField;
+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;
+
+public final class AlertDialog extends PopupScreen implements FieldChangeListener {
+
+ private ButtonField button;
+
+ /**
+ * Open a custom alert dialog, with a customizable title and button text.
+ *
+ * @param {String} message Message to print in the body of the alert
+ * @param {String} title Title of the alert dialog (default: 'Alert')
+ * @param {String} buttonLabel Label of the close button (default: 'OK')
+ */
+ public AlertDialog(String message, String title, String buttonLabel) {
+
+ super(new VerticalFieldManager());
+
+ // title
+ add(new LabelField(title));
+
+ // separator
+ add(new SeparatorField(SeparatorField.LINE_HORIZONTAL));
+
+ // message
+ add(new SpacerField(0, 20));
+ add(new LabelField(message, FIELD_HCENTER | FIELD_VCENTER));
+ add(new SpacerField(0, 20));
+
+ // button
+ button = new ButtonField(buttonLabel, ButtonField.CONSUME_CLICK | FIELD_HCENTER);
+ button.setChangeListener(this);
+ add(button);
+ }
+
+ public void fieldChanged(Field field, int context) {
+ if (button == field) {
+ close();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/BeepAction.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/BeepAction.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/BeepAction.java
new file mode 100644
index 0000000..b1c3658
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/BeepAction.java
@@ -0,0 +1,160 @@
+/*
+ * 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 java.io.IOException;
+
+import javax.microedition.media.Control;
+import javax.microedition.media.Manager;
+import javax.microedition.media.MediaException;
+import javax.microedition.media.Player;
+import javax.microedition.media.control.ToneControl;
+import javax.microedition.media.control.VolumeControl;
+
+import org.apache.cordova.CordovaExtension;
+import org.apache.cordova.api.PluginResult;
+import org.apache.cordova.json4j.JSONArray;
+import org.apache.cordova.json4j.JSONException;
+import org.apache.cordova.util.Logger;
+
+import net.rim.device.api.media.control.AudioPathControl;
+import net.rim.device.api.notification.NotificationsManager;
+import net.rim.device.api.system.Alert;
+
+/**
+ * Beep Action plays a device tone.
+ */
+public class BeepAction {
+
+ private static final int BEEP_VOLUME = 100;
+ private static final byte NOTE = 76; // E5
+ private static final byte D = 16; // quarter note
+ private static final byte tempo = 30; // 120 bpm
+
+ private static final byte[] TONE_SEQUENCE_START = {
+ ToneControl.VERSION, 1,
+ ToneControl.TEMPO, tempo
+ };
+
+ private static final byte[] TONE = {
+ NOTE,D, ToneControl.SILENCE,D/2
+ };
+
+ /**
+ * Beeps the device for a given number of times. By default, it will beep
+ * once. If the user explicitly sets the beep count to zero, it will play
+ * the applications notification profile. The application profile playback
+ * sequence is controlled by the user.
+ *
+ * @param args JSONArray formatted as [ count ]
+ * count: specifies the number of times to beep the device (default: 1).
+ * @return A CommandResult object with the success or failure
+ * state for beeping the device.
+ */
+ public static PluginResult execute(JSONArray args) {
+ PluginResult result = null;
+
+ if (Alert.isAudioSupported()) {
+
+ try {
+ int repeatCount = 1;
+ if (args.length() > 0 && !args.isNull(0)) {
+ repeatCount = args.getInt(0);
+ }
+
+ // play tone n times
+ if (repeatCount > 0) {
+ playTone(repeatCount);
+ }
+ // FIXME: unsupported on other platforms
+ // send notification event to application profile
+ else {
+ NotificationsManager.triggerImmediateEvent(
+ CordovaExtension.getAppID(), 0, null, null);
+ }
+ }
+ catch (JSONException e) {
+ Logger.log(BeepAction.class.getName() + ": " + e);
+ result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
+ }
+ catch (Exception e) {
+ Logger.log(BeepAction.class.getName() + ": " + e);
+ result = new PluginResult(PluginResult.Status.IO_EXCEPTION, e.getMessage());
+ }
+
+ result = new PluginResult(PluginResult.Status.OK);
+ }
+ else {
+ result = new PluginResult(PluginResult.Status.ILLEGAL_ACCESS_EXCEPTION, "Audio not supported");
+ }
+
+ return result;
+ }
+
+ /**
+ * Plays a tone the specified number of times on the device audio system.
+ * @param repeatCount number of times to play tone
+ */
+ private static void playTone(int repeatCount) throws MediaException, IOException {
+
+ // get tone player
+ Player p = Manager.createPlayer(Manager.TONE_DEVICE_LOCATOR);
+ p.realize();
+
+ // set tone sequence
+ ToneControl tc = (ToneControl)p.getControl("ToneControl");
+ tc.setSequence(getToneSequence(repeatCount));
+
+ // crank up the volume
+ VolumeControl vc = (VolumeControl)p.getControl("VolumeControl");
+ vc.setLevel(BEEP_VOLUME);
+
+ // route audio to speaker phone
+ p.prefetch();
+ Control[] c = p.getControls();
+ for(int i=c.length-1; i>=0; --i) {
+ if(c[i] instanceof AudioPathControl) {
+ AudioPathControl apc = (AudioPathControl)c[i];
+ apc.setAudioPath(AudioPathControl.AUDIO_PATH_HANDSFREE);
+ break;
+ }
+ }
+
+ // play
+ p.start();
+ }
+
+ /**
+ * Creates a tone sequence to play.
+ * @param repeatCount number of times to play tone
+ * @return tone sequence
+ */
+ private static byte[] getToneSequence(int repeatCount) {
+ // we have to build the sequence dynamically because
+ // ToneControl.REPEAT, repeatCount, TONE, DURATION
+ // doesn't seem to work
+ byte[] sequence = new byte[TONE_SEQUENCE_START.length + TONE.length * repeatCount];
+ System.arraycopy(TONE_SEQUENCE_START, 0, sequence, 0, TONE_SEQUENCE_START.length);
+ for (int i = 0; i < repeatCount; i++) {
+ System.arraycopy(TONE, 0, sequence, (TONE_SEQUENCE_START.length+TONE.length*i), TONE.length);
+ }
+
+ return sequence;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ConfirmAction.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ConfirmAction.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ConfirmAction.java
new file mode 100644
index 0000000..881ca0e
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ConfirmAction.java
@@ -0,0 +1,85 @@
+/*
+ * 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.util.Logger;
+
+import net.rim.device.api.ui.UiApplication;
+
+/**
+ * Displays a confirmation dialog with customizable title, message, and button
+ * fields.
+ */
+public class ConfirmAction {
+
+ private static final String DEFAULT_MESSAGE = "";
+ private static final String DEFAULT_TITLE = "Confirm";
+ private static final String DEFAULT_BUTTONS = "OK,Cancel";
+
+ /**
+ * Displays a custom confirmation dialog.
+ *
+ * @param args JSONArray formatted as [ message, title, buttonLabels ]
+ * message: the message to display in the dialog body (default: "").
+ * title: the title to display at the top of the dialog (default: "Confirm").
+ * buttonLabel: the button text (default: "OK,Cancel").
+ * @return A PluginResult object with index of dialog button pressed (1,2,3...).
+ */
+ public static PluginResult execute(JSONArray args) {
+
+ PluginResult result = null;
+
+ try {
+ String message = DEFAULT_MESSAGE;
+ String title = DEFAULT_TITLE;
+ String buttonLabels = DEFAULT_BUTTONS;
+ if (args.length() > 0 && !args.isNull(0))
+ message = args.getString(0);
+ if (args.length() > 1 && !args.isNull(1))
+ title = args.getString(1);
+ if (args.length() > 2 && !args.isNull(2))
+ buttonLabels = args.getString(2);
+
+ // construct the dialog
+ final ConfirmDialog dialog = new ConfirmDialog(message, title, buttonLabels);
+
+ // ask the event dispatch thread to show it
+ Runnable runnable = new Runnable() {
+ public void run() {
+ UiApplication ui = UiApplication.getUiApplication();
+ ui.pushModalScreen(dialog);
+ }
+ };
+ Logger.log(ConfirmAction.class.getName() + ": showing confirm dialog: '" + title + "'");
+ UiApplication.getUiApplication().invokeAndWait(runnable);
+
+ // add +1 to the button index to match the JavaScript API (which starts at 1)
+ int button = dialog.getSelectedValue() + 1;
+ result = new PluginResult(PluginResult.Status.OK, Integer.toString(button));
+ }
+ catch (JSONException e) {
+ result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, "JSONException: " + e.getMessage());
+ }
+
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ConfirmDialog.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ConfirmDialog.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ConfirmDialog.java
new file mode 100644
index 0000000..d19003c
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/ConfirmDialog.java
@@ -0,0 +1,100 @@
+/*
+ * 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.ui.SpacerField;
+import org.apache.cordova.util.StringUtils;
+
+import net.rim.device.api.ui.Field;
+import net.rim.device.api.ui.FieldChangeListener;
+import net.rim.device.api.ui.component.ButtonField;
+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;
+
+/**
+ * Creates a dialog box in which the title, message, and button labels are all
+ * customizable.
+ */
+public final class ConfirmDialog extends PopupScreen implements FieldChangeListener {
+
+ private ButtonField[] buttons; // the button fields
+ private int selectedValue = -1; // the selected button
+
+ /**
+ * Construct a confirmation dialog, with customizable title and button text.
+ *
+ * @param {String} message Message to print in the body of the alert
+ * @param {String} title Title of the alert dialog (default: 'Confirm')
+ * @param {String} buttonLabels Labels of the buttons (default: 'OK,Cancel')
+ */
+ public ConfirmDialog(String message, String title, String buttonLabels) {
+ super(new VerticalFieldManager());
+
+ // title
+ add(new LabelField(title));
+
+ // separator
+ add(new SeparatorField(SeparatorField.LINE_HORIZONTAL));
+
+ // message
+ add(new SpacerField(0, 20));
+ add(new LabelField(message, FIELD_HCENTER | FIELD_VCENTER));
+ add(new SpacerField(0, 20));
+
+ // parse the button labels
+ String[] labels = StringUtils.split(buttonLabels, ",");
+ buttons = new ButtonField[labels.length];
+
+ // add buttons
+ for (int i = 0; i < labels.length; i++) {
+ buttons[i] = new ButtonField(labels[i], ButtonField.CONSUME_CLICK | FIELD_HCENTER);
+ buttons[i].setChangeListener(this);
+ add(new SpacerField(0, 5));
+ add(buttons[i]);
+ }
+ }
+
+ /**
+ * Returns the index of the button pressed.
+ *
+ * @return The index of the button pressed (0,1,2...).
+ */
+ public int getSelectedValue() {
+ return this.selectedValue;
+ }
+
+ /**
+ * Invoked when a button is pressed.
+ */
+ public void fieldChanged(Field field, int context) {
+
+ // figure out which button was pressed
+ for (int i = 0; i < buttons.length; i++) {
+ if (buttons[i] == field) {
+ this.selectedValue = i;
+ break;
+ }
+ }
+
+ // close the dialog
+ close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/Notification.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/Notification.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/Notification.java
new file mode 100644
index 0000000..4183987
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/notification/Notification.java
@@ -0,0 +1,135 @@
+/*
+ * 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.CordovaExtension;
+import org.apache.cordova.api.Plugin;
+import org.apache.cordova.api.PluginResult;
+import org.apache.cordova.json4j.JSONArray;
+
+import net.rim.device.api.notification.NotificationsConstants;
+import net.rim.device.api.notification.NotificationsManager;
+
+/**
+ * Cordova Notification plugin.
+ *
+ * The Notification plugin can invoke the following actions:
+ *
+ * - alert(message, title, buttonLabel)
+ * - confirm(message, title, button1,button2,button3...)
+ * - beep(count)
+ * - vibrate(duration)
+ * - progressStart(title, message)
+ * - progressStop()
+ * - progressValue(value)
+ * - activityStart(title, message)
+ * - activityStop()
+ */
+public class Notification extends Plugin {
+
+ /**
+ * Possible actions
+ */
+ private static final String ACTION_ALERT = "alert";
+ private static final String ACTION_BEEP = "beep";
+ private static final String ACTION_CONFIRM = "confirm";
+ private static final String ACTION_VIBRATE = "vibrate";
+ private static final String ACTION_PROGRESS_START = "progressStart";
+ private static final String ACTION_PROGRESS_STOP = "progressStop";
+ private static final String ACTION_PROGRESS_VALUE = "progressValue";
+ private static final String ACTION_ACTIVITY_START = "activityStart";
+ private static final String ACTION_ACTIVITY_STOP = "activityStop";
+
+ /**
+ * Creates a notification profile for the application on the device. The
+ * application can trigger a notification event that will play the profile.
+ * The profile settings are set by the user.
+ */
+ public static void registerProfile() {
+ // Register with the NotificationsManager to create a notification
+ // profile for this application and enable notifications to be
+ // controlled by the user
+ Object object = new Object() {
+ private String appName = CordovaExtension.getAppName();
+
+ public String toString() {
+ return appName;
+ }
+ };
+ NotificationsManager.registerSource(CordovaExtension.getAppID(),
+ object, NotificationsConstants.IMPORTANT);
+ }
+
+ /**
+ * Executes the request and returns CommandResult.
+ *
+ * @param action
+ * The action to perform.
+ * @param callbackId
+ * The callback ID to be invoked upon action completion
+ * @param args
+ * JSONArry of arguments for the specified action.
+ * @return A PluginResult object with a status and message.
+ */
+ public PluginResult execute(String action, JSONArray args, String callbackId) {
+ PluginResult result = null;
+
+ if (ACTION_ALERT.equals(action)) {
+ result = AlertAction.execute(args);
+ } else if (ACTION_BEEP.equals(action)) {
+ result = BeepAction.execute(args);
+ } else if (ACTION_CONFIRM.equals(action)) {
+ result = ConfirmAction.execute(args);
+ } else if (ACTION_VIBRATE.equals(action)) {
+ result = VibrateAction.execute(args);
+ } else if (ACTION_ACTIVITY_START.equals(action)) {
+ result = ActivityDialog.start(args);
+ } else if (ACTION_ACTIVITY_STOP.equals(action)) {
+ result = ActivityDialog.stop();
+ } else if (ACTION_PROGRESS_START.equals(action)) {
+ result = ProgressDialog.start(args);
+ } else if (ACTION_PROGRESS_STOP.equals(action)) {
+ result = ProgressDialog.stop();
+ } else if (ACTION_PROGRESS_VALUE.equals(action)) {
+ result = ProgressDialog.setValue(args);
+ } else {
+ result = new PluginResult(PluginResult.Status.INVALID_ACTION,
+ "Notification: Invalid action: " + action);
+ }
+
+ return result;
+ }
+
+ /**
+ * 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 (ACTION_ALERT.equals(action) || ACTION_CONFIRM.equals(action)) {
+ return false;
+ }
+
+ return true;
+ }
+
+}