diff options
| author | Bartlomiej Moskal <bartlomiej.moskal@qt.io> | 2022-11-21 17:28:52 +0100 |
|---|---|---|
| committer | Bartlomiej Moskal <bartlomiej.moskal@qt.io> | 2022-12-13 12:04:40 +0000 |
| commit | 4ceee3911a2ef567f614fc296475bc2b2a0e3add (patch) | |
| tree | 0066f318ed0a3bb0a8c3a26e639c4c24d2e168c4 | |
| parent | fbfaf5d38b3455bb561e739271986be91a7c7169 (diff) | |
Android: fix Android assets handler not listing dirs with only sub dirs
It looks like AAssetDir_getNextFileName is not enough.
Directories that contain only other directories (no files)
were not listed.
On the other hand, AAssetManager_openDir() will always return a
pointer to initialized object (even if the specified directory does not
exists), so we can't just leave only it here.
Using FolderIterator as a last resort. This approach should not be too
time consuming.
As part of this fix, add some unit tests to cover/ensure assets
listing/iterating works as expected.
Fixes: QTBUG-107627
Pick-to: 6.4 6.2 5.15
Change-Id: Id375fe8f99f4ca3f8cad4756f783ffafe5c074df
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
5 files changed, 35 insertions, 1 deletions
diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp index 67b2506e684..c7785486b02 100644 --- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp +++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp @@ -108,6 +108,8 @@ public: FolderIterator(const QString &path) : m_path(path) { + // Note that empty dirs in the assets dir before the build are not going to be + // included in the final apk, so no empty folders should expected to be listed. QJniObject files = QJniObject::callStaticObjectMethod(QtAndroid::applicationClass(), "listAssetContent", "(Landroid/content/res/AssetManager;Ljava/lang/String;)[Ljava/lang/String;", @@ -350,8 +352,13 @@ public: } else { auto *assetDir = AAssetManager_openDir(m_assetManager, m_fileName.toUtf8()); if (assetDir) { - if (AAssetDir_getNextFileName(assetDir)) + if (AAssetDir_getNextFileName(assetDir) + || (!FolderIterator::fromCache(m_fileName, false)->empty())) { + // If AAssetDir_getNextFileName is not valid, it still can be a directory that + // contains only other directories (no files). FolderIterator will not be called + // on the directory containing files so it should not be too time consuming now. m_assetInfo->type = AssetItem::Type::Folder; + } AAssetDir_close(assetDir); } } diff --git a/tests/auto/corelib/platform/android/testdata/assets/top_level_dir/file_in_top_dir.txt b/tests/auto/corelib/platform/android/testdata/assets/top_level_dir/file_in_top_dir.txt new file mode 100644 index 00000000000..61e2c47c258 --- /dev/null +++ b/tests/auto/corelib/platform/android/testdata/assets/top_level_dir/file_in_top_dir.txt @@ -0,0 +1 @@ +FooBar
\ No newline at end of file diff --git a/tests/auto/corelib/platform/android/testdata/assets/top_level_dir/sub_dir/file_in_sub_dir.txt b/tests/auto/corelib/platform/android/testdata/assets/top_level_dir/sub_dir/file_in_sub_dir.txt new file mode 100644 index 00000000000..61e2c47c258 --- /dev/null +++ b/tests/auto/corelib/platform/android/testdata/assets/top_level_dir/sub_dir/file_in_sub_dir.txt @@ -0,0 +1 @@ +FooBar
\ No newline at end of file diff --git a/tests/auto/corelib/platform/android/testdata/assets/top_level_dir/sub_dir/sub_dir_2/sub_dir_3/file_in_sub_dir_3.txt b/tests/auto/corelib/platform/android/testdata/assets/top_level_dir/sub_dir/sub_dir_2/sub_dir_3/file_in_sub_dir_3.txt new file mode 100644 index 00000000000..61e2c47c258 --- /dev/null +++ b/tests/auto/corelib/platform/android/testdata/assets/top_level_dir/sub_dir/sub_dir_2/sub_dir_3/file_in_sub_dir_3.txt @@ -0,0 +1 @@ +FooBar
\ No newline at end of file diff --git a/tests/auto/corelib/platform/android/tst_android.cpp b/tests/auto/corelib/platform/android/tst_android.cpp index 49ba175c066..bb1fdcae1c1 100644 --- a/tests/auto/corelib/platform/android/tst_android.cpp +++ b/tests/auto/corelib/platform/android/tst_android.cpp @@ -7,9 +7,11 @@ #include <QGuiApplication> #include <QtCore/qnativeinterface.h> #include <QtCore/qjniobject.h> +#include <QtCore/qdiriterator.h> #include <QScreen> #include <qpa/qplatformscreen.h> #include <qpa/qplatformnativeinterface.h> +#include <QtCore/qdiriterator.h> class tst_Android : public QObject { @@ -17,6 +19,7 @@ Q_OBJECT private slots: void assetsRead(); void assetsNotWritable(); + void assetsIterating(); void testAndroidSdkVersion(); void testAndroidActivity(); void testRunOnAndroidMainThread(); @@ -46,6 +49,27 @@ void tst_Android::assetsNotWritable() QVERIFY(!file.open(QIODevice::Append)); } +void tst_Android::assetsIterating() +{ + QStringList assets = {"assets:/top_level_dir/file_in_top_dir.txt", + "assets:/top_level_dir/sub_dir", + "assets:/top_level_dir/sub_dir/file_in_sub_dir.txt", + "assets:/top_level_dir/sub_dir/sub_dir_2", + "assets:/top_level_dir/sub_dir/sub_dir_2/sub_dir_3", + "assets:/top_level_dir/sub_dir/sub_dir_2/sub_dir_3/file_in_sub_dir_3.txt"}; + + // Note that we have an "assets:/top_level_dir/sub_dir/empty_sub_dir" in the test's + // assets physical directory, but empty folders are not packaged in the built apk, + // so it's expected to not have such folder be listed in the assets on runtime + + QDirIterator it("assets:/top_level_dir", QDirIterator::Subdirectories); + QStringList iteratorAssets; + while (it.hasNext()) + iteratorAssets.append(it.next()); + + QVERIFY(assets == iteratorAssets); +} + void tst_Android::testAndroidSdkVersion() { QVERIFY(QNativeInterface::QAndroidApplication::sdkVersion() > 0); |
