Monday, November 23, 2015

Getting camera captured image in android WebView

Hi all,

Last week was very exciting because I had to get an image from camera and place it inside a WebView. I have googled and couple of results were found as follows.

Here it is said that there is an issue using  "<input type="file" />" in KitKat. At the end of this link there are some links claiming as working modules for lollipop(I did't try them.) Because of this lack of useful codes I decided to share my findings which may help someone. I have tested this code in my nexus 4 running on lollipop. I have added comments in the code to understand the code. Please note that this is only for getting image from camera NOT from file chooser.

 1. AndroidManifest.xml

 <?xml version="1.0" encoding="utf-8"?>  
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
   package="com.duo.wishesapptest" >  
   <uses-permission android:name="android.permission.CAMERA" />  
   <uses-feature android:name="android.hardware.camera" />  
   <uses-permission android:name="android.permission.INTERNET" />  
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
   <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />  
   <application  
     android:allowBackup="true"  
     android:icon="@mipmap/ic_launcher"  
     android:label="@string/app_name"  
     android:supportsRtl="true"  
     android:theme="@style/AppTheme" >  
     <activity  
       android:name=".CameraActivity"  
       android:label="@string/title_activity_camera"  
       android:theme="@style/AppTheme.NoActionBar" >  
       <intent-filter>  
         <action android:name="android.intent.action.MAIN" />  
         <category android:name="android.intent.category.LAUNCHER" />  
       </intent-filter>  
     </activity>  
     <activity android:name=".WebContent" >  
     </activity>  
   </application>  
 </manifest>  

2. CameraActivity.java

 package com.duo.wishesapptest;  
 import android.content.Intent;  
 import android.os.Bundle;  
 import android.support.v7.app.AppCompatActivity;  
 import android.support.v7.widget.Toolbar;  
 import android.view.View;  
 public class CameraActivity extends AppCompatActivity {  
   @Override  
   protected void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     setContentView(R.layout.activity_camera);  
     Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);  
     setSupportActionBar(toolbar);  
   }  
   public void callWebview(View view){  
     Intent intent=new Intent(this,WebContent.class);  
     startActivity(intent);  
   }  
 }  

3. WebContent.java

 package com.duo.wishesapptest;  
 import android.app.Activity;  
 import android.content.Intent;  
 import android.graphics.Bitmap;  
 import android.graphics.BitmapFactory;  
 import android.net.Uri;  
 import android.os.Bundle;  
 import android.os.Environment;  
 import android.provider.MediaStore;  
 import android.support.v7.app.ActionBarActivity;  
 import android.util.Base64;  
 import android.webkit.JavascriptInterface;  
 import android.webkit.WebView;  
 import android.webkit.WebViewClient;  
 import java.io.ByteArrayOutputStream;  
 import java.io.File;  
 public class WebContent extends ActionBarActivity {  
   WebView webView;  
   static Uri picUri = null;  
   String url;  
   String uriInString;  
   boolean isFirstLoad = true; // for the first time there is no image.Used this not to show image in the first page load.  
   @Override  
   protected void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     setContentView(R.layout.activity_web_content);  
     webView = (WebView) findViewById(R.id.webViewHtm);  
     webView.setWebViewClient(new WebViewClient(){  
       @Override  
       public void onPageFinished(WebView view, String url1) { // This is the important part. Everytime camera intent finish it calls onCreate method.  
         super.onPageFinished(view, url1);          // So after getting the camera image javascript run to set image in WebView  
         if(!isFirstLoad)  
         webView.loadUrl("javascript:getImage('" + url + "')");  
       }  
     });  
     webView.addJavascriptInterface(this, "Android"); // javascript interfaces are in 'this' activity  
                              // if javascript interfaces are added to another class we can't call 'startActivityForResult'  
     webView.loadUrl("https://f073b6f1598031631202dc1cf1408f54a9fede00-www.googledrive.com/host/0B_1iFNsKSU55SkdmbTlwMUQxTWc");  
             // here I published my html file in google drive.this link should work till 2016 may.(google is going to stop this service in 2016)  
             // I believe dropbox is also good to host a simple html page if you don't have a server  
     webView.getSettings().setJavaScriptEnabled(true);  
     webView.getSettings().setDomStorageEnabled(true);  
   }  
   @JavascriptInterface  
   public void showAndroidCamera() { // This is called when click the button in html page.  
     // Create AndroidExampleFolder in storage. You can see this folder by opening Android Device Monitor. See for 'mnt' folder in DDMS --> File Explorer view.  
     File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "AndroidExampleFolder");  
     if (!imageStorageDir.exists()) {  
       imageStorageDir.mkdirs(); // Create AndroidExampleFolder if not exists  
     }  
     // Create camera captured image file path and name  
     File file = new File(imageStorageDir + File.separator + "IMG"+ String.valueOf(System.currentTimeMillis())+ ".jpg");  
     Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE"); // crating the camera intent  
     cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));  
     picUri = Uri.fromFile(file);  
     startActivityForResult(cameraIntent, 123); // result is passed to onActivityResult  
   }  
   @Override  
   protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
     super.onActivityResult(requestCode, resultCode, data);  
     isFirstLoad = false;  
     uriInString = picUri.toString().replace("file://", ""); //needs to remove 'file://' part in uri path.  
     switch (requestCode) {  
       case 123:  
         if (resultCode == Activity.RESULT_OK) {  
           Bitmap bm = BitmapFactory.decodeFile(uriInString);  
           ByteArrayOutputStream baos = new ByteArrayOutputStream();  
           bm.compress(Bitmap.CompressFormat.PNG, 100, baos); //bm is the bitmap object  
           byte[] byteArrayImage = baos.toByteArray();  
           String encodedImage = Base64.encodeToString(byteArrayImage, Base64.DEFAULT);  
           url="data:image/png;base64,"+encodedImage; // encoded value passed to javascript  
         }  
     }  
   }  
 }  

4. activity_camera.xml

 <?xml version="1.0" encoding="utf-8"?>  
 <android.support.design.widget.CoordinatorLayout  
   xmlns:android="http://schemas.android.com/apk/res/android"  
   xmlns:app="http://schemas.android.com/apk/res-auto"  
   xmlns:tools="http://schemas.android.com/tools"  
   android:layout_width="match_parent"  
   android:layout_height="match_parent"   
   android:fitsSystemWindows="true"  
   tools:context="com.duo.wishesapptest.CameraActivity">  
   <android.support.design.widget.AppBarLayout   
     android:layout_height="wrap_content"  
     android:layout_width="match_parent"   
     android:theme="@style/AppTheme.AppBarOverlay">  
     <android.support.v7.widget.Toolbar   
       android:id="@+id/toolbar"  
       android:layout_width="match_parent"   
       android:layout_height="?attr/actionBarSize"  
       android:background="?attr/colorPrimary"   
       app:popupTheme="@style/AppTheme.PopupOverlay" />  
   </android.support.design.widget.AppBarLayout>  
   <include layout="@layout/content_camera" />  
   <android.support.design.widget.FloatingActionButton   
     android:id="@+id/fab"  
     android:layout_width="wrap_content" android:layout_height="wrap_content"  
     android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin"  
     android:src="@android:drawable/ic_dialog_email" />  
 </android.support.design.widget.CoordinatorLayout>  

5. activity_web_content.xml

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
   xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"  
   android:layout_height="match_parent"  
   tools:context="com.example.lakshan.vers.WebContent">  
   <WebView  
     android:layout_width="match_parent"  
     android:layout_height="300dp"  
     android:id="@+id/webViewHtm"  
     />  
 </RelativeLayout>  

6. content_camera.xml

 <?xml version="1.0" encoding="utf-8"?>  
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
   xmlns:tools="http://schemas.android.com/tools"  
   xmlns:app="http://schemas.android.com/apk/res-auto"  
   android:layout_width="match_parent"  
   android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"  
   android:paddingRight="@dimen/activity_horizontal_margin"  
   android:paddingTop="@dimen/activity_vertical_margin"  
   android:paddingBottom="@dimen/activity_vertical_margin"  
   tools:context="com.duo.wishesapptest.CameraActivity">  
   <Button  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:text="Get Cam on web view"  
     android:id="@+id/camera_btn"  
     android:layout_alignParentTop="true"  
     android:layout_marginTop="69dp"  
     android:onClick="callWebview"/>  
 </RelativeLayout>  

7. camera.html

 <!DOCTYPE html>  
 <html>  
 <head>  
 <script type="text/javascript">  
   function showAndroidCameraHere() {  
     Android.showAndroidCamera();  
   }       
 function getImage(src) {  
   var img = document.createElement("IMG");  
      img.setAttribute("src", src);  
   img.setAttribute("width", "94");  
   img.setAttribute("height", "70");  
   img.setAttribute("alt", "Your image here");  
   document.getElementById('imageHolder').appendChild(img);  
 }  
 </script>  
 </head>  
 <body>  
 <form id="formContainer"">  
   <h2>capture=camera</h2>  
      <button type="button" onClick="showAndroidCameraHere()">Try it</button>  
      <div id="imageHolder" width="100px" height="80px"></div>  
 </form>  
 </body>  
 </html>  

8. build.gradle

 apply plugin: 'com.android.application'  
 android {  
   compileSdkVersion 22  
   buildToolsVersion "22.0.1"  
   defaultConfig {  
     applicationId "com.duo.wishesapptest"  
     minSdkVersion 19  
     targetSdkVersion 22  
     versionCode 1  
     versionName "1.0"  
   }  
   buildTypes {  
     release {  
       minifyEnabled false  
       proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
     }  
   }  
 }  
 dependencies {  
   compile fileTree(dir: 'libs', include: ['*.jar'])  
   testCompile 'junit:junit:4.12'  
   compile 'com.android.support:appcompat-v7:22.2.1'  
   compile 'com.android.support:design:22.2.1'  
 }  

That's it. Hope someone can find this useful. Happy Coding :-).

3 comments: