My Experiments with Android : Camera (Part 2/X : Camera Intent API)

pic credits.
As I discussed in my previous Article, the Camera Intent API (Am not sure its the actual terminology, but well.) is a simple and light way of achieving our original aim of receiving a picture captured via camera.

In a nutshell, our app will not have any camera implementation of our own, we would be simply delegating our requirement to the system camera app. On a button click, the system app would open, take a picture and send it to our app.

why is it good? Well:
  1.  It provides a lot of small features  like retaking a picture , toggling front/back/other cameras, toggling flashlight /hdr ,etc . basically it provides access to all features from the default camera app
  2. Since default camera app is being used, we are saved from implementing these features manually and in a Thread safe/ Leak proof manner.
  3. We are able to receive a picture directly with minimum permissions and checks
  4. It even provides us with a way to  either receive a thumbnail* or actual image* {covered later in this article} this is a significant feature based on your app usage.
Why is it bad ? Well :
  1.  We are using system camera and that is that. Its like a sandbox model: it will handle all the process of taking picture itself and would send the result to us at the end. Our app is in no control of the live preview* or other image data.
  2. something i forgot
  3. something i forgot
So let's dive into it. Let's assume that our app consist of a Button , on the click of which the camera should open and user should be able to click a picture. when user presses send, our app is able to recieve that image inside an ImageView. The ui would look something like below, and its java code is here




Getting the captured picture thumbnail.

This would be rather an easy task:
1. We put an optional feature request in your manifest(This will prevent our app from being installed on a device that lacks a camera.)

2. in our main activity , we call the startActivityForResult() with an Intent having action as ACTION_IMAGE_CAPTURE and a request code.
3. we receive image as bitmap in onActivityResult()

The image we receive in onActivity result is actually a very reduced version(thumbnail) of the actual picture. This could be used as a gallery icon or in a small profile pic view, but not elsewhere. To be able to put the actual image in a bigger preview pane or something like that, we have to perform some more steps.



Getting the original, full-HD captured picture.

  • We receive a reduced , small size size copy of our captured image because intent can carry only upto a specific size of data when passed between different apps and activities. The image captured by our camera can be as large as a 6mb bitmap.  Thus we have to make the camera save it in a file so we can access it in our app via its Uri. (Any big file or data is accessed via uri in android) . This would also mean adding read/write permissions in manifest and java code(runtime permission checks).
  • But with the usage of uri comes its own set of problems for android 23+ : The file://uri are banned and causes some exceptions (read more here .) So we have to implement a File Provider in manifest, R.asset.xml and java code.
  • With a file provider, we are pretty much done. Our button click would create a temporary file and pass its uri to system cam, the user would capture the image  via system cam and system will write all the bitmap to this temporary file. and we could simply access and use our now temporary-turned to-image file via its uri
  • But this image could still cause problems for our ui. these images are of very high resolution, and they should be used with a scaling algorithm before p setting it in ui. Most of the time, this image would also be somehow received as rotated by some angle . The rotating algorithm could fix that. I found a stack overflow solution having one such algorithm, but i would definably recommend picasso or glide library for such tasks
  • Thus our code becomes something like this:


This code follows along the lines of following steps:
(0. add permission WRITE_STORAGE_EXTERNAL/READ_STORAGE_INTERNAL in manifest)

1. call the code to check this permission at runtime todo
2 create temporary file in public external directory(or your internal directory)
(3-internal: your app should have a file provider , make it in manifest and xml)
3 if succesfully created, generate its uri via file provider.
4 send it to camera app by passing it as Extra data attached to OUTPUT key.
5 Recieve captured image Bitmap in  onActivity or Result Recieve image Uri in OnActivityResult. You will not be receiving the captured hdImage or its uri in onActivity result, because you already have them! The OS will write image data to the same temp file you previously created and its uri will remain the same. This function would just act as an alert about the OS completing its actions and for you to start reading/ using this image uri.
The file it will now point to will have a high res picture. We use a scaling algorithm (https://stackoverflow.com/a/31720143/7500651) before displaying it.


Comments