6package org.qtproject.qt.android;
8import android.app.Activity;
9import android.content.pm.ActivityInfo;
10import android.content.pm.PackageManager;
11import android.content.res.Configuration;
12import android.graphics.drawable.ColorDrawable;
13import android.graphics.drawable.Drawable;
14import android.graphics.Rect;
15import android.util.DisplayMetrics;
16import android.util.Log;
17import android.util.TypedValue;
18import android.view.ViewTreeObserver;
19import android.view.animation.AccelerateInterpolator;
20import android.view.animation.AlphaAnimation;
21import android.view.animation.Animation;
22import android.view.Menu;
23import android.view.View;
24import android.view.ViewConfiguration;
25import android.view.ViewGroup;
26import android.widget.ImageView;
27import android.widget.PopupMenu;
29import java.util.HashMap;
31class QtActivityDelegate
extends QtActivityDelegateBase
35 private static final String QtTAG =
"QtActivityDelegate";
37 private QtRootLayout m_layout =
null;
38 private ImageView m_splashScreen =
null;
39 private boolean m_splashScreenSticky =
false;
40 private boolean m_backendsRegistered =
false;
42 private View m_dummyView =
null;
43 private final HashMap<Integer, View> m_nativeViews =
new HashMap<>();
45 QtActivityDelegate(Activity activity)
54 setActionBarVisibility(
false);
55 setActivityBackgroundDrawable();
56 if (QtNativeAccessibility.accessibilitySupported())
57 m_accessibilityDelegate.initLayoutAccessibility(m_layout);
60 void registerBackends()
62 if (m_backendsRegistered || BackendRegister.isNull())
65 m_backendsRegistered =
true;
66 BackendRegister.registerBackend(QtWindowInterface.class, QtActivityDelegate.this);
67 BackendRegister.registerBackend(QtAccessibilityInterface.class, QtActivityDelegate.this);
68 BackendRegister.registerBackend(QtMenuInterface.class, QtActivityDelegate.this);
69 BackendRegister.registerBackend(QtInputInterface.class, m_inputDelegate);
72 void unregisterBackends()
74 if (!m_backendsRegistered)
77 m_backendsRegistered =
false;
79 if (BackendRegister.isNull())
82 BackendRegister.unregisterBackend(QtWindowInterface.class);
83 BackendRegister.unregisterBackend(QtAccessibilityInterface.class);
84 BackendRegister.unregisterBackend(QtMenuInterface.class);
85 BackendRegister.unregisterBackend(QtInputInterface.class);
89 final public void onAppStateDetailsChanged(QtNative.ApplicationStateDetails details) {
90 if (details.isStarted)
97 void startNativeApplicationImpl(
String appParams,
String mainLib)
99 if (m_layout ==
null) {
100 Log.e(QtTAG,
"Unable to start native application with a null layout");
104 m_layout.getViewTreeObserver().addOnGlobalLayoutListener(
105 new ViewTreeObserver.OnGlobalLayoutListener() {
107 public void onGlobalLayout() {
108 if (m_layout != null) {
109 QtNative.startApplication(appParams, mainLib);
110 m_layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
117 protected void setUpLayout()
121 m_layout =
new QtRootLayout(m_activity);
123 int orientation = m_activity.getResources().getConfiguration().orientation;
124 setUpSplashScreen(orientation);
125 m_activity.registerForContextMenu(m_layout);
126 ViewGroup.LayoutParams rootParams =
new ViewGroup.LayoutParams(
127 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
128 m_activity.setContentView(m_layout, rootParams);
130 handleUiModeChange();
132 m_displayManager.initDisplayProperties();
134 m_layout.getViewTreeObserver().addOnPreDrawListener(() -> {
135 if (!m_inputDelegate.isKeyboardVisible())
139 m_activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(
r);
140 DisplayMetrics
metrics =
new DisplayMetrics();
141 QtDisplayManager.getDisplay(m_activity).getMetrics(
metrics);
142 final int kbHeight = metrics.heightPixels -
r.bottom;
144 m_inputDelegate.setKeyboardVisibility(
false,
System.nanoTime());
148 m_layout.getLocationOnScreen(
location);
150 r.width(), kbHeight);
156 protected void setUpSplashScreen(
int orientation)
158 if (m_layout ==
null) {
159 Log.e(QtTAG,
"Unable to setup splash screen with a null layout");
164 ActivityInfo
info = m_activity.getPackageManager().getActivityInfo(
165 m_activity.getComponentName(),
166 PackageManager.GET_META_DATA);
168 String splashScreenKey =
"android.app.splash_screen_drawable_"
169 + (orientation == Configuration.ORIENTATION_LANDSCAPE ?
"landscape" :
"portrait");
170 if (!
info.metaData.containsKey(splashScreenKey))
171 splashScreenKey =
"android.app.splash_screen_drawable";
173 if (
info.metaData.containsKey(splashScreenKey)) {
174 m_splashScreenSticky =
175 info.metaData.containsKey(
"android.app.splash_screen_sticky") &&
176 info.metaData.getBoolean(
"android.app.splash_screen_sticky");
178 int id =
info.metaData.getInt(splashScreenKey);
179 m_splashScreen =
new ImageView(m_activity);
180 m_splashScreen.setImageDrawable(m_activity.getResources().getDrawable(
181 id, m_activity.getTheme()));
182 m_splashScreen.setScaleType(ImageView.ScaleType.FIT_XY);
183 m_splashScreen.setLayoutParams(
new ViewGroup.LayoutParams(
184 ViewGroup.LayoutParams.MATCH_PARENT,
185 ViewGroup.LayoutParams.MATCH_PARENT));
186 m_layout.addView(m_splashScreen);
188 }
catch (Exception e) {
194 protected void hideSplashScreen(
final int duration)
197 if (m_splashScreen ==
null)
200 if (m_layout !=
null && duration <= 0) {
201 m_layout.removeView(m_splashScreen);
202 m_splashScreen =
null;
206 final Animation fadeOut =
new AlphaAnimation(1, 0);
207 fadeOut.setInterpolator(
new AccelerateInterpolator());
208 fadeOut.setDuration(duration);
210 fadeOut.setAnimationListener(
new Animation.AnimationListener() {
212 public void onAnimationEnd(Animation animation) {
217 public void onAnimationRepeat(Animation animation) {
221 public void onAnimationStart(Animation animation) {
225 m_splashScreen.startAnimation(fadeOut);
232 m_accessibilityDelegate.notifyLocationChange(viewId);
238 m_accessibilityDelegate.notifyObjectHide(viewId, parentId);
244 m_accessibilityDelegate.notifyObjectShow(parentId);
250 m_accessibilityDelegate.notifyObjectFocus(viewId);
256 m_accessibilityDelegate.notifyValueChanged(viewId,
value);
261 m_accessibilityDelegate.notifyDescriptionOrNameChanged(viewId,
value);
267 m_accessibilityDelegate.notifyScrolledEvent(viewId);
273 m_accessibilityDelegate.notifyAnnouncementEvent(viewId,
message);
278 public void resetOptionsMenu()
280 QtNative.runAction(m_activity::invalidateOptionsMenu);
286 QtNative.runAction(m_activity::openOptionsMenu);
290 public void closeContextMenu()
292 QtNative.runAction(m_activity::closeContextMenu);
296 public void openContextMenu(
final int x,
final int y,
final int w,
final int h)
298 if (m_layout ==
null) {
299 Log.e(QtTAG,
"Unable to open context menu with a null layout");
303 m_layout.postDelayed(() -> {
304 if (m_layout ==
null) {
305 Log.w(QtTAG,
"Unable to open context menu on null layout");
308 final QtEditText focusedEditText = m_inputDelegate.getCurrentQtEditText();
309 if (focusedEditText ==
null) {
310 Log.w(QtTAG,
"No focused view when trying to open context menu");
313 m_layout.setLayoutParams(focusedEditText,
new QtLayout.LayoutParams(
w,
h,
x,
y),
false);
314 focusedEditText.requestLayout();
315 focusedEditText.getViewTreeObserver().addOnGlobalLayoutListener(
316 new ViewTreeObserver.OnGlobalLayoutListener() {
318 public void onGlobalLayout() {
319 focusedEditText.getViewTreeObserver().removeOnGlobalLayoutListener(this);
320 PopupMenu popup = new PopupMenu(m_activity, focusedEditText);
321 QtActivityDelegate.this.onCreatePopupMenu(popup.getMenu());
322 popup.setOnMenuItemClickListener(m_activity::onContextItemSelected);
323 popup.setOnDismissListener(popupMenu ->
324 m_activity.onContextMenuClosed(popupMenu.getMenu()));
332 void onCreatePopupMenu(Menu
menu)
334 QtNative.fillContextMenu(
menu);
335 setContextMenuVisible(
true);
339 void setActionBarVisibility(
boolean visible)
341 if (m_activity.getActionBar() ==
null)
343 if (ViewConfiguration.get(m_activity).hasPermanentMenuKey() || !visible)
344 m_activity.getActionBar().hide();
346 m_activity.getActionBar().show();
351 public void addTopLevelWindow(
final QtWindow
window)
353 if (m_layout ==
null ||
window ==
null)
356 QtNative.runAction(()-> {
357 if (m_layout ==
null)
360 if (m_topLevelWindows.isEmpty()) {
361 if (m_dummyView !=
null) {
362 m_layout.removeView(m_dummyView);
367 m_layout.addView(
window, m_topLevelWindows.size());
369 if (!m_splashScreenSticky)
376 public void removeTopLevelWindow(
final int id)
378 QtNative.runAction(()-> {
379 if (m_topLevelWindows.containsKey(
id)) {
380 QtWindow
window = m_topLevelWindows.remove(
id);
381 window.setOnApplyWindowInsetsListener(
null);
382 if (m_topLevelWindows.isEmpty()) {
386 }
else if (m_layout !=
null) {
387 m_layout.removeView(
window);
395 public void bringChildToFront(
final int id)
397 if (m_layout !=
null) {
398 QtNative.runAction(() -> {
399 QtWindow
window = m_topLevelWindows.get(
id);
400 if (
window !=
null && m_layout !=
null)
401 m_layout.moveChild(
window, m_topLevelWindows.size() - 1);
408 public void bringChildToBack(
int id)
410 if (m_layout !=
null) {
411 QtNative.runAction(() -> {
412 QtWindow
window = m_topLevelWindows.get(
id);
413 if (
window !=
null && m_layout !=
null)
414 m_layout.moveChild(
window, 0);
419 private void setActivityBackgroundDrawable()
421 TypedValue attr =
new TypedValue();
422 m_activity.getTheme().resolveAttribute(android.R.attr.windowBackground,
424 Drawable backgroundDrawable;
425 if (attr.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
426 attr.type <= TypedValue.TYPE_LAST_COLOR_INT) {
427 backgroundDrawable =
new ColorDrawable(attr.data);
429 backgroundDrawable = m_activity.getResources().
430 getDrawable(attr.resourceId, m_activity.getTheme());
433 m_activity.getWindow().setBackgroundDrawable(backgroundDrawable);
438 void insertNativeView(
int id,
View view,
int x,
int y,
int w,
int h)
440 if (m_layout ==
null)
443 QtNative.runAction(()-> {
444 if (m_dummyView !=
null) {
445 m_layout.removeView(m_dummyView);
449 if (m_nativeViews.containsKey(
id))
450 m_layout.removeView(m_nativeViews.remove(
id));
452 if (
w < 0 ||
h < 0) {
453 view.setLayoutParams(
new ViewGroup.LayoutParams(
454 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
456 view.setLayoutParams(
new QtLayout.LayoutParams(
w,
h,
x,
y));
460 m_layout.addView(
view);
461 m_nativeViews.put(
id,
view);
467 void setNativeViewGeometry(
int id,
int x,
int y,
int w,
int h)
469 QtNative.runAction(() -> {
470 if (m_nativeViews.containsKey(
id)) {
473 view.setLayoutParams(
new QtLayout.LayoutParams(
w,
h,
x,
y));
475 Log.e(QtTAG,
"View " +
id +
" not found!");
void notifyDescriptionOrNameChanged(uint accessibilityObjectId)
void notifyObjectShow(uint accessibilityObjectId)
void notifyLocationChange(uint accessibilityObjectId)
void notifyObjectFocus(uint accessibilityObjectId)
void notifyObjectHide(uint accessibilityObjectId)
void notifyValueChanged(uint accessibilityObjectId)
void notifyAnnouncementEvent(uint accessibilityObjectId, const QString &message)
void notifyScrolledEvent(uint accessiblityObjectId)
EGLOutputLayerEXT EGLint EGLAttrib value
[3]
GLint GLint GLint GLint GLint x
GLfloat GLfloat GLfloat w
[0]
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
GLuint GLsizei const GLchar * message
GLfloat GLfloat GLfloat GLfloat h