Android: Implement QInputMethod::keyboardRectangle

We can use getWindowVisibleDisplayFrame to know the height on the
keyboard, and we can use getLocationOnScreen to find out how much
the view is scrolled. Since onPreDraw is always called when the
view is scrolled or when the keyboard appears or disapear, we can
call the native functions from there.

This is not working for floating keyboards.

[ChangeLog][Android] Implemented QInputMethod::keyboardRectangle

Task-number: QTBUG-40731
Change-Id: I7848eb34fece410b29a06bf0bbb2313112fffa68
Reviewed-by: Samuel Nevala <samuel.nevala@intopalo.com>
Reviewed-by: BogDan Vatra <bogdan@kdab.com>
bb10
Olivier Goffart 2015-12-05 13:23:26 +01:00 committed by Olivier Goffart (Woboq GmbH)
parent 7908da98f0
commit 420b4dbece
6 changed files with 58 additions and 3 deletions

View File

@ -66,6 +66,8 @@ import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.view.ViewTreeObserver;
import android.graphics.Rect;
import java.io.BufferedReader;
import java.io.DataOutputStream;
@ -859,6 +861,25 @@ public class QtActivityDelegate
QtNative.handleOrientationChanged(rotation, m_nativeOrientation);
m_currentRotation = rotation;
m_layout.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if (!m_keyboardIsVisible)
return true;
Rect r = new Rect();
m_activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
DisplayMetrics metrics = new DisplayMetrics();
m_activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
final int kbHeight = metrics.heightPixels - r.bottom;
final int[] location = new int[2];
m_layout.getLocationOnScreen(location);
QtNative.keyboardGeometryChanged(location[0], r.bottom - location[1],
r.width(), kbHeight);
return true;
}
});
}
public void initializeAccessibility()

View File

@ -677,6 +677,7 @@ public class QtNative
public static native void keyDown(int key, int unicode, int modifier, boolean autoRepeat);
public static native void keyUp(int key, int unicode, int modifier, boolean autoRepeat);
public static native void keyboardVisibilityChanged(boolean visibility);
public static native void keyboardGeometryChanged(int x, int y, int width, int height);
// keyboard methods
// dispatch events methods

View File

@ -147,6 +147,9 @@ QRectF QInputMethod::cursorRectangle() const
/*!
\property QInputMethod::keyboardRectangle
\brief Virtual keyboard's geometry in window coordinates.
This might be an empty rectangle if it is not possible to know the geometry
of the keyboard. This is the case for a floating keyboard on android.
*/
QRectF QInputMethod::keyboardRectangle() const
{

View File

@ -51,6 +51,7 @@ namespace QtAndroidInput
static bool m_ignoreMouseEvents = false;
static bool m_softwareKeyboardVisible = false;
static QRect m_softwareKeyboardRect;
static QList<QWindowSystemInterface::TouchPoint> m_touchPoints;
@ -108,6 +109,11 @@ namespace QtAndroidInput
return m_softwareKeyboardVisible;
}
QRect softwareKeyboardRect()
{
return m_softwareKeyboardRect;
}
static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
{
@ -734,14 +740,35 @@ namespace QtAndroidInput
static void keyboardVisibilityChanged(JNIEnv */*env*/, jobject /*thiz*/, jboolean visibility)
{
m_softwareKeyboardVisible = visibility;
if (!visibility)
m_softwareKeyboardRect = QRect();
QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
if (inputContext && qGuiApp)
if (inputContext && qGuiApp) {
inputContext->emitInputPanelVisibleChanged();
if (!visibility)
inputContext->emitKeyboardRectChanged();
}
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ KEYBOARDVISIBILITYCHANGED" << inputContext;
#endif
}
static void keyboardGeometryChanged(JNIEnv */*env*/, jobject /*thiz*/, jint x, jint y, jint w, jint h)
{
QRect r = QRect(x, y, w, h);
if (r == m_softwareKeyboardRect)
return;
m_softwareKeyboardRect = r;
QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
if (inputContext && qGuiApp)
inputContext->emitKeyboardRectChanged();
#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
qDebug() << "@@@ KEYBOARDRECTCHANGED" << m_softwareKeyboardRect;
#endif
}
static JNINativeMethod methods[] = {
{"touchBegin","(I)V",(void*)touchBegin},
{"touchAdd","(IIIZIIFF)V",(void*)touchAdd},
@ -753,7 +780,8 @@ namespace QtAndroidInput
{"tabletEvent", "(IIJIIIFFF)V", (void *)tabletEvent},
{"keyDown", "(IIIZ)V", (void *)keyDown},
{"keyUp", "(IIIZ)V", (void *)keyUp},
{"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged}
{"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged},
{"keyboardGeometryChanged", "(IIII)V", (void *)keyboardGeometryChanged}
};
bool registerNatives(JNIEnv *env)

View File

@ -35,6 +35,7 @@
#define ANDROIDJNIINPUT_H
#include <jni.h>
#include <QtCore/qglobal.h>
#include <QtCore/QRect>
QT_BEGIN_NAMESPACE
@ -45,6 +46,7 @@ namespace QtAndroidInput
void resetSoftwareKeyboard();
void hideSoftwareKeyboard();
bool isSoftwareKeyboardVisible();
QRect softwareKeyboardRect();
void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd);
// Software keyboard support

View File

@ -512,7 +512,7 @@ void QAndroidInputContext::invokeAction(QInputMethod::Action action, int cursorP
QRectF QAndroidInputContext::keyboardRect() const
{
return QPlatformInputContext::keyboardRect();
return QtAndroidInput::softwareKeyboardRect();
}
bool QAndroidInputContext::isAnimating() const