javascriptandroidwebviewandroid-softkeyboardgoogle-chrome-android

How to avoid the Android keyboard is closed automatically after I click on an Input to type on it?


My PWA had been working fine for several years until recently. Now, it seems there is a new problem with the keyboard because I cannot type anything at all.

My bug, in my opinion, is related to another well-known issue: "Web apps are resized against our will when we open the keyboard." (I'm wondering how Twitter does since it doesn't resize when I do click on the input).

bug

These are some pieces of my code. I wrote them trying to prevent the app to be resized:

HTML:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">

Javascript:

window.onresize = function() {
    resizeScreen();
};

function resizeScreen() {
    let scaleVal = window.innerHeight / 600;
    if (window.innerHeight < 514) {
        if (externalContainer === null) {
            let bodyTmp = document.body;
            let divTmp = document.createElement("div");
            divTmp.id = 'externalContainer';
            bodyTmp.insertBefore(divTmp, bodyTmp.firstChild);
        }
        externalContainer = document.getElementById('externalContainer');
        let sContainer = document.getElementById('superContainer');
        externalContainer.append(sContainer);
        externalContainer.style.height = `${window.innerHeight}px`;
        sContainer.style.transformOrigin = "50% 0% 0px";

        setTimeout(function() {
            sContainer.style.transform = `scale(${scaleVal})`;
            setTimeout(function() {
                let cHeight = (1 + scaleVal) * window.innerHeight;
                if (cHeight < 514)
                    cHeight = 514;
                sContainer.style.height = `${cHeight}px`;
            }, 100);
        }, 100);
    } else {
        let sContainer = document.getElementById('superContainer');
        sContainer.style.height = `${window.innerHeight}px`;
        sContainer.style.transformOrigin = "50% 0% 0px";

        setTimeout(function() {
            sContainer.style.transform = `scale(${scaleVal})`;
        }, 100);

        setTimeout(function() {
            if (cmbSpeechType.getBoundingClientRect().width > window.outerWidth)
                sContainer.style.transform = `scale(${scaleVal - (scaleVal - cmbSpeechType.getBoundingClientRect().width / window.outerWidth)})`;
        }, 100);
    }
}

In order to fix the "native app" (a custom version that I wrote), I added: android:windowSoftInputMode="adjustNothing", but I couldn't find any alternative in JS. I tried to emulate it using onfocus="window.location.href='#id'; return true;" but it didn't work. This point about adjustNothing has been suggested in Chromium since 2014.

I also tried setting a min-height in CSS equals to the window height, but it didn't change the problem.

Furthermore, I tried this other crazy idea of making floating the control, it didn't work:

txtSpeaker.addEventListener("onfocus", function() {
    window.body.style.zIndex = -1;
    txtSpeaker.style.zIndex = 1000;
});

txtSpeaker.addEventListener("onblur", function() {
    window.body.style.zIndex = "";
    txtSpeaker.style.zIndex = "";
});

You can check the full source code here:

https://github.com/FANMixco/toastmasters-timer-material-design

Also, here is the app:

https://fanmixco.github.io/toastmasters-timer-material-design

The main source sections are here:

Any idea how to fix this odd issue?

P.S.:

This is an Android-specific bug because, on iOS and Windows 10, the PWA is working fine. After all, the view is not resized.


Solution

  • I kind of fixed it by doing the following:

    function androidOrIOS() {
        const userAgent = navigator.userAgent;
        if(/android/i.test(userAgent)){
            return 'android';
        }
        if(/iPad|iPhone|iPod/i.test(userAgent)){
            return 'ios';
        }
    }
    
    var os = androidOrIOS();
    
    //Only resize if it´s Android
    if (os !== "Android") {
        window.onresize = function() {
            resizeScreen();
        };
    }
    
    
    //Change the location of the body based on the location that I "need".
    if (os === "Android") {
        txtSpeaker.addEventListener("onfocus", function() {
            let y = document.getElementById("playControl").getBoundingClientRect().y;
            document.body.marginTop = `-${y}px`;
        });
        
        txtSpeaker.addEventListener("onblur", function() {
            document.body.marginTop = '0px';
        });
    }
    

    The function androidOrIOS is based on https://stackoverflow.com/a/51911220/1928691.