Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
QtEditText.java
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:critical reason:password-input-type
5
6package org.qtproject.qt.android;
7
8import android.annotation.SuppressLint;
9import android.app.Activity;
10import android.content.Context;
11import android.graphics.Canvas;
12import android.text.InputType;
13import android.view.View;
14import android.view.inputmethod.EditorInfo;
15import android.view.inputmethod.ExtractedText;
16import android.view.inputmethod.ExtractedTextRequest;
17import android.view.inputmethod.InputConnection;
18import android.view.KeyEvent;
19
20import org.qtproject.qt.android.QtInputConnection.QtInputConnectionListener;
21
22@SuppressLint("ViewConstructor")
23class QtEditText extends View
24{
25 int m_initialCapsMode = 0;
26 int m_imeOptions = 0;
27 int m_inputType = InputType.TYPE_CLASS_TEXT;
28 boolean m_optionsChanged = false;
29 QtInputConnection m_inputConnection = null;
30
31 // input method hints - must be kept in sync with QTDIR/src/corelib/global/qnamespace.h
32 private final int ImhHiddenText = 0x1;
33 private final int ImhSensitiveData = 0x2;
34 private final int ImhNoAutoUppercase = 0x4;
35 private final int ImhPreferNumbers = 0x8;
36 private final int ImhPreferUppercase = 0x10;
37 private final int ImhPreferLowercase = 0x20;
38 private final int ImhNoPredictiveText = 0x40;
39
40 private final int ImhDate = 0x80;
41 private final int ImhTime = 0x100;
42
43 private final int ImhPreferLatin = 0x200;
44
45 private final int ImhMultiLine = 0x400;
46
47 private final int ImhDigitsOnly = 0x10000;
48 private final int ImhFormattedNumbersOnly = 0x20000;
49 private final int ImhUppercaseOnly = 0x40000;
50 private final int ImhLowercaseOnly = 0x80000;
51 private final int ImhDialableCharactersOnly = 0x100000;
52 private final int ImhEmailCharactersOnly = 0x200000;
53 private final int ImhUrlCharactersOnly = 0x400000;
54 private final int ImhLatinOnly = 0x800000;
55
56 private final QtInputConnectionListener m_qtInputConnectionListener;
57
58
59 // Values coming from QAndroidInputContext::CursorHandleShowMode
60 static final int CursorHandleNotShown = 0;
61 static final int CursorHandleShowNormal = 1;
62 static final int CursorHandleShowSelection = 2;
63 static final int CursorHandleShowEdit = 0x100;
64
65 private CursorHandle m_cursorHandle;
66 private CursorHandle m_leftSelectionHandle;
67 private CursorHandle m_rightSelectionHandle;
68
69 final private EditPopupMenu m_editPopupMenu;
70
71 QtEditText(Context context, QtInputConnectionListener listener)
72 {
73 super(context);
74 setFocusable(true);
75 setFocusableInTouchMode(true);
76 m_qtInputConnectionListener = listener;
77 m_editPopupMenu = new EditPopupMenu(this);
78 }
79
80 private void setImeOptions(int imeOptions)
81 {
82 if (m_imeOptions == imeOptions)
83 return;
84 m_imeOptions = imeOptions;
85 m_optionsChanged = true;
86 }
87
88 private void setInitialCapsMode(int initialCapsMode)
89 {
90 if (m_initialCapsMode == initialCapsMode)
91 return;
92 m_initialCapsMode = initialCapsMode;
93 m_optionsChanged = true;
94 }
95
96
97 private void setInputType(int inputType)
98 {
99 if (m_inputType == inputType)
100 return;
101 m_inputType = inputType;
102 m_optionsChanged = true;
103 }
104
105 @Override
106 public InputConnection onCreateInputConnection(EditorInfo outAttrs)
107 {
108 outAttrs.inputType = m_inputType;
109 outAttrs.imeOptions = m_imeOptions;
110 outAttrs.initialCapsMode = m_initialCapsMode;
111 m_inputConnection = new QtInputConnection(this,m_qtInputConnectionListener);
112
113 ExtractedText extracted = m_inputConnection.getExtractedText(new ExtractedTextRequest(), 0);
114 if (extracted != null) {
115 outAttrs.initialSelStart = extracted.selectionStart;
116 outAttrs.initialSelEnd = extracted.selectionEnd;
117 }
118
119 return m_inputConnection;
120 }
121
122 @Override
123 public boolean onCheckIsTextEditor ()
124 {
125 return true;
126 }
127
128 @Override
129 public boolean onKeyDown (int keyCode, KeyEvent event)
130 {
131 if (null != m_inputConnection)
132 m_inputConnection.restartImmInput();
133
134 return super.onKeyDown(keyCode, event);
135 }
136
137 @Override
138 protected void onDraw(Canvas canvas) {
139 // DEBUG CODE
140 // canvas.drawARGB(127, 255, 0, 255);
141 super.onDraw(canvas);
142 }
143
144
145 void setEditTextOptions(int enterKeyType, int inputHints)
146 {
147 int initialCapsMode = 0;
148 int imeOptions = imeOptionsFromEnterKeyType(enterKeyType);
149 int inputType = android.text.InputType.TYPE_CLASS_TEXT;
150
151 if ((inputHints & (ImhPreferNumbers | ImhDigitsOnly | ImhFormattedNumbersOnly)) != 0) {
152 inputType = android.text.InputType.TYPE_CLASS_NUMBER;
153 if ((inputHints & ImhFormattedNumbersOnly) != 0) {
154 inputType |= (android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL
155 | android.text.InputType.TYPE_NUMBER_FLAG_SIGNED);
156 }
157
158 if ((inputHints & ImhHiddenText) != 0)
159 inputType |= android.text.InputType.TYPE_NUMBER_VARIATION_PASSWORD;
160 } else if ((inputHints & ImhDialableCharactersOnly) != 0) {
161 inputType = android.text.InputType.TYPE_CLASS_PHONE;
162 } else if ((inputHints & (ImhDate | ImhTime)) != 0) {
163 inputType = android.text.InputType.TYPE_CLASS_DATETIME;
164 if ((inputHints & (ImhDate | ImhTime)) != (ImhDate | ImhTime)) {
165 if ((inputHints & ImhDate) != 0)
166 inputType |= android.text.InputType.TYPE_DATETIME_VARIATION_DATE;
167 else
168 inputType |= android.text.InputType.TYPE_DATETIME_VARIATION_TIME;
169 } // else { TYPE_DATETIME_VARIATION_NORMAL(0) }
170 } else { // CLASS_TEXT
171 if ((inputHints & ImhHiddenText) != 0) {
172 inputType |= android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
173 } else if ((inputHints & ImhSensitiveData) != 0 ||
174 isDisablePredictiveTextWorkaround(inputHints)) {
175 inputType |= android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
176 } else if ((inputHints & ImhUrlCharactersOnly) != 0) {
177 inputType |= android.text.InputType.TYPE_TEXT_VARIATION_URI;
178 if (enterKeyType == 0) // not explicitly overridden
179 imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO;
180 } else if ((inputHints & ImhEmailCharactersOnly) != 0) {
181 inputType |= android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
182 }
183
184 if ((inputHints & ImhMultiLine) != 0) {
185 inputType |= android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE;
186 // Clear imeOptions for Multi-Line Type
187 // User should be able to insert new line in such case
188 imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
189 }
190 if ((inputHints & (ImhNoPredictiveText | ImhSensitiveData | ImhHiddenText)) != 0)
191 inputType |= android.text.InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
192
193 if ((inputHints & ImhUppercaseOnly) != 0) {
194 initialCapsMode |= android.text.TextUtils.CAP_MODE_CHARACTERS;
195 inputType |= android.text.InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
196 } else if ((inputHints & ImhLowercaseOnly) == 0
197 && (inputHints & ImhNoAutoUppercase) == 0) {
198 initialCapsMode |= android.text.TextUtils.CAP_MODE_SENTENCES;
199 inputType |= android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
200 }
201 }
202
203 if (enterKeyType == 0 && (inputHints & ImhMultiLine) != 0)
204 imeOptions = android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION;
205
206 setInitialCapsMode(initialCapsMode);
207 setImeOptions(imeOptions);
208 setInputType(inputType);
209 }
210
211 private int imeOptionsFromEnterKeyType(int enterKeyType)
212 {
213 int imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
214
215 // enter key type - must be kept in sync with QTDIR/src/corelib/global/qnamespace.h
216 switch (enterKeyType) {
217 case 0: // EnterKeyDefault
218 break;
219 case 1: // EnterKeyReturn
220 imeOptions = android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION;
221 break;
222 case 2: // EnterKeyDone
223 break;
224 case 3: // EnterKeyGo
225 imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO;
226 break;
227 case 4: // EnterKeySend
228 imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_SEND;
229 break;
230 case 5: // EnterKeySearch
231 imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_SEARCH;
232 break;
233 case 6: // EnterKeyNext
234 imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_NEXT;
235 break;
236 case 7: // EnterKeyPrevious
237 imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_PREVIOUS;
238 break;
239 }
240 return imeOptions;
241 }
242
243 int getSelectionHandleBottom()
244 {
245 if (m_cursorHandle != null)
246 return m_cursorHandle.bottom();
247 if (m_leftSelectionHandle != null && m_rightSelectionHandle != null)
248 return Math.max(m_leftSelectionHandle.bottom(), m_rightSelectionHandle.bottom());
249
250 return 0;
251 }
252
253 int getSelectionHandleWidth()
254 {
255 if (m_leftSelectionHandle != null && m_rightSelectionHandle != null)
256 return Math.max(m_leftSelectionHandle.width(), m_rightSelectionHandle.width());
257 if (m_cursorHandle != null)
258 return m_cursorHandle.width();
259
260 return 0;
261 }
262
263 void updateHandles(int mode, int editX, int editY, int editButtons,
264 int x1, int y1, int x2, int y2, boolean rtl)
265 {
266 switch (mode & 0xff)
267 {
268 case CursorHandleNotShown:
269 if (m_cursorHandle != null) {
270 m_cursorHandle.hide();
271 m_cursorHandle = null;
272 }
273 if (m_rightSelectionHandle != null) {
274 m_rightSelectionHandle.hide();
275 m_leftSelectionHandle.hide();
276 m_rightSelectionHandle = null;
277 m_leftSelectionHandle = null;
278 }
279 break;
280 case CursorHandleShowNormal:
281 if (m_cursorHandle == null) {
282 m_cursorHandle = new CursorHandle((Activity) getContext(), this,
283 CursorHandle.IdCursorHandle,
284 android.R.attr.textSelectHandle, false);
285 }
286 m_cursorHandle.setPosition(x1, y1);
287 if (m_rightSelectionHandle != null) {
288 m_rightSelectionHandle.hide();
289 m_leftSelectionHandle.hide();
290 m_rightSelectionHandle = null;
291 m_leftSelectionHandle = null;
292 }
293 break;
294 case CursorHandleShowSelection:
295 if (m_rightSelectionHandle == null) {
296 m_leftSelectionHandle = new CursorHandle((Activity) getContext(), this,
297 CursorHandle.IdLeftHandle,
298 !rtl ? android.R.attr.textSelectHandleLeft :
299 android.R.attr.textSelectHandleRight,
300 rtl);
301 m_rightSelectionHandle = new CursorHandle((Activity) getContext(), this,
302 CursorHandle.IdRightHandle,
303 !rtl ? android.R.attr.textSelectHandleRight :
304 android.R.attr.textSelectHandleLeft,
305 rtl);
306 }
307 m_leftSelectionHandle.setPosition(x1,y1);
308 m_rightSelectionHandle.setPosition(x2,y2);
309 if (m_cursorHandle != null) {
310 m_cursorHandle.hide();
311 m_cursorHandle = null;
312 }
313 mode |= CursorHandleShowEdit;
314 break;
315 }
316
317 if (!QtClipboardManager.hasClipboardText(getContext()))
318 editButtons &= ~EditContextView.PASTE_BUTTON;
319
320 final boolean setEditPopupPosition = (mode & QtEditText.CursorHandleShowEdit) ==
321 QtEditText.CursorHandleShowEdit && editButtons != 0;
322 if (setEditPopupPosition)
323 m_editPopupMenu.setPosition(editX, editY, editButtons);
324 else
325 m_editPopupMenu.hide();
326 }
327
328 private boolean isDisablePredictiveTextWorkaround(int inputHints)
329 {
330 return (inputHints & ImhNoPredictiveText) != 0 &&
331 System.getenv("QT_ANDROID_ENABLE_WORKAROUND_TO_DISABLE_PREDICTIVE_TEXT") != null;
332 }
333}
QPainter Context
static const QString context()
Definition java.cpp:398
void updateHandles(int mode, QPoint editMenuPos, uint32_t editButtons, QPoint cursor, QPoint anchor, bool rtl)
@ ImhPreferUppercase
@ ImhPreferLatin
@ ImhUrlCharactersOnly
@ ImhPreferLowercase
@ ImhTime
@ ImhFormattedNumbersOnly
@ ImhMultiLine
@ ImhLatinOnly
@ ImhUppercaseOnly
@ ImhNoPredictiveText
@ ImhDigitsOnly
@ ImhSensitiveData
@ ImhLowercaseOnly
@ ImhEmailCharactersOnly
@ ImhHiddenText
@ ImhNoAutoUppercase
@ ImhDialableCharactersOnly
@ ImhDate
@ ImhPreferNumbers
GLenum mode
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLuint GLfloat GLfloat GLfloat x1
struct _cl_event * event
GLfixed GLfixed GLfixed y2
GLfixed GLfixed x2