diff --git a/framework/assets/js/camera.js b/framework/assets/js/camera.js
old mode 100644
new mode 100755
index 4b42470f..0933c9da
--- a/framework/assets/js/camera.js
+++ b/framework/assets/js/camera.js
@@ -4,14 +4,46 @@
  *
  * @constructor
  */
-function Camera() {
+Camera = function() {
     this.successCallback = null;
     this.errorCallback = null;
     this.options = null;
 };
 
 /**
- * Takes a photo and returns the image as a base64 encoded `String`.
+ * Format of image that returned from getPicture.
+ *
+ * Example: navigator.camera.getPicture(success, fail,
+ *              { quality: 80,
+ *                destinationType: Camera.DestinationType.DATA_URL,
+ *                sourceType: Camera.PictureSourceType.PHOTOLIBRARY})
+ */
+Camera.DestinationType = {
+    DATA_URL: 0,                // Return base64 encoded string
+    FILE_URI: 1                 // Return file uri (content://media/external/images/media/2 for Android)
+};
+Camera.prototype.DestinationType = Camera.DestinationType;
+
+/**
+ * Source to getPicture from.
+ *
+ * Example: navigator.camera.getPicture(success, fail,
+ *              { quality: 80,
+ *                destinationType: Camera.DestinationType.DATA_URL,
+ *                sourceType: Camera.PictureSourceType.PHOTOLIBRARY})
+ */
+Camera.PictureSourceType = {
+    PHOTOLIBRARY : 0,           // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
+    CAMERA : 1,                 // Take picture from camera
+    SAVEDPHOTOALBUM : 2         // Choose image from picture library (same as PHOTOLIBRARY for Android)
+};
+Camera.prototype.PictureSourceType = Camera.PictureSourceType;
+
+/**
+ * Gets a picture from source defined by "options.sourceType", and returns the
+ * image as defined by the "options.destinationType" option.
+
+ * The defaults are sourceType=CAMERA and destinationType=DATA_URL.
  *
  * @param {Function} successCallback
  * @param {Function} errorCallback
@@ -34,15 +66,19 @@ Camera.prototype.getPicture = function(successCallback, errorCallback, options)
     this.successCallback = successCallback;
     this.errorCallback = errorCallback;
     this.options = options;
-    var capturetype = "base64";
     var quality = 80;
-    if (this.options.capturetype) {
-        capturetype = this.options.capturetype;
-    }
     if (options.quality) {
         quality = this.options.quality;
     }
-    PhoneGap.execAsync(null, null, "Camera", "takePicture", [quality, capturetype]);
+    var destinationType = Camera.DestinationType.DATA_URL;
+    if (this.options.destinationType) {
+        destinationType = this.options.destinationType;
+    }
+    var sourceType = Camera.PictureSourceType.CAMERA;
+    if (typeof this.options.sourceType == "number") {
+        sourceType = this.options.sourceType;
+    }
+    PhoneGap.execAsync(null, null, "Camera", "takePicture", [quality, destinationType, sourceType]);
 };
 
 /**
diff --git a/framework/src/com/phonegap/CameraLauncher.java b/framework/src/com/phonegap/CameraLauncher.java
index 92183000..cb05721b 100755
--- a/framework/src/com/phonegap/CameraLauncher.java
+++ b/framework/src/com/phonegap/CameraLauncher.java
@@ -2,6 +2,7 @@ package com.phonegap;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.OutputStream;
 
@@ -20,6 +21,7 @@ import android.graphics.Bitmap.CompressFormat;
 import android.net.Uri;
 import android.os.Environment;
 import android.webkit.WebView;
+import android.provider.MediaStore;
 
 /**
  * This class launches the camera view, allows the user to take a picture, closes the camera view,
@@ -28,12 +30,18 @@ import android.webkit.WebView;
  */
 public class CameraLauncher implements Plugin {
 
-    WebView webView;					// WebView object
-    DroidGap ctx;						// DroidGap object
+	private static final int DATA_URL = 0;				// Return base64 encoded string
+	private static final int FILE_URI = 1;				// Return file uri (content://media/external/images/media/2 for Android)
+	
+	private static final int PHOTOLIBRARY = 0;			// Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
+	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)
+	
+    WebView webView;						// WebView object
+    DroidGap ctx;							// DroidGap object
 
-	private int mQuality;				// Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
-	private Uri imageUri;				// Uri of captured image 
-	private boolean base64 = true;
+	private int mQuality;					// Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
+	private Uri imageUri;					// Uri of captured image 
 	
     /**
      * Constructor.
@@ -74,7 +82,20 @@ public class CameraLauncher implements Plugin {
 		
 		try {
 			if (action.equals("takePicture")) {
-				this.takePicture(args.getInt(0), args.getString(1));
+				int destType = DATA_URL;
+				if (args.length() > 1) {
+					destType = args.getInt(1);
+				}
+				int srcType = CAMERA;
+				if (args.length() > 2) {
+					srcType = args.getInt(2);
+				}
+				if (srcType == CAMERA) {
+					this.takePicture(args.getInt(0), destType);
+				}
+				else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
+					this.getImage(srcType, destType);
+				}
 			}
 			return new PluginResult(status, result);
 		} catch (JSONException e) {
@@ -130,12 +151,8 @@ public class CameraLauncher implements 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, String returnType) {
+	public void takePicture(int quality, int returnType) {
 		this.mQuality = quality;
-		this.base64 = false;
-		if (returnType.equals("base64")) {
-			this.base64 = true;
-		}
 		
 		// Display camera
         Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
@@ -146,7 +163,22 @@ public class CameraLauncher implements Plugin {
         intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
         this.imageUri = Uri.fromFile(photo);
 
-        this.ctx.startActivityForResult((Plugin) this, intent);
+        this.ctx.startActivityForResult((Plugin) this, intent, (CAMERA+1)*16 + returnType+1);
+	}
+	
+	/**
+	 * Get image from photo library.
+	 * 
+	 * @param returnType
+	 */
+	// TODO: Images selected from SDCARD don't display correctly, but from CAMERA ALBUM do!
+	public void getImage(int srcType, int returnType) {
+		Intent intent = new Intent();
+		intent.setType("image/*");
+		intent.setAction(Intent.ACTION_GET_CONTENT);
+		intent.addCategory(Intent.CATEGORY_OPENABLE);
+		this.ctx.startActivityForResult((Plugin) this, Intent.createChooser(intent,
+				new String("Get Picture")), (srcType+1)*16 + returnType + 1);
 	}
 
     /**
@@ -158,61 +190,98 @@ public class CameraLauncher implements Plugin {
      * @param intent			An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
      */
 	public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+		
+		// Get src and dest types from request code
+		int srcType = (requestCode/16) - 1;
+		int destType = (requestCode % 16) - 1;
 
-		// If image available
-		if (resultCode == Activity.RESULT_OK) {
-			try {
-				// Read in bitmap of captured image
-				Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
-				
+		// If CAMERA
+		if (srcType == CAMERA) {
+			
+			// If image available
+			if (resultCode == Activity.RESULT_OK) {
+				try {
+					// Read in bitmap of captured image
+					Bitmap bitmap = android.provider.MediaStore.Images.Media.getBitmap(this.ctx.getContentResolver(), imageUri);
+
+					// If sending base64 image back
+					if (destType == DATA_URL) {
+						this.processPicture(bitmap);
+					}
+
+					// If sending filename back
+					else if (destType == FILE_URI){
+						// Create entry in media store for image
+						// (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
+						ContentValues values = new ContentValues();
+						values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
+						Uri uri = null;
+						try {
+							uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+						} catch (UnsupportedOperationException e) {
+							System.out.println("Can't write to external media storage.");
+							try {
+								uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
+							} catch (UnsupportedOperationException ex) {
+								System.out.println("Can't write to internal media storage.");							
+								this.failPicture("Error capturing image - no media storage found.");
+								return;
+							}
+						}
+
+						// Add compressed version of captured image to returned media store Uri
+						OutputStream os = this.ctx.getContentResolver().openOutputStream(uri);
+						bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
+						os.close();
+
+						// Send Uri back to JavaScript for viewing image
+						this.ctx.sendJavascript("navigator.camera.success('" + uri.toString() + "');");
+					}
+				} catch (IOException e) {
+					e.printStackTrace();
+					this.failPicture("Error capturing image.");
+				}		
+			}
+
+			// If cancelled
+			else if (resultCode == Activity.RESULT_CANCELED) {
+				this.failPicture("Camera cancelled.");
+			}
+
+			// If something else
+			else {
+				this.failPicture("Did not complete!");
+			}
+		}
+		
+		// If retrieving photo from library
+		else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
+			if (resultCode == Activity.RESULT_OK) {
+				Uri uri = intent.getData();
+				android.content.ContentResolver resolver = this.ctx.getContentResolver();
 				// If sending base64 image back
-				if (this.base64) {
-					this.processPicture(bitmap);
+				if (destType == DATA_URL) {
+					try {
+						Bitmap bitmap =	android.graphics.BitmapFactory.decodeStream(resolver.openInputStream(uri));
+						this.processPicture(bitmap);
+					} catch (FileNotFoundException e) {
+						e.printStackTrace();
+						this.failPicture("Error retrieving image.");
+					}
 				}
 				
 				// If sending filename back
-				else {
-					// Create entry in media store for image
-					// (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
-					ContentValues values = new ContentValues();
-					values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
-					Uri uri = null;
-					try {
-						uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
-					} catch (UnsupportedOperationException e) {
-						System.out.println("Can't write to external media storage.");
-						try {
-							uri = this.ctx.getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
-						} catch (UnsupportedOperationException ex) {
-							System.out.println("Can't write to internal media storage.");							
-				        	this.failPicture("Error capturing image - no media storage found.");
-				        	return;
-						}
-					}
-	            
-					// Add compressed version of captured image to returned media store Uri
-					OutputStream os = this.ctx.getContentResolver().openOutputStream(uri);
-					bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
-					os.close();
-            	
-					// Send Uri back to JavaScript for viewing image
-					this.ctx.sendJavascript("navigator.camera.success('" + uri.toString() + "');");
+				else if (destType == FILE_URI) {
+					this.ctx.sendJavascript("navigator.camera.success('" + uri + "');");
 				}
-			} catch (IOException e) {
-				e.printStackTrace();
-	        	this.failPicture("Error capturing image.");
-			}		
+			}
+			else if (resultCode == Activity.RESULT_CANCELED) {
+				this.failPicture("Selection cancelled.");				
+			}
+			else {
+				this.failPicture("Selection did not complete!");				
+			}
 		}
-		
-		// If cancelled
-		else if (resultCode == Activity.RESULT_CANCELED) {
-			this.failPicture("Camera cancelled.");
-		}
-		
-		// If something else
-	    else {
-	    	this.failPicture("Did not complete!");
-	    }
 	}
 	
 	/**
diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java
index 3fa921ed..4786d357 100755
--- a/framework/src/com/phonegap/DroidGap.java
+++ b/framework/src/com/phonegap/DroidGap.java
@@ -25,7 +25,6 @@ package com.phonegap;
 
 
 import com.phonegap.api.Plugin;
-import java.util.HashMap;
 import com.phonegap.api.PluginManager;
 
 import android.app.Activity;
@@ -91,10 +90,8 @@ public class DroidGap extends Activity {
     private String url;							// The initial URL for our app
     private String baseUrl;						// The base of the initial URL for our app
 
-    // Variables to manage ActivityResultCallbacks
-    private int activityResultCallbackCounter = 1000;
-    private HashMap<Integer,Plugin> activityResultCallbacks = new HashMap<Integer,Plugin>();
-     
+    private Plugin activityResultCallback = null;	// Plugin to call when activity result is received
+         
     /** 
      * Called when the activity is first created. 
      * 
@@ -677,13 +674,11 @@ public class DroidGap extends Activity {
      *  
      * @param command			The command object
      * @param intent			The intent to start
-     * @return					The request code to use for the callback
+     * @param requestCode		The request code that is passed to callback to identify the activity
      */
-    public int startActivityForResult(Plugin command, Intent intent) {
-    	int requestCode = this.activityResultCallbackCounter++;
-    	this.activityResultCallbacks.put(requestCode, command);
+    public void startActivityForResult(Plugin command, Intent intent, int requestCode) {
+    	this.activityResultCallback = command;
     	super.startActivityForResult(intent, requestCode);
-    	return requestCode;
     }
 
      @Override
@@ -698,8 +693,7 @@ public class DroidGap extends Activity {
      */
     protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
         super.onActivityResult(requestCode, resultCode, intent);
-        
-        Plugin callback = this.activityResultCallbacks.remove(requestCode);
+        Plugin callback = this.activityResultCallback;
         if (callback != null) {
         	callback.onActivityResult(requestCode, resultCode, intent); 
         }