Android Webview irregular loading issue - javascript

Hi I would like to have an explanation regarding the following code. Here Sometimes my javascript functtion is working and sometime it is not. As a result, I don't really know where is the problem. Here my index.html file automatically loads a map position. Then I call the javascript function with current lat,lng as argument. SO, initially it loads the by default map. Then the map should be overridden by the javascript function. The problem is sometimes it happens and sometimes it doesn't. So, I would like to have an answer regarding this.
public class MapOptionsDemoModified extends Activity{
//Geocoder geocoder;
WebView mWebView;
LocationManager mlocManager=null;
LocationListener mlocListener;
private MyLocationOverlay myLocationOverlay;
protected MapView map;
private RadioButton mapButton;
private RadioButton satelliteButton;
private ToggleButton trafficToggle;
private ToggleButton labelsToggle;
private Configuration config;
EditText LOC;
Button routesbtn,settingsbtn;
public String location="State Street"
double lati,longi;
GeoPoint currentLocation;
double curlat,curlong;
InputMethodManager imm;
//String adrs;
double latitude=40.07546;
double longitude=-76.329999;
String adrs="";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.map_options_modified);
lati=34.1161;
longi=-118.149399;
adrs="";
routesbtn=(Button)findViewById(R.id.mom_bt2);
mlocManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
mlocListener = new MyLocationListener();
mlocManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
mWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
mWebView.loadUrl("file:///android_asset/index.html");
//mWebView.loadUrl("http://www.google.com");
webSettings.setBuiltInZoomControls(true);
webSettings.setSupportZoom(true);
imm=(InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
/* taking data from caller activity page */
// ###################Receiving data starts
Bundle extras = getIntent().getExtras();
if (extras == null) {
return;
}
lati=extras.getDouble("latitude");
longi = extras.getDouble("longitude");
adrs=extras.getString("adrs");
// ##### Receiving data ends
AlertDialog.Builder pdb=new AlertDialog.Builder(MapOptionsDemoModified.this);
pdb.setTitle("GPS");
pdb.setMessage(adrs+" "+Double.toString(lati)+" "+Double.toString(longi));
pdb.setPositiveButton("Ok", null);
pdb.show();
mWebView.loadUrl("javascript:getCurrentLocation("+lati+","+longi+")");
routesbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mlocManager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
//while(j<cnt)
//{
mlocManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, 0, 0, mlocListener);
if(MyLocationListener.latitude>0)
{
latitude=MyLocationListener.latitude;
longitude=MyLocationListener.longitude;
//flag=1;
Geocoder gcd = new Geocoder(MapOptionsDemoModified.this, Locale.getDefault());
List<Address> addresses;
try {
addresses = gcd.getFromLocation(latitude,longitude, 5);
if (addresses.size() > 0)
{
adrs=addresses.get(0).getAddressLine(0)+" "+addresses.get(0).getAddressLine(1)+" "+addresses.get(0).getAddressLine(2);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//break;
finish();
Intent i = new Intent(MapOptionsDemoModified.this,RoutesPageOne.class);
i.putExtra("adrs", adrs);
i.putExtra("latitude", latitude);
i.putExtra("longitude", longitude);
startActivity(i);
}
else
{
AlertDialog.Builder pdb=new AlertDialog.Builder(MapOptionsDemoModified.this);
pdb.setTitle("GPS");
pdb.setMessage("GPS activation in progress");
pdb.setPositiveButton("Ok", null);
pdb.show();
}
//}
}
else {
AlertDialog.Builder pdb=new AlertDialog.Builder(MapOptionsDemoModified.this);
pdb.setTitle("GPS");
pdb.setMessage("GPS is not turned on..., please start gps");
pdb.setPositiveButton("Ok", null);
pdb.show();
}
}
});
LOC=(EditText)findViewById(R.id.mom_editText1);
LOC.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
location = LOC.getText().toString();
if (keyCode == KeyEvent.KEYCODE_ENTER && location.length() > 0) {
LOC.setText("");
imm.hideSoftInputFromWindow(LOC.getWindowToken(), 0);
mWebView.loadUrl("javascript:getLocation('" + location + "')");
/*AlertDialog.Builder edb=new AlertDialog.Builder(MapOptionsDemoModified.this);
edb.setTitle("gps");
edb.setMessage(location+" lat= "+lati+" long="+longi);
edb.setPositiveButton("Ok", null);
edb.show();*/
//searchBarcode(barcode);
return true;
}
return false;
}
});
//imm.hideSoftInputFromWindow(myEditText.getWindowToken(), 0);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
mWebView.setWebViewClient(new HelloWebViewClient());
private class HelloWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
}

The problem was in timing. Sometimes, the first url took more time to be loaded, as a result the 2nd url wasn't invoked. So I have included SystemClock.sleep(1000) in between loadUrl calls and it has worked like a charm.

Related

calling activity from webview with #JavascriptInterface? [duplicate]

I'm stuck on my project and requesting your help!
I'm trying to call an Activity(BarcodeScannerActivity.java) from webview in MainActivity.java with button click using javascript call. I think I messed up with parameters somewhere... I'm not sure where I've made mistake, I just copied and modified the codes from blogs and stackoverflow.
I'm having this error in my Android Studio logcat:
[INFO:CONSOLE(315)] "Uncaught Error: Error calling method on NPObject.", source: http:// .........
this is my server side html:
<input type="button" value="Scanner" id="BtnScan" class="btn_dark" onclick="callActivity();" />
<script>
function callActivity() {
Android.openBarcodeScanner();
}
</script>
this is my MainActivity.java containing webview:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
//getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
//getActionBar().hide();
setContentView(R.layout.activity_main);
MainWebView = (WebView) findViewById(R.id.mainWebview);
MainWebView.setWebViewClient(new WebViewClient());
//-- add javascript listener
MainWebView.addJavascriptInterface(new WebAppInterface(this), "Android");
MainWebView.getSettings().setJavaScriptEnabled(true);
MainWebView.loadUrl(WebViewURL);
}
..skipped for brevity..
public class WebAppInterface {
Context mContext;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
#JavascriptInterface
public void openBarcodeScanner(String str) {
Intent barcodeScanIntent = new Intent(mContext, BarcodeScannerActivity.class);
mContext.startActivity(barcodeScanIntent);
}
}
and last, the BarcodeScannerActivity.java that wants to be called:
public class BarcodeScannerActivity extends Activity implements View.OnClickListener {
// private static final R = ;
// use a compound button so either checkbox or switch widgets work.
private CompoundButton autoFocus;
private CompoundButton useFlash;
private TextView statusMessage;
private TextView barcodeValue;
private static final int RC_BARCODE_CAPTURE = 9001;
private static final String TAG = "BarcodeMain";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.barcode_scanner);
statusMessage = (TextView)findViewById(R.id.status_message);
barcodeValue = (TextView)findViewById(R.id.barcode_value);
autoFocus = (CompoundButton) findViewById(R.id.auto_focus);
useFlash = (CompoundButton) findViewById(R.id.use_flash);
findViewById(R.id.read_barcode).setOnClickListener(this);
}
/**
* Called when a view has been clicked.
*
* #param v The view that was clicked.
*/
#Override
public void onClick(View v) {
if (v.getId() == R.id.read_barcode) {
// launch barcode activity.
Intent intent = new Intent(this, BarcodeCaptureActivity.class);
intent.putExtra(BarcodeCaptureActivity.AutoFocus, autoFocus.isChecked());
intent.putExtra(BarcodeCaptureActivity.UseFlash, useFlash.isChecked());
startActivityForResult(intent, RC_BARCODE_CAPTURE);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RC_BARCODE_CAPTURE) {
if (resultCode == CommonStatusCodes.SUCCESS) {
if (data != null) {
Barcode barcode = data.getParcelableExtra(BarcodeCaptureActivity.BarcodeObject);
statusMessage.setText(R.string.barcode_success);
barcodeValue.setText(barcode.displayValue);
Log.d(TAG, "Barcode read: " + barcode.displayValue);
} else {
statusMessage.setText(R.string.barcode_failure);
Log.d(TAG, "No barcode captured, intent data is null");
}
} else {
statusMessage.setText(String.format(getString(R.string.barcode_error),
CommonStatusCodes.getStatusCodeString(resultCode)));
}
}
else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
and one last question is, would this javascript code work in my situation, too?
or do I need to modify a bit?
function callActivity(){
if(window.android){
console.info("android");
window.android.openBarcodeScanner(number.value);
}
else{
console.info("web");
document.form.submit();
}
}
}
Thank you so much in advance!
Your interface takes a string as a parameter:
#JavascriptInterface
public void openBarcodeScanner(String str) {
But your invocation doesn't pass any parameters:
Android.openBarcodeScanner();

calling activity from webview with #JavascriptInterface

I'm stuck on my project and requesting your help!
I'm trying to call an Activity(BarcodeScannerActivity.java) from webview in MainActivity.java with button click using javascript call. I think I messed up with parameters somewhere... I'm not sure where I've made mistake, I just copied and modified the codes from blogs and stackoverflow.
I'm having this error in my Android Studio logcat:
[INFO:CONSOLE(315)] "Uncaught Error: Error calling method on NPObject.", source: http:// .........
this is my server side html:
<input type="button" value="Scanner" id="BtnScan" class="btn_dark" onclick="callActivity();" />
<script>
function callActivity() {
Android.openBarcodeScanner();
}
</script>
this is my MainActivity.java containing webview:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
//getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
//getActionBar().hide();
setContentView(R.layout.activity_main);
MainWebView = (WebView) findViewById(R.id.mainWebview);
MainWebView.setWebViewClient(new WebViewClient());
//-- add javascript listener
MainWebView.addJavascriptInterface(new WebAppInterface(this), "Android");
MainWebView.getSettings().setJavaScriptEnabled(true);
MainWebView.loadUrl(WebViewURL);
}
..skipped for brevity..
public class WebAppInterface {
Context mContext;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
#JavascriptInterface
public void openBarcodeScanner(String str) {
Intent barcodeScanIntent = new Intent(mContext, BarcodeScannerActivity.class);
mContext.startActivity(barcodeScanIntent);
}
}
and last, the BarcodeScannerActivity.java that wants to be called:
public class BarcodeScannerActivity extends Activity implements View.OnClickListener {
// private static final R = ;
// use a compound button so either checkbox or switch widgets work.
private CompoundButton autoFocus;
private CompoundButton useFlash;
private TextView statusMessage;
private TextView barcodeValue;
private static final int RC_BARCODE_CAPTURE = 9001;
private static final String TAG = "BarcodeMain";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.barcode_scanner);
statusMessage = (TextView)findViewById(R.id.status_message);
barcodeValue = (TextView)findViewById(R.id.barcode_value);
autoFocus = (CompoundButton) findViewById(R.id.auto_focus);
useFlash = (CompoundButton) findViewById(R.id.use_flash);
findViewById(R.id.read_barcode).setOnClickListener(this);
}
/**
* Called when a view has been clicked.
*
* #param v The view that was clicked.
*/
#Override
public void onClick(View v) {
if (v.getId() == R.id.read_barcode) {
// launch barcode activity.
Intent intent = new Intent(this, BarcodeCaptureActivity.class);
intent.putExtra(BarcodeCaptureActivity.AutoFocus, autoFocus.isChecked());
intent.putExtra(BarcodeCaptureActivity.UseFlash, useFlash.isChecked());
startActivityForResult(intent, RC_BARCODE_CAPTURE);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RC_BARCODE_CAPTURE) {
if (resultCode == CommonStatusCodes.SUCCESS) {
if (data != null) {
Barcode barcode = data.getParcelableExtra(BarcodeCaptureActivity.BarcodeObject);
statusMessage.setText(R.string.barcode_success);
barcodeValue.setText(barcode.displayValue);
Log.d(TAG, "Barcode read: " + barcode.displayValue);
} else {
statusMessage.setText(R.string.barcode_failure);
Log.d(TAG, "No barcode captured, intent data is null");
}
} else {
statusMessage.setText(String.format(getString(R.string.barcode_error),
CommonStatusCodes.getStatusCodeString(resultCode)));
}
}
else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
and one last question is, would this javascript code work in my situation, too?
or do I need to modify a bit?
function callActivity(){
if(window.android){
console.info("android");
window.android.openBarcodeScanner(number.value);
}
else{
console.info("web");
document.form.submit();
}
}
}
Thank you so much in advance!
Your interface takes a string as a parameter:
#JavascriptInterface
public void openBarcodeScanner(String str) {
But your invocation doesn't pass any parameters:
Android.openBarcodeScanner();

How to extract text from a WebPage

First off, yes, I have done research on this question. And yes, I have found an answer here. But the whole process still isn't working for me. All I need to do is grab text off of a webpage like Google, and create a string from the text it grabs. Here is my code with the aforementioned tutorials code in it:
public class Searching_Animation_Screen extends ActionBarActivity {
TextView loading_txt;
Animation blink;
public String pre_split;
public String[] split_string;
TextView text;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_searchinganimationscreen);
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
int width = getWindowManager().getDefaultDisplay().getWidth();
loading_txt = (TextView)findViewById(R.id.loading);
text =(TextView)findViewById(R.id.textView);
Typeface pacifico_typeface = Typeface.createFromAsset(getAssets(), "fonts/pacifico.ttf");
loading_txt.setTypeface(pacifico_typeface);
loading_txt.setTextSize(width / 20);
blink = AnimationUtils.loadAnimation(getApplicationContext(),
R.anim.blink);
loading_txt.setAnimation(blink);
Begin();
}
private void Begin() {
Intent SEARCH_INTENT = getIntent();
pre_split=SEARCH_INTENT.getStringExtra("Search_Text");
split_string = pre_split.split(" ");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_searchinganimationscreen, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private class DownloadWebPageTask extends AsyncTask<String, Void, String> {
String google_url ="https://www.google.com/#safe=active&q=";
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(
new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return response;
}
#Override
protected void onPostExecute(String result) {
text.setText(Html.fromHtml(result));
//throw into summarizer
}
public void readWebpage(View view) {
DownloadWebPageTask task = new DownloadWebPageTask();
task.execute(new String[] {"www.google.com"});
}
}
}
Android studio is saying that readWebpage is never used, along with the actual DownloadWebPageTask class. Any ideas? I would like this class to run immediately on Create. Thanks!
#Ethan, sure, I hope this is what you want, just adding the readWebpage method in the onCreate method, but I modified it and removed the View object since it is not being used,
public class Searching_Animation_Screen extends ActionBarActivity {
TextView loading_txt;
Animation blink;
public String pre_split;
public String[] split_string;
TextView text;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_searchinganimationscreen);
ActionBar actionBar = getSupportActionBar();
actionBar.hide();
int width = getWindowManager().getDefaultDisplay().getWidth();
loading_txt = (TextView)findViewById(R.id.loading);
text =(TextView)findViewById(R.id.textView);
Typeface pacifico_typeface = Typeface.createFromAsset(getAssets(), "fonts/pacifico.ttf");
loading_txt.setTypeface(pacifico_typeface);
loading_txt.setTextSize(width / 20);
blink = AnimationUtils.loadAnimation(getApplicationContext(),
R.anim.blink);
loading_txt.setAnimation(blink);
Begin();
//* call webpage here,
//* note, i removed passing the view object since it is not being used
readWebpage()
}
//* (modify) by remvoving it from the code below
//* and removing the view object since it is not being used
public void readWebpage() {
DownloadWebPageTask task = new DownloadWebPageTask();
task.execute(new String[] {"http://www.google.com"});
}
private void Begin() {
Intent SEARCH_INTENT = getIntent();
pre_split=SEARCH_INTENT.getStringExtra("Search_Text");
split_string = pre_split.split(" ");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_searchinganimationscreen, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private class DownloadWebPageTask extends AsyncTask<String, Void, String> {
String google_url ="https://www.google.com/#safe=active&q=";
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(
new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return response;
}
#Override
protected void onPostExecute(String result) {
text.setText(Html.fromHtml(result));
//throw into summarizer
}
}
}

Android WebView utilizing Camera and GPS

I'm playing around with the WebView in the Android browser, but is wondering if anyone have used the browser together with the html5 to use the camera and gps of the local device?
Or will I need to do a Javascript connection to the Java source code for this?
Will this also work in IOS?
This is, without using PhoneGap.
best,
Henrik
It might be a bit late, but just in case I will give you an example to do that.
(Camera)
1////add this to your webChromeClient
myWebView.setWebChromeClient(new WebChromeClient()
{
public void openFileChooser( ValueCallback<Uri> uploadMsg, String acceptType )
{
mUploadMessage = uploadMsg;
Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE");
Calendar cal = Calendar.getInstance();
cal.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("HHmmss");
File photo = new File(Environment.getExternalStorageDirectory(), sdf.format(cal.getTime()) +".jpg");
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
picUri = Uri.fromFile(photo);
startActivityForResult(cameraIntent, TAKE_PICTURE);
}
});
2///add this function
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
switch(requestCode)
{
case TAKE_PICTURE:
if(resultCode == Activity.RESULT_OK)
{
Uri mypic = picUri;
mUploadMessage.onReceiveValue(mypic);
mUploadMessage = null;
}
else
{
mUploadMessage.onReceiveValue(null);
mUploadMessage = null;
return;
}
default:
{
return;
}
}
}
3// and the HTML looks like this
<input type="file" id="files" name="files" accept="image/*" capture="camera" >
The above code will open the native camera app.
P.S. This is a mix of code from different sources.
It's worth pointing out where the code shown here should live, as it's not obvious for a newbie - it goes in your Activity class, i.e.
public class MyActivity extends Activity {
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
...
}
#Override
public void onCreate(Bundle savedInstanceState) {
...
myWebView.setWebChromeClient(new WebChromeClient()
{
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
...
}
});
}
}
In my case, I've override the makeWebViewEngine method in order to be able to modify the CordovaWebViewEngine casted to a SystemWebViewEngine as follows (based on this answer):
public class MainActivity extends CordovaActivity {
private static final int FILECHOOSER_RESULTCODE = 12345;
private ValueCallback<Uri> mUploadMessage;
private Uri mPicUri;
private ValueCallback<Uri[]> mFilePathCallback;
private String mCameraPhotoPath;
#Override
protected CordovaWebViewEngine makeWebViewEngine() {
SystemWebViewEngine systemWebViewEngine = (SystemWebViewEngine) super.makeWebViewEngine();
SystemWebView systemWebView = (SystemWebView) systemWebViewEngine.getView();
systemWebView.setWebChromeClient(new SystemWebChromeClient(systemWebViewEngine) {
// For Android 4.1
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
mUploadMessage = uploadMsg;
Intent cameraIntent = new Intent("android.media.action.IMAGE_CAPTURE");
Calendar cal = Calendar.getInstance();
cal.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("HHmmss");
File photo = new File(Environment.getExternalStorageDirectory(), sdf.format(cal.getTime()) + ".jpg");
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
mPicUri = Uri.fromFile(photo);
startActivityForResult(cameraIntent, FILECHOOSER_RESULTCODE);
}
// For Android 5.0+
public boolean onShowFileChooser(
WebView webView, ValueCallback<Uri[]> filePathCallback,
WebChromeClient.FileChooserParams fileChooserParams) {
// Double check that we don't have any existing callbacks
if (mFilePathCallback != null) {
mFilePathCallback.onReceiveValue(null);
}
mFilePathCallback = filePathCallback;
// Set up the take picture intent
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(MainActivity.this.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;
}
}
// Set up the intent to get an existing image
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
contentSelectionIntent.setType("image/*");
// Set up the intents for the Intent chooser
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, MainActivity.FILECHOOSER_RESULTCODE);
return true;
}
});
return systemWebViewEngine;
}
// …
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set by <content src="index.html" /> in config.xml
loadUrl(launchUrl);
}
}
Furthermore, based on this other answer, I've had to specify the openFileChooser method for Android 4.1 and, for Android 5.0+, I've had to specify the onShowFileChooser method.
By the way, I've modified the onActivityResult method as follows:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (Build.VERSION.SDK_INT >= 21) {
if (requestCode != FILECHOOSER_RESULTCODE || mFilePathCallback == null) {
super.onActivityResult(requestCode, resultCode, intent);
return;
}
Uri[] results = null;
// Check that the response is a good one
if (resultCode == Activity.RESULT_OK) {
String dataString = intent.getDataString();
if (dataString != null) {
results = new Uri[]{Uri.parse(dataString)};
} else {
// If there is not data, then we may have taken a photo
if (mCameraPhotoPath != null) {
results = new Uri[]{Uri.parse(mCameraPhotoPath)};
}
}
}
mFilePathCallback.onReceiveValue(results);
mFilePathCallback = null;
} else {
if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == this.mUploadMessage) {
return;
}
Uri result;
if (resultCode != RESULT_OK) {
result = null;
} else {
result = intent == null ? this.mPicUri : intent.getData(); // retrieve from the private variable if the intent is null
}
this.mUploadMessage.onReceiveValue(result);
this.mUploadMessage = null;
}
}
}
Thanks to #Will and #Christian for pointing the good direction in this answer BTW :)

Android: How to saveState of a WebView with an addJavascriptInterface attached?

I have an android WebView that has a JavaScript interface added with addJavajavascriptInterface().
Is it possible to save the state of the WebView (webpage state, html, css, javascript) and then restore it on onCreate? If yes, how?
The code I have so far keeps crashing:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
final WebBackForwardList list = mWebView.restoreState(savedInstanceState);
if (savedInstanceState.containsKey("currentPicture")) {
final File f = new File(savedInstanceState.getString("currentPicture"));
mWebView.restorePicture(savedInstanceState, f);
f.delete();
}
} else {
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.addJavascriptInterface(new MyJavaScriptInterface(this), "AndroidApp");
mWebView.loadUrl(url);
}
}
public void onSaveInstanceState(Bundle outState) {
final WebBackForwardList list = mWebView.saveState(outState);
File mThumbnailDir = getDir("my-thumbnails", 0);
if (list != null) {
final File f = new File(mThumbnailDir, mWebView.hashCode() + "_pic.save");
if (mWebView.savePicture(outState, f))
outState.putString("currentPicture", f.getPath());
}
}

Categories