6#include <QtCore/qbuffer.h>
7#include <QtCore/qdatastream.h>
8#include <QtCore/qjnienvironment.h>
9#include <QtCore/qvariant.h>
10#include <QtCore/qmutex.h>
11#include <QtCore/qtimer.h>
12#include <QtCore/qset.h>
14#if QT_CONFIG(permissions)
15#include <QtCore/qpromise.h>
20using namespace Qt::StringLiterals;
21using namespace QtJniTypes;
38 friend class QAndroidBinder;
39 friend class QAndroidParcel;
46 :
handle(
"java/io/FileDescriptor")
48 QJniEnvironment().checkAndClearExceptions();
49 handle.setField(
"descriptor", fd);
57 "()Landroid/os/Parcel;").
object())
69 handle.callMethod<
void>(
"writeByteArray", data);
74 QJniEnvironment().checkAndClearExceptions();
75 handle.callMethod<
void>(
"writeStrongBinder",
"(Landroid/os/IBinder;)V",
76 binder.handle().object());
81 QJniEnvironment().checkAndClearExceptions();
82 handle.callMethod<
void>(
"writeFileDescriptor",
"(Ljava/io/FileDescriptor;)V",
83 FileDescriptor(fd).handle.object());
88 QJniEnvironment().checkAndClearExceptions();
89 auto array = handle.callObjectMethod(
"createByteArray",
"()[B");
91 auto sz = env->GetArrayLength(jbyteArray(array.object()));
92 QByteArray res(sz, Qt::Initialization::Uninitialized);
93 env->GetByteArrayRegion(jbyteArray(array.object()), 0, sz,
94 reinterpret_cast<jbyte *>(res.data()));
100 QJniEnvironment().checkAndClearExceptions();
101 auto parcelFD = handle.callObjectMethod(
"readFileDescriptor",
102 "()Landroid/os/ParcelFileDescriptor;");
103 if (parcelFD.isValid())
104 return parcelFD.callMethod<jint>(
"getFd",
"()I");
110 QJniEnvironment().checkAndClearExceptions();
111 auto strongBinder = handle.callObjectMethod(
"readStrongBinder",
"()Landroid/os/IBinder;");
112 return QAndroidBinder(strongBinder.object());
116
117
118
119
120
121
122
123
124
125
126
127
130
131
132QAndroidParcel::QAndroidParcel()
133 : d(
new QAndroidParcelPrivate())
138
139
140QAndroidParcel::QAndroidParcel(
const QJniObject& parcel)
141 : d(
new QAndroidParcelPrivate(parcel))
146QAndroidParcel::~QAndroidParcel()
151
152
153void QAndroidParcel::writeData(
const QByteArray &data)
const
159
160
161
162void QAndroidParcel::writeVariant(
const QVariant &value)
const
165 QDataStream stream(&buff, QIODevice::WriteOnly);
171
172
173
174void QAndroidParcel::writeBinder(
const QAndroidBinder &binder)
const
176 d->writeBinder(binder);
180
181
182void QAndroidParcel::writeFileDescriptor(
int fd)
const
184 d->writeFileDescriptor(fd);
188
189
190QByteArray QAndroidParcel::readData()
const
192 return d->readData();
196
197
198QVariant QAndroidParcel::readVariant()
const
200 QDataStream stream(d->readData());
207
208
209QAndroidBinder QAndroidParcel::readBinder()
const
211 return d->readBinder();
215
216
217int QAndroidParcel::readFileDescriptor()
const
219 return d->readFileDescriptor();
223
224
225QJniObject QAndroidParcel::handle()
const
233
234
235
236
237
238
239
240
241
242
243
244
248
249
250
251
252
253
254
255
256
263 :
handle(
"org/qtproject/qt/android/extras/QtAndroidBinder",
"(J)V",
jlong(
binder))
264 , m_isQtAndroidBinder(
true)
266 QJniEnvironment().checkAndClearExceptions();
274 if (m_isQtAndroidBinder) {
275 QJniEnvironment().checkAndClearExceptions();
276 handle.callMethod<
void>(
"setId",
"(J)V", jlong(0));
277 if (m_deleteListener)
284 std::function<
void()> m_deleteListener;
285 bool m_isQtAndroidBinder;
286 friend class QAndroidBinder;
290
291
292
293
294QAndroidBinder::QAndroidBinder()
295 : d(
new QAndroidBinderPrivate(
this))
300
301
302
303
304QAndroidBinder::QAndroidBinder(
const QJniObject &binder)
305 : d(
new QAndroidBinderPrivate(binder))
309QAndroidBinder::~QAndroidBinder()
314
315
316
317
318
319
320
321
322
323
324
325
326
327bool QAndroidBinder::onTransact(
int ,
const QAndroidParcel &,
328 const QAndroidParcel &, CallType )
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348bool QAndroidBinder::transact(
int code,
const QAndroidParcel &data,
349 QAndroidParcel *reply, CallType flags)
const
351 QJniEnvironment().checkAndClearExceptions();
352 return d->handle.callMethod<jboolean>(
"transact",
353 "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z",
354 jint(code), data.d->handle.object(),
355 reply ? reply->d->handle.object() :
nullptr,
360
361
362QJniObject QAndroidBinder::handle()
const
371
372
373
374
375
376
377
378
379
380
381
382
383
384
387
388
389QAndroidServiceConnection::QAndroidServiceConnection()
390 : m_handle(
"org/qtproject/qt/android/extras/QtAndroidServiceConnection",
"(J)V", jlong(
this))
395
396
397
398
399
400
401QAndroidServiceConnection::QAndroidServiceConnection(
const QJniObject &serviceConnection)
402 : m_handle(serviceConnection)
406QAndroidServiceConnection::~QAndroidServiceConnection()
408 m_handle.callMethod<
void>(
"setId",
"(J)V", jlong(
this));
412
413
414QJniObject QAndroidServiceConnection::handle()
const
420
421
422
423
424
425
426
427
428
429
430
433
434
435
436
437
438
439
440
441
442
445Q_CONSTINIT
static QBasicAtomicInteger<uint> nextUniqueActivityRequestCode = Q_BASIC_ATOMIC_INITIALIZER(0);
450 constexpr uint ReservedForQtOffset = 0x1000;
452 const uint requestCodeBase = nextUniqueActivityRequestCode.fetchAndAddRelaxed(1);
453 if (requestCodeBase == uint(INT_MAX) - ReservedForQtOffset)
454 qWarning(
"Unique activity request code has wrapped. Unexpected behavior may occur.");
456 const int requestCode =
static_cast<
int>(requestCodeBase + ReservedForQtOffset);
469 const auto oldSize = localToGlobalRequestCode.size();
470 auto &e = localToGlobalRequestCode[localRequestCode];
471 if (localToGlobalRequestCode.size() != oldSize) {
474 e = globalRequestCode;
475 globalToLocalRequestCode[globalRequestCode] = localRequestCode;
482 const auto it = std::as_const(globalToLocalRequestCode).find(requestCode);
483 if (it != globalToLocalRequestCode.cend()) {
484 q->handleActivityResult(*it, resultCode, QJniObject(data));
493 return publicObject->d.get();
498
499
500
501
502
503
504
505
506
507
508
511
512
513QAndroidActivityResultReceiver::QAndroidActivityResultReceiver()
514 : d(
new QAndroidActivityResultReceiverPrivate)
517 QtAndroidPrivate::registerActivityResultListener(d.get());
521
522
523QAndroidActivityResultReceiver::~QAndroidActivityResultReceiver()
525 QtAndroidPrivate::unregisterActivityResultListener(d.get());
529
530
531
532
533
534
535
536
537
538
546 const std::function<QAndroidBinder*(
const QAndroidIntent&)> &binder ={})
550 QTimer::singleShot(0,
this, [
this]{ QtAndroidPrivate::setOnBindListener(
this);});
555 QMutexLocker lock(&m_bindersMutex);
556 while (!m_binders.empty()) {
557 auto it = m_binders.begin();
567 auto qai = QAndroidIntent(intent);
568 auto binder = m_binder ? m_binder(qai) : m_service->onBind(qai);
571 QMutexLocker lock(&m_bindersMutex);
572 binder->d->setDeleteListener([
this, binder]{binderDestroied(binder);});
573 m_binders.insert(binder);
575 return binder->handle().object();
581 void binderDestroied(QAndroidBinder* obj)
583 QMutexLocker lock(&m_bindersMutex);
584 m_binders.remove(obj);
595
596
597
598
599
600
601
602
603
604
605
606
610
611
612
613
614
615
616
617
618QAndroidService::QAndroidService(
int &argc,
char **argv,
int flags)
619 : QCoreApplication (argc, argv, QtAndroidPrivate::acuqireServiceSetup(flags))
620 , d(
new QAndroidServicePrivate{
this})
625
626
627
628
629
630
631
632
633
634
635QAndroidService::QAndroidService(
int &argc,
char **argv,
636 const std::function<QAndroidBinder*(
const QAndroidIntent&)> &binder,
638 : QCoreApplication (argc, argv, QtAndroidPrivate::acuqireServiceSetup(flags))
639 , d(
new QAndroidServicePrivate{
this, binder})
643QAndroidService::~QAndroidService()
647
648
649
650
651
652
653
654
655
656
657
658QAndroidBinder* QAndroidService::onBind(
const QAndroidIntent &)
664 jobject reply, jint flags)
669 return reinterpret_cast<QAndroidBinder*>(id)->onTransact(
670 code, QAndroidParcel(data), QAndroidParcel(reply), QAndroidBinder::CallType(flags));
679 return reinterpret_cast<QAndroidServiceConnection *>(id)->onServiceConnected(
680 QJniObject(name).toString(), QAndroidBinder(service));
688 return reinterpret_cast<QAndroidServiceConnection *>(id)->onServiceDisconnected(
689 QJniObject(name).toString());
694 static const JNINativeMethod methods[] = {
695 {
"onTransact",
"(JILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (
void *)onTransact},
696 {
"onServiceConnected",
"(JLjava/lang/String;Landroid/os/IBinder;)V", (
void *)onServiceConnected},
697 {
"onServiceDisconnected",
"(JLjava/lang/String;)V", (
void *)onServiceDisconnected}
700 return env.registerNativeMethods(
"org/qtproject/qt/android/extras/QtNative", methods, 3);
704
705
706
707
708
709
710
711
712
713
714
715
718
719
720QAndroidIntent::QAndroidIntent()
721 : m_handle(
"android.content.Intent",
"()V")
726QAndroidIntent::~QAndroidIntent()
730
731
732QAndroidIntent::QAndroidIntent(
const QJniObject &intent)
738
739
740QAndroidIntent::QAndroidIntent(
const QString &action)
741 : m_handle(
"android.content.Intent",
"(Ljava/lang/String;)V",
742 QJniObject::fromString(action).object())
744 QJniEnvironment().checkAndClearExceptions();
748
749
750
751
752
753
754
755
756QAndroidIntent::QAndroidIntent(
const QJniObject &packageContext,
const char *className)
757 : m_handle(
"android/content/Intent",
"(Landroid/content/Context;Ljava/lang/Class;)V",
758 packageContext.object(), QJniEnvironment().findClass(className))
760 QJniEnvironment().checkAndClearExceptions();
764
765
766void QAndroidIntent::putExtra(
const QString &key,
const QByteArray &data)
768 m_handle.callMethod<QtJniTypes::Intent>(
"putExtra", key, data);
772
773
774QByteArray QAndroidIntent::extraBytes(
const QString &key)
776 return m_handle.callMethod<QByteArray>(
"getByteArrayExtra", key);
780
781
782void QAndroidIntent::putExtra(
const QString &key,
const QVariant &value)
785 QDataStream stream(&buff, QIODevice::WriteOnly);
791
792
793QVariant QAndroidIntent::extraVariant(
const QString &key)
795 QDataStream stream(extraBytes(key));
802
803
804QJniObject QAndroidIntent::handle()
const
812
813
814
815
816
817
818
819
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
859
860
861
862
863
864
865
866
867
868
869
870
871
872
874 int receiverRequestCode,
875 QAndroidActivityResultReceiver *resultReceiver)
877 QJniObject activity = QtAndroidPrivate::activity();
878 if (resultReceiver != 0) {
880 QAndroidActivityResultReceiverPrivate::get(resultReceiver);
881 activity.callMethod<
void>(
"startActivityForResult",
882 "(Landroid/content/Intent;I)V",
883 intent.object<jobject>(),
884 resultReceiverD->globalRequestCode(receiverRequestCode));
886 activity.callMethod<
void>(
"startActivity",
887 "(Landroid/content/Intent;)V",
888 intent.object<jobject>());
893
894
895
896
897
898
899
900
901
902
903
904
905
906
908 int receiverRequestCode,
909 QAndroidActivityResultReceiver *resultReceiver)
911 startActivity(intent.handle(), receiverRequestCode, resultReceiver);
915
916
917
918
919
921 int receiverRequestCode,
922 std::function<
void(
int,
int,
const QJniObject &data)> callbackFunc)
924 QJniObject activity = QtAndroidPrivate::activity();
931
932
933
934
935
936
937
938
939
940
941
942
943
944
946 int receiverRequestCode,
947 QAndroidActivityResultReceiver *resultReceiver)
949 QJniObject activity = QtAndroidPrivate::activity();
950 if (resultReceiver != 0) {
952 QAndroidActivityResultReceiverPrivate::get(resultReceiver);
953 activity.callMethod<
void>(
"startIntentSenderForResult",
954 "(Landroid/content/IntentSender;ILandroid/content/Intent;III)V",
955 intentSender.object<jobject>(),
956 resultReceiverD->globalRequestCode(receiverRequestCode),
962 activity.callMethod<
void>(
"startIntentSender",
963 "(Landroid/content/IntentSender;Landroid/content/Intent;III)V",
964 intentSender.object<jobject>(),
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
991 const QAndroidServiceConnection &serviceConnection, BindFlags flags)
993 QJniEnvironment().checkAndClearExceptions();
994 QJniObject contextObj = QtAndroidPrivate::context();
995 return contextObj.callMethod<jboolean>(
997 "(Landroid/content/Intent;Landroid/content/ServiceConnection;I)Z",
998 serviceIntent.handle().object(),
999 serviceConnection.handle().object(),
1013 const QJniObject &intent)
1015 callbackMap[receiverRequestCode](receiverRequestCode, resultCode, intent);
1016 callbackMap.remove(receiverRequestCode);
1027 int receiverRequestCode,
1028 std::function<
void(
int,
int,
const QJniObject &data)> callbackFunc)
1030 callbackMap.insert(receiverRequestCode, callbackFunc);
1033#if QT_CONFIG(permissions)
1036QtAndroidPrivate::PermissionResult resultFromAndroid(jint value)
1038 return value == 0 ? QtAndroidPrivate::Authorized : QtAndroidPrivate::Denied;
1041using PendingPermissionRequestsHash
1042 = QHash<
int, QSharedPointer<QPromise<QtAndroidPrivate::PermissionResult>>>;
1043Q_GLOBAL_STATIC(PendingPermissionRequestsHash, g_pendingPermissionRequests);
1044Q_CONSTINIT
static QBasicMutex g_pendingPermissionRequestsMutex;
1046static int nextRequestCode()
1048 Q_CONSTINIT
static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0);
1049 return counter.fetchAndAddRelaxed(1);
1053
1054
1055
1056
1057
1058
1059static void sendRequestPermissionsResult(JNIEnv *env, jclass obj, jint requestCode,
1060 const QJniArray<
int> &grantResults)
1065 QMutexLocker locker(&g_pendingPermissionRequestsMutex);
1066 auto it = g_pendingPermissionRequests->constFind(requestCode);
1067 if (it == g_pendingPermissionRequests->constEnd()) {
1068 qWarning() <<
"Found no valid pending permission request for request code" << requestCode;
1073 g_pendingPermissionRequests->erase(it);
1076 request->addResults([grantResults](){
1077 QList<QtAndroidPrivate::PermissionResult> results(grantResults.size(),
1079 for (qsizetype i = 0; i < grantResults.size(); ++i)
1080 results[i] = resultFromAndroid(grantResults.at(i));
1084 QtAndroidPrivate::releaseAndroidDeadlockProtector();
1087Q_DECLARE_JNI_NATIVE_METHOD(sendRequestPermissionsResult)
1089QFuture<QtAndroidPrivate::PermissionResult>
1090requestPermissionsInternal(
const QStringList &permissions)
1094 if (QtAndroidPrivate::androidSdkVersion() < 23) {
1095 QList<QtAndroidPrivate::PermissionResult> result;
1096 result.reserve(permissions.size());
1098 for (
const QString &permission : permissions)
1099 result.push_back(QtAndroidPrivate::checkPermission(permission).result());
1100 return QtFuture::makeReadyRangeFuture(result);
1103 QtAndroidPrivate::AndroidDeadlockProtector protector(
1104 u"requestPermissionsInternal()"_s);
1105 if (!protector.acquire())
1106 return QtFuture::makeReadyValueFuture(QtAndroidPrivate::Denied);
1108 QSharedPointer<QPromise<QtAndroidPrivate::PermissionResult>> promise;
1109 promise.reset(
new QPromise<QtAndroidPrivate::PermissionResult>());
1110 QFuture<QtAndroidPrivate::PermissionResult> future = promise->future();
1113 const int requestCode = nextRequestCode();
1114 QMutexLocker locker(&g_pendingPermissionRequestsMutex);
1115 g_pendingPermissionRequests->insert(requestCode, promise);
1118 QNativeInterface::QAndroidApplication::runOnAndroidMainThread([permissions, requestCode] {
1119 QJniEnvironment env;
1120 jclass clazz = env.findClass(
"java/lang/String");
1121 auto array = env->NewObjectArray(permissions.size(), clazz,
nullptr);
1124 for (
auto &perm : permissions)
1125 env->SetObjectArrayElement(array, index++, QJniObject::fromString(perm).object());
1127 QJniObject(QtAndroidPrivate::activity()).callMethod<
void>(
"requestPermissions",
1128 "([Ljava/lang/String;I)V",
1131 env->DeleteLocalRef(array);
1134 QtAndroidPrivate::releaseAndroidDeadlockProtector();
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151QFuture<QtAndroidPrivate::PermissionResult>
1152QtAndroidPrivate::requestPermission(
const QString &permission)
1154 return requestPermissions({permission});
1157QFuture<QtAndroidPrivate::PermissionResult>
1158QtAndroidPrivate::requestPermissions(
const QStringList &permissions)
1161 if (permissions.isEmpty())
1162 return QtFuture::makeReadyValueFuture(QtAndroidPrivate::Denied);
1163 return requestPermissionsInternal(permissions);
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178QFuture<QtAndroidPrivate::PermissionResult>
1179QtAndroidPrivate::checkPermission(
const QString &permission)
1181 QtAndroidPrivate::PermissionResult result = Denied;
1182 if (!permission.isEmpty()) {
1183 auto res = QtNative::callStaticMethod<jint>(
"checkSelfPermission", permission);
1184 result = resultFromAndroid(res);
1186 return QtFuture::makeReadyValueFuture(result);
1189bool QtAndroidPrivate::registerPermissionNatives(QJniEnvironment &env)
1191 if (QtAndroidPrivate::androidSdkVersion() < 23)
1194 return env.registerNativeMethods<QtNative>({
1195 Q_JNI_NATIVE_METHOD(sendRequestPermissionsResult)
1203#include "moc_qandroidextras_p.cpp"
void handleActivityResult(int receiverRequestCode, int resultCode, const QJniObject &intent) override
Reimplement this function to get activity results after starting an activity using either QtAndroidPr...
static QAndroidActivityCallbackResultReceiver * instance()
QAndroidActivityCallbackResultReceiver()
void registerCallback(int receiverRequestCode, std::function< void(int, int, const QJniObject &)> callbackFunc)
int globalRequestCode(int localRequestCode) const
QAndroidActivityResultReceiver * q
QHash< int, int > globalToLocalRequestCode
bool handleActivityResult(jint requestCode, jint resultCode, jobject data)
static QAndroidActivityResultReceiverPrivate * get(QAndroidActivityResultReceiver *publicObject)
QHash< int, int > localToGlobalRequestCode
QAndroidBinderPrivate(const QJniObject &binder)
void setDeleteListener(const std::function< void()> &func)
QAndroidBinderPrivate(QAndroidBinder *binder)
void writeBinder(const QAndroidBinder &binder) const
QAndroidBinder readBinder() const
void writeData(const QByteArray &data) const
QAndroidParcelPrivate(const QJniObject &parcel)
QByteArray readData() const
int readFileDescriptor() const
void writeFileDescriptor(int fd) const
QSet< QAndroidBinder * > m_binders
~QAndroidServicePrivate()
std::function< QAndroidBinder *(const QAndroidIntent &)> m_binder
QAndroidServicePrivate(QAndroidService *service, const std::function< QAndroidBinder *(const QAndroidIntent &)> &binder={})
QAndroidService * m_service
jobject onBind(jobject intent) override
\preliminary \inmodule QtCorePrivate
Q_CORE_EXPORT void startIntentSender(const QJniObject &intentSender, int receiverRequestCode, QAndroidActivityResultReceiver *resultReceiver=nullptr)
bool registerExtrasNatives(QJniEnvironment &env)
Q_CORE_EXPORT void startActivity(const QJniObject &intent, int receiverRequestCode, QAndroidActivityResultReceiver *resultReceiver=nullptr)
Q_CORE_EXPORT bool bindService(const QAndroidIntent &serviceIntent, const QAndroidServiceConnection &serviceConnection, BindFlags flags=BindFlag::None)
Q_CORE_EXPORT void startActivity(const QJniObject &intent, int receiverRequestCode, std::function< void(int, int, const QJniObject &data)> callbackFunc)
static jboolean onTransact(JNIEnv *, jclass, jlong id, jint code, jobject data, jobject reply, jint flags)
static void onServiceConnected(JNIEnv *, jclass, jlong id, jstring name, jobject service)
static void onServiceDisconnected(JNIEnv *, jclass, jlong id, jstring name)
static int uniqueActivityRequestCode()
FileDescriptor(int fd=-1)