Upload camera photo and filechooser from webview INPUT field

android, android-camera, filechooser, webviewclient

Solution

Solved. Inside my question, there's the functional code in case anyone needs it.

Here's the solution of the issues:

Couldn't open camera/filechooser if I previously opened and cancelled:

//inside onActivityResult
if (resultCode != RESULT_OK) {
     mUploadMessage.onReceiveValue(null);
     return;
}

Get the "content://media/external/images/xxx" uri format, to upload the uri via "mUploadMessage.onReceiveValue(selectedImage);", avoiding a nullpointerexception

//inside OnActivityResult
getContentResolver().notifyChange(mCapturedImageURI, null);
ContentResolver cr = getContentResolver();
Uri uriContent = Uri.parse(android.provider.MediaStore.Images.Media.insertImage(getContentResolver(), photo.getAbsolutePath(), null, null));

Problem

My app is webbased and I need to upload pictures from an INPUT field camp. I've two situations and as i don't know another way to do it depending the page I'm choosing one or another with "boolean boolFileChoser" depending its URL petition: a. file picker b. camera photo shoot. I've dealt with file picker and it upload the file perfectly, the problem is with the camera. Once i try to upload the Camera Pic, it crashes. As far as i know its because the URI. a) File picker: content://media/external/images/1234 b) Camera shoot: file:///mnt/sdcard/Pic.jpg I've found no way to change it. See update It now crashes because a nullpointerexception while trying to upload the "content://media/external/images/1234". (only with camera, not file chooser. ). Also if the chooser/camera is closed (back button), i'm unable to call it again. Case a) and b) 100% working, here's the working code, including how I know if fileChooser or camera are called: ``` @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if (resultCode != RESULT_OK) { /** fixed code **/ //To be able to use the filechooser again in case of error mUploadMessage.onReceiveValue(null); /** fixed code **/ return; } if (mUploadMessage==null) { Log.d("androidruntime","no mUploadMessage"); return; } if (requestCode == FILECHOOSER_RESULTCODE) { Uri selectedImage= intent == null || resultCode != RESULT_OK ? null : intent.getData(); Log.d("androidruntime","url: "+selectedImage.toString()); }else if (requestCode == CAMERAREQUEST_RESULTCODE) { if(mCapturedImageURI==null){ Log.d("androidruntime","no mCapturedImageURI"); return; } /** fixed code **/ getContentResolver().notifyChange(mCapturedImageURI, null); ContentResolver cr = getContentResolver(); Uri uriContent= Uri.parse(MediaStore.Images.Media.insertImage(getContentResolver(), photo.getAbsolutePath(), null, null)); photo = null; /** fixed code **/ } mUploadMessage.onReceiveValue(selectedImage); mUploadMessage = null; } private static final int FILECHOOSER_RESULTCODE = 2888; private static final int CAMERAREQUEST_RESULTCODE = 1888; private ValueCallback<Uri> mUploadMessage; private Uri mCapturedImageURI = null; protected class AwesomeWebChromeClient extends WebChromeClient{ // Per Android 3.0+ public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType){ /**updated, out of the IF **/ mUploadMessage = uploadMsg; /**updated, out of the IF **/ if(boolFileChooser){ //Take picture from filechooser Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); MainActivity.this.startActivityForResult( Intent.createChooser( i, "Escoger Archivo" ), MainActivity.FILECHOOSER_RESULTCODE ); } else { //Take photo and upload picture Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE"); File photo = new File(Environment.getExternalStorageDirectory(), "Pic.jpg"); cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo)); mCapturedImageURI = Uri.fromFile(photo); startActivityForResult(cameraIntent, MainActivity.CAMERA_REQUEST); } } // Per Android < 3.0 public void openFileChooser(ValueCallback<Uri> uploadMsg){ openFileChooser(uploadMsg, ""); } //Altre public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) { openFileChooser(uploadMsg, ""); } /** Added code to clarify chooser. **/ //The webPage has 2 filechoosers and will send a console message informing what action to perform, taking a photo or updating the file public boolean onConsoleMessage(ConsoleMessage cm) { onConsoleMessage(cm.message(), cm.lineNumber(), cm.sourceId()); return true; } public void onConsoleMessage(String message, int lineNumber, String sourceID) { Log.d("androidruntime", "Per cònsola: " + cm.message()); if(message.endsWith("foto")){ boolFileChooser= true; } else if(message.endsWith("pujada")){ boolFileChooser= false; } } /** Added code to clarify chooser. **/ } ``` UPDATE 1 I could get the "content://media/external/images/xxx" uri format, but the app still crashes while trying to upload the uri via "mUploadMessage.onReceiveValue(selectedImage);". Now I'm getting a nullpointerexception. UPDATE 2 Fixed and working. I've had the 'ValueCallback uploadMsg' in local variable only in file-chooser case, so it allways throwed me an exception when i tried to upload a photo file because it was null. Once i took out from if-else statement, all worked. The previous update was the easiest method to deal with the file upload. I've already added a 'mUploadMessage.onReceiveValue(null);' if the Camera/filechooser intent is cancelled (you must deal with it in your webpage), if not, you won't be able to launch the INPUT field (Intent) again. UPDATE 3 Added the part of the code inside AwesomeChromeClient to discriminate the option, take a photo or choose a file.. its MY way of doing it and added by petition, i'm sure there're a lot of other valid ways to do it, The code is 100% functionally now. If you indicate if you want picture or file-chooser

Original source