Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' of git://github.com/filmaj/phonegap

  • Loading branch information...
commit 4dbf8ad379c08b20c609cbc33e7f84b58fe59990 2 parents 49f827c + d36b7ba
shazron authored
Showing with 2,196 additions and 325 deletions.
  1. +3 −9 .gitignore
  2. +4 −0 blackberry/.gitignore
  3. +14 −60 blackberry/phonegap.jdp
  4. +218 −60 blackberry/src/com/nitobi/phonegap/PhoneGap.java
  5. +7 −5 blackberry/src/com/nitobi/phonegap/api/CommandManager.java
  6. +4 −7 blackberry/src/com/nitobi/phonegap/api/impl/CameraCommand.java
  7. +212 −22 blackberry/src/com/nitobi/phonegap/api/impl/ContactsCommand.java
  8. +74 −0 blackberry/src/com/nitobi/phonegap/api/impl/DeviceCommand.java
  9. +22 −7 blackberry/src/com/nitobi/phonegap/api/impl/GeoLocationCommand.java
  10. +94 −0 blackberry/src/com/nitobi/phonegap/api/impl/MediaCommand.java
  11. +106 −0 blackberry/src/com/nitobi/phonegap/api/impl/NotificationCommand.java
  12. +1 −4 blackberry/src/com/nitobi/phonegap/api/impl/TelephonyCommand.java
  13. +2 −4 blackberry/src/com/nitobi/phonegap/io/AsynchronousResourceFetcher.java
  14. +101 −13 blackberry/src/com/nitobi/phonegap/io/ConnectionManager.java
  15. +38 −0 blackberry/src/com/nitobi/phonegap/io/PrimaryResourceFetchThread.java
  16. +169 −0 blackberry/src/com/nitobi/phonegap/io/SecondaryResourceFetchThread.java
  17. +1 −1  blackberry/src/com/nitobi/phonegap/model/Position.java
  18. +1 −0  blackberry/src/www/css/test.css
  19. +9 −4 blackberry/src/www/js/camera.js
  20. +82 −17 blackberry/src/www/js/contacts.js
  21. +9 −11 blackberry/src/www/js/device.js
  22. +7 −8 blackberry/src/www/js/geolocation.js
  23. +5 −0 blackberry/src/www/js/media.js
  24. +8 −0 blackberry/src/www/js/notification.js
  25. +11 −14 blackberry/src/www/js/position.js
  26. +1 −1  blackberry/src/www/js/telephony.js
  27. BIN  blackberry/src/www/media/bird.mp3
  28. BIN  blackberry/src/www/media/percBass2.wav
  29. +3 −1 blackberry/src/www/test/camera.html
  30. +36 −11 blackberry/src/www/test/contacts.html
  31. +2 −1  blackberry/src/www/test/device.html
  32. +5 −2 blackberry/src/www/test/index.html
  33. +7 −15 blackberry/src/www/test/location.html
  34. +17 −0 blackberry/src/www/test/media.html
  35. +18 −0 blackberry/src/www/test/notification.html
  36. +0 −19 blackberry/src/www/test/vibration.html
  37. +30 −0 javascripts/blackberry/camera.js
  38. +56 −0 javascripts/blackberry/contacts.js
  39. +31 −0 javascripts/blackberry/device.js
  40. +75 −29 javascripts/blackberry/geolocation.js
  41. +5 −0 javascripts/blackberry/media.js
  42. +8 −0 javascripts/blackberry/notification.js
  43. +72 −0 javascripts/blackberry/position.js
  44. +18 −0 javascripts/blackberry/telephony.js
  45. +12 −0 winmo/Command.cs
  46. +30 −0 winmo/CommandManager.cs
  47. +148 −0 winmo/InitializationCommand.cs
  48. +91 −0 winmo/MediaCommand.cs
  49. +16 −0 winmo/Program.cs
  50. +66 −0 winmo/WebForm.Designer.cs
  51. +61 −0 winmo/WebForm.cs
  52. +129 −0 winmo/WebForm.resx
  53. +32 −0 winmo/www/index.html
  54. +20 −0 winmo/www/js/device.js
  55. +5 −0 winmo/www/js/media.js
  56. BIN  winmo/www/media/applause.wav
  57. BIN  winmo/www/media/bird.mp3
View
12 .gitignore
@@ -1,9 +1,3 @@
-.DS_Store
-.*.sw?
-*.cso
-tmp/
-*.xcodeproj/* !*.xcodeproj/project.pbxproj
-lib/iphone/phonegap-min.js
-lib/iphone/phonegap.js
-android/bin
-android/gen
+android/default.properties
+android/bin/*
+android/gen/*
View
4 blackberry/.gitignore
@@ -0,0 +1,4 @@
+.tmp
+.settings
+bin/*
+.project.old
View
74 blackberry/phonegap.jdp
@@ -21,80 +21,35 @@ AutoRestart=0
]
ExcludeFromBuildAll=0
[Files
-..\..\..\..\workspace_blackberry\phonegap\src\0.png
-..\..\..\..\workspace_blackberry\phonegap\src\1.png
-..\..\..\..\workspace_blackberry\phonegap\src\2.png
-..\..\..\..\workspace_blackberry\phonegap\src\3.png
-..\..\..\..\workspace_blackberry\phonegap\src\4.png
-..\..\..\..\workspace_blackberry\phonegap\src\5.png
-..\..\..\..\workspace_blackberry\phonegap\src\camera.html
-..\..\..\..\workspace_blackberry\phonegap\src\camera.js
-..\..\..\..\workspace_blackberry\phonegap\src\com\nitobi\phonegap\api\Command.java
-..\..\..\..\workspace_blackberry\phonegap\src\com\nitobi\phonegap\api\CommandManager.java
-..\..\..\..\workspace_blackberry\phonegap\src\com\nitobi\phonegap\api\impl\CameraCommand.java
-..\..\..\..\workspace_blackberry\phonegap\src\com\nitobi\phonegap\api\impl\ContactsCommand.java
-..\..\..\..\workspace_blackberry\phonegap\src\com\nitobi\phonegap\api\impl\GeoLocationCommand.java
-..\..\..\..\workspace_blackberry\phonegap\src\com\nitobi\phonegap\api\impl\InitializationCommand.java
-..\..\..\..\workspace_blackberry\phonegap\src\com\nitobi\phonegap\api\impl\TelephonyCommand.java
-..\..\..\..\workspace_blackberry\phonegap\src\com\nitobi\phonegap\api\impl\VibrationCommand.java
-..\..\..\..\workspace_blackberry\phonegap\src\com\nitobi\phonegap\io\AsynchronousResourceFetcher.java
-..\..\..\..\workspace_blackberry\phonegap\src\com\nitobi\phonegap\io\Callback.java
-..\..\..\..\workspace_blackberry\phonegap\src\com\nitobi\phonegap\io\ConnectionManager.java
-..\..\..\..\workspace_blackberry\phonegap\src\com\nitobi\phonegap\io\QueueResourceFetcher.java
-..\..\..\..\workspace_blackberry\phonegap\src\com\nitobi\phonegap\model\Position.java
-..\..\..\..\workspace_blackberry\phonegap\src\com\nitobi\phonegap\PhoneGap.java
-..\..\..\..\workspace_blackberry\phonegap\src\contacts.html
-..\..\..\..\workspace_blackberry\phonegap\src\contacts.js
-..\..\..\..\workspace_blackberry\phonegap\src\device.html
-..\..\..\..\workspace_blackberry\phonegap\src\device.js
-..\..\..\..\workspace_blackberry\phonegap\src\geolocation.js
-..\..\..\..\workspace_blackberry\phonegap\src\index.html
-..\..\..\..\workspace_blackberry\phonegap\src\io.html
-..\..\..\..\workspace_blackberry\phonegap\src\location.html
-..\..\..\..\workspace_blackberry\phonegap\src\position.js
-..\..\..\..\workspace_blackberry\phonegap\src\telephony.html
-..\..\..\..\workspace_blackberry\phonegap\src\telephony.js
-..\..\..\..\workspace_blackberry\phonegap\src\vibration.html
-..\..\..\..\workspace_blackberry\phonegap\src\www\js\camera.js
-..\..\..\..\workspace_blackberry\phonegap\src\www\js\contacts.js
-..\..\..\..\workspace_blackberry\phonegap\src\www\js\device.js
-..\..\..\..\workspace_blackberry\phonegap\src\www\js\geolocation.js
-..\..\..\..\workspace_blackberry\phonegap\src\www\js\position.js
-..\..\..\..\workspace_blackberry\phonegap\src\www\js\telephony.js
-..\..\..\..\workspace_blackberry\phonegap\src\www\test\camera.html
-..\..\..\..\workspace_blackberry\phonegap\src\www\test\contacts.html
-..\..\..\..\workspace_blackberry\phonegap\src\www\test\device.html
-..\..\..\..\workspace_blackberry\phonegap\src\www\test\images\0.png
-..\..\..\..\workspace_blackberry\phonegap\src\www\test\images\1.png
-..\..\..\..\workspace_blackberry\phonegap\src\www\test\images\2.png
-..\..\..\..\workspace_blackberry\phonegap\src\www\test\images\3.png
-..\..\..\..\workspace_blackberry\phonegap\src\www\test\images\4.png
-..\..\..\..\workspace_blackberry\phonegap\src\www\test\images\5.png
-..\..\..\..\workspace_blackberry\phonegap\src\www\test\index.html
-..\..\..\..\workspace_blackberry\phonegap\src\www\test\io.html
-..\..\..\..\workspace_blackberry\phonegap\src\www\test\location.html
-..\..\..\..\workspace_blackberry\phonegap\src\www\test\telephony.html
-..\..\..\..\workspace_blackberry\phonegap\src\www\test\vibration.html
src\com\nitobi\phonegap\api\Command.java
src\com\nitobi\phonegap\api\CommandManager.java
src\com\nitobi\phonegap\api\impl\CameraCommand.java
src\com\nitobi\phonegap\api\impl\ContactsCommand.java
+src\com\nitobi\phonegap\api\impl\DeviceCommand.java
src\com\nitobi\phonegap\api\impl\GeoLocationCommand.java
-src\com\nitobi\phonegap\api\impl\InitializationCommand.java
+src\com\nitobi\phonegap\api\impl\MediaCommand.java
+src\com\nitobi\phonegap\api\impl\NotificationCommand.java
src\com\nitobi\phonegap\api\impl\TelephonyCommand.java
-src\com\nitobi\phonegap\api\impl\VibrationCommand.java
src\com\nitobi\phonegap\io\AsynchronousResourceFetcher.java
src\com\nitobi\phonegap\io\Callback.java
src\com\nitobi\phonegap\io\ConnectionManager.java
+src\com\nitobi\phonegap\io\HttpConnection.java
+src\com\nitobi\phonegap\io\PrimaryResourceFetchThread.java
src\com\nitobi\phonegap\io\QueueResourceFetcher.java
+src\com\nitobi\phonegap\io\SecondaryResourceFetchThread.java
src\com\nitobi\phonegap\model\Position.java
src\com\nitobi\phonegap\PhoneGap.java
+src\www\css\test.css
src\www\js\camera.js
src\www\js\contacts.js
src\www\js\device.js
src\www\js\geolocation.js
+src\www\js\media.js
+src\www\js\notification.js
src\www\js\position.js
src\www\js\telephony.js
+src\www\media\bird.mp3
+src\www\media\percBass2.wav
src\www\test\camera.html
src\www\test\contacts.html
src\www\test\device.html
@@ -107,8 +62,9 @@ src\www\test\images\5.png
src\www\test\index.html
src\www\test\io.html
src\www\test\location.html
+src\www\test\media.html
+src\www\test\notification.html
src\www\test\telephony.html
-src\www\test\vibration.html
]
HaveAlxImports=0
HaveDefs=0
@@ -120,9 +76,8 @@ HaveImports=0
[Imports
]
Listing=0
-MidletClass=data:///www/test/index.html
Options=-quiet
-OutputFileName=phonegap
+OutputFileName=PhoneGapBB
[PackageProtection
]
RibbonPosition=0
@@ -131,6 +86,5 @@ RibbonPosition=0
RunOnStartup=0
StartupTier=7
SystemModule=0
-Title=PhoneGap
Type=0
UserData=|src
View
278 blackberry/src/com/nitobi/phonegap/PhoneGap.java
@@ -22,46 +22,51 @@
*/
package com.nitobi.phonegap;
+import java.io.IOException;
import java.util.Vector;
import javax.microedition.io.HttpConnection;
import net.rim.device.api.browser.field.BrowserContent;
-import net.rim.device.api.browser.field.BrowserContentManager;
+import net.rim.device.api.browser.field.BrowserContentChangedEvent;
import net.rim.device.api.browser.field.Event;
import net.rim.device.api.browser.field.RedirectEvent;
import net.rim.device.api.browser.field.RenderingApplication;
+import net.rim.device.api.browser.field.RenderingException;
import net.rim.device.api.browser.field.RenderingOptions;
+import net.rim.device.api.browser.field.RenderingSession;
import net.rim.device.api.browser.field.RequestedResource;
+import net.rim.device.api.browser.field.SetHttpCookieEvent;
import net.rim.device.api.browser.field.UrlRequestedEvent;
+import net.rim.device.api.io.http.HttpHeaders;
+import net.rim.device.api.system.Application;
import net.rim.device.api.system.Display;
-import net.rim.device.api.ui.Screen;
+import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.UiApplication;
+import net.rim.device.api.ui.component.Status;
import net.rim.device.api.ui.container.MainScreen;
import com.nitobi.phonegap.api.CommandManager;
-import com.nitobi.phonegap.io.AsynchronousResourceFetcher;
-import com.nitobi.phonegap.io.Callback;
import com.nitobi.phonegap.io.ConnectionManager;
-import com.nitobi.phonegap.io.QueueResourceFetcher;
+import com.nitobi.phonegap.io.PrimaryResourceFetchThread;
+import com.nitobi.phonegap.io.SecondaryResourceFetchThread;
/**
* Bridges HTML/JS/CSS to a native Blackberry application.
- *
* @author Jose Noheda
- *
+ * @author Fil Maj
+ * @author Dave Johnson
*/
public class PhoneGap extends UiApplication implements RenderingApplication {
- public static final String PHONEGAP_PROTOCOL = "gap://";
+ public static final String PHONEGAP_PROTOCOL = "PhoneGap=";
private static final String DEFAULT_INITIAL_URL = "data:///www/test/index.html";
-
- private Screen mainScreen;
+ private static final String REFERER = "referer";
private Vector pendingResponses = new Vector();
- private QueueResourceFetcher queueResourceFetcher;
private CommandManager commandManager = new CommandManager();
- private ConnectionManager connectionManager = new ConnectionManager();
- private BrowserContentManager _browserContentManager = new BrowserContentManager(0);
+ private RenderingSession _renderingSession;
+ public HttpConnection _currentConnection;
+ private MainScreen _mainScreen;
/**
* Launches the application. Accepts up to one parameter, an URL to the index page.
@@ -88,49 +93,120 @@ public PhoneGap(final String url) {
}
private void init(final String url) {
- RenderingOptions renderingOptions = _browserContentManager.getRenderingSession().getRenderingOptions();
- renderingOptions.setProperty(RenderingOptions.CORE_OPTIONS_GUID, RenderingOptions.JAVASCRIPT_ENABLED, true);
- renderingOptions.setProperty(RenderingOptions.CORE_OPTIONS_GUID, RenderingOptions.JAVASCRIPT_LOCATION_ENABLED, true);
- // The following line is commented out for now, until we figure out how to use this rendering mode properly.
- //renderingOptions.setProperty(RenderingOptions.CORE_OPTIONS_GUID, 17000, true);
- mainScreen = new MainScreen();
- mainScreen.add(_browserContentManager);
- pushScreen(mainScreen);
- queueResourceFetcher = new QueueResourceFetcher(this, connectionManager);
- loadUrl(url);
- invokeLater(queueResourceFetcher);
- }
-
- private void loadUrl(String url) {
- invokeAndWait(new AsynchronousResourceFetcher(url, new Callback() {
- public void execute(final Object input) {
- // setContent here causes Blackberry to freeze - leads to two calls: handleNewContent and finishLoading.
- // finishLoading then calls Object.wait(), which is likely the cause for the freeze? Help!
- _browserContentManager.setContent((HttpConnection) input, PhoneGap.this, null);
- }
- }, connectionManager));
- }
-
- public Object eventOccurred(final Event event) {
- if (event instanceof RedirectEvent) {
- RedirectEvent command = (RedirectEvent) event;
- String url = command.getLocation();
- if (url.startsWith(PHONEGAP_PROTOCOL)) {
- String response = commandManager.processInstruction(url);
- if ((response != null) && (response.trim().length() > 0)) pendingResponses.addElement(response);
- }
- }
- if (event instanceof UrlRequestedEvent) {
- final String url = ((UrlRequestedEvent) event).getURL();
- new Thread(new AsynchronousResourceFetcher(url, new Callback() {
- public void execute(final Object input) {
- _browserContentManager.setContent((HttpConnection) input, PhoneGap.this, null);
- }
- }, connectionManager)).start();
- }
- return null;
+ _mainScreen = new MainScreen();
+ pushScreen(_mainScreen);
+ _renderingSession = RenderingSession.getNewInstance();
+
+ // Enable JavaScript.
+ _renderingSession.getRenderingOptions().setProperty(RenderingOptions.CORE_OPTIONS_GUID, RenderingOptions.JAVASCRIPT_ENABLED, true);
+ _renderingSession.getRenderingOptions().setProperty(RenderingOptions.CORE_OPTIONS_GUID, RenderingOptions.JAVASCRIPT_LOCATION_ENABLED, true);
+ // Enable nice-looking BB browser field.
+ _renderingSession.getRenderingOptions().setProperty(RenderingOptions.CORE_OPTIONS_GUID, 17000, true);
+ PrimaryResourceFetchThread thread = new PrimaryResourceFetchThread(url, null, null, null, this);
+ thread.start();
}
+ public Object eventOccurred(final Event event)
+ {
+ int eventId = event.getUID();
+ switch (eventId)
+ {
+ case Event.EVENT_REDIRECT :
+ {
+ RedirectEvent e = (RedirectEvent) event;
+ String url = e.getLocation();
+ String referrer = e.getSourceURL();
+ switch (e.getType())
+ {
+ case RedirectEvent.TYPE_SINGLE_FRAME_REDIRECT :
+ // Show redirect message.
+ Application.getApplication().invokeAndWait(new Runnable()
+ {
+ public void run()
+ {
+ Status.show("You are being redirected to a different page...");
+ }
+ });
+ break;
+
+ case RedirectEvent.TYPE_JAVASCRIPT :
+ String test = "test";
+ break;
+
+ case RedirectEvent.TYPE_META :
+ // MSIE and Mozilla don't send a Referer for META Refresh.
+ referrer = null;
+ break;
+
+ case RedirectEvent.TYPE_300_REDIRECT :
+ // MSIE, Mozilla, and Opera all send the original
+ // request's Referer as the Referer for the new
+ // request.
+ Object eventSource = e.getSource();
+ if (eventSource instanceof HttpConnection)
+ {
+ referrer = ((HttpConnection)eventSource).getRequestProperty(REFERER);
+ }
+
+ break;
+ }
+ HttpHeaders requestHeaders = new HttpHeaders();
+ requestHeaders.setProperty(REFERER, referrer);
+ PrimaryResourceFetchThread thread = new PrimaryResourceFetchThread(e.getLocation(), requestHeaders,null, event, this);
+ thread.start();
+ break;
+ }
+ case Event.EVENT_URL_REQUESTED :
+ {
+ UrlRequestedEvent urlRequestedEvent = (UrlRequestedEvent) event;
+ String url = urlRequestedEvent.getURL();
+ HttpHeaders header = urlRequestedEvent.getHeaders();
+ PrimaryResourceFetchThread thread = new PrimaryResourceFetchThread(
+ url, header, urlRequestedEvent.getPostData(), event, this);
+ thread.start();
+ break;
+ }
+ case Event.EVENT_BROWSER_CONTENT_CHANGED:
+ {
+ // Browser field title might have changed update title.
+ BrowserContentChangedEvent browserContentChangedEvent = (BrowserContentChangedEvent) event;
+ if (browserContentChangedEvent.getSource() instanceof BrowserContent)
+ {
+ BrowserContent browserField = (BrowserContent) browserContentChangedEvent.getSource();
+ String newTitle = browserField.getTitle();
+ if (newTitle != null)
+ {
+ synchronized (getAppEventLock())
+ {
+ _mainScreen.setTitle(newTitle);
+ }
+ }
+ }
+ break;
+ }
+ case Event.EVENT_CLOSE :
+ // TODO: close the application
+ break;
+
+ case Event.EVENT_SET_HEADER : // No cache support.
+ case Event.EVENT_SET_HTTP_COOKIE :
+ String cookie = ((SetHttpCookieEvent) event).getCookie();
+ if (cookie.startsWith(PHONEGAP_PROTOCOL)) {
+ String response = commandManager.processInstruction(cookie);
+ if ((response != null) && (response.trim().length() > 0)) pendingResponses.addElement(response);
+ }
+ break;
+ case Event.EVENT_HISTORY : // No history support.
+ case Event.EVENT_EXECUTING_SCRIPT : // No progress bar is supported.
+ case Event.EVENT_FULL_WINDOW : // No full window support.
+ case Event.EVENT_STOP : // No stop loading support.
+ default :
+ }
+ return null;
+ }
+ /**
+ * Catch the 'get' cookie event, aggregate PhoneGap API responses that haven't been flushed and return.
+ */
public String getHTTPCookie(String url) {
StringBuffer responseCode = new StringBuffer();
synchronized (pendingResponses) {
@@ -156,16 +232,98 @@ public int getHistoryPosition(BrowserContent browserContent) {
public HttpConnection getResource(RequestedResource resource, BrowserContent referrer) {
if ((resource != null) && (resource.getUrl() != null) && !resource.isCacheOnly()) {
String url = resource.getUrl().trim();
- if ((referrer == null) || (connectionManager.isInternal(url)))
- return connectionManager.getUnmanagedConnection(url);
+ if ((referrer == null) || (ConnectionManager.isInternal(url)))
+ return ConnectionManager.getUnmanagedConnection(url, resource.getRequestHeaders(), null);
else
- queueResourceFetcher.enqueue(resource, referrer);
+ SecondaryResourceFetchThread.enqueue(resource, referrer);
}
return null;
}
+ /**
+ * Processes a new HttpConnection object to instantiate a new browser Field (aka WebView) object, and then resets the screen to the newly-created Field.
+ * @param connection
+ * @param e
+ */
+ public void processConnection(HttpConnection connection, Event e)
+ {
+ // Cancel previous request.
+ if (_currentConnection != null)
+ {
+ try
+ {
+ _currentConnection.close();
+ }
+ catch (IOException e1)
+ {
+ }
+ }
+ _currentConnection = connection;
+ BrowserContent browserContent = null;
+ try
+ {
+ browserContent = _renderingSession.getBrowserContent(connection, this, e);
+ if (browserContent != null)
+ {
+ Field field = browserContent.getDisplayableContent();
+ if (field != null)
+ {
+ synchronized (Application.getEventLock())
+ {
+ _mainScreen.deleteAll();
+ _mainScreen.add(field);
+ }
+ }
+
+ browserContent.finishLoading();
+ }
+ }
+ catch (RenderingException re)
+ {
+ }
+ }
+ public void invokeRunnable(Runnable runnable)
+ {
+ (new Thread(runnable)).start();
+ }
+ public static final String[] splitString(final String data, final char splitChar, final boolean allowEmpty)
+ {
+ Vector v = new Vector();
- public void invokeRunnable(Runnable runnable) {
- invokeLater(runnable);
- }
+ int indexStart = 0;
+ int indexEnd = data.indexOf(splitChar);
+ if (indexEnd != -1)
+ {
+ while (indexEnd != -1)
+ {
+ String s = data.substring(indexStart, indexEnd);
+ if (allowEmpty || s.length() > 0)
+ {
+ v.addElement(s);
+ }
+ indexStart = indexEnd + 1;
+ indexEnd = data.indexOf(splitChar, indexStart);
+ }
+
+ if (indexStart != data.length())
+ {
+ // Add the rest of the string
+ String s = data.substring(indexStart);
+ if (allowEmpty || s.length() > 0)
+ {
+ v.addElement(s);
+ }
+ }
+ }
+ else
+ {
+ if (allowEmpty || data.length() > 0)
+ {
+ v.addElement(data);
+ }
+ }
+ String[] result = new String[v.size()];
+ v.copyInto(result);
+ return result;
+ }
}
View
12 blackberry/src/com/nitobi/phonegap/api/CommandManager.java
@@ -24,10 +24,11 @@
import com.nitobi.phonegap.api.impl.CameraCommand;
import com.nitobi.phonegap.api.impl.ContactsCommand;
+import com.nitobi.phonegap.api.impl.DeviceCommand;
import com.nitobi.phonegap.api.impl.GeoLocationCommand;
-import com.nitobi.phonegap.api.impl.InitializationCommand;
+import com.nitobi.phonegap.api.impl.MediaCommand;
+import com.nitobi.phonegap.api.impl.NotificationCommand;
import com.nitobi.phonegap.api.impl.TelephonyCommand;
-import com.nitobi.phonegap.api.impl.VibrationCommand;
/**
* Given a execution request detects matching {@link Command} and executes it.
@@ -38,15 +39,16 @@
public final class CommandManager {
// List of installed Commands
- private Command[] commands = new Command[6];
+ private Command[] commands = new Command[7];
public CommandManager() {
commands[0] = new CameraCommand();
commands[1] = new ContactsCommand();
- commands[2] = new VibrationCommand();
+ commands[2] = new NotificationCommand();
commands[3] = new TelephonyCommand();
commands[4] = new GeoLocationCommand();
- commands[5] = new InitializationCommand();
+ commands[5] = new DeviceCommand();
+ commands[6] = new MediaCommand();
}
/**
View
11 blackberry/src/com/nitobi/phonegap/api/impl/CameraCommand.java
@@ -35,7 +35,7 @@
import com.nitobi.phonegap.api.Command;
/**
- * Switchs current application to the camera to take a photo.
+ * Switches current application to the camera to take a photo.
*
* @author Jose Noheda
*
@@ -44,7 +44,8 @@
private static final int INVOKE_COMMAND = 0;
private static final int PICTURE_COMMAND = 1;
- private static final String CODE = "gap://camera";
+ private static final String CODE = "PhoneGap=camera";
+ //private static final String
private long lastUSN = 0;
private String photoPath;
@@ -70,10 +71,6 @@ public void fileJournalChanged() {
}
};
}
-
- /**
- * Able to run the <i>camera</i> command. Ex: gap://camera/obtain
- */
public boolean accept(String instruction) {
return instruction != null && instruction.startsWith(CODE);
}
@@ -85,7 +82,7 @@ public String execute(String instruction) {
switch (getCommand(instruction)) {
case PICTURE_COMMAND:
UiApplication.getUiApplication().removeFileSystemJournalListener(listener);
- return "navigator.camera.picture = '" + photoPath + "'";
+ return ";navigator.camera.picture = '" + photoPath + "';";
case INVOKE_COMMAND:
photoPath = null;
UiApplication.getUiApplication().addFileSystemJournalListener(listener);
View
234 blackberry/src/com/nitobi/phonegap/api/impl/ContactsCommand.java
@@ -23,29 +23,34 @@
package com.nitobi.phonegap.api.impl;
import java.util.Enumeration;
+import java.util.Hashtable;
import javax.microedition.pim.Contact;
import javax.microedition.pim.PIM;
-
+import javax.microedition.pim.PIMException;
import net.rim.blackberry.api.pdap.BlackBerryContact;
import net.rim.blackberry.api.pdap.BlackBerryContactList;
+import com.nitobi.phonegap.PhoneGap;
import com.nitobi.phonegap.api.Command;
/**
* Finds data in agenda.
*
* @author Jose Noheda
+ * @author Fil Maj
*
*/
public class ContactsCommand implements Command {
private static final int SEARCH_COMMAND = 0;
- private static final String CODE = "gap://contacts";
+ private static final int GET_ALL_COMMAND = 1;
+ private static final int CHOOSE_COMMAND = 2;
+ private static final int REMOVE_COMMAND = 3;
+ private static final int NEW_COMMAND = 4;
+ private static final String CODE = "PhoneGap=contacts";
+ private static final String CONTACT_MANAGER_JS_NAMESPACE = "navigator.ContactManager";
- /**
- * Able to run the <i>call</i> command. Ex: gap://contacts/search/name/Joe
- */
public boolean accept(String instruction) {
return instruction != null && instruction.startsWith(CODE);
}
@@ -54,39 +59,224 @@ public boolean accept(String instruction) {
* Invokes internal phone application.
*/
public String execute(String instruction) {
+ Hashtable options = ContactsCommand.parseParameters(instruction);
switch (getCommand(instruction)) {
case SEARCH_COMMAND:
- return "navigator.ContactManager.contacts = navigator.ContactManager.contacts.concat(" + getAgendaByName("Joe") + ");";
+ return getAgenda(options);
+ case GET_ALL_COMMAND:
+ return getAgenda(options);
+ case CHOOSE_COMMAND:
+ return chooseContact();
+ case REMOVE_COMMAND:
+ return removeContact(options);
+ case NEW_COMMAND:
+ return newContact(options);
}
return null;
}
-
+ /**
+ * Parses the options object and returns a hash of params.
+ * @param instruction The cookie/string representation of the instruction.
+ * @return Hashtable Hash of key:value pairs containing the parameter names & values.
+ */
+ private static Hashtable parseParameters(String instruction) {
+ String[] params = PhoneGap.splitString(instruction, '/', false);
+ int numParams = params.length;
+ Hashtable hash = new Hashtable();
+ for (int i = 0; i < numParams; i++) {
+ String curParam = params[i];
+ if (curParam.indexOf(':') == -1) continue;
+ String[] key_value = PhoneGap.splitString(curParam, ':', false);
+ if (key_value.length < 2) continue;
+ String key = key_value[0];
+ String value = key_value[1];
+ hash.put(key, value);
+ }
+ return hash;
+ }
private int getCommand(String instruction) {
- String command = instruction.substring(instruction.substring(7).indexOf('/') + 1);
- if (command.indexOf("search") > 0) return SEARCH_COMMAND;
+ String command = instruction.substring(instruction.indexOf('/') + 1);
+ if (command.startsWith("search")) return SEARCH_COMMAND;
+ if (command.startsWith("getall")) return GET_ALL_COMMAND;
+ if (command.startsWith("choose")) return CHOOSE_COMMAND;
+ if (command.startsWith("remove")) return REMOVE_COMMAND;
+ if (command.startsWith("new")) return NEW_COMMAND;
return -1;
}
+ /**
+ * Creates a new contact based on the hash of parameters passed in via options.
+ * @param options Parsed parameters for use with creating a new contact.
+ * @return String, which will be executed back in browser. Just callback invokes.
+ */
+ private String newContact(Hashtable options) {
+ try {
+ BlackBerryContactList agenda = (BlackBerryContactList) PIM.getInstance().openPIMList(PIM.CONTACT_LIST, PIM.READ_WRITE);
+ BlackBerryContact contact = (BlackBerryContact) agenda.createContact();
+ // Add name(s).
+ String[] nameField = new String[2];
+ nameField[Contact.NAME_FAMILY] = options.get("lastName").toString();
+ nameField[Contact.NAME_GIVEN] = options.get("firstName").toString();
+ if (agenda.isSupportedField(Contact.NAME)) contact.addStringArray(Contact.NAME, Contact.ATTR_NONE, nameField);
+ // TODO: Need to finalize JSON representation of address - it's multi-field in BlackBerry :s.
+
+ // TODO: Figure out how attributes and fields work for contact in BlackBerry. RUN TESTS! Code below may change.
+ String numbers = options.get("phoneNumber").toString();
+ if (agenda.isSupportedField(Contact.TEL)) contact.addString(Contact.TEL, Contact.ATTR_MOBILE, numbers.substring(numbers.lastIndexOf('=')+1));
+ String emails = options.get("email").toString();
+ if (agenda.isSupportedField(Contact.EMAIL)) contact.addString(Contact.EMAIL, Contact.ATTR_MOBILE, emails.substring(emails.lastIndexOf('=')+1));
+ contact.commit();
+ return ";if (" + CONTACT_MANAGER_JS_NAMESPACE + ".new_onSuccess) { " + CONTACT_MANAGER_JS_NAMESPACE + ".new_onSuccess(); };";
+ } catch (PIMException e) {
+ e.printStackTrace();
+ return ";if (" + CONTACT_MANAGER_JS_NAMESPACE + ".new_onError) { " + CONTACT_MANAGER_JS_NAMESPACE + ".new_onError(); };";
+ }
+ }
- private String getAgendaByName(String name) {
+ /**
+ * Removes the specified contact from the contact list.
+ * @param options A hash of options (parameters) passed by the PhoneGap app. Needs to contain a 'contactID' property for the removal to go through properly.
+ * @return JavaScript that will be evaluated by the PhoneGap app - only callbacks.
+ */
+ private String removeContact(Hashtable options) {
+ if (options.contains("contactID")) {
+ try {
+ BlackBerryContactList agenda = (BlackBerryContactList) PIM
+ .getInstance().openPIMList(PIM.CONTACT_LIST,
+ PIM.READ_WRITE);
+ Contact matchContact = agenda.createContact();
+ int contactID = Integer.parseInt(options.get("contactID").toString());
+ if (agenda.isSupportedField(Contact.UID)) matchContact.addInt(Contact.UID, Contact.ATTR_HOME | Contact.ATTR_PREFERRED, contactID);
+ Enumeration matches = agenda.items(matchContact);
+ if (matches.hasMoreElements()) {
+ // Matched to a contact.
+ } else {
+ // No matches found - call error callback.
+
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ // Trigger error callback if exception occurs.
+ return ";if (" + CONTACT_MANAGER_JS_NAMESPACE + ".remove_onError) { " + CONTACT_MANAGER_JS_NAMESPACE + ".remove_onError(); };";
+ }
+ } else {
+ return ";alert('[PhoneGap Error] Contact ID not specified during contact removal operation.');";
+ }
+ return null;
+ }
+ /**
+ * Invokes the default BlackBerry contact chooser to allow the user to choose a contact.
+ * @return JSON representation of the chosen contact, which will then be sent back to JavaScript.
+ */
+ private String chooseContact() {
try {
BlackBerryContactList agenda = (BlackBerryContactList) PIM.getInstance().openPIMList(PIM.CONTACT_LIST, PIM.READ_ONLY);
+ BlackBerryContact blackberryContact;
+ StringBuffer contacts = new StringBuffer("[");
if (agenda != null) {
- StringBuffer contacts = new StringBuffer("[");
- Enumeration matches = agenda.itemsByName(name);
- while (matches.hasMoreElements()) {
- BlackBerryContact contact = (BlackBerryContact) matches.nextElement();
- contacts.append("{email:'");
- contacts.append(contact.getString(Contact.EMAIL, 0));
- contacts.append("', phone:'");
- contacts.append(contact.getString(Contact.TEL, 0));
- contacts.append("'},");
+ blackberryContact = (BlackBerryContact) agenda.choose();
+ agenda.close();
+ ContactsCommand.addContactToBuffer(contacts, blackberryContact);
+ contacts.append("];");
+ return ";" + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + ".contacts=" + contacts.toString() + "if (" + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + ".choose_onSuccess) { " + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + ".choose_onSuccess();" + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + ".choose_onSuccess = null; };";
+ } else {
+ // TODO: If cannot get reference to Agenda, should the error or success callback be called?
+ return ";" + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + ".contacts=" + contacts.append("];").toString() + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + ".choose_onSuccess = null;";
+ }
+ } catch (Exception e) {
+ System.out.println("Exception getting contact list: " + e.getMessage());
+ // TODO: No error callbacks associated with contact chooser - what to do?
+ }
+ return null;
+ }
+ /**
+ * Returns a contact list, either all contacts or contacts matching the optional search parameter.
+ * @param options A hash of options to pass into retrieving contacts. These can include name filters and paging parameters.
+ * @return JSON string representing the contacts that are retrieved, plus necessary JavaScript callbacks.
+ */
+ private String getAgenda(Hashtable options) {
+ String callbackHook = "";
+ try {
+ BlackBerryContactList agenda = (BlackBerryContactList) PIM.getInstance().openPIMList(PIM.CONTACT_LIST, PIM.READ_ONLY);
+ StringBuffer contacts = new StringBuffer("[");
+ if (agenda != null) {
+ Enumeration matches;
+ String name = options.get("nameFilter")!=null?options.get("nameFilter").toString():"";
+ if (name != "") {
+ matches = agenda.itemsByName(name);
+ callbackHook = "search_";
+ } else {
+ matches = agenda.items();
+ callbackHook = "global_";
}
- return contacts.deleteCharAt(contacts.length() - 1).append("]").toString();
+ int pageSize = 0, pageNumber = 0;
+ if (options.contains("pageSize")) pageSize = Integer.parseInt(options.get("pageSize").toString());
+ if (options.contains("pageNumber")) pageNumber = Integer.parseInt(options.get("pageNumber").toString());
+ if (pageSize > 0) {
+ for (int i = 0; i < pageSize*pageNumber && matches.hasMoreElements(); i++) {
+ matches.nextElement();
+ }
+ for (int j = 0; j < pageSize && matches.hasMoreElements(); j++) {
+ BlackBerryContact contact = (BlackBerryContact)matches.nextElement();
+ ContactsCommand.addContactToBuffer(contacts, contact);
+ contacts.append(',');
+ }
+ } else {
+ while (matches.hasMoreElements()) {
+ BlackBerryContact contact = (BlackBerryContact)matches.nextElement();
+ ContactsCommand.addContactToBuffer(contacts, contact);
+ contacts.append(',');
+ }
+ }
+ if (contacts.length() > 1) contacts = contacts.deleteCharAt(contacts.length() - 1);
+ contacts.append("];");
+ // Return an assignment to the contact manager contacts array with the contacts JSON generated above.
+ // Also call the right onSuccess if it exists.
+ return ";" + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + ".contacts=" + contacts.toString() + "if (" + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + "." + callbackHook + "onSuccess) { " + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + "." + callbackHook + "onSuccess();" + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + "." + callbackHook + "onSuccess = null;" + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + "." + callbackHook + "onError = null; };";
+ } else {
+ // TODO: If cannot get reference to Agenda, should the error or success callback be called?
+ return ";" + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + ".contacts=" + contacts.append("];").toString() + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + "." + callbackHook + "onSuccess = null;" + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + "." + callbackHook + "onError = null;";
}
} catch (Exception ex) {
System.out.println("Exception getting contact list: " + ex.getMessage());
+ return ";if (" + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + "." + callbackHook + "onError) { " + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + "." + callbackHook + "onError();" + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + "." + callbackHook + "onSuccess = null;" + ContactsCommand.CONTACT_MANAGER_JS_NAMESPACE + "." + callbackHook + "onError = null; };";
}
- return null;
}
-
+ private static void addContactToBuffer(StringBuffer buff, BlackBerryContact contact) {
+ // TODO: Eventually extend this to return proper labels/values for differing phone/email types.
+ buff.append("{email:[{'label':'mobile','value':'");
+ buff.append(contact.getString(Contact.EMAIL, 0));
+ buff.append("'}], phoneNumber:[{'label':'mobile','value':'");
+ buff.append(contact.getString(Contact.TEL, 0));
+ buff.append("'}], firstName:'");
+ // See if there is a meaningful name set for the contact.
+ if (contact.countValues(Contact.NAME) > 0) {
+ final String[] name = contact.getStringArray(Contact.NAME, 0);
+ final String firstName = name[Contact.NAME_GIVEN];
+ final String lastName = name[Contact.NAME_FAMILY];
+ if (firstName != null) buff.append(firstName + "',lastName:'");
+ else buff.append("',lastName:'");
+ if (lastName != null) buff.append(lastName + "',");
+ else buff.append("',");
+ } else {
+ buff.append("',lastName:''");
+ }
+ buff.append(",address:'");
+ // Build up a meaningful address field.
+ if (contact.countValues(Contact.ADDR) > 0) {
+ String address = "";
+ final String[] addr = contact.getStringArray(Contact.ADDR, 0);
+ final String street = addr[Contact.ADDR_STREET];
+ final String city = addr[Contact.ADDR_LOCALITY];
+ final String state = addr[Contact.ADDR_REGION];
+ final String country = addr[Contact.ADDR_COUNTRY];
+ final String postalCode = addr[Contact.ADDR_POSTALCODE];
+ if (street!=null) address = street.replace('\'',' ');
+ if (city!=null) if (address.length() > 0) address += ", " + city.replace('\'',' '); else address = city.replace('\'',' ');
+ if (state!=null) if (address.length() > 0) address += ", " + state.replace('\'',' '); else address = state.replace('\'',' ');
+ if (country!=null) if (address.length() > 0) address += ", " + country.replace('\'',' '); else address = country.replace('\'',' ');
+ if (postalCode!=null) if (address.length() > 0) address += ", " + postalCode.replace('\'',' '); else address = postalCode.replace('\'',' ');
+ buff.append(address);
+ }
+ buff.append("'}");
+ }
}
View
74 blackberry/src/com/nitobi/phonegap/api/impl/DeviceCommand.java
@@ -0,0 +1,74 @@
+/**
+ * The MIT License
+ * -------------------------------------------------------------
+ * Copyright (c) 2008, Rob Ellis, Brock Whitten, Brian Leroux, Joe Bowser, Dave Johnson, Nitobi
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.nitobi.phonegap.api.impl;
+
+import com.nitobi.phonegap.api.Command;
+import net.rim.device.api.system.DeviceInfo;
+
+/**
+ * Configures the Device API.
+ *
+ * @author Jose Noheda [jose.noheda@gmail.com]
+ *
+ */
+public class DeviceCommand implements Command {
+
+ private static final String CODE = "PhoneGap=initialize";
+
+ /**
+ * Determines whether the specified instruction is accepted by the command.
+ * @param instruction The string instruction passed from JavaScript via cookie.
+ * @return true if the Command accepts the instruction, false otherwise.
+ */
+ public boolean accept(String instruction) {
+ return instruction != null && instruction.startsWith(CODE);
+ }
+
+ /**
+ * Fills the JS variable 'device' with:
+ * Model
+ * Flash memory available
+ * Platform
+ * Vendor
+ * Battery
+ * Software version
+ * Camera support
+ * ID
+ * Simulator
+ *
+ */
+ public String execute(String instruction) {
+ StringBuffer deviceInfo = new StringBuffer(";device.name = '");
+ deviceInfo.append(DeviceInfo.getDeviceName()).append("';device.flash = ");
+ deviceInfo.append(DeviceInfo.getTotalFlashSize()).append(";device.platform = '");
+ deviceInfo.append(DeviceInfo.getPlatformVersion().length()>0?DeviceInfo.getPlatformVersion():"Emulator").append("';device.vendor = '");
+ deviceInfo.append(DeviceInfo.getManufacturerName()).append("';device.battery = ");
+ deviceInfo.append(DeviceInfo.getBatteryLevel()).append(";device.version = '");
+ deviceInfo.append(DeviceInfo.getSoftwareVersion()).append("';device.isSimulator = ");
+ deviceInfo.append(DeviceInfo.isSimulator()).append(";device.hasCamera = ");
+ deviceInfo.append(DeviceInfo.hasCamera()).append(";device.uuid = ");
+ deviceInfo.append(DeviceInfo.getDeviceId()).append(";");
+ return deviceInfo.toString();
+ }
+
+}
View
29 blackberry/src/com/nitobi/phonegap/api/impl/GeoLocationCommand.java
@@ -46,7 +46,7 @@
private static final int START_COMMAND = 2;
private static final int CHECK_COMMAND = 3;
private static final int CAPTURE_INTERVAL = 5;
- private static final String CODE = "gap://location";
+ private static final String CODE = "PhoneGap=location";
private Position position;
private boolean availableGPS = true;
@@ -59,10 +59,10 @@ public GeoLocationCommand() {
availableGPS = false;
}
}
-
/**
- * Able to run the <i>location</i> command (all options).
- * Ex: gap://location/start
+ * Determines whether the specified instruction is accepted by the command.
+ * @param instruction The string instruction passed from JavaScript via cookie.
+ * @return true if the Command accepts the instruction, false otherwise.
*/
public boolean accept(String instruction) {
return instruction != null && instruction.startsWith(CODE);
@@ -77,7 +77,7 @@ public void clearPosition() {
/**
* Executes the following sub-commands:
- * START: Initiliazes the internal GPS module
+ * START: Initializes the internal GPS module
* STOP: Stops GPS module (saving battery life)
* CHECK: Reads latest position available
* MAP: Invokes the internal MAP application
@@ -96,7 +96,11 @@ public String execute(String instruction) {
}
return null;
}
-
+ /**
+ * Parses the specified instruction and the parameters and determines what type of functional call is being made.
+ * @param instruction The string instruction passed from JavaScript via cookie.
+ * @return Integer representing action type.
+ */
private int getCommand(String instruction) {
String command = instruction.substring(instruction.lastIndexOf('/') + 1);
if ("map".equals(command)) return MAP_COMMAND;
@@ -145,7 +149,18 @@ public void locationUpdated(LocationProvider provider, Location location) {
} else command.clearPosition();
}
- public void providerStateChanged(LocationProvider provider, int newState) {}
+ public void providerStateChanged(LocationProvider provider, int newState) {
+ switch (newState) {
+ case LocationProvider.AVAILABLE:
+ break;
+ case LocationProvider.OUT_OF_SERVICE:
+ // TODO: Should call fail() here.
+ break;
+ case LocationProvider.TEMPORARILY_UNAVAILABLE:
+ break;
+ }
+
+ }
}
}
View
94 blackberry/src/com/nitobi/phonegap/api/impl/MediaCommand.java
@@ -0,0 +1,94 @@
+/**
+ * The MIT License
+ * -------------------------------------------------------------
+ * Copyright (c) 2008, Rob Ellis, Brock Whitten, Brian Leroux, Joe Bowser, Dave Johnson, Fil Maj, Nitobi
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.nitobi.phonegap.api.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+
+import javax.microedition.media.Player;
+import com.nitobi.phonegap.api.Command;
+
+/**
+ * Wraps playing local storage (music) media on the BlackBerry for access from JavaScript.
+ * @author Fil Maj
+ *
+ */
+public class MediaCommand implements Command {
+ private static final String CODE = "PhoneGap=media";
+ private Player musicPlayer;
+ private Hashtable extToMime = new Hashtable();
+
+ public MediaCommand() {
+ extToMime.put("wav", "audio/x-wav");
+ extToMime.put("au", "audio/basic");
+ extToMime.put("snd", "audio/basic");
+ extToMime.put("mid", "audio/mid");
+ extToMime.put("rmi", "audio/mid");
+ extToMime.put("mp3", "audio/mpeg");
+ extToMime.put("aif", "audio/x-aiff");
+ extToMime.put("aiff", "audio/x-aiff");
+ extToMime.put("aifc", "audio/x-aiff");
+ extToMime.put("ra", "audio/x-pn-realaudio");
+ extToMime.put("ram", "audio/x-pn-realaudio");
+ }
+
+ /**
+ * Determines whether the specified instruction is accepted by the command.
+ * @param instruction The string instruction passed from JavaScript via cookie.
+ * @return true if the Command accepts the instruction, false otherwise.
+ */
+ public boolean accept(String instruction) {
+ return instruction != null && instruction.startsWith(CODE);
+ }
+
+ public String execute(String instruction) {
+ String mediaURI = instruction.substring(instruction.indexOf('/')+1);
+ try
+ {
+ InputStream in = getClass().getResourceAsStream("/" + mediaURI);
+ String audioMime = this.mapExtensionToMime(mediaURI.substring(mediaURI.lastIndexOf('.')+1));
+ if (audioMime == null) return ";alert('[PhoneGap Error] Media type not supported.');";
+ // Create a media player with our inputstream
+ musicPlayer = javax.microedition.media.Manager.createPlayer(in, audioMime);
+ musicPlayer.realize();
+ musicPlayer.prefetch();
+ musicPlayer.setLoopCount(1);
+ musicPlayer.start();
+ return "";
+ }
+ catch (IOException e) {
+ return ";alert('[PhoneGap Error] Media file I/O exception.');";
+ } catch (javax.microedition.media.MediaException e) {
+ return ";alert('[PhoneGap Error] Could not play and/or determine media file type.');";
+ }
+ }
+ /**
+ * Maps media file extensions to mime type, for use with the sound player.
+ * @param extension The media file extension
+ * @return A mime type as a string
+ */
+ private String mapExtensionToMime(String extension) {
+ return extToMime.get(extension).toString();
+ }
+}
View
106 blackberry/src/com/nitobi/phonegap/api/impl/NotificationCommand.java
@@ -0,0 +1,106 @@
+/**
+ * The MIT License
+ * -------------------------------------------------------------
+ * Copyright (c) 2008, Rob Ellis, Brock Whitten, Brian Leroux, Joe Bowser, Dave Johnson, Nitobi
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.nitobi.phonegap.api.impl;
+
+import net.rim.device.api.system.Alert;
+
+import com.nitobi.phonegap.api.Command;
+
+/**
+ * Vibrates the phone if able.
+ *
+ * @author Jose Noheda
+ *
+ */
+public class NotificationCommand implements Command {
+
+ private static final int VIBRATE_COMMAND = 0;
+ private static final int BEEP_COMMAND = 1;
+ private static final int DURATION = 5;
+ private static final String CODE = "PhoneGap=notification";
+
+ private static final short A = 440; //440.00
+ private static final short NOTE_DURATION = 500;
+ private static final short PAUSE_DURATION = 50;
+ private static final int TUNE_LENGTH = 4;
+ private static final short[] TUNE = new short[]
+ {
+ A, NOTE_DURATION, 0, PAUSE_DURATION
+ };
+ /**
+ * Determines whether the specified instruction is accepted by the command.
+ * @param instruction The string instruction passed from JavaScript via cookie.
+ * @return true if the Command accepts the instruction, false otherwise.
+ */
+ public boolean accept(String instruction) {
+ return instruction != null && instruction.startsWith(CODE);
+ }
+
+ public String execute(String instruction) {
+ switch (getCommand(instruction)) {
+ case VIBRATE_COMMAND:
+ if (Alert.isVibrateSupported()) Alert.startVibrate(getVibrateDuration(instruction));
+ break;
+ case BEEP_COMMAND:
+ if (Alert.isAudioSupported()) Alert.startAudio(getTune(instruction), 99);
+ break;
+ }
+ return null;
+ }
+ private int getCommand(String instruction) {
+ String command = instruction.substring(CODE.length()+1);
+ if (command.startsWith("beep")) return BEEP_COMMAND;
+ if (command.startsWith("vibrate")) return VIBRATE_COMMAND;
+ return -1;
+ }
+ /**
+ * Parses the vibrate instruction and tries to extract the specified duration. Returns the default duration if there are issues parsing.
+ * @param instruction The instruction called from the JS.
+ * @return The number of seconds the vibration should last.
+ */
+ private int getVibrateDuration(String instruction) {
+ try {
+ return Integer.parseInt(instruction.substring(instruction.lastIndexOf('/') + 1));
+ } catch(Exception ex) {
+ return DURATION;
+ }
+ }
+ private short[] getTune(String instruction) {
+ String beepParam = instruction.substring(CODE.length()+1);
+ int param = 1;
+ try {
+ param = Integer.parseInt(beepParam.substring(beepParam.indexOf('/')+1));
+ } catch(Exception e) {
+ param = 1;
+ }
+ short[] theTune = new short[TUNE_LENGTH * param];
+ if (param == 1)
+ return TUNE;
+ else {
+ for (int i = 0; i < param; i++) {
+ System.arraycopy(TUNE, 0, theTune, i*TUNE_LENGTH, TUNE_LENGTH);
+ }
+ }
+ return theTune;
+ }
+}
View
5 blackberry/src/com/nitobi/phonegap/api/impl/TelephonyCommand.java
@@ -35,11 +35,8 @@
*/
public class TelephonyCommand implements Command {
- private static final String CODE = "gap://call";
+ private static final String CODE = "PhoneGap=call";
- /**
- * Able to run the <i>call</i> command. Ex: gap://call/555666777
- */
public boolean accept(String instruction) {
return instruction != null && instruction.startsWith(CODE);
}
View
6 blackberry/src/com/nitobi/phonegap/io/AsynchronousResourceFetcher.java
@@ -32,16 +32,14 @@
private String url;
private Callback callback;
- private ConnectionManager connectionManager;
- public AsynchronousResourceFetcher(String url, Callback callback, ConnectionManager connectionManager) {
+ public AsynchronousResourceFetcher(String url, Callback callback) {
this.url = url;
this.callback = callback;
- this.connectionManager = connectionManager;
}
public void run() {
- callback.execute(connectionManager.getUnmanagedConnection(url));
+ callback.execute(ConnectionManager.getUnmanagedConnection(url, null, null));
}
}
View
114 blackberry/src/com/nitobi/phonegap/io/ConnectionManager.java
@@ -27,6 +27,8 @@
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Vector;
import javax.microedition.io.Connection;
import javax.microedition.io.Connector;
@@ -34,7 +36,10 @@
import javax.microedition.io.InputConnection;
import net.rim.device.api.io.Base64OutputStream;
+import net.rim.device.api.io.http.HttpHeaders;
+import net.rim.device.api.io.http.HttpProtocolConstants;
import net.rim.device.api.system.Application;
+import net.rim.device.api.util.StringUtilities;
/**
* Manages all HTTP connections.
@@ -46,19 +51,88 @@
public static final String DATA = "data";
public static final String DATA_PROTOCOL = DATA + ":///";
- private static final byte[] DATA_URL = (ConnectionManager.DATA + ":text/html;base64,").getBytes();
+ private static final String URI_SUFFIX = ";charset=utf-8;base64,";
+ private static final byte[] DATA_URL_HTML = (ConnectionManager.DATA + ":text/html" + URI_SUFFIX).getBytes();
+ private static final byte[] DATA_URL_JS = (ConnectionManager.DATA + ":text/javascript" + URI_SUFFIX).getBytes();
+ private static final byte[] DATA_URL_IMG_JPG = (ConnectionManager.DATA + ":image/jpeg" + URI_SUFFIX).getBytes();
+ private static final byte[] DATA_URL_CSS = (ConnectionManager.DATA + ":text/css" + URI_SUFFIX).getBytes();
+ private static final byte[] DATA_URL_PLAIN = (ConnectionManager.DATA + ":text/plain" + URI_SUFFIX).getBytes();
/**
* Creates a connection and returns it. Calling this method without care may saturate BB capacity.
*
* @param url a http:// or data:// URL
*/
- public HttpConnection getUnmanagedConnection(String url) {
- if ((url != null) && (url.trim().length() > 0))
- return isInternal(url) ? getDataProtocolConnection(url) : getExternalConnection(url);
- return null;
+ public static HttpConnection getUnmanagedConnection(String url, HttpHeaders requestHeaders, byte[] postData) {
+ HttpConnection conn = null;
+ OutputStream out = null;
+ if ((url != null) && (url.trim().length() > 0)) {
+ conn = isInternal(url) ? getDataProtocolConnection(url) : getExternalConnection(url);
+ } else {
+ return conn;
+ }
+ try {
+ //conn = setConnectionRequestHeaders(url, requestHeaders, conn);
+ if (postData == null) {
+ conn.setRequestMethod(HttpConnection.GET);
+ } else {
+ conn.setRequestMethod(HttpConnection.POST);
+ conn.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_LENGTH, String.valueOf(postData.length));
+ out = conn.openOutputStream();
+ out.write(postData);
+ }
+ } catch (IOException e1) {
+ } finally {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException e2) {
+ }
+ }
+ }
+ return conn;
}
+ public static HttpConnection setConnectionRequestHeaders(String url, HttpHeaders requestHeaders, HttpConnection conn) {
+ HttpConnection returnConn = conn;
+ if (requestHeaders != null) {
+ // From
+ // http://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3
+ //
+ // Clients SHOULD NOT include a Referer header field in a
+ // (non-secure) HTTP
+ // request if the referring page was transferred with a secure
+ // protocol.
+ String referer = requestHeaders.getPropertyValue("referer");
+ boolean sendReferrer = true;
+
+ if (referer != null && StringUtilities.startsWithIgnoreCase(referer,"https:") && !StringUtilities.startsWithIgnoreCase(url, "https:")) {
+ sendReferrer = false;
+ }
+ int size = requestHeaders.size();
+ for (int i = 0; i < size;) {
+ String header = requestHeaders.getPropertyKey(i);
+
+ // Remove referer header if needed.
+ if (!sendReferrer && header.equals("referer")) {
+ requestHeaders.removeProperty(i);
+ --size;
+ continue;
+ }
+
+ String value = requestHeaders.getPropertyValue(i++);
+ if (value != null) {
+ try {
+ returnConn.setRequestProperty(header, value);
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ return returnConn;
+ }
/**
* Loads an external URL and provides a connection that holds the array of bytes. Internal
* URLs (data://) simply pass through.
@@ -66,7 +140,7 @@ public HttpConnection getUnmanagedConnection(String url) {
* @param url a http:// or data:// URL
*/
public InputConnection getPreLoadedConnection(String url) {
- InputConnection connection = getUnmanagedConnection(url);
+ InputConnection connection = getUnmanagedConnection(url, null, null);
if ((connection != null) && (!isInternal(url))) {
try {
final byte[] data = read(connection.openInputStream());
@@ -97,7 +171,7 @@ public void close() throws IOException {
/**
* Detects data:// URLs
*/
- public boolean isInternal(String url) {
+ public static boolean isInternal(String url) {
return (url != null) && url.startsWith(ConnectionManager.DATA_PROTOCOL);
}
@@ -117,24 +191,39 @@ private static void close(Connection connection) {
private static HttpConnection getExternalConnection(String url) {
try {
- return (HttpConnection) Connector.open(url);
+ HttpConnection con = (HttpConnection)Connector.open(url);
+ return con;
} catch (Exception ex) {
return null;
}
}
private static HttpConnection getDataProtocolConnection(String url) {
- String dataUrl = url.startsWith(ConnectionManager.DATA_PROTOCOL) ? url.substring(ConnectionManager.DATA_PROTOCOL.length()-1) : url;
+ String dataUrl = url.startsWith(ConnectionManager.DATA_PROTOCOL) ? url.substring(ConnectionManager.DATA_PROTOCOL.length() - 1) : url;
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
- output.write(ConnectionManager.DATA_URL);
+ if (dataUrl.endsWith(".html") || dataUrl.endsWith(".htm")) {
+ output.write(ConnectionManager.DATA_URL_HTML);
+ } else if (dataUrl.endsWith(".js")) {
+ output.write(ConnectionManager.DATA_URL_JS);
+ } else if (dataUrl.endsWith(".jpg") || dataUrl.endsWith(".jpeg")) {
+ output.write(ConnectionManager.DATA_URL_IMG_JPG);
+ } else if (dataUrl.endsWith(".css")) {
+ output.write(ConnectionManager.DATA_URL_CSS);
+ } else {
+ output.write(ConnectionManager.DATA_URL_PLAIN);
+ }
Base64OutputStream boutput = new Base64OutputStream(output);
- boutput.write(read(Application.class.getResourceAsStream(dataUrl)));
+ InputStream theResource = Application.class.getResourceAsStream(dataUrl);
+ byte[] resourceBytes = read(theResource);
+ boutput.write(resourceBytes);
boutput.flush();
boutput.close();
output.flush();
output.close();
- return (HttpConnection) Connector.open(output.toString());
+ Connection outputCon = Connector.open(output.toString());
+ HttpConnection outputHttp = (HttpConnection) outputCon;
+ return outputHttp;
} catch (IOException ex) {
return null;
}
@@ -153,5 +242,4 @@ private static HttpConnection getDataProtocolConnection(String url) {
}
return bytes.toByteArray();
}
-
}
View
38 blackberry/src/com/nitobi/phonegap/io/PrimaryResourceFetchThread.java
@@ -0,0 +1,38 @@
+package com.nitobi.phonegap.io;
+
+import javax.microedition.io.HttpConnection;
+
+import net.rim.device.api.browser.field.Event;
+import net.rim.device.api.io.http.HttpHeaders;
+
+import com.nitobi.phonegap.PhoneGap;
+
+public class PrimaryResourceFetchThread extends Thread
+{
+ private PhoneGap _application;
+ private Event _event;
+ private byte[] _postData;
+ private HttpHeaders _requestHeaders;
+ private String _url;
+
+ public PrimaryResourceFetchThread(String url, HttpHeaders requestHeaders, byte[] postData,
+ Event event, PhoneGap application)
+ {
+ _url = url;
+ _requestHeaders = requestHeaders;
+ _postData = postData;
+ _application = application;
+ _event = event;
+ }
+
+ public void run()
+ {
+ HttpConnection connection = null;
+ if (_url.startsWith(PhoneGap.PHONEGAP_PROTOCOL)) {
+ connection = _application._currentConnection;
+ } else {
+ connection = ConnectionManager.getUnmanagedConnection(_url, _requestHeaders, _postData);
+ }
+ _application.processConnection(connection, _event);
+ }
+}
View
169 blackberry/src/com/nitobi/phonegap/io/SecondaryResourceFetchThread.java
@@ -0,0 +1,169 @@
+/*
+ * SecondaryResourceFetchThread.java
+ *
+ * Copyright © 1998-2008 Research In Motion Ltd.
+ *
+ * Note: For the sake of simplicity, this sample application may not leverage
+ * resource bundles and resource strings. However, it is STRONGLY recommended
+ * that application developers make use of the localization features available
+ * within the BlackBerry development platform to ensure a seamless application
+ * experience across a variety of languages and geographies. For more information
+ * on localizing your application, please refer to the BlackBerry Java Development
+ * Environment Development Guide associated with this release.
+ */
+
+package com.nitobi.phonegap.io;
+
+import java.util.Vector;
+
+import javax.microedition.io.HttpConnection;
+
+import net.rim.device.api.browser.field.BrowserContent;
+import net.rim.device.api.browser.field.RequestedResource;
+
+
+public class SecondaryResourceFetchThread extends Thread
+{
+
+ /**
+ * Callback browser field.
+ */
+ private BrowserContent _browserField;
+
+ /**
+ * Images to retrieve.
+ */
+ private Vector _imageQueue;
+
+ /**
+ * True is all images have been enqueued.
+ */
+ private boolean _done;
+
+ /**
+ * Sync object.
+ */
+ private static Object _syncObject = new Object();
+
+ /**
+ * Secondary thread.
+ */
+ private static SecondaryResourceFetchThread _currentThread;
+
+
+ /**
+ * Enqueues secondary resource for a browser field.
+ *
+ * @param resource - resource to retrieve.
+ * @param referrer - call back browsr field.
+ */
+ public static void enqueue(RequestedResource resource, BrowserContent referrer)
+ {
+ if (resource == null)
+ {
+ return;
+ }
+
+ synchronized( _syncObject )
+ {
+
+ // Create new thread.
+ if (_currentThread == null)
+ {
+ _currentThread = new SecondaryResourceFetchThread();
+ _currentThread.start();
+ }
+ else
+ {
+ // If thread alread is running, check that we are adding images for the same browser field.
+ if (referrer != _currentThread._browserField)
+ {
+ synchronized( _currentThread._imageQueue)
+ {
+ // If the request is for a different browser field,
+ // clear old elements.
+ _currentThread._imageQueue.removeAllElements();
+ }
+ }
+ }
+
+ synchronized( _currentThread._imageQueue)
+ {
+ _currentThread._imageQueue.addElement(resource);
+ }
+
+ _currentThread._browserField = referrer;
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ */
+ private SecondaryResourceFetchThread()
+ {
+ _imageQueue = new Vector();
+ }
+
+ /**
+ * Indicate that all images have been enqueued for this browser field.
+ */
+ static void doneAddingImages()
+ {
+ synchronized( _syncObject )
+ {
+ if (_currentThread != null)
+ {
+ _currentThread._done = true;
+ }
+ }
+ }
+
+ public void run()
+ {
+ while (true)
+ {
+ if (_done)
+ {
+ // Check if we are done requesting images.
+ synchronized( _syncObject )
+ {
+ synchronized( _imageQueue )
+ {
+ if (_imageQueue.size() == 0)
+ {
+ _currentThread = null;
+ break;
+ }
+ }
+ }
+ }
+
+ RequestedResource resource = null;
+
+ // Request next image.
+ synchronized( _imageQueue )
+ {
+ if (_imageQueue.size() > 0)
+ {
+ resource = (RequestedResource)_imageQueue.elementAt(0);
+ _imageQueue.removeElementAt(0);
+ }
+ }
+
+ if (resource != null)
+ {
+
+ HttpConnection connection = ConnectionManager.getUnmanagedConnection(resource.getUrl(), resource.getRequestHeaders(), null);
+ resource.setHttpConnection(connection);
+
+ // Signal to the browser field that resource is ready.
+ if (_browserField != null)
+ {
+ _browserField.resourceReady(resource);
+ }
+ }
+ }
+ }
+
+}
View
2  blackberry/src/com/nitobi/phonegap/model/Position.java
@@ -77,7 +77,7 @@ public void setVelocity(float velocity) {
}
public String toJavascript() {
- return "new Position(" + _lat + "," + _lng + ",1," + altitude + ",1" + heading + "," + velocity + ")";
+ return "new Position(new Coordinates(" + _lat + "," + _lng + "," + altitude + ",1," + heading + "," + velocity + "))";
}
}
View
1  blackberry/src/www/css/test.css
@@ -0,0 +1 @@
+a { color:red; }
View
13 blackberry/src/www/js/camera.js
@@ -7,8 +7,8 @@ function Camera() {
}
Camera.prototype.launch = function () {
- if (Device.hasCamera) Device.exec("camera", ["obtain"], true);
- else alert("Camera not supported");
+ if (device.hasCamera) device.exec("camera", ["obtain"], true);
+ else alert("Camera not supported on this device.");
}
/**
@@ -18,8 +18,13 @@ Camera.prototype.launch = function () {
* @param {Object} options
*/
Camera.prototype.getPicture = function(successCallback, errorCallback, options) {
- if (Device.hasCamera) Device.exec("camera", ["picture"], true);
- else alert("Camera not supported");
+ if (device.hasCamera) {
+ if (successCallback) this.onSuccess = successCallback;
+ else this.onSuccess = null;
+ if (errorCallback) this.onError = errorCallback;
+ else this.onError = null;
+ device.exec("camera", ["picture"], true);
+ } else alert("Camera not supported");
}
if (typeof navigator.camera == "undefined") navigator.camera = new Camera();
View
99 blackberry/src/www/js/contacts.js
@@ -3,29 +3,94 @@
* @constructor
*/
function Contact() {
- this.name = "";
- this.phone = "";
+ this.firstName = "";
+ this.lastName = "";
+ this.phoneNumber = {};
this.address = "";
+ this.email = {};
}
-/**
- *
- * @param {Object} successCallback
- * @param {Object} errorCallback
- * @param {Object} options
- */
-Contact.prototype.get = function(successCallback, errorCallback, options) {
-
-}
-
-
function ContactManager() {
this.contacts = [];
- this.timestap = new Date().getTime();
+ this.timestamp = new Date().getTime();
+ // Options used when calling ContactManager functions.
+ this.options = {
+ 'pageSize':0,
+ 'pageNumber':0,
+ 'nameFilter':'',
+ 'contactID':0
+ };
}
-
-ContactManager.prototype.get = function(successCallback, errorCallback, options) {
- Device.exec("contacts", [options.operation, options.field, options.value], true);
+ContactManager.prototype.formParams = function(options, startArray) {
+ var params = [];
+ if (startArray) params = startArray;
+ if (options.pageSize && options.pageSize > 0) params.push("pageSize:" + options.pageSize);
+ if (options.pageNumber) params.push("pageNumber:" + options.pageNumber);
+ if (options.nameFilter) params.push("nameFilter:" + options.nameFilter);
+ if (options.contactID) params.push("contactID:" + options.contactID);
+ return params;
+}
+ContactManager.prototype.newContact = function(contact, successCallback, errorCallback, options) {
+ if (!contact) {
+ alert("[PhoneGap Error] newContact function not provided with a contact parameter.");
+ return;
+ } else {
+ if (!contact.firstName || !contact.lastName || !contact.phoneNumber || !contact.address || !contact.email) {
+ alert("[PhoneGap Error] newContact function parameter 'contact' does not have proper contact members (firstName, lastName, phoneNumber, address and email).");
+ return;
+ }
+ options.push("firstName:" + contact.firstName);
+ options.push("lastName:" + contact.lastName);
+ options.push("address:" + contact.address);
+ // Create a phone number parameter that we can parse on the BlackBerry end.
+ var phones = '';
+ for (var i = 0; i < contact.phoneNumber.length; i++) {
+ phones += contact.phoneNumber[i].label + '=';
+ phones += contact.phoneNumber[i].value + '|';
+ }
+ options.push("phoneNumber:" + phones.substring(0,phones.length-1);
+ var emails = '';
+ for (var i = 0; i < contact.email.length; i++) {
+ emails += contact.email[i].label + '=';
+ emails += contact.email[i].value + '|';
+ }
+ options.push("email:" + emails.substring(0,emails.length-1);
+ this.new_onSuccess = successCallback;
+ this.new_onError = errorCallback;
+ device.exec("new", options, true);
+ }
+}
+ContactManager.prototype.displayContact = function(successCallback, errorCallback, options) {
+ if (options.nameFilter && options.nameFilter.length > 0) {
+ var params = ["search"];
+ params = this.formParams(options,params);
+ this.search_onSuccess = successCallback;
+ this.search_onError = errorCallback;
+ device.exec("contacts", params, true);
+ } else {
+ ContactManager.getAllContacts(successCallback,errorCallback,options);
+ return;
+ }
+}
+ContactManager.prototype.getAllContacts = function(successCallback, errorCallback, options) {
+ this.global_onSuccess = successCallback;
+ this.global_onError = errorCallback;
+ var params = ["getall"];
+ params = this.formParams(options,params);
+ device.exec("contacts", params, true);
+}
+ContactManager.prototype.chooseContact = function(successCallback, options) {
+ this.choose_onSuccess = successCallback;
+ var params = ["choose"];
+ params = this.formParams(options,params);
+ device.exec("contacts", params, true);
+}
+ContactManager.prototype.removeContact = function(successCallback, errorCallback, options) {
+ this.remove_onSuccess = successCallback;
+ this.remove_onError = errorCallback;
+ var params = ["remove"];
+ params = this.formParams(options,params);
+ device.exec("contacts", params, true);
}
if (typeof navigator.ContactManager == "undefined") navigator.ContactManager = new ContactManager();
View
20 blackberry/src/www/js/device.js
@@ -1,4 +1,4 @@
-window.Device = {
+window.device = {
isIPhone: false,
isIPod: false,
isBlackBerry: true,
@@ -6,28 +6,26 @@ window.Device = {
init: function() {
this.exec("initialize");
this.poll(function() {
- Device.available = typeof Device.model == "string";
+ device.available = typeof device.name == "string";
});
},
exec: function(command, params, sync) {
- if (Device.available || command == "initialize") {
+ if (device.available || command == "initialize") {
try {
- var url = "gap://" + command;
- if (params) url += "/" + params.join("/");
- document.location = url;
+ var cookieCommand = "PhoneGap=" + command;
+ if (params) cookieCommand += "/" + params.join("/");
+ document.cookie = cookieCommand;
if (sync) this.poll();
} catch(e) {
console.log("Command '" + command + "' has not been executed, because of exception: " + e);
alert("Error executing command '" + command + "'.")
}
+ } else {
+ alert("Device not available YET - still loading.");
}
},
poll: function(callback) {
eval(document.cookie + (callback ? ";callback();" : ""));
- },
- vibrate: function(secs) {
- return Device.exec("vibrate", [secs]);
}
};
-
-window.Device.init();
+window.device.init();
View
15 blackberry/src/www/js/geolocation.js
@@ -22,7 +22,7 @@ Geolocation.prototype.start = function() {
alert("GPS already started");
return;
}
- Device.exec("location", ["start"], true);
+ device.exec("location", ["start"], true);
}
/**
@@ -34,7 +34,7 @@ Geolocation.prototype.stop = function() {
return;
}
if (this.locationTimeout) window.clearTimeout(this.locationTimeout);
- Device.exec("location", ["stop"], true);
+ device.exec("location", ["stop"], true);
}
/**
@@ -45,11 +45,11 @@ Geolocation.prototype.map = function() {
alert("No position to map yet");
return;
}
- Device.exec("location", ["map"], true);
+ device.exec("location", ["map"], true);
}
/**
- * Asynchronously adquires the current position.
+ * Asynchronously acquires the current position.
*
* @param {Function} successCallback The function to call when the position
* data is available
@@ -62,8 +62,7 @@ Geolocation.prototype.map = function() {
*/
Geolocation.prototype.getCurrentPosition = function(successCallback, errorCallback, options) {
if (!this.started) {
- alert("GPS not started");
- return;
+ this.start();
}
this.onSuccess = successCallback;
this.locationTimeout = window.setInterval("navigator.geolocation._getCurrentPosition();", 1000);
@@ -71,10 +70,10 @@ Geolocation.prototype.getCurrentPosition = function(successCallback, errorCallba
Geolocation.prototype._getCurrentPosition = function() {
this.lastPosition = null;
- Device.exec("location", ["check"], true);
+ device.exec("location", ["check"], true);
if (this.lastPosition != null) {
window.clearTimeout(this.locationTimeout);
- if (this.onSuccess) this.onSuccess();
+ if (this.onSuccess) this.onSuccess(this.lastPosition);
this.onSuccess = null;
}
}
View
5 blackberry/src/www/js/media.js
@@ -0,0 +1,5 @@
+navigator.media = {
+ playSound: function(media) {
+ window.device.exec("media",[media],true);
+ }
+};
View
8 blackberry/src/www/js/notification.js
@@ -0,0 +1,8 @@
+navigator.notification = {
+ vibrate: function(secs) {
+ window.device.exec("notification/vibrate",[secs]);
+ },
+ beep: function(times) {
+ window.device.exec("notification/beep",[times]);
+ }
+};
View
25 blackberry/src/www/js/position.js
@@ -9,7 +9,12 @@
* @param {Object} vel
* @constructor
*/
-function Position(lat, lng, acc, alt, altacc, head, vel) {
+function Position(coords) {
+ this.coords = coords;
+ this.timestamp = new Date().getTime();
+}
+
+function Coordinates(lat, lng, alt, acc, head, vel) {
/**
* The latitude of the position.
*/
@@ -27,23 +32,15 @@ function Position(lat, lng, acc, alt, altacc, head, vel) {
*/
this.altitude = alt;
/**
- * The altitude accuracy of the position.
- */
- this.altitudeAccuracy = altacc;
- /**
* The direction the device is moving at the position.
*/
this.heading = head;
/**
* The velocity with which the device is moving at the position.
*/
- this.velocity = vel;
- /**
- * The time that the position was obtained.
- */
- this.timestamp = new Date().getTime();
+ this.speed = vel;
}
-
+
/**
* This class specifies the options for requesting position data.
* @constructor
@@ -59,7 +56,7 @@ function PositionOptions() {
*/
this.timeout = 10000;
}
-
+
/**
* This class contains information about any GSP errors.
* @constructor
@@ -68,8 +65,8 @@ function PositionError() {
this.code = null;
this.message = "";
}
-
+
PositionError.UNKNOWN_ERROR = 0;
PositionError.PERMISSION_DENIED = 1;
PositionError.POSITION_UNAVAILABLE = 2;
-PositionError.TIMEOUT = 3;
+PositionError.TIMEOUT = 3;
View
2  blackberry/src/www/js/telephony.js
@@ -12,7 +12,7 @@ function Telephony() {
*/
Telephony.prototype.call = function(number) {
this.number = number;
- Device.exec("call", [this.number]);
+ device.exec("call", [this.number]);
}
if (typeof navigator.telephony == "undefined") navigator.telephony = new Telephony();
View
BIN  blackberry/src/www/media/bird.mp3
Binary file not shown
View
BIN  blackberry/src/www/media/percBass2.wav
Binary file not shown
View
4 blackberry/src/www/test/camera.html
@@ -9,6 +9,7 @@
function picture() {
navigator.camera.getPicture();
alert("Path is: " + navigator.camera.picture);
+ document.getElementById('testImg').src = navigator.camera.picture;
}
</script>
</head>
@@ -18,7 +19,8 @@
<p><a href="javascript:camera();">Use the Camera</a></p>
<p><a href="javascript:picture();">Get the picture</a></p>
<hr>
- <br/>
+ <p>Placeholder for image:</p>
+ <img src="" id="testImg" />
<br/>
<br/>
<br/>
View
47 blackberry/src/www/test/contacts.html
@@ -3,24 +3,49 @@
<script type="text/javascript" src="data:///www/js/device.js"></script>
<script type="text/javascript" src="data:///www/js/contacts.js"></script>
<script type="text/javascript">
- function findContactByName(name) {
+ function findContactsByName(name) {
var options = {
- operation: "search",
- field: "name",
- value: name
+ nameFilter: name
};
- navigator.ContactManager.get(null, null, options);
- if (navigator.ContactManager.contacts.length > 0) alert('Found:\nemail: ' + navigator.ContactManager.contacts[0].email + '\nphone: ' + navigator.ContactManager.contacts[0].phone);
- else alert("No Joe found in contacts");
+ var win = function() {
+ if (navigator.ContactManager.contacts.length > 0) alert('Found:\nname: ' + navigator.ContactManager.contacts[0].name + '\nemail: ' + navigator.ContactManager.contacts[0].email + '\nphone: ' + navigator.ContactManager.contacts[0].phone);
+ else alert("Contact '" + name + "' not found.");
+ };
+ var fail = function() {
+ alert('Failure to retrieve contact!');
+ };
+ navigator.ContactManager.displayContact(win, fail, options);
+ }
+ function getAllContacts(pageSize, pageNumber) {
+ var options = {};
+ if (pageSize) options.pageSize = pageSize;
+ if (pageNumber) options.pageNumber = pageNumber;
+ var win = function() {
+ if (navigator.ContactManager.contacts.length > 0) alert('Found:\nname: ' + navigator.ContactManager.contacts[0].name + '\nemail: ' + navigator.ContactManager.contacts[0].email + '\nphone: ' + navigator.ContactManager.contacts[0].phone);
+ else alert("No contacts found.");
+ };
+ var fail = function() {
+ alert('Failure to retrieve contacts!');
+ };
+ navigator.ContactManager.getAllContacts(win,fail,options);
+ }
+ function chooseContact() {
+ var options = {};
+ var win = function() {
+ if (navigator.ContactManager.contacts.length > 0) alert('Found:\nname: ' + navigator.ContactManager.contacts[0].name + '\nemail: ' + navigator.ContactManager.contacts[0].email + '\nphone: ' + navigator.ContactManager.contacts[0].phone);
+ else alert("No contacts found.");
+ };
+ navigator.ContactManager.chooseContact(win, options);
}
</script>
</head>
<body>
- <p>Add a contact with name Joe first</p>
- <hr/>
- <p><a href="javascript:findContactByName('Joe');">Find Joe in contacts</a></p>
+ <p><a href="javascript:findContactsByName('Joe');">Find Joe in contacts</a></p>
+ <hr>
+ <p><a href="javascript:getAllContacts(null,null);">Get first contact in address book</a></p>
+ <hr>
+ <p><a href="javascript:chooseContact();">Use Contact Chooser to select a Contact</a></p>
<hr>
- <br/>
<br/>
<br/>
<br/>
View
3  blackberry/src/www/test/device.html
@@ -1,9 +1,10 @@
<html>
<head>
+ <meta http-equiv="HandheldFriendly" content="true" />
<script type="text/javascript" src="data:///www/js/device.js"></script>
<script type="text/javascript">
function showDeviceInfo() {
- alert("ID: " + Device.uuid + "\nModel: " + Device.model + "\nVersion: " + Device.version + "\nPlatform: " + Device.platform + "\nMemory: " + Device.flash + "\nBattery: " + Device.battery + "\nisSimulator: " + Device.isSimulator + "\nhasCamera: " + Device.hasCamera);
+ alert("ID: " + device.uuid + "\nModel: " + device.name + "\nVersion: " + device.version + "\nPlatform: " + device.platform + "\nMemory: " + device.flash + "\nBattery: " + device.battery + "\nisSimulator: " + device.isSimulator + "\nhasCamera: " + device.hasCamera);
}
</script>
</head>
View
7 blackberry/src/www/test/index.html
@@ -1,12 +1,15 @@
<html>
<head>
- <meta http-equiv="HandheldFriendly" content="true" />
+ <meta http-equiv="HandheldFriendly" content="true" />
+ <LINK href="data:///www/css/test.css" rel="stylesheet" type="text/css" />
</head>
<body>
<a href="http://www.google.com">Navigate to Internet</a> (needs MDS)<br/>
<a href="data:///www/test/io.html">Test IO</a> (needs MDS)<br/>
+ <hr/>
<a href="data:///www/test/device.html">Test Device API</a><br/>
- <a href="data:///www/test/vibration.html">Test Vibration API</a><br/>
+ <a href="data:///www/test/notification.html">Test Notification API</a><br/>
+ <a href="data:///www/test/media.html">Test Media API</a><br/>
<a href="data:///www/test/telephony.html">Test Telephony API</a><br/>
<a href="data:///www/test/location.html">Test GeoLocation API</a><br/>
<a href="data:///www/test/camera.html">Test Camera API</a><br/>
View
22 blackberry/src/www/test/location.html
@@ -4,27 +4,19 @@
<script type="text/javascript" src="data:///www/js/position.js"></script>
<script type="text/javascript" src="data:///www/js/geolocation.js"></script>
<script type="text/javascript">
- function start() {
- navigator.geolocation.start();
- }
- function stop() {
- navigator.geolocation.stop();
- }
function check() {
- navigator.geolocation.getCurrentPosition();
- if (navigator.geolocation.lastPosition == null) alert("No position retrieved yet");
- else alert("Position: " + navigator.geolocation.lastPosition.latitude + " " + navigator.geolocation.lastPosition.longitude);
- }
- function map() {
- navigator.geolocation.map();
+ var win = function(loc) {
+ alert('Longitude: ' + loc.coords.longitude + ', Latitude: ' + loc.coords.latitude);
+ };
+ var fail = function() {
+ alert('Failure to retrieve GPS position.');
+ }
+ navigator.geolocation.getCurrentPosition(win, fail);
}
</script>
</head>
<body>
- <p><a href="javascript:start();">Start location module</a></p>
- <p><a href="javascript:stop();">Stop location module</a></p>
<p><a href="javascript:check();">Get current position</a></p>
- <p><a href="javascript:map();">Map current position</a></p>
<hr>
<br/>
<br/>
View
17 blackberry/src/www/test/media.html
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <meta http-equiv="HandheldFriendly" content="true" />
+ <script type="text/javascript" src="data:///www/js/device.js"></