Android let user pick/capture photo from gallery or camera-Collection of common programming errors

I want to that when a user clicks a button, he can choose gallery or camera, and that the program can retrieve the captured/picked photo. I tried a couple of things, but nothing seems to work completely. This is how I start the gallery so the user can pick a photo:

    Intent i = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    startActivityForResult(i,3);

And this is how I try to retrieve the by the user picked photo:

        Uri selectedImage = data.getData();

        filename = "NEWIMAGE";
        String[] filePathColumn = { MediaStore.Images.Media.DATA };

        Cursor cursor = getContentResolver().query(selectedImage,
                filePathColumn, null, null, null);
        cursor.moveToFirst();

        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
        String picturePath = cursor.getString(columnIndex);
        cursor.close();
        final int REQUIRED_SIZE=70;
        int scale = 1;
        BitmapFactory.Options options = new BitmapFactory.Options();
        if (options.outHeight > REQUIRED_SIZE || options.outWidth > REQUIRED_SIZE) {
            scale = (int)Math.pow(2, (int) Math.round(Math.log(REQUIRED_SIZE / 
               (double) Math.max(options.outHeight, options.outWidth)) / Math.log(0.5)));
        }

        options.inJustDecodeBounds = true;
        options.inSampleSize = scale;           
        photo = BitmapFactory.decodeFile(picturePath, options);

The error when I run it:

E/AndroidRuntime(21260): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=3, result=-1, data=Intent { dat=content://media/external/images/media/2449 }} to activity {com.aquariumzoekenpro.android/com.aquariumzoekenpro.android.LogboekNotitie}: java.lang.NullPointerException
E/AndroidRuntime(21260):    at android.app.ActivityThread.deliverResults(ActivityThread.java:3000)
E/AndroidRuntime(21260):    at android.app.ActivityThread.handleSendResult(ActivityThread.java:3043)
E/AndroidRuntime(21260):    at android.app.ActivityThread.access$1100(ActivityThread.java:127)
E/AndroidRuntime(21260):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1188)
E/AndroidRuntime(21260):    at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(21260):    at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime(21260):    at android.app.ActivityThread.main(ActivityThread.java:4441)
E/AndroidRuntime(21260):    at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(21260):    at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime(21260):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:823)
E/AndroidRuntime(21260):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:590)
E/AndroidRuntime(21260):    at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime(21260): Caused by: java.lang.NullPointerException
E/AndroidRuntime(21260):    at com.aquariumzoekenpro.android.LogboekNotitie.onActivityResult(LogboekNotitie.java:1483)
E/AndroidRuntime(21260):    at android.app.Activity.dispatchActivityResult(Activity.java:4649)
E/AndroidRuntime(21260):    at android.app.ActivityThread.deliverResults(ActivityThread.java:2996)
E/AndroidRuntime(21260):    ... 11 more

Capturing a photo with the camera and retrieving also fails. This is how I start the camera:

    Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);     
    String filename = "NEWIMAGE1";
    imageUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory().getPath()+"/"+filename));
    i.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
    startActivityForResult(i,2);

And this is how I try to retrieve the captured photo:

String filename = "NEWIMAGE1";
String urifilename = filename + ".jpg";
imageUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory().getPath()+"/"+urifilename));
this.getContentResolver().notifyChange(imageUri, null);
ContentResolver cr = this.getContentResolver();     
photo = android.provider.MediaStore.Images.Media.getBitmap(cr, imageUri);

The error I get from the logcat:

W/dalvikvm(21424): threadid=1: thread exiting with uncaught exception (group=0x40abc210)
E/AndroidRuntime(21424): FATAL EXCEPTION: main
E/AndroidRuntime(21424): java.lang.OutOfMemoryError
E/AndroidRuntime(21424):    at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
E/AndroidRuntime(21424):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:499)
E/AndroidRuntime(21424):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:555)
E/AndroidRuntime(21424):    at android.provider.MediaStore$Images$Media.getBitmap(MediaStore.java:710)
E/AndroidRuntime(21424):    at com.aquariumzoekenpro.android.LogboekNotitie.onActivityResult(LogboekNotitie.java:1429)
E/AndroidRuntime(21424):    at android.app.Activity.dispatchActivityResult(Activity.java:4649)
E/AndroidRuntime(21424):    at android.app.ActivityThread.deliverResults(ActivityThread.java:2996)
E/AndroidRuntime(21424):    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2451)
E/AndroidRuntime(21424):    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2492)
E/AndroidRuntime(21424):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1997)
E/AndroidRuntime(21424):    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3371)
E/AndroidRuntime(21424):    at android.app.ActivityThread.access$700(ActivityThread.java:127)
E/AndroidRuntime(21424):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1162)
E/AndroidRuntime(21424):    at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime(21424):    at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime(21424):    at android.app.ActivityThread.main(ActivityThread.java:4441)
E/AndroidRuntime(21424):    at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(21424):    at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime(21424):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:823)
E/AndroidRuntime(21424):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:590)
E/AndroidRuntime(21424):    at dalvik.system.NativeStart.main(Native Method)

So I want to let the user choose to either pick an image from the gallery or to capture a photo with the camera. Then I want the program to get the picked or captured image in the original quality, so I can show it in an Imageview or something.

Thanks in advance,

Simon

  1. Simon, I have this working for picking from the gallery using this intent:

    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.setType("image/*");
    

    And then handling the choice like this:

      mFilename=null;
      mPath=null;
    
      Uri selectedImage = data.getData();
      final String[] filePathColumn = { MediaColumns.DATA, MediaColumns.DISPLAY_NAME };
      Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
    
      // some devices (OS versions return an URI of com.android instead of com.google.android 
      if (selectedImage.toString().startsWith("content://com.android.gallery3d.provider"))  
      {
          // use the com.google provider, not the com.android provider. 
          selectedImage = Uri.parse(selectedImage.toString().replace("com.android.gallery3d","com.google.android.gallery3d"));
      }
    
      if (cursor != null) {
          cursor.moveToFirst();
          int columnIndex = cursor.getColumnIndex(MediaColumns.DATA);
    
          // if it is a picasa image on newer devices with OS 3.0 and up
          if (selectedImage.toString().startsWith("content://com.google.android.gallery3d"))
          {
              columnIndex = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME);
              if (columnIndex != -1)
              {
                  final Uri uriurl = selectedImage;
                  // should do this in a background thread, since we are fetching a large image from the web
                  mFilename = getGalleryFile(activity, uriurl);
              }
          }
          else
          {
              // it is a regular local image file
              String filePath = cursor.getString(columnIndex);
              cursor.close();
              mFilename = filePath;
          }
      }
      // If it is a picasa image on devices running OS prior to 3.0
      else if (selectedImage != null && selectedImage.toString().length() > 0)
      {
          final Uri uriurl = selectedImage;
          // should do this in a background thread, since we are fetching a large image from the web
          mFilename = getGalleryFile(activity, uriurl);
       }
    

    And as for the camera part of what you want, what you’re doing looks fine you are just running out of memory creating the Bitmap. You should use BitmapFactory::decodeStream with BitmapFactory.Options set to scale the incoming image to the size of the View you’re going to display it in.

    As explained below, to complete the answer here is getGalleryFile:

    public static String getGalleryFile(Activity activity, Uri url)
    {
        String fileName=null;
        File path;
    
        try {
            // getCameraStoragePath is a function in my activity
            // that returns a location where I'm writing files
            // you could use Environment.getExternalStorageDirectory()
            // or ....
            path = new File(MyTask.getCameraStoragePath());
        } catch (Exception e1) {
            // todo: handle exception
            return null;
        }
    
        SimpleDateFormat timeStampFormat = new SimpleDateFormat("yyyyMMddHHmmssSS");
        fileName = "gallery." + timeStampFormat.format(new java.util.Date()) + ".jpg";
        File out = new File(path, fileName);
    
        try {
            InputStream is = null;
            if (url.toString().startsWith("content://com.google.android.gallery3d"))
            {
                is=activity.getContentResolver().openInputStream(url);
            }
            else
            {
                is=new URL(url.toString()).openStream();
            }
    
            OutputStream os = new FileOutputStream(out);
    
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) != -1)
            {
                os.write(buffer, 0, len);
            }
    
            os.close();
            return out.getAbsolutePath();
        }
        catch (Exception ex)
        {
            // todo: handle exception
            return null;
        }
    }
    

Originally posted 2013-11-16 20:52:27.