Android: Fix application state tracking
- Make sure we don't process state changes before the platform plugin is completely created and registered. - Protect shared data with mutexes. - Don't update the application state from different threads. This was causing issues when testing run-time permission checks, when the application quickly switches state due to permission dialog being shown. In this case the states would be incorrectly delivered when the application was made active again. Change-Id: I3446eab9414ee5437cd788c27d65f808d1314aa5 Reviewed-by: BogDan Vatra <bogdan@kdab.com>
This commit is contained in:
parent
05b3295a57
commit
9091a058bc
@ -82,8 +82,8 @@ static jobject m_serviceObject = nullptr;
|
|||||||
static jmethodID m_setSurfaceGeometryMethodID = nullptr;
|
static jmethodID m_setSurfaceGeometryMethodID = nullptr;
|
||||||
static jmethodID m_destroySurfaceMethodID = nullptr;
|
static jmethodID m_destroySurfaceMethodID = nullptr;
|
||||||
|
|
||||||
static bool m_activityActive = true; // defaults to true because when the platform plugin is
|
static int m_pendingApplicationState = -1;
|
||||||
// initialized, QtActivity::onResume() has already been called
|
static QBasicMutex m_pendingAppStateMtx;
|
||||||
|
|
||||||
static jclass m_bitmapClass = nullptr;
|
static jclass m_bitmapClass = nullptr;
|
||||||
static jmethodID m_createBitmapMethodID = nullptr;
|
static jmethodID m_createBitmapMethodID = nullptr;
|
||||||
@ -130,13 +130,22 @@ static const char m_qtTag[] = "Qt";
|
|||||||
static const char m_classErrorMsg[] = "Can't find class \"%s\"";
|
static const char m_classErrorMsg[] = "Can't find class \"%s\"";
|
||||||
static const char m_methodErrorMsg[] = "Can't find method \"%s%s\"";
|
static const char m_methodErrorMsg[] = "Can't find method \"%s%s\"";
|
||||||
|
|
||||||
|
static void flushPendingApplicationState();
|
||||||
|
|
||||||
namespace QtAndroid
|
namespace QtAndroid
|
||||||
{
|
{
|
||||||
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration)
|
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration)
|
||||||
{
|
{
|
||||||
m_surfacesMutex.lock();
|
QMutexLocker lock(&m_surfacesMutex);
|
||||||
m_androidPlatformIntegration = androidPlatformIntegration;
|
m_androidPlatformIntegration = androidPlatformIntegration;
|
||||||
m_surfacesMutex.unlock();
|
|
||||||
|
// flush the pending state if necessary.
|
||||||
|
if (m_androidPlatformIntegration) {
|
||||||
|
flushPendingApplicationState();
|
||||||
|
} else {
|
||||||
|
QMutexLocker locker(&m_pendingAppStateMtx);
|
||||||
|
m_pendingApplicationState = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QAndroidPlatformIntegration *androidPlatformIntegration()
|
QAndroidPlatformIntegration *androidPlatformIntegration()
|
||||||
@ -215,12 +224,6 @@ namespace QtAndroid
|
|||||||
m_statusBarShowing = false;
|
m_statusBarShowing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setApplicationActive()
|
|
||||||
{
|
|
||||||
if (m_activityActive)
|
|
||||||
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
|
|
||||||
}
|
|
||||||
|
|
||||||
jobject createBitmap(QImage img, JNIEnv *env)
|
jobject createBitmap(QImage img, JNIEnv *env)
|
||||||
{
|
{
|
||||||
if (!m_bitmapClass)
|
if (!m_bitmapClass)
|
||||||
@ -446,6 +449,16 @@ namespace QtAndroid
|
|||||||
|
|
||||||
} // namespace QtAndroid
|
} // namespace QtAndroid
|
||||||
|
|
||||||
|
// Force an update of the pending application state (state set before the platform plugin was created)
|
||||||
|
static void flushPendingApplicationState()
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_pendingAppStateMtx);
|
||||||
|
if (m_pendingApplicationState == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState(m_pendingApplicationState));
|
||||||
|
m_pendingApplicationState = -1;
|
||||||
|
}
|
||||||
|
|
||||||
static jboolean startQtAndroidPlugin(JNIEnv* /*env*/, jobject /*object*//*, jobject applicationAssetManager*/)
|
static jboolean startQtAndroidPlugin(JNIEnv* /*env*/, jobject /*object*//*, jobject applicationAssetManager*/)
|
||||||
{
|
{
|
||||||
@ -655,13 +668,14 @@ static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/)
|
|||||||
|
|
||||||
static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state)
|
static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state)
|
||||||
{
|
{
|
||||||
m_activityActive = (state == Qt::ApplicationActive);
|
if (!m_main || !QtAndroid::androidPlatformIntegration()) {
|
||||||
|
QMutexLocker locker(&m_pendingAppStateMtx);
|
||||||
if (!m_main || !m_androidPlatformIntegration || !QGuiApplicationPrivate::platformIntegration()) {
|
m_pendingApplicationState = Qt::ApplicationState(state);
|
||||||
QAndroidPlatformIntegration::setDefaultApplicationState(Qt::ApplicationState(state));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flushPendingApplicationState();
|
||||||
|
|
||||||
if (state == Qt::ApplicationActive)
|
if (state == Qt::ApplicationActive)
|
||||||
QtAndroidPrivate::handleResume();
|
QtAndroidPrivate::handleResume();
|
||||||
else if (state == Qt::ApplicationInactive)
|
else if (state == Qt::ApplicationInactive)
|
||||||
|
@ -85,8 +85,6 @@ namespace QtAndroid
|
|||||||
jobject activity();
|
jobject activity();
|
||||||
jobject service();
|
jobject service();
|
||||||
|
|
||||||
void setApplicationActive();
|
|
||||||
|
|
||||||
void showStatusBar();
|
void showStatusBar();
|
||||||
void hideStatusBar();
|
void hideStatusBar();
|
||||||
|
|
||||||
|
@ -80,8 +80,6 @@ int QAndroidPlatformIntegration::m_defaultPhysicalSizeHeight = 71;
|
|||||||
Qt::ScreenOrientation QAndroidPlatformIntegration::m_orientation = Qt::PrimaryOrientation;
|
Qt::ScreenOrientation QAndroidPlatformIntegration::m_orientation = Qt::PrimaryOrientation;
|
||||||
Qt::ScreenOrientation QAndroidPlatformIntegration::m_nativeOrientation = Qt::PrimaryOrientation;
|
Qt::ScreenOrientation QAndroidPlatformIntegration::m_nativeOrientation = Qt::PrimaryOrientation;
|
||||||
|
|
||||||
Qt::ApplicationState QAndroidPlatformIntegration::m_defaultApplicationState = Qt::ApplicationActive;
|
|
||||||
|
|
||||||
bool QAndroidPlatformIntegration::m_showPasswordEnabled = false;
|
bool QAndroidPlatformIntegration::m_showPasswordEnabled = false;
|
||||||
|
|
||||||
void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteArray &resource)
|
void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteArray &resource)
|
||||||
@ -120,6 +118,12 @@ void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteA
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QAndroidPlatformNativeInterface::customEvent(QEvent *event)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::User)
|
||||||
|
QtAndroid::setAndroidPlatformIntegration(static_cast<QAndroidPlatformIntegration *>(QGuiApplicationPrivate::platformIntegration()));
|
||||||
|
}
|
||||||
|
|
||||||
QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶mList)
|
QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶mList)
|
||||||
: m_touchDevice(nullptr)
|
: m_touchDevice(nullptr)
|
||||||
#ifndef QT_NO_ACCESSIBILITY
|
#ifndef QT_NO_ACCESSIBILITY
|
||||||
@ -147,7 +151,6 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶
|
|||||||
m_primaryScreen->setAvailableGeometry(QRect(0, 0, m_defaultGeometryWidth, m_defaultGeometryHeight));
|
m_primaryScreen->setAvailableGeometry(QRect(0, 0, m_defaultGeometryWidth, m_defaultGeometryHeight));
|
||||||
|
|
||||||
m_mainThread = QThread::currentThread();
|
m_mainThread = QThread::currentThread();
|
||||||
QtAndroid::setAndroidPlatformIntegration(this);
|
|
||||||
|
|
||||||
m_androidFDB = new QAndroidPlatformFontDatabase();
|
m_androidFDB = new QAndroidPlatformFontDatabase();
|
||||||
m_androidPlatformServices = new QAndroidPlatformServices();
|
m_androidPlatformServices = new QAndroidPlatformServices();
|
||||||
@ -210,7 +213,9 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QGuiApplicationPrivate::instance()->setApplicationState(m_defaultApplicationState);
|
// We can't safely notify the jni bridge that we're up and running just yet, so let's postpone
|
||||||
|
// it for now.
|
||||||
|
QCoreApplication::postEvent(m_androidPlatformNativeInterface, new QEvent(QEvent::User));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool needsBasicRenderloopWorkaround()
|
static bool needsBasicRenderloopWorkaround()
|
||||||
|
@ -65,6 +65,9 @@ class QAndroidPlatformNativeInterface: public QPlatformNativeInterface
|
|||||||
public:
|
public:
|
||||||
void *nativeResourceForIntegration(const QByteArray &resource) override;
|
void *nativeResourceForIntegration(const QByteArray &resource) override;
|
||||||
std::shared_ptr<AndroidStyle> m_androidStyle;
|
std::shared_ptr<AndroidStyle> m_androidStyle;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void customEvent(QEvent *event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class QAndroidPlatformIntegration : public QPlatformIntegration
|
class QAndroidPlatformIntegration : public QPlatformIntegration
|
||||||
@ -121,7 +124,6 @@ public:
|
|||||||
|
|
||||||
QTouchDevice *touchDevice() const { return m_touchDevice; }
|
QTouchDevice *touchDevice() const { return m_touchDevice; }
|
||||||
void setTouchDevice(QTouchDevice *touchDevice) { m_touchDevice = touchDevice; }
|
void setTouchDevice(QTouchDevice *touchDevice) { m_touchDevice = touchDevice; }
|
||||||
static void setDefaultApplicationState(Qt::ApplicationState applicationState) { m_defaultApplicationState = applicationState; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EGLDisplay m_eglDisplay;
|
EGLDisplay m_eglDisplay;
|
||||||
@ -140,9 +142,6 @@ private:
|
|||||||
|
|
||||||
static Qt::ScreenOrientation m_orientation;
|
static Qt::ScreenOrientation m_orientation;
|
||||||
static Qt::ScreenOrientation m_nativeOrientation;
|
static Qt::ScreenOrientation m_nativeOrientation;
|
||||||
|
|
||||||
static Qt::ApplicationState m_defaultApplicationState;
|
|
||||||
|
|
||||||
static bool m_showPasswordEnabled;
|
static bool m_showPasswordEnabled;
|
||||||
|
|
||||||
QPlatformFontDatabase *m_androidFDB;
|
QPlatformFontDatabase *m_androidFDB;
|
||||||
|
@ -96,11 +96,6 @@ void QAndroidPlatformWindow::setVisible(bool visible)
|
|||||||
QRect availableGeometry = screen()->availableGeometry();
|
QRect availableGeometry = screen()->availableGeometry();
|
||||||
if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
|
if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
|
||||||
QPlatformWindow::setVisible(visible);
|
QPlatformWindow::setVisible(visible);
|
||||||
|
|
||||||
// The Android Activity is activated before Qt is initialized, causing the application state to
|
|
||||||
// never be set to 'active'. We explicitly set this state when the first window becomes visible.
|
|
||||||
if (visible)
|
|
||||||
QtAndroid::setApplicationActive();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QAndroidPlatformWindow::setWindowState(Qt::WindowState state)
|
void QAndroidPlatformWindow::setWindowState(Qt::WindowState state)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user