function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
hylim12hylim12 

Camera doesnt work in sample hybrid app (contact explorer)

Hi, so i follow the guide provided here to create a Hybrid mobile app (Android) in Eclipse.

 

Everything seems ok, i am able to load contact list but after i capture a photo for the contact, it stays there and did not return back to my apps. the log shows:

 

09-26 05:24:22.827: E/SoundPool(289): error loading /system/media/audio/ui/Effect_Tick.ogg
09-26 05:24:22.827: W/AudioService(289): Soundpool could not load file: /system/media/audio/ui/Effect_Tick.ogg
09-26 05:24:22.838: E/SoundPool(289): error loading /system/media/audio/ui/Effect_Tick.ogg
09-26 05:24:22.838: W/AudioService(289): Soundpool could not load file: /system/media/audio/ui/Effect_Tick.ogg
09-26 05:24:22.847: E/SoundPool(289): error loading /system/media/audio/ui/Effect_Tick.ogg
09-26 05:24:22.847: W/AudioService(289): Soundpool could not load file: /system/media/audio/ui/Effect_Tick.ogg
09-26 05:24:22.847: E/SoundPool(289): error loading /system/media/audio/ui/Effect_Tick.ogg
09-26 05:24:22.887: W/AudioService(289): Soundpool could not load file: /system/media/audio/ui/Effect_Tick.ogg
09-26 05:24:22.897: E/SoundPool(289): error loading /system/media/audio/ui/Effect_Tick.ogg
09-26 05:24:22.897: W/AudioService(289): Soundpool could not load file: /system/media/audio/ui/Effect_Tick.ogg
09-26 05:24:22.897: E/SoundPool(289): error loading /system/media/audio/ui/KeypressStandard.ogg
09-26 05:24:22.928: W/AudioService(289): Soundpool could not load file: /system/media/audio/ui/KeypressStandard.ogg
09-26 05:24:22.928: E/SoundPool(289): error loading /system/media/audio/ui/KeypressSpacebar.ogg
09-26 05:24:22.928: W/AudioService(289): Soundpool could not load file: /system/media/audio/ui/KeypressSpacebar.ogg
09-26 05:24:22.937: E/SoundPool(289): error loading /system/media/audio/ui/KeypressDelete.ogg
09-26 05:24:22.977: W/AudioService(289): Soundpool could not load file: /system/media/audio/ui/KeypressDelete.ogg
09-26 05:24:22.977: E/SoundPool(289): error loading /system/media/audio/ui/KeypressReturn.ogg
09-26 05:24:22.977: W/AudioService(289): Soundpool could not load file: /system/media/audio/ui/KeypressReturn.ogg
09-26 05:24:22.987: W/AudioService(289): onLoadSoundEffects(), Error -1 while loading samples

 

is this the reason causing the problem? Im using Eclipse Android Emulator.

 

Please advice is there any working sample else where?

 

Thanks

bhariharanbhariharan

I have observed this behavior in the past in some emulators. Some Android emulators are quirky with respect to camera behavior, depending on the configuration. Please try to use an Android device to test camera related functionality.

hylim12hylim12

I tried on Samsung S3. Able to take photo but when return back to my Apps, nothing happen, the photo is not uploaded to my Salesforce.

 

Here is my VF code:

 

<apex:page docType="html-5.0"
	       showHeader="false" sidebar="false"
		   standardController="Contact">          
	<apex:stylesheet value="{!URLFOR($Resource.MobileSample_Resources_jQueryMobile, 'jquery.mobile-1.3.0.min.css')}"/>
	<apex:includeScript value="{!URLFOR($Resource.MobileSample_Resources_jQueryMobile, 'jquery-1.9.1.min.js')}"/>
	<apex:includeScript value="{!URLFOR($Resource.MobileSample_Resources_jQueryMobile, 'jquery.mobile-1.3.0.min.js')}"/>
	<apex:includeScript value="{!URLFOR($Resource.MobileSample_Resources_jQueryMobile, 'cordova.force.js')}"/>
	<apex:includeScript value="{!URLFOR($Resource.MobileSample_Resources_jQueryMobile, 'backbone/underscore-1.4.4.min.js')}"/>
	<apex:includeScript value="{!URLFOR($Resource.MobileSample_Resources_jQueryMobile, 'force.entity.js')}"/>
	<apex:includeScript value="{!URLFOR($Resource.MobileSample_Resources_jQueryMobile, 'SObjectData.js')}"/>
               <apex:includeScript value="{!URLFOR($Resource.Stat_Resource,'Mobile-Design/common/js/cordova-2.3.0.js')}"/>

    <head>
		<title>Contacts</title>
		<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
        <c:RemoteTK />

		<script type="text/javascript">
            var $j = jQuery.noConflict(); 
        	var client = new remotetk.Client();
			Force.init(null,null,client,null);
			
			var Contacts = new SObjectData();
			Contacts.errorHandler = displayError;
			
            $j(document).ready(function() {
            	regBtnClickHandlers();
				getAllContacts();
            });
            
            function getAllContacts() {
				Contacts.fetch('soql','SELECT id, firstName, lastName, phone from Contact LIMIT 100',function() {
					showContacts(Contacts.data());
				});
			}

            function showContacts(records) {    
                $j('#cList').empty();
                $j.each(Contacts.data(),
                    function() {
                    var newLi = $j('<li></li>');
                                
                    var newLink = $j('<a id="' +this.Id+ '" data-transition="flip">' +this.FirstName+ ' '+this.LastName+ '</a>');
                    newLink.click(function(e) {
                        e.preventDefault();
                        $j.mobile.showPageLoadingMsg();
                        $j('#fName').val(Contacts.findRecordById([this.id]).FirstName);
                        $j('#lName').val(Contacts.findRecordById([this.id]).LastName);
                        $j('#phone').val(Contacts.findRecordById([this.id]).Phone);
                        $j('#contactId').val(Contacts.findRecordById([this.id]).Id);
                        $j('#error').html('');
                       
                        $j.mobile.changePage('#detailpage', {changeHash: true});
                    });
                    newLi.append(newLink);            
                    newLi.appendTo('#cList');
                  //  x++;
                  });
                
                $j.mobile.hidePageLoadingMsg();
                $j('#cList').listview('refresh');
            }      
        
            function addUpdateContact(e){
                e.preventDefault();
                var cId = $j('#contactId').val();
				var record = Contacts.findRecordById(cId);
				if(record == null) { //new record
					record = Contacts.create();
				} 
				record.FirstName = $j('#fName').val();
				record.LastName = $j('#lName').val();
				record.Phone = $j('#phone').val();
				Contacts.sync(record,successCallback);
            }

            
        
            function deleteContact(e){
                e.preventDefault();
				Contacts.remove(Contacts.findIndexById($j('#contactId').val()),successCallback);
            }
            
            function successCallback(r){
                getAllContacts();
                $j.mobile.changePage('#listpage', {changeHash: true});
            }
        
            function displayError(e){
				console.log(e);
                $j('#error').html(e[0].message);
            }
        
            function regBtnClickHandlers() {
                $j('#add').click(function(e) {
                    e.preventDefault();
                    $j.mobile.showPageLoadingMsg();
                    $j('#fName').val('');
                    $j('#lName').val('');
                    $j('#phone').val('');
                    $j('#error').html('');
                    $j('#contactId').val('');
                    $j.mobile.changePage('#detailpage', {changeHash: true});
                    $j.mobile.hidePageLoadingMsg();            
                });
        
                $j('#save').click(function(e) {
                   addUpdateContact(e);
                });
        
                $j('#delete').click(function(e) {
                   deleteContact(e);
                });
                
                $j('#Image').click(function(e) {
        			getPhotoAndUploadToContact(e);
    			});
            }
        
        	function getPhotoAndUploadToContact(e) {
                e.preventDefault();
    			var $j = jQuery.noConflict();
				var contactId = $j('#contactId').val();
                var name = $j('#fName').val();
    			

    			$j('#Image').attr('data-old-src', $j('#Image').attr('src'));
    			$j('#Image').attr('src', "{!URLFOR($Resource.Stat_Resource,'Mobile-Design/common/images/icons/gear.png')}");

    			navigator.camera.getPicture(function(imageData) {
        			onPhotoDataSuccess(imageData, name, contactId);
    			}, function(errorMsg) {

        		onPhotoDataError(errorMsg);
    			}, {
        			quality: 50,
        			correctOrientation: true,
        			sourceType: Camera.PictureSourceType.CAMERA,
        			destinationType: Camera.DestinationType.DATA_URL
    			});
			}        

        	function onPhotoDataSuccess(imageData, name, contactId) {
                var $j = jQuery.noConflict();
            

                $j('#Image').attr('src', "data&colon;image/jpeg;base64," + imageData);
            

                $j.mobile.showPageLoadingMsg();
                forcetkClient.create('ContentVersion', {
                    "Origin": "H",
                    "PathOnClient": name + ".png",
                    "VersionData": imageData
                }, function(data) {

                    SFHybridApp.logToConsole('Created ContentVersion ' + data.id);
                    forcetkClient.update('Contact', contactId, {
                        "Image_ID__c": data.id
                    }, function() {
                        SFHybridApp.logToConsole('Updated Contact ' + contactId);
                        forcetkClient.apexrest('/makeContentPublic', function() {
                            SFHybridApp.logToConsole('Updated perms ' + data.id);
                            $j.mobile.hidePageLoadingMsg();
                        }, onErrorSfdc, 'POST', {
                            "contentVersionId": data.id
                        })
                    }, onErrorSfdc);
                }, onErrorSfdc);
            }
        
        	function onPhotoDataError(errorMsg) {
                var $j = jQuery.noConflict();
            
				showPopupMessage('Error accessing your camera');
            }	
        
		</script>    
	</head>

    <body>    
        <div data-role="page" data-theme="b" id="listpage">                
            <div data-role="header" data-position="fixed">
                <h2>Contacts</h2>
	            <a href='#' id="add" class='ui-btn-right' data-icon='add' data-theme="b">Add</a>
            </div>
            <div data-role="content" id="contactList">            
                <ul id="cList" data-filter="true" data-inset="true" data-role="listview" 
                    data-theme="c" data-dividertheme="b">
                </ul>
            </div>
        </div>
        
        <div data-role="page" data-theme="b" id="detailpage">
            <div data-role="header" data-position="fixed">
                <a href='#listpage' id="back2ContactList" class='ui-btn-left' data-icon='arrow-l' data-direction="reverse" data-transition="flip">Back</a>
                <h1>Contact Details</h1>
            </div>
            <div data-role="content">
                <tr><td colspan="2" style="text-align: center;"><img id="Image" width="180" src="{!URLFOR($Resource.Stat_Resource,'Mobile-Design/common/images/icons/tile-camera.png')}"/></td></tr>
				<div data-role="fieldcontain">
					<label for="fName">First Name:</label>
					<input name="fName" id="fName" />
				</div>
				<div data-role="fieldcontain">
					<label for="lName">Last Name:</label>
					<input name="lName" id="lName" />
				</div>
				<div data-role="fieldcontain">
					<label for="phone">Phone:</label>
					<input name="phone" id="phone"/>
				</div>
				<h2 style="color:red" id="error"></h2><br/>
                <input type="hidden" id="contactId" />
				<button id="save" data-role="button" data-icon="check" data-inline="true" data-theme="b" class="save">Save</button>
				<button id="delete" data-role="button" data-icon="delete" data-inline="true" class="destroy">Delete</button>
            </div>    
        </div>  
    </body>    
</apex:page>

 Any thoughts please?

hylim12hylim12

I've modify my Apex page to:

 

<apex:page docType="html-5.0" showHeader="false" sidebar="false" standardController="Contact" extensions="ContactAtt">          
    <apex:stylesheet value="{!URLFOR($Resource.MobileSample_Resources_jQueryMobile, 'jquery.mobile-1.3.0.min.css')}"/>
    <apex:includeScript value="{!URLFOR($Resource.MobileSample_Resources_jQueryMobile, 'jquery-1.9.1.min.js')}"/>
    <apex:includeScript value="{!URLFOR($Resource.MobileSample_Resources_jQueryMobile, 'jquery.mobile-1.3.0.min.js')}"/>
    <apex:includeScript value="{!URLFOR($Resource.MobileSample_Resources_jQueryMobile, 'cordova.force.js')}"/>
    <apex:includeScript value="{!URLFOR($Resource.MobileSample_Resources_jQueryMobile, 'backbone/underscore-1.4.4.min.js')}"/>
    <apex:includeScript value="{!URLFOR($Resource.MobileSample_Resources_jQueryMobile, 'force.entity.js')}"/>
    <apex:includeScript value="{!URLFOR($Resource.MobileSample_Resources_jQueryMobile, 'SObjectData.js')}"/>
    <apex:includeScript value="{!URLFOR($Resource.Stat_Resource,'Mobile-Design/common/js/cordova-2.3.0.js')}"/>

    <head>
        <title>Contacts</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
        <c:RemoteTK />

        <script type="text/javascript">
            var $j = jQuery.noConflict(); 
            var client = new remotetk.Client();
            Force.init(null,null,client,null);
            
            var Contacts = new SObjectData();
            Contacts.errorHandler = displayError;
            
            $j(document).ready(function() {
                regBtnClickHandlers();
                getAllContacts();
            });
            
            function getAllContacts() {
                Contacts.fetch('soql','SELECT id, firstName, lastName, phone from Contact LIMIT 100',function() {
                    showContacts(Contacts.data());
                });
            }

            function showContacts(records) {    
                $j('#cList').empty();
                $j.each(Contacts.data(),
                    function() {
                    var newLi = $j('<li></li>');
                                
                    var newLink = $j('<a id="' +this.Id+ '" data-transition="flip">' +this.FirstName+ ' '+this.LastName+ '</a>');
                    newLink.click(function(e) {
                        e.preventDefault();
                        $j.mobile.showPageLoadingMsg();
                        $j('#fName').val(Contacts.findRecordById([this.id]).FirstName);
                        $j('#lName').val(Contacts.findRecordById([this.id]).LastName);
                        $j('#phone').val(Contacts.findRecordById([this.id]).Phone);
                        $j('#contactId').val(Contacts.findRecordById([this.id]).Id);
                        $j('#error').html('');
                       
                        $j.mobile.changePage('#detailpage', {changeHash: true});
                    });
                    newLi.append(newLink);            
                    newLi.appendTo('#cList');
                  //  x++;
                  });
                
                $j.mobile.hidePageLoadingMsg();
                $j('#cList').listview('refresh');
            }      
        
            function addUpdateContact(e){
                e.preventDefault();
                var cId = $j('#contactId').val();
                var record = Contacts.findRecordById(cId);
                if(record == null) { //new record
                    record = Contacts.create();
                } 
                record.FirstName = $j('#fName').val();
                record.LastName = $j('#lName').val();
                record.Phone = $j('#phone').val();
                Contacts.sync(record,successCallback);
            }

            
        
            function deleteContact(e){
                e.preventDefault();
                Contacts.remove(Contacts.findIndexById($j('#contactId').val()),successCallback);
            }
            
            function successCallback(r){
                getAllContacts();
                $j.mobile.changePage('#listpage', {changeHash: true});
            }
        
            function displayError(e){
                console.log(e);
                $j('#error').html(e[0].message);
            }
        
            function regBtnClickHandlers() {
                $j('#add').click(function(e) {
                    e.preventDefault();
                    $j.mobile.showPageLoadingMsg();
                    $j('#fName').val('');
                    $j('#lName').val('');
                    $j('#phone').val('');
                    $j('#error').html('');
                    $j('#contactId').val('');
                    $j.mobile.changePage('#detailpage', {changeHash: true});
                    $j.mobile.hidePageLoadingMsg();            
                });
        
                $j('#save').click(function(e) {
                   addUpdateContact(e);
                });
        
                $j('#delete').click(function(e) {
                   deleteContact(e);
                });
                
                $j('#Image').click(function(e) {
                    getPhotoAndUploadToContact(e);
                });
            }
        
            function getPhotoAndUploadToContact(e) {
                e.preventDefault();
                var $j = jQuery.noConflict();
                var contactId = $j('#contactId').val();
                var name = $j('#fName').val();
                

                $j('#Image').attr('data-old-src', $j('#Image').attr('src'));
                $j('#Image').attr('src', "{!URLFOR($Resource.Stat_Resource,'Mobile-Design/common/images/icons/gear.png')}");

                //navigator.camera.getPicture(function(imageData) {
                //onPhotoDataSuccess(imageData, name, contactId);
                //}, function(errorMsg) {

                //onPhotoDataError(errorMsg);
                //}, {
                //quality: 50,
                //correctOrientation: true,
                //sourceType: Camera.PictureSourceType.CAMERA,
                //destinationType: Camera.DestinationType.DATA_URL
                //});
               
                navigator.camera.getPicture(onPicSuccess, 
                                      onPicFail, 
                                      { quality: 25, destinationType: 0, sourceType: 1}); 
            }        

            function onPicSuccess(imageData) {
            
                var contactId = $j('#contactId').val();
                var name = $j('#fName').val();
                
                
                Visualforce.remoting.Manager.invokeAction(
                '{!$RemoteAction.ContactAtt.completeCamera}',
                imageData, 
                contactId, 
                name, 
                function(res,event){
                    $j.mobile.hidePageLoadingMsg();
                    
                    if (event){
                        if (res) {
                            if (res != -1) {
                                 $j.mobile.changePage('#listpage', {changeHash: true});
                            } else {
                                showPopupMessage('Issue reading your photo');
                            }
                        } else {
                            showPopupMessage('Error loading picture. Please try again.',redirectUrl);
                        }
                    } else {
                        showPopupMessage('Error loading picture. Please try again.',redirectUrl);
                    }
                });

            }
        
            function onPicFail(errorMsg) {
                var $j = jQuery.noConflict();
            
                showPopupMessage('Error accessing your camera');
            }   
        
        </script>    
    </head>

    <body>    
        <div data-role="page" data-theme="b" id="listpage">                
            <div data-role="header" data-position="fixed">
                <h2>Contacts</h2>
                <a href='#' id="add" class='ui-btn-right' data-icon='add' data-theme="b">Add</a>
            </div>
            <div data-role="content" id="contactList">            
                <ul id="cList" data-filter="true" data-inset="true" data-role="listview" 
                    data-theme="c" data-dividertheme="b">
                </ul>
            </div>
        </div>
        
        <div data-role="page" data-theme="b" id="detailpage">
            <div data-role="header" data-position="fixed">
                <a href='#listpage' id="back2ContactList" class='ui-btn-left' data-icon='arrow-l' data-direction="reverse" data-transition="flip">Back</a>
                <h1>Contact Details</h1>
            </div>
            <div data-role="content">
                <tr><td colspan="2" style="text-align: center;"><img id="Image" width="180" src="{!URLFOR($Resource.Stat_Resource,'Mobile-Design/common/images/icons/tile-camera.png')}"/></td></tr>
                <div data-role="fieldcontain">
                    <label for="fName">First Name:</label>
                    <input name="fName" id="fName" />
                </div>
                <div data-role="fieldcontain">
                    <label for="lName">Last Name:</label>
                    <input name="lName" id="lName" />
                </div>
                <div data-role="fieldcontain">
                    <label for="phone">Phone:</label>
                    <input name="phone" id="phone"/>
                </div>
                <h2 style="color:red" id="error"></h2><br/>
                <input type="hidden" id="contactId" />
                <button id="save" data-role="button" data-icon="check" data-inline="true" data-theme="b" class="save">Save</button>
                <button id="delete" data-role="button" data-icon="delete" data-inline="true" class="destroy">Delete</button>
            </div>    
        </div>  
    </body>    
</apex:page>

 

 

 And my extension class:

 

global with sharing class ContactAtt{

    public String contactId { get; set; }
    public String contactName { get; set; }
    

    public ContactAtt(ApexPages.StandardController stdController){
        contactId = ApexPages.currentPage().getParameters().get('C');
        contactName = ApexPages.currentPage().getParameters().get('N');
    }
    
    @RemoteAction
    public static void completeCamera(String imageData, String contactId, String contactName){
        Attachment a = new Attachment (ParentId = contactId,
                                   Body = EncodingUtil.base64Decode(imageData),
                                   ContentType = 'image/jpg',
                                   Name = contactName + 'PhoneImage');
       insert a;
            
    Contact c = [SELECT Id, Image_ID__c FROM Contact WHERE Id = :contactId];
            
        c.Image_ID__c = a.Id;
        Update c;
        }
}

 But it still doesnt add an attachment to my salesforce. Any help pls?

bhariharanbhariharan

This blog post might help you - Developing Hybrid Apps with the Salesforce Mobile SDK. Scroll down to the section titled 'Customize your Hybrid Mobile Application to Use the Device Camera'.

hylim12hylim12
I actually follow the sample you provided but still the same..the photo is not uploaded to my org.
Gaurav KheterpalGaurav Kheterpal

Can you try debugging your code to see if the binary image data is being sent to Salesforce or not?