Mobile back button activates twice - javascript

I've got a function that makes use of the back button on Android Phones but for some reason when I use it, the app goes back 2 pages instead of the intended one.
This is what my code looks like at the moment:
function onBackKeyDown()
{
currentPage = $.mobile.activePage.attr('id');
if(currentPage == "createUser")
{
$.mobile.changePage("#logIn");
alert("Return To Login Page");
currentPage = "";
}
else if(currentPage == "cardDetails")
{
$.mobile.changePage("#createUser");
alert("Return To Create User");
currentPage = "";
}
else if(currentPage == "mainMenu")
{
$.mobile.changePage("#logIn");
alert("Return To Log In");
currentPage = "";
}
else if(currentPage == "locationPage")
{
$.mobile.changePage("#mainMenu");
alert("Return To Main Menu");
currentPage = "";
}
else if(currentPage == "editUserPage")
{
$.mobile.changePage("#mainMenu");
alert("Return To Main Menu");
currentPage = "";
}
else if(currentPage == "editCardDetailsPage")
{
$.mobile.changePage("#editUserPage");
alert("Return To Edit User");
currentPage = "";
}
else
alert("TEST");
}
For example if I were to be incardDetailsand I pushed the back button it would go back tocreateUserand continue back tologIn. Is there anything in my code that would cause this, I've tried resetting the currentPage to empty and added in else thinking that it was going though each of them individually when they were just if statements
EDIT: Requested Java Code:
import android.os.Bundle;
import org.apache.cordova.DroidGap;
public class FnBApp extends DroidGap {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
super.loadUrl("file:///android_asset/www/index.html");
}
}
Any help would be appreciated
John

You need to overload the android back button instead of just detecting and acting on it.
remove your key listener or return true when you have KEY_BACK
you just need the following to catch back key (make sure not to call super)
Also, if you plan on having a service run in the background, make sure to look at startForeground() and make sure to have an ongoing notification or android will kill your service if it needs to free memory
#Override
public void onBackPressed() {
Log.d("CDA", "onBackPressed Called");
Intent setIntent = new Intent(Intent.ACTION_MAIN);
setIntent.addCategory(Intent.CATEGORY_HOME);
setIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(setIntent);
}
Update: Changes for app specific psuedocode
public class FnBApp extends DroidGap {
....
#Override
public void onBackPressed() {
Log.d("CDA", "onBackPressed Called");
//if super.getUrl shows a specific page:
if() {
super.loadUrl("file://android_asset/www/index.html#login");
};
}
Android - How To Override the "Back" button so it doesn't Finish() my Activity?

If you are using Cordova, maybe you want to use your code in other devices apart from Android? In which case you don't want to use any Java at all. Going back to the original question, would this help?:
function onDeviceReady() {
// Register the event listener
document.addEventListener("backbutton", onBackKeyDown, false);
}
(taken from this post)

Related

Android[Kotlin] - ERROR TypeError: ["Android"].showToast is not a function

I am loading the webpage in webview using WebChromeClient(). The webpage has a dropdown whenever the user select's item from that dropdown I need to show a toast. For this, I'm following official doc I've implemented the same as the doc says. still, I'm getting the error in the console. "showToast is not a function".
In Fragment:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val webSettings = webView.settings
webSettings.javaScriptEnabled = true
webSettings.domStorageEnabled = true
webSettings.databaseEnabled = true
webView.addJavascriptInterface(WebAppInterface(requireContext()), "Android")
webView.webChromeClient = object : WebChromeClient() {
override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean {
Log.i(TAG, consoleMessage.message())
return true
}
override fun onProgressChanged(view: WebView?, newProgress: Int) {
super.onProgressChanged(view, newProgress)
if (newProgress == 100) {
if (webView != null) {
webView.settings.builtInZoomControls = true
webView.settings.displayZoomControls = false
webView.loadUrl("javascript:loadMobileDashboard($data);")
}
}
}
}
webView.loadUrl(url)
}
WebAppInterface:
class WebAppInterface(private val context: Context) {
private val TAG = WebAppInterface::class.java.simpleName
#JavascriptInterface
fun showToast(toast: String) {
Log.d(TAG, "showToast: $toast")
}
}
I tried several changes and searched about it on the internet didn't work single solution. Please let me know what mistake am making here. Thanks :)
Create an html page in your assets folder, let's say named dropDown.html.
Copy this code into that file
<input type="dropDown" value="Hello" onClick="showToastInWebView('strMsg')" />
<script type="text/javascript">
function showToastInWebView(toast) {
Android.showToast(toast);
}
</script>
Now load url like this
myWebView.loadUrl("file:///android_asset/dropDown.html");
Note: webView does not invoke the JS function you have added a bridge to, You need to use your own webpage(in this case which is dropDown.html) that does indeed invoke the function, either local(our case) or on the web.

cordova inAppBrowser "Before Exit" event

I have a cordova (android) app with window popout using window.open javascript that override with cordova inAppBrowser when device is ready refer to the code below:
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
window.open = cordova.InAppBrowser.open;
}
Then i want to set an event when user press phone back button or press "x" button to close the popout a dialog will pop out and asked "Are you sure? Y/N" before closing window popout. The code look like this:
var newwindow;
newwindow = window.open('something', '_self ', 'location=no');
newwindow.addEventListener('exit', function(event){ Exit() });
function Exit(){
navigator.notification.confirm(
'Are you sure?',
function(i){
if(i==2)
{
//exit the window popout
}
},
'App Name',
'Cancel,Exit'
);
But it doesn't work as i wanted, the popout window closed then dialog is prompt to user...How can i show a dialog and decides whether to close popout window.
Note: Sorry for bad grammar, i try my best to explain my problem.
I have found a fairly easy solution (android) for simple prompt like "Are you sure" "yes/no?" by editing the inappbrowser.dialog.java file. This solution is only prompting for confirmation before closing inappbrowser, which is suitable for my case.
Modify the java file InAppBrowserDialog.java in this location:
[your cordova project]/platforms/android/src/org/apache/cordova/inappbrowser/
ADD REQUIRED IMPORTS:
import android.content.DialogInterface;
MODIFY THE onBackPressed() FUNCTION
FROM:
public void onBackPressed () {
if (this.inAppBrowser == null) {
this.dismiss();
} else {
// better to go through the in inAppBrowser
// because it does a clean up
if (this.inAppBrowser.hardwareBack() && this.inAppBrowser.canGoBack()) {
this.inAppBrowser.goBack();
} else {
this.inAppBrowser.closeDialog();
}
}
}
TO:
public void onBackPressed() {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context)
.setTitle("Exit")
.setMessage("You are about to exit, are you sure?")
.setPositiveButton("Exit", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int which){
if (inAppBrowser == null) {
dismiss();
}
else {
// better to go through the in inAppBrowser
// because it does a clean up
if (inAppBrowser.hardwareBack() && inAppBrowser.canGoBack()) {
inAppBrowser.goBack();
} else {
inAppBrowser.closeDialog();
}
}
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog,int which){
dialog.cancel();
}
});
alertDialogBuilder.create();
alertDialogBuilder.show();
}
I basically just create an alert dialog on top of checking for inappbrowser when back button is pressed.

Using onBackPressed with Cordova backbutton

I asked a similar question before but I'm hoping with additional information and with what I learnt from the previous question I might be able to solve my issue.
I need to be able to use the back button on my Android phone. At the moment I have the Cordova backbutton implemented which caused the application to go back 2 pages per click.
I should also mention that my app is build around JavaScript, HTML and CSS with very minimal Java as you will see below.
Backbutton JS code:
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
//alert ('123');
document.addEventListener('backbutton', onBackKeyDown, false);
}
function onBackKeyDown()
{
currentPage = $.mobile.activePage.attr('id');
if(currentPage == "createUser"){
$.mobile.changePage("#logIn");
alert("Return To Login Page");
}
if(currentPage == "cardDetails"){
$.mobile.changePage("#createUser");
alert("Return to Create User");
}
if(currentPage == "mainMenu"){
$.mobile.changePage("#logIn");
alert("Return To Log In");
}
if(currentPage == "locationPage"){
$.mobile.changePage("#mainMenu");
alert("Return To Main Menu");
$("#pId").empty();
}
if(currentPage == "editUserPage")
{
$.mobile.changePage("#mainMenu");
alert("Return To Main Menu");
$("#trId").empty();
}
if(currentPage == "editCardDetailsPage")
{
$.mobile.changePage("#editUserPage");
alert("Return To Edit User");
}
}
I was told to implement a onBackPressed function inside my java file. I'm not very experienced in Java but with a bit of help I was able to figure out where the code goes
Java code:
import android.os.Bundle;
import org.apache.cordova.DroidGap;
public class FnBApp extends DroidGap {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
super.loadUrl("file:///android_asset/www/index.html");
}
#Override
public void onBackPressed() {
//Log.d("CDA", "onBackPressed Called");
//if super.getUrl shows a specific page:
if() {
super.loadUrl("file://android_asset/www/index.html#login");
};
}
}
Now I'm not sure what I should put in the if statement in the Java file I've tried WebView, AppView and a few other things to no avail and from what I can see using Java will only change the page which if that is all I wanted to do I wouldn't need to edit the back button functions but as I have placed in the backbutton js code, I also need to run some DOM functions as well.
Is there a way to be able to run the DOM functions in conjunction with the Java
If any more clarification is needed let me know.
John
So the problem is that the backbutton fires two events because it goes back to page. What you need to do in JavaScript is to stop the event propagation.
So, you need to get the event on the onBackKeyDown and stop propagation with event.preventDefault();. You don't need Java.
function onBackKeyDown(event)
{
currentPage = $.mobile.activePage.attr('id');
if(currentPage == "createUser"){
$.mobile.changePage("#logIn");
alert("Return To Login Page");
}
if(currentPage == "cardDetails"){
$.mobile.changePage("#createUser");
alert("Return to Create User");
}
if(currentPage == "mainMenu"){
$.mobile.changePage("#logIn");
alert("Return To Log In");
}
if(currentPage == "locationPage"){
$.mobile.changePage("#mainMenu");
alert("Return To Main Menu");
$("#pId").empty();
}
if(currentPage == "editUserPage")
{
$.mobile.changePage("#mainMenu");
alert("Return To Main Menu");
$("#trId").empty();
}
if(currentPage == "editCardDetailsPage")
{
$.mobile.changePage("#editUserPage");
alert("Return To Edit User");
}
event.preventDefault();
}

How to close html dialog in Android on press of back key

I have created a webview in Android in which i am loading my html file.At the time of clicking a button i am displaying a pop up like alert dialog which is developed in html itself.
Now problem is as soon as i press back button on android phone,application is returning to previous page.But with identical behavior only dialog should be closed and application should be on same page.
How can i achieve it?
Thanks
I think you do not need the JavascriptInterface (as #Henil posted). I would do it like so:
in Java - onBackPressed:
if (webView.getUrl.equals("yourPopupUrl.com")) {
webView.loadUrl("javascript:goAwayPopup();");
return;
}
in JS:
function goAwayPopup() {
var popUp = document.getElementById("popUp"); // in my case popUp is just a <div>
var isVisible = popUp .offsetWidth > 0 || popUp .offsetHeight > 0;
if (isVisible) {
popUp.style.display = 'none';
}
}
EDIT:
Solution with JavascriptInterface:
in JS - function which is called when dialog popups:
function popUp() {
if (typeof Android != "undefined"){
if (Android.popUp!= "undefined") {
Android.popUp();
}
}
}
in Java:
define a inner class and a boolean field in your Activity
declare the bridge to your webview
override onBackPressed
private boolean isPopUpVisible = false;
// some code...
webView.addJavascriptInterface(new MyJavascriptBridge(), "Android");
// some code...
class MyJavascriptBridge {
public void popUp() {
if (isPopUpVisible)
isPopUpVisible = false;
else
isPopUpVisible = true;
}
}
onBackPressed:
if (isPopUpVisible) {
webView.loadUrl("javascript:goAwayPopup();");
return;
}
JS, again:
function goAwayPopup() {
// close alert here...
popUp(); // sets isPopUpVisible to false
}
Here is a post of closing a alert: How to "auto close" Alert boxes
Use java script interface and handle html page from that interface

WebView loadURL("javascript:XYZ") get executed several times in my webview

I have a webview that shows a message to confirm an user interaction. That message should fade out after any user interaction somewhere else on that page. To do this I detect any onTouchEvent and inject back a call to the webpage to trigger the message to fade out.
This works well for the first time but if I do it a second time (the webpage is not reloaded but the message is shown again through javascript by setting opacity back to 1 and display to "block") the message appears again but then fades out immediately w/o any user interactions. From the log statement I can see that the onTouchEvent does not get triggered and I do not inject the javascript.
I suspect that the loadURL creates some resilient call in the webpage that sticks around and somehow activates again.
Is there any way to clear this and see this executed only once ?
I catch the onTouchEvent in my WebView like this:
final class MyWebView extends WebView {
...
#Override
public boolean onTouchEvent(MotionEvent event) {
Log.v(TAG,"onTouchEvent");
if (mUndoActive && (event.getAction() == MotionEvent.ACTION_DOWN)) {
mUndoActive = false;
mLastAction = LAST_ACTION_NONE;
Log.v(TAG,"send hide message");
handler.sendEmptyMessageDelayed(CLICK_ON_WEBVIEW, 300);
}
return super.onTouchEvent(event);
}
}
In the parent activity I override the handleMessage and inject a javascript to my webview to trigger the javascript that fades out a message element like this:
#Override
public boolean handleMessage(Message msg) {
Log.v(TAG,"handleMessage triggered");
if (msg.what == CLICK_ON_WEBVIEW){
Log.v(TAG,"handle message registerd click from stack view web page");
webview.loadUrl("javascript:hideMessage()");
return true;
}
return false;
}
and the javascript in the webview is:
function hideMessage() {
var message = document.getElementById("message");
if (message != null) {
if (!message.style.opacity) {
message.style.opacity = 1;
}
var fader = setInterval(function(){
message.style.opacity -= .02;
if (message.style.opacity <= 0) {
clearInterval(fader);
message.style.display = "none";
}
}, 25);
}
}
I found a soulution myself: Preceding the 2 Interval calls with window, ie. window.clearInterval(fader) did fix the issue. I don't quite understand why but it looks like the interval timer did keep running permanently and was not properly turned off.

Categories