1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qjnihelpers_p.h"
41 #include "qjni_p.h"
42 #include "qmutex.h"
43 #include "qlist.h"
44 #include "qsemaphore.h"
45 #include "qsharedpointer.h"
46 #include "qvector.h"
47 #include "qthread.h"
48 #include "qcoreapplication.h"
49 #include <QtCore/qrunnable.h>
50
51 #include <deque>
52 #include <memory>
53
54 QT_BEGIN_NAMESPACE
55
56 namespace QtAndroidPrivate {
57 // *Listener virtual function implementations.
58 // Defined out-of-line to pin the vtable/type_info.
~ActivityResultListener()59 ActivityResultListener::~ActivityResultListener() {}
~NewIntentListener()60 NewIntentListener::~NewIntentListener() {}
~ResumePauseListener()61 ResumePauseListener::~ResumePauseListener() {}
handlePause()62 void ResumePauseListener::handlePause() {}
handleResume()63 void ResumePauseListener::handleResume() {}
~GenericMotionEventListener()64 GenericMotionEventListener::~GenericMotionEventListener() {}
~KeyEventListener()65 KeyEventListener::~KeyEventListener() {}
66 }
67
68 static JavaVM *g_javaVM = nullptr;
69 static jobject g_jActivity = nullptr;
70 static jobject g_jService = nullptr;
71 static jobject g_jClassLoader = nullptr;
72 static jint g_androidSdkVersion = 0;
73 static jclass g_jNativeClass = nullptr;
74 static jmethodID g_runPendingCppRunnablesMethodID = nullptr;
75 static jmethodID g_hideSplashScreenMethodID = nullptr;
76 Q_GLOBAL_STATIC(std::deque<QtAndroidPrivate::Runnable>, g_pendingRunnables);
77 static QBasicMutex g_pendingRunnablesMutex;
78
79 Q_GLOBAL_STATIC_WITH_ARGS(QtAndroidPrivate::OnBindListener*, g_onBindListener, (nullptr));
80 Q_GLOBAL_STATIC(QMutex, g_onBindListenerMutex);
81 Q_GLOBAL_STATIC(QSemaphore, g_waitForServiceSetupSemaphore);
82 Q_GLOBAL_STATIC(QAtomicInt, g_serviceSetupLockers);
83
84 class PermissionsResultClass : public QObject
85 {
86 Q_OBJECT
87 public:
PermissionsResultClass(const QtAndroidPrivate::PermissionsResultFunc & func)88 PermissionsResultClass(const QtAndroidPrivate::PermissionsResultFunc &func) : m_func(func) {}
sendResult(const QtAndroidPrivate::PermissionsHash & result)89 Q_INVOKABLE void sendResult(const QtAndroidPrivate::PermissionsHash &result) { m_func(result); delete this;}
90
91 private:
92 QtAndroidPrivate::PermissionsResultFunc m_func;
93 };
94
95 typedef QHash<int, PermissionsResultClass*> PendingPermissionRequestsHash;
96 Q_GLOBAL_STATIC(PendingPermissionRequestsHash, g_pendingPermissionRequests);
97 static QBasicMutex g_pendingPermissionRequestsMutex;
nextRequestCode()98 static int nextRequestCode()
99 {
100 static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0);
101 return counter.fetchAndAddRelaxed(1);
102 }
103
104 // function called from Java from Android UI thread
runPendingCppRunnables(JNIEnv *,jobject)105 static void runPendingCppRunnables(JNIEnv */*env*/, jobject /*obj*/)
106 {
107 for (;;) { // run all posted runnables
108 QMutexLocker locker(&g_pendingRunnablesMutex);
109 if (g_pendingRunnables->empty()) {
110 break;
111 }
112 QtAndroidPrivate::Runnable runnable(std::move(g_pendingRunnables->front()));
113 g_pendingRunnables->pop_front();
114 locker.unlock();
115 runnable(); // run it outside the sync block!
116 }
117 }
118
119 namespace {
120 struct GenericMotionEventListeners {
121 QMutex mutex;
122 QVector<QtAndroidPrivate::GenericMotionEventListener *> listeners;
123 };
124
125 enum {
126 PERMISSION_GRANTED = 0
127 };
128 }
Q_GLOBAL_STATIC(GenericMotionEventListeners,g_genericMotionEventListeners)129 Q_GLOBAL_STATIC(GenericMotionEventListeners, g_genericMotionEventListeners)
130
131 static void sendRequestPermissionsResult(JNIEnv *env, jobject /*obj*/, jint requestCode,
132 jobjectArray permissions, jintArray grantResults)
133 {
134 QMutexLocker locker(&g_pendingPermissionRequestsMutex);
135 auto it = g_pendingPermissionRequests->find(requestCode);
136 if (it == g_pendingPermissionRequests->end()) {
137 // show an error or something ?
138 return;
139 }
140 auto request = *it;
141 g_pendingPermissionRequests->erase(it);
142 locker.unlock();
143
144 Qt::ConnectionType connection = QThread::currentThread() == request->thread() ? Qt::DirectConnection : Qt::QueuedConnection;
145 QtAndroidPrivate::PermissionsHash hash;
146 const int size = env->GetArrayLength(permissions);
147 std::unique_ptr<jint[]> results(new jint[size]);
148 env->GetIntArrayRegion(grantResults, 0, size, results.get());
149 for (int i = 0 ; i < size; ++i) {
150 const auto &permission = QJNIObjectPrivate(env->GetObjectArrayElement(permissions, i)).toString();
151 auto value = results[i] == PERMISSION_GRANTED ?
152 QtAndroidPrivate::PermissionsResult::Granted :
153 QtAndroidPrivate::PermissionsResult::Denied;
154 hash[permission] = value;
155 }
156 QMetaObject::invokeMethod(request, "sendResult", connection, Q_ARG(QtAndroidPrivate::PermissionsHash, hash));
157 }
158
dispatchGenericMotionEvent(JNIEnv *,jclass,jobject event)159 static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event)
160 {
161 jboolean ret = JNI_FALSE;
162 QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
163 for (auto *listener : qAsConst(g_genericMotionEventListeners()->listeners))
164 ret |= listener->handleGenericMotionEvent(event);
165 return ret;
166 }
167
168 namespace {
169 struct KeyEventListeners {
170 QMutex mutex;
171 QVector<QtAndroidPrivate::KeyEventListener *> listeners;
172 };
173 }
Q_GLOBAL_STATIC(KeyEventListeners,g_keyEventListeners)174 Q_GLOBAL_STATIC(KeyEventListeners, g_keyEventListeners)
175
176 static jboolean dispatchKeyEvent(JNIEnv *, jclass, jobject event)
177 {
178 jboolean ret = JNI_FALSE;
179 QMutexLocker locker(&g_keyEventListeners()->mutex);
180 for (auto *listener : qAsConst(g_keyEventListeners()->listeners))
181 ret |= listener->handleKeyEvent(event);
182 return ret;
183 }
184
185 namespace {
186 class ActivityResultListeners
187 {
188 public:
189 QMutex mutex;
190 QList<QtAndroidPrivate::ActivityResultListener *> listeners;
191 };
192 }
193
Q_GLOBAL_STATIC(ActivityResultListeners,g_activityResultListeners)194 Q_GLOBAL_STATIC(ActivityResultListeners, g_activityResultListeners)
195
196 void QtAndroidPrivate::registerActivityResultListener(ActivityResultListener *listener)
197 {
198 QMutexLocker locker(&g_activityResultListeners()->mutex);
199 g_activityResultListeners()->listeners.append(listener);
200 }
201
unregisterActivityResultListener(ActivityResultListener * listener)202 void QtAndroidPrivate::unregisterActivityResultListener(ActivityResultListener *listener)
203 {
204 QMutexLocker locker(&g_activityResultListeners()->mutex);
205 g_activityResultListeners()->listeners.removeAll(listener);
206 }
207
handleActivityResult(jint requestCode,jint resultCode,jobject data)208 void QtAndroidPrivate::handleActivityResult(jint requestCode, jint resultCode, jobject data)
209 {
210 QMutexLocker locker(&g_activityResultListeners()->mutex);
211 const QList<QtAndroidPrivate::ActivityResultListener *> &listeners = g_activityResultListeners()->listeners;
212 for (int i=0; i<listeners.size(); ++i) {
213 if (listeners.at(i)->handleActivityResult(requestCode, resultCode, data))
214 break;
215 }
216 }
217
218 namespace {
219 class NewIntentListeners
220 {
221 public:
222 QMutex mutex;
223 QList<QtAndroidPrivate::NewIntentListener *> listeners;
224 };
225 }
226
Q_GLOBAL_STATIC(NewIntentListeners,g_newIntentListeners)227 Q_GLOBAL_STATIC(NewIntentListeners, g_newIntentListeners)
228
229 void QtAndroidPrivate::registerNewIntentListener(NewIntentListener *listener)
230 {
231 QMutexLocker locker(&g_newIntentListeners()->mutex);
232 g_newIntentListeners()->listeners.append(listener);
233 }
234
unregisterNewIntentListener(NewIntentListener * listener)235 void QtAndroidPrivate::unregisterNewIntentListener(NewIntentListener *listener)
236 {
237 QMutexLocker locker(&g_newIntentListeners()->mutex);
238 g_newIntentListeners()->listeners.removeAll(listener);
239 }
240
handleNewIntent(JNIEnv * env,jobject intent)241 void QtAndroidPrivate::handleNewIntent(JNIEnv *env, jobject intent)
242 {
243 QMutexLocker locker(&g_newIntentListeners()->mutex);
244 const QList<QtAndroidPrivate::NewIntentListener *> &listeners = g_newIntentListeners()->listeners;
245 for (int i=0; i<listeners.size(); ++i) {
246 if (listeners.at(i)->handleNewIntent(env, intent))
247 break;
248 }
249 }
250
251 namespace {
252 class ResumePauseListeners
253 {
254 public:
255 QMutex mutex;
256 QList<QtAndroidPrivate::ResumePauseListener *> listeners;
257 };
258 }
259
Q_GLOBAL_STATIC(ResumePauseListeners,g_resumePauseListeners)260 Q_GLOBAL_STATIC(ResumePauseListeners, g_resumePauseListeners)
261
262 void QtAndroidPrivate::registerResumePauseListener(ResumePauseListener *listener)
263 {
264 QMutexLocker locker(&g_resumePauseListeners()->mutex);
265 g_resumePauseListeners()->listeners.append(listener);
266 }
267
unregisterResumePauseListener(ResumePauseListener * listener)268 void QtAndroidPrivate::unregisterResumePauseListener(ResumePauseListener *listener)
269 {
270 QMutexLocker locker(&g_resumePauseListeners()->mutex);
271 g_resumePauseListeners()->listeners.removeAll(listener);
272 }
273
handlePause()274 void QtAndroidPrivate::handlePause()
275 {
276 QMutexLocker locker(&g_resumePauseListeners()->mutex);
277 const QList<QtAndroidPrivate::ResumePauseListener *> &listeners = g_resumePauseListeners()->listeners;
278 for (int i=0; i<listeners.size(); ++i)
279 listeners.at(i)->handlePause();
280 }
281
handleResume()282 void QtAndroidPrivate::handleResume()
283 {
284 QMutexLocker locker(&g_resumePauseListeners()->mutex);
285 const QList<QtAndroidPrivate::ResumePauseListener *> &listeners = g_resumePauseListeners()->listeners;
286 for (int i=0; i<listeners.size(); ++i)
287 listeners.at(i)->handleResume();
288 }
289
exceptionCheck(JNIEnv * env)290 static inline bool exceptionCheck(JNIEnv *env)
291 {
292 if (env->ExceptionCheck()) {
293 #ifdef QT_DEBUG
294 env->ExceptionDescribe();
295 #endif // QT_DEBUG
296 env->ExceptionClear();
297 return true;
298 }
299
300 return false;
301 }
302
setAndroidSdkVersion(JNIEnv * env)303 static void setAndroidSdkVersion(JNIEnv *env)
304 {
305 jclass androidVersionClass = env->FindClass("android/os/Build$VERSION");
306 if (exceptionCheck(env))
307 return;
308
309 jfieldID androidSDKFieldID = env->GetStaticFieldID(androidVersionClass, "SDK_INT", "I");
310 if (exceptionCheck(env))
311 return;
312
313 g_androidSdkVersion = env->GetStaticIntField(androidVersionClass, androidSDKFieldID);
314 }
315
setNativeActivity(JNIEnv * env,jclass,jobject activity)316 static void setNativeActivity(JNIEnv *env, jclass, jobject activity)
317 {
318 if (g_jActivity != 0)
319 env->DeleteGlobalRef(g_jActivity);
320
321 if (activity != 0) {
322 g_jActivity = env->NewGlobalRef(activity);
323 env->DeleteLocalRef(activity);
324 } else {
325 g_jActivity = 0;
326 }
327 }
328
setNativeService(JNIEnv * env,jclass,jobject service)329 static void setNativeService(JNIEnv *env, jclass, jobject service)
330 {
331 if (g_jService != 0)
332 env->DeleteGlobalRef(g_jService);
333
334 if (service != 0) {
335 g_jService = env->NewGlobalRef(service);
336 env->DeleteLocalRef(service);
337 } else {
338 g_jService = 0;
339 }
340 }
341
initJNI(JavaVM * vm,JNIEnv * env)342 jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
343 {
344 jclass jQtNative = env->FindClass("org/qtproject/qt5/android/QtNative");
345
346 if (exceptionCheck(env))
347 return JNI_ERR;
348
349 jmethodID activityMethodID = env->GetStaticMethodID(jQtNative,
350 "activity",
351 "()Landroid/app/Activity;");
352
353 if (exceptionCheck(env))
354 return JNI_ERR;
355
356 jobject activity = env->CallStaticObjectMethod(jQtNative, activityMethodID);
357
358 if (exceptionCheck(env))
359 return JNI_ERR;
360
361 jmethodID serviceMethodID = env->GetStaticMethodID(jQtNative,
362 "service",
363 "()Landroid/app/Service;");
364
365 if (exceptionCheck(env))
366 return JNI_ERR;
367
368 jobject service = env->CallStaticObjectMethod(jQtNative, serviceMethodID);
369
370 if (exceptionCheck(env))
371 return JNI_ERR;
372
373 jmethodID classLoaderMethodID = env->GetStaticMethodID(jQtNative,
374 "classLoader",
375 "()Ljava/lang/ClassLoader;");
376
377 if (exceptionCheck(env))
378 return JNI_ERR;
379
380 jobject classLoader = env->CallStaticObjectMethod(jQtNative, classLoaderMethodID);
381 if (exceptionCheck(env))
382 return JNI_ERR;
383
384 setAndroidSdkVersion(env);
385
386 g_jClassLoader = env->NewGlobalRef(classLoader);
387 env->DeleteLocalRef(classLoader);
388 if (activity) {
389 g_jActivity = env->NewGlobalRef(activity);
390 env->DeleteLocalRef(activity);
391 }
392 if (service) {
393 g_jService = env->NewGlobalRef(service);
394 env->DeleteLocalRef(service);
395 }
396 g_javaVM = vm;
397
398 static const JNINativeMethod methods[] = {
399 {"runPendingCppRunnables", "()V", reinterpret_cast<void *>(runPendingCppRunnables)},
400 {"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast<void *>(dispatchGenericMotionEvent)},
401 {"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast<void *>(dispatchKeyEvent)},
402 {"setNativeActivity", "(Landroid/app/Activity;)V", reinterpret_cast<void *>(setNativeActivity)},
403 {"setNativeService", "(Landroid/app/Service;)V", reinterpret_cast<void *>(setNativeService)},
404 {"sendRequestPermissionsResult", "(I[Ljava/lang/String;[I)V", reinterpret_cast<void *>(sendRequestPermissionsResult)},
405 };
406
407 const bool regOk = (env->RegisterNatives(jQtNative, methods, sizeof(methods) / sizeof(methods[0])) == JNI_OK);
408
409 if (!regOk && exceptionCheck(env))
410 return JNI_ERR;
411
412 g_runPendingCppRunnablesMethodID = env->GetStaticMethodID(jQtNative,
413 "runPendingCppRunnablesOnAndroidThread",
414 "()V");
415 g_hideSplashScreenMethodID = env->GetStaticMethodID(jQtNative, "hideSplashScreen", "(I)V");
416 g_jNativeClass = static_cast<jclass>(env->NewGlobalRef(jQtNative));
417 env->DeleteLocalRef(jQtNative);
418
419 qRegisterMetaType<QtAndroidPrivate::PermissionsHash>();
420 return JNI_OK;
421 }
422
423
activity()424 jobject QtAndroidPrivate::activity()
425 {
426 return g_jActivity;
427 }
428
service()429 jobject QtAndroidPrivate::service()
430 {
431 return g_jService;
432 }
433
context()434 jobject QtAndroidPrivate::context()
435 {
436 if (g_jActivity)
437 return g_jActivity;
438 if (g_jService)
439 return g_jService;
440
441 return 0;
442 }
443
javaVM()444 JavaVM *QtAndroidPrivate::javaVM()
445 {
446 return g_javaVM;
447 }
448
classLoader()449 jobject QtAndroidPrivate::classLoader()
450 {
451 return g_jClassLoader;
452 }
453
androidSdkVersion()454 jint QtAndroidPrivate::androidSdkVersion()
455 {
456 return g_androidSdkVersion;
457 }
458
runOnUiThread(QRunnable * runnable,JNIEnv * env)459 void QtAndroidPrivate::runOnUiThread(QRunnable *runnable, JNIEnv *env)
460 {
461 runOnAndroidThread([runnable]() {
462 runnable->run();
463 if (runnable->autoDelete())
464 delete runnable;
465 }, env);
466 }
467
runOnAndroidThread(const QtAndroidPrivate::Runnable & runnable,JNIEnv * env)468 void QtAndroidPrivate::runOnAndroidThread(const QtAndroidPrivate::Runnable &runnable, JNIEnv *env)
469 {
470 QMutexLocker locker(&g_pendingRunnablesMutex);
471 const bool triggerRun = g_pendingRunnables->empty();
472 g_pendingRunnables->push_back(runnable);
473 locker.unlock();
474 if (triggerRun)
475 env->CallStaticVoidMethod(g_jNativeClass, g_runPendingCppRunnablesMethodID);
476 }
477
waitForSemaphore(int timeoutMs,QSharedPointer<QSemaphore> sem)478 static bool waitForSemaphore(int timeoutMs, QSharedPointer<QSemaphore> sem)
479 {
480 while (timeoutMs > 0) {
481 if (sem->tryAcquire(1, 10))
482 return true;
483 timeoutMs -= 10;
484 QCoreApplication::processEvents();
485 }
486 return false;
487 }
488
runOnAndroidThreadSync(const QtAndroidPrivate::Runnable & runnable,JNIEnv * env,int timeoutMs)489 void QtAndroidPrivate::runOnAndroidThreadSync(const QtAndroidPrivate::Runnable &runnable, JNIEnv *env, int timeoutMs)
490 {
491 QSharedPointer<QSemaphore> sem(new QSemaphore);
492 runOnAndroidThread([&runnable, sem]{
493 runnable();
494 sem->release();
495 }, env);
496 waitForSemaphore(timeoutMs, sem);
497 }
498
requestPermissions(JNIEnv * env,const QStringList & permissions,const QtAndroidPrivate::PermissionsResultFunc & callbackFunc,bool directCall)499 void QtAndroidPrivate::requestPermissions(JNIEnv *env, const QStringList &permissions, const QtAndroidPrivate::PermissionsResultFunc &callbackFunc, bool directCall)
500 {
501 if (androidSdkVersion() < 23 || !activity()) {
502 QHash<QString, QtAndroidPrivate::PermissionsResult> res;
503 for (const auto &perm : permissions)
504 res[perm] = checkPermission(perm);
505 callbackFunc(res);
506 return;
507 }
508 // Check API 23+ permissions
509 const int requestCode = nextRequestCode();
510 if (!directCall) {
511 QMutexLocker locker(&g_pendingPermissionRequestsMutex);
512 (*g_pendingPermissionRequests)[requestCode] = new PermissionsResultClass(callbackFunc);
513 }
514
515 runOnAndroidThread([permissions, callbackFunc, requestCode, directCall] {
516 if (directCall) {
517 QMutexLocker locker(&g_pendingPermissionRequestsMutex);
518 (*g_pendingPermissionRequests)[requestCode] = new PermissionsResultClass(callbackFunc);
519 }
520
521 QJNIEnvironmentPrivate env;
522 auto array = env->NewObjectArray(permissions.size(), env->FindClass("java/lang/String"), nullptr);
523 int index = 0;
524 for (const auto &perm : permissions)
525 env->SetObjectArrayElement(array, index++, QJNIObjectPrivate::fromString(perm).object());
526 QJNIObjectPrivate(activity()).callMethod<void>("requestPermissions", "([Ljava/lang/String;I)V", array, requestCode);
527 env->DeleteLocalRef(array);
528 }, env);
529 }
530
requestPermissionsSync(JNIEnv * env,const QStringList & permissions,int timeoutMs)531 QtAndroidPrivate::PermissionsHash QtAndroidPrivate::requestPermissionsSync(JNIEnv *env, const QStringList &permissions, int timeoutMs)
532 {
533 QSharedPointer<QHash<QString, QtAndroidPrivate::PermissionsResult>> res(new QHash<QString, QtAndroidPrivate::PermissionsResult>());
534 QSharedPointer<QSemaphore> sem(new QSemaphore);
535 requestPermissions(env, permissions, [sem, res](const QHash<QString, PermissionsResult> &result){
536 *res = result;
537 sem->release();
538 }, true);
539 if (waitForSemaphore(timeoutMs, sem))
540 return std::move(*res);
541 else // mustn't touch *res
542 return QHash<QString, QtAndroidPrivate::PermissionsResult>();
543 }
544
checkPermission(const QString & permission)545 QtAndroidPrivate::PermissionsResult QtAndroidPrivate::checkPermission(const QString &permission)
546 {
547 const auto res = QJNIObjectPrivate::callStaticMethod<jint>("org/qtproject/qt5/android/QtNative",
548 "checkSelfPermission",
549 "(Ljava/lang/String;)I",
550 QJNIObjectPrivate::fromString(permission).object());
551 return res == PERMISSION_GRANTED ? PermissionsResult::Granted : PermissionsResult::Denied;
552 }
553
shouldShowRequestPermissionRationale(const QString & permission)554 bool QtAndroidPrivate::shouldShowRequestPermissionRationale(const QString &permission)
555 {
556 if (androidSdkVersion() < 23 || !activity())
557 return false;
558
559 return QJNIObjectPrivate(activity()).callMethod<jboolean>("shouldShowRequestPermissionRationale", "(Ljava/lang/String;)Z",
560 QJNIObjectPrivate::fromString(permission).object());
561 }
562
registerGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener * listener)563 void QtAndroidPrivate::registerGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener *listener)
564 {
565 QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
566 g_genericMotionEventListeners()->listeners.push_back(listener);
567 }
568
unregisterGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener * listener)569 void QtAndroidPrivate::unregisterGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener *listener)
570 {
571 QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
572 g_genericMotionEventListeners()->listeners.removeOne(listener);
573 }
574
registerKeyEventListener(QtAndroidPrivate::KeyEventListener * listener)575 void QtAndroidPrivate::registerKeyEventListener(QtAndroidPrivate::KeyEventListener *listener)
576 {
577 QMutexLocker locker(&g_keyEventListeners()->mutex);
578 g_keyEventListeners()->listeners.push_back(listener);
579 }
580
unregisterKeyEventListener(QtAndroidPrivate::KeyEventListener * listener)581 void QtAndroidPrivate::unregisterKeyEventListener(QtAndroidPrivate::KeyEventListener *listener)
582 {
583 QMutexLocker locker(&g_keyEventListeners()->mutex);
584 g_keyEventListeners()->listeners.removeOne(listener);
585 }
586
hideSplashScreen(JNIEnv * env,int duration)587 void QtAndroidPrivate::hideSplashScreen(JNIEnv *env, int duration)
588 {
589 env->CallStaticVoidMethod(g_jNativeClass, g_hideSplashScreenMethodID, duration);
590 }
591
waitForServiceSetup()592 void QtAndroidPrivate::waitForServiceSetup()
593 {
594 g_waitForServiceSetupSemaphore->acquire();
595 }
596
acuqireServiceSetup(int flags)597 int QtAndroidPrivate::acuqireServiceSetup(int flags)
598 {
599 g_serviceSetupLockers->ref();
600 return flags;
601 }
602
setOnBindListener(QtAndroidPrivate::OnBindListener * listener)603 void QtAndroidPrivate::setOnBindListener(QtAndroidPrivate::OnBindListener *listener)
604 {
605 QMutexLocker lock(g_onBindListenerMutex);
606 *g_onBindListener = listener;
607 if (!g_serviceSetupLockers->deref())
608 g_waitForServiceSetupSemaphore->release();
609 }
610
callOnBindListener(jobject intent)611 jobject QtAndroidPrivate::callOnBindListener(jobject intent)
612 {
613 QMutexLocker lock(g_onBindListenerMutex);
614 if (*g_onBindListener)
615 return (*g_onBindListener)->onBind(intent);
616 return nullptr;
617 }
618
619 QT_END_NAMESPACE
620
621 #include "qjnihelpers.moc"
622