diff options
author | Frederik Gladhorn <frederik.gladhorn@theqtcompany.com> | 2014-10-20 19:12:23 +0200 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@theqtcompany.com> | 2014-10-20 19:12:25 +0200 |
commit | 3361fcbc28be96262d22fd2b024c85fbcbc61462 (patch) | |
tree | 48976f337b3885971dc1976b9a27cec5e7dfa2ec /src/plugins/platforms/android | |
parent | dc612acdc6577594c8f61345cea2de549d7aae34 (diff) | |
parent | 5e342f6f041208d142d97202f61179d7163eb773 (diff) |
Merge remote-tracking branch 'origin/5.4' into dev
Change-Id: If7e51514ed6832750e3ad967e4d322ccf920d2bb
Diffstat (limited to 'src/plugins/platforms/android')
9 files changed, 169 insertions, 22 deletions
diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro index f55bc40a55..3c3a4b4b2e 100644 --- a/src/plugins/platforms/android/android.pro +++ b/src/plugins/platforms/android/android.pro @@ -26,6 +26,7 @@ INCLUDEPATH += \ $$QT_SOURCE_TREE/src/3rdparty/android SOURCES += $$PWD/androidplatformplugin.cpp \ + $$PWD/androiddeadlockprotector.cpp \ $$PWD/androidjnimain.cpp \ $$PWD/androidjniaccessibility.cpp \ $$PWD/androidjniinput.cpp \ @@ -53,6 +54,7 @@ SOURCES += $$PWD/androidplatformplugin.cpp \ $$PWD/qandroideventdispatcher.cpp HEADERS += $$PWD/qandroidplatformintegration.h \ + $$PWD/androidandroiddeadlockprotector.h \ $$PWD/androidjnimain.h \ $$PWD/androidjniaccessibility.h \ $$PWD/androidjniinput.h \ diff --git a/src/plugins/platforms/android/androiddeadlockprotector.cpp b/src/plugins/platforms/android/androiddeadlockprotector.cpp new file mode 100644 index 0000000000..e53e0c2447 --- /dev/null +++ b/src/plugins/platforms/android/androiddeadlockprotector.cpp @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "androiddeadlockprotector.h" + +QAtomicInt AndroidDeadlockProtector::s_blocked(0); + diff --git a/src/plugins/platforms/android/androiddeadlockprotector.h b/src/plugins/platforms/android/androiddeadlockprotector.h new file mode 100644 index 0000000000..a0a82aa9d1 --- /dev/null +++ b/src/plugins/platforms/android/androiddeadlockprotector.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ANDROID_DEADLOCKPROTECTOR_H +#define ANDROID_DEADLOCKPROTECTOR_H + +#include <QAtomicInt> + +QT_BEGIN_NAMESPACE + +class AndroidDeadlockProtector +{ +public: + AndroidDeadlockProtector() + : m_acquired(0) + { + } + + ~AndroidDeadlockProtector() { + if (m_acquired) + s_blocked.storeRelease(0); + } + + bool acquire() { + m_acquired = s_blocked.testAndSetAcquire(0, 1); + return m_acquired; + } + +private: + static QAtomicInt s_blocked; + int m_acquired; +}; + +QT_END_NAMESPACE + +#endif // ANDROID_DEADLOCKPROTECTOR_H + diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index 7229fd7af5..5c927da9c5 100644 --- a/src/plugins/platforms/android/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp @@ -187,18 +187,30 @@ if (!clazz) { \ //__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); - static jstring descriptionForAccessibleObject(JNIEnv *env, jobject /*thiz*/, jint objectId) + + static jstring descriptionForAccessibleObject_helper(JNIEnv *env, QAccessibleInterface *iface) { QString desc; - QAccessibleInterface *iface = interfaceFromId(objectId); if (iface && iface->isValid()) { desc = iface->text(QAccessible::Name); if (desc.isEmpty()) desc = iface->text(QAccessible::Description); + if (desc.isEmpty()) { + desc = iface->text(QAccessible::Value); + if (desc.isEmpty()) { + if (QAccessibleValueInterface *valueIface = iface->valueInterface()) { + desc= valueIface->currentValue().toString(); + } + } + } } + return env->NewString((jchar*) desc.constData(), (jsize) desc.size()); + } - jstring jdesc = env->NewString((jchar*) desc.constData(), (jsize) desc.size()); - return jdesc; + static jstring descriptionForAccessibleObject(JNIEnv *env, jobject /*thiz*/, jint objectId) + { + QAccessibleInterface *iface = interfaceFromId(objectId); + return descriptionForAccessibleObject_helper(env, iface); } static bool populateNode(JNIEnv *env, jobject /*thiz*/, jint objectId, jobject node) @@ -216,11 +228,8 @@ if (!clazz) { \ const bool hasDecreaseAction = actions.contains(QAccessibleActionInterface::decreaseAction()); // try to fill in the text property, this is what the screen reader reads - QString desc = iface->text(QAccessible::Value); - if (desc.isEmpty()) - desc = iface->text(QAccessible::Name); - if (desc.isEmpty()) - desc = iface->text(QAccessible::Description); + jstring jdesc = descriptionForAccessibleObject_helper(env, iface); + if (QAccessibleTextInterface *textIface = iface->textInterface()) { if (m_setTextSelectionMethodID && textIface->selectionCount() > 0) { int startSelection; @@ -252,7 +261,6 @@ if (!clazz) { \ env->CallVoidMethod(node, m_addActionMethodID, (int)8192); // ACTION_SCROLL_BACKWARD defined in AccessibilityNodeInfo - jstring jdesc = env->NewString((jchar*) desc.constData(), (jsize) desc.size()); //CALL_METHOD(node, "setText", "(Ljava/lang/CharSequence;)V", jdesc) env->CallVoidMethod(node, m_setContentDescriptionMethodID, jdesc); diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index a23d05520c..a3848c9c2b 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -38,6 +38,7 @@ #include "androidjnimain.h" #include "androidjniinput.h" #include "qandroideventdispatcher.h" +#include "androiddeadlockprotector.h" #include <QDebug> #include <qevent.h> #include <qguiapplication.h> @@ -519,6 +520,10 @@ bool QAndroidInputContext::isAnimating() const void QAndroidInputContext::showInputPanel() { + if (QGuiApplication::applicationState() != Qt::ApplicationActive) { + connect(qGuiApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(showInputPanelLater(Qt::ApplicationState))); + return; + } QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe(); if (query.isNull()) return; @@ -541,6 +546,14 @@ void QAndroidInputContext::showInputPanel() query->value(Qt::ImHints).toUInt()); } +void QAndroidInputContext::showInputPanelLater(Qt::ApplicationState state) +{ + if (state != Qt::ApplicationActive) + return; + disconnect(qGuiApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(showInputPanelLater(Qt::ApplicationState))); + showInputPanel(); +} + void QAndroidInputContext::hideInputPanel() { QtAndroidInput::hideSoftwareKeyboard(); @@ -642,13 +655,13 @@ jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint right // Android docs say the cursor must not move jboolean QAndroidInputContext::finishComposingText() { + if (m_composingText.isEmpty()) + return JNI_TRUE; // not composing + QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQueryThreadSafe(); if (query.isNull()) return JNI_FALSE; - if (m_composingText.isEmpty()) - return JNI_TRUE; // not composing - const int blockPos = getBlockPosition(query); const int localCursorPos = m_composingCursor - blockPos; @@ -986,6 +999,9 @@ QVariant QAndroidInputContext::queryFocusObjectThreadSafe(Qt::InputMethodQuery q const bool inMainThread = qGuiApp->thread() == QThread::currentThread(); if (QAndroidEventDispatcherStopper::stopped() && !inMainThread) return retval; + AndroidDeadlockProtector protector; + if (!inMainThread && !protector.acquire()) + return retval; QMetaObject::invokeMethod(this, "queryFocusObjectUnsafe", inMainThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection, @@ -1003,6 +1019,9 @@ QSharedPointer<QInputMethodQueryEvent> QAndroidInputContext::focusObjectInputMet const bool inMainThread = qGuiApp->thread() == QThread::currentThread(); if (QAndroidEventDispatcherStopper::stopped() && !inMainThread) return QSharedPointer<QInputMethodQueryEvent>(); + AndroidDeadlockProtector protector; + if (!inMainThread && !protector.acquire()) + return QSharedPointer<QInputMethodQueryEvent>(); QInputMethodQueryEvent *queryEvent = 0; QMetaObject::invokeMethod(this, "focusObjectInputMethodQueryUnsafe", @@ -1040,7 +1059,9 @@ void QAndroidInputContext::sendInputMethodEventThreadSafe(QInputMethodEvent *eve const bool inMainThread = qGuiApp->thread() == QThread::currentThread(); if (QAndroidEventDispatcherStopper::stopped() && !inMainThread) return; - + AndroidDeadlockProtector protector; + if (!inMainThread && !protector.acquire()) + return; QMetaObject::invokeMethod(this, "sendInputMethodEventUnsafe", inMainThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection, Q_ARG(QInputMethodEvent*, event)); diff --git a/src/plugins/platforms/android/qandroidinputcontext.h b/src/plugins/platforms/android/qandroidinputcontext.h index 670a051139..2ebb155d2a 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.h +++ b/src/plugins/platforms/android/qandroidinputcontext.h @@ -112,6 +112,9 @@ public: public slots: void updateCursorPosition(); +private slots: + void showInputPanelLater(Qt::ApplicationState); + private: void sendInputMethodEventThreadSafe(QInputMethodEvent *event); Q_INVOKABLE void sendInputMethodEventUnsafe(QInputMethodEvent *event); diff --git a/src/plugins/platforms/android/qandroidplatformclipboard.cpp b/src/plugins/platforms/android/qandroidplatformclipboard.cpp index 86fd152bff..fb73db8455 100644 --- a/src/plugins/platforms/android/qandroidplatformclipboard.cpp +++ b/src/plugins/platforms/android/qandroidplatformclipboard.cpp @@ -44,19 +44,19 @@ QAndroidPlatformClipboard::QAndroidPlatformClipboard() QMimeData *QAndroidPlatformClipboard::mimeData(QClipboard::Mode mode) { - if (QClipboard::Clipboard != mode || !QtAndroidClipboard::hasClipboardText()) - return 0; - - m_mimeData.setText(QtAndroidClipboard::clipboardText()); + Q_ASSERT(supportsMode(mode)); + m_mimeData.setText(QtAndroidClipboard::hasClipboardText() + ? QtAndroidClipboard::clipboardText() + : QString()); return &m_mimeData; } void QAndroidPlatformClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) { - if (!data || !data->hasText() || QClipboard::Clipboard != mode) - return; - - QtAndroidClipboard::setClipboardText(data->text()); + Q_ASSERT(supportsMode(mode)); + QtAndroidClipboard::setClipboardText(data != 0 && data->hasText() ? data->text() : QString()); + if (data != 0) + data->deleteLater(); } bool QAndroidPlatformClipboard::supportsMode(QClipboard::Mode mode) const diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp index 8afc35c57a..8dc8e84f0a 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp @@ -37,6 +37,7 @@ #include "qandroidplatformscreen.h" #include "androidjnimain.h" #include "qandroideventdispatcher.h" +#include "androiddeadlockprotector.h" #include <QSurfaceFormat> #include <QtGui/private/qwindow_p.h> @@ -120,6 +121,10 @@ EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config) QMutexLocker lock(&m_surfaceMutex); if (m_nativeSurfaceId == -1) { + AndroidDeadlockProtector protector; + if (!protector.acquire()) + return m_eglSurface; + const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint); m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), windowStaysOnTop, 32); m_surfaceWaitCondition.wait(&m_surfaceMutex); diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index 09e5d7e346..8a07735e5f 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -43,6 +43,7 @@ #include "qandroidplatformwindow.h" #include "androidjnimain.h" #include "androidjnimenu.h" +#include "androiddeadlockprotector.h" #include <android/bitmap.h> #include <android/native_window_jni.h> @@ -299,6 +300,9 @@ void QAndroidPlatformScreen::doRedraw() QMutexLocker lock(&m_surfaceMutex); if (m_id == -1 && m_rasterSurfaces) { m_id = QtAndroid::createSurface(this, m_availableGeometry, true, m_depth); + AndroidDeadlockProtector protector; + if (!protector.acquire()) + return; m_surfaceWaitCondition.wait(&m_surfaceMutex); } |