diff options
author | Assam Boudjelthia <assam.boudjelthia@qt.io> | 2022-12-17 02:59:54 +0200 |
---|---|---|
committer | Assam Boudjelthia <assam.boudjelthia@qt.io> | 2023-01-17 20:24:12 +0200 |
commit | f48abc46321502df2425aebc0999be2f5f3bf1f2 (patch) | |
tree | 377d7aefcb868b5e54e5ed4c0707fb8e38d693f6 | |
parent | d50d4e8b9febb670e5a48fdf5b60dff8456d8692 (diff) |
Android: handle move operation with content uris
Allow moving content uris if the destination is provided
a full content uri with a parent that's different from the
source content uri (i.e. different folders).
Note: since the underlaying Android APIs don't always know about
the parent of a uri, we do some step to deduce that, but that's
not always guaranteed to work.
Task-number: QTBUG-98974
Change-Id: If21954e5963f4eb0b96c7ccd983943ea2cab5b24
Reviewed-by: Ville Voutilainen <ville.voutilainen@qt.io>
(cherry picked from commit c203ec2720b694fd877512da531a227e0f3310cb)
-rw-r--r-- | src/plugins/platforms/android/androidcontentfileengine.cpp | 25 | ||||
-rw-r--r-- | tests/manual/android_content_uri/tst_content_uris.cpp | 65 |
2 files changed, 71 insertions, 19 deletions
diff --git a/src/plugins/platforms/android/androidcontentfileengine.cpp b/src/plugins/platforms/android/androidcontentfileengine.cpp index ffda304308..1e6cd9baba 100644 --- a/src/plugins/platforms/android/androidcontentfileengine.cpp +++ b/src/plugins/platforms/android/androidcontentfileengine.cpp @@ -500,6 +500,7 @@ const QLatin1String COLUMN_SIZE("_size"); constexpr int FLAG_DIR_SUPPORTS_CREATE = 0x00000008; constexpr int FLAG_SUPPORTS_DELETE = 0x00000004; +constexpr int FLAG_SUPPORTS_MOVE = 0x00000100; constexpr int FLAG_SUPPORTS_RENAME = 0x00000040; constexpr int FLAG_SUPPORTS_WRITE = 0x00000002; constexpr int FLAG_VIRTUAL_DOCUMENT = 0x00000200; @@ -592,6 +593,24 @@ bool deleteDocument(const QJNIObjectPrivate &documentUri) documentUri.object()); } +QJNIObjectPrivate moveDocument(const QJNIObjectPrivate &sourceDocumentUri, + const QJNIObjectPrivate &sourceParentDocumentUri, + const QJNIObjectPrivate &targetParentDocumentUri) +{ + const int flags = Cursor::queryColumn(sourceDocumentUri, Document::COLUMN_FLAGS).toInt(); + if (!(flags & Document::FLAG_SUPPORTS_MOVE)) + return {}; + + JniExceptionCleaner cleaner; + return QJNIObjectPrivate::callStaticObjectMethod("android/provider/DocumentsContract", + "moveDocument", + "(Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/net/Uri;Landroid/net/Uri;)Landroid/net/Uri;", + contentResolverInstance().object(), + sourceDocumentUri.object(), + sourceParentDocumentUri.object(), + targetParentDocumentUri.object()); +} + QJNIObjectPrivate renameDocument(const QJNIObjectPrivate &documentUri, const QString &displayName) { const int flags = Cursor::queryColumn(documentUri, Document::COLUMN_FLAGS).toInt(); @@ -848,6 +867,12 @@ bool DocumentFile::rename(const QString &newName) displayName.remove(0, 3); uri = renameDocument(m_uri, displayName); + } else { + // Move + QJNIObjectPrivate srcParentUri = fromTreeUri(parseUri(parent))->uri(); + const QString destParent = newName.left(lastSeparatorIndex(newName)); + QJNIObjectPrivate targetParentUri = fromTreeUri(parseUri(destParent))->uri(); + uri = moveDocument(m_uri, srcParentUri, targetParentUri); } } else { uri = renameDocument(m_uri, newName); diff --git a/tests/manual/android_content_uri/tst_content_uris.cpp b/tests/manual/android_content_uri/tst_content_uris.cpp index e0fb10eb98..a837049aef 100644 --- a/tests/manual/android_content_uri/tst_content_uris.cpp +++ b/tests/manual/android_content_uri/tst_content_uris.cpp @@ -194,31 +194,58 @@ void tst_ContentUris::fileOperations() QVERIFY(file.exists()); // Rename - const QString renamedFileName = "renamed_new_file.txt"; - QVERIFY(file.rename(renamedFileName)); - const auto renamedUrl = url.replace(fileName, renamedFileName); - QVERIFY(file.fileName() == renamedUrl); - - // NOTE: The uri doesn't seem to stay usable after a rename and it needs to get - // permission again via the SAF picker. - showInstructionsDialog("Choose the file that was renamed"); - QFileDialog::getOpenFileName(nullptr, tr("Open File")); - QVERIFY(file.exists()); + { + const QString renamedFileName = "renamed_new_file.txt"; + QVERIFY(file.rename(renamedFileName)); + const auto renamedUrl = url.replace(fileName, renamedFileName); + QVERIFY(file.fileName() == renamedUrl); + + // NOTE: The uri doesn't seem to stay usable after a rename and it needs to get + // permission again via the SAF picker. + showInstructionsDialog("Choose the file that was renamed"); + QFileDialog::getOpenFileName(nullptr, tr("Open File")); + QVERIFY(file.exists()); - // rename now with full content uri - const auto secondRenamedUrl = url.replace(renamedFileName, "second_nenamed_file.txt"); - QVERIFY(file.rename(secondRenamedUrl)); - QVERIFY(file.fileName() == secondRenamedUrl); + // rename now with full content uri + const auto secondRenamedUrl = url.replace(renamedFileName, "second_nenamed_file.txt"); + QVERIFY(file.rename(secondRenamedUrl)); + QVERIFY(file.fileName() == secondRenamedUrl); - // NOTE: The uri doesn't seem to stay usable after a rename and it needs to get - // permission again via the SAF picker. - showInstructionsDialog("Choose the file that was renamed"); - QFileDialog::getOpenFileName(nullptr, tr("Open File")); - QVERIFY(file.exists()); + // NOTE: The uri doesn't seem to stay usable after a rename and it needs to get + // permission again via the SAF picker. + showInstructionsDialog("Choose the file that was renamed"); + QFileDialog::getOpenFileName(nullptr, tr("Open File")); + QVERIFY(file.exists()); + } // Remove QVERIFY(file.remove()); QVERIFY(!file.exists()); + + // Move + { + showInstructionsDialog("Choose source directory of file to move"); + const QString srcDir = QFileDialog::getExistingDirectory(nullptr, tr("Choose Directory")); + + const QString fileName = QLatin1String("file_to_move.txt"); + + // Create a file + QFile file(srcDir + QLatin1Char('/') + fileName); + QVERIFY(file.open(QFile::WriteOnly)); + QVERIFY(file.exists()); + + showInstructionsDialog("Choose target directory to where to move the file"); + const QString destDir = QFileDialog::getExistingDirectory(nullptr, tr("Choose Directory")); + + QVERIFY(file.rename(destDir + QLatin1Char('/') + fileName)); + + // NOTE: The uri doesn't seem to stay usable after a rename and it needs to get + // permission again via the SAF picker. + showInstructionsDialog("Choose the file that was moved"); + QFileDialog::getOpenFileName(nullptr, tr("Open File")); + + QVERIFY(file.remove()); + } } QTEST_MAIN(tst_ContentUris) |