I am trying to interact with the JavaScript through Android. i followed the tutorial found [here][1].
But I am getting the following warning.system.out.println is also not working
WARN/KeyCharacterMap(310): No keyboard for id 0
WARN/KeyCharacterMap(310): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
WARN/InputManagerService(66): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy#44faba68
cause of which I am not able to pass values or get the values back
webEngine=(WebView) findViewById(R.id.webengine);
webEngine.getSettings().setJavaScriptEnabled(true);
webEngine.addJavascriptInterface(this, "android");
webEngine.setWebViewClient(new WebViewClient()
{
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
return false;
}
});
webEngine.loadUrl("http://www.a11y.in/a11y_fs/");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
// TODO Auto-generated method stub
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
// Handle item selection
switch (item.getItemId())
{
case R.id.edit:
webEngine.loadUrl("javascript:var path =android.path();var newContent=android.newContent();var name = 'myname'; android.toast(name););
return true;
case R.id.renarration:
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public String path()
{
return xPath = "//H3[#id='header']";
}
public String newContent()
{
return newContent ="my New Home";
}
public void toast(String x)
{
Toast.makeText(this, "hello from js"+x, Toast.LENGTH_LONG).show();
}
plz help
First, those error messages are not related to your code, so you can just ignore them.
Then there seems to be some error with the quotes, there do not match (which also breaks the syntax highlighting in your question)... or it might be only this site which parses it incorrectly...
I also don't see the "path" method in your class, although you are accessing it from javascript. Similarly the "newContent" method.
Related
I am developing an android app using webview. after a button is clicked it navigates to other page. i used javascript function onClick() to navigate.when back button is pressed it used to close that application but i want it to navigate to previous page. after using following code it states "unfortunately, myapp stopped working". I tried all possible ways. please help me
package com.example.anush.teamcetrankevaluator;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.WebView;
public class MainActivity extends Activity {
WebView web;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView web=(WebView)this.findViewById(R.id.webview);
web.loadUrl("file:///android_asset/webview.html");
web.getSettings().setJavaScriptEnabled(true);
//web.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
}
#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_main, 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);
}
#Override
public void onBackPressed() {
super.onBackPressed();
if (web.canGoBack()) {
web.goBack();
}
else
{
super.onBackPressed();
finish();
}
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// TODO Auto-generated method stub
// finish the activity
if (keyCode == KeyEvent.KEYCODE_BACK && web.canGoBack()) {
web.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
Logcat Error :
09-10 20:44:52.688 10542-10542/? D/AndroidRuntime﹕ Shutting down VM
09-10 20:44:52.690 10542-10542/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.anush.teamcetrankevaluator, PID: 10542
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.webkit.WebView.canGoBack()' on a null object reference
at com.example.anush.teamcetrankevaluator.MainActivity.onKeyDown(MainActivity.java:65)
at android.view.KeyEvent.dispatch(KeyEvent.java:2622)
at android.app.Activity.dispatchKeyEvent(Activity.java:2714)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:2221)
at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:3988)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3950)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3509)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3562)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3528)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3638)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3536)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3695)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3509)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3562)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3528)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3536)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3509)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3562)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3528)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3671)
at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:3832)
at android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:2210)
at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:1851)
at android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:1842)
at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:2187)
at android.view.InputEventSender.dispatchInputEventFinished(InputEventSender.java:141)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:143)
at android.os.Looper.loop(Looper.java:122)
at android.app.ActivityThread.main(ActivityThread.java:5312)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)
09-10 20:44:54.495 10542-10542/? I/Process﹕ Sending signal. PID: 10542 SIG: 9
Edit your onBackPressed to look like this:
#Override
public void onBackPressed() {
// get rid of this --> super.onBackPressed();
if (web.canGoBack()) {
web.goBack();
}
else
{
super.onBackPressed();
// get rid of this --> finish();
}
}
You've also got an error in onCreate:
WebView web;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// this line is wrong: WebView web=(WebView)this.findViewById(R.id.webview);
//should be:
web=(WebView)this.findViewById(R.id.webview);
web.loadUrl("file:///android_asset/webview.html");
web.getSettings().setJavaScriptEnabled(true);
//web.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
}
This line is the useful part of your logcat error:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.webkit.WebView.canGoBack()' on a null object reference
It means that web was null, but you were trying to do web.canGoBack();
You create your variable WebView web in the main activity and then declare the same variable in the oncreate method. By doing this, you cannot access this initialised variable web outside of the scope of the oncreate bundle.
So the variable that you are attempting to access, the class variable WebView web that you declared first is not initialised, this is what is causing your app to stop.
So as the other answer Joe says, just
web=(WebView)this.findViewById(R.id.webview);
within your oncreate bundle.
This is a link which discusses variable scope in java.
http://www.java-made-easy.com/variable-scope.html
edit just saw your logcat:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.webkit.WebView.canGoBack()' on a null object reference
at com.example.anush.teamcetrankevaluator.MainActivity.onKeyDown(MainActivity.java:65)
at android.view.KeyEvent.dispatch(KeyEvent.java:2622)
The null object reference is referring to the uninitialised Webview web, when there is an attempt to access it in your onKeyDown method.
I'm trying to refresh Canvas on DoubleTap in android. I use GestureDetector in custom View.
final GestureDetector mDetector = new GestureDetector(
getContext(), new GestureDetector.OnGestureListener() {
#Override
public boolean onDoubleTap(MotionEvent e) {
invalidate();
return true;
}
}
But I'm getting the error
The method onDoubleTap(MotionEvent) of type new
GestureDetector.OnGestureListener(){} must override or implement a
supertype method
with
Remove '#Override' annotation
solution. I remove override and get this warning
The method onDoubleTap(MotionEvent) from the type new
GestureDetector.OnGestureListener() {} is never used locally.
Then I tried to test whether this works and made a function to change TextView string whenever I DoubleTap. Nothing happens.
I also looked at GestureDetector Reference for explanations, but they don't even have DoubleTap there, which everybody uses. What should I do?
try this
final GestureDetector mDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener {
#Override
public boolean onDown(MotionEvent e) {
return true;
}
#Override
public boolean onDoubleTap(MotionEvent e) {
return true;
}
});
For the ones, who were wondering how to set it also to the corresponding view:
final GestureDetector gDetector = new GestureDetector(getBaseContext(), new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onDown(MotionEvent e) {
return true;
}
#Override
public boolean onDoubleTap(MotionEvent e) {
doIt();
return true;
}
});
// Set it to the view
mButton.setOnTouchListener((v, event) -> gDetector.onTouchEvent(event));
My approach to this problem was different since I needed to perform something for the onClick listener as well, and also it was in a list view, so I needed to know what was the item content.
here is my approach using kotlin Job:
At the top of the class I've declared something like this:
private var doubleTapTimerJob: Job = Job()
private var clickedViewItem: CartViewItem? = null
val DOUBLE_TAP_DELAY = 200L
where CartViewItem is the model that is used in the list.
and this is my onClickListener logic:
if (clickedViewItem == null || clickedViewItem != cartViewItem) {
doubleTapTimerJob.cancel()
doubleTapTimerJob = lifecycleScope.launch {
delay(DOUBLE_TAP_DELAY)
clickedViewItem = null
}
clickedViewItem = cartViewItem
onClicked(cartViewItem)
} else {
onDoubleClicked(cartViewItem)
clickedViewItem = null
doubleTapTimerJob.cancel()
}
here I wait for 200 milliseconds for the second tap, and if it didn't happen, I will make clickedViewItem null, so its not valid anymore
I have some javascript running in WebView. In this Javascript code there a function which returns a boolean. I want to check the return value from this function and depends on it hide or not a view in my android code. I tried for one day and it does not work. Do someone knows where is my error? This is my code:
public class MyActivity extends Activity {
private static final String JS_INTERFACE = "Android";
....
webView.getSettings().setJavaScriptEnabled(true);
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webView.loadUrl(getUrl(this.getResources().getString(R.string.host)));
webView.addJavascriptInterface(new WebViewJavaScriptInterface(this), JS_INTERFACE);
webView.setWebViewClient(new WebViewClient(progressBar, this, tvError));
webView.setWebChromeClient(new WebChromeClient(progressBar));
webView.loadUrl("javascript:window.Android.showAdBanner(showSdkAd())");
}
public class WebViewJavaScriptInterface
{
....
#JavascriptInterface
public void showAdBanner(String jsResult) {
if (jsResult == "true") {
((Activity) context).findViewById(R.id.adView).setVisibility(View.GONE);
} else {
((Activity) context).findViewById(R.id.adView).setVisibility(View.GONE);
}
}
}
You're setting the visibility to View.GONE in both cases of the if (jsResult == "true") if statement.
I think the window in the js is unneeded, so
webView.loadUrl("javascript:window.Android.showAdBanner(showSdkAd())");
Should be
webView.loadUrl("javascript:Android.showAdBanner(showSdkAd())");
Also, the javascript callback will be executed in a background thread, so you need to move to the main thread (posting a runnable to a view, runOnUiThread, using a handler etc), before performing Ui operations.
If you have a reference to a View, you can do:
#JavascriptInterface
public void showAdBanner(String jsResult) {
viewReference.post(new Runnable() {
public void run() {
if (jsResult == "true") {
((Activity) context).findViewById(R.id.adView).setVisibility(View.GONE);
} else {
((Activity) context).findViewById(R.id.adView).setVisibility(View.GONE);
}
}
}
Since, you have a reference to the activity, you can replace viewReference.post with ((Activity) context).runOnUiThread
If you initialise a Handler on the main thread, it will be bound to the main thread. As a field of the Activity, you could have:
private Handler mHandler = new Handler();
And then replace viewReference.post with mHandler.post
You could also make a custom Handler that implements handleMessage(Message msg) and then you can just send it an empty message. However, you should read https://techblog.badoo.com/blog/2014/08/28/android-handler-memory-leaks/ to avoid memory issues.
I'm developing an hybrid app in Android. I want to show an alertDialog(instead of an alert/confirm JavaScript function) and when the user touch YES, return a true response to JavaScript, otherwise return false. Then if it's true I want to redirect to another URL.
Here's the 'binding JavaScript code to Android code':
public class WebAppInterface {
Context mContext;
boolean result;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
#JavascriptInterface
public boolean showAlert(String title, String message) {
new AlertDialog.Builder(mContext)
.setTitle(title)
.setMessage(message)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result = true;
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result = false;
}
})
.show();
return result;
}
}
And the JavaScript part:
if (Android.showAlert('Title example', 'Are you sure you wanna exit?') == true) {
window.location = "http://newurl.com/example.html";
}
It actually works but not as it supposed to do. JavaScript receives the result when I open again the alertDialog and then redirect to the new URL, It needs to redirect at the moment the user touch the YES button.
I've done lot of research on this particular case and sadly found nothing.
Thank you.
Here is the Javascript Code. Add a function to navigate to a page. Like doNavigate:
<script type="text/javascript">
function showAlert(toast) {
navigate = Android.showAlert('Title example', 'Are you sure you wanna exit?');
}
function doNavigate(){
window.location = "http://www.google.com"
}
</script>
And here is the Android code for show alert. Call the javascript method from onClick positive button:
#JavascriptInterface
public boolean showAlert(String title, String message) {
new AlertDialog.Builder(mContext)
.setTitle(title)
.setMessage(message)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
((Activity)mContext).runOnUiThread(new Runnable() {
#Override
public void run() {
myWeb.loadUrl("javascript:doNavigate()");
}
});
result = true;
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result = false;
}
})
.show();
return result;
}
Keep a reference of the WebView in your WebAppInterface:
public static class WebAppInterface{
Context mContext;
boolean result;
WebView myWeb;
/** Instantiate the interface and set the context */
WebAppInterface(Context c, WebView webView) {
mContext = c;
myWeb = webView;
}
Probably when on click gets executed it doesnt immediately return the desired boolean value.
I'm thinking the next time you open the dialog then the if statment gets executed.
Maybe you can try injecting the logic through the constructor using an interface or class. And when the positive button is clicked it will call a method of that interface setting window.location
Hope it helps . Good luck
public class engageLink extends AjaxLink{
private Engage engage;
private String name;
engageLink(String string, Engage anEngage,String name) {
super(string);
this.engage = anEngage;
this.name = name;
hasEngage=((Application) getApplication()).getVtb().hasEngagement(engage,name);
if(hasEngage)
this.add(new AttributeAppender("onclick", new Model("alert('This is my JS script');"), ";"));
}
boolean randevuAlmis;
#Override
public void onClick(AjaxRequestTarget target) {
if(hasEngage){
//do nothing or call ajax on failure script
} else{
((Application) getApplication()).getVtb().addEngagement(engage, name);
}
setResponsePage(new Sick(name));
}
#Override
protected org.apache.wicket.ajax.IAjaxCallDecorator getAjaxCallDecorator()
{
return new AjaxCallDecorator()
{
#Override
public CharSequence decorateOnSuccessScript(CharSequence script)
{
return "alert('Success');";
}
#Override
public CharSequence decorateOnFailureScript(CharSequence script)
{
return "alert('Failure');";
}
};
};
}
This is my code.IN the method on click i call ajax onfailure script .but it doesn't work.
I tried adding javascript in the constructor.It does not work too.
What is the problem.
Note i call ajaxdecorator like;
getAjaxCallDecorator().decorateOnFailureScript("some message");
How can i solve these problems.
Thanks
Are you trying to call the failure script without a failure? If that's the case, you could call:
target.appendJavascript("alert('Failure');");
or
target.appendJavascript(getAjaxCallDecorator().decorateOnFailureScript("some message"));
BUT, you are calling setResponsePage() at the end of the onClick() method, I think that could block any scripts from being executed, since you are redirecting to another page instead of simply executing the ajax response.