Remove old Android code that have now has alternative public APIs

* Remove the old qjni private APIs.
* Remove the Android permission private APIs.
* Remove runOnAndroidThread().

Pick-to: 6.2
Change-Id: I37ba8b4cb87a099f067e2e0b6744b8d01a0f9bbc
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Assam Boudjelthia 2021-05-05 20:45:30 +03:00
parent 182afbe335
commit 03eb44394e
5 changed files with 3 additions and 2901 deletions

View File

@ -994,7 +994,6 @@ qt_internal_extend_target(Core CONDITION ANDROID AND NOT ANDROID_EMBEDDED
io/qstandardpaths_android.cpp
kernel/qcoreapplication_android.cpp
io/qstorageinfo_unix.cpp
kernel/qjni.cpp kernel/qjni_p.h
kernel/qjnienvironment.cpp kernel/qjnienvironment.h
kernel/qjniobject.cpp kernel/qjniobject.h
kernel/qjnihelpers.cpp kernel/qjnihelpers_p.h

File diff suppressed because it is too large Load Diff

View File

@ -1,292 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** 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 The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
// FIXME: Remove this once the JNI API is used by other modules.
#ifndef QJNI_P_H
#define QJNI_P_H
#include <jni.h>
#include <QtCore/private/qglobal_p.h>
#include <QtCore/qsharedpointer.h>
QT_BEGIN_NAMESPACE
struct Q_CORE_EXPORT QJNILocalRefDeleter
{
static void cleanup(jobject obj);
};
// To simplify this we only define it for jobjects.
typedef QScopedPointer<_jobject, QJNILocalRefDeleter> QJNIScopedLocalRef;
class Q_CORE_EXPORT QJNIEnvironmentPrivate
{
public:
QJNIEnvironmentPrivate();
~QJNIEnvironmentPrivate();
JNIEnv *operator->();
operator JNIEnv *() const;
static jclass findClass(const char *className, JNIEnv *env = nullptr);
private:
friend class QAndroidJniEnvironment;
Q_DISABLE_COPY_MOVE(QJNIEnvironmentPrivate)
JNIEnv *jniEnv;
};
class Q_CORE_EXPORT QJNIObjectData
{
public:
QJNIObjectData();
~QJNIObjectData();
jobject m_jobject;
jclass m_jclass;
bool m_own_jclass;
QByteArray m_className;
};
class Q_CORE_EXPORT QJNIObjectPrivate
{
public:
QJNIObjectPrivate();
explicit QJNIObjectPrivate(const char *className);
QJNIObjectPrivate(const char *className, const char *sig, ...);
explicit QJNIObjectPrivate(jclass clazz);
QJNIObjectPrivate(jclass clazz, const char *sig, ...);
// In most cases you should never call this function with a local ref. unless you intend
// to manage the local ref. yourself.
// NOTE: see fromLocalRef() for converting a local ref. to QJNIObjectPrivate.
explicit QJNIObjectPrivate(jobject globalRef);
template <typename T>
T callMethod(const char *methodName,
const char *sig,
...) const;
template <typename T>
T callMethod(const char *methodName) const;
template <typename T>
QJNIObjectPrivate callObjectMethod(const char *methodName) const;
QJNIObjectPrivate callObjectMethod(const char *methodName,
const char *sig,
...) const;
template <typename T>
static T callStaticMethod(const char *className,
const char *methodName,
const char *sig, ...);
template <typename T>
static T callStaticMethod(const char *className,
const char *methodName);
template <typename T>
static T callStaticMethod(jclass clazz,
const char *methodName,
const char *sig, ...);
template <typename T>
static T callStaticMethod(jclass clazz,
const char *methodName);
static QJNIObjectPrivate callStaticObjectMethod(const char *className,
const char *methodName,
const char *sig, ...);
static QJNIObjectPrivate callStaticObjectMethod(jclass clazz,
const char *methodName,
const char *sig, ...);
template <typename T>
T getField(const char *fieldName) const;
template <typename T>
static T getStaticField(const char *className, const char *fieldName);
template <typename T>
static T getStaticField(jclass clazz, const char *fieldName);
QJNIObjectPrivate getObjectField(const char *fieldName, const char *sig) const;
static QJNIObjectPrivate getStaticObjectField(const char *className,
const char *fieldName,
const char *sig);
static QJNIObjectPrivate getStaticObjectField(jclass clazz,
const char *fieldName,
const char *sig);
template <typename T>
void setField(const char *fieldName, T value);
template <typename T>
void setField(const char *fieldName, const char *sig, T value);
template <typename T>
static void setStaticField(const char *className,
const char *fieldName,
T value);
template <typename T>
static void setStaticField(const char *className,
const char *fieldName,
const char *sig,
T value);
template <typename T>
static void setStaticField(jclass clazz,
const char *fieldName,
const char *sig,
T value);
template <typename T>
static void setStaticField(jclass clazz,
const char *fieldName,
T value);
static QJNIObjectPrivate fromString(const QString &string);
QString toString() const;
static bool isClassAvailable(const char *className);
bool isValid() const;
jobject object() const { return d->m_jobject; }
template <typename T>
inline QJNIObjectPrivate &operator=(T o)
{
jobject jobj = static_cast<jobject>(o);
if (!isSameObject(jobj)) {
d = QSharedPointer<QJNIObjectData>::create();
if (jobj) {
QJNIEnvironmentPrivate env;
d->m_jobject = env->NewGlobalRef(jobj);
jclass objectClass = env->GetObjectClass(jobj);
d->m_jclass = static_cast<jclass>(env->NewGlobalRef(objectClass));
env->DeleteLocalRef(objectClass);
}
}
return *this;
}
// This function takes ownership of the jobject and releases the local ref. before returning.
static QJNIObjectPrivate fromLocalRef(jobject lref);
private:
friend class QAndroidJniObject;
struct QVaListPrivate { operator va_list &() const { return m_args; } va_list &m_args; };
QJNIObjectPrivate(const char *className, const char *sig, const QVaListPrivate &args);
QJNIObjectPrivate(jclass clazz, const char *sig, const QVaListPrivate &args);
template <typename T>
T callMethodV(const char *methodName,
const char *sig,
va_list args) const;
QJNIObjectPrivate callObjectMethodV(const char *methodName,
const char *sig,
va_list args) const;
template <typename T>
static T callStaticMethodV(const char *className,
const char *methodName,
const char *sig,
va_list args);
template <typename T>
static T callStaticMethodV(jclass clazz,
const char *methodName,
const char *sig,
va_list args);
static QJNIObjectPrivate callStaticObjectMethodV(const char *className,
const char *methodName,
const char *sig,
va_list args);
static QJNIObjectPrivate callStaticObjectMethodV(jclass clazz,
const char *methodName,
const char *sig,
va_list args);
bool isSameObject(jobject obj) const;
bool isSameObject(const QJNIObjectPrivate &other) const;
friend bool operator==(const QJNIObjectPrivate &, const QJNIObjectPrivate &);
friend bool operator!=(const QJNIObjectPrivate&, const QJNIObjectPrivate&);
template <typename T> friend bool operator!=(const QJNIObjectPrivate&, T);
template <typename T> friend bool operator==(const QJNIObjectPrivate&, T);
template <typename T> friend bool operator!=(T, const QJNIObjectPrivate&);
template <typename T> friend bool operator==(T, const QJNIObjectPrivate&);
QSharedPointer<QJNIObjectData> d;
};
inline bool operator==(const QJNIObjectPrivate &obj1, const QJNIObjectPrivate &obj2)
{
return obj1.isSameObject(obj2);
}
inline bool operator!=(const QJNIObjectPrivate &obj1, const QJNIObjectPrivate &obj2)
{
return !obj1.isSameObject(obj2);
}
template <typename T>
inline bool operator==(const QJNIObjectPrivate &obj1, T obj2)
{
return obj1.isSameObject(static_cast<jobject>(obj2));
}
template <typename T>
inline bool operator==(T obj1, const QJNIObjectPrivate &obj2)
{
return obj2.isSameObject(static_cast<jobject>(obj1));
}
template <typename T>
inline bool operator!=(const QJNIObjectPrivate &obj1, T obj2)
{
return !obj1.isSameObject(obj2);
}
template <typename T>
inline bool operator!=(T obj1, const QJNIObjectPrivate &obj2)
{
return !obj2.isSameObject(obj1);
}
QT_END_NAMESPACE
#endif // QJNI_P_H

View File

@ -37,18 +37,14 @@
**
****************************************************************************/
#include "qcoreapplication.h"
#include "qjnienvironment.h"
#include "qjnihelpers_p.h"
#include "qjnienvironment.h"
#include "qjniobject.h"
#include "qlist.h"
#include "qmutex.h"
#include "qsemaphore.h"
#include "qsharedpointer.h"
#include "qthread.h"
#include <QtCore/private/qcoreapplication_p.h>
#include <QtCore/qrunnable.h>
#include <android/log.h>
#include <deque>
@ -72,91 +68,20 @@ static JavaVM *g_javaVM = nullptr;
static jobject g_jActivity = nullptr;
static jobject g_jService = nullptr;
static jobject g_jClassLoader = nullptr;
static jclass g_jNativeClass = nullptr;
static jmethodID g_runPendingCppRunnablesMethodID = nullptr;
Q_GLOBAL_STATIC(std::deque<QtAndroidPrivate::Runnable>, g_pendingRunnables);
static QBasicMutex g_pendingRunnablesMutex;
Q_GLOBAL_STATIC_WITH_ARGS(QtAndroidPrivate::OnBindListener*, g_onBindListener, (nullptr));
Q_GLOBAL_STATIC(QMutex, g_onBindListenerMutex);
Q_GLOBAL_STATIC(QSemaphore, g_waitForServiceSetupSemaphore);
Q_GLOBAL_STATIC(QAtomicInt, g_serviceSetupLockers);
class PermissionsResultClass : public QObject
{
Q_OBJECT
public:
PermissionsResultClass(const QtAndroidPrivate::PermissionsResultFunc &func) : m_func(func) {}
Q_INVOKABLE void sendResult(const QtAndroidPrivate::PermissionsHash &result) { m_func(result); delete this;}
private:
QtAndroidPrivate::PermissionsResultFunc m_func;
};
typedef QHash<int, PermissionsResultClass*> PendingPermissionRequestsHash;
Q_GLOBAL_STATIC(PendingPermissionRequestsHash, g_pendingPermissionRequests);
static QBasicMutex g_pendingPermissionRequestsMutex;
static int nextRequestCode()
{
static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0);
return counter.fetchAndAddRelaxed(1);
}
// function called from Java from Android UI thread
static void runPendingCppRunnables(JNIEnv */*env*/, jobject /*obj*/)
{
for (;;) { // run all posted runnables
QMutexLocker locker(&g_pendingRunnablesMutex);
if (g_pendingRunnables->empty()) {
break;
}
QtAndroidPrivate::Runnable runnable(std::move(g_pendingRunnables->front()));
g_pendingRunnables->pop_front();
locker.unlock();
runnable(); // run it outside the sync block!
}
}
namespace {
struct GenericMotionEventListeners {
QMutex mutex;
QList<QtAndroidPrivate::GenericMotionEventListener *> listeners;
};
enum {
PERMISSION_GRANTED = 0
};
}
Q_GLOBAL_STATIC(GenericMotionEventListeners, g_genericMotionEventListeners)
static void sendRequestPermissionsResult(JNIEnv *env, jobject /*obj*/, jint requestCode,
jobjectArray permissions, jintArray grantResults)
{
QMutexLocker locker(&g_pendingPermissionRequestsMutex);
auto it = g_pendingPermissionRequests->find(requestCode);
if (it == g_pendingPermissionRequests->end()) {
// show an error or something ?
return;
}
auto request = *it;
g_pendingPermissionRequests->erase(it);
locker.unlock();
Qt::ConnectionType connection = QThread::currentThread() == request->thread() ? Qt::DirectConnection : Qt::QueuedConnection;
QtAndroidPrivate::PermissionsHash hash;
const int size = env->GetArrayLength(permissions);
std::unique_ptr<jint[]> results(new jint[size]);
env->GetIntArrayRegion(grantResults, 0, size, results.get());
for (int i = 0 ; i < size; ++i) {
const auto &permission = QJniObject(env->GetObjectArrayElement(permissions, i)).toString();
auto value = results[i] == PERMISSION_GRANTED ?
QtAndroidPrivate::PermissionsResult::Granted :
QtAndroidPrivate::PermissionsResult::Denied;
hash[permission] = value;
}
QMetaObject::invokeMethod(request, "sendResult", connection, Q_ARG(QtAndroidPrivate::PermissionsHash, hash));
}
static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event)
{
jboolean ret = JNI_FALSE;
@ -344,14 +269,12 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
}
static const JNINativeMethod methods[] = {
{"runPendingCppRunnables", "()V", reinterpret_cast<void *>(runPendingCppRunnables)},
{"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast<void *>(dispatchGenericMotionEvent)},
{"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast<void *>(dispatchKeyEvent)},
{"sendRequestPermissionsResult", "(I[Ljava/lang/String;[I)V", reinterpret_cast<void *>(sendRequestPermissionsResult)},
};
const bool regOk = (env->RegisterNatives(jQtNative, methods, sizeof(methods) / sizeof(methods[0])) == JNI_OK);
env->DeleteLocalRef(jQtNative);
if (!regOk && QJniEnvironment::checkAndClearExceptions(env))
return JNI_ERR;
@ -361,17 +284,9 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
if (!registerNativeInterfaceNatives())
return JNI_ERR;
g_runPendingCppRunnablesMethodID = env->GetStaticMethodID(jQtNative,
"runPendingCppRunnablesOnAndroidThread",
"()V");
g_jNativeClass = static_cast<jclass>(env->NewGlobalRef(jQtNative));
env->DeleteLocalRef(jQtNative);
qRegisterMetaType<QtAndroidPrivate::PermissionsHash>();
return JNI_OK;
}
jobject QtAndroidPrivate::activity()
{
return g_jActivity;
@ -410,110 +325,6 @@ jint QtAndroidPrivate::androidSdkVersion()
return sdkVersion;
}
void QtAndroidPrivate::runOnAndroidThread(const QtAndroidPrivate::Runnable &runnable, JNIEnv *env)
{
QMutexLocker locker(&g_pendingRunnablesMutex);
const bool triggerRun = g_pendingRunnables->empty();
g_pendingRunnables->push_back(runnable);
locker.unlock();
if (triggerRun)
env->CallStaticVoidMethod(g_jNativeClass, g_runPendingCppRunnablesMethodID);
}
static bool waitForSemaphore(int timeoutMs, QSharedPointer<QSemaphore> sem)
{
while (timeoutMs > 0) {
if (sem->tryAcquire(1, 10))
return true;
timeoutMs -= 10;
QCoreApplication::processEvents();
}
return false;
}
void QtAndroidPrivate::runOnAndroidThreadSync(const QtAndroidPrivate::Runnable &runnable, JNIEnv *env, int timeoutMs)
{
QSharedPointer<QSemaphore> sem(new QSemaphore);
runOnAndroidThread([&runnable, sem]{
runnable();
sem->release();
}, env);
waitForSemaphore(timeoutMs, sem);
}
void QtAndroidPrivate::requestPermissions(JNIEnv *env,
const QStringList &permissions,
const QtAndroidPrivate::PermissionsResultFunc &callbackFunc,
bool directCall)
{
if (androidSdkVersion() < 23 || !activity()) {
QHash<QString, QtAndroidPrivate::PermissionsResult> res;
for (const auto &perm : permissions)
res[perm] = checkPermission(perm);
callbackFunc(res);
return;
}
// Check API 23+ permissions
const int requestCode = nextRequestCode();
if (!directCall) {
QMutexLocker locker(&g_pendingPermissionRequestsMutex);
(*g_pendingPermissionRequests)[requestCode] = new PermissionsResultClass(callbackFunc);
}
runOnAndroidThread([permissions, callbackFunc, requestCode, directCall] {
if (directCall) {
QMutexLocker locker(&g_pendingPermissionRequestsMutex);
(*g_pendingPermissionRequests)[requestCode] = new PermissionsResultClass(callbackFunc);
}
QJniEnvironment env;
jclass clazz = env->FindClass("java/lang/String");
if (env.checkAndClearExceptions())
return;
auto array = env->NewObjectArray(permissions.size(), clazz, nullptr);
int index = 0;
for (const auto &perm : permissions)
env->SetObjectArrayElement(array, index++, QJniObject::fromString(perm).object());
QJniObject(activity()).callMethod<void>("requestPermissions", "([Ljava/lang/String;I)V", array, requestCode);
env->DeleteLocalRef(array);
}, env);
}
QtAndroidPrivate::PermissionsHash QtAndroidPrivate::requestPermissionsSync(JNIEnv *env, const QStringList &permissions, int timeoutMs)
{
QSharedPointer<QHash<QString, QtAndroidPrivate::PermissionsResult>> res(new QHash<QString, QtAndroidPrivate::PermissionsResult>());
QSharedPointer<QSemaphore> sem(new QSemaphore);
requestPermissions(env, permissions, [sem, res](const QHash<QString, PermissionsResult> &result){
*res = result;
sem->release();
}, true);
if (waitForSemaphore(timeoutMs, sem))
return std::move(*res);
else // mustn't touch *res
return QHash<QString, QtAndroidPrivate::PermissionsResult>();
}
QtAndroidPrivate::PermissionsResult QtAndroidPrivate::checkPermission(const QString &permission)
{
const auto res = QJniObject::callStaticMethod<jint>("org/qtproject/qt/android/QtNative",
"checkSelfPermission",
"(Ljava/lang/String;)I",
QJniObject::fromString(permission).object());
return res == PERMISSION_GRANTED ? PermissionsResult::Granted : PermissionsResult::Denied;
}
bool QtAndroidPrivate::shouldShowRequestPermissionRationale(const QString &permission)
{
if (androidSdkVersion() < 23 || !activity())
return false;
return QJniObject(activity()).callMethod<jboolean>("shouldShowRequestPermissionRationale",
"(Ljava/lang/String;)Z",
QJniObject::fromString(permission).object());
}
void QtAndroidPrivate::registerGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener *listener)
{
QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
@ -538,13 +349,6 @@ void QtAndroidPrivate::unregisterKeyEventListener(QtAndroidPrivate::KeyEventList
g_keyEventListeners()->listeners.removeOne(listener);
}
void QtAndroidPrivate::hideSplashScreen(JNIEnv *env, int duration)
{
Q_UNUSED(env)
QJniObject::callStaticMethod<void>("org/qtproject/qt/android/QtNative",
"hideSplashScreen", "(I)V", duration);
}
void QtAndroidPrivate::waitForServiceSetup()
{
g_waitForServiceSetupSemaphore->acquire();
@ -608,5 +412,3 @@ Q_CORE_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
return JNI_VERSION_1_6;
}
#include "qjnihelpers.moc"

View File

@ -54,13 +54,9 @@
#include <jni.h>
#include <functional>
#include <QtCore/private/qglobal_p.h>
#include <QHash>
#include <QMetaType>
QT_BEGIN_NAMESPACE
class QRunnable;
namespace QtAndroidPrivate
{
class Q_CORE_EXPORT ActivityResultListener
@ -106,14 +102,6 @@ namespace QtAndroidPrivate
virtual jobject onBind(jobject intent) = 0;
};
enum class PermissionsResult {
Granted,
Denied
};
typedef QHash<QString, QtAndroidPrivate::PermissionsResult> PermissionsHash;
typedef std::function<void()> Runnable;
typedef std::function<void(const PermissionsHash &)> PermissionsResultFunc;
Q_CORE_EXPORT jobject activity();
Q_CORE_EXPORT jobject service();
Q_CORE_EXPORT jobject context();
@ -122,12 +110,6 @@ namespace QtAndroidPrivate
Q_CORE_EXPORT jclass findClass(const char *className, JNIEnv *env);
jobject classLoader();
Q_CORE_EXPORT jint androidSdkVersion();
Q_CORE_EXPORT void runOnAndroidThread(const Runnable &runnable, JNIEnv *env);
Q_CORE_EXPORT void runOnAndroidThreadSync(const Runnable &runnable, JNIEnv *env, int timeoutMs = INT_MAX);
Q_CORE_EXPORT void requestPermissions(JNIEnv *env, const QStringList &permissions, const PermissionsResultFunc &callbackFunc, bool directCall = false);
Q_CORE_EXPORT PermissionsHash requestPermissionsSync(JNIEnv *env, const QStringList &permissions, int timeoutMs = INT_MAX);
Q_CORE_EXPORT PermissionsResult checkPermission(const QString &permission);
Q_CORE_EXPORT bool shouldShowRequestPermissionRationale(const QString &permission);
bool registerPermissionNatives();
bool registerNativeInterfaceNatives();
@ -151,9 +133,6 @@ namespace QtAndroidPrivate
Q_CORE_EXPORT void registerKeyEventListener(KeyEventListener *listener);
Q_CORE_EXPORT void unregisterKeyEventListener(KeyEventListener *listener);
// TODO: Remove once other modules refectoring is done and androidextras is not needed.
Q_CORE_EXPORT void hideSplashScreen(JNIEnv *env, int duration = 0);
Q_CORE_EXPORT void waitForServiceSetup();
Q_CORE_EXPORT int acuqireServiceSetup(int flags);
Q_CORE_EXPORT void setOnBindListener(OnBindListener *listener);
@ -162,6 +141,4 @@ namespace QtAndroidPrivate
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QtAndroidPrivate::PermissionsHash)
#endif // QJNIHELPERS_H