Upload an Image from camera or gallery in WebView

Chirag picture Chirag · Mar 31, 2013 · Viewed 64.5k times · Source

WebView in this app opens a page with upload button.

Page in webview with upload button

Below is the code block that allows to open a dialog box to upload image from gallery or camera.

Within my Activity I have:

 private WebView wv;  

//make HTML upload button work in Webview   
 private ValueCallback<Uri> mUploadMessage;  
 private final static int FILECHOOSER_RESULTCODE=1;

 @Override  
 protected void onActivityResult(int requestCode, int resultCode, Intent intent) {  
  if(requestCode==FILECHOOSER_RESULTCODE)  
  {  
   if (null == mUploadMessage) return;  
            Uri result = intent == null || resultCode != RESULT_OK ? null  
                    : intent.getData();  
            mUploadMessage.onReceiveValue(result);  
            mUploadMessage = null;        
  }  
 }  

Within onCreate I have the following:

    wv.setWebChromeClient(new WebChromeClient()  {
        private Uri imageUri;   

        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType )  {      
             File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyApp");
            // Create the storage directory if it does not exist
            if (! imageStorageDir.exists()){
                imageStorageDir.mkdirs();                  
            }
            File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");  
            imageUri = Uri.fromFile(file); 

            final List<Intent> cameraIntents = new ArrayList<Intent>();
            final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
            final PackageManager packageManager = getPackageManager();
            final List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
            for(ResolveInfo res : listCam) {
                final String packageName = res.activityInfo.packageName;
                final Intent i = new Intent(captureIntent);
                i.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
                i.setPackage(packageName);
                i.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                cameraIntents.add(i);

            }


            mUploadMessage = uploadMsg; 
            Intent i = new Intent(Intent.ACTION_GET_CONTENT);  
            i.addCategory(Intent.CATEGORY_OPENABLE);  
            i.setType("image/*"); 
            Intent chooserIntent = Intent.createChooser(i,"Image Chooser");
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));
            MainActivity.this.startActivityForResult(chooserIntent,  FILECHOOSER_RESULTCODE); 
        }

I am able to see option for camera, image gallery and file explorer on clicking Upload button. Camera, gallery and file explorer upload option

File explorer and Gallery is working as expected. The problem is that, when I take a picture using camera, it is not uploaded in the "choose file" option which shows status "No file chosen".

ON SELECTING CAMERA:

camera

ON TAKING SNAPSHOT USING CAMERA: back and check options appear.

snapshot using camera

ON CHOOSING CHECK MARK:

FILE IS NOT UPLOADED :( IN "CHOOSE FILE" OPTION

enter image description here

WHAT IS EXPECTED:

image uploaded

I checked that I have the proper writing permission and hence a directory named "MyApp" is generated and the picture is stored within it (if taken by invoking camera after clicking upload button on webpage).

How to programatically tell the application to choose picture taken from camera (that was stored in MyApp directory) after hitting check mark?

Answer

vortexwolf picture vortexwolf · Mar 31, 2013

I suppose that the onActivityResult method is actually called, but the 3rd parameter Intent intent is null. It seems that it is a bug of Nexus phones.

But you can save the output image uri to the private variable and use it instead of the intent:

private Uri imageUri;

private void showAttachmentDialog(ValueCallback<Uri> uploadMsg) {
    this.mUploadMessage = uploadMsg;

    File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "TestApp");
    if (!imageStorageDir.exists()) {
        imageStorageDir.mkdirs();
    }
    File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
    this.imageUri = Uri.fromFile(file); // save to the private variable

    final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);

    Intent i = new Intent(Intent.ACTION_GET_CONTENT);
    i.addCategory(Intent.CATEGORY_OPENABLE);
    i.setType("image/*");

    Intent chooserIntent = Intent.createChooser(i, "Image Chooser");
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[] { captureIntent });

    this.startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    if (requestCode == FILECHOOSER_RESULTCODE) {
        if (null == this.mUploadMessage) {
            return;
        }

        Uri result;
        if (resultCode != RESULT_OK) {
            result = null;
        } else {
            result = intent == null ? this.imageUri : intent.getData(); // retrieve from the private variable if the intent is null
        }

        this.mUploadMessage.onReceiveValue(result);
        this.mUploadMessage = null;
    }
}

In this code I added the imageUri variable to the activity and used it in both methods.