summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAssam Boudjelthia <assam.boudjelthia@qt.io>2022-12-17 02:59:54 +0200
committerAssam Boudjelthia <assam.boudjelthia@qt.io>2023-01-17 20:24:12 +0200
commitf48abc46321502df2425aebc0999be2f5f3bf1f2 (patch)
tree377d7aefcb868b5e54e5ed4c0707fb8e38d693f6
parentd50d4e8b9febb670e5a48fdf5b60dff8456d8692 (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.cpp25
-rw-r--r--tests/manual/android_content_uri/tst_content_uris.cpp65
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)