diff --git a/VERSION b/VERSION
index 8862dbae..1bb19905 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.0rc2
+1.0.0rc3
diff --git a/example/index.html b/example/index.html
index 10a69d06..b5106057 100644
--- a/example/index.html
+++ b/example/index.html
@@ -5,7 +5,7 @@
PhoneGap
-
+
diff --git a/example/main.js b/example/main.js
index 110d3089..1001aabc 100644
--- a/example/main.js
+++ b/example/main.js
@@ -99,7 +99,7 @@ function get_contacts() {
var obj = new ContactFindOptions();
obj.filter = "";
obj.multiple = true;
- navigator.service.contacts.find(
+ navigator.contacts.find(
[ "displayName", "name" ], contacts_success,
fail, obj);
}
diff --git a/framework/assets/js/camera.js b/framework/assets/js/camera.js
index 1c4be96d..3971e1f1 100755
--- a/framework/assets/js/camera.js
+++ b/framework/assets/js/camera.js
@@ -34,6 +34,21 @@ Camera.DestinationType = {
};
Camera.prototype.DestinationType = Camera.DestinationType;
+/**
+ * Encoding of image returned from getPicture.
+ *
+ * Example: navigator.camera.getPicture(success, fail,
+ * { quality: 80,
+ * destinationType: Camera.DestinationType.DATA_URL,
+ * sourceType: Camera.PictureSourceType.CAMERA,
+ * encodingType: Camera.EncodingType.PNG})
+*/
+Camera.EncodingType = {
+ JPEG: 0, // Return JPEG encoded image
+ PNG: 1 // Return PNG encoded image
+};
+Camera.prototype.EncodingType = Camera.EncodingType;
+
/**
* Source to getPicture from.
*
@@ -78,6 +93,12 @@ Camera.prototype.getPicture = function(successCallback, errorCallback, options)
if (options.quality) {
quality = this.options.quality;
}
+
+ var maxResolution = 0;
+ if (options.maxResolution) {
+ maxResolution = this.options.maxResolution;
+ }
+
var destinationType = Camera.DestinationType.DATA_URL;
if (this.options.destinationType) {
destinationType = this.options.destinationType;
@@ -86,7 +107,32 @@ Camera.prototype.getPicture = function(successCallback, errorCallback, options)
if (typeof this.options.sourceType === "number") {
sourceType = this.options.sourceType;
}
- PhoneGap.exec(successCallback, errorCallback, "Camera", "takePicture", [quality, destinationType, sourceType]);
+ var encodingType = Camera.EncodingType.JPEG;
+ if (typeof options.encodingType == "number") {
+ encodingType = this.options.encodingType;
+ }
+
+ var targetWidth = -1;
+ if (typeof options.targetWidth == "number") {
+ targetWidth = options.targetWidth;
+ } else if (typeof options.targetWidth == "string") {
+ var width = new Number(options.targetWidth);
+ if (isNaN(width) === false) {
+ targetWidth = width.valueOf();
+ }
+ }
+
+ var targetHeight = -1;
+ if (typeof options.targetHeight == "number") {
+ targetHeight = options.targetHeight;
+ } else if (typeof options.targetHeight == "string") {
+ var height = new Number(options.targetHeight);
+ if (isNaN(height) === false) {
+ targetHeight = height.valueOf();
+ }
+ }
+
+ PhoneGap.exec(successCallback, errorCallback, "Camera", "takePicture", [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType]);
};
PhoneGap.addConstructor(function() {
diff --git a/framework/assets/js/media.js b/framework/assets/js/media.js
index 8c492271..de955c66 100755
--- a/framework/assets/js/media.js
+++ b/framework/assets/js/media.js
@@ -63,6 +63,7 @@ var Media = function(src, successCallback, errorCallback, statusCallback, positi
// Media messages
Media.MEDIA_STATE = 1;
Media.MEDIA_DURATION = 2;
+Media.MEDIA_POSITION = 3;
Media.MEDIA_ERROR = 9;
// Media states
@@ -187,7 +188,6 @@ PhoneGap.Media.getMediaObject = function(id) {
*/
PhoneGap.Media.onStatus = function(id, msg, value) {
var media = PhoneGap.mediaObjects[id];
-
// If state update
if (msg === Media.MEDIA_STATE) {
if (value === Media.MEDIA_STOPPED) {
@@ -207,5 +207,8 @@ PhoneGap.Media.onStatus = function(id, msg, value) {
media.errorCallback(value);
}
}
+ else if (msg == Media.MEDIA_POSITION) {
+ media._position = value;
+ }
};
}
diff --git a/framework/assets/www/index.html b/framework/assets/www/index.html
index e742b835..701402aa 100644
--- a/framework/assets/www/index.html
+++ b/framework/assets/www/index.html
@@ -1,7 +1,7 @@
-
+
diff --git a/framework/build.xml b/framework/build.xml
index d48e8a1f..05da712a 100755
--- a/framework/build.xml
+++ b/framework/build.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/framework/res/xml/plugins.xml b/framework/res/xml/plugins.xml
old mode 100755
new mode 100644
index e62c959f..3d8d48d8
--- a/framework/res/xml/plugins.xml
+++ b/framework/res/xml/plugins.xml
@@ -10,7 +10,6 @@
-
diff --git a/framework/src/com/phonegap/AudioPlayer.java b/framework/src/com/phonegap/AudioPlayer.java
index 8f84a90e..2d99fdbc 100755
--- a/framework/src/com/phonegap/AudioPlayer.java
+++ b/framework/src/com/phonegap/AudioPlayer.java
@@ -11,11 +11,12 @@ import java.io.File;
import java.io.IOException;
import android.media.AudioManager;
import android.media.MediaPlayer;
-import android.media.MediaPlayer.OnErrorListener;
-import android.media.MediaRecorder;
import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
import android.media.MediaPlayer.OnPreparedListener;
+import android.media.MediaRecorder;
import android.os.Environment;
+import android.util.Log;
/**
* This class implements the audio playback and recording capabilities used by PhoneGap.
@@ -28,7 +29,9 @@ import android.os.Environment;
*/
public class AudioPlayer implements OnCompletionListener, OnPreparedListener, OnErrorListener {
- // AudioPlayer states
+ private static final String LOG_TAG = "AudioPlayer";
+
+ // AudioPlayer states
private static int MEDIA_NONE = 0;
private static int MEDIA_STARTING = 1;
private static int MEDIA_RUNNING = 2;
@@ -38,6 +41,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
// AudioPlayer message ids
private static int MEDIA_STATE = 1;
private static int MEDIA_DURATION = 2;
+ private static int MEDIA_POSITION = 3;
private static int MEDIA_ERROR = 9;
// AudioPlayer error codes
@@ -99,7 +103,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
*/
public void startRecording(String file) {
if (this.mPlayer != null) {
- System.out.println("AudioPlayer Error: Can't record in play mode.");
+ Log.d(LOG_TAG, "AudioPlayer Error: Can't record in play mode.");
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_PLAY_MODE_SET+");");
}
@@ -124,7 +128,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_STARTING_RECORDING+");");
}
else {
- System.out.println("AudioPlayer Error: Already recording.");
+ Log.d(LOG_TAG, "AudioPlayer Error: Already recording.");
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_ALREADY_RECORDING+");");
}
}
@@ -166,7 +170,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
*/
public void startPlaying(String file) {
if (this.recorder != null) {
- System.out.println("AudioPlayer Error: Can't play in record mode.");
+ Log.d(LOG_TAG, "AudioPlayer Error: Can't play in record mode.");
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_RECORD_MODE_SET+");");
}
@@ -225,7 +229,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.setState(MEDIA_RUNNING);
}
else {
- System.out.println("AudioPlayer Error: startPlaying() called during invalid state: "+this.state);
+ Log.d(LOG_TAG, "AudioPlayer Error: startPlaying() called during invalid state: "+this.state);
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_RESUME_STATE+");");
}
}
@@ -237,6 +241,8 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
public void seekToPlaying(int milliseconds) {
if (this.mPlayer != null) {
this.mPlayer.seekTo(milliseconds);
+ Log.d(LOG_TAG, "Send a onStatus update for the new seek");
+ this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_POSITION+", "+milliseconds/1000.0f+");");
}
}
@@ -251,7 +257,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.setState(MEDIA_PAUSED);
}
else {
- System.out.println("AudioPlayer Error: pausePlaying() called during invalid state: "+this.state);
+ Log.d(LOG_TAG, "AudioPlayer Error: pausePlaying() called during invalid state: "+this.state);
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_PAUSE_STATE+");");
}
}
@@ -265,7 +271,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.setState(MEDIA_STOPPED);
}
else {
- System.out.println("AudioPlayer Error: stopPlaying() called during invalid state: "+this.state);
+ Log.d(LOG_TAG, "AudioPlayer Error: stopPlaying() called during invalid state: "+this.state);
this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_ERROR+", "+MEDIA_ERROR_STOP_STATE+");");
}
}
@@ -286,7 +292,9 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
*/
public long getCurrentPosition() {
if ((this.state == MEDIA_RUNNING) || (this.state == MEDIA_PAUSED)) {
- return this.mPlayer.getCurrentPosition();
+ int curPos = this.mPlayer.getCurrentPosition();
+ this.handler.sendJavascript("PhoneGap.Media.onStatus('" + this.id + "', "+MEDIA_POSITION+", "+curPos/1000.0f+");");
+ return curPos;
}
else {
return -1;
@@ -386,7 +394,7 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
* @param arg2 an extra code, specific to the error.
*/
public boolean onError(MediaPlayer mPlayer, int arg1, int arg2) {
- System.out.println("AudioPlayer.onError(" + arg1 + ", " + arg2+")");
+ Log.d(LOG_TAG, "AudioPlayer.onError(" + arg1 + ", " + arg2+")");
// TODO: Not sure if this needs to be sent?
this.mPlayer.stop();
@@ -409,5 +417,4 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
this.state = state;
}
-
}
diff --git a/framework/src/com/phonegap/CameraLauncher.java b/framework/src/com/phonegap/CameraLauncher.java
index 1ad4bac0..6ca85c43 100755
--- a/framework/src/com/phonegap/CameraLauncher.java
+++ b/framework/src/com/phonegap/CameraLauncher.java
@@ -26,8 +26,6 @@ import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.net.Uri;
-import android.os.Environment;
-import android.provider.MediaStore;
import android.util.Log;
/**
@@ -44,7 +42,12 @@ public class CameraLauncher extends Plugin {
private static final int CAMERA = 1; // Take picture from camera
private static final int SAVEDPHOTOALBUM = 2; // Choose image from picture library (same as PHOTOLIBRARY for Android)
+ private static final int JPEG = 0; // Take a picture of type JPEG
+ private static final int PNG = 1; // Take a picture of type PNG
+
private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
+ private int targetWidth; // desired width of the image
+ private int targetHeight; // desired height of the image
private Uri imageUri; // Uri of captured image
public String callbackId;
@@ -77,8 +80,18 @@ public class CameraLauncher extends Plugin {
if (args.length() > 2) {
srcType = args.getInt(2);
}
+ if (args.length() > 3) {
+ this.targetWidth = args.getInt(3);
+ }
+ if (args.length() > 4) {
+ this.targetHeight = args.getInt(4);
+ }
+ int encodingType = JPEG;
+ if (args.length() > 5) {
+ encodingType = args.getInt(5);
+ }
if (srcType == CAMERA) {
- this.takePicture(args.getInt(0), destType);
+ this.takePicture(args.getInt(0), destType, encodingType);
}
else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
this.getImage(args.getInt(0), srcType, destType);
@@ -112,7 +125,7 @@ public class CameraLauncher extends Plugin {
* @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
* @param returnType Set the type of image to return.
*/
- public void takePicture(int quality, int returnType) {
+ public void takePicture(int quality, int returnType, int encodingType) {
this.mQuality = quality;
// Display camera
@@ -120,13 +133,29 @@ public class CameraLauncher extends Plugin {
// Specify file so that large image is captured and returned
// TODO: What if there isn't any external storage?
- File photo = new File(DirectoryManager.getTempDirectoryPath(ctx), "Pic.jpg");
+ File photo = createCaptureFile(encodingType);
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
this.imageUri = Uri.fromFile(photo);
this.ctx.startActivityForResult((Plugin) this, intent, (CAMERA+1)*16 + returnType+1);
}
+ /**
+ * Create a file in the applications temporary directory based upon the supplied encoding.
+ *
+ * @param encodingType of the image to be taken
+ * @return a File object pointing to the temporary picture
+ */
+ private File createCaptureFile(int encodingType) {
+ File photo = null;
+ if (encodingType == JPEG) {
+ photo = new File(DirectoryManager.getTempDirectoryPath(ctx), "Pic.jpg");
+ } else {
+ photo = new File(DirectoryManager.getTempDirectoryPath(ctx), "Pic.png");
+ }
+ return photo;
+ }
+
/**
* Get image from photo library.
*
@@ -146,6 +175,50 @@ public class CameraLauncher extends Plugin {
new String("Get Picture")), (srcType+1)*16 + returnType + 1);
}
+ /**
+ * Scales the bitmap according to the requested size.
+ *
+ * @param bitmap The bitmap to scale.
+ * @return Bitmap A new Bitmap object of the same bitmap after scaling.
+ */
+ public Bitmap scaleBitmap(Bitmap bitmap) {
+ int newWidth = this.targetWidth;
+ int newHeight = this.targetHeight;
+ int origWidth = bitmap.getWidth();
+ int origHeight = bitmap.getHeight();
+
+ // If no new width or height were specified return the original bitmap
+ if (newWidth <= 0 && newHeight <= 0) {
+ return bitmap;
+ }
+ // Only the width was specified
+ else if (newWidth > 0 && newHeight <= 0) {
+ newHeight = (newWidth * origHeight) / origWidth;
+ }
+ // only the height was specified
+ else if (newWidth <= 0 && newHeight > 0) {
+ newWidth = (newHeight * origWidth) / origHeight;
+ }
+ // If the user specified both a positive width and height
+ // (potentially different aspect ratio) then the width or height is
+ // scaled so that the image fits while maintaining aspect ratio.
+ // Alternatively, the specified width and height could have been
+ // kept and Bitmap.SCALE_TO_FIT specified when scaling, but this
+ // would result in whitespace in the new image.
+ else {
+ double newRatio = newWidth / (double)newHeight;
+ double origRatio = origWidth / (double)origHeight;
+
+ if (origRatio > newRatio) {
+ newHeight = (newWidth * origHeight) / origWidth;
+ } else if (origRatio < newRatio) {
+ newWidth = (newHeight * origWidth) / origHeight;
+ }
+ }
+
+ return Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
+ }
+
/**
* Called when the camera view exits.
*
@@ -175,6 +248,8 @@ public class CameraLauncher extends Plugin {
bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
}
+ bitmap = scaleBitmap(bitmap);
+
// If sending base64 image back
if (destType == DATA_URL) {
this.processPicture(bitmap);
@@ -237,6 +312,7 @@ public class CameraLauncher extends Plugin {
if (destType == DATA_URL) {
try {
Bitmap bitmap = android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
+ bitmap = scaleBitmap(bitmap);
this.processPicture(bitmap);
bitmap.recycle();
bitmap = null;
diff --git a/framework/src/com/phonegap/ContactAccessorSdk5.java b/framework/src/com/phonegap/ContactAccessorSdk5.java
index bcb25227..7e856049 100644
--- a/framework/src/com/phonegap/ContactAccessorSdk5.java
+++ b/framework/src/com/phonegap/ContactAccessorSdk5.java
@@ -425,13 +425,28 @@ public class ContactAccessorSdk5 extends ContactAccessor {
JSONArray addresses, JSONArray phones, JSONArray emails,
JSONArray ims, JSONArray websites, JSONArray photos) {
try {
- contact.put("organizations", organizations);
- contact.put("addresses", addresses);
- contact.put("phoneNumbers", phones);
- contact.put("emails", emails);
- contact.put("ims", ims);
- contact.put("websites", websites);
- contact.put("photos", photos);
+ // Only return the array if it has at least one entry
+ if (organizations.length() > 0) {
+ contact.put("organizations", organizations);
+ }
+ if (addresses.length() > 0) {
+ contact.put("addresses", addresses);
+ }
+ if (phones.length() > 0) {
+ contact.put("phoneNumbers", phones);
+ }
+ if (emails.length() > 0) {
+ contact.put("emails", emails);
+ }
+ if (ims.length() > 0) {
+ contact.put("ims", ims);
+ }
+ if (websites.length() > 0) {
+ contact.put("websites", websites);
+ }
+ if (photos.length() > 0) {
+ contact.put("photos", photos);
+ }
}
catch (JSONException e) {
Log.e(LOG_TAG,e.getMessage(),e);
diff --git a/framework/src/com/phonegap/Device.java b/framework/src/com/phonegap/Device.java
index 60858bc9..aa8c52dd 100644
--- a/framework/src/com/phonegap/Device.java
+++ b/framework/src/com/phonegap/Device.java
@@ -18,7 +18,7 @@ import android.provider.Settings;
public class Device extends Plugin {
- public static String phonegapVersion = "1.0.0rc2"; // PhoneGap version
+ public static String phonegapVersion = "1.0.0rc3"; // PhoneGap version
public static String platform = "Android"; // Device OS
public static String uuid; // Device UUID
diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java
old mode 100755
new mode 100644
index a22622ba..d9ecccd9
--- a/framework/src/com/phonegap/DroidGap.java
+++ b/framework/src/com/phonegap/DroidGap.java
@@ -1123,7 +1123,7 @@ public class DroidGap extends PhonegapActivity {
try {
// Init parameters to new DroidGap activity and propagate existing parameters
HashMap params = new HashMap();
- params.put("loadingDialog", "");
+ params.put("loadingDialog", null);
if (this.ctx.loadInWebView) {
params.put("loadInWebView", true);
}