summaryrefslogtreecommitdiffstats
path: root/src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java')
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java327
1 files changed, 327 insertions, 0 deletions
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java b/src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java
new file mode 100644
index 0000000000..1bfe05e7ac
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java
@@ -0,0 +1,327 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.content.Context;
+import android.os.Build;
+import android.util.Log;
+import android.view.WindowMetrics;
+import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputMethodManager;
+import android.view.KeyEvent;
+import android.graphics.Rect;
+import android.app.Activity;
+import android.util.DisplayMetrics;
+
+class QtExtractedText
+{
+ public int partialEndOffset;
+ public int partialStartOffset;
+ public int selectionEnd;
+ public int selectionStart;
+ public int startOffset;
+ public String text;
+}
+
+class QtNativeInputConnection
+{
+ static native boolean beginBatchEdit();
+ static native boolean endBatchEdit();
+ static native boolean commitText(String text, int newCursorPosition);
+ static native boolean commitCompletion(String text, int position);
+ static native boolean deleteSurroundingText(int leftLength, int rightLength);
+ static native boolean finishComposingText();
+ static native int getCursorCapsMode(int reqModes);
+ static native QtExtractedText getExtractedText(int hintMaxChars, int hintMaxLines, int flags);
+ static native String getSelectedText(int flags);
+ static native String getTextAfterCursor(int length, int flags);
+ static native String getTextBeforeCursor(int length, int flags);
+ static native boolean setComposingText(String text, int newCursorPosition);
+ static native boolean setComposingRegion(int start, int end);
+ static native boolean setSelection(int start, int end);
+ static native boolean selectAll();
+ static native boolean cut();
+ static native boolean copy();
+ static native boolean copyURL();
+ static native boolean paste();
+ static native boolean updateCursorPosition();
+ static native void reportFullscreenMode(boolean enabled);
+ static native boolean fullscreenMode();
+}
+
+class QtInputConnection extends BaseInputConnection
+{
+ private static final int ID_SELECT_ALL = android.R.id.selectAll;
+ private static final int ID_CUT = android.R.id.cut;
+ private static final int ID_COPY = android.R.id.copy;
+ private static final int ID_PASTE = android.R.id.paste;
+ private static final int ID_COPY_URL = android.R.id.copyUrl;
+ private static final int ID_SWITCH_INPUT_METHOD = android.R.id.switchInputMethod;
+ private static final int ID_ADD_TO_DICTIONARY = android.R.id.addToDictionary;
+
+ private static final String QtTAG = "QtInputConnection";
+
+ private final QtInputConnectionListener m_qtInputConnectionListener;
+
+ class HideKeyboardRunnable implements Runnable {
+ @Override
+ public void run() {
+ // Check that the keyboard is really no longer there.
+ Activity activity = QtNative.activity();
+ if (activity == null) {
+ Log.w(QtTAG, "HideKeyboardRunnable: The activity reference is null");
+ return;
+ }
+
+ Rect r = new Rect();
+ activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
+
+ int screenHeight;
+ if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+ DisplayMetrics metrics = new DisplayMetrics();
+ activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ screenHeight = metrics.heightPixels;
+ } else {
+ final WindowMetrics maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics();
+ screenHeight = maximumWindowMetrics.getBounds().height();
+ }
+ final int kbHeight = screenHeight - r.bottom;
+ if (kbHeight < 100)
+ m_qtInputConnectionListener.onHideKeyboardRunnableDone(false, System.nanoTime());
+ }
+ }
+
+ public interface QtInputConnectionListener {
+ void onSetClosing(boolean closing);
+ void onHideKeyboardRunnableDone(boolean visibility, long hideTimeStamp);
+ void onSendKeyEventDefaultCase();
+ }
+
+ private final QtEditText m_view;
+ private final InputMethodManager m_imm;
+
+ private void setClosing(boolean closing)
+ {
+ if (closing)
+ m_view.postDelayed(new HideKeyboardRunnable(), 100);
+ else
+ m_qtInputConnectionListener.onSetClosing(false);
+ }
+
+ public QtInputConnection(QtEditText targetView, QtInputConnectionListener listener)
+ {
+ super(targetView, true);
+ m_view = targetView;
+ m_imm = (InputMethodManager)m_view.getContext().getSystemService(
+ Context.INPUT_METHOD_SERVICE);
+ m_qtInputConnectionListener = listener;
+ }
+
+ public void restartImmInput()
+ {
+ if (QtNativeInputConnection.fullscreenMode()) {
+ if (m_imm != null)
+ m_imm.restartInput(m_view);
+ }
+
+ }
+
+ @Override
+ public boolean beginBatchEdit()
+ {
+ setClosing(false);
+ return QtNativeInputConnection.beginBatchEdit();
+ }
+
+ @Override
+ public boolean reportFullscreenMode (boolean enabled)
+ {
+ QtNativeInputConnection.reportFullscreenMode(enabled);
+ // Always ignored on calling editor.
+ // Always false on Android 8 and later, true with earlier.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
+ return false;
+
+ return true;
+ }
+
+ @Override
+ public boolean endBatchEdit()
+ {
+ setClosing(false);
+ return QtNativeInputConnection.endBatchEdit();
+ }
+
+ @Override
+ public boolean commitCompletion(CompletionInfo text)
+ {
+ setClosing(false);
+ return QtNativeInputConnection.commitCompletion(text.getText().toString(), text.getPosition());
+ }
+
+ @Override
+ public boolean commitText(CharSequence text, int newCursorPosition)
+ {
+ setClosing(false);
+ restartImmInput();
+ return QtNativeInputConnection.commitText(text.toString(), newCursorPosition);
+ }
+
+ @Override
+ public boolean deleteSurroundingText(int leftLength, int rightLength)
+ {
+ setClosing(false);
+ return QtNativeInputConnection.deleteSurroundingText(leftLength, rightLength);
+ }
+
+ @Override
+ public boolean finishComposingText()
+ {
+ // on some/all android devices hide event is not coming, but instead finishComposingText() is called twice
+ setClosing(true);
+ return QtNativeInputConnection.finishComposingText();
+ }
+
+ @Override
+ public int getCursorCapsMode(int reqModes)
+ {
+ return QtNativeInputConnection.getCursorCapsMode(reqModes);
+ }
+
+ @Override
+ public ExtractedText getExtractedText(ExtractedTextRequest request, int flags)
+ {
+ QtExtractedText qExtractedText = QtNativeInputConnection.getExtractedText(request.hintMaxChars,
+ request.hintMaxLines,
+ flags);
+ if (qExtractedText == null)
+ return null;
+
+ ExtractedText extractedText = new ExtractedText();
+ extractedText.partialEndOffset = qExtractedText.partialEndOffset;
+ extractedText.partialStartOffset = qExtractedText.partialStartOffset;
+ extractedText.selectionEnd = qExtractedText.selectionEnd;
+ extractedText.selectionStart = qExtractedText.selectionStart;
+ extractedText.startOffset = qExtractedText.startOffset;
+ extractedText.text = qExtractedText.text;
+ return extractedText;
+ }
+
+ public CharSequence getSelectedText(int flags)
+ {
+ return QtNativeInputConnection.getSelectedText(flags);
+ }
+
+ @Override
+ public CharSequence getTextAfterCursor(int length, int flags)
+ {
+ return QtNativeInputConnection.getTextAfterCursor(length, flags);
+ }
+
+ @Override
+ public CharSequence getTextBeforeCursor(int length, int flags)
+ {
+ return QtNativeInputConnection.getTextBeforeCursor(length, flags);
+ }
+
+ @Override
+ public boolean performContextMenuAction(int id)
+ {
+ switch (id) {
+ case ID_SELECT_ALL:
+ restartImmInput();
+ return QtNativeInputConnection.selectAll();
+ case ID_COPY:
+ restartImmInput();
+ return QtNativeInputConnection.copy();
+ case ID_COPY_URL:
+ restartImmInput();
+ return QtNativeInputConnection.copyURL();
+ case ID_CUT:
+ restartImmInput();
+ return QtNativeInputConnection.cut();
+ case ID_PASTE:
+ restartImmInput();
+ return QtNativeInputConnection.paste();
+ case ID_SWITCH_INPUT_METHOD:
+ if (m_imm != null)
+ m_imm.showInputMethodPicker();
+
+ return true;
+ case ID_ADD_TO_DICTIONARY:
+// TODO
+// String word = m_editable.subSequence(0, m_editable.length()).toString();
+// if (word != null) {
+// Intent i = new Intent("com.android.settings.USER_DICTIONARY_INSERT");
+// i.putExtra("word", word);
+// i.setFlags(i.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
+// m_view.getContext().startActivity(i);
+// }
+ return true;
+ }
+ return super.performContextMenuAction(id);
+ }
+
+ @Override
+ public boolean sendKeyEvent(KeyEvent event)
+ {
+ // QTBUG-85715
+ // If the sendKeyEvent was invoked, it means that the button not related with composingText was used
+ // In such case composing text (if it exists) should be finished immediately
+ finishComposingText();
+ if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER && m_view != null) {
+ KeyEvent fakeEvent;
+ switch (m_view.m_imeOptions) {
+ case android.view.inputmethod.EditorInfo.IME_ACTION_NEXT:
+ fakeEvent = new KeyEvent(event.getDownTime(),
+ event.getEventTime(),
+ event.getAction(),
+ KeyEvent.KEYCODE_TAB,
+ event.getRepeatCount(),
+ event.getMetaState());
+ return super.sendKeyEvent(fakeEvent);
+ case android.view.inputmethod.EditorInfo.IME_ACTION_PREVIOUS:
+ fakeEvent = new KeyEvent(event.getDownTime(),
+ event.getEventTime(),
+ event.getAction(),
+ KeyEvent.KEYCODE_TAB,
+ event.getRepeatCount(),
+ KeyEvent.META_SHIFT_ON);
+ return super.sendKeyEvent(fakeEvent);
+ case android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION:
+ restartImmInput();
+ break;
+ default:
+ m_qtInputConnectionListener.onSendKeyEventDefaultCase();
+ break;
+ }
+ }
+ return super.sendKeyEvent(event);
+ }
+
+ @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);
+ }
+}