How to access device camera and save a photo in Oracle MAF

INTRODUCTION

Oracle MAF provides a very convenient way to access device features for your android/ios/windows device. You enable device feature access by enabling the correct plugin in the applications maf-application.xml
 
maf-core-plugins.PNG
 
Once the core plugin is enabled, all you have to do is use the MAF api to access device related features. You can find the related api links in the references below.
In this blog, I will demonstrate how to access the device camera to take a picture or select an existing picture from a picture gallery. The new photo taken (or the pre-existing photo) using the camera is then saved to the device’s local sqlite database. We will build a simple profile page where you can upload your photo and save it.

SETUP

Start by creating a Mobile FrameWork Application in Jdeveloper. Add a new feature to your application in the maf-feature.xml and create a new task flow under the Content Tab for the feature.
 
creatingTaskflow.PNG
 

Add two views and create the associated amx pages for each view. Your task flow will look like:
 
feature1_taskflow.PNG
 

ACCESSING THE DEVICE CAMERA

Add a new java class to the application called PhotoUtility. This class will be converted to a data control and used on page “view1” to upload and display a photo. Add a private String variable called “photo” to store the base64 encoded photo image as a string. Generate the accessors for this private variable and ensure that “Notify Listeners when property changes” flag is selected.

public class PhotoUtility {

private String photo;
private PropertyChangeSupport _propertyChangeSupport = new PropertyChangeSupport(this);

public PhotoUtility() {
super();
}

public void setPhoto(String photo) {
String oldPhoto = this.photo;
this.photo = photo;
_propertyChangeSupport.firePropertyChange("photo", oldPhoto, photo);
}

public void addPropertyChangeListener(PropertyChangeListener l) {
_propertyChangeSupport.addPropertyChangeListener(l);
}

public void removePropertyChangeListener(PropertyChangeListener l) {
_propertyChangeSupport.removePropertyChangeListener(l);
}

public String getPhoto() {
if (photo == null || photo.isEmpty()) {
getFromDB();
}
return photo;
}

Now, we will add two methods that will help to capture a new image from camera and allow you to select an existing image from a photo album on the device. The methods use the DeviceManagerFactory class to access the device camera. It provides the following api to launch the device camera and capture an image:

String getPicture(int quality,
                  int destinationType,
                  int sourceType,
                  boolean allowEdit,
                  int encodingType,
                  int targetWidth,
                  int targetHeight)
Provides access to the device's default camera application, which enables taking a picture or retrieving a previously-saved image See PhoneGap documentation for more details: http://docs.phonegap.com/en/1.0.0/phonegap_camera_camera.md.html#camera.getPicture
Parameters:
quality - - Quality of saved image. Range is [0, 100]
destinationType - - Choose the format of the return value. 0 = DESTINATIONTYPE_DATA_URL = Return image as base64 encoded string 1 = DESTINATIONTYPE_FILE_URI = Return image as a filename URI, like "file:///absolute/path/to/image.png" DESTINATIONTYPE_FILE_URI is recommended to avoid exhausting device resources.
sourceType - - Where should the picture come from? 0 = SOURCETYPE_PHOTOLIBRARY = Device's photo library 1 = SOURCETYPE_CAMERA = Take a picture with the device's camera 2 = SOURCETYPE_SAVEDPHOTOALBUM = Device's saved photo album
allowEdit - - Allow simple editing of image before selection
encodingType - - Choose the encoding of the returned image file. 0 = ENCODING_TYPE_JPEG = JPEG image 1 = ENCODING_TYPE_PNG = PNG image
targetWidth - - Width in pixels to scale image. Must be used with targetHeight. Aspect ratio is maintained
targetHeight - - Height in pixels to scale image. Must be used with targetWidth. Aspect ratio is maintained
Returns:
a String representing either base64 image data or a file URI, depending on the value of destinationType

 

Copy the two methods below to your PhotoUtility class:

public void getPhotoFromCamera() {
        String photo1 =
            DeviceManagerFactory.getDeviceManager().getPicture(40, DeviceManager.CAMERA_DESTINATIONTYPE_DATA_URL ,
                                                               DeviceManager.CAMERA_SOURCETYPE_CAMERA, false,
                                                               DeviceManager.CAMERA_ENCODINGTYPE_JPEG, 1000, 1000);
        photo1 = "data:image/jpeg;base64," + photo1;
    setPhoto(photo1);
    }

    public void getPhotoFromLibrary() {
        String photo1 =
            DeviceManagerFactory.getDeviceManager().getPicture(40, DeviceManager.CAMERA_DESTINATIONTYPE_DATA_URL ,
                                                               DeviceManager.CAMERA_SOURCETYPE_PHOTOLIBRARY, false,
                                                               DeviceManager.CAMERA_ENCODINGTYPE_JPEG, 1000, 1000);
        photo1 = "data:image/jpeg;base64," + photo1;
    setPhoto(photo1);
    }

 

Note the line:
photo1 = “data:image/jpeg;base64,” + photo1;

The MAF getPicture api returns a base 64 encoded string for the image.  You will use the class property photo in an amx image tag that displays the captured photo on the screen. The prefix added above helps the amx image tag decipher the variable contents to be base 64 encoded string.
Convert the PhotoUtility class to a datacontrol by selecting it in the project window, right click on it and select “Create Data Control”. We have enough now to complete the “view1” page.

 
PhotoUtility-datacontrol.PNG
 

From the data controls window, drag the “photo” variable as an outputtext component on the page. Similarly, drag the “getPhotoFromCamera()” and “getPhotoFromLibrary()” methods as buttons on the page. Drop an image tag from the Components window and use the binding created in the previous output text. Your view1 page should look like:

<amx:tableLayout id="tl1" halign="center" width="100%">
                            <amx:rowLayout id="rl1">                                
                                <amx:cellFormat id="cf2"  width="60%" halign="center" >
                                    <amx:image id="i1"
                                           source="#{(bindings.photo.inputValue != null)? bindings.photo.inputValue :&quot;/images/90.png&quot;}"
                                           styleClass="#{deviceScope.hardware.screen.diagonalSize gt 7 ? 'springboard-avatar' : 'springboard-avatar-phone'}"
                                           inlineStyle="width: 128px; height: 128px"
                                           shortDesc="Avatar Image"/>
                                </amx:cellFormat>
                                <amx:cellFormat id="cf3"  width="40%" halign="center" >
                                    <amx:commandButton actionListener="#{bindings.getPhotoFromLibrary.execute}"
                                           text="From Album"
                                           disabled="#{!bindings.getPhotoFromLibrary.enabled}"
                                           id="cb31"
                                           inlineStyle="-webkit-transition: background-color .2s, color .2s;transition: background-color .2s, color .2s;
                                            border-radius: 10; white-space: nowrap; text-align: center; outline: none;
                                            margin: 5px 0; margin-top: 11px; box-sizing: border-box; min-height: 20px;
                                            background-color: #0572CE; color: #FFFFFF; font-size: 12px;"
                                            />
                                    <amx:commandButton actionListener="#{bindings.getPhotoFromCamera.execute}"
                                           text="Take New"
                                           disabled="#{!bindings.getPhotoFromCamera.enabled}"
                                           id="cb4" inlineStyle="-webkit-transition: background-color .2s, color .2s;transition: background-color .2s, color .2s;
                                            border-radius: 10; white-space: nowrap; text-align: center; outline: none;
                                            margin: 5px 0; margin-top: 11px; box-sizing: border-box; min-height: 20px;
                                            background-color: #0572CE; color: #FFFFFF; font-size: 12px;"
                                            />
                                  </amx:cellFormat>
                            </amx:rowLayout>
                        </amx:tableLayout>

You are now ready to run the application and see this in action. This works well and its all great, but when you restart your application, the selected image is gone! In the next blog, we will make your image selection stay across application sessions. To do that, we will store the image to the local sqlite database. We will enhance the methods “getPhotoFromCamera” and “getPhotoFromLibrary” to persist the image string to the device database.
 
The complete sample application can be downloaded from here:
PhotoApp.zip

REFERENCES

Javadoc for DeviceManager
Javadoc for DeviceDataControl

vivek