25

It seems to be the simplest thing in the world: taking a picture within your Android app using the default camera activity. However, there are many pitfalls which are covered in several posts across StackOverflow and the web as, for instance, Null Intents being passed back, the orientation of the picture not being correct or OutOfMemoryErrors.

I'm looking for a solution that allows me to

  1. start the camera activity via the camera intent,
  2. retrieve the Uri of the photo, and
  3. retrieve the correct orientation of the photo.

Moreover, I would like to avoid a device configuration (manufacturer, model, os version) specific implementation as far as possible. So I'm wondering: what is the best way to achieve this?

Ralf
  • 709
  • 6
  • 14
  • Some users approached me saying that the camera is not working on their device. I fixed the bug, improved the code, and updated my post (see above). Please let me know if you experience issues or have questions. – Ralf Apr 25 '13 at 10:18
  • No, I haven't same problem. I just considered your question interesting. I you want - post in answer all, what you do to solve the problem and bounty will yours. – jimpanzer Apr 26 '13 at 09:36
  • please, provide answer, that bounty was not lost. – jimpanzer Apr 29 '13 at 11:57
  • Please see the answer below. – Ralf Apr 30 '13 at 08:11
  • I was so upset when I got the camera working perfectly fine for the nexus 4 and then all of a sudden I port it to the S3 and it blows up. This was perfect, THANKS! – Aaron Smentkowski Jun 03 '13 at 19:42
  • Can we put this onto github? – Kleptine Oct 21 '13 at 20:40
  • Yes, I will soon. I will let you know. – Ralf Oct 22 '13 at 10:08
  • +1 for summary and a solution. Doesn't get rid of the itch though. One reason is that the user might have chosen a custom default camera; the code looks at who manufactured the _phone_, not the currently default camera app. I'll look into the possibility of using the package name to switch behavior instead. Also, I'd prefer to invoke the intent according to API and cover up for buggy behavior _after_ invocation. That would sort of reward manufacturers who fix their implementation. Do you think that would be possible, given the issues with orientation and all? – volley Oct 23 '13 at 07:40
  • This is cool, but please put it on github as library of some sort, I just tried implementing your code and you have a strange style I dont quite understand. For example why dont you use setContentView instead of some weird inflating in onCreate? – A. Steenbergen Oct 23 '13 at 15:47
  • Hey man, do you mind if I put this out onto GitHub or are you going to? Would be great to help out all the people that are getting stuck, and would make it easy to make quick updates with new phone releases. – Kleptine Dec 12 '13 at 05:24
  • I'm going to do that very soon and I'll share the link here asap. I'm currently trying to figure out how to fix the issue on Android devices running on CyanogenMod. It seems to work perfeclty now on all stock Android devices. – Ralf Dec 12 '13 at 10:56
  • Hi Ralf, could you please extract the answer part from your question to an answer? – bummi Dec 20 '13 at 16:48
  • 1
    This question appears to be off-topic because it is not a question but a post providing as solution. This topic could fit for Stack Overflow if separated into a question and an answer. – bummi Dec 20 '13 at 17:22
  • There is [a meta post](http://meta.stackexchange.com/questions/212952/how-to-handle-a-questions-which-does-not-seem-to-be-a-question/212953#212953) discussing how this post should be handled. Feel free to discuss it there. – Servy Dec 20 '13 at 17:24
  • The code is now available on [github](https://github.com/ralfgehrer/AndroidCameraUtil). Additionally, I separated the question part from the answer part. Please consider to reopen the thread. Many thanks in advance! – Ralf Jan 02 '14 at 15:34

4 Answers4

22

UPDATE: January 2nd, 2014: I tried really hard to avoid implementing different strategies based on the device manufacturer. Unfortunately, I did not get around it. Going through hundreds of posts and talking to several developers, nobody found a solution that works on all devices without implementing device manufacturer specific code.

After I posted my solution here on StackOverflow, some developers asked me to publish my code on github. So here it is now: AndroidCameraUtil on github

The code was successfully tested on a wide variety of devices with Android API-Level >= 8. For a complete list, please see the Readme file on github.

The CameraIntentHelperActivity provides the main functionality, which is also described in more detail in the following.

Calling the default camera activity:

  • for Samsung and Sony devices: I call the camera activity with the method call to startActivityForResult. I only set the constant CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE. I do NOT set any other intent extras.
  • for all other devices: I call the camera activity with the method call to startActivityForResult as previously. This time, however, I additionally set the intent extra MediaStore.EXTRA_OUTPUT and provide an URI, where I want the image to be stored.

In both cases I remember the time the camera activity was started.


On camera activity result:

  1. Mediastore: First, I try to read the photo being captured from the MediaStore. Using a mangedQuery on the MediaStore content, I retrieve the latest image being taken, as well as its orientation property and its timestamp. If I find an image and it was not taken before the camera intent was called, it is the image I was looking for. Otherwise, I dismiss the result and try one of the following approaches.
  2. Intent extra: Second, I try to get an image Uri from intent.getData() of the returning intent. If this is not successful either, I continue with step 3.
  3. Default photo Uri: If all of the above mentioned steps did not work, I use the image Uri I passed to the camera activity.

At this point, I retrieved the photo Uri and its orientation which I pass to my UploadPhotoActivity.


Image processing

Please take a close look at my BitmapHelper class. It is based on the code described in detail in that tutorial.

Moreover, the shrinkBitmap method also rotates the image if required based on the orientation information extracted earlier.


I hope this is helpful to some of you.

Ralf
  • 709
  • 6
  • 14
  • 1
    Can you please provide more information, e.g. what Android version are you running, do you have a custom Rom installed, do you use a third party camera app, etc. – Ralf Aug 07 '14 at 14:20
  • I bought Sony Xperia C2305 Android 4.2.2 , Build number 16.0.B.2.13 20 days ago .. I haven't installed anything, using the Sony's default camera app .. can you help me out ? The cam app is opened but after taping the "take pic button" a flash and then back to the calling screen.. the pictures is not saved.. this app of mine worked perfectly on samsung and some local vendor cell phones.. – Sharp Edge Aug 08 '14 at 07:29
  • I suppose you have to implement a device specifc "strategy". You can do this by simply adding the following lines to the startCameraIntent method within the CameraIntentHelperActivity class. Please ensure that the model field actually holds the value "C2305": if (manufacturer.contains("sony") && model.contains("C2305")) { setPreDefinedCameraUri = true; } – Ralf Aug 08 '14 at 16:06
  • or i could make a custom camera app from the camera API.. with basic features so far the creating own camera app instead of intent seems to be the better way for me.. Thanks for the quick Response @Ralf – Sharp Edge Aug 09 '14 at 07:58
  • 1
    do You plan on making easier to add to project like with `compile 'de.ecostatic:camerautil:1.0.0'` ? it would be very, very handful :) – jean d'arme May 06 '15 at 20:43
0

I have tested this code with a Sony Xperia Go, Samsung Galaxy SII, Samsung Galaxy SIII mini and a Samsung Galaxy Y it worked on all devices!

But on the LG E400 (2.3.6) it didn’t work and you get double pictures in the gallery. So i have added the manufacturer.contains("lge") in the void startCameraIntent() and it fixed the problem.

if(!(manufacturer.contains("samsung")) && !(manufacturer.contains("sony")) && !(manufacturer.contains("lge"))) {
    String filename = System.currentTimeMillis() + ".jpg";
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.TITLE, filename);
    cameraPicUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, cameraPicUri);
}
Bhavesh G
  • 3,000
  • 4
  • 39
  • 66
Iwan
  • 11
  • 3
0

On a Galaxy S3 with CM 10.1 I get a nullpointer exception in BitmapHelper:

bm = BitmapFactory.decodeFileDescriptor(fileDescriptor.getFileDescriptor(), null, options);

subsequently my UploadPhotoActivity fails at:

    try {
        photo = BitmapHelper.readBitmap(this, cameraPicUri);
        if (photo != null) {
            photo = BitmapHelper.shrinkBitmap(photo, 600, rotateXDegrees);
            thumbnail = BitmapHelper.shrinkBitmap(photo, 100);
            ImageView imageView = (ImageView) findViewById(R.id.sustainable_action_photo);
            imageView.setImageBitmap(photo);                
        } else {
            Log.e(TAG,"IMAGE ERROR 1");
        }
    } catch (Exception e) {
            Log.e(TAG,"IMAGE ERROR 2");
        e.printStackTrace();
    }

at the second log (IMAGE ERROR 2). After a couple of tries my camera broke and I got a "Could not connect to camera"-error.

Tested it on a nexus 7 and it works perfectly.

Edit: Narrowed it down to this:

fileDescriptor = context.getContentResolver().openAssetFileDescriptor(selectedImage, "r");

Although selectedImage contains this:

file:///storage/emulated/0/DCIM/Camera/IMG_20131023_183343.jpg

The fileDescriptor returns a FileNotFoundException. I checked the file system and the image is not saved at this location. The cameraPicUri in TakePhotoActivity points to a non existant image. I am currently checking where it all goes wrong.

Edit2: I figured out the error: Since the device is a Samsung, and tells the App that it is a Samsung device, your Samsung specific fixes are applied. Cyanogenmod does not need those fixes though, and in the end the code breaks. Once you remove

(manufacturer.contains("samsung")) &&

It works. Since this is a custom ROM you could not plan for that of course. I am trying to figure out a way to detect if the device is running cyanogenmod and then include this in your code.

Thanks for a nice camera fix!

Edit3: I fixed it to run on Cyanogenmod on the Galaxy S3 by changing your code to this: Well, now it sometimes works, sometimes it does not. Strange.

if (getPackageManager().hasSystemFeature("com.cyanogenmod.android") || (!(manufacturer.contains("samsung")) && !(manufacturer.contains("sony")) && !(manufacturer.contains("lge"))))

A. Steenbergen
  • 3,360
  • 4
  • 34
  • 51
  • Hey, I updated my code above and fixed some bugs. Maybe this also solves your issue. – Ralf Nov 20 '13 at 16:53
0

I experience some problems when using this with Sony Xperia Z5.

I added this and it got a lot better.

if (buildType.contains("sony")&& buildDevice.contains("e5823")) {
                setPreDefinedCameraUri = true;}

But 4 times out of 22 it restarted the camera and once it restarted two times. I restarted the App due to every test. Is there some way to get around this or do I accept this result?

The thing is that if the camera restarts I can press the back button twice and boom, the image is there in my Imageview and saved

Waffles.Inc
  • 3,310
  • 4
  • 13
  • 17