File Upload in WebView (4.4.2)android - android

I have read this article below,but the progress bar and upload file don't work for android(4.4.2)
this aritcle seems not update so I post another Question,hope someone know how to solve it.
thanks
File Upload in WebView
I tried another method of the code below and
it can upload file well but the url bar will appear on the top ,same as I using browser.
So I added WebView.setWebViewClient(new WebViewClient());
in order to hide url bar then the file upload button not working.
public class WebActivity extends Activity {
WebView mWebView;
#Override
public void onCreate(Bundle savedInstanceState)
{
final Activity mActivity = this;
super.onCreate(savedInstanceState);
// Adds Progrss bar Support
this.getWindow().requestFeature(Window.FEATURE_PROGRESS);
setContentView(R.layout.main);
// Makes Progress bar Visible
getWindow().setFeatureInt( Window.FEATURE_PROGRESS, Window.PROGRESS_VISIBILITY_ON);
mWebView = (WebView) findViewById( R.id.webview );
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.loadUrl(http://your.url.com);
mWebView.setWebChromeClient(new WebChromeClient()
{
public void onProgressChanged(WebView view, int progress)
{
//Make the bar disappear after URL is loaded, and changes string to Loading...
mActivity .setTitle("Loading...");
mActivity .setProgress(progress * 100); //Make the bar disappear after URL is loaded
// Return the app name after finish loading
if(progress == 100)
{
financialPortalActivity.setTitle(R.string.yourWebSiteName);
}
}
});
}
}

here is a full solution for all android versions, I had a hard time with this too.
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.webkit.JsResult;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebSettings.PluginState;
import android.widget.Toast;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView webView = (WebView) findViewById(R.id.webView1);
initWebView(webView);
webView.loadUrl("http://google.com"); // TODO input your url
}
private final static Object methodInvoke(Object obj, String method, Class<?>[] parameterTypes, Object[] args) {
try {
Method m = obj.getClass().getMethod(method, new Class[] { boolean.class });
m.invoke(obj, args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void initWebView(WebView webView) {
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setAllowFileAccess(true);
settings.setDomStorageEnabled(true);
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
settings.setLoadWithOverviewMode(true);
settings.setUseWideViewPort(true);
settings.setSupportZoom(true);
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setPluginState(PluginState.ON);
methodInvoke(settings, "setPluginState", new Class[] { PluginState.class }, new Object[] { PluginState.ON });
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowUniversalAccessFromFileURLs(true);
methodInvoke(settings, "setAllowUniversalAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowFileAccessFromFileURLs(true);
methodInvoke(settings, "setAllowFileAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webView.clearHistory();
webView.clearFormData();
webView.clearCache(true);
webView.setWebChromeClient(new MyWebChromeClient());
// webView.setDownloadListener(downloadListener);
}
UploadHandler mUploadHandler;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == Controller.FILE_SELECTED) {
// Chose a file from the file picker.
if (mUploadHandler != null) {
mUploadHandler.onResult(resultCode, intent);
}
}
super.onActivityResult(requestCode, resultCode, intent);
}
class MyWebChromeClient extends WebChromeClient {
public MyWebChromeClient() {
}
private String getTitleFromUrl(String url) {
String title = url;
try {
URL urlObj = new URL(url);
String host = urlObj.getHost();
if (host != null && !host.isEmpty()) {
return urlObj.getProtocol() + "://" + host;
}
if (url.startsWith("file:")) {
String fileName = urlObj.getFile();
if (fileName != null && !fileName.isEmpty()) {
return fileName;
}
}
} catch (Exception e) {
// ignore
}
return title;
}
#Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
String newTitle = getTitleFromUrl(url);
new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setCancelable(false).create().show();
return true;
// return super.onJsAlert(view, url, message, result);
}
#Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
String newTitle = getTitleFromUrl(url);
new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
}).setCancelable(false).create().show();
return true;
// return super.onJsConfirm(view, url, message, result);
}
// Android 2.x
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
openFileChooser(uploadMsg, "");
}
// Android 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
openFileChooser(uploadMsg, "", "filesystem");
}
// Android 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUploadHandler = new UploadHandler(new Controller());
mUploadHandler.openFileChooser(uploadMsg, acceptType, capture);
}
};
class Controller {
final static int FILE_SELECTED = 4;
Activity getActivity() {
return MainActivity.this;
}
}
// copied from android-4.4.3_r1/src/com/android/browser/UploadHandler.java
//////////////////////////////////////////////////////////////////////
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// package com.android.browser;
//
// import android.app.Activity;
// import android.content.ActivityNotFoundException;
// import android.content.Intent;
// import android.net.Uri;
// import android.os.Environment;
// import android.provider.MediaStore;
// import android.webkit.ValueCallback;
// import android.widget.Toast;
//
// import java.io.File;
// import java.util.Vector;
//
// /**
// * Handle the file upload callbacks from WebView here
// */
// public class UploadHandler {
class UploadHandler {
/*
* The Object used to inform the WebView of the file to upload.
*/
private ValueCallback<Uri> mUploadMessage;
private String mCameraFilePath;
private boolean mHandled;
private boolean mCaughtActivityNotFoundException;
private Controller mController;
public UploadHandler(Controller controller) {
mController = controller;
}
String getFilePath() {
return mCameraFilePath;
}
boolean handled() {
return mHandled;
}
void onResult(int resultCode, Intent intent) {
if (resultCode == Activity.RESULT_CANCELED && mCaughtActivityNotFoundException) {
// Couldn't resolve an activity, we are going to try again so skip
// this result.
mCaughtActivityNotFoundException = false;
return;
}
Uri result = intent == null || resultCode != Activity.RESULT_OK ? null
: intent.getData();
// As we ask the camera to save the result of the user taking
// a picture, the camera application does not return anything other
// than RESULT_OK. So we need to check whether the file we expected
// was written to disk in the in the case that we
// did not get an intent returned but did get a RESULT_OK. If it was,
// we assume that this result has came back from the camera.
if (result == null && intent == null && resultCode == Activity.RESULT_OK) {
File cameraFile = new File(mCameraFilePath);
if (cameraFile.exists()) {
result = Uri.fromFile(cameraFile);
// Broadcast to the media scanner that we have a new photo
// so it will be added into the gallery for the user.
mController.getActivity().sendBroadcast(
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result));
}
}
mUploadMessage.onReceiveValue(result);
mHandled = true;
mCaughtActivityNotFoundException = false;
}
void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
final String imageMimeType = "image/*";
final String videoMimeType = "video/*";
final String audioMimeType = "audio/*";
final String mediaSourceKey = "capture";
final String mediaSourceValueCamera = "camera";
final String mediaSourceValueFileSystem = "filesystem";
final String mediaSourceValueCamcorder = "camcorder";
final String mediaSourceValueMicrophone = "microphone";
// According to the spec, media source can be 'filesystem' or 'camera' or 'camcorder'
// or 'microphone' and the default value should be 'filesystem'.
String mediaSource = mediaSourceValueFileSystem;
if (mUploadMessage != null) {
// Already a file picker operation in progress.
return;
}
mUploadMessage = uploadMsg;
// Parse the accept type.
String params[] = acceptType.split(";");
String mimeType = params[0];
if (capture.length() > 0) {
mediaSource = capture;
}
if (capture.equals(mediaSourceValueFileSystem)) {
// To maintain backwards compatibility with the previous implementation
// of the media capture API, if the value of the 'capture' attribute is
// "filesystem", we should examine the accept-type for a MIME type that
// may specify a different capture value.
for (String p : params) {
String[] keyValue = p.split("=");
if (keyValue.length == 2) {
// Process key=value parameters.
if (mediaSourceKey.equals(keyValue[0])) {
mediaSource = keyValue[1];
}
}
}
}
//Ensure it is not still set from a previous upload.
mCameraFilePath = null;
if (mimeType.equals(imageMimeType)) {
if (mediaSource.equals(mediaSourceValueCamera)) {
// Specified 'image/*' and requested the camera, so go ahead and launch the
// camera directly.
startActivity(createCameraIntent());
return;
} else {
// Specified just 'image/*', capture=filesystem, or an invalid capture parameter.
// In all these cases we show a traditional picker filetered on accept type
// so launch an intent for both the Camera and image/* OPENABLE.
Intent chooser = createChooserIntent(createCameraIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(imageMimeType));
startActivity(chooser);
return;
}
} else if (mimeType.equals(videoMimeType)) {
if (mediaSource.equals(mediaSourceValueCamcorder)) {
// Specified 'video/*' and requested the camcorder, so go ahead and launch the
// camcorder directly.
startActivity(createCamcorderIntent());
return;
} else {
// Specified just 'video/*', capture=filesystem or an invalid capture parameter.
// In all these cases we show an intent for the traditional file picker, filtered
// on accept type so launch an intent for both camcorder and video/* OPENABLE.
Intent chooser = createChooserIntent(createCamcorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(videoMimeType));
startActivity(chooser);
return;
}
} else if (mimeType.equals(audioMimeType)) {
if (mediaSource.equals(mediaSourceValueMicrophone)) {
// Specified 'audio/*' and requested microphone, so go ahead and launch the sound
// recorder.
startActivity(createSoundRecorderIntent());
return;
} else {
// Specified just 'audio/*', capture=filesystem of an invalid capture parameter.
// In all these cases so go ahead and launch an intent for both the sound
// recorder and audio/* OPENABLE.
Intent chooser = createChooserIntent(createSoundRecorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(audioMimeType));
startActivity(chooser);
return;
}
}
// No special handling based on the accept type was necessary, so trigger the default
// file upload chooser.
startActivity(createDefaultOpenableIntent());
}
private void startActivity(Intent intent) {
try {
mController.getActivity().startActivityForResult(intent, Controller.FILE_SELECTED);
} catch (ActivityNotFoundException e) {
// No installed app was able to handle the intent that
// we sent, so fallback to the default file upload control.
try {
mCaughtActivityNotFoundException = true;
mController.getActivity().startActivityForResult(createDefaultOpenableIntent(),
Controller.FILE_SELECTED);
} catch (ActivityNotFoundException e2) {
// Nothing can return us a file, so file upload is effectively disabled.
Toast.makeText(mController.getActivity(), R.string.uploads_disabled,
Toast.LENGTH_LONG).show();
}
}
}
private Intent createDefaultOpenableIntent() {
// Create and return a chooser with the default OPENABLE
// actions including the camera, camcorder and sound
// recorder where available.
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
Intent chooser = createChooserIntent(createCameraIntent(), createCamcorderIntent(),
createSoundRecorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, i);
return chooser;
}
private Intent createChooserIntent(Intent... intents) {
Intent chooser = new Intent(Intent.ACTION_CHOOSER);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents);
chooser.putExtra(Intent.EXTRA_TITLE,
mController.getActivity().getResources()
.getString(R.string.choose_upload));
return chooser;
}
private Intent createOpenableIntent(String type) {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType(type);
return i;
}
private Intent createCameraIntent() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File externalDataDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM);
File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
File.separator + "browser-photos");
cameraDataDir.mkdirs();
mCameraFilePath = cameraDataDir.getAbsolutePath() + File.separator +
System.currentTimeMillis() + ".jpg";
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCameraFilePath)));
return cameraIntent;
}
private Intent createCamcorderIntent() {
return new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
}
private Intent createSoundRecorderIntent() {
return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
}
}
}
For 4.4.2 Use this. This is a demo application link. download and import in your workspace.
http://applusform.com/down/AgateWebViewFileUpload_AndroidEclipse.zip

Related

The application does not have sufficient geolocation permissions

I thought this would be a simple solution but a day later I'm still unable to solve it.
Im creating a hybrid webview app and my site has a button that gets the users current location. This is working in chrome browser fine but in webview I get the following error:
E/cr_LocationProvider: Caught security exception while registering for location updates from the system. The application does not have sufficient geolocation permissions.
I've added permissions to the manifest:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
In the MainActivity.java I have:
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Parcelable;
import android.provider.MediaStore;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import android.webkit.GeolocationPermissions;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainActivity extends Activity {
private static final int INPUT_FILE_REQUEST_CODE = 1;
private static final int FILECHOOSER_RESULTCODE = 1;
private static final String TAG = MainActivity.class.getSimpleName();
private WebView webView;
private WebSettings webSettings;
private ValueCallback<Uri> mUploadMessage;
private Uri mCapturedImageURI = null;
private ValueCallback<Uri[]> mFilePathCallback;
private String mCameraPhotoPath;
#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;
}
public class GeoWebChromeClient extends WebChromeClient {
#Override
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
// Always grant permission since the app itself requires location
// permission and the user has therefore already granted it
callback.invoke(origin, true, false);
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = (WebView) findViewById(R.id.webview);
webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setLoadWithOverviewMode(true);
webSettings.setAllowFileAccess(true);
webView.setWebViewClient(new PQClient());
webView.setWebChromeClient(new PQChromeClient());
//webView.setWebViewClient(new GeoWebViewClient());
// Below required for geolocation
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setGeolocationEnabled(true);
webView.setWebChromeClient(new GeoWebChromeClient());
//if SDK version is greater of 19 then activate hardware acceleration otherwise activate software acceleration
if (Build.VERSION.SDK_INT >= 19) {
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
else if(Build.VERSION.SDK_INT >=11 && Build.VERSION.SDK_INT < 19) {
webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
//webView.loadUrl("file:///android_asset/index.html");
webView.loadUrl("https://google.com/");
}
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;
}
public class PQChromeClient 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(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);
}
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Check if the key event was the Back button and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
webView.goBack();
return true;
}
// If it wasn't the Back key or there's no web page history, bubble up to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
}
public class PQClient extends WebViewClient {
ProgressDialog progressDialog;
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// If url contains mailto link then open Mail Intent
if (url.contains("mailto:")) {
// Could be cleverer and use a regex
//Open links in new browser
view.getContext().startActivity(
new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
// Here we can open new activity
return true;
}else {
// Stay within this webview and load url
view.loadUrl(url);
return true;
}
}
//Show loader on url load
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// Then show progress Dialog
// in standard case YourActivity.this
if (progressDialog == null) {
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage("Loading...");
progressDialog.show();
}
}
// Called when all page resources loaded
public void onPageFinished(WebView view, String url) {
webView.loadUrl("javascript:(function(){ "+
"document.getElementById('android-app').style.display='none';})()");
try {
// Close progressDialog
if (progressDialog.isShowing()) {
progressDialog.dismiss();
progressDialog = null;
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
}
Any ideas where I've gone wrong?
Thanks

Multiple file upload in Android Webview

Please, How can I enable or something else my Android Webview to upload multiple files?
When I upload only a file works very well, but I can't select more than one file to upload at the same time.
Is it possible? I think yes, but don't know how =/.
Take a look of my code to upload multiple image , it will give you nice idea for other type of file also.
For selecting multiple image from gallery
i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,true);
An Ultimate Solution for multiple image upload with camera option also for Android Lollipop to Android 10, SDK 30.
private static final int FILECHOOSER_RESULTCODE = 1;
private ValueCallback<Uri> mUploadMessage;
private ValueCallback<Uri[]> mUploadMessages;
private Uri mCapturedImageURI = null;
Add this to OnCreate of MainActivity
mWebView.setWebChromeClient(new WebChromeClient() {
// openFileChooser for Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType){
mUploadMessage = uploadMsg;
openImageChooser();
}
// For Lollipop 5.0+ Devices
public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
mUploadMessages = filePathCallback;
openImageChooser();
return true;
}
// 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);
}
private void openImageChooser() {
try {
File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "FolderName");
if (!imageStorageDir.exists()) {
imageStorageDir.mkdirs();
}
File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");
mCapturedImageURI = Uri.fromFile(file);
final Intent captureIntent = new Intent(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/*");
i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,true);
Intent chooserIntent = Intent.createChooser(i, "Image Chooser");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Parcelable[]{captureIntent});
startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE);
} catch (Exception e) {
e.printStackTrace();
}
}
});
onActivityResult
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == mUploadMessage && null == mUploadMessages) {
return;
}
if (null != mUploadMessage) {
handleUploadMessage(requestCode, resultCode, data);
} else if (mUploadMessages != null) {
handleUploadMessages(requestCode, resultCode, data);
}
}
}
private void handleUploadMessage(final int requestCode, final int resultCode, final Intent data) {
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) {
e.printStackTrace();
}
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
// code for all versions except of Lollipop
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
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;
}
} // end of code for all versions except of Lollipop
private void handleUploadMessages(final int requestCode, final int resultCode, final Intent data) {
Uri[] results = null;
try {
if (resultCode != RESULT_OK) {
results = null;
} else {
if (data != null) {
String dataString = data.getDataString();
ClipData clipData = data.getClipData();
if (clipData != null) {
results = new Uri[clipData.getItemCount()];
for (int i = 0; i < clipData.getItemCount(); i++) {
ClipData.Item item = clipData.getItemAt(i);
results[i] = item.getUri();
}
}
if (dataString != null) {
results = new Uri[]{Uri.parse(dataString)};
}
} else {
results = new Uri[]{mCapturedImageURI};
}
}
} catch (Exception e) {
e.printStackTrace();
}
mUploadMessages.onReceiveValue(results);
mUploadMessages = null;
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
setContentView(R.layout.activity_webview);
WebView webView = (WebView) findViewById(R.id.activity_main_webview);
progress = (ProgressBar) findViewById(R.id.progressBar);
progress.setVisibility(View.GONE);
initWebView(webView);
webView.loadUrl("URL"); // TODO input your url
}
private void initWebView(android.webkit.WebView webView) {
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setAllowFileAccess(true);
settings.setDomStorageEnabled(true);
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
settings.setLoadWithOverviewMode(true);
settings.setUseWideViewPort(true);
settings.setSupportZoom(true);
settings.setSupportMultipleWindows(true);
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setPluginState(PluginState.ON);
methodInvoke(settings, "setPluginState", new Class[] { WebSettings.PluginState.class }, new Object[] { WebSettings.PluginState.ON });
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowUniversalAccessFromFileURLs(true);
methodInvoke(settings, "setAllowUniversalAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowFileAccessFromFileURLs(true);
methodInvoke(settings, "setAllowFileAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
methodInvoke(settings, "setMixedContentAllowed", new Class[] { boolean.class }, new Object[] { true });
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webView.clearHistory();
webView.clearFormData();
webView.clearCache(true);
}
UploadHandler mUploadHandler;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == Controller.FILE_SELECTED) {
// Chose a file from the file picker.
if (mUploadHandler != null) {
mUploadHandler.onResult(resultCode, intent);
}
}
super.onActivityResult(requestCode, resultCode, intent);
}
class MyWebChromeClient extends WebChromeClient {
public MyWebChromeClient() {
}
private String getTitleFromUrl(String url) {
String title = url;
try {
URL urlObj = new URL(url);
String host = urlObj.getHost();
if (host != null && !host.isEmpty()) {
return urlObj.getProtocol() + "://" + host;
}
if (url.startsWith("file:")) {
String fileName = urlObj.getFile();
if (fileName != null && !fileName.isEmpty()) {
return fileName;
}
}
} catch (Exception e) {
// ignore
}
return title;
}
#Override
public boolean onJsAlert(android.webkit.WebView view, String url, String message, final JsResult result) {
String newTitle = getTitleFromUrl(url);
new AlertDialog.Builder(WebViewClass.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setCancelable(false).create().show();
return true;
// return super.onJsAlert(view, url, message, result);
}
#Override
public boolean onJsConfirm(android.webkit.WebView view, String url, String message, final JsResult result) {
String newTitle = getTitleFromUrl(url);
new AlertDialog.Builder(WebViewClass.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
}).setCancelable(false).create().show();
return true;
// return super.onJsConfirm(view, url, message, result);
}
// Android 2.x
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
openFileChooser(uploadMsg, "");
}
// Android 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
openFileChooser(uploadMsg, "", "filesystem");
}
// Android 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUploadHandler = new UploadHandler(new Controller());
mUploadHandler.openFileChooser(uploadMsg, acceptType, capture);
}
// Android 4.4, 4.4.1, 4.4.2
// openFileChooser function is not called on Android 4.4, 4.4.1, 4.4.2,
// you may use your own java script interface or other hybrid framework.
// Android 5.0.1
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public boolean onShowFileChooser(
android.webkit.WebView webView, ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams) {
String acceptTypes[] = fileChooserParams.getAcceptTypes();
String acceptType = "";
for (int i = 0; i < acceptTypes.length; ++ i) {
if (acceptTypes[i] != null && acceptTypes[i].length() != 0)
acceptType += acceptTypes[i] + ";";
}
if (acceptType.length() == 0)
acceptType = "*/*";
final ValueCallback<Uri[]> finalFilePathCallback = filePathCallback;
ValueCallback<Uri> vc = new ValueCallback<Uri>() {
#Override
public void onReceiveValue(Uri value) {
Uri[] result;
if (value != null)
result = new Uri[]{value};
else
result = null;
finalFilePathCallback.onReceiveValue(result);
}
};
openFileChooser(vc, acceptType, "filesystem");
return true;
}
};
class Controller {
final static int FILE_SELECTED = 4;
Activity getActivity() {
return WebViewClass.this;
}
}
// copied from android-4.4.3_r1/src/com/android/browser/UploadHandler.java
//////////////////////////////////////////////////////////////////////
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// package com.android.browser;
//
// import android.app.Activity;
// import android.content.ActivityNotFoundException;
// import android.content.Intent;
// import android.net.Uri;
// import android.os.Environment;
// import android.provider.MediaStore;
// import android.webkit.ValueCallback;
// import android.widget.Toast;
//
// import java.io.File;
// import java.util.Vector;
//
// /**
// * Handle the file upload callbacks from WebView here
// */
// public class UploadHandler {
class UploadHandler {
/*
* The Object used to inform the WebView of the file to upload.
*/
private ValueCallback<Uri> mUploadMessage;
private String mCameraFilePath;
private boolean mHandled;
private boolean mCaughtActivityNotFoundException;
private Controller mController;
public UploadHandler(Controller controller) {
mController = controller;
}
String getFilePath() {
return mCameraFilePath;
}
boolean handled() {
return mHandled;
}
void onResult(int resultCode, Intent intent) {
if (resultCode == Activity.RESULT_CANCELED && mCaughtActivityNotFoundException) {
// Couldn't resolve an activity, we are going to try again so skip
// this result.
mCaughtActivityNotFoundException = false;
return;
}
Uri result = intent == null || resultCode != Activity.RESULT_OK ? null
: intent.getData();
// As we ask the camera to save the result of the user taking
// a picture, the camera application does not return anything other
// than RESULT_OK. So we need to check whether the file we expected
// was written to disk in the in the case that we
// did not get an intent returned but did get a RESULT_OK. If it was,
// we assume that this result has came back from the camera.
if (result == null && intent == null && resultCode == Activity.RESULT_OK) {
File cameraFile = new File(mCameraFilePath);
if (cameraFile.exists()) {
result = Uri.fromFile(cameraFile);
// Broadcast to the media scanner that we have a new photo
// so it will be added into the gallery for the user.
mController.getActivity().sendBroadcast(
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result));
}
}
mUploadMessage.onReceiveValue(result);
mHandled = true;
mCaughtActivityNotFoundException = false;
}
void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
final String imageMimeType = "image/*";
final String videoMimeType = "video/*";
final String audioMimeType = "audio/*";
final String mediaSourceKey = "capture";
final String mediaSourceValueCamera = "camera";
final String mediaSourceValueFileSystem = "filesystem";
final String mediaSourceValueCamcorder = "camcorder";
final String mediaSourceValueMicrophone = "microphone";
// According to the spec, media source can be 'filesystem' or 'camera' or 'camcorder'
// or 'microphone' and the default value should be 'filesystem'.
String mediaSource = mediaSourceValueFileSystem;
if (mUploadMessage != null) {
// Already a file picker operation in progress.
return;
}
mUploadMessage = uploadMsg;
// Parse the accept type.
String params[] = acceptType.split(";");
String mimeType = params[0];
if (capture.length() > 0) {
mediaSource = capture;
}
if (capture.equals(mediaSourceValueFileSystem)) {
// To maintain backwards compatibility with the previous implementation
// of the media capture API, if the value of the 'capture' attribute is
// "filesystem", we should examine the accept-type for a MIME type that
// may specify a different capture value.
for (String p : params) {
String[] keyValue = p.split("=");
if (keyValue.length == 2) {
// Process key=value parameters.
if (mediaSourceKey.equals(keyValue[0])) {
mediaSource = keyValue[1];
}
}
}
}
//Ensure it is not still set from a previous upload.
mCameraFilePath = null;
if (mimeType.equals(imageMimeType)) {
if (mediaSource.equals(mediaSourceValueCamera)) {
// Specified 'image/*' and requested the camera, so go ahead and launch the
// camera directly.
startActivity(createCameraIntent());
return;
} else {
// Specified just 'image/*', capture=filesystem, or an invalid capture parameter.
// In all these cases we show a traditional picker filetered on accept type
// so launch an intent for both the Camera and image/* OPENABLE.
Intent chooser = createChooserIntent(createCameraIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(imageMimeType));
startActivity(chooser);
return;
}
} else if (mimeType.equals(videoMimeType)) {
if (mediaSource.equals(mediaSourceValueCamcorder)) {
// Specified 'video/*' and requested the camcorder, so go ahead and launch the
// camcorder directly.
startActivity(createCamcorderIntent());
return;
} else {
// Specified just 'video/*', capture=filesystem or an invalid capture parameter.
// In all these cases we show an intent for the traditional file picker, filtered
// on accept type so launch an intent for both camcorder and video/* OPENABLE.
Intent chooser = createChooserIntent(createCamcorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(videoMimeType));
startActivity(chooser);
return;
}
} else if (mimeType.equals(audioMimeType)) {
if (mediaSource.equals(mediaSourceValueMicrophone)) {
// Specified 'audio/*' and requested microphone, so go ahead and launch the sound
// recorder.
startActivity(createSoundRecorderIntent());
return;
} else {
// Specified just 'audio/*', capture=filesystem of an invalid capture parameter.
// In all these cases so go ahead and launch an intent for both the sound
// recorder and audio/* OPENABLE.
Intent chooser = createChooserIntent(createSoundRecorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(audioMimeType));
startActivity(chooser);
return;
}
}
// No special handling based on the accept type was necessary, so trigger the default
// file upload chooser.
startActivity(createDefaultOpenableIntent());
}
private void startActivity(Intent intent) {
try {
mController.getActivity().startActivityForResult(intent, Controller.FILE_SELECTED);
} catch (ActivityNotFoundException e) {
// No installed app was able to handle the intent that
// we sent, so fallback to the default file upload control.
try {
mCaughtActivityNotFoundException = true;
mController.getActivity().startActivityForResult(createDefaultOpenableIntent(),
Controller.FILE_SELECTED);
} catch (ActivityNotFoundException e2) {
// Nothing can return us a file, so file upload is effectively disabled.
Toast.makeText(mController.getActivity(), R.string.action_settings,
Toast.LENGTH_LONG).show();
}
}
}
private Intent createDefaultOpenableIntent() {
// Create and return a chooser with the default OPENABLE
// actions including the camera, camcorder and sound
// recorder where available.
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
Intent chooser = createChooserIntent(createCameraIntent(), createCamcorderIntent(),
createSoundRecorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, i);
return chooser;
}
private Intent createChooserIntent(Intent... intents) {
Intent chooser = new Intent(Intent.ACTION_CHOOSER);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents);
chooser.putExtra(Intent.EXTRA_TITLE,
mController.getActivity().getResources()
.getString(R.string.action_settings));
return chooser;
}
private Intent createOpenableIntent(String type) {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType(type);
return i;
}
private Intent createCameraIntent() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File externalDataDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM);
File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
File.separator + "Webbme");
cameraDataDir.mkdirs();
mCameraFilePath = cameraDataDir.getAbsolutePath() + File.separator +
System.currentTimeMillis() + ".jpg";
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCameraFilePath)));
return cameraIntent;
}
private Intent createCamcorderIntent() {
return new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
}
private Intent createSoundRecorderIntent() {
return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
}
}

add progressbar to my webview

I have webview from :UploadHandler class in Android 4.0.4 .
I want to add a Progress Bar to web view.
All the codes I try dont work.
Who can help. ??!
this my MainAvtivity.java:
package com.com.myapplication;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.webkit.JsResult;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebSettings.PluginState;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
WebView webView = (WebView) findViewById(R.id.webview);
initWebView(webView);
webView.loadUrl("http://google"); // TODO input your url
}
private final static Object methodInvoke(Object obj, String method, Class<?>[] parameterTypes, Object[] args) {
try {
Method m = obj.getClass().getMethod(method, new Class[] { boolean.class });
m.invoke(obj, args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void initWebView(WebView webView) {
WebSettings settings = webView.getSettings();
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient());
settings.setJavaScriptEnabled(true);
settings.setAllowFileAccess(true);
settings.setDomStorageEnabled(true);
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
settings.setLoadWithOverviewMode(true);
settings.setUseWideViewPort(true);
settings.setSupportZoom(true);
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setPluginState(PluginState.ON);
methodInvoke(settings, "setPluginState", new Class[] { PluginState.class }, new Object[] { PluginState.ON });
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowUniversalAccessFromFileURLs(true);
methodInvoke(settings, "setAllowUniversalAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowFileAccessFromFileURLs(true);
methodInvoke(settings, "setAllowFileAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webView.clearHistory();
webView.clearFormData();
webView.clearCache(true);
webView.setWebChromeClient(new MyWebChromeClient());
// webView.setDownloadListener(downloadListener);
}
UploadHandler mUploadHandler;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == Controller.FILE_SELECTED) {
// Chose a file from the file picker.
if (mUploadHandler != null) {
mUploadHandler.onResult(resultCode, intent);
}
}
super.onActivityResult(requestCode, resultCode, intent);
}
class MyWebChromeClient extends WebChromeClient {
public MyWebChromeClient() {
}
private String getTitleFromUrl(String url) {
String title = url;
try {
URL urlObj = new URL(url);
String host = urlObj.getHost();
if (host != null && !host.isEmpty()) {
return urlObj.getProtocol() + "://" + host;
}
if (url.startsWith("file:")) {
String fileName = urlObj.getFile();
if (fileName != null && !fileName.isEmpty()) {
return fileName;
}
}
} catch (Exception e) {
// ignore
}
return title;
}
#Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
String newTitle = getTitleFromUrl(url);
new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setCancelable(false).create().show();
return true;
// return super.onJsAlert(view, url, message, result);
}
#Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
String newTitle = getTitleFromUrl(url);
new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
}).setCancelable(false).create().show();
return true;
// return super.onJsConfirm(view, url, message, result);
}
// Android 2.x
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
openFileChooser(uploadMsg, "");
}
// Android 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
openFileChooser(uploadMsg, "", "filesystem");
}
// Android 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUploadHandler = new UploadHandler(new Controller());
mUploadHandler.openFileChooser(uploadMsg, acceptType, capture);
}
};
class Controller {
final static int FILE_SELECTED = 4;
Activity getActivity() {
return MainActivity.this;
}
}
// copied from android-4.4.3_r1/src/com/android/browser/UploadHandler.java
//////////////////////////////////////////////////////////////////////
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// package com.android.browser;
//
// import android.app.Activity;
// import android.content.ActivityNotFoundException;
// import android.content.Intent;
// import android.net.Uri;
// import android.os.Environment;
// import android.provider.MediaStore;
// import android.webkit.ValueCallback;
// import android.widget.Toast;
//
// import java.io.File;
// import java.util.Vector;
//
// /**
// * Handle the file upload callbacks from WebView here
// */
// public class UploadHandler {
class UploadHandler {
/*
* The Object used to inform the WebView of the file to upload.
*/
private ValueCallback<Uri> mUploadMessage;
private String mCameraFilePath;
private boolean mHandled;
private boolean mCaughtActivityNotFoundException;
private Controller mController;
public UploadHandler(Controller controller) {
mController = controller;
}
String getFilePath() {
return mCameraFilePath;
}
boolean handled() {
return mHandled;
}
void onResult(int resultCode, Intent intent) {
if (resultCode == Activity.RESULT_CANCELED && mCaughtActivityNotFoundException) {
// Couldn't resolve an activity, we are going to try again so skip
// this result.
mCaughtActivityNotFoundException = false;
return;
}
Uri result = intent == null || resultCode != Activity.RESULT_OK ? null
: intent.getData();
// As we ask the camera to save the result of the user taking
// a picture, the camera application does not return anything other
// than RESULT_OK. So we need to check whether the file we expected
// was written to disk in the in the case that we
// did not get an intent returned but did get a RESULT_OK. If it was,
// we assume that this result has came back from the camera.
if (result == null && intent == null && resultCode == Activity.RESULT_OK) {
File cameraFile = new File(mCameraFilePath);
if (cameraFile.exists()) {
result = Uri.fromFile(cameraFile);
// Broadcast to the media scanner that we have a new photo
// so it will be added into the gallery for the user.
mController.getActivity().sendBroadcast(
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result));
}
}
mUploadMessage.onReceiveValue(result);
mHandled = true;
mCaughtActivityNotFoundException = false;
}
void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
final String imageMimeType = "image/*";
final String videoMimeType = "video/*";
final String audioMimeType = "audio/*";
final String mediaSourceKey = "capture";
final String mediaSourceValueCamera = "camera";
final String mediaSourceValueFileSystem = "filesystem";
final String mediaSourceValueCamcorder = "camcorder";
final String mediaSourceValueMicrophone = "microphone";
// According to the spec, media source can be 'filesystem' or 'camera' or 'camcorder'
// or 'microphone' and the default value should be 'filesystem'.
String mediaSource = mediaSourceValueFileSystem;
if (mUploadMessage != null) {
// Already a file picker operation in progress.
return;
}
mUploadMessage = uploadMsg;
// Parse the accept type.
String params[] = acceptType.split(";");
String mimeType = params[0];
if (capture.length() > 0) {
mediaSource = capture;
}
if (capture.equals(mediaSourceValueFileSystem)) {
// To maintain backwards compatibility with the previous implementation
// of the media capture API, if the value of the 'capture' attribute is
// "filesystem", we should examine the accept-type for a MIME type that
// may specify a different capture value.
for (String p : params) {
String[] keyValue = p.split("=");
if (keyValue.length == 2) {
// Process key=value parameters.
if (mediaSourceKey.equals(keyValue[0])) {
mediaSource = keyValue[1];
}
}
}
}
//Ensure it is not still set from a previous upload.
mCameraFilePath = null;
if (mimeType.equals(imageMimeType)) {
if (mediaSource.equals(mediaSourceValueCamera)) {
// Specified 'image/*' and requested the camera, so go ahead and launch the
// camera directly.
startActivity(createCameraIntent());
return;
} else {
// Specified just 'image/*', capture=filesystem, or an invalid capture parameter.
// In all these cases we show a traditional picker filetered on accept type
// so launch an intent for both the Camera and image/* OPENABLE.
Intent chooser = createChooserIntent(createCameraIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(imageMimeType));
startActivity(chooser);
return;
}
} else if (mimeType.equals(videoMimeType)) {
if (mediaSource.equals(mediaSourceValueCamcorder)) {
// Specified 'video/*' and requested the camcorder, so go ahead and launch the
// camcorder directly.
startActivity(createCamcorderIntent());
return;
} else {
// Specified just 'video/*', capture=filesystem or an invalid capture parameter.
// In all these cases we show an intent for the traditional file picker, filtered
// on accept type so launch an intent for both camcorder and video/* OPENABLE.
Intent chooser = createChooserIntent(createCamcorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(videoMimeType));
startActivity(chooser);
return;
}
} else if (mimeType.equals(audioMimeType)) {
if (mediaSource.equals(mediaSourceValueMicrophone)) {
// Specified 'audio/*' and requested microphone, so go ahead and launch the sound
// recorder.
startActivity(createSoundRecorderIntent());
return;
} else {
// Specified just 'audio/*', capture=filesystem of an invalid capture parameter.
// In all these cases so go ahead and launch an intent for both the sound
// recorder and audio/* OPENABLE.
Intent chooser = createChooserIntent(createSoundRecorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(audioMimeType));
startActivity(chooser);
return;
}
}
// No special handling based on the accept type was necessary, so trigger the default
// file upload chooser.
startActivity(createDefaultOpenableIntent());
}
private void startActivity(Intent intent) {
try {
mController.getActivity().startActivityForResult(intent, Controller.FILE_SELECTED);
} catch (ActivityNotFoundException e) {
// No installed app was able to handle the intent that
// we sent, so fallback to the default file upload control.
try {
mCaughtActivityNotFoundException = true;
mController.getActivity().startActivityForResult(createDefaultOpenableIntent(),
Controller.FILE_SELECTED);
} catch (ActivityNotFoundException e2) {
// Nothing can return us a file, so file upload is effectively disabled.
Toast.makeText(mController.getActivity(), R.string.uploads_disabled,
Toast.LENGTH_LONG).show();
}
}
}
private Intent createDefaultOpenableIntent() {
// Create and return a chooser with the default OPENABLE
// actions including the camera, camcorder and sound
// recorder where available.
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
Intent chooser = createChooserIntent(createCameraIntent(), createCamcorderIntent(),
createSoundRecorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, i);
return chooser;
}
private Intent createChooserIntent(Intent... intents) {
Intent chooser = new Intent(Intent.ACTION_CHOOSER);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents);
chooser.putExtra(Intent.EXTRA_TITLE,
mController.getActivity().getResources()
.getString(R.string.choose_upload));
return chooser;
}
private Intent createOpenableIntent(String type) {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType(type);
return i;
}
private Intent createCameraIntent() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File externalDataDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM);
File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
File.separator + "browser-photos");
cameraDataDir.mkdirs();
mCameraFilePath = cameraDataDir.getAbsolutePath() + File.separator +
System.currentTimeMillis() + ".jpg";
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCameraFilePath)));
return cameraIntent;
}
private Intent createCamcorderIntent() {
return new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
}
private Intent createSoundRecorderIntent() {
return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
}
}
#Override
public void onBackPressed()
{
WebView webView = (WebView) findViewById(R.id.webview);
if(webView.canGoBack()){
webView.goBack();
}else{
super.onBackPressed();
}
}
}
and this my layout Main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="fill"
android:id="#+id/rel_webpage_whole"
android:background="#000000"
>
<ProgressBar
android:layout_width="fill_parent"
android:layout_height="5dip"
android:layout_alignParentTop="true"
style="?android:attr/progressBarStyleHorizontal"
android:id="#+id/progressBar"
android:max="100"
android:background="#228b22"
/>
<WebView
android:id="#+id/webview"
android:layout_below="#id/progressBar"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerVertical="true"
android:layout_centerInParent="true"
/>
</RelativeLayout>
tnx!!! :)
You can use your layout as follows:
<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=".MainActivity" >
<ProgressBar
android:id="#+id/progressDialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<WebView
android:id="#+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
Now in your code
ProgressDialog progressDialog = (ProgressDialog)findViewById(R.id.progressDialog);
progressDialog.setTitle("Loading");
progressDialog.setMessage("Your Message");
progressDialog.show();
once loading your webview contents are done or your expected action is done,
progressDialog.dismiss();
If you want horizontal Progress Dialog
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
if you know progress
progressDialog.setProgress(0);
progressDialog.setMax(100);
and Set Progress in your thread. If you don't Know progress,
progressDialog.setIndeterminate(true);
Initialize progressbar like this:
ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressDialog);
This is wrong casting:
ProgressDialog progressDialog = (ProgressDialog)findViewById(R.id.progressDialog);
Using this code you can show progressdialog to webview and dismiss dialog when web view page loading is finished
public class Activity extends ActionBarActivity {
WebView myBrowser;
ProgressDialog progress;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mapwebview);
myBrowser = (WebView)findViewById(R.id.mybrowser);
myBrowser.setWebViewClient(new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
progress = ProgressDialog.show(Activity.this, "Please Wait", "Refreshing");
}
#Override
public void onPageFinished(WebView view, String url) {
if (progress.isShowing()) {
progress.dismiss();
}
}
});
//load saved file
Log.e("PAth", getFilesDir().toString());
myBrowser.loadUrl("file:///"+getFilesDir()+"/MySampleFile.html");
myBrowser.getSettings().setJavaScriptEnabled(true);
myBrowser.getSettings().setBuiltInZoomControls(true);
}
}
Use sample code below:
WebView view= new WebView(getApplicationContext());
view.setWebViewClient(new WebViewClient(){
ProgressDialog dialog= new ProgressDialog(getApplicationContext());
#Override
public void onPageStarted(WebView view, String url,
Bitmap favicon) {
// TODO Auto-generated method stub
dialog.setMessage("Loading please wait");
dialog.show();
super.onPageStarted(view, url, favicon);
}
#Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
dialog.dismiss();
super.onPageFinished(view, url);
}
});
If by chance app get crashed then use "MainActivity.this" at place of getapplicationContext.
Hope this will solve your problem.
I am using your code below to show dialog:
private void initWebView(WebView view, String url) {
WebSettings settings = view.getSettings();
// WebView myWebView = (WebView) findViewById(R.id.webview);
view.setWebViewClient(new WebViewClient());
settings.setJavaScriptEnabled(true);
settings.setAllowFileAccess(true);
settings.setDomStorageEnabled(true);
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
settings.setLoadWithOverviewMode(true);
settings.setUseWideViewPort(true);
settings.setSupportZoom(true);
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setPluginState(PluginState.ON);
methodInvoke(settings, "setPluginState", new Class[] { PluginState.class }, new Object[] { PluginState.ON });
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowUniversalAccessFromFileURLs(true);
methodInvoke(settings, "setAllowUniversalAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowFileAccessFromFileURLs(true);
methodInvoke(settings, "setAllowFileAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
view.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
view.clearHistory();
view.clearFormData();
view.clearCache(true);
view.loadUrl(url);
view.setWebViewClient(new WebViewClient(){
ProgressDialog dialog= new ProgressDialog(getApplicationContext());
// suppose Imageview and Webview has visibility gone by default then
#Override
public void onPageStarted(WebView view, String url,
Bitmap favicon) {
// TODO Auto-generated method stub
//dialog.setMessage("Loading please wait");
//dialog.show();
Imageview.setvisivility(View.VISIBLE);
super.onPageStarted(view, url, favicon);
}
#Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
//dialog.dismiss();
imageview.setvisibility(View.GONE);
view.setvisibility(View.VISIBLE);
super.onPageFinished(view, url);
}
});
view.setWebChromeClient(new MyWebChromeClient());
// webView.setDownloadListener(downloadListener);
}
now your Onceate Method;
String url="http://stackoverflow.com/posts/25986941"
WebView v= (Webview)findviewbyId(R.id.webviewid);
initWebView(v,url);

"choose file to upload" on webview android kitkat 4.4.2

I have a web view, I add the code to upload files and it works well on 4.3 and 4.2 (galaxy s3) , but it doesn't work on 4.4.2 like galaxy s5 and lg3.
when I click on "choose file" it does not respond and nothing happens...
this my code.
MainActivity.java :
package com.com.myapplication;
/**
* Created by tadmitinteractive on 9/21/14.
*/
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.webkit.JsResult;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebSettings.PluginState;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
WebView webView = (WebView) findViewById(R.id.webview);
String url="http://www.ipets.co.il/wp-login.php";
initWebView(webView,url);
// TODO input your url
}
private final static Object methodInvoke(Object obj, String method, Class<?>[] parameterTypes, Object[] args) {
try {
Method m = obj.getClass().getMethod(method, new Class[] { boolean.class });
m.invoke(obj, args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void initWebView(WebView view, String url) {
WebSettings settings = view.getSettings();
final WebView myWebView = (WebView) findViewById(R.id.webview);
final ImageView imageView = (ImageView) findViewById(R.id.imageView);
view.setWebViewClient(new WebViewClient());
settings.setJavaScriptEnabled(true);
settings.setAllowFileAccess(true);
settings.setDomStorageEnabled(true);
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
settings.setLoadWithOverviewMode(true);
settings.setUseWideViewPort(true);
settings.setSupportZoom(true);
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setPluginState(PluginState.ON);
methodInvoke(settings, "setPluginState", new Class[] { PluginState.class }, new Object[] { PluginState.ON });
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowUniversalAccessFromFileURLs(true);
methodInvoke(settings, "setAllowUniversalAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowFileAccessFromFileURLs(true);
methodInvoke(settings, "setAllowFileAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
view.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
view.clearHistory();
view.clearFormData();
view.clearCache(true);
view.loadUrl(url);
view.setWebViewClient(new WebViewClient() {
ProgressDialog dialog = new ProgressDialog(MainActivity.this);
#Override
public void onPageStarted(WebView view, String url,
Bitmap favicon) {
// TODO Auto-generated method stub
dialog.setMessage("טוען...");
dialog.show();
super.onPageStarted(view, url, favicon);
}
#Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
myWebView.setVisibility(View.VISIBLE);
imageView.setVisibility(View.GONE);
dialog.dismiss();
super.onPageFinished(view, url);
}
});
view.setWebChromeClient(new MyWebChromeClient());
// webView.setDownloadListener(downloadListener);
}
UploadHandler mUploadHandler;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == Controller.FILE_SELECTED) {
// Chose a file from the file picker.
if (mUploadHandler != null) {
mUploadHandler.onResult(resultCode, intent);
}
}
super.onActivityResult(requestCode, resultCode, intent);
}
class MyWebChromeClient extends WebChromeClient {
public MyWebChromeClient() {
}
private String getTitleFromUrl(String url) {
String title = url;
try {
URL urlObj = new URL(url);
String host = urlObj.getHost();
if (host != null && !host.isEmpty()) {
return urlObj.getProtocol() + "://" + host;
}
if (url.startsWith("file:")) {
String fileName = urlObj.getFile();
if (fileName != null && !fileName.isEmpty()) {
return fileName;
}
}
} catch (Exception e) {
// ignore
}
return title;
}
#Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
String newTitle = getTitleFromUrl(url);
new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setCancelable(false).create().show();
return true;
// return super.onJsAlert(view, url, message, result);
}
#Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
String newTitle = getTitleFromUrl(url);
new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
}).setCancelable(false).create().show();
return true;
// return super.onJsConfirm(view, url, message, result);
}
// Android 2.x
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
openFileChooser(uploadMsg, "");
}
// Android 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
openFileChooser(uploadMsg, "", "filesystem");
}
// Android 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUploadHandler = new UploadHandler(new Controller());
mUploadHandler.openFileChooser(uploadMsg, acceptType, capture);
}
};
class Controller {
final static int FILE_SELECTED = 4;
Activity getActivity() {
return MainActivity.this;
}
}
// copied from android-4.4.3_r1/src/com/android/browser/UploadHandler.java
//////////////////////////////////////////////////////////////////////
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// package com.android.browser;
//
// import android.app.Activity;
// import android.content.ActivityNotFoundException;
// import android.content.Intent;
// import android.net.Uri;
// import android.os.Environment;
// import android.provider.MediaStore;
// import android.webkit.ValueCallback;
// import android.widget.Toast;
//
// import java.io.File;
// import java.util.Vector;
//
// /**
// * Handle the file upload callbacks from WebView here
// */
// public class UploadHandler {
class UploadHandler {
/*
* The Object used to inform the WebView of the file to upload.
*/
private ValueCallback<Uri> mUploadMessage;
private String mCameraFilePath;
private boolean mHandled;
private boolean mCaughtActivityNotFoundException;
private Controller mController;
public UploadHandler(Controller controller) {
mController = controller;
}
String getFilePath() {
return mCameraFilePath;
}
boolean handled() {
return mHandled;
}
void onResult(int resultCode, Intent intent) {
if (resultCode == Activity.RESULT_CANCELED && mCaughtActivityNotFoundException) {
// Couldn't resolve an activity, we are going to try again so skip
// this result.
mCaughtActivityNotFoundException = false;
return;
}
Uri result = intent == null || resultCode != Activity.RESULT_OK ? null
: intent.getData();
// As we ask the camera to save the result of the user taking
// a picture, the camera application does not return anything other
// than RESULT_OK. So we need to check whether the file we expected
// was written to disk in the in the case that we
// did not get an intent returned but did get a RESULT_OK. If it was,
// we assume that this result has came back from the camera.
if (result == null && intent == null && resultCode == Activity.RESULT_OK) {
File cameraFile = new File(mCameraFilePath);
if (cameraFile.exists()) {
result = Uri.fromFile(cameraFile);
// Broadcast to the media scanner that we have a new photo
// so it will be added into the gallery for the user.
mController.getActivity().sendBroadcast(
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result));
}
}
mUploadMessage.onReceiveValue(result);
mHandled = true;
mCaughtActivityNotFoundException = false;
}
void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
final String imageMimeType = "image/*";
final String videoMimeType = "video/*";
final String audioMimeType = "audio/*";
final String mediaSourceKey = "capture";
final String mediaSourceValueCamera = "camera";
final String mediaSourceValueFileSystem = "filesystem";
final String mediaSourceValueCamcorder = "camcorder";
final String mediaSourceValueMicrophone = "microphone";
// According to the spec, media source can be 'filesystem' or 'camera' or 'camcorder'
// or 'microphone' and the default value should be 'filesystem'.
String mediaSource = mediaSourceValueFileSystem;
if (mUploadMessage != null) {
// Already a file picker operation in progress.
return;
}
mUploadMessage = uploadMsg;
// Parse the accept type.
String params[] = acceptType.split(";");
String mimeType = params[0];
if (capture.length() > 0) {
mediaSource = capture;
}
if (capture.equals(mediaSourceValueFileSystem)) {
// To maintain backwards compatibility with the previous implementation
// of the media capture API, if the value of the 'capture' attribute is
// "filesystem", we should examine the accept-type for a MIME type that
// may specify a different capture value.
for (String p : params) {
String[] keyValue = p.split("=");
if (keyValue.length == 2) {
// Process key=value parameters.
if (mediaSourceKey.equals(keyValue[0])) {
mediaSource = keyValue[1];
}
}
}
}
//Ensure it is not still set from a previous upload.
mCameraFilePath = null;
if (mimeType.equals(imageMimeType)) {
if (mediaSource.equals(mediaSourceValueCamera)) {
// Specified 'image/*' and requested the camera, so go ahead and launch the
// camera directly.
startActivity(createCameraIntent());
return;
} else {
// Specified just 'image/*', capture=filesystem, or an invalid capture parameter.
// In all these cases we show a traditional picker filetered on accept type
// so launch an intent for both the Camera and image/* OPENABLE.
Intent chooser = createChooserIntent(createCameraIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(imageMimeType));
startActivity(chooser);
return;
}
} else if (mimeType.equals(videoMimeType)) {
if (mediaSource.equals(mediaSourceValueCamcorder)) {
// Specified 'video/*' and requested the camcorder, so go ahead and launch the
// camcorder directly.
startActivity(createCamcorderIntent());
return;
} else {
// Specified just 'video/*', capture=filesystem or an invalid capture parameter.
// In all these cases we show an intent for the traditional file picker, filtered
// on accept type so launch an intent for both camcorder and video/* OPENABLE.
Intent chooser = createChooserIntent(createCamcorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(videoMimeType));
startActivity(chooser);
return;
}
} else if (mimeType.equals(audioMimeType)) {
if (mediaSource.equals(mediaSourceValueMicrophone)) {
// Specified 'audio/*' and requested microphone, so go ahead and launch the sound
// recorder.
startActivity(createSoundRecorderIntent());
return;
} else {
// Specified just 'audio/*', capture=filesystem of an invalid capture parameter.
// In all these cases so go ahead and launch an intent for both the sound
// recorder and audio/* OPENABLE.
Intent chooser = createChooserIntent(createSoundRecorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(audioMimeType));
startActivity(chooser);
return;
}
}
// No special handling based on the accept type was necessary, so trigger the default
// file upload chooser.
startActivity(createDefaultOpenableIntent());
}
private void startActivity(Intent intent) {
try {
mController.getActivity().startActivityForResult(intent, Controller.FILE_SELECTED);
} catch (ActivityNotFoundException e) {
// No installed app was able to handle the intent that
// we sent, so fallback to the default file upload control.
try {
mCaughtActivityNotFoundException = true;
mController.getActivity().startActivityForResult(createDefaultOpenableIntent(),
Controller.FILE_SELECTED);
} catch (ActivityNotFoundException e2) {
// Nothing can return us a file, so file upload is effectively disabled.
Toast.makeText(mController.getActivity(), R.string.uploads_disabled,
Toast.LENGTH_LONG).show();
}
}
}
private Intent createDefaultOpenableIntent() {
// Create and return a chooser with the default OPENABLE
// actions including the camera, camcorder and sound
// recorder where available.
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
Intent chooser = createChooserIntent(createCameraIntent(), createCamcorderIntent(),
createSoundRecorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, i);
return chooser;
}
private Intent createChooserIntent(Intent... intents) {
Intent chooser = new Intent(Intent.ACTION_CHOOSER);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents);
chooser.putExtra(Intent.EXTRA_TITLE,
mController.getActivity().getResources()
.getString(R.string.choose_upload));
return chooser;
}
private Intent createOpenableIntent(String type) {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType(type);
return i;
}
private Intent createCameraIntent() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File externalDataDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM);
File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
File.separator + "browser-photos");
cameraDataDir.mkdirs();
mCameraFilePath = cameraDataDir.getAbsolutePath() + File.separator +
System.currentTimeMillis() + ".jpg";
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCameraFilePath)));
return cameraIntent;
}
private Intent createCamcorderIntent() {
return new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
}
private Intent createSoundRecorderIntent() {
return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
}
}
#Override
public void onBackPressed()
{
WebView webView = (WebView) findViewById(R.id.webview);
if(webView.canGoBack()){
webView.goBack();
}else{
super.onBackPressed();
}
}
}
here is a full solution for all android versions,
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.webkit.JsResult;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebSettings.PluginState;
import android.widget.Toast;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView webView = (WebView) findViewById(R.id.webView1);
initWebView(webView);
webView.loadUrl("http://google.com"); // TODO input your url
}
private final static Object methodInvoke(Object obj, String method, Class<?>[] parameterTypes, Object[] args) {
try {
Method m = obj.getClass().getMethod(method, new Class[] { boolean.class });
m.invoke(obj, args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void initWebView(WebView webView) {
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setAllowFileAccess(true);
settings.setDomStorageEnabled(true);
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
settings.setLoadWithOverviewMode(true);
settings.setUseWideViewPort(true);
settings.setSupportZoom(true);
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setPluginState(PluginState.ON);
methodInvoke(settings, "setPluginState", new Class[] { PluginState.class }, new Object[] { PluginState.ON });
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowUniversalAccessFromFileURLs(true);
methodInvoke(settings, "setAllowUniversalAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowFileAccessFromFileURLs(true);
methodInvoke(settings, "setAllowFileAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webView.clearHistory();
webView.clearFormData();
webView.clearCache(true);
webView.setWebChromeClient(new MyWebChromeClient());
// webView.setDownloadListener(downloadListener);
}
UploadHandler mUploadHandler;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == Controller.FILE_SELECTED) {
// Chose a file from the file picker.
if (mUploadHandler != null) {
mUploadHandler.onResult(resultCode, intent);
}
}
super.onActivityResult(requestCode, resultCode, intent);
}
class MyWebChromeClient extends WebChromeClient {
public MyWebChromeClient() {
}
private String getTitleFromUrl(String url) {
String title = url;
try {
URL urlObj = new URL(url);
String host = urlObj.getHost();
if (host != null && !host.isEmpty()) {
return urlObj.getProtocol() + "://" + host;
}
if (url.startsWith("file:")) {
String fileName = urlObj.getFile();
if (fileName != null && !fileName.isEmpty()) {
return fileName;
}
}
} catch (Exception e) {
// ignore
}
return title;
}
#Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
String newTitle = getTitleFromUrl(url);
new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setCancelable(false).create().show();
return true;
// return super.onJsAlert(view, url, message, result);
}
#Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
String newTitle = getTitleFromUrl(url);
new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
}).setCancelable(false).create().show();
return true;
// return super.onJsConfirm(view, url, message, result);
}
// Android 2.x
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
openFileChooser(uploadMsg, "");
}
// Android 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
openFileChooser(uploadMsg, "", "filesystem");
}
// Android 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUploadHandler = new UploadHandler(new Controller());
mUploadHandler.openFileChooser(uploadMsg, acceptType, capture);
}
};
class Controller {
final static int FILE_SELECTED = 4;
Activity getActivity() {
return MainActivity.this;
}
}
// copied from android-4.4.3_r1/src/com/android/browser/UploadHandler.java
//////////////////////////////////////////////////////////////////////
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// package com.android.browser;
//
// import android.app.Activity;
// import android.content.ActivityNotFoundException;
// import android.content.Intent;
// import android.net.Uri;
// import android.os.Environment;
// import android.provider.MediaStore;
// import android.webkit.ValueCallback;
// import android.widget.Toast;
//
// import java.io.File;
// import java.util.Vector;
//
// /**
// * Handle the file upload callbacks from WebView here
// */
// public class UploadHandler {
class UploadHandler {
/*
* The Object used to inform the WebView of the file to upload.
*/
private ValueCallback<Uri> mUploadMessage;
private String mCameraFilePath;
private boolean mHandled;
private boolean mCaughtActivityNotFoundException;
private Controller mController;
public UploadHandler(Controller controller) {
mController = controller;
}
String getFilePath() {
return mCameraFilePath;
}
boolean handled() {
return mHandled;
}
void onResult(int resultCode, Intent intent) {
if (resultCode == Activity.RESULT_CANCELED && mCaughtActivityNotFoundException) {
// Couldn't resolve an activity, we are going to try again so skip
// this result.
mCaughtActivityNotFoundException = false;
return;
}
Uri result = intent == null || resultCode != Activity.RESULT_OK ? null
: intent.getData();
// As we ask the camera to save the result of the user taking
// a picture, the camera application does not return anything other
// than RESULT_OK. So we need to check whether the file we expected
// was written to disk in the in the case that we
// did not get an intent returned but did get a RESULT_OK. If it was,
// we assume that this result has came back from the camera.
if (result == null && intent == null && resultCode == Activity.RESULT_OK) {
File cameraFile = new File(mCameraFilePath);
if (cameraFile.exists()) {
result = Uri.fromFile(cameraFile);
// Broadcast to the media scanner that we have a new photo
// so it will be added into the gallery for the user.
mController.getActivity().sendBroadcast(
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result));
}
}
mUploadMessage.onReceiveValue(result);
mHandled = true;
mCaughtActivityNotFoundException = false;
}
void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
final String imageMimeType = "image/*";
final String videoMimeType = "video/*";
final String audioMimeType = "audio/*";
final String mediaSourceKey = "capture";
final String mediaSourceValueCamera = "camera";
final String mediaSourceValueFileSystem = "filesystem";
final String mediaSourceValueCamcorder = "camcorder";
final String mediaSourceValueMicrophone = "microphone";
// According to the spec, media source can be 'filesystem' or 'camera' or 'camcorder'
// or 'microphone' and the default value should be 'filesystem'.
String mediaSource = mediaSourceValueFileSystem;
if (mUploadMessage != null) {
// Already a file picker operation in progress.
return;
}
mUploadMessage = uploadMsg;
// Parse the accept type.
String params[] = acceptType.split(";");
String mimeType = params[0];
if (capture.length() > 0) {
mediaSource = capture;
}
if (capture.equals(mediaSourceValueFileSystem)) {
// To maintain backwards compatibility with the previous implementation
// of the media capture API, if the value of the 'capture' attribute is
// "filesystem", we should examine the accept-type for a MIME type that
// may specify a different capture value.
for (String p : params) {
String[] keyValue = p.split("=");
if (keyValue.length == 2) {
// Process key=value parameters.
if (mediaSourceKey.equals(keyValue[0])) {
mediaSource = keyValue[1];
}
}
}
}
//Ensure it is not still set from a previous upload.
mCameraFilePath = null;
if (mimeType.equals(imageMimeType)) {
if (mediaSource.equals(mediaSourceValueCamera)) {
// Specified 'image/*' and requested the camera, so go ahead and launch the
// camera directly.
startActivity(createCameraIntent());
return;
} else {
// Specified just 'image/*', capture=filesystem, or an invalid capture parameter.
// In all these cases we show a traditional picker filetered on accept type
// so launch an intent for both the Camera and image/* OPENABLE.
Intent chooser = createChooserIntent(createCameraIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(imageMimeType));
startActivity(chooser);
return;
}
} else if (mimeType.equals(videoMimeType)) {
if (mediaSource.equals(mediaSourceValueCamcorder)) {
// Specified 'video/*' and requested the camcorder, so go ahead and launch the
// camcorder directly.
startActivity(createCamcorderIntent());
return;
} else {
// Specified just 'video/*', capture=filesystem or an invalid capture parameter.
// In all these cases we show an intent for the traditional file picker, filtered
// on accept type so launch an intent for both camcorder and video/* OPENABLE.
Intent chooser = createChooserIntent(createCamcorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(videoMimeType));
startActivity(chooser);
return;
}
} else if (mimeType.equals(audioMimeType)) {
if (mediaSource.equals(mediaSourceValueMicrophone)) {
// Specified 'audio/*' and requested microphone, so go ahead and launch the sound
// recorder.
startActivity(createSoundRecorderIntent());
return;
} else {
// Specified just 'audio/*', capture=filesystem of an invalid capture parameter.
// In all these cases so go ahead and launch an intent for both the sound
// recorder and audio/* OPENABLE.
Intent chooser = createChooserIntent(createSoundRecorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(audioMimeType));
startActivity(chooser);
return;
}
}
// No special handling based on the accept type was necessary, so trigger the default
// file upload chooser.
startActivity(createDefaultOpenableIntent());
}
private void startActivity(Intent intent) {
try {
mController.getActivity().startActivityForResult(intent, Controller.FILE_SELECTED);
} catch (ActivityNotFoundException e) {
// No installed app was able to handle the intent that
// we sent, so fallback to the default file upload control.
try {
mCaughtActivityNotFoundException = true;
mController.getActivity().startActivityForResult(createDefaultOpenableIntent(),
Controller.FILE_SELECTED);
} catch (ActivityNotFoundException e2) {
// Nothing can return us a file, so file upload is effectively disabled.
Toast.makeText(mController.getActivity(), R.string.uploads_disabled,
Toast.LENGTH_LONG).show();
}
}
}
private Intent createDefaultOpenableIntent() {
// Create and return a chooser with the default OPENABLE
// actions including the camera, camcorder and sound
// recorder where available.
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
Intent chooser = createChooserIntent(createCameraIntent(), createCamcorderIntent(),
createSoundRecorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, i);
return chooser;
}
private Intent createChooserIntent(Intent... intents) {
Intent chooser = new Intent(Intent.ACTION_CHOOSER);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents);
chooser.putExtra(Intent.EXTRA_TITLE,
mController.getActivity().getResources()
.getString(R.string.choose_upload));
return chooser;
}
private Intent createOpenableIntent(String type) {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType(type);
return i;
}
private Intent createCameraIntent() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File externalDataDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM);
File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
File.separator + "browser-photos");
cameraDataDir.mkdirs();
mCameraFilePath = cameraDataDir.getAbsolutePath() + File.separator +
System.currentTimeMillis() + ".jpg";
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCameraFilePath)));
return cameraIntent;
}
private Intent createCamcorderIntent() {
return new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
}
private Intent createSoundRecorderIntent() {
return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
}
}
}
For 4.4.2 Use this. This is a demo application link. download and import in your workspace.
http://applusform.com/down/AgateWebViewFileUpload_AndroidEclipse.zip

android webview file upload not working [duplicate]

I have been struggling to upload files from WebView. I googled and implemented all suggested solutions (e.g. this SO post), but none work.
I have an HTML page with the following code to upload a file.
<form method="POST" enctype="multipart/form-data">
File to upload: <input type="file" name="uploadfile">
<input type="submit" value="Press to Upload..."> to upload the file!
</form>
It works fine in a desktop browser like Firefox and built-in browser
of emulator / AVD i.e., when I click "Browse..." button rendered by
element, browser opens a Dialog
box where I can choose a file to upload.
However, in the android 3.0 emulator / AVD, when I click on "Choose
file", nothing happens, no file dialog is opened!
This is a full solution for all android versions, I had a hard time with this too.
public class MyWb extends Activity {
/** Called when the activity is first created. */
WebView web;
ProgressBar progressBar;
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;
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
web = (WebView) findViewById(R.id.webview01);
progressBar = (ProgressBar) findViewById(R.id.progressBar1);
web = new WebView(this);
web.getSettings().setJavaScriptEnabled(true);
web.loadUrl("http://www.script-tutorials.com/demos/199/index.html");
web.setWebViewClient(new myWebClient());
web.setWebChromeClient(new WebChromeClient()
{
//The undocumented magic method override
//Eclipse will swear at you if you try to put #Override here
// For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
MyWb.this.startActivityForResult(Intent.createChooser(i,"File Chooser"), FILECHOOSER_RESULTCODE);
}
// For Android 3.0+
public void openFileChooser( ValueCallback uploadMsg, String acceptType ) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
MyWb.this.startActivityForResult(
Intent.createChooser(i, "File Browser"),
FILECHOOSER_RESULTCODE);
}
//For Android 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
MyWb.this.startActivityForResult( Intent.createChooser( i, "File Chooser" ), MyWb.FILECHOOSER_RESULTCODE );
}
});
setContentView(web);
}
public class myWebClient extends WebViewClient
{
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO Auto-generated method stub
super.onPageStarted(view, url, favicon);
}
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// TODO Auto-generated method stub
view.loadUrl(url);
return true;
}
#Override
public void onPageFinished(WebView view, String url) {
// TODO Auto-generated method stub
super.onPageFinished(view, url);
progressBar.setVisibility(View.GONE);
}
}
//flipscreen not loading again
#Override
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
}
// To handle "Back" key press event for WebView to go back to previous screen.
/*#Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if ((keyCode == KeyEvent.KEYCODE_BACK) && web.canGoBack()) {
web.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}*/
}
Also I want to add that the "upload page" like the one in this example, wont work on < 4 versions, since it has an image preview feature, if you want to make it work use a simple php upload without preview.
Update:
Please find the solution for lollipop devices here and thanks for gauntface
Update 2:
Complete solution for all android devices till oreo here and this is more advanced version, you should look into it, maybe it can help.
Working Method from HONEYCOMB (API 11) to Android 11
As updated by swati vishnoi, this works on Pie and above too
static WebView mWebView;
private ValueCallback<Uri> mUploadMessage;
public ValueCallback<Uri[]> uploadMessage;
public static final int REQUEST_SELECT_FILE = 100;
private final static int FILECHOOSER_RESULTCODE = 1;
Modified onActivityResult()
#Override
public void onActivityResult(int requestCode, int resultCode, Intent intent)
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
if (requestCode == REQUEST_SELECT_FILE)
{
if (uploadMessage == null)
return;
uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
uploadMessage = null;
}
}
else if (requestCode == FILECHOOSER_RESULTCODE)
{
if (null == mUploadMessage)
return;
// Use MainActivity.RESULT_OK if you're implementing WebView inside Fragment
// Use RESULT_OK only if you're implementing WebView inside an Activity
Uri result = intent == null || resultCode != MainActivity.RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
else
Toast.makeText(getActivity().getApplicationContext(), "Failed to Upload Image", Toast.LENGTH_LONG).show();
}
Now in onCreate() or onCreateView() paste the following code
WebSettings mWebSettings = mWebView.getSettings();
mWebSettings.setJavaScriptEnabled(true);
mWebSettings.setSupportZoom(false);
mWebSettings.setAllowFileAccess(true);
mWebSettings.setAllowContentAccess(true);
mWebView.setWebChromeClient(new WebChromeClient()
{
// For 3.0+ Devices (Start)
// onActivityResult attached before constructor
protected void openFileChooser(ValueCallback uploadMsg, String acceptType)
{
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE);
}
// For Lollipop 5.0+ Devices
public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams)
{
if (uploadMessage != null) {
uploadMessage.onReceiveValue(null);
uploadMessage = null;
}
uploadMessage = filePathCallback;
Intent intent = fileChooserParams.createIntent();
try
{
startActivityForResult(intent, REQUEST_SELECT_FILE);
} catch (ActivityNotFoundException e)
{
uploadMessage = null;
Toast.makeText(getActivity().getApplicationContext(), "Cannot Open File Chooser", Toast.LENGTH_LONG).show();
return false;
}
return true;
}
//For Android 4.1 only
protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)
{
mUploadMessage = uploadMsg;
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("image/*");
startActivityForResult(Intent.createChooser(intent, "File Browser"), FILECHOOSER_RESULTCODE);
}
protected void openFileChooser(ValueCallback<Uri> uploadMsg)
{
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
}
});
this is the only solution that i found that works!
WebView 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;
}
}
// Next part
class MyWebChromeClient extends WebChromeClient {
// The undocumented magic method override
// Eclipse will swear at you if you try to put #Override here
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
Cv5appActivity.this.startActivityForResult(
Intent.createChooser(i, "Image Browser"),
FILECHOOSER_RESULTCODE);
}
}
In 5.0 Lollipop, Google added an official method, WebChromeClient.onShowFileChooser. They even provide a way to automatically generate the file chooser intent so that it uses the input accept mime types.
public class MyWebChromeClient extends WebChromeClient {
// reference to activity instance. May be unnecessary if your web chrome client is member class.
private MyActivity activity;
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
// make sure there is no existing message
if (myActivity.uploadMessage != null) {
myActivity.uploadMessage.onReceiveValue(null);
myActivity.uploadMessage = null;
}
myActivity.uploadMessage = filePathCallback;
Intent intent = fileChooserParams.createIntent();
try {
myActivity.startActivityForResult(intent, MyActivity.REQUEST_SELECT_FILE);
} catch (ActivityNotFoundException e) {
myActivity.uploadMessage = null;
Toast.makeText(myActivity, "Cannot open file chooser", Toast.LENGTH_LONG).show();
return false;
}
return true;
}
}
public class MyActivity extends ... {
public static final int REQUEST_SELECT_FILE = 100;
public ValueCallback<Uri[]> uploadMessage;
protected void onActivityResult(int requestCode, int resultCode, Intent data){
if (requestCode == REQUEST_SELECT_FILE) {
if (uploadMessage == null) return;
uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
uploadMessage = null;
}
}
}
}
For Android versions before KitKat, the private methods mentioned in the other answers work. I have not found a good workaround for KitKat (4.4).
I found that I needed 3 interface definitions in order to handle various version of android.
public void openFileChooser(ValueCallback < Uri > uploadMsg) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
FreeHealthTrack.this.startActivityForResult(Intent.createChooser(i, "Image Chooser"), FILECHOOSER_RESULTCODE);
}
public void openFileChooser(ValueCallback < Uri > uploadMsg, String acceptType) {
openFileChooser(uploadMsg);
}
public void openFileChooser(ValueCallback < Uri > uploadMsg, String acceptType, String capture) {
openFileChooser(uploadMsg);
}
This solution also works for Honeycomb and Ice Cream Sandwich. Seems like Google introduced a cool new feature (accept attribute) and forgot to to implement an overload for backwards compatibility.
protected class CustomWebChromeClient extends WebChromeClient
{
// For Android 3.0+
public void openFileChooser( ValueCallback<Uri> uploadMsg, String acceptType )
{
context.mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
context.startActivityForResult( Intent.createChooser( i, "File Chooser" ), MainActivity.FILECHOOSER_RESULTCODE );
}
// For Android < 3.0
public void openFileChooser( ValueCallback<Uri> uploadMsg )
{
openFileChooser( uploadMsg, "" );
}
}
hifarrer's full solution is very helpful to me.
but, I met many other problems - supporting other mime type, listing capture devices(camera, video, audio recoder), opening capture device immediately(ex: <input accept="image/*;capture"> )...
So, I made a solution that works exactly same as default web browser app.
I used android-4.4.3_r1/src/com/android/browser/UploadHandler.java. (thanks to Rupert Rawnsley )
package org.mospi.agatenativewebview;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.webkit.JsResult;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebSettings.PluginState;
import android.widget.Toast;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView webView = (WebView) findViewById(R.id.webView1);
initWebView(webView);
webView.loadUrl("http://google.com"); // TODO input your url
}
private final static Object methodInvoke(Object obj, String method, Class<?>[] parameterTypes, Object[] args) {
try {
Method m = obj.getClass().getMethod(method, new Class[] { boolean.class });
m.invoke(obj, args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void initWebView(WebView webView) {
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setAllowFileAccess(true);
settings.setDomStorageEnabled(true);
settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
settings.setLoadWithOverviewMode(true);
settings.setUseWideViewPort(true);
settings.setSupportZoom(true);
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setPluginState(PluginState.ON);
methodInvoke(settings, "setPluginState", new Class[] { PluginState.class }, new Object[] { PluginState.ON });
// settings.setPluginsEnabled(true);
methodInvoke(settings, "setPluginsEnabled", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowUniversalAccessFromFileURLs(true);
methodInvoke(settings, "setAllowUniversalAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
// settings.setAllowFileAccessFromFileURLs(true);
methodInvoke(settings, "setAllowFileAccessFromFileURLs", new Class[] { boolean.class }, new Object[] { true });
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webView.clearHistory();
webView.clearFormData();
webView.clearCache(true);
webView.setWebChromeClient(new MyWebChromeClient());
// webView.setDownloadListener(downloadListener);
}
UploadHandler mUploadHandler;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == Controller.FILE_SELECTED) {
// Chose a file from the file picker.
if (mUploadHandler != null) {
mUploadHandler.onResult(resultCode, intent);
}
}
super.onActivityResult(requestCode, resultCode, intent);
}
class MyWebChromeClient extends WebChromeClient {
public MyWebChromeClient() {
}
private String getTitleFromUrl(String url) {
String title = url;
try {
URL urlObj = new URL(url);
String host = urlObj.getHost();
if (host != null && !host.isEmpty()) {
return urlObj.getProtocol() + "://" + host;
}
if (url.startsWith("file:")) {
String fileName = urlObj.getFile();
if (fileName != null && !fileName.isEmpty()) {
return fileName;
}
}
} catch (Exception e) {
// ignore
}
return title;
}
#Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
String newTitle = getTitleFromUrl(url);
new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setCancelable(false).create().show();
return true;
// return super.onJsAlert(view, url, message, result);
}
#Override
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
String newTitle = getTitleFromUrl(url);
new AlertDialog.Builder(MainActivity.this).setTitle(newTitle).setMessage(message).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
}).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
}).setCancelable(false).create().show();
return true;
// return super.onJsConfirm(view, url, message, result);
}
// Android 2.x
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
openFileChooser(uploadMsg, "");
}
// Android 3.0
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
openFileChooser(uploadMsg, "", "filesystem");
}
// Android 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUploadHandler = new UploadHandler(new Controller());
mUploadHandler.openFileChooser(uploadMsg, acceptType, capture);
}
// Android 4.4, 4.4.1, 4.4.2
// openFileChooser function is not called on Android 4.4, 4.4.1, 4.4.2,
// you may use your own java script interface or other hybrid framework.
// Android 5.0.1
public boolean onShowFileChooser(
WebView webView, ValueCallback<Uri[]> filePathCallback,
FileChooserParams fileChooserParams) {
String acceptTypes[] = fileChooserParams.getAcceptTypes();
String acceptType = "";
for (int i = 0; i < acceptTypes.length; ++ i) {
if (acceptTypes[i] != null && acceptTypes[i].length() != 0)
acceptType += acceptTypes[i] + ";";
}
if (acceptType.length() == 0)
acceptType = "*/*";
final ValueCallback<Uri[]> finalFilePathCallback = filePathCallback;
ValueCallback<Uri> vc = new ValueCallback<Uri>() {
#Override
public void onReceiveValue(Uri value) {
Uri[] result;
if (value != null)
result = new Uri[]{value};
else
result = null;
finalFilePathCallback.onReceiveValue(result);
}
};
openFileChooser(vc, acceptType, "filesystem");
return true;
}
};
class Controller {
final static int FILE_SELECTED = 4;
Activity getActivity() {
return MainActivity.this;
}
}
// copied from android-4.4.3_r1/src/com/android/browser/UploadHandler.java
//////////////////////////////////////////////////////////////////////
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// package com.android.browser;
//
// import android.app.Activity;
// import android.content.ActivityNotFoundException;
// import android.content.Intent;
// import android.net.Uri;
// import android.os.Environment;
// import android.provider.MediaStore;
// import android.webkit.ValueCallback;
// import android.widget.Toast;
//
// import java.io.File;
// import java.util.Vector;
//
// /**
// * Handle the file upload callbacks from WebView here
// */
// public class UploadHandler {
class UploadHandler {
/*
* The Object used to inform the WebView of the file to upload.
*/
private ValueCallback<Uri> mUploadMessage;
private String mCameraFilePath;
private boolean mHandled;
private boolean mCaughtActivityNotFoundException;
private Controller mController;
public UploadHandler(Controller controller) {
mController = controller;
}
String getFilePath() {
return mCameraFilePath;
}
boolean handled() {
return mHandled;
}
void onResult(int resultCode, Intent intent) {
if (resultCode == Activity.RESULT_CANCELED && mCaughtActivityNotFoundException) {
// Couldn't resolve an activity, we are going to try again so skip
// this result.
mCaughtActivityNotFoundException = false;
return;
}
Uri result = intent == null || resultCode != Activity.RESULT_OK ? null
: intent.getData();
// As we ask the camera to save the result of the user taking
// a picture, the camera application does not return anything other
// than RESULT_OK. So we need to check whether the file we expected
// was written to disk in the in the case that we
// did not get an intent returned but did get a RESULT_OK. If it was,
// we assume that this result has came back from the camera.
if (result == null && intent == null && resultCode == Activity.RESULT_OK) {
File cameraFile = new File(mCameraFilePath);
if (cameraFile.exists()) {
result = Uri.fromFile(cameraFile);
// Broadcast to the media scanner that we have a new photo
// so it will be added into the gallery for the user.
mController.getActivity().sendBroadcast(
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result));
}
}
mUploadMessage.onReceiveValue(result);
mHandled = true;
mCaughtActivityNotFoundException = false;
}
void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
final String imageMimeType = "image/*";
final String videoMimeType = "video/*";
final String audioMimeType = "audio/*";
final String mediaSourceKey = "capture";
final String mediaSourceValueCamera = "camera";
final String mediaSourceValueFileSystem = "filesystem";
final String mediaSourceValueCamcorder = "camcorder";
final String mediaSourceValueMicrophone = "microphone";
// According to the spec, media source can be 'filesystem' or 'camera' or 'camcorder'
// or 'microphone' and the default value should be 'filesystem'.
String mediaSource = mediaSourceValueFileSystem;
if (mUploadMessage != null) {
// Already a file picker operation in progress.
return;
}
mUploadMessage = uploadMsg;
// Parse the accept type.
String params[] = acceptType.split(";");
String mimeType = params[0];
if (capture.length() > 0) {
mediaSource = capture;
}
if (capture.equals(mediaSourceValueFileSystem)) {
// To maintain backwards compatibility with the previous implementation
// of the media capture API, if the value of the 'capture' attribute is
// "filesystem", we should examine the accept-type for a MIME type that
// may specify a different capture value.
for (String p : params) {
String[] keyValue = p.split("=");
if (keyValue.length == 2) {
// Process key=value parameters.
if (mediaSourceKey.equals(keyValue[0])) {
mediaSource = keyValue[1];
}
}
}
}
//Ensure it is not still set from a previous upload.
mCameraFilePath = null;
if (mimeType.equals(imageMimeType)) {
if (mediaSource.equals(mediaSourceValueCamera)) {
// Specified 'image/*' and requested the camera, so go ahead and launch the
// camera directly.
startActivity(createCameraIntent());
return;
} else {
// Specified just 'image/*', capture=filesystem, or an invalid capture parameter.
// In all these cases we show a traditional picker filetered on accept type
// so launch an intent for both the Camera and image/* OPENABLE.
Intent chooser = createChooserIntent(createCameraIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(imageMimeType));
startActivity(chooser);
return;
}
} else if (mimeType.equals(videoMimeType)) {
if (mediaSource.equals(mediaSourceValueCamcorder)) {
// Specified 'video/*' and requested the camcorder, so go ahead and launch the
// camcorder directly.
startActivity(createCamcorderIntent());
return;
} else {
// Specified just 'video/*', capture=filesystem or an invalid capture parameter.
// In all these cases we show an intent for the traditional file picker, filtered
// on accept type so launch an intent for both camcorder and video/* OPENABLE.
Intent chooser = createChooserIntent(createCamcorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(videoMimeType));
startActivity(chooser);
return;
}
} else if (mimeType.equals(audioMimeType)) {
if (mediaSource.equals(mediaSourceValueMicrophone)) {
// Specified 'audio/*' and requested microphone, so go ahead and launch the sound
// recorder.
startActivity(createSoundRecorderIntent());
return;
} else {
// Specified just 'audio/*', capture=filesystem of an invalid capture parameter.
// In all these cases so go ahead and launch an intent for both the sound
// recorder and audio/* OPENABLE.
Intent chooser = createChooserIntent(createSoundRecorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, createOpenableIntent(audioMimeType));
startActivity(chooser);
return;
}
}
// No special handling based on the accept type was necessary, so trigger the default
// file upload chooser.
startActivity(createDefaultOpenableIntent());
}
private void startActivity(Intent intent) {
try {
mController.getActivity().startActivityForResult(intent, Controller.FILE_SELECTED);
} catch (ActivityNotFoundException e) {
// No installed app was able to handle the intent that
// we sent, so fallback to the default file upload control.
try {
mCaughtActivityNotFoundException = true;
mController.getActivity().startActivityForResult(createDefaultOpenableIntent(),
Controller.FILE_SELECTED);
} catch (ActivityNotFoundException e2) {
// Nothing can return us a file, so file upload is effectively disabled.
Toast.makeText(mController.getActivity(), R.string.uploads_disabled,
Toast.LENGTH_LONG).show();
}
}
}
private Intent createDefaultOpenableIntent() {
// Create and return a chooser with the default OPENABLE
// actions including the camera, camcorder and sound
// recorder where available.
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
Intent chooser = createChooserIntent(createCameraIntent(), createCamcorderIntent(),
createSoundRecorderIntent());
chooser.putExtra(Intent.EXTRA_INTENT, i);
return chooser;
}
private Intent createChooserIntent(Intent... intents) {
Intent chooser = new Intent(Intent.ACTION_CHOOSER);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents);
chooser.putExtra(Intent.EXTRA_TITLE,
mController.getActivity().getResources()
.getString(R.string.choose_upload));
return chooser;
}
private Intent createOpenableIntent(String type) {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType(type);
return i;
}
private Intent createCameraIntent() {
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File externalDataDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM);
File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
File.separator + "browser-photos");
cameraDataDir.mkdirs();
mCameraFilePath = cameraDataDir.getAbsolutePath() + File.separator +
System.currentTimeMillis() + ".jpg";
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCameraFilePath)));
return cameraIntent;
}
private Intent createCamcorderIntent() {
return new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
}
private Intent createSoundRecorderIntent() {
return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
}
}
}
additional string resoruce of res/values/string.xml :
<string name="uploads_disabled">File uploads are disabled.</string>
<string name="choose_upload">Choose file for upload</string>
If you are using proguard, you may need below option in proguard-project.txt :
-keepclassmembers class * extends android.webkit.WebChromeClient {
public void openFileChooser(...);
}
UPDATE #1 (2015.09.09)
adds code for Android 5.0.1 compatability.
Kotlin solution for Android 8:
private var mUploadMessage: ValueCallback<Uri>? = null
private var uploadMessage: ValueCallback<Array<Uri>>? = null
Constants:
const val FILECHOOSER_RESULTCODE = 1
const val REQUEST_SELECT_FILE = 100
WebView setup:
webView.webChromeClient = object : WebChromeClient() {
override fun onPermissionRequest(request: PermissionRequest?) {
Log.d("MainActivity", "onPermissionRequest")
requestPermission(request)
}
// For Android 3.0+
fun openFileChooser(uploadMsg: ValueCallback<*>, acceptType: String) {
mUploadMessage = uploadMsg as ValueCallback<Uri>
val i = Intent(Intent.ACTION_GET_CONTENT)
i.addCategory(Intent.CATEGORY_OPENABLE)
i.type = "*/*"
this#MainActivity.startActivityForResult(
Intent.createChooser(i, "File Browser"),
FILECHOOSER_RESULTCODE)
}
//For Android 4.1
fun openFileChooser(uploadMsg: ValueCallback<Uri>, acceptType: String, capture: String) {
mUploadMessage = uploadMsg
val i = Intent(Intent.ACTION_GET_CONTENT)
i.addCategory(Intent.CATEGORY_OPENABLE)
i.type = "image/*"
this#MainActivity.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE)
}
protected fun openFileChooser(uploadMsg: ValueCallback<Uri>) {
mUploadMessage = uploadMsg
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "*/*"
startActivityForResult(Intent.createChooser(intent, "File Chooser"), FILECHOOSER_RESULTCODE)
}
override fun onShowFileChooser(webView: WebView?, filePathCallback: ValueCallback<Array<Uri>>?, fileChooserParams: FileChooserParams?): Boolean {
uploadMessage?.onReceiveValue(null)
uploadMessage = null
uploadMessage = filePathCallback
val intent = fileChooserParams!!.createIntent()
try {
startActivityForResult(intent, REQUEST_SELECT_FILE)
} catch (e: ActivityNotFoundException) {
uploadMessage = null
Toast.makeText(applicationContext, "Cannot Open File Chooser", Toast.LENGTH_LONG).show()
return false
}
return true
}
}
And the onAcrtivityResult part:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (requestCode === REQUEST_SELECT_FILE) {
if (uploadMessage == null)
return
print("result code = " + resultCode)
var results: Array<Uri>? = WebChromeClient.FileChooserParams.parseResult(resultCode, data)
uploadMessage?.onReceiveValue(results)
uploadMessage = null
}
} else if (requestCode === FILECHOOSER_RESULTCODE) {
if (null == mUploadMessage)
return
// Use MainActivity.RESULT_OK if you're implementing WebView inside Fragment
// Use RESULT_OK only if you're implementing WebView inside an Activity
val result = if (intent == null || resultCode !== RESULT_OK) null else intent.data
mUploadMessage?.onReceiveValue(result)
mUploadMessage = null
} else
Toast.makeText(applicationContext, "Failed to Upload Image", Toast.LENGTH_LONG).show()
}
Please, pay attention that our intent variable called "data".
This is work for me. Also work for Nougat and Marshmallow[[
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private final static int FCR = 1;
WebView webView;
private String mCM;
private ValueCallback<Uri> mUM;
private ValueCallback<Uri[]> mUMA;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (Build.VERSION.SDK_INT >= 21) {
Uri[] results = null;
//Check if response is positive
if (resultCode == Activity.RESULT_OK) {
if (requestCode == FCR) {
if (null == mUMA) {
return;
}
if (intent == null) {
//Capture Photo if no image available
if (mCM != null) {
results = new Uri[]{Uri.parse(mCM)};
}
} else {
String dataString = intent.getDataString();
if (dataString != null) {
results = new Uri[]{Uri.parse(dataString)};
}
}
}
}
mUMA.onReceiveValue(results);
mUMA = null;
} else {
if (requestCode == FCR) {
if (null == mUM) return;
Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
mUM.onReceiveValue(result);
mUM = null;
}
}
}
#SuppressLint({"SetJavaScriptEnabled", "WrongViewCast"})
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= 23 && (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, 1);
}
webView = (WebView) findViewById(R.id.ifView);
assert webView != null;
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setAllowFileAccess(true);
if (Build.VERSION.SDK_INT >= 21) {
webSettings.setMixedContentMode(0);
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else if (Build.VERSION.SDK_INT >= 19) {
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else if (Build.VERSION.SDK_INT < 19) {
webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
webView.setWebViewClient(new Callback());
webView.loadUrl("https://infeeds.com/");
webView.setWebChromeClient(new WebChromeClient() {
//For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUM = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), FCR);
}
// For Android 3.0+, above method not supported in some android 3+ versions, in such case we use this
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
mUM = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
MainActivity.this.startActivityForResult(
Intent.createChooser(i, "File Browser"),
FCR);
}
//For Android 4.1+
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUM = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), MainActivity.FCR);
}
//For Android 5.0+
public boolean onShowFileChooser(
WebView webView, ValueCallback<Uri[]> filePathCallback,
WebChromeClient.FileChooserParams fileChooserParams) {
if (mUMA != null) {
mUMA.onReceiveValue(null);
}
mUMA = filePathCallback;
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(MainActivity.this.getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = createImageFile();
takePictureIntent.putExtra("PhotoPath", mCM);
} catch (IOException ex) {
Log.e(TAG, "Image file creation failed", ex);
}
if (photoFile != null) {
mCM = "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("*/*");
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, FCR);
return true;
}
});
}
// Create an image file
private File createImageFile() throws IOException {
#SuppressLint("SimpleDateFormat") String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "img_" + timeStamp + "_";
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
return File.createTempFile(imageFileName, ".jpg", storageDir);
}
#Override
public boolean onKeyDown(int keyCode, #NonNull KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
if (webView.canGoBack()) {
webView.goBack();
} else {
finish();
}
return true;
}
}
return super.onKeyDown(keyCode, event);
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
public class Callback extends WebViewClient {
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Toast.makeText(getApplicationContext(), "Failed loading app!", Toast.LENGTH_SHORT).show();
}
}
}
I found it necessary to define public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture), in Android 4.1. Then I followed Michel Olivier's solution.
2019: This code worked for me (Tested on Androids 5 - 9).
package com.example.filechooser;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Bundle;
import android.webkit.SslErrorHandler;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class MainActivity extends Activity {
// variables para manejar la subida de archivos
private final static int FILECHOOSER_RESULTCODE = 1;
private ValueCallback<Uri[]> mUploadMessage;
// variable para manejar el navegador empotrado
WebView mainWebView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// instanciamos el webview
mainWebView = findViewById(R.id.main_web_view);
// establecemos el cliente interno para que la navegacion no se salga de la aplicacion
mainWebView.setWebViewClient(new MyWebViewClient());
// establecemos el cliente chrome para seleccionar archivos
mainWebView.setWebChromeClient(new MyWebChromeClient());
// configuracion del webview
mainWebView.getSettings().setJavaScriptEnabled(true);
// cargamos la pagina
mainWebView.loadUrl("https://example.com");
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
// manejo de seleccion de archivo
if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == mUploadMessage || intent == null || resultCode != RESULT_OK) {
return;
}
Uri[] result = null;
String dataString = intent.getDataString();
if (dataString != null) {
result = new Uri[]{ Uri.parse(dataString) };
}
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
}
// ====================
// Web clients classes
// ====================
/**
* Clase para configurar el webview
*/
private class MyWebViewClient extends WebViewClient {
// permite la navegacion dentro del webview
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
/**
* Clase para configurar el chrome client para que nos permita seleccionar archivos
*/
private class MyWebChromeClient extends WebChromeClient {
// maneja la accion de seleccionar archivos
#Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
// asegurar que no existan callbacks
if (mUploadMessage != null) {
mUploadMessage.onReceiveValue(null);
}
mUploadMessage = filePathCallback;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*"); // set MIME type to filter
MainActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), MainActivity.FILECHOOSER_RESULTCODE );
return true;
}
}
}
Hope can help you.
Ive actually managed to get the file picker to appear in Kitkat, to select a image and to get the filepath in activity result but the only thing that im not able to "fix" (cause this workaround) is to make the input filed to fill out with file data.
Does anyone know any way how to access the input-field from a activity ? Am using this example comment. Is just this last piece, the last brick in the wall that i just have to put into right place (tho i could trigger upload of image file directly from code.
UPDATE #1
Im no hardcore Android dev so i'll show code on newbie level. Im creating a new Activity in already existing Activity
Manifest part
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application android:label="TestApp">
<activity android:name=".BrowseActivity"></activity>
</application>
Am creating my BrowseActivity class from this example answer. The WebChromeClient() instance basically looks the same, except last piece, triggering the picker UI part...
private final static int FILECHOOSER_RESULTCODE=1;
private final static int KITKAT_RESULTCODE = 2;
...
// The new WebChromeClient() looks pretty much the same, except one piece...
WebChromeClient chromeClient = new WebChromeClient(){
// For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg) { /* Default code */ }
// For Android 3.0+
public void openFileChooser( ValueCallback uploadMsg, String acceptType ) { /* Default code */ }
//For Android 4.1, also default but it'll be as example
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
BrowseActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), BrowseActivity.FILECHOOSER_RESULTCODE);
}
// The new code
public void showPicker( ValueCallback<Uri> uploadMsg ){
// Here is part of the issue, the uploadMsg is null since it is not triggered from Android
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
BrowseActivity.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), BrowseActivity.KITKAT_RESULTCODE);
}}
And some more stuff
web = new WebView(this);
// Notice this part, setting chromeClient as js interface is just lazy
web.getSettings().setJavaScriptEnabled(true);
web.addJavascriptInterface(chromeClient, "jsi" );
web.getSettings().setAllowFileAccess(true);
web.getSettings().setAllowContentAccess(true);
web.clearCache(true);
web.loadUrl( "http://as3breeze.com/upload.html" );
web.setWebViewClient(new myWebClient());
web.setWebChromeClient(chromeClient);
#Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
Log.d("Result", "("+requestCode+ ") - (" +resultCode + ") - (" + intent + ") - " + mUploadMessage);
if (null == intent) return;
Uri result = null;
if(requestCode==FILECHOOSER_RESULTCODE)
{
Log.d("Result","Old android");
if (null == mUploadMessage) return;
result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
} else if (requestCode == KITKAT_RESULTCODE) {
Log.d("Result","Kitkat android");
result = intent.getData();
final int takeFlags = intent.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
String path = getPath( this, result);
File selectedFile = new File(path);
//I used you example with a bit of editing so thought i would share, here i added a method to upload the file to the webserver
File selectedFile = new File(path);
UploadFile(selectedFile);
//mUploadMessage.onReceiveValue( Uri.parse(selectedFile.toString()) );
// Now we have the file but since mUploadMessage was null, it gets errors
}
}
public void UploadFile(File selectedFile)
{
Random rnd = new Random();
String sName = "File" + rnd.nextInt(999999) + selectedFile.getAbsolutePath().substring(selectedFile.getAbsolutePath().lastIndexOf("."));
UploadedFileName = sName;
uploadFile = selectedFile;
if (progressBar != null && progressBar.isShowing())
{
progressBar.dismiss();
}
// prepare for a progress bar dialog
progressBar = new ProgressDialog(mContext);
progressBar.setCancelable(true);
progressBar.setMessage("Uploading File");
progressBar.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressBar.show();
new Thread() {
public void run()
{
int serverResponseCode;
String serverResponseMessage;
HttpURLConnection connection = null;
DataOutputStream outputStream = null;
DataInputStream inputStream = null;
String pathToOurFile = uploadFile.getAbsolutePath();
String urlServer = "http://serveraddress/Scripts/UploadHandler.php?name" + UploadedFileName;
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 1*1024*1024;
try
{
FileInputStream fileInputStream = new FileInputStream(uploadFile);
URL url = new URL(urlServer);
connection = (HttpURLConnection) url.openConnection();
Log.i("File", urlServer);
// Allow Inputs & Outputs.
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
// Set HTTP method to POST.
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
Log.i("File", "Open conn");
outputStream = new DataOutputStream( connection.getOutputStream() );
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + pathToOurFile +"\"" + lineEnd);
outputStream.writeBytes(lineEnd);
Log.i("File", "write bytes");
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
Log.i("File", "available: " + fileInputStream.available());
// Read file
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
Log.i("file", "Bytes Read: " + bytesRead);
while (bytesRead > 0)
{
outputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// Responses from the server (code and message)
serverResponseCode = connection.getResponseCode();
serverResponseMessage = connection.getResponseMessage();
Log.i("file repsonse", serverResponseMessage);
//once the file is uploaded call a javascript function to verify the user wants to save the image
progressBar.dismiss();
runOnUiThread(new Runnable()
{
#Override
public void run()
{
Log.i("start", "File name: " + UploadedFileName);
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("javascript:CheckImage('" + UploadedFileName + "')");
}
});
fileInputStream.close();
outputStream.flush();
outputStream.close();
}
catch (Exception ex)
{
Log.i("exception", "Error: " + ex.toString());
}
}
}.start();
}
Lastly, some more code to get the actual file path, code found on SO, ive added post url in comments as well so the author gets credits for his work.
/**
* Get a file path from a Uri. This will get the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.
*
* #param context The context.
* #param uri The Uri to query.
* #author paulburke
* #source https://stackoverflow.com/a/20559175
*/
#TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] {
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* #param context The context.
* #param uri The Uri to query.
* #param selection (Optional) Filter used in the query.
* #param selectionArgs (Optional) Selection arguments used in the query.
* #return The value of the _data column, which is typically a file path.
* #source https://stackoverflow.com/a/20559175
*/
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* #param uri The Uri to check.
* #return Whether the Uri authority is ExternalStorageProvider.
* #source https://stackoverflow.com/a/20559175
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* #param uri The Uri to check.
* #return Whether the Uri authority is DownloadsProvider.
* #source https://stackoverflow.com/a/20559175
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* #param uri The Uri to check.
* #return Whether the Uri authority is MediaProvider.
* #source https://stackoverflow.com/a/20559175
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
Lastly, the HTML page needs to trigger that new method of showPicker (specificaly when on A4.4)
<form id="form-upload" method="post" enctype="multipart/form-data">
<input id="fileupload" name="fileupload" type="file" onclick="javascript:prepareForPicker();"/>
</form>
<script type="text/javascript">
function getAndroidVersion() {
var ua = navigator.userAgent;
var match = ua.match(/Android\s([0-9\.]*)/);
return match ? match[1] : false;
};
function prepareForPicker(){
if(getAndroidVersion().indexOf("4.4") != -1){
window.jsi.showPicker();
return false;
}
}
function CheckImage(name)
{
//Check to see if user wants to save I used some ajax to save the file if necesarry
}
</script>
Google's own browser offers such a comprehensive solution to this problem that it warrants it's own class:
openFileChooser implementation in Android 4.0.4
UploadHandler class in Android 4.0.4
Found a SOLUTION which works for me! Add one more rule in the file proguard-android.txt:
-keepclassmembers class * extends android.webkit.WebChromeClient {
public void openFileChooser(...);
}
have you visited this links?
http://groups.google.com/group/android-developers/browse_thread/thread/dcaf8b2fdd8a90c4/62d5e2ffef31ebdb
http://moazzam-khan.com/blog/?tag=android-upload-file
http://evgenyg.wordpress.com/2010/05/01/uploading-files-multipart-post-apache/
Concise example of file upload via Java lib Apache Commons
i think you will get help from this
Webview - Single & Multiple files choose
you needs two minutes to implement this code:
build.gradle
implementation 'com.github.angads25:filepicker:1.1.1'
java code:
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.bivoiclient.utils.Constants;
import com.github.angads25.filepicker.controller.DialogSelectionListener;
import com.github.angads25.filepicker.model.DialogConfigs;
import com.github.angads25.filepicker.model.DialogProperties;
import com.github.angads25.filepicker.view.FilePickerDialog;
import java.io.File;
public class WebBrowserScreen extends Activity {
private WebView webView;
private ValueCallback<Uri[]> mUploadMessage;
private FilePickerDialog dialog;
private String LOG_TAG = "DREG";
private Uri[] results;
#SuppressLint("SetJavaScriptEnabled")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_complain);
webView = findViewById(R.id.webview);
WebSettings webSettings = webView.getSettings();
webSettings.setAppCacheEnabled(true);
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
webSettings.setJavaScriptEnabled(true);
webSettings.setLoadWithOverviewMode(true);
webSettings.setAllowFileAccess(true);
webView.setWebViewClient(new PQClient());
webView.setWebChromeClient(new PQChromeClient());
if (Build.VERSION.SDK_INT >= 19) {
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else {
webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
webView.loadUrl(Constants.COMPLAIN_URL);
}
private void openFileSelectionDialog() {
if (null != dialog && dialog.isShowing()) {
dialog.dismiss();
}
//Create a DialogProperties object.
final DialogProperties properties = new DialogProperties();
//Instantiate FilePickerDialog with Context and DialogProperties.
dialog = new FilePickerDialog(WebBrowserScreen.this, properties);
dialog.setTitle("Select a File");
dialog.setPositiveBtnName("Select");
dialog.setNegativeBtnName("Cancel");
properties.selection_mode = DialogConfigs.MULTI_MODE; // for multiple files
// properties.selection_mode = DialogConfigs.SINGLE_MODE; // for single file
properties.selection_type = DialogConfigs.FILE_SELECT;
//Method handle selected files.
dialog.setDialogSelectionListener(new DialogSelectionListener() {
#Override
public void onSelectedFilePaths(String[] files) {
results = new Uri[files.length];
for (int i = 0; i < files.length; i++) {
String filePath = new File(files[i]).getAbsolutePath();
if (!filePath.startsWith("file://")) {
filePath = "file://" + filePath;
}
results[i] = Uri.parse(filePath);
Log.d(LOG_TAG, "file path: " + filePath);
Log.d(LOG_TAG, "file uri: " + String.valueOf(results[i]));
}
mUploadMessage.onReceiveValue(results);
mUploadMessage = null;
}
});
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialogInterface) {
if (null != mUploadMessage) {
if (null != results && results.length >= 1) {
mUploadMessage.onReceiveValue(results);
} else {
mUploadMessage.onReceiveValue(null);
}
}
mUploadMessage = null;
}
});
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialogInterface) {
if (null != mUploadMessage) {
if (null != results && results.length >= 1) {
mUploadMessage.onReceiveValue(results);
} else {
mUploadMessage.onReceiveValue(null);
}
}
mUploadMessage = null;
}
});
dialog.show();
}
public class PQChromeClient extends WebChromeClient {
#Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
// Double check that we don't have any existing callbacks
if (mUploadMessage != null) {
mUploadMessage.onReceiveValue(null);
}
mUploadMessage = filePathCallback;
openFileSelectionDialog();
return true;
}
}
//Add this method to show Dialog when the required permission has been granted to the app.
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String permissions[], #NonNull int[] grantResults) {
switch (requestCode) {
case FilePickerDialog.EXTERNAL_READ_PERMISSION_GRANT: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (dialog != null) {
openFileSelectionDialog();
}
} else {
//Permission has not been granted. Notify the user.
Toast.makeText(WebBrowserScreen.this, "Permission is Required for getting list of files", Toast.LENGTH_SHORT).show();
}
}
}
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Check if the key event was the Back button and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
webView.goBack();
return true;
}
// If it wasn't the Back key or there's no web page history, bubble up to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
}
public class PQClient extends WebViewClient {
ProgressBar progressDialog;
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// If url contains mailto link then open Mail Intent
if (url.contains("mailto:")) {
// Could be cleverer and use a regex
//Open links in new browser
view.getContext().startActivity(
new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
// Here we can open new activity
return true;
} else {
// Stay within this webview and load url
view.loadUrl(url);
return true;
}
}
// Show loader on url load
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// Then show progress Dialog
// in standard case YourActivity.this
if (progressDialog == null) {
progressDialog = findViewById(R.id.progressBar);
progressDialog.setVisibility(View.VISIBLE);
}
}
// Called when all page resources loaded
public void onPageFinished(WebView view, String url) {
webView.loadUrl("javascript:(function(){ " +
"document.getElementById('android-app').style.display='none';})()");
try {
// Close progressDialog
progressDialog.setVisibility(View.GONE);
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
}
In KitKat you can use the Storage Access Framework.
Storage Access Framework / Writing a Client App
Solution: https://github.com/delight-im/Android-AdvancedWebView
Solution for Fragent:
The difference between activity and fragment is only in onActivityResult:
Fragment:
lateinit var webViewGlobal: AdvancedWebView private set
class WebViewFragment : Fragment(), AdvancedWebView.Listener {
private lateinit var binding: FragmentWebViewBinding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = FragmentWebViewBinding.inflate(inflater)
webViewGlobal = binding.webWiew
return binding.root
}
}
Activity:
class MainActivity : AppCompatActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
webViewGlobal.onActivityResult(requestCode, resultCode, data)
super.onActivityResult(requestCode, resultCode, data)
}
}
Android 11:
<application
...
android:requestLegacyExternalStorage="true"
...
/>
Manifest:
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
I'm new to Andriod and struggled with this also. According to Google Reference Guide WebView.
By default, a WebView provides no browser-like widgets, does not
enable JavaScript and web page errors are ignored. If your goal is
only to display some HTML as a part of your UI, this is probably fine;
the user won't need to interact with the web page beyond reading it,
and the web page won't need to interact with the user. If you actually
want a full-blown web browser, then you probably want to invoke the
Browser application with a URL Intent rather than show it with a
WebView.
Example code I executed in MainActvity.java.
Uri uri = Uri.parse("https://www.example.com");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
Excuted
package example.com.myapp;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.content.Intent;
import android.net.Uri;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Uri uri = Uri.parse("http://www.example.com/");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
getSupportActionBar().hide();
}}
I researched on this issue for almost one month. Everything failed. All codes seen in multiple websites does n't work good. But here exists the best solution
https://github.com/chiclaim/android-webview-upload-file
Steps
1) Click on clone or download
2) Get the zip fle in your local directory
3) unzip the zip file
4) Open Android studio
5) Goto File ----> Open ---> Navigate to directory where you unzipped the contents.
6) Change the required web url in webView.loadUrl("your url hre"); in MainActivity.java
7) Works good with version Android studio 3.4.2
Custom WebChromeClient:
class AppChromeClient(private val fragmentWeakReference: WeakReference<WebViewFragment>) :
WebChromeClient() {
private var openFileCallback: ValueCallback<Array<Uri>>? = null
override fun onShowFileChooser(
webView: WebView?,
filePathCallback: ValueCallback<Array<Uri>>?,
fileChooserParams: FileChooserParams?
): Boolean {
if (filePathCallback == null) {
return (super.onShowFileChooser(webView, filePathCallback, fileChooserParams))
}
openFileCallback = filePathCallback
val webViewFragment = fragmentWeakReference.get() ?: return false
webViewFragment.launchGetMultipleContents("*/*")
return true
}
fun receiveFileCallback(result: Array<Uri>) {
openFileCallback?.onReceiveValue(result)
openFileCallback = null
}
}
WebViewFragment:
class WebViewFragment : Fragment() {
private var _binding: FragmentWebviewBinding? = null
private val binding get() = _binding!!
private lateinit var webView: WebView
private val chromeClient = AppChromeClient(WeakReference(this))
private var contentLauncher: ActivityResultLauncher<String> = getMultipleContentLauncher()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentWebviewBinding.inflate(inflater, container, false)
webView.webChromeClient = chromeClient
val url = requireContext().getString(R.string.app_domain)
webView.setting.javaScriptEnabled = true
webView.loadUrl(url)
return binding.root
}
private fun getMultipleContentLauncher(): ActivityResultLauncher<String> {
return this.registerForActivityResult(ActivityResultContracts.GetMultipleContents()) { list ->
if (list.isEmpty()) {
showToast("No files selected")
}
chromeClient.receiveFileCallback(list.toTypedArray())
}
}
fun launchGetMultipleContents(type: String) {
contentLauncher.launch(type)
}
}

Categories

Resources