Android Studio not recognizing changes in JUCE native Android code / Bug in keyboard

keyboard
android
#1

Important:

PLEASE read the post at the very bottom. Many questions asked prior to that are already somewhat answered. But I encounter a very serious problem in the way that android studio doesn’t want to compile changes in the JUCE native android code, which makes it impossible to debug my error! Please someone give me a hint what to do!

As it turns out there is a serious bug in the JUCE native code that prevents us from releasing our app.

We use TextEditors, to handle user input. Unfortunately you can’t dismiss the soft keyboard. If I press the back key, the keyboard disappears for a brief second and pops up again.

There is already code present that should do this. But it doesn’t.

The JNI function handleKeyboardHiddenJni is defined inside juce_android_Windowing.cpp, and assigned to the member function handleKeyboardHiddenCallback. The method is also implemented correctly (as I would have done as well)

void handleKeyboardHiddenCallback()
{
    Component::unfocusAllComponents();
}

The function gets called inside ComponentPeerView.java within private final class KeyboardDismissListener where apparently it is detected, whether or not it should hide the keyboard

// Arbitrary threshold, surely keyboard would take more than 20 pix.
if (diff < 20 && keyboardShown)
{
    keyboardShown = false;
    handleKeyboardHidden (view.host);
}

if (!keyboardShown && diff > 20)
    keyboardShown = true;

As I wanted to debug this whole thing, I added a breakpoint to handleKeyboardHiddenCallback() inside juce_android_Windowing.cpp, but the method is never called!

I would handle the keyboard dismiss by myself, but unfortunately, the backButtonPressed() function of juce_ApplicationBase that I have overriden in my Main.cpp (which implements JUCEApplication), is not called when dismissing the keyboard. I have to press the back button twice (once for the keyboard and then for the “application”), for backButtonPressed() to trigger!

I would be so happy about a quick reply with a working fix or workaround as we obviously can’t release our app with this non intuitive and odd behaviour.

Thanks a lot

EDIT 1:
Apparently there are some commits which mention either the keyboard or focusing the TextEditor:




and also a fix for a crash bug I had encountered not too long ago

But all these commits don’t seem to solve the issue I have described, as I tried both with the newest master branch and the newest develop branch.

EDIT 2:
This is really weird. I somehow got it to work once. Also the delay after whichthe keyboard reappears is completely random. Sometimes you don’t even notice it and on some other occasions, you can see it “slide” down and “slide” back up again. I have a slight suspicion, it might have something to do with the arbitrary threshold, which is described in the comment

// Arbitrary threshold, surely keyboard would take more than 20 pix.
if (diff < 20 && keyboardShown)
{
...

the thing I have no clue about is that the keyboard indeed gets dismissed! But just for a brief second before it appears again (except the one time I somehow managed to dispose it).
But in my opinion the keyboard is never even dismissed by JUCE itself (so the handleKeyboardHidden (view.host); is never triggered), because the method handleKeyboardHiddenCallback() is never triggered!
God this makes no sense

0 Likes

#2

Nobody got a solution for this? I really can’t imagine it being a huge bug, but I don’t know how to try and figure out whats the problem …

0 Likes

#3

I have investigated that problem further and it seems, as if onGlobalLayout of class TreeObserver within KeyboardDismissListener inside the file ComponentPeerView.java is never called as I think it is supposed to! Because of this, the method can’t do its job properly, which would be hiding the keyboard.
Can someone please assist me with this?
@ed95 You are somewhat familiar with this, aren’t you? As I have seen you did the fix for the back button crash as well… Maybe you can shine some light on this oddity

0 Likes

#4

HELP! My brain!
Ok so it turns out that onGlobalLayout is never called, if I simply press the back button once (as one would hide the keyboard in any other app), but I have to press back and then press a button for example, in order for onGlobalLayout to be called, which means that onGlobalLayout is not called, when simply pressing the back button, in other word hiding the keyboard doesn’t induce a layout change, which is really weird!
Can someone please look into this? I have no idea what to do to solve this!

0 Likes

#5

As mentioned here (answer by Kachi), onGlobalLayout is only called for dismissing the keyboard

if you set your windowSoftInputMode to adjustResize

Can I do that from the projucer?

0 Likes

#6

I now tried with adjustResize. It’s really wonky. But nevertheless it doesn’t solve the problem. The keyboard not disappearing issue still persists. But now I mentioned through debugging that in the whole method

@Override
public void onGlobalLayout ()
{
    Rect r = new Rect ();

    View parentView = getRootView ();
    int diff = 0;

    if (parentView == null)
    {
        getWindowVisibleDisplayFrame (r);
        diff = getHeight () - (r.bottom - r.top);
    } else
    {
        parentView.getWindowVisibleDisplayFrame (r);
        diff = parentView.getHeight () - (r.bottom - r.top);
    }

    // Arbitrary threshold, surely keyboard would take more than 20 pix.
    if (diff < 20 && keyboardShown)
    {
        keyboardShown = false;
        handleKeyboardHidden (view.host);
    }

    if (!keyboardShown && diff > 20)
        keyboardShown = true;
}

the part

if (diff < 20 && keyboardShown)
{
    keyboardShown = false;
    handleKeyboardHidden (view.host);
}

if (!keyboardShown && diff > 20)
    keyboardShown = true;

is never called, because r has the values bottom = 10000, left = -10000, right = 10000, top = -10000 and there fore the diff value is -18898 in my case! This leads to both of the conditionals never triggering and therefore neither modifying keyboardShown nor triggering handleKeyboardHidden

Shouldn’t the second if rather be an else?

0 Likes

#7

Now I’m trying to play around with ComponentPeerView.java, but it doesn’t care! If I debug the application I get an error that the source code doesn’t match the byte code!
I did everything: clean, rebuild, refresh linked c++ project, gradlew clean, buildDependents, restart Android Studio, invalidate caches and restart, delete caches dir in ~/.gradle, etc pp! It just doesn’t care!

PLEASE someone help me PLEASE. Don’t let me alone with this. I have no idea what to do at this point, my client wants a working app and I have no freaking clue what to do. I understand that some of you have more important stuff to do, but maybe someone (@ed95, @jules, @t0m? I don’t know… someone) can tell me what to do in order for Android Studio to accept my damn changes and not to just ignore them!!!
I can do what I want, it just doesn’t incorporate my changes in juce_gui_basic/native/java/app/com/roli/juce/ComponentPeerView.java in the resulting binary. I even deleted the complete Android folder!!! Nothing. It doesn’t care! I have no idea what to do. I would love to debug this myself and come up with a solution, but how if the changes I make are not compiled!

0 Likes

#8

The keyboard bouncing issue is due to TextEditor::checkFocus() being called on a timer and calling ComponentPeer::textInputRequired(), which is causing the keyboard to be immediately shown again after being dismissed with the back button. I’ve pushed this commit to develop and it seems to fix the issue.

However, the issue with getWindowVisibleDisplayFrame() returning an invalid frame for the View is still present meaning that the keyboard dismissed callback won’t be called and the text editor won’t be unfocused when the keyboard is dismissed. I’ve spent a while looking into this but can’t figure out exactly what’s going on here - the Android code in JUCE has changed quite a bit recently and the way that the Views are structured for JUCE’s ComponentPeers might be the culprit.

As for how to debug the java code, you’ll need to move the juce_gui_basics/native/java/app/com/roli/juce/ComponentPeerView.java file to juce_gui_basics/native/javacore/app/com/roli/juce/ComponentPeerView.java and change line 899 in juce_android_Windowing.cpp from:

DECLARE_JNI_CLASS_WITH_BYTECODE (ComponentPeerView, "com/roli/juce/ComponentPeerView", 16, javaComponentPeerView, sizeof (javaComponentPeerView))

to:

DECLARE_JNI_CLASS_WITH_MIN_SDK (ComponentPeerView, "com/roli/juce/ComponentPeerView", 16)

This way you can debug the .java file directly instead of using the compiled bytecode that is at the top of that file.

0 Likes

#9

Thanks. I’ll have a look at this then, now that I know how to debug things. But one problem still persists: onGlobalLayout doesn’t work the intended way if windowSoftInputMode isn’t set to adjustResize! But in my case for example I’d rather not have adjustResize enabled, as it doesn’t produce the behavior I want. I’ll look into this as there were some other suggested approaches of how to detect whether the keyboard is dismissed, which could also solve the issue with getWindowVisibleDisplayFrane()

0 Likes

#10

Ok so I checked this and the keyboard not bouncing back is a HUGE improvement! Thanks for the quick fix!

As for the other problem I might have some time to look into this.

0 Likes