4package org.qtproject.qt.android;
6import android.annotation.SuppressLint;
7import android.app.ActionBar;
8import android.app.Activity;
9import android.content.Context;
10import android.content.res.TypedArray;
11import android.graphics.Insets;
13import android.view.DisplayCutout;
14import android.view.GestureDetector;
15import android.view.MotionEvent;
16import android.view.Surface;
17import android.view.View;
18import android.view.ViewGroup;
19import android.view.ViewTreeObserver;
20import android.view.Window;
21import android.view.WindowInsets;
22import android.view.WindowManager;
23import android.view.WindowInsetsController;
24import android.os.Build;
26import java.util.HashMap;
27import java.util.concurrent.ConcurrentLinkedQueue;
29@SuppressLint(
"ViewConstructor")
32 private View m_surfaceContainer;
34 private volatile Surface m_surface;
35 private boolean m_nativeSurfaceRetired =
false;
36 private final ConcurrentLinkedQueue<Runnable> m_pendingSurfaceReleases =
new ConcurrentLinkedQueue<>();
37 private View m_nativeView;
38 private final HashMap<Integer, QtWindow> m_childWindows =
new HashMap<>();
39 private QtWindow m_parentWindow;
40 private GestureDetector m_gestureDetector;
41 private final QtEditText m_editText;
42 private boolean m_editTextFocusInitialized =
false;
44 private boolean m_firstSafeMarginsDelivered =
false;
45 private WindowInsets m_pendingSafeAreaInsets;
46 private int m_actionBarHeight = -1;
48 private static native
void surfaceCreated(
int windowId, Surface surface);
49 private static native
void surfaceRedrawNeeded(
int windowId, Runnable drawingFinished);
50 private static native
void surfaceDestroyed(
int windowId, Runnable surfaceReleased);
51 private static native
void safeAreaMarginsChanged(Insets insets,
int id);
52 static native
void windowFocusChanged(
boolean hasFocus,
int id);
53 static native
void updateWindows();
55 QtWindow(
Context context,
boolean isForeignWindow, QtWindow parentWindow,
56 QtInputConnection.QtInputConnectionListener listener)
59 m_inputConnectionListener = listener;
61 setFocusableInTouchMode(
true);
62 setDefaultFocusHighlightEnabled(
false);
63 setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
67 setVisibility(View.INVISIBLE);
69 if (!isForeignWindow && context instanceof Activity) {
71 m_editText =
new QtEditText(context, listener);
72 m_editText.setFocusable(
false);
73 m_editText.setFocusableInTouchMode(
false);
74 m_editText.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
75 LayoutParams layoutParams =
new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
76 ViewGroup.LayoutParams.WRAP_CONTENT);
77 QtNative.runAction(() -> addView(m_editText, layoutParams));
84 new GestureDetector(context,
new GestureDetector.SimpleOnGestureListener() {
86 public void onLongPress(MotionEvent event) {
87 QtInputDelegate.longPress(getId(), (int) event.getX(), (int) event.getY(),
88 event.getMetaState());
91 m_gestureDetector.setIsLongpressEnabled(
true);
94 registerSafeAreaMarginsListener();
99 void reportSafeAreaMarginsFromRoot(WindowInsets freshInsets)
101 if (!isAttachedToWindow())
105 getRootView().post(() -> {
106 WindowInsets insets = freshInsets !=
null ? freshInsets : getRootWindowInsets();
108 updateSafeAreaMargins(insets);
110 for (QtWindow
child : m_childWindows.values())
111 child.reportSafeAreaMarginsFromRoot(freshInsets);
114 void registerSafeAreaMarginsListener()
119 setOnApplyWindowInsetsListener((
view, insets) -> {
120 WindowInsets windowInsets =
view.onApplyWindowInsets(insets);
121 updateSafeAreaMargins(windowInsets);
127 if (isAttachedToWindow()) {
128 WindowInsets insets = getRootWindowInsets();
129 if (insets !=
null) {
130 getRootView().post(() -> updateSafeAreaMargins(insets));
131 m_firstSafeMarginsDelivered =
true;
134 addOnAttachStateChangeListener(
new View.OnAttachStateChangeListener() {
136 public void onViewAttachedToWindow(View view) {
137 view.removeOnAttachStateChangeListener(this);
138 view.requestApplyInsets();
142 public void onViewDetachedFromWindow(View
view) {}
147 if (!m_firstSafeMarginsDelivered) {
148 ViewTreeObserver.OnPreDrawListener listener =
new ViewTreeObserver.OnPreDrawListener() {
150 public boolean onPreDraw() {
151 if (isAttachedToWindow()) {
152 WindowInsets insets = getRootWindowInsets();
153 if (insets !=
null) {
154 getViewTreeObserver().removeOnPreDrawListener(
this);
155 getRootView().post(() -> updateSafeAreaMargins(insets));
156 m_firstSafeMarginsDelivered =
true;
161 requestApplyInsets();
166 getViewTreeObserver().addOnPreDrawListener(listener);
171 protected void onLayout(
boolean changed,
int l,
int t,
int r,
int b)
175 reportSafeAreaMargins();
176 super.onLayout(changed, l,
t,
r,
b);
179 @SuppressWarnings(
"deprecation")
180 private boolean isAdjustResize()
182 if (!(getContext() instanceof Activity))
184 int mode = ((Activity) getContext()).getWindow().getAttributes().softInputMode
185 & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
186 return mode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
189 @SuppressWarnings(
"deprecation")
190 Insets getSafeInsets(
View view, WindowInsets insets)
192 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
193 int types = WindowInsets.Type.displayCutout() | WindowInsets.Type.systemBars();
196 if (isAdjustResize())
197 types |= WindowInsets.Type.ime();
198 return insets.getInsets(types);
202 int left = insets.getSystemWindowInsetLeft();
203 int top = insets.getSystemWindowInsetTop();
204 int right = insets.getSystemWindowInsetRight();
205 int bottom = insets.getSystemWindowInsetBottom();
209 DisplayCutout cutout = insets.getDisplayCutout();
210 if (cutout !=
null) {
211 left = Math.max(
left, cutout.getSafeInsetLeft());
212 top = Math.max(
top, cutout.getSafeInsetTop());
213 right = Math.max(
right, cutout.getSafeInsetRight());
221 ActionBar actionBar = ((Activity) getContext()).getActionBar();
222 if (actionBar ==
null || !actionBar.isShowing()) {
223 int topWithoutActionBar = top - actionBarHeight();
224 if (topWithoutActionBar > 0)
225 top = topWithoutActionBar;
231 private void updateSafeAreaMargins(WindowInsets insets)
233 if (getVisibility() !=
View.VISIBLE)
236 m_pendingSafeAreaInsets = insets;
237 if (!isLayoutRequested() || isInLayout())
238 reportSafeAreaMargins();
241 private void reportSafeAreaMargins()
243 WindowInsets insets = m_pendingSafeAreaInsets;
244 m_pendingSafeAreaInsets =
null;
245 if (getVisibility() !=
View.VISIBLE || !(getContext() instanceof QtActivityBase))
248 insets = getRootWindowInsets();
251 View rootView = getRootView();
253 int[] rootLocation =
new int[2];
254 rootView.getLocationOnScreen(rootLocation);
255 int rootX = rootLocation[0];
256 int rootY = rootLocation[1];
258 int[] windowLocation =
new int[2];
259 getLocationOnScreen(windowLocation);
260 int windowX = windowLocation[0];
261 int windowY = windowLocation[1];
264 int leftOffset = windowX - rootX;
265 int topOffset = windowY - rootY;
266 int rightOffset = (rootX + rootView.getWidth()) - (windowX + getWidth());
267 int bottomOffset = (rootY + rootView.getHeight()) - (windowY + getHeight());
270 Insets safeInsets = getSafeInsets(rootView, insets);
271 int left = Math.max(0, Math.min(safeInsets.left, safeInsets.left - leftOffset));
272 int top = Math.max(0, Math.min(safeInsets.top, safeInsets.top - topOffset));
273 int right = Math.max(0, Math.min(safeInsets.right, safeInsets.right - rightOffset));
274 int bottom = Math.max(0, Math.min(safeInsets.bottom, safeInsets.bottom - bottomOffset));
279 private int actionBarHeight()
281 if (m_actionBarHeight == -1) {
282 TypedArray ta = getContext().getTheme().obtainStyledAttributes(
283 new int[] { android.R.attr.actionBarSize });
285 m_actionBarHeight = ta.getDimensionPixelSize(0, 0);
290 return m_actionBarHeight;
294 public void onSurfaceCreated(Surface surface)
297 surfaceCreated(getId(), surface);
300 if (surface !=
null && !m_editTextFocusInitialized && m_editText !=
null) {
301 enableEditTextFocus();
302 if (m_inputConnectionListener !=
null)
303 m_inputConnectionListener.onEditTextChanged(m_editText);
304 m_editText.requestFocus();
309 public void onSurfaceRedrawNeeded(Runnable drawingFinished)
311 surfaceRedrawNeeded(getId(), drawingFinished);
315 public void onSurfaceDestroyed(Runnable surfaceReleased)
318 if (m_nativeSurfaceRetired) {
319 surfaceReleased.run();
322 m_pendingSurfaceReleases.add(surfaceReleased);
323 surfaceDestroyed(getId(), () -> {
324 if (m_pendingSurfaceReleases.remove(surfaceReleased))
325 surfaceReleased.run();
338 public boolean onTouchEvent(MotionEvent
event)
340 enableEditTextFocus();
342 windowFocusChanged(
true, getId());
343 if (m_editText !=
null && m_inputConnectionListener !=
null)
344 m_inputConnectionListener.onEditTextChanged(m_editText);
346 QtInputDelegate.sendTouchEvent(
event, getId());
347 if (m_gestureDetector !=
null)
348 m_gestureDetector.onTouchEvent(
event);
352 private void enableEditTextFocus()
354 if (m_editTextFocusInitialized || m_editText ==
null)
356 m_editTextFocusInitialized =
true;
357 m_editText.setFocusable(
true);
358 m_editText.setFocusableInTouchMode(
true);
362 public boolean onTrackballEvent(MotionEvent
event)
364 QtInputDelegate.sendTrackballEvent(
event, getId());
369 public boolean onGenericMotionEvent(MotionEvent
event)
371 return QtInputDelegate.sendGenericMotionEvent(
event, getId());
375 protected void onAttachedToWindow()
377 super.onAttachedToWindow();
378 setOnDragListener(QtDragManager.getInstance());
382 protected void onDetachedFromWindow()
384 QtDragManager.getInstance().onSourceWindowDetached(
this);
385 setOnDragListener(
null);
386 super.onDetachedFromWindow();
392 if (m_parentWindow !=
null)
393 m_parentWindow.removeChildWindow(getId());
398 private int m_x, m_y, m_width, m_height;
399 private boolean m_visible;
400 private boolean m_needsSurface, m_surfaceOnTop, m_surfaceOpaque;
401 private int m_surfaceContainerType;
402 private final Runnable m_applyUpdate = this::applyUpdate;
405 void configureSurface(
boolean onTop,
boolean isOpaque,
int containerType)
407 synchronized (
this) {
408 m_needsSurface =
true;
409 m_surfaceOnTop = onTop;
410 m_surfaceOpaque = isOpaque;
411 m_surfaceContainerType = containerType;
416 void updateWindow(
int x,
int y,
int width,
int height,
boolean visible)
418 synchronized (
this) {
425 removeCallbacks(m_applyUpdate);
429 private void applyUpdate()
432 final boolean visible, needsSurface, onTop, isOpaque;
433 synchronized (
this) {
439 needsSurface = m_needsSurface;
440 onTop = m_surfaceOnTop;
441 isOpaque = m_surfaceOpaque;
442 containerType = m_surfaceContainerType;
444 if (getContext() instanceof QtActivityBase && !hasLayoutGeometry(
x,
y,
width,
height))
445 setLayoutParams(
new QtLayout.LayoutParams(
width,
height,
x,
y));
447 if (visible && needsSurface && m_surfaceContainer ==
null)
448 addSurfaceContainer(onTop, isOpaque, containerType);
449 final boolean shown = visible && getVisibility() !=
View.VISIBLE;
450 setVisibility(visible ?
View.VISIBLE :
View.INVISIBLE);
456 private boolean hasLayoutGeometry(
int x,
int y,
int w,
int h)
458 if (!(getLayoutParams() instanceof QtLayout.LayoutParams))
460 QtLayout.LayoutParams
params = (QtLayout.LayoutParams) getLayoutParams();
461 return params.x ==
x && params.y ==
y && params.width ==
w && params.height ==
h;
464 private void addSurfaceContainer(
boolean onTop,
boolean isOpaque,
int surfaceContainerType)
466 if (surfaceContainerType == 0)
467 m_surfaceContainer =
new QtSurface(getContext(), QtWindow.this, onTop, 32);
469 m_surfaceContainer =
new QtTextureView(getContext(), QtWindow.this, isOpaque);
470 m_surfaceContainer.setLayoutParams(
new QtLayout.LayoutParams(
471 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
474 addView(m_surfaceContainer, 0);
478 void destroySurface()
480 QtNative.runAction(this::destroySurfaceOnUiThread,
false);
483 private void destroySurfaceOnUiThread()
486 m_nativeSurfaceRetired =
true;
487 Throwable removalFailure =
null;
489 if (m_surfaceContainer !=
null) {
490 removeView(m_surfaceContainer);
491 m_surfaceContainer =
null;
493 }
catch (RuntimeException |
Error failure) {
494 removalFailure = failure;
498 releasePendingSurfaces();
499 }
catch (RuntimeException |
Error failure) {
500 if (removalFailure ==
null)
502 if (removalFailure != failure)
503 removalFailure.addSuppressed(failure);
508 private void releasePendingSurfaces()
510 Throwable firstFailure =
null;
512 while ((released = m_pendingSurfaceReleases.poll()) !=
null) {
515 }
catch (RuntimeException |
Error failure) {
516 if (firstFailure ==
null)
517 firstFailure = failure;
518 else if (firstFailure != failure)
519 firstFailure.addSuppressed(failure);
522 if (firstFailure instanceof RuntimeException)
523 throw (RuntimeException) firstFailure;
524 if (firstFailure instanceof
Error)
525 throw (
Error) firstFailure;
528 void addChildWindow(QtWindow
window)
530 QtNative.runAction(()-> {
532 addView(
window, getChildCount());
536 void removeChildWindow(
int id)
538 QtNative.runAction(()-> {
539 if (m_childWindows.containsKey(
id))
540 removeView(m_childWindows.remove(
id));
547 QtNative.runAction(()-> {
548 if (m_nativeView !=
null)
549 removeView(m_nativeView);
552 m_nativeView.setLayoutParams(
new QtLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
553 ViewGroup.LayoutParams.MATCH_PARENT));
554 addView(m_nativeView);
559 void bringChildToFront(
int id)
561 QtNative.runAction(()-> {
564 if (getChildCount() > 0)
565 moveChild(
view, getChildCount() - 1);
571 void bringChildToBack(
int id) {
572 QtNative.runAction(()-> {
581 void removeNativeView()
583 QtNative.runAction(()-> {
584 if (m_nativeView !=
null) {
585 removeView(m_nativeView);
593 if (m_parentWindow == parentWindow)
596 if (m_parentWindow !=
null)
597 m_parentWindow.removeChildWindow(getId());
599 m_parentWindow = parentWindow;
600 if (m_parentWindow !=
null)
601 m_parentWindow.addChildWindow(
this);
605 void updateFocusedEditText()
607 if (m_editText !=
null && m_inputConnectionListener !=
null)
608 m_inputConnectionListener.onEditTextChanged(m_editText);
Napi::TypedArray TypedArray
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
GLfloat GLfloat GLfloat w
[0]
GLdouble GLdouble GLdouble GLdouble top
GLfloat GLfloat GLfloat GLfloat h
file setParent(multiPart)
manager post(request, myJson, this, [this](QRestReply &reply) { if(!reply.isSuccess()) { } if(std::optional json=reply.readJson()) { } })
if(foo.startsWith("("+type+") 0x")) ... QString hello("hello")
[0]