Android: Add a context delegate for embedding QML to native Android
When we are embedding a QML view to a non-Qt Android app, there are a lot of functionalities that are shared with the refular Qt Android app, but some are not. We should not, for example, try to control the hosting Activity. Create a base class that both the QtActivityDelegate, used for the standard Qt for Android app, and the delegate for the embedding case can extend. In this commit, the QtEmbeddedDelegate is very simple, the biggest difference to QtActivityDelegate being it does not create a QtLayout or instantiate a QtAccessibilityDelegate. It does start the Qt app, without waiting for a layout, and register to listen for changes in the state of the Qt app. Taking the embedded delegate into use, loading the embedded QML views and their handling is added in a follow up commit. Task-number: QTBUG-118872 Change-Id: Id390a2b35c70b35880523886bf6fcf59d420cb42 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io> (cherry picked from commit 06d2aa91eb4faafc0e52faafeb184d6d3da671ab) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
66b732244a
commit
03ca126bb6
@ -33,6 +33,8 @@ set(java_sources
|
||||
src/org/qtproject/qt/android/UsedFromNativeCode.java
|
||||
src/org/qtproject/qt/android/QtRootLayout.java
|
||||
src/org/qtproject/qt/android/QtWindow.java
|
||||
src/org/qtproject/qt/android/QtActivityDelegateBase.java
|
||||
src/org/qtproject/qt/android/QtEmbeddedDelegate.java
|
||||
)
|
||||
|
||||
qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}Android
|
||||
|
@ -318,7 +318,7 @@ public class QtActivityBase extends Activity
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
QtActivityDelegate getActivityDelegate()
|
||||
QtActivityDelegateBase getActivityDelegate()
|
||||
{
|
||||
return m_delegate;
|
||||
}
|
||||
|
@ -33,48 +33,36 @@ import android.widget.PopupMenu;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
class QtActivityDelegate
|
||||
class QtActivityDelegate extends QtActivityDelegateBase
|
||||
{
|
||||
private Activity m_activity;
|
||||
private static final String QtTAG = "QtActivityDelegate";
|
||||
|
||||
private QtRootLayout m_layout = null;
|
||||
private HashMap<Integer, QtWindow> m_topLevelWindows;
|
||||
private ImageView m_splashScreen = null;
|
||||
private boolean m_splashScreenSticky = false;
|
||||
|
||||
private View m_dummyView = null;
|
||||
private QtAccessibilityDelegate m_accessibilityDelegate = null;
|
||||
private QtDisplayManager m_displayManager = null;
|
||||
|
||||
private QtInputDelegate m_inputDelegate = null;
|
||||
private boolean m_membersInitialized = false;
|
||||
|
||||
QtActivityDelegate(Activity activity)
|
||||
{
|
||||
m_activity = activity;
|
||||
QtNative.setActivity(m_activity);
|
||||
super(activity);
|
||||
|
||||
setActionBarVisibility(false);
|
||||
setActivityBackgroundDrawable();
|
||||
}
|
||||
|
||||
QtDisplayManager displayManager() {
|
||||
return m_displayManager;
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
QtInputDelegate getInputDelegate() {
|
||||
return m_inputDelegate;
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
@Override
|
||||
QtLayout getQtLayout()
|
||||
{
|
||||
return m_layout;
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void setSystemUiVisibility(int systemUiVisibility)
|
||||
@Override
|
||||
void setSystemUiVisibility(int systemUiVisibility)
|
||||
{
|
||||
QtNative.runAction(() -> {
|
||||
m_displayManager.setSystemUiVisibility(systemUiVisibility);
|
||||
@ -83,45 +71,24 @@ class QtActivityDelegate
|
||||
});
|
||||
}
|
||||
|
||||
void setContextMenuVisible(boolean contextMenuVisible)
|
||||
{
|
||||
m_contextMenuVisible = contextMenuVisible;
|
||||
}
|
||||
|
||||
boolean isContextMenuVisible()
|
||||
{
|
||||
return m_contextMenuVisible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateActivityAfterRestart(Activity activity) {
|
||||
try {
|
||||
// set new activity
|
||||
m_activity = activity;
|
||||
QtNative.setActivity(m_activity);
|
||||
boolean updated = super.updateActivityAfterRestart(activity);
|
||||
// TODO verify whether this is even needed, the last I checked the initMembers
|
||||
// recreates the layout anyway
|
||||
// update the new activity content view to old layout
|
||||
ViewGroup layoutParent = (ViewGroup)m_layout.getParent();
|
||||
if (layoutParent != null)
|
||||
layoutParent.removeView(m_layout);
|
||||
|
||||
// update the new activity content view to old layout
|
||||
ViewGroup layoutParent = (ViewGroup) m_layout.getParent();
|
||||
if (layoutParent != null)
|
||||
layoutParent.removeView(m_layout);
|
||||
m_activity.setContentView(m_layout);
|
||||
|
||||
m_activity.setContentView(m_layout);
|
||||
|
||||
// force c++ native activity object to update
|
||||
return QtNative.updateNativeActivity();
|
||||
} catch (Exception e) {
|
||||
Log.w(QtNative.QtTAG, "Failed to update the activity.");
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
public void startNativeApplication(String appParams, String mainLib)
|
||||
@Override
|
||||
void startNativeApplicationImpl(String appParams, String mainLib)
|
||||
{
|
||||
if (m_membersInitialized)
|
||||
return;
|
||||
|
||||
initMembers();
|
||||
|
||||
m_layout.getViewTreeObserver().addOnGlobalLayoutListener(
|
||||
new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
@ -132,50 +99,13 @@ class QtActivityDelegate
|
||||
});
|
||||
}
|
||||
|
||||
private void initMembers()
|
||||
@Override
|
||||
protected void setUpLayout()
|
||||
{
|
||||
m_layout = new QtRootLayout(m_activity);
|
||||
m_membersInitialized = true;
|
||||
m_topLevelWindows = new HashMap<Integer, QtWindow>();
|
||||
|
||||
m_displayManager = new QtDisplayManager(m_activity);
|
||||
m_displayManager.registerDisplayListener();
|
||||
|
||||
QtInputDelegate.KeyboardVisibilityListener keyboardVisibilityListener =
|
||||
() -> m_displayManager.updateFullScreen();
|
||||
m_inputDelegate = new QtInputDelegate(m_activity, keyboardVisibilityListener);
|
||||
|
||||
try {
|
||||
PackageManager pm = m_activity.getPackageManager();
|
||||
ActivityInfo activityInfo = pm.getActivityInfo(m_activity.getComponentName(), 0);
|
||||
m_inputDelegate.setSoftInputMode(activityInfo.softInputMode);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
int orientation = m_activity.getResources().getConfiguration().orientation;
|
||||
m_layout = new QtRootLayout(m_activity);
|
||||
|
||||
try {
|
||||
ActivityInfo info = m_activity.getPackageManager().getActivityInfo(m_activity.getComponentName(), PackageManager.GET_META_DATA);
|
||||
|
||||
String splashScreenKey = "android.app.splash_screen_drawable_"
|
||||
+ (orientation == Configuration.ORIENTATION_LANDSCAPE ? "landscape" : "portrait");
|
||||
if (!info.metaData.containsKey(splashScreenKey))
|
||||
splashScreenKey = "android.app.splash_screen_drawable";
|
||||
|
||||
if (info.metaData.containsKey(splashScreenKey)) {
|
||||
m_splashScreenSticky = info.metaData.containsKey("android.app.splash_screen_sticky") && info.metaData.getBoolean("android.app.splash_screen_sticky");
|
||||
int id = info.metaData.getInt(splashScreenKey);
|
||||
m_splashScreen = new ImageView(m_activity);
|
||||
m_splashScreen.setImageDrawable(m_activity.getResources().getDrawable(id, m_activity.getTheme()));
|
||||
m_splashScreen.setScaleType(ImageView.ScaleType.FIT_XY);
|
||||
m_splashScreen.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
m_layout.addView(m_splashScreen);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
setUpSplashScreen(orientation);
|
||||
m_activity.registerForContextMenu(m_layout);
|
||||
m_activity.setContentView(m_layout,
|
||||
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
@ -211,12 +141,41 @@ class QtActivityDelegate
|
||||
m_inputDelegate.setEditPopupMenu(new EditPopupMenu(m_activity, m_layout));
|
||||
}
|
||||
|
||||
public void hideSplashScreen()
|
||||
@Override
|
||||
protected void setUpSplashScreen(int orientation)
|
||||
{
|
||||
hideSplashScreen(0);
|
||||
try {
|
||||
ActivityInfo info = m_activity.getPackageManager().getActivityInfo(
|
||||
m_activity.getComponentName(),
|
||||
PackageManager.GET_META_DATA);
|
||||
|
||||
String splashScreenKey = "android.app.splash_screen_drawable_"
|
||||
+ (orientation == Configuration.ORIENTATION_LANDSCAPE ? "landscape" : "portrait");
|
||||
if (!info.metaData.containsKey(splashScreenKey))
|
||||
splashScreenKey = "android.app.splash_screen_drawable";
|
||||
|
||||
if (info.metaData.containsKey(splashScreenKey)) {
|
||||
m_splashScreenSticky =
|
||||
info.metaData.containsKey("android.app.splash_screen_sticky") &&
|
||||
info.metaData.getBoolean("android.app.splash_screen_sticky");
|
||||
|
||||
int id = info.metaData.getInt(splashScreenKey);
|
||||
m_splashScreen = new ImageView(m_activity);
|
||||
m_splashScreen.setImageDrawable(m_activity.getResources().getDrawable(
|
||||
id, m_activity.getTheme()));
|
||||
m_splashScreen.setScaleType(ImageView.ScaleType.FIT_XY);
|
||||
m_splashScreen.setLayoutParams(new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
m_layout.addView(m_splashScreen);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void hideSplashScreen(final int duration)
|
||||
@Override
|
||||
protected void hideSplashScreen(final int duration)
|
||||
{
|
||||
QtNative.runAction(() -> {
|
||||
if (m_splashScreen == null)
|
||||
@ -251,50 +210,16 @@ class QtActivityDelegate
|
||||
});
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void notifyLocationChange(int viewId)
|
||||
{
|
||||
if (m_accessibilityDelegate == null)
|
||||
return;
|
||||
m_accessibilityDelegate.notifyLocationChange(viewId);
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void notifyObjectHide(int viewId, int parentId)
|
||||
{
|
||||
if (m_accessibilityDelegate == null)
|
||||
return;
|
||||
m_accessibilityDelegate.notifyObjectHide(viewId, parentId);
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void notifyObjectFocus(int viewId)
|
||||
{
|
||||
if (m_accessibilityDelegate == null)
|
||||
return;
|
||||
m_accessibilityDelegate.notifyObjectFocus(viewId);
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void notifyValueChanged(int viewId, String value)
|
||||
{
|
||||
if (m_accessibilityDelegate == null)
|
||||
return;
|
||||
m_accessibilityDelegate.notifyValueChanged(viewId, value);
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void notifyScrolledEvent(int viewId)
|
||||
{
|
||||
if (m_accessibilityDelegate == null)
|
||||
return;
|
||||
m_accessibilityDelegate.notifyScrolledEvent(viewId);
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void initializeAccessibility()
|
||||
{
|
||||
QtNative.runAction(() -> m_accessibilityDelegate = new QtAccessibilityDelegate(m_layout));
|
||||
QtNative.runAction(() -> {
|
||||
// FIXME make QtAccessibilityDelegate window based
|
||||
if (m_layout != null)
|
||||
m_accessibilityDelegate = new QtAccessibilityDelegate(m_layout);
|
||||
else
|
||||
Log.w(QtTAG, "Null layout, failed to initialize accessibility delegate.");
|
||||
});
|
||||
}
|
||||
|
||||
void handleUiModeChange(int uiMode)
|
||||
@ -345,6 +270,7 @@ class QtActivityDelegate
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
@Override
|
||||
public void openContextMenu(final int x, final int y, final int w, final int h)
|
||||
{
|
||||
m_layout.postDelayed(() -> {
|
||||
@ -365,6 +291,7 @@ class QtActivityDelegate
|
||||
QtNative.runAction(() -> m_activity.closeContextMenu());
|
||||
}
|
||||
|
||||
@Override
|
||||
void setActionBarVisibility(boolean visible)
|
||||
{
|
||||
if (m_activity.getActionBar() == null)
|
||||
@ -376,8 +303,12 @@ class QtActivityDelegate
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
@Override
|
||||
public void addTopLevelWindow(final QtWindow window)
|
||||
{
|
||||
if (window == null)
|
||||
return;
|
||||
|
||||
QtNative.runAction(()-> {
|
||||
if (m_topLevelWindows.size() == 0) {
|
||||
if (m_dummyView != null) {
|
||||
@ -398,7 +329,8 @@ class QtActivityDelegate
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void removeTopLevelWindow(final int id)
|
||||
@Override
|
||||
void removeTopLevelWindow(final int id)
|
||||
{
|
||||
QtNative.runAction(()-> {
|
||||
if (m_topLevelWindows.containsKey(id)) {
|
||||
@ -415,18 +347,19 @@ class QtActivityDelegate
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void bringChildToFront(final int id)
|
||||
@Override
|
||||
void bringChildToFront(final int id)
|
||||
{
|
||||
QtNative.runAction(() -> {
|
||||
QtWindow window = m_topLevelWindows.get(id);
|
||||
if (window != null) {
|
||||
if (window != null)
|
||||
m_layout.moveChild(window.getLayout(), m_topLevelWindows.size() - 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void bringChildToBack(int id)
|
||||
@Override
|
||||
void bringChildToBack(int id)
|
||||
{
|
||||
QtNative.runAction(() -> {
|
||||
QtWindow window = m_topLevelWindows.get(id);
|
||||
@ -435,6 +368,16 @@ class QtActivityDelegate
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
QtAccessibilityDelegate createAccessibilityDelegate()
|
||||
{
|
||||
if (m_layout != null)
|
||||
return new QtAccessibilityDelegate(m_layout);
|
||||
|
||||
Log.w(QtTAG, "Null layout, failed to initialize accessibility delegate.");
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setActivityBackgroundDrawable()
|
||||
{
|
||||
TypedValue attr = new TypedValue();
|
||||
|
@ -0,0 +1,240 @@
|
||||
// Copyright (C) 2017 BogDan Vatra <bogdan@kde.org>
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
|
||||
// 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.app.Activity;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Display;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.AlphaAnimation;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowInsetsController;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.PopupMenu;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
abstract class QtActivityDelegateBase
|
||||
{
|
||||
protected Activity m_activity;
|
||||
protected HashMap<Integer, QtWindow> m_topLevelWindows;
|
||||
protected QtAccessibilityDelegate m_accessibilityDelegate = null;
|
||||
protected QtDisplayManager m_displayManager = null;
|
||||
protected QtInputDelegate m_inputDelegate = null;
|
||||
|
||||
private boolean m_membersInitialized = false;
|
||||
private boolean m_contextMenuVisible = false;
|
||||
|
||||
// Subclass must implement these
|
||||
abstract void startNativeApplicationImpl(String appParams, String mainLib);
|
||||
abstract QtAccessibilityDelegate createAccessibilityDelegate();
|
||||
abstract QtLayout getQtLayout();
|
||||
|
||||
// With these we are okay with default implementation doing nothing
|
||||
void setUpLayout() {}
|
||||
void setUpSplashScreen(int orientation) {}
|
||||
void hideSplashScreen(final int duration) {}
|
||||
void openContextMenu(final int x, final int y, final int w, final int h) {}
|
||||
void setActionBarVisibility(boolean visible) {}
|
||||
void addTopLevelWindow(final QtWindow window) {}
|
||||
void removeTopLevelWindow(final int id) {}
|
||||
void bringChildToFront(final int id) {}
|
||||
void bringChildToBack(int id) {}
|
||||
void setSystemUiVisibility(int systemUiVisibility) {}
|
||||
|
||||
QtActivityDelegateBase(Activity activity)
|
||||
{
|
||||
m_activity = activity;
|
||||
// Set native context
|
||||
QtNative.setActivity(m_activity);
|
||||
}
|
||||
|
||||
QtDisplayManager displayManager() {
|
||||
return m_displayManager;
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
QtInputDelegate getInputDelegate() {
|
||||
return m_inputDelegate;
|
||||
}
|
||||
|
||||
void setContextMenuVisible(boolean contextMenuVisible)
|
||||
{
|
||||
m_contextMenuVisible = contextMenuVisible;
|
||||
}
|
||||
|
||||
boolean isContextMenuVisible()
|
||||
{
|
||||
return m_contextMenuVisible;
|
||||
}
|
||||
|
||||
public boolean updateActivityAfterRestart(Activity activity) {
|
||||
try {
|
||||
// set new activity
|
||||
m_activity = activity;
|
||||
QtNative.setActivity(m_activity);
|
||||
|
||||
// force c++ native activity object to update
|
||||
return QtNative.updateNativeActivity();
|
||||
} catch (Exception e) {
|
||||
Log.w(QtNative.QtTAG, "Failed to update the activity.");
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void startNativeApplication(String appParams, String mainLib)
|
||||
{
|
||||
if (m_membersInitialized)
|
||||
return;
|
||||
initMembers();
|
||||
startNativeApplicationImpl(appParams, mainLib);
|
||||
}
|
||||
|
||||
void initMembers()
|
||||
{
|
||||
m_membersInitialized = true;
|
||||
m_topLevelWindows = new HashMap<Integer, QtWindow>();
|
||||
|
||||
m_displayManager = new QtDisplayManager(m_activity);
|
||||
m_displayManager.registerDisplayListener();
|
||||
|
||||
QtInputDelegate.KeyboardVisibilityListener keyboardVisibilityListener =
|
||||
() -> m_displayManager.updateFullScreen();
|
||||
m_inputDelegate = new QtInputDelegate(m_activity, keyboardVisibilityListener);
|
||||
|
||||
try {
|
||||
PackageManager pm = m_activity.getPackageManager();
|
||||
ActivityInfo activityInfo = pm.getActivityInfo(m_activity.getComponentName(), 0);
|
||||
m_inputDelegate.setSoftInputMode(activityInfo.softInputMode);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
setUpLayout();
|
||||
}
|
||||
|
||||
|
||||
public void hideSplashScreen()
|
||||
{
|
||||
hideSplashScreen(0);
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void notifyLocationChange(int viewId)
|
||||
{
|
||||
if (m_accessibilityDelegate == null)
|
||||
return;
|
||||
m_accessibilityDelegate.notifyLocationChange(viewId);
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void notifyObjectHide(int viewId, int parentId)
|
||||
{
|
||||
if (m_accessibilityDelegate == null)
|
||||
return;
|
||||
m_accessibilityDelegate.notifyObjectHide(viewId, parentId);
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void notifyObjectFocus(int viewId)
|
||||
{
|
||||
if (m_accessibilityDelegate == null)
|
||||
return;
|
||||
m_accessibilityDelegate.notifyObjectFocus(viewId);
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void notifyValueChanged(int viewId, String value)
|
||||
{
|
||||
if (m_accessibilityDelegate == null)
|
||||
return;
|
||||
m_accessibilityDelegate.notifyValueChanged(viewId, value);
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void notifyScrolledEvent(int viewId)
|
||||
{
|
||||
if (m_accessibilityDelegate == null)
|
||||
return;
|
||||
m_accessibilityDelegate.notifyScrolledEvent(viewId);
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void initializeAccessibility()
|
||||
{
|
||||
QtNative.runAction(() -> {
|
||||
m_accessibilityDelegate = createAccessibilityDelegate();
|
||||
});
|
||||
}
|
||||
|
||||
void handleUiModeChange(int uiMode)
|
||||
{
|
||||
// QTBUG-108365
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
// Since 29 version we are using Theme_DeviceDefault_DayNight
|
||||
Window window = m_activity.getWindow();
|
||||
WindowInsetsController controller = window.getInsetsController();
|
||||
if (controller != null) {
|
||||
// set APPEARANCE_LIGHT_STATUS_BARS if needed
|
||||
int appearanceLight = Color.luminance(window.getStatusBarColor()) > 0.5 ?
|
||||
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS : 0;
|
||||
controller.setSystemBarsAppearance(appearanceLight,
|
||||
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS);
|
||||
}
|
||||
}
|
||||
switch (uiMode) {
|
||||
case Configuration.UI_MODE_NIGHT_NO:
|
||||
ExtractStyle.runIfNeeded(m_activity, false);
|
||||
QtDisplayManager.handleUiDarkModeChanged(0);
|
||||
break;
|
||||
case Configuration.UI_MODE_NIGHT_YES:
|
||||
ExtractStyle.runIfNeeded(m_activity, true);
|
||||
QtDisplayManager.handleUiDarkModeChanged(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void resetOptionsMenu()
|
||||
{
|
||||
QtNative.runAction(() -> m_activity.invalidateOptionsMenu());
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void openOptionsMenu()
|
||||
{
|
||||
QtNative.runAction(() -> m_activity.openOptionsMenu());
|
||||
}
|
||||
|
||||
public void onCreatePopupMenu(Menu menu)
|
||||
{
|
||||
QtNative.fillContextMenu(menu);
|
||||
m_contextMenuVisible = true;
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
public void closeContextMenu()
|
||||
{
|
||||
QtNative.runAction(() -> m_activity.closeContextMenu());
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// 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 static org.qtproject.qt.android.QtNative.ApplicationState.*;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
class QtEmbeddedDelegate extends QtActivityDelegateBase implements QtNative.AppStateDetailsListener {
|
||||
private QtNative.ApplicationStateDetails m_stateDetails;
|
||||
|
||||
public QtEmbeddedDelegate(Activity context) {
|
||||
super(context);
|
||||
|
||||
m_stateDetails = QtNative.getStateDetails();
|
||||
QtNative.registerAppStateListener(this);
|
||||
|
||||
m_activity.getApplication().registerActivityLifecycleCallbacks(
|
||||
new Application.ActivityLifecycleCallbacks() {
|
||||
@Override
|
||||
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}
|
||||
|
||||
@Override
|
||||
public void onActivityStarted(Activity activity) {}
|
||||
|
||||
@Override
|
||||
public void onActivityResumed(Activity activity) {
|
||||
if (m_activity == activity && m_stateDetails.isStarted) {
|
||||
QtNative.setApplicationState(ApplicationActive);
|
||||
QtNative.updateWindow();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused(Activity activity) {
|
||||
if (m_activity == activity && m_stateDetails.isStarted) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N ||
|
||||
!activity.isInMultiWindowMode()) {
|
||||
QtNative.setApplicationState(ApplicationInactive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStopped(Activity activity) {
|
||||
if (m_activity == activity && m_stateDetails.isStarted) {
|
||||
QtNative.setApplicationState(ApplicationSuspended);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
if (m_activity == activity && m_stateDetails.isStarted) {
|
||||
m_activity.getApplication().unregisterActivityLifecycleCallbacks(this);
|
||||
QtNative.unregisterAppStateListener(QtEmbeddedDelegate.this);
|
||||
QtNative.terminateQt();
|
||||
QtNative.setActivity(null);
|
||||
QtNative.getQtThread().exit();
|
||||
onDestroy();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppStateDetailsChanged(QtNative.ApplicationStateDetails details) {
|
||||
m_stateDetails = details;
|
||||
if (m_stateDetails.nativePluginIntegrationReady) {
|
||||
QtNative.runAction(() -> {
|
||||
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
|
||||
QtDisplayManager.setApplicationDisplayMetrics(m_activity,
|
||||
metrics.widthPixels,
|
||||
metrics.heightPixels);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void startNativeApplicationImpl(String appParams, String mainLib)
|
||||
{
|
||||
QtNative.startApplication(appParams, mainLib);
|
||||
}
|
||||
|
||||
@Override
|
||||
QtAccessibilityDelegate createAccessibilityDelegate()
|
||||
{
|
||||
// FIXME make QtAccessibilityDelegate window based or verify current way works
|
||||
// also for child windows: QTBUG-120685
|
||||
return null;
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
@Override
|
||||
QtLayout getQtLayout()
|
||||
{
|
||||
// TODO could probably use QtView here when it's added?
|
||||
return null;
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
// TODO delete the window once it's added
|
||||
}
|
||||
}
|
@ -53,7 +53,7 @@ static jobject m_resourcesObj = nullptr;
|
||||
static jclass m_qtActivityClass = nullptr;
|
||||
static jclass m_qtServiceClass = nullptr;
|
||||
|
||||
static QtJniTypes::QtActivityDelegate m_activityDelegate = nullptr;
|
||||
static QtJniTypes::QtActivityDelegateBase m_activityDelegate = nullptr;
|
||||
static QtJniTypes::QtInputDelegate m_inputDelegate = nullptr;
|
||||
|
||||
static int m_pendingApplicationState = -1;
|
||||
@ -185,11 +185,11 @@ namespace QtAndroid
|
||||
}
|
||||
|
||||
// FIXME: avoid direct access to QtActivityDelegate
|
||||
QtJniTypes::QtActivityDelegate qtActivityDelegate()
|
||||
QtJniTypes::QtActivityDelegateBase qtActivityDelegate()
|
||||
{
|
||||
if (!m_activityDelegate.isValid()) {
|
||||
auto activity = QtAndroidPrivate::activity();
|
||||
m_activityDelegate = activity.callMethod<QtJniTypes::QtActivityDelegate>(
|
||||
m_activityDelegate = activity.callMethod<QtJniTypes::QtActivityDelegateBase>(
|
||||
"getActivityDelegate");
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ class QWindow;
|
||||
class QAndroidPlatformWindow;
|
||||
class QBasicMutex;
|
||||
|
||||
Q_DECLARE_JNI_CLASS(QtActivityDelegate, "org/qtproject/qt/android/QtActivityDelegate")
|
||||
Q_DECLARE_JNI_CLASS(QtActivityDelegateBase, "org/qtproject/qt/android/QtActivityDelegateBase")
|
||||
Q_DECLARE_JNI_CLASS(QtInputDelegate, "org/qtproject/qt/android/QtInputDelegate")
|
||||
|
||||
namespace QtAndroid
|
||||
@ -48,7 +48,7 @@ namespace QtAndroid
|
||||
AAssetManager *assetManager();
|
||||
jclass applicationClass();
|
||||
|
||||
QtJniTypes::QtActivityDelegate qtActivityDelegate();
|
||||
QtJniTypes::QtActivityDelegateBase qtActivityDelegate();
|
||||
QtJniTypes::QtInputDelegate qtInputDelegate();
|
||||
|
||||
// Keep synchronized with flags in ActivityDelegate.java
|
||||
|
@ -203,13 +203,13 @@ void tst_Android::testRunOnAndroidMainThread()
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_JNI_CLASS(QtActivityDelegate, "org/qtproject/qt/android/QtActivityDelegate")
|
||||
Q_DECLARE_JNI_CLASS(QtActivityDelegateBase, "org/qtproject/qt/android/QtActivityDelegateBase")
|
||||
|
||||
void setSystemUiVisibility(int visibility)
|
||||
{
|
||||
QNativeInterface::QAndroidApplication::runOnAndroidMainThread([visibility] {
|
||||
auto context = QNativeInterface::QAndroidApplication::context();
|
||||
auto activityDelegate = context.callMethod<QtJniTypes::QtActivityDelegate>("getActivityDelegate");
|
||||
auto activityDelegate = context.callMethod<QtJniTypes::QtActivityDelegateBase>("getActivityDelegate");
|
||||
activityDelegate.callMethod<void>("setSystemUiVisibility", jint(visibility));
|
||||
}).waitForFinished();
|
||||
}
|
||||
@ -342,4 +342,3 @@ void tst_Android::orientationChange()
|
||||
|
||||
QTEST_MAIN(tst_Android)
|
||||
#include "tst_android.moc"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user