summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBogDan Vatra <bogdan@kde.org>2013-10-31 18:00:30 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-11-01 09:38:12 +0100
commitb7440536c788b04861591187edd071bf2c2ec137 (patch)
treefe7709f9e0f3aeccddbf4133dbb8948a32878bb9
parentd1114669e301e35cc4e9b2e4c8c4b9476180fb56 (diff)
Android: Handle virtual keyboard visibility changes.
emitInputPanelVisibleChanged when virtual keyboard visibility is changed. Task-number: QTBUG-34347 Change-Id: Iab7374db42ff8ce6f33dcc793b23f84d3c8692d5 Reviewed-by: Paul Olav Tvete <paul.tvete@digia.com>
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java47
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtEditText.java13
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java80
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtNative.java22
-rw-r--r--src/plugins/platforms/android/src/androidjniinput.cpp31
-rw-r--r--src/plugins/platforms/android/src/qandroidinputcontext.cpp5
-rw-r--r--src/plugins/platforms/android/src/qandroidinputcontext.h1
7 files changed, 133 insertions, 66 deletions
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java
index 1f99440428..82533dc9cb 100644
--- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java
@@ -42,13 +42,6 @@
package org.qtproject.qt5.android;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Iterator;
-
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -68,11 +61,18 @@ import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
-import android.view.Surface;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
public class QtActivityDelegate
{
@@ -111,7 +111,7 @@ public class QtActivityDelegate
private boolean m_quitApp = true;
private Process m_debuggerProcess = null; // debugger process
- public boolean m_keyboardIsVisible = false;
+ private boolean m_keyboardIsVisible = false;
public boolean m_backKeyPressedSent = false;
@@ -176,6 +176,13 @@ public class QtActivityDelegate
private final int ApplicationInactive = 0x2;
private final int ApplicationActive = 0x4;
+ public void setKeyboardVisibility(boolean visibility)
+ {
+ if (m_keyboardIsVisible == visibility)
+ return;
+ m_keyboardIsVisible = visibility;
+ QtNative.keyboardVisibilityChanged(m_keyboardIsVisible);
+ }
public void resetSoftwareKeyboard()
{
if (m_imm == null)
@@ -256,27 +263,21 @@ public class QtActivityDelegate
m_editText.postDelayed(new Runnable() {
@Override
public void run() {
- m_imm.showSoftInput(m_editText, 0, new ResultReceiver( new Handler()){
+ m_imm.showSoftInput(m_editText, 0, new ResultReceiver(new Handler()) {
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
switch (resultCode) {
case InputMethodManager.RESULT_SHOWN:
case InputMethodManager.RESULT_UNCHANGED_SHOWN:
- m_keyboardIsVisible = true;
+ setKeyboardVisibility(true);
break;
case InputMethodManager.RESULT_HIDDEN:
case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
- m_keyboardIsVisible = false;
+ setKeyboardVisibility(false);
break;
}
}
- }) ;
- m_editText.postDelayed(new Runnable() {
- @Override
- public void run() {
- m_imm.restartInput(m_editText);
- }
- }, 25);
+ });
}
}, 15);
}
@@ -291,11 +292,11 @@ public class QtActivityDelegate
switch (resultCode) {
case InputMethodManager.RESULT_SHOWN:
case InputMethodManager.RESULT_UNCHANGED_SHOWN:
- m_keyboardIsVisible = true;
+ setKeyboardVisibility(true);
break;
case InputMethodManager.RESULT_HIDDEN:
case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
- m_keyboardIsVisible = false;
+ setKeyboardVisibility(false);
break;
}
}
@@ -612,7 +613,7 @@ public class QtActivityDelegate
}
m_layout = new QtLayout(m_activity);
m_surface = new QtSurface(m_activity, 0);
- m_editText = new QtEditText(m_activity);
+ m_editText = new QtEditText(m_activity, this);
m_imm = (InputMethodManager)m_activity.getSystemService(Context.INPUT_METHOD_SERVICE);
m_layout.addView(m_surface,0);
m_activity.setContentView(m_layout,
@@ -770,7 +771,7 @@ public class QtActivityDelegate
if (keyCode == KeyEvent.KEYCODE_BACK && !m_backKeyPressedSent) {
hideSoftwareKeyboard();
- m_keyboardIsVisible = false;
+ setKeyboardVisibility(false);
return true;
}
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtEditText.java b/src/android/jar/src/org/qtproject/qt5/android/QtEditText.java
index b95e0c070c..7e3ebb539a 100644
--- a/src/android/jar/src/org/qtproject/qt5/android/QtEditText.java
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtEditText.java
@@ -50,10 +50,10 @@ import android.view.inputmethod.InputConnection;
public class QtEditText extends View
{
- QtInputConnection m_inputConnection;
int m_initialCapsMode = 0;
int m_imeOptions = 0;
int m_inputType = InputType.TYPE_CLASS_TEXT;
+ QtActivityDelegate m_activityDelegate;
public void setImeOptions(int m_imeOptions)
{
@@ -71,12 +71,16 @@ public class QtEditText extends View
this.m_inputType = m_inputType;
}
- public QtEditText(Context context)
+ public QtEditText(Context context, QtActivityDelegate activityDelegate)
{
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
- m_inputConnection = new QtInputConnection(this);
+ m_activityDelegate = activityDelegate;
+ }
+ public QtActivityDelegate getActivityDelegate()
+ {
+ return m_activityDelegate;
}
@Override
@@ -86,8 +90,9 @@ public class QtEditText extends View
outAttrs.imeOptions = m_imeOptions;
outAttrs.initialCapsMode = m_initialCapsMode;
outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI;
- return m_inputConnection;
+ return new QtInputConnection(this);
}
+
// // DEBUG CODE
// @Override
// protected void onDraw(Canvas canvas) {
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java b/src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java
index f28ea3be83..4b2d50ca1f 100644
--- a/src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java
@@ -43,7 +43,6 @@
package org.qtproject.qt5.android;
import android.content.Context;
-import android.view.View;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.ExtractedText;
@@ -81,6 +80,22 @@ class QtNativeInputConnection
static native boolean paste();
}
+class HideKeyboardRunnable implements Runnable {
+ private QtInputConnection m_connection;
+ HideKeyboardRunnable(QtInputConnection connection)
+ {
+ m_connection = connection;
+ }
+
+ @Override
+ public void run() {
+ if (m_connection.getInputState() == QtInputConnection.InputStates.Hiding) {
+ QtNative.activityDelegate().setKeyboardVisibility(false);
+ m_connection.reset();
+ }
+ }
+}
+
public class QtInputConnection extends BaseInputConnection
{
private static final int ID_SELECT_ALL = android.R.id.selectAll;
@@ -91,65 +106,83 @@ public class QtInputConnection extends BaseInputConnection
private static final int ID_SWITCH_INPUT_METHOD = android.R.id.switchInputMethod;
private static final int ID_ADD_TO_DICTIONARY = android.R.id.addToDictionary;
- View m_view;
- boolean m_closing;
- public QtInputConnection(View targetView)
+
+ enum InputStates { Visible, FinishComposing, Hiding };
+
+ private QtEditText m_view = null;
+ private InputStates m_inputState = InputStates.Visible;
+
+ public void reset()
+ {
+ m_inputState = InputStates.Visible;
+ }
+
+ public InputStates getInputState()
+ {
+ return m_inputState;
+ }
+
+ private void setClosing(boolean closing)
+ {
+ if (closing && m_inputState == InputStates.Hiding)
+ return;
+
+ if (closing && m_inputState == InputStates.FinishComposing && m_view.getActivityDelegate().isSoftwareKeyboardVisible()) {
+ m_view.postDelayed(new HideKeyboardRunnable(this), 100);
+ m_inputState = InputStates.Hiding;
+ } else {
+ if (m_inputState == InputStates.Hiding)
+ QtNative.activityDelegate().setKeyboardVisibility(true);
+ m_inputState = closing ? InputStates.FinishComposing : InputStates.Visible;
+ }
+ }
+
+ public QtInputConnection(QtEditText targetView)
{
super(targetView, true);
m_view = targetView;
- m_closing = false;
}
@Override
public boolean beginBatchEdit()
{
- m_closing = false;
+ setClosing(false);
return true;
}
@Override
public boolean endBatchEdit()
{
- m_closing = false;
+// setClosing(false);
return true;
}
@Override
public boolean commitCompletion(CompletionInfo text)
{
- m_closing = false;
+ setClosing(false);
return QtNativeInputConnection.commitCompletion(text.getText().toString(), text.getPosition());
}
@Override
public boolean commitText(CharSequence text, int newCursorPosition)
{
- m_closing = false;
+ setClosing(false);
return QtNativeInputConnection.commitText(text.toString(), newCursorPosition);
}
@Override
public boolean deleteSurroundingText(int leftLength, int rightLength)
{
- m_closing = false;
+ setClosing(false);
return QtNativeInputConnection.deleteSurroundingText(leftLength, rightLength);
}
@Override
public boolean finishComposingText()
{
- if (m_closing) {
- m_view.postDelayed(new Runnable() {
- @Override
- public void run() {
- QtNative.activityDelegate().m_keyboardIsVisible=false;
- }
- }, 100); // it seems finishComposingText comes much faster than onKeyUp event,
- // so we must delay hide notification
- m_closing = false;
- } else {
- m_closing = true;
- }
+ // on some/all android devices hide event is not coming, but instead finishComposingText() is called twice
+ setClosing(true);
return QtNativeInputConnection.finishComposingText();
}
@@ -231,18 +264,21 @@ public class QtInputConnection extends BaseInputConnection
@Override
public boolean setComposingText(CharSequence text, int newCursorPosition)
{
+ setClosing(false);
return QtNativeInputConnection.setComposingText(text.toString(), newCursorPosition);
}
@Override
public boolean setComposingRegion(int start, int end)
{
+ setClosing(false);
return QtNativeInputConnection.setComposingRegion(start, end);
}
@Override
public boolean setSelection(int start, int end)
{
+ setClosing(false);
return QtNativeInputConnection.setSelection(start, end);
}
}
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
index b37f1e87fd..67093a007e 100644
--- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
+++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
@@ -418,30 +418,21 @@ public class QtNative
private static boolean isSoftwareKeyboardVisible()
{
- Semaphore semaphore = new Semaphore(1);
- Boolean ret = false;
- class RunnableRes implements Runnable {
- @SuppressWarnings("unused")
- Boolean returnValue = null;
- Semaphore semaphore = null;
- RunnableRes(Boolean ret, Semaphore sem) {
- semaphore = sem;
- returnValue = ret;
- }
+ final Semaphore semaphore = new Semaphore(0);
+ final Boolean[] ret = {false};
+ runAction(new Runnable() {
@Override
public void run() {
- returnValue = m_activityDelegate.isSoftwareKeyboardVisible();
+ ret[0] = m_activityDelegate.isSoftwareKeyboardVisible();
semaphore.release();
}
- }
-
- runAction(new RunnableRes(ret, semaphore));
+ });
try {
semaphore.acquire();
} catch (Exception e) {
e.printStackTrace();
}
- return ret;
+ return ret[0];
}
private static void setFullScreen(final boolean fullScreen)
@@ -568,6 +559,7 @@ public class QtNative
// keyboard methods
public static native void keyDown(int key, int unicode, int modifier);
public static native void keyUp(int key, int unicode, int modifier);
+ public static native void keyboardVisibilityChanged(boolean visibility);
// keyboard methods
// surface methods
diff --git a/src/plugins/platforms/android/src/androidjniinput.cpp b/src/plugins/platforms/android/src/androidjniinput.cpp
index 30d4e69afe..27d29129f8 100644
--- a/src/plugins/platforms/android/src/androidjniinput.cpp
+++ b/src/plugins/platforms/android/src/androidjniinput.cpp
@@ -47,6 +47,10 @@
#include <QTouchEvent>
#include <QPointer>
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+# include <QDebug>
+#endif
+
using namespace QtAndroid;
namespace QtAndroidInput
@@ -86,6 +90,9 @@ namespace QtAndroidInput
width,
height,
inputHints);
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ qDebug() << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints;
+#endif
}
void resetSoftwareKeyboard()
@@ -95,6 +102,9 @@ namespace QtAndroidInput
return;
env.jniEnv->CallStaticVoidMethod(applicationClass(), m_resetSoftwareKeyboardMethodID);
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ qDebug() << "@@@ RESETSOFTWAREKEYBOARD";
+#endif
}
void hideSoftwareKeyboard()
@@ -104,6 +114,9 @@ namespace QtAndroidInput
return;
env.jniEnv->CallStaticVoidMethod(applicationClass(), m_hideSoftwareKeyboardMethodID);
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ qDebug() << "@@@ HIDESOFTWAREKEYBOARD";
+#endif
}
bool isSoftwareKeyboardVisible()
@@ -112,7 +125,11 @@ namespace QtAndroidInput
if (!env.jniEnv)
return false;
- return env.jniEnv->CallStaticBooleanMethod(applicationClass(), m_isSoftwareKeyboardVisibleMethodID);
+ bool visibility = env.jniEnv->CallStaticBooleanMethod(applicationClass(), m_isSoftwareKeyboardVisibleMethodID);
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ qDebug() << "@@@ ISSOFTWAREKEYBOARDVISIBLE" << visibility;
+#endif
+ return visibility;
}
@@ -511,6 +528,15 @@ namespace QtAndroidInput
false);
}
+ static void keyboardVisibilityChanged(JNIEnv */*env*/, jobject /*thiz*/, jboolean /*visibility*/)
+ {
+ QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
+ if (inputContext)
+ inputContext->emitInputPanelVisibleChanged();
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ qDebug() << "@@@ KEYBOARDVISIBILITYCHANGED" << inputContext;
+#endif
+ }
static JNINativeMethod methods[] = {
{"touchBegin","(I)V",(void*)touchBegin},
@@ -521,7 +547,8 @@ namespace QtAndroidInput
{"mouseMove", "(III)V", (void *)mouseMove},
{"longPress", "(III)V", (void *)longPress},
{"keyDown", "(III)V", (void *)keyDown},
- {"keyUp", "(III)V", (void *)keyUp}
+ {"keyUp", "(III)V", (void *)keyUp},
+ {"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged}
};
#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
diff --git a/src/plugins/platforms/android/src/qandroidinputcontext.cpp b/src/plugins/platforms/android/src/qandroidinputcontext.cpp
index 386c8e006a..8556e8ebf1 100644
--- a/src/plugins/platforms/android/src/qandroidinputcontext.cpp
+++ b/src/plugins/platforms/android/src/qandroidinputcontext.cpp
@@ -381,6 +381,11 @@ QAndroidInputContext::~QAndroidInputContext()
m_textFieldID = 0;
}
+QAndroidInputContext *QAndroidInputContext::androidInputContext()
+{
+ return m_androidInputContext;
+}
+
void QAndroidInputContext::reset()
{
clear();
diff --git a/src/plugins/platforms/android/src/qandroidinputcontext.h b/src/plugins/platforms/android/src/qandroidinputcontext.h
index d19dcc384b..041bd0dc49 100644
--- a/src/plugins/platforms/android/src/qandroidinputcontext.h
+++ b/src/plugins/platforms/android/src/qandroidinputcontext.h
@@ -80,6 +80,7 @@ public:
public:
QAndroidInputContext();
~QAndroidInputContext();
+ static QAndroidInputContext * androidInputContext();
bool isValid() const { return true; }
void reset();