8#include <QtCore/qcoreapplication.h>
9#include <QtCore/qjnienvironment.h>
10#include <QtCore/qjniobject.h>
11#include <QtCore/qurl.h>
12#include <QtCore/qdatetime.h>
13#include <QtCore/qmimedatabase.h>
14#include <QtCore/qdebug.h>
15#include <QtCore/qloggingcategory.h>
19using namespace QNativeInterface;
20using namespace Qt::StringLiterals;
24Q_DECLARE_JNI_CLASS(ParcelFileDescriptorType,
"android/os/ParcelFileDescriptor");
37 static QJniObject contentResolver;
38 if (!contentResolver.isValid()) {
39 contentResolver = QJniObject(QNativeInterface::QAndroidApplication::context())
40 .callMethod<QtJniTypes::ContentResolver>(
"getContentResolver");
43 return contentResolver;
50 setFileName(filename);
54 std::optional<QFile::Permissions> permissions)
56 Q_UNUSED(permissions);
58 if (openMode == QIODeviceBase::NotOpen)
61 if (!m_documentFile->exists() && (openMode & QIODevice::WriteOnly)) {
63 DocumentFilePtr parent = m_documentFile->parent();
65 qCWarning(lcAndroidContentFileEngine) <<
"Cannot create file under a null parent.";
69 if (!parent->exists() || !parent->isDirectory()) {
70 qCWarning(lcAndroidContentFileEngine)
71 <<
"Cannot create file, parent doesn't exist or not a directory:"
72 << parent->uri().toString();
76 const QString fileName = m_documentFile->initialName();
77 if (fileName.isEmpty()) {
78 qCWarning(lcAndroidContentFileEngine) <<
"Coudln't determine filename from content URI:"
79 << m_documentFile->uri().toString();
84 QString mimeType = db.mimeTypeForFile(fileName, QMimeDatabase::MatchDefault).name();
86 m_documentFile = parent->createFile(mimeType, fileName);
87 if (!m_documentFile) {
88 qCWarning(lcAndroidContentFileEngine) <<
"Failed to create new document under parent:"
89 << parent->uri().toString();
94 using namespace QtJniTypes;
95 const QString openModeStr = (openMode & QIODevice::WriteOnly) ?
"w"_L1 :
"r"_L1;
96 m_pfd = QtContentFileEngine::callStaticMethod<ParcelFileDescriptorType>(
98 contentResolverInstance().object<ContentResolver>(),
99 m_documentFile->uri().object<Uri>(),
102 if (!m_pfd.isValid())
105 const auto fd = m_pfd.callMethod<jint>(
"getFd");
108 closeNativeFileDescriptor();
112 return QFSFileEngine::open(openMode, fd, QFile::DontCloseHandle);
117 closeNativeFileDescriptor();
118 return QFSFileEngine::close();
123 if (m_pfd.isValid()) {
124 m_pfd.callMethod<
void>(
"close");
125 m_pfd = QJniObject();
131 return m_documentFile->length();
136 return m_documentFile->remove();
141 if (m_documentFile->rename(newName)) {
142 m_initialFile = newName;
149 std::optional<QFileDevice::Permissions> permissions)
const
151 Q_UNUSED(permissions)
153 QString tmp = dirName;
154 tmp.remove(m_initialFile);
156 QStringList dirParts = tmp.split(u'/');
157 dirParts.removeAll(
"");
159 if (dirParts.isEmpty())
162 auto createdDir = m_documentFile;
163 bool allDirsCreated =
true;
164 for (
const auto &dir : dirParts) {
166 bool subDirExists =
false;
167 for (
const DocumentFilePtr &subDir : m_documentFile->listFiles()) {
168 if (dir == subDir->initialName() && subDir->isDirectory()) {
175 createdDir = createdDir->createDirectory(dir);
177 allDirsCreated =
false;
182 if (!createParentDirectories)
186 return allDirsCreated;
191 Q_UNUSED(recurseParentDirectories)
193 return DocumentFile::parseFromAnyUri(dirName)->remove();
198 return m_documentFile->id().toUtf8();
204 case QFile::FileModificationTime:
205 return m_documentFile->lastModified();
217 if (!m_documentFile->exists())
221 if (!m_documentFile->canRead())
224 flags |= ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm;
226 if (m_documentFile->isDirectory()) {
227 flags |= DirectoryType;
230 if (m_documentFile->canWrite())
231 flags |= WriteOwnerPerm|WriteUserPerm|WriteGroupPerm|WriteOtherPerm;
240 case AbsolutePathName:
241 case CanonicalPathName:
245 return m_documentFile->uri().toString();
247 const QString queriedName = m_documentFile->name();
248 return queriedName.isEmpty() ? m_documentFile->initialName() : queriedName;
259 const QStringList &filterNames)
261 return std::make_unique<AndroidContentFileEngineIterator>(path, filters, filterNames);
270 if (fileName.startsWith(contentScheme))
271 return std::make_unique<AndroidContentFileEngine>(fileName);
278 const QString &path, QDirListing::IteratorFlags filters,
const QStringList &filterNames)
289 if (m_index == -1 && m_files.isEmpty()) {
290 const auto currentPath = path();
291 if (currentPath.isEmpty())
294 const auto iterDoc = DocumentFile::parseFromAnyUri(currentPath);
295 if (iterDoc->isDirectory())
296 for (
const auto &doc : iterDoc->listFiles())
298 if (m_files.isEmpty())
304 if (m_index < m_files.size() - 1) {
314 if (m_index < 0 || m_index > m_files.size())
316 return m_files.at(m_index)->name();
321 if (m_index < 0 || m_index > m_files.size())
323 return m_files.at(m_index)->uri().toString();
331 explicit Cursor(
const QJniObject &object)
336 if (m_object.isValid())
337 m_object.callMethod<
void>(
"close");
350 int type = m_object.callMethod<jint>(
"getType", columnIndex);
354 case FIELD_TYPE_INTEGER:
355 return QVariant::fromValue(m_object.callMethod<jlong>(
"getLong", columnIndex));
356 case FIELD_TYPE_FLOAT:
357 return QVariant::fromValue(m_object.callMethod<jdouble>(
"getDouble", columnIndex));
358 case FIELD_TYPE_STRING:
359 return QVariant::fromValue(m_object.callMethod<jstring>(
"getString",
360 columnIndex).toString());
362 auto blob = m_object.callMethod<jbyteArray>(
"getBlob", columnIndex);
364 const auto blobArray = blob.object<jbyteArray>();
365 const int size = env->GetArrayLength(blobArray);
366 const auto byteArray = env->GetByteArrayElements(blobArray,
nullptr);
367 QByteArray data{
reinterpret_cast<
const char *>(byteArray), size};
368 env->ReleaseByteArrayElements(blobArray, byteArray, 0);
369 return QVariant::fromValue(data);
376 const QStringList &projection = {},
377 const QString &selection = {},
378 const QStringList &selectionArgs = {},
379 const QString &sortOrder = {})
381 using namespace QtJniTypes;
382 auto cursor = QtContentFileEngine::callStaticMethod<CursorType>(
"query",
383 contentResolverInstance().object<ContentResolver>(),
385 QJniArray(projection),
386 selection.isEmpty() ?
nullptr : selection,
387 QJniArray(selectionArgs),
388 sortOrder.isEmpty() ?
nullptr : sortOrder);
389 if (!cursor.isValid())
391 return std::make_unique<Cursor>(cursor);
396 const auto query = queryUri(uri, {column});
400 if (query->rowCount() != 1 || query->columnCount() != 1)
402 query->moveToFirst();
403 return query->data(0);
408 return m_object.callMethod<jboolean>(
"isNull", columnIndex);
411 int columnCount()
const {
return m_object.callMethod<jint>(
"getColumnCount"); }
412 int rowCount()
const {
return m_object.callMethod<jint>(
"getCount"); }
413 int row()
const {
return m_object.callMethod<jint>(
"getPosition"); }
414 bool isFirst()
const {
return m_object.callMethod<jboolean>(
"isFirst"); }
415 bool isLast()
const {
return m_object.callMethod<jboolean>(
"isLast"); }
416 bool moveToFirst() {
return m_object.callMethod<jboolean>(
"moveToFirst"); }
417 bool moveToLast() {
return m_object.callMethod<jboolean>(
"moveToLast"); }
418 bool moveToNext() {
return m_object.callMethod<jboolean>(
"moveToNext"); }
431
432
433
434
435
436
437
438
462 return QJniObject::callStaticMethod<jstring, QtJniTypes::Uri>(
463 QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
465 uri.object()).toString();
470 return QJniObject::callStaticMethod<jstring, QtJniTypes::Uri>(
471 QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
473 uri.object()).toString();
478 return QJniObject::callStaticMethod<QtJniTypes::Uri>(
479 QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
480 "buildChildDocumentsUriUsingTree",
481 uri.object<QtJniTypes::Uri>(),
482 QJniObject::fromString(parentDocumentId).object<jstring>());
488 return QJniObject::callStaticMethod<QtJniTypes::Uri>(
489 QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
490 "buildDocumentUriUsingTree",
491 treeUri.object<QtJniTypes::Uri>(),
492 QJniObject::fromString(documentId).object<jstring>());
497 return QJniObject::callStaticMethod<jboolean>(
498 QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
500 QNativeInterface::QAndroidApplication::context(),
501 uri.object<QtJniTypes::Uri>());
506 return QJniObject::callStaticMethod<jboolean>(
507 QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
509 uri.object<QtJniTypes::Uri>());
513 const QString &displayName)
515 return QJniObject::callStaticMethod<QtJniTypes::Uri>(
516 QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
518 contentResolverInstance().object<QtJniTypes::ContentResolver>(),
519 parentDocumentUri.object<QtJniTypes::Uri>(),
520 QJniObject::fromString(mimeType).object<jstring>(),
521 QJniObject::fromString(displayName).object<jstring>());
526 const int flags = Cursor::queryColumn(documentUri, Document::COLUMN_FLAGS).toInt();
530 return QJniObject::callStaticMethod<jboolean>(
531 QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
533 contentResolverInstance().object<QtJniTypes::ContentResolver>(),
534 documentUri.object<QtJniTypes::Uri>());
538 const QJniObject &sourceParentDocumentUri,
539 const QJniObject &targetParentDocumentUri)
541 const int flags = Cursor::queryColumn(sourceDocumentUri, Document::COLUMN_FLAGS).toInt();
545 return QJniObject::callStaticMethod<QtJniTypes::Uri>(
546 QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
548 contentResolverInstance().object<QtJniTypes::ContentResolver>(),
549 sourceDocumentUri.object<QtJniTypes::Uri>(),
550 sourceParentDocumentUri.object<QtJniTypes::Uri>(),
551 targetParentDocumentUri.object<QtJniTypes::Uri>());
556 const int flags = Cursor::queryColumn(documentUri, Document::COLUMN_FLAGS).toInt();
560 return QJniObject::callStaticMethod<QtJniTypes::Uri>(
561 QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
563 contentResolverInstance().object<QtJniTypes::ContentResolver>(),
564 documentUri.object<QtJniTypes::Uri>(),
565 QJniObject::fromString(displayName).object<jstring>());
577 MakeableDocumentFile(
const QJniObject &uri,
const DocumentFilePtr &parent = {})
580 QString uriString = uri.toString();
585 uriString.chop(std::size(childrenSegment) - 1);
588 const QString path = QUrl(uriString).path();
589 if (path.isEmpty() || path == u"/")
592 int displayNameStartIndex = uriString.lastIndexOf(u'/') + 1;
594 const int encodedSlashPos = uriString.lastIndexOf(u"%2F");
595 if (encodedSlashPos != -1)
596 displayNameStartIndex = qMax(displayNameStartIndex, encodedSlashPos + 3);
598 const int encodedColonPos = uriString.lastIndexOf(u"%3A");
599 if (encodedColonPos != -1)
600 displayNameStartIndex = qMax(displayNameStartIndex, encodedColonPos + 3);
602 m_displayName = uriString.mid(displayNameStartIndex);
605 MakeableDocumentFile(
const QJniObject &uri,
const QString &displayName,
const DocumentFilePtr &parent = {})
612 const QString &displayName,
613 const DocumentFilePtr &parent)
624 const auto jSegments = uri.callMethod<QtJniTypes::List>(
"getPathSegments");
625 if (!jSegments.isValid())
628 QStringList segments;
629 for (
int i = 0; i < jSegments.callMethod<jint>(
"size"); ++i)
630 segments.append(jSegments.callMethod<QJniObject>(
"get", i).toString());
637 return QJniObject::callStaticMethod<QtJniTypes::Uri>(
638 QtJniTypes::Traits<QtJniTypes::Uri>::className(),
640 QJniObject::fromString(uri).object<jstring>());
645 const QJniObject uri = parseUri(fileName);
646 if (!uri.isValid() || uri.toString().isEmpty())
649 const auto scheme = uri.callMethod<QString>(
"getScheme");
650 if (scheme != QLatin1String(contentScheme))
651 return std::make_shared<MakeableDocumentFile>(uri);
653 const auto authority = uri.callMethod<QString>(
"getAuthority");
654 const QStringList segments = getPathSegments(uri);
656 const int treeIndex = segments.indexOf(
treeSegment);
659 DocumentFilePtr parent;
660 QJniObject parsedUri;
662 if (treeIndex != -1) {
664 if (segments.size() <= treeIndex + 1)
665 return fromSingleUri(uri);
667 const QString treeId = segments.at(treeIndex + 1);
668 const QString encodedTreeId = QUrl::toPercentEncoding(treeId);
669 const QString treeUriString =
"%1://%2/%3/%4"_L1.arg(scheme, authority,
670 treeSegment, encodedTreeId);
671 const QJniObject treeUri = parseUri(treeUriString);
673 const int midIndex = (docIndex > treeIndex) ? docIndex + 1 : treeIndex + 2;
674 QString docIdOrPath = segments.mid(midIndex).join(
'/');
676 if (docIdOrPath.isEmpty())
677 return fromTreeUri(treeUri);
680 if (docIndex > treeIndex)
681 fullDocId = docIdOrPath;
683 fullDocId = treeId + u'/' + docIdOrPath;
685 parsedUri = buildDocumentUriUsingTree(treeUri, fullDocId);
687 const int lastSlash = fullDocId.lastIndexOf(
'/');
688 if (lastSlash != -1) {
689 const QString parentDocId = fullDocId.left(lastSlash);
691 if (!parentDocId.isEmpty() && parentDocId.startsWith(treeId)) {
692 QJniObject parentUri = buildDocumentUriUsingTree(treeUri, parentDocId);
693 parent = std::make_shared<MakeableDocumentFile>(parentUri);
698 parent = fromTreeUri(treeUri);
699 }
else if (docIndex != -1) {
700 const QString docId = segments.mid(docIndex + 1).join(
'/');
701 const QString encodedDocId = QUrl::toPercentEncoding(docId);
702 const QString docUriStr =
"%1://%2/%3/%4"_L1.arg(scheme, authority,
703 documentSegment, encodedDocId);
704 parsedUri = parseUri(docUriStr);
706 const int lastSlash = docId.lastIndexOf(
'/');
707 if (lastSlash != -1) {
708 const QString parentDocId = docId.left(lastSlash);
709 const QString encodedParentDocId = QUrl::toPercentEncoding(parentDocId);
710 const QString parentUriStr =
"%1://%2/%3/%4"_L1.arg(scheme, authority, documentSegment,
712 parent = fromSingleUri(parseUri(parentUriStr));
716 if (segments.size() > 1) {
717 QStringList parentSegments = segments;
718 parentSegments.removeLast();
719 const QString parendDocId = parentSegments.join(
'/');
720 const QString parentUriStr =
"%1://%2/%3"_L1.arg(scheme, authority, parendDocId);
721 parent = fromSingleUri(parseUri(parentUriStr));
725 if (!parsedUri.isValid())
726 return fromSingleUri(uri);
728 auto docFile = std::make_shared<MakeableDocumentFile>(parsedUri);
730 docFile->m_parent = parent;
740 return std::make_shared<MakeableDocumentFile>(uri);
745 if (!treeUri.isValid())
748 if (isDocumentUri(treeUri))
749 return std::make_shared<MakeableDocumentFile>(treeUri);
751 if (isTreeUri(treeUri)) {
752 const QString docId = treeDocumentId(treeUri);
753 if (!docId.isEmpty()) {
754 const QJniObject docUri = buildDocumentUriUsingTree(treeUri, docId);
755 return std::make_shared<MakeableDocumentFile>(docUri);
759 return std::make_shared<MakeableDocumentFile>(treeUri);
765 const QString decodedName = QUrl::fromPercentEncoding(displayName.toUtf8());
766 return std::make_shared<MakeableDocumentFile>(
767 createDocument(m_uri, mimeType, decodedName),
776 return std::make_shared<MakeableDocumentFile>(
777 createDocument(m_uri, Document::MIME_TYPE_DIR, displayName),
795 return m_displayName;
800 return Cursor::queryColumn(m_uri, Document::COLUMN_DISPLAY_NAME).toString();
805 return DocumentsContract::documentId(uri());
810 return Cursor::queryColumn(m_uri, Document::COLUMN_MIME_TYPE).toString();
815 return mimeType() == Document::MIME_TYPE_DIR;
820 const QString type = mimeType();
821 return type != Document::MIME_TYPE_DIR && !type.isEmpty();
826 return isDocumentUri(m_uri) && (Cursor::queryColumn(m_uri,
827 Document::COLUMN_FLAGS).toInt() & Document::FLAG_VIRTUAL_DOCUMENT);
832 const auto timeVariant = Cursor::queryColumn(m_uri, Document::COLUMN_LAST_MODIFIED);
833 if (timeVariant.isValid())
834 return QDateTime::fromMSecsSinceEpoch(timeVariant.toLongLong());
840 return Cursor::queryColumn(m_uri, Document::COLUMN_SIZE).toLongLong();
844constexpr int FLAG_GRANT_READ_URI_PERMISSION = 0x00000001;
845constexpr int FLAG_GRANT_WRITE_URI_PERMISSION = 0x00000002;
850 const auto context = QJniObject(QNativeInterface::QAndroidApplication::context());
851 const bool selfUriPermission = context.callMethod<jint>(
"checkCallingOrSelfUriPermission",
852 m_uri.object<QtJniTypes::Uri>(),
853 FLAG_GRANT_READ_URI_PERMISSION);
854 if (selfUriPermission != 0)
857 return !mimeType().isEmpty();
862 const auto context = QJniObject(QNativeInterface::QAndroidApplication::context());
863 const bool selfUriPermission = context.callMethod<jint>(
"checkCallingOrSelfUriPermission",
864 m_uri.object<QtJniTypes::Uri>(),
865 FLAG_GRANT_WRITE_URI_PERMISSION);
866 if (selfUriPermission != 0)
869 const QString type = mimeType();
873 const int flags = Cursor::queryColumn(m_uri, Document::COLUMN_FLAGS).toInt();
878 const bool isDir = (type == Document::MIME_TYPE_DIR);
881 return dirSupportsCreate || supportsWrite;
886 return deleteDocument(m_uri);
891 return !name().isEmpty();
896 std::vector<DocumentFilePtr> res;
897 const auto childrenUri = buildChildDocumentsUriUsingTree(m_uri, documentId(m_uri));
898 const auto query = Cursor::queryUri(childrenUri, {Document::COLUMN_DOCUMENT_ID});
902 while (query->moveToNext()) {
903 const auto uri = buildDocumentUriUsingTree(m_uri, query->data(0).toString());
904 res.push_back(std::make_shared<MakeableDocumentFile>(uri, shared_from_this()));
913 QJniObject renamedUri = renameDocument(m_uri, newName);
914 if (!renamedUri.isValid())
918 m_displayName = newName;
924 auto destDoc = parseFromAnyUri(newName);
928 DocumentFilePtr destParent = destDoc->parent();
929 const QString oldName = name();
930 const QString destName = QUrl::fromPercentEncoding(QFileInfo(newName).fileName().toUtf8());
933 if (parent() && destParent && parent()->uri().toString() != destParent->uri().toString())
936 QJniObject currentUri = m_uri;
941 currentUri = moveDocument(m_uri, parent()->uri(), destParent->uri());
942 if (!currentUri.isValid())
946 if (oldName != destName) {
947 QJniObject renamedUri = renameDocument(currentUri, destName);
948 if (!renamedUri.isValid())
951 currentUri = renamedUri;
955 m_displayName = destName;
957 m_parent = destParent;
static QJniObject & contentResolverInstance()
constexpr char documentSegment[]
constexpr char contentSchemeFull[]
constexpr char contentScheme[]
constexpr char treeSegment[]
constexpr char childrenSegment[]
QJniObject parseUri(const QString &uri)
std::unique_ptr< QAbstractFileEngine > create(const QString &fileName) const override
If this file handler can handle fileName, this method creates a file engine and returns it wrapped in...
~AndroidContentFileEngineHandler()
bool advance() override
This pure virtual function advances the iterator to the next directory entry; if the operation was su...
~AndroidContentFileEngineIterator()
QString currentFilePath() const override
Returns the path to the current directory entry.
AndroidContentFileEngineIterator(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames)
QString currentFileName() const override
This pure virtual function returns the name of the current directory entry, excluding the path.
QByteArray id() const override
qint64 size() const override
Returns the size of the file.
bool mkdir(const QString &dirName, bool createParentDirectories, std::optional< QFile::Permissions > permissions=std::nullopt) const override
Requests that the directory dirName be created with the specified permissions.
FileFlags fileFlags(FileFlags type=FileInfoAll) const override
This function should return the set of OR'd flags that are true for the file engine's file,...
QDateTime fileTime(QFile::FileTime time) const override
If time is BirthTime, return when the file was born (created).
bool rmdir(const QString &dirName, bool recurseParentDirectories) const override
Requests that the directory dirName is deleted from the file system.
IteratorUniquePtr beginEntryList(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) override
Returns a QAbstractFileEngine::IteratorUniquePtr, that can be used to iterate over the entries in pat...
bool close() override
Closes the file, returning true if successful; otherwise returns false.
AndroidContentFileEngine(const QString &fileName)
bool rename(const QString &newName) override
Requests that the file be renamed to newName in the file system.
bool remove() override
Requests that the file is deleted from the file system.
QString fileName(FileName file=DefaultName) const override
Return the file engine's current file name in the format specified by file.
Cursor(const QJniObject &object)
QVariant data(int columnIndex) const
static QVariant queryColumn(const QJniObject &uri, const QString &column)
bool isNull(int columnIndex) const
static std::unique_ptr< Cursor > queryUri(const QJniObject &uri, const QStringList &projection={}, const QString &selection={}, const QStringList &selectionArgs={}, const QString &sortOrder={})
const DocumentFilePtr & parent() const
bool rename(const QString &newName)
const QJniObject & uri() const
DocumentFilePtr createFile(const QString &mimeType, const QString &displayName)
DocumentFilePtr createDirectory(const QString &displayName)
std::vector< DocumentFilePtr > listFiles()
QString initialName() const
DocumentFile(const QJniObject &uri, const QString &displayName, const std::shared_ptr< DocumentFile > &parent)
QDateTime lastModified() const
const QLatin1String COLUMN_LAST_MODIFIED("last_modified")
constexpr int FLAG_SUPPORTS_MOVE
const QLatin1String MIME_TYPE_DIR("vnd.android.document/directory")
const QLatin1String COLUMN_MIME_TYPE("mime_type")
const QLatin1String COLUMN_DISPLAY_NAME("_display_name")
const QLatin1String COLUMN_DOCUMENT_ID("document_id")
constexpr int FLAG_VIRTUAL_DOCUMENT
constexpr int FLAG_SUPPORTS_DELETE
const QLatin1String COLUMN_FLAGS("flags")
const QLatin1String COLUMN_SIZE("_size")
constexpr int FLAG_SUPPORTS_RENAME
constexpr int FLAG_DIR_SUPPORTS_CREATE
constexpr int FLAG_SUPPORTS_WRITE
bool isDocumentUri(const QJniObject &uri)
bool isTreeUri(const QJniObject &uri)
bool deleteDocument(const QJniObject &documentUri)
QJniObject renameDocument(const QJniObject &documentUri, const QString &displayName)
QJniObject buildDocumentUriUsingTree(const QJniObject &treeUri, const QString &documentId)
QString treeDocumentId(const QJniObject &uri)
QString documentId(const QJniObject &uri)
QJniObject moveDocument(const QJniObject &sourceDocumentUri, const QJniObject &sourceParentDocumentUri, const QJniObject &targetParentDocumentUri)
QJniObject buildChildDocumentsUriUsingTree(const QJniObject &uri, const QString &parentDocumentId)
QJniObject createDocument(const QJniObject &parentDocumentUri, const QString &mimeType, const QString &displayName)
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent")