WebView in this app opens a page 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.
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:
ON TAKING SNAPSHOT USING CAMERA: back and check options appear.
ON CHOOSING CHECK MARK:
FILE IS NOT UPLOADED :( IN "CHOOSE FILE" OPTION
WHAT IS EXPECTED:
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?
webView. setWebViewClient(new WebViewClient(){ public void onPageStarted(WebView view, String url, Bitmap favicon) { super. onPageStarted(view, url, favicon); } public boolean shouldOverrideUrlLoading(WebView view, String url) { webView. postUrl(Base_Url, postData.
The loadUrl() and loadData() methods of Android WebView class are used to load and display web page.
After struggling a lot I found a code that works for taking files from galley and camera from 5.0+ devices
private ValueCallback<Uri> mUploadMessage; private Uri mCapturedImageURI = null; private ValueCallback<Uri[]> mFilePathCallback; private String mCameraPhotoPath; private static final int INPUT_FILE_REQUEST_CODE = 1; private static final int FILECHOOSER_RESULTCODE = 1; private File createImageFile() throws IOException { // Create an image file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES); File imageFile = File.createTempFile( imageFileName, /* prefix */ ".jpg", /* suffix */ storageDir /* directory */ ); return imageFile; }
this is initialization and setting webview
mWebView= (WebView) findViewById(R.id.webview); mWebView.getSettings().setJavaScriptEnabled(true); mWebView.getSettings().setPluginState(WebSettings.PluginState.OFF); mWebView.getSettings().setLoadWithOverviewMode(true); mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); mWebView.getSettings().setUseWideViewPort(true); mWebView.getSettings().setUserAgentString("Android Mozilla/5.0 AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30"); mWebView.getSettings().setAllowFileAccess(true); mWebView.getSettings().setAllowFileAccess(true); mWebView.getSettings().setAllowContentAccess(true); mWebView.getSettings().supportZoom(); mWebView.loadUrl(Common.adPostUrl); mWebView.setWebViewClient(new WebViewClient() { public boolean shouldOverrideUrlLoading(WebView view, String url) { // do your handling codes here, which url is the requested url // probably you need to open that url rather than redirect: if ( url.contains(".pdf")){ Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse(url), "application/pdf"); try{ view.getContext().startActivity(intent); } catch (ActivityNotFoundException e) { //user does not have a pdf viewer installed } } else { mWebView.loadUrl(url); } return false; // then it is not handled by default action } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { Log.e("error",description); } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { //show progressbar here super.onPageStarted(view, url, favicon); } @Override public void onPageFinished(WebView view, String url) { //hide progressbar here } }); mWebView.setWebChromeClient(new ChromeClient());
and here is my ChomeClient() method
public class ChromeClient extends WebChromeClient { // For Android 5.0 public boolean onShowFileChooser(WebView view, ValueCallback<Uri[]> filePath, WebChromeClient.FileChooserParams fileChooserParams) { // Double check that we don't have any existing callbacks if (mFilePathCallback != null) { mFilePathCallback.onReceiveValue(null); } mFilePathCallback = filePath; Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(getPackageManager()) != null) { // Create the File where the photo should go File photoFile = null; try { photoFile = createImageFile(); takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath); } catch (IOException ex) { // Error occurred while creating the File Log.e(Common.TAG, "Unable to create Image File", ex); } // Continue only if the File was successfully created if (photoFile != null) { mCameraPhotoPath = "file:" + photoFile.getAbsolutePath(); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile)); } else { takePictureIntent = null; } } Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT); contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE); contentSelectionIntent.setType("image/*"); Intent[] intentArray; if (takePictureIntent != null) { intentArray = new Intent[]{takePictureIntent}; } else { intentArray = new Intent[0]; } Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER); chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent); chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser"); chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray); startActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE); return true; } // openFileChooser for Android 3.0+ public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) { mUploadMessage = uploadMsg; // Create AndroidExampleFolder at sdcard // Create AndroidExampleFolder at sdcard File imageStorageDir = new File( Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES) , "AndroidExampleFolder"); if (!imageStorageDir.exists()) { // Create AndroidExampleFolder at sdcard imageStorageDir.mkdirs(); } // Create camera captured image file path and name File file = new File( imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg"); mCapturedImageURI = Uri.fromFile(file); // Camera capture image intent final Intent captureIntent = new Intent( android.provider.MediaStore.ACTION_IMAGE_CAPTURE); captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mCapturedImageURI); Intent i = new Intent(Intent.ACTION_GET_CONTENT); i.addCategory(Intent.CATEGORY_OPENABLE); i.setType("image/*"); // Create file chooser intent Intent chooserIntent = Intent.createChooser(i, "Image Chooser"); // Set camera intent to file chooser chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS , new Parcelable[] { captureIntent }); // On select image call onActivityResult method of activity startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE); } // openFileChooser for Android < 3.0 public void openFileChooser(ValueCallback<Uri> uploadMsg) { openFileChooser(uploadMsg, ""); } //openFileChooser for other Android versions public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) { openFileChooser(uploadMsg, acceptType); } }
//here is my onActivityResult method to handle data from gallery or camera intent
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (requestCode != INPUT_FILE_REQUEST_CODE || mFilePathCallback == null) { super.onActivityResult(requestCode, resultCode, data); return; } Uri[] results = null; // Check that the response is a good one if (resultCode == Activity.RESULT_OK) { if (data == null) { // If there is not data, then we may have taken a photo if (mCameraPhotoPath != null) { results = new Uri[]{Uri.parse(mCameraPhotoPath)}; } } else { String dataString = data.getDataString(); if (dataString != null) { results = new Uri[]{Uri.parse(dataString)}; } } } mFilePathCallback.onReceiveValue(results); mFilePathCallback = null; } else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { if (requestCode != FILECHOOSER_RESULTCODE || mUploadMessage == null) { super.onActivityResult(requestCode, resultCode, data); return; } if (requestCode == FILECHOOSER_RESULTCODE) { if (null == this.mUploadMessage) { return; } Uri result = null; try { if (resultCode != RESULT_OK) { result = null; } else { // retrieve from the private variable if the intent is null result = data == null ? mCapturedImageURI : data.getData(); } } catch (Exception e) { Toast.makeText(getApplicationContext(), "activity :" + e, Toast.LENGTH_LONG).show(); } mUploadMessage.onReceiveValue(result); mUploadMessage = null; } } return; }
and here is the permissions required to open camera
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA2" /> // for new versions api 21+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
Note: My code also contains the code for devices running 3.0+ also but I never tested them , the above code worked on Lolipop, Marshmallow and Nougat emulators. One more thing , if you see and icon of Android System in place of Camera it means you have many apps available in your device to handle camera.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With