summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmake/FindBundletool.cmake48
-rw-r--r--cmake/QtAndroidHelpers.cmake30
-rw-r--r--cmake/QtBaseHelpers.cmake3
-rw-r--r--cmake/QtInternalTargets.cmake7
-rw-r--r--cmake/QtPlatformAndroid.cmake30
-rw-r--r--cmake/QtPostProcessHelpers.cmake2
-rw-r--r--cmake/QtTestHelpers.cmake7
-rw-r--r--coin/instructions/prepare_building_env.yaml20
-rw-r--r--configure.cmake3
-rw-r--r--doc/global/includes/cli-build-cmake.qdocinc2
-rw-r--r--licenseRule.json2
-rw-r--r--src/3rdparty/gradle/gradle.properties3
-rw-r--r--src/android/CMakeLists.txt1
-rw-r--r--src/android/REUSE.toml2
-rw-r--r--src/android/templates/build.gradle2
-rw-r--r--src/android/templates_cmake/CMakeLists.txt46
-rw-r--r--src/android/templates_cmake/app/AndroidManifest.xml.in54
-rw-r--r--src/android/templates_cmake/app/build.gradle.in53
-rw-r--r--src/android/templates_cmake/app/gradle.properties.in1
-rw-r--r--src/android/templates_cmake/dynamic_feature/AndroidManifest.xml.in15
-rw-r--r--src/android/templates_cmake/dynamic_feature/build.gradle.in53
-rw-r--r--src/android/templates_cmake/gradle.properties.in12
-rw-r--r--src/android/templates_cmake/settings.gradle.in18
-rw-r--r--src/assets/CMakeLists.txt1
-rw-r--r--src/assets/icons/128x128/document-new.pngbin1258 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/document-open.pngbin1855 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/document-print.pngbin1576 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/document-save.pngbin1298 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/edit-copy.pngbin1480 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/edit-cut.pngbin2012 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/edit-delete.pngbin2665 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/edit-paste.pngbin1892 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/edit-redo.pngbin1239 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/edit-undo.pngbin1233 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/format-justify-center.pngbin663 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/format-justify-fill.pngbin506 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/format-justify-left.pngbin603 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/format-justify-right.pngbin634 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/format-text-bold.pngbin1459 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/format-text-italic.pngbin1158 -> 0 bytes
-rw-r--r--src/assets/icons/128x128/format-text-underline.pngbin1263 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin2541 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin3865 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin3721 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin2682 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin3467 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin5004 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin5870 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin4005 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin2528 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin2530 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin1599 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin1475 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin1539 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin1557 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin3092 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin2374 -> 0 bytes
-rw-r--r--src/assets/icons/128x128@2/[email protected]bin2477 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/document-new.pngbin241 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/document-open.pngbin286 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/document-print.pngbin261 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/document-save.pngbin224 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/edit-copy.pngbin216 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/edit-cut.pngbin267 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/edit-delete.pngbin250 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/edit-paste.pngbin272 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/edit-redo.pngbin253 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/edit-undo.pngbin253 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/format-justify-center.pngbin134 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/format-justify-fill.pngbin122 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/format-justify-left.pngbin128 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/format-justify-right.pngbin134 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/format-text-bold.pngbin264 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/format-text-italic.pngbin255 -> 0 bytes
-rw-r--r--src/assets/icons/16x16/format-text-underline.pngbin186 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin318 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin455 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin393 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin311 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin333 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin416 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin495 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin464 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin346 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin347 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin179 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin156 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin171 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin173 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin430 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin391 -> 0 bytes
-rw-r--r--src/assets/icons/16x16@2/[email protected]bin290 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/document-new.pngbin2541 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/document-open.pngbin3865 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/document-print.pngbin3721 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/document-save.pngbin2682 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/edit-copy.pngbin3467 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/edit-cut.pngbin5004 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/edit-delete.pngbin5870 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/edit-paste.pngbin4005 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/edit-redo.pngbin2528 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/edit-undo.pngbin2530 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/format-justify-center.pngbin1599 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/format-justify-fill.pngbin1475 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/format-justify-left.pngbin1539 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/format-justify-right.pngbin1557 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/format-text-bold.pngbin3092 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/format-text-italic.pngbin2374 -> 0 bytes
-rw-r--r--src/assets/icons/256x256/format-text-underline.pngbin2477 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin5683 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin8174 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin8055 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin5666 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin7329 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin11388 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin12743 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin8485 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin5378 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin5433 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin3855 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin3681 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin3775 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin3756 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin7046 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin6224 -> 0 bytes
-rw-r--r--src/assets/icons/256x256@2/[email protected]bin5168 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/document-new.pngbin318 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/document-open.pngbin455 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/document-print.pngbin393 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/document-save.pngbin311 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/edit-copy.pngbin333 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/edit-cut.pngbin416 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/edit-delete.pngbin495 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/edit-paste.pngbin464 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/edit-redo.pngbin346 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/edit-undo.pngbin347 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/format-justify-center.pngbin179 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/format-justify-fill.pngbin156 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/format-justify-left.pngbin171 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/format-justify-right.pngbin173 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/format-text-bold.pngbin430 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/format-text-italic.pngbin391 -> 0 bytes
-rw-r--r--src/assets/icons/32x32/format-text-underline.pngbin290 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin588 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin923 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin762 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin565 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin710 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin843 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin954 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin909 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin628 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin608 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin317 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin266 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin298 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin305 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin777 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin657 -> 0 bytes
-rw-r--r--src/assets/icons/32x32@2/[email protected]bin577 -> 0 bytes
-rw-r--r--src/assets/icons/CMakeLists.txt174
-rw-r--r--src/assets/icons/README29
-rw-r--r--src/assets/icons/index.theme46
-rw-r--r--src/assets/icons/scalable/document-new.svg1
-rw-r--r--src/assets/icons/scalable/document-open.svg1
-rw-r--r--src/assets/icons/scalable/document-print.svg1
-rw-r--r--src/assets/icons/scalable/document-save.svg1
-rw-r--r--src/assets/icons/scalable/edit-copy.svg1
-rw-r--r--src/assets/icons/scalable/edit-cut.svg1
-rw-r--r--src/assets/icons/scalable/edit-delete.svg1
-rw-r--r--src/assets/icons/scalable/edit-paste.svg1
-rw-r--r--src/assets/icons/scalable/edit-redo.svg1
-rw-r--r--src/assets/icons/scalable/edit-undo.svg1
-rw-r--r--src/assets/icons/scalable/format-justify-center.svg1
-rw-r--r--src/assets/icons/scalable/format-justify-fill.svg1
-rw-r--r--src/assets/icons/scalable/format-justify-left.svg1
-rw-r--r--src/assets/icons/scalable/format-justify-right.svg1
-rw-r--r--src/assets/icons/scalable/format-text-bold.svg1
-rw-r--r--src/assets/icons/scalable/format-text-italic.svg1
-rw-r--r--src/assets/icons/scalable/format-text-underline.svg1
-rw-r--r--src/corelib/CMakeLists.txt6
-rw-r--r--src/corelib/Qt6AndroidDynamicFeatureHelpers.cmake152
-rw-r--r--src/corelib/Qt6AndroidGradleHelpers.cmake631
-rw-r--r--src/corelib/Qt6AndroidMacros.cmake216
-rw-r--r--src/corelib/Qt6AndroidPermissionHelpers.cmake126
-rw-r--r--src/corelib/Qt6CoreConfigExtras.cmake.in4
-rw-r--r--src/corelib/Qt6CoreMacros.cmake3
-rw-r--r--src/corelib/animation/qabstractanimation.cpp1
-rw-r--r--src/corelib/animation/qabstractanimation.h1
-rw-r--r--src/corelib/animation/qabstractanimation_p.h1
-rw-r--r--src/corelib/animation/qanimationgroup.cpp1
-rw-r--r--src/corelib/animation/qanimationgroup.h1
-rw-r--r--src/corelib/animation/qanimationgroup_p.h1
-rw-r--r--src/corelib/animation/qparallelanimationgroup.cpp1
-rw-r--r--src/corelib/animation/qparallelanimationgroup.h1
-rw-r--r--src/corelib/animation/qparallelanimationgroup_p.h1
-rw-r--r--src/corelib/animation/qpauseanimation.cpp1
-rw-r--r--src/corelib/animation/qpauseanimation.h1
-rw-r--r--src/corelib/animation/qpropertyanimation.cpp1
-rw-r--r--src/corelib/animation/qpropertyanimation.h1
-rw-r--r--src/corelib/animation/qpropertyanimation_p.h1
-rw-r--r--src/corelib/animation/qsequentialanimationgroup.cpp1
-rw-r--r--src/corelib/animation/qsequentialanimationgroup.h1
-rw-r--r--src/corelib/animation/qsequentialanimationgroup_p.h1
-rw-r--r--src/corelib/animation/qvariantanimation.cpp1
-rw-r--r--src/corelib/animation/qvariantanimation.h1
-rw-r--r--src/corelib/animation/qvariantanimation_p.h1
-rw-r--r--src/corelib/configure.cmake1
-rw-r--r--src/corelib/doc/snippets/qprocess/CMakeLists.txt2
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp11
-rw-r--r--src/corelib/io/qiodevice.cpp7
-rw-r--r--src/corelib/io/qtemporaryfile.cpp6
-rw-r--r--src/corelib/io/qurl.cpp32
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp24
-rw-r--r--src/corelib/kernel/qcoreapplication_p.h12
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder.cpp20
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder_p.h2
-rw-r--r--src/corelib/kernel/qmetatype.cpp112
-rw-r--r--src/corelib/kernel/qmetatype_p.h26
-rw-r--r--src/corelib/kernel/qtranslator.cpp41
-rw-r--r--src/corelib/platform/windows/qt_winrtbase_p.h1
-rw-r--r--src/corelib/thread/qatomicwait.cpp14
-rw-r--r--src/corelib/thread/qmutex.cpp19
-rw-r--r--src/corelib/tools/qatomicscopedvaluerollback.h28
-rw-r--r--src/corelib/tools/qfreelist_p.h22
-rw-r--r--src/corelib/tools/qhashfunctions.h32
-rw-r--r--src/gui/kernel/qguivariant.cpp15
-rw-r--r--src/gui/kernel/qscreen.cpp6
-rw-r--r--src/gui/kernel/qtestsupport_gui.cpp63
-rw-r--r--src/gui/kernel/qtestsupport_gui.h16
-rw-r--r--src/gui/painting/qtransform.cpp2
-rw-r--r--src/gui/rhi/qrhi.cpp2
-rw-r--r--src/gui/rhi/qshader.cpp2
-rw-r--r--src/gui/text/qfontdatabase_p.h2
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp6
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp1
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp1
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp5
-rw-r--r--src/plugins/styles/modernwindows/qwindows11style.cpp218
-rw-r--r--src/sql/models/qsqlquerymodel.cpp4
-rw-r--r--src/sql/models/qsqlquerymodel.h2
-rw-r--r--src/testlib/3rdparty/valgrind/qt_attribution.json2
-rw-r--r--src/testlib/3rdparty/valgrind/valgrind_p.h537
-rw-r--r--src/tools/androiddeployqt/main.cpp26
-rw-r--r--src/tools/androidtestrunner/main.cpp155
-rw-r--r--src/widgets/itemviews/qheaderview.cpp4
-rw-r--r--src/widgets/kernel/qtestsupport_widgets.cpp63
-rw-r--r--src/widgets/kernel/qtestsupport_widgets.h13
-rw-r--r--src/widgets/kernel/qwidgetsvariant.cpp14
-rw-r--r--src/widgets/styles/qfusionstyle.cpp2
-rw-r--r--src/widgets/styles/qfusionstyle_p_p.h5
-rw-r--r--src/widgets/widgets/qdockarealayout.cpp3
-rw-r--r--tests/auto/corelib/io/qfile/tst_qfile.cpp32
-rw-r--r--tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp29
-rw-r--r--tests/auto/corelib/io/qurl/tst_qurl.cpp4
-rw-r--r--tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp6
-rw-r--r--tests/auto/corelib/platform/CMakeLists.txt4
-rw-r--r--tests/auto/corelib/platform/android_legacy_packaging/testdata/build.gradle2
-rw-r--r--tests/auto/corelib/text/qlocale/tst_qlocale.cpp6
-rw-r--r--tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp89
-rw-r--r--tests/auto/gui/kernel/qwindow/BLACKLIST1
-rw-r--r--tests/auto/other/android/CMakeLists.txt8
-rw-r--r--tests/auto/other/android/deployment_settings/tst_android_deployment_settings.cpp9
-rw-r--r--tests/auto/other/android/dynamic_feature/CMakeLists.txt33
-rw-r--r--tests/auto/other/android/dynamic_feature/feature/CMakeLists.txt8
-rw-r--r--tests/auto/other/android/dynamic_feature/feature/qtlogo.pngbin0 -> 1214 bytes
-rw-r--r--tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoader.java175
-rw-r--r--tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoaderListener.java92
-rw-r--r--tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoaderListenerCallback.java26
-rw-r--r--tests/auto/other/android/dynamic_feature/storeloader/storeloader.cpp227
-rw-r--r--tests/auto/other/android/dynamic_feature/storeloader/storeloader.h65
-rw-r--r--tests/auto/other/android/dynamic_feature/tst_android_dynamic_feature.cpp37
-rw-r--r--tests/auto/other/android/package_source_dir/CMakeLists.txt54
-rw-r--r--tests/auto/other/android/package_source_dir/custom_android_manifest/AndroidManifest.xml51
-rw-r--r--tests/auto/other/android/package_source_dir/custom_android_manifest_bundle/app/AndroidManifest.xml51
-rw-r--r--tests/auto/other/android/package_source_dir/partial_template/app/AndroidManifest.xml51
-rw-r--r--tests/auto/other/android/package_source_dir/partial_template/app/build.gradle.in54
-rw-r--r--tests/auto/other/android/package_source_dir/tst_android_package_source_dir.cpp47
-rw-r--r--tests/auto/other/android/permissions/CMakeLists.txt23
-rw-r--r--tests/auto/other/android/permissions/tst_android_permissions.cpp80
-rw-r--r--tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp16
281 files changed, 3975 insertions, 725 deletions
diff --git a/cmake/FindBundletool.cmake b/cmake/FindBundletool.cmake
new file mode 100644
index 00000000000..f691b27da89
--- /dev/null
+++ b/cmake/FindBundletool.cmake
@@ -0,0 +1,48 @@
+# Copyright (C) 2025 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#.rst:
+# FindBundletool
+# ---------
+#
+# Try to locate the android bundletool.
+# If found, this will define the following variables:
+#
+# ``Bundletool_FOUND``
+# True if the Bundletool is found
+#
+# ``Bundletool_EXECUTABLE ``
+# Path to the Bundletool executable
+#
+# If ``Bundletool_FOUND`` is TRUE, it will also define the following
+# imported target:
+#
+# ``Bundletool::Bundletool``
+# The Bundletool executable
+
+if(DEFINED ENV{Bundletool_EXECUTABLE})
+ if((NOT Bundletool_EXECUTABLE OR NOT EXISTS "${Bundletool_EXECUTABLE}")
+ AND EXISTS "$ENV{Bundletool_EXECUTABLE}")
+ set(_Bundletool_use_force FORCE)
+ else()
+ set(_Bundletool_use_force "")
+ endif()
+ set(Bundletool_EXECUTABLE "$ENV{Bundletool_EXECUTABLE}" CACHE FILEPATH
+ "Path to the 'bundletool' executable." ${_Bundletool_use_force})
+ unset(_Bundletool_use_force)
+endif()
+
+find_file(Bundletool_EXECUTABLE bundletool bundletool.jar)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Bundletool DEFAULT_MSG Bundletool_EXECUTABLE)
+
+if(Bundletool_FOUND)
+ if(NOT TARGET Bundletool::Bundletool)
+ add_executable(Bundletool::Bundletool IMPORTED)
+ set_target_properties(Bundletool::Bundletool PROPERTIES
+ IMPORTED_LOCATION "${Bundletool_EXECUTABLE}")
+ endif()
+endif()
+
+mark_as_advanced(Bundletool_EXECUTABLE)
diff --git a/cmake/QtAndroidHelpers.cmake b/cmake/QtAndroidHelpers.cmake
index 64696fff6d4..cb7d4716f12 100644
--- a/cmake/QtAndroidHelpers.cmake
+++ b/cmake/QtAndroidHelpers.cmake
@@ -473,3 +473,33 @@ function(qt_internal_create_source_jar)
add_dependencies(install_android_source_jar_${module} ${jar_target})
add_dependencies(install_android_source_jars install_android_source_jar_${module})
endfunction()
+
+# The function stores Android permissions that are required by the module target.
+# The stored INTERFACE_QT_ANDROID_PERMISSIONS is the transitive property.
+function(qt_internal_android_add_interface_permissions target)
+ get_target_property(permissions ${target} QT_ANDROID_PERMISSIONS)
+ if(NOT permissions)
+ return()
+ endif()
+
+ set(postprocessed_permissions "")
+ foreach(permission IN LISTS permissions)
+ # TODO: skip processing extras for now, add them back once internal API
+ # will cover adding extras using internal function.
+ list(APPEND postprocessed_permissions "name\;${permission}")
+ endforeach()
+ qt_internal_set_module_transitive_properties(${target} TYPE LINK PROPERTIES
+ INTERFACE_QT_ANDROID_PERMISSIONS "${postprocessed_permissions}")
+endfunction()
+
+# The function stores Android features that are required by the module target.
+# The stored INTERFACE_QT_ANDROID_FEATURES is the transitive property.
+function(qt_internal_android_add_interface_features target)
+ get_target_property(features ${target} QT_ANDROID_FEATURES)
+ if(NOT features)
+ return()
+ endif()
+
+ qt_internal_set_module_transitive_properties(${target} TYPE LINK PROPERTIES
+ INTERFACE_QT_ANDROID_FEATURES "${features}")
+endfunction()
diff --git a/cmake/QtBaseHelpers.cmake b/cmake/QtBaseHelpers.cmake
index b3a4e8c7619..911b6001564 100644
--- a/cmake/QtBaseHelpers.cmake
+++ b/cmake/QtBaseHelpers.cmake
@@ -237,6 +237,9 @@ macro(qt_internal_qtbase_build_repo)
# Needed when building qtbase for android.
if(ANDROID)
include(src/corelib/Qt6AndroidMacros.cmake)
+ include(src/corelib/Qt6AndroidDynamicFeatureHelpers.cmake)
+ include(src/corelib/Qt6AndroidGradleHelpers.cmake)
+ include(src/corelib/Qt6AndroidPermissionHelpers.cmake)
endif()
# Needed when building for WebAssembly.
diff --git a/cmake/QtInternalTargets.cmake b/cmake/QtInternalTargets.cmake
index 1b0adccd5b5..c041f9d3ac5 100644
--- a/cmake/QtInternalTargets.cmake
+++ b/cmake/QtInternalTargets.cmake
@@ -368,6 +368,13 @@ if (MSVC AND NOT CLANG)
)
endif()
+if (WIN32 AND (CLANG OR MINGW) AND (TEST_architecture_arch STREQUAL x86_64))
+ # windows 10 requires cmpxchg16b
+ target_compile_options(PlatformCommonInternal INTERFACE
+ -mcx16
+ )
+endif()
+
set(_qt_internal_clang_msvc_frontend False)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
diff --git a/cmake/QtPlatformAndroid.cmake b/cmake/QtPlatformAndroid.cmake
index b480b1c14a6..d56a889d114 100644
--- a/cmake/QtPlatformAndroid.cmake
+++ b/cmake/QtPlatformAndroid.cmake
@@ -30,6 +30,7 @@ include(UseJava)
# Find JDK 8.0
find_package(Java 1.8 COMPONENTS Development REQUIRED)
+find_package(Bundletool)
# Ensure we are using the shared version of libc++
if(NOT ANDROID_STL STREQUAL c++_shared)
@@ -117,13 +118,32 @@ function(qt_internal_android_test_runner_arguments target out_test_runner out_te
set(deployment_tool "${host_bin_dir}/androiddeployqt")
_qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
- set(${out_test_arguments}
+ _qt_internal_android_get_platform_tools_path(platform_tools)
+ set(test_arguments
"--path" "${android_build_dir}"
- "--adb" "${ANDROID_SDK_ROOT}/platform-tools/adb"
+ "--adb" "${platform_tools}/adb"
"--skip-install-root"
- "--make" "\"${CMAKE_COMMAND}\" --build ${CMAKE_BINARY_DIR} --target ${target}_make_apk"
- "--apk" "${android_build_dir}/${target}.apk"
"--ndk-stack" "${ANDROID_NDK_ROOT}/ndk-stack"
- PARENT_SCOPE
)
+
+ if(QT_USE_ANDROID_MODERN_BUNDLE)
+ _qt_internal_android_get_target_deployment_dir(target_deployment_dir ${target})
+ list(APPEND test_arguments
+ "--manifest" "${target_deployment_dir}/AndroidManifest.xml")
+ endif()
+
+ if(EXISTS "${Bundletool_EXECUTABLE}" AND QT_USE_ANDROID_MODERN_BUNDLE)
+ list(APPEND test_arguments
+ "--make" "\"${CMAKE_COMMAND}\" --build ${CMAKE_BINARY_DIR} --target ${target}_make_aab"
+ "--aab" "${android_build_dir}/${target}.aab"
+ "--bundletool" "${Bundletool_EXECUTABLE}"
+ )
+ else()
+ list(APPEND test_arguments
+ "--make" "\"${CMAKE_COMMAND}\" --build ${CMAKE_BINARY_DIR} --target ${target}_make_apk"
+ "--apk" "${android_build_dir}/${target}.apk"
+ )
+ endif()
+
+ set(${out_test_arguments} "${test_arguments}" PARENT_SCOPE)
endfunction()
diff --git a/cmake/QtPostProcessHelpers.cmake b/cmake/QtPostProcessHelpers.cmake
index 9f220f9d78b..07fcdee268b 100644
--- a/cmake/QtPostProcessHelpers.cmake
+++ b/cmake/QtPostProcessHelpers.cmake
@@ -790,6 +790,8 @@ function(qt_modules_process_android_dependencies)
qt_internal_get_qt_repo_known_modules(repo_known_modules)
foreach (target ${repo_known_modules})
qt_internal_android_dependencies(${target})
+ qt_internal_android_add_interface_permissions(${target})
+ qt_internal_android_add_interface_features(${target})
endforeach()
endfunction()
diff --git a/cmake/QtTestHelpers.cmake b/cmake/QtTestHelpers.cmake
index ad8a9d65c14..8a0666b0ceb 100644
--- a/cmake/QtTestHelpers.cmake
+++ b/cmake/QtTestHelpers.cmake
@@ -1176,6 +1176,13 @@ function(qt_internal_collect_command_environment out_path out_plugin_path)
set(test_env_path "${test_env_path}${QT_PATH_SEPARATOR}${install_prefix}")
endforeach()
set(test_env_path "${test_env_path}${QT_PATH_SEPARATOR}$ENV{PATH}")
+ if(ANDROID)
+ # Add android platform tools to path. Required for the correct androidtestrunner work.
+ _qt_internal_android_get_platform_tools_path(platform_tools)
+ string(PREPEND test_env_path
+ "${platform_tools}" "${QT_PATH_SEPARATOR}")
+ endif()
+
string(REPLACE ";" "\;" test_env_path "${test_env_path}")
set(${out_path} "${test_env_path}" PARENT_SCOPE)
diff --git a/coin/instructions/prepare_building_env.yaml b/coin/instructions/prepare_building_env.yaml
index 20e7ef7f01c..85661f8f3eb 100644
--- a/coin/instructions/prepare_building_env.yaml
+++ b/coin/instructions/prepare_building_env.yaml
@@ -646,6 +646,26 @@ instructions:
property: features
contains_value: Sccache
+ # VCPKG
+ - type: Group
+ instructions:
+ - type: AppendToEnvironmentVariable
+ variableName: COMMON_NON_QTBASE_CMAKE_ARGS
+ variableValue: " -DQT_USE_VCPKG=ON -DVCPKG_INSTALLED_DIR={{.Env.VCPKG_INSTALLED_DIR}} -DVCPKG_HOST_TRIPLET={{.Env.VCPKG_HOST_TRIPLET}} -DVCPKG_TARGET_TRIPLET={{.Env.VCPKG_TARGET_TRIPLET}}"
+ - type: AppendToEnvironmentVariable
+ variableName: COMMON_TEST_CMAKE_ARGS
+ variableValue: " -DQT_USE_VCPKG=ON -DVCPKG_INSTALLED_DIR={{.Env.VCPKG_INSTALLED_DIR}} -DVCPKG_HOST_TRIPLET={{.Env.VCPKG_HOST_TRIPLET}} -DVCPKG_TARGET_TRIPLET={{.Env.VCPKG_TARGET_TRIPLET}}"
+ - type: AppendToEnvironmentVariable
+ variableName: COMMON_EXAMPLES_CMAKE_ARGS
+ variableValue: " -DQT_USE_VCPKG=ON -DVCPKG_INSTALLED_DIR={{.Env.VCPKG_INSTALLED_DIR}} -DVCPKG_HOST_TRIPLET={{.Env.VCPKG_HOST_TRIPLET}} -DVCPKG_TARGET_TRIPLET={{.Env.VCPKG_TARGET_TRIPLET}}"
+ - type: AppendToEnvironmentVariable
+ variableName: COMMON_NON_QTBASE_TARGET_CMAKE_ARGS
+ variableValue: " -DQT_USE_VCPKG=ON -DVCPKG_INSTALLED_DIR={{.Env.VCPKG_INSTALLED_DIR}} -DVCPKG_HOST_TRIPLET={{.Env.VCPKG_HOST_TRIPLET}} -DVCPKG_TARGET_TRIPLET={{.Env.VCPKG_TARGET_TRIPLET}}"
+ enable_if:
+ condition: runtime
+ env_var: USE_VCPKG
+ equals_value: "ON"
+
# Specify a custom examples installation directory, so that the built example binaries are not
# packaged into the artifact archive together with the Qt libraries.
# Also specify that during examples deployment, only a subset of examples should be deployed, to
diff --git a/configure.cmake b/configure.cmake
index 92fe4dba448..8d96ba7e1f0 100644
--- a/configure.cmake
+++ b/configure.cmake
@@ -1116,13 +1116,12 @@ qt_feature("network" PRIVATE
)
qt_feature("printsupport" PRIVATE
LABEL "Qt PrintSupport"
- CONDITION QT_FEATURE_widgets AND NOT WASM
+ CONDITION QT_FEATURE_widgets
SECTION "Module"
PURPOSE "Provides the Qt PrintSupport module."
)
qt_feature("sql" PRIVATE
LABEL "Qt Sql"
- CONDITION NOT WASM
SECTION "Module"
PURPOSE "Provides the Sql module."
)
diff --git a/doc/global/includes/cli-build-cmake.qdocinc b/doc/global/includes/cli-build-cmake.qdocinc
index b4c6ffccb4b..5f30e8632b7 100644
--- a/doc/global/includes/cli-build-cmake.qdocinc
+++ b/doc/global/includes/cli-build-cmake.qdocinc
@@ -28,7 +28,7 @@
\badcode \QtVersion
md notepad-build
cd notepad-build
- C:\Qt\\1\msvc2019_64\bin\qt-cmake -GNinja C:\Examples\notepad
+ C:\Qt\\1\msvc2022_64\bin\qt-cmake -GNinja C:\Examples\notepad
ninja
\endcode
diff --git a/licenseRule.json b/licenseRule.json
index e35e8ba7fd1..b40e225e347 100644
--- a/licenseRule.json
+++ b/licenseRule.json
@@ -119,7 +119,7 @@
"file type": "test",
"spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
},
- "ests/auto/testlib/selftests/": {
+ "tests/auto/testlib/selftests/(?!README)": {
"comment": "Exception. Those are test files",
"file type": "test",
"spdx": ["LicenseRef-Qt-Commercial OR GPL-3.0-only"]
diff --git a/src/3rdparty/gradle/gradle.properties b/src/3rdparty/gradle/gradle.properties
index 4fe1674abd3..3472b396d96 100644
--- a/src/3rdparty/gradle/gradle.properties
+++ b/src/3rdparty/gradle/gradle.properties
@@ -16,3 +16,6 @@ org.gradle.parallel=true
# Allow AndroidX usage
android.useAndroidX=true
+
+# User-defined properties
+@EXTRA_PROPERTIES@
diff --git a/src/android/CMakeLists.txt b/src/android/CMakeLists.txt
index 7c99ce7264e..12fbca624b3 100644
--- a/src/android/CMakeLists.txt
+++ b/src/android/CMakeLists.txt
@@ -9,6 +9,7 @@ if (ANDROID)
add_subdirectory(java)
add_subdirectory(templates)
add_subdirectory(templates_aar)
+ add_subdirectory(templates_cmake)
endif()
qt_internal_add_java_documentation(Global)
diff --git a/src/android/REUSE.toml b/src/android/REUSE.toml
index 7d5a22fd2f7..6d821d52904 100644
--- a/src/android/REUSE.toml
+++ b/src/android/REUSE.toml
@@ -1,7 +1,7 @@
version = 1
[[annotations]]
-path = ["jar/build.gradle", "jar/settings.gradle", "templates/build.gradle"]
+path = ["jar/build.gradle", "jar/settings.gradle", "templates/build.gradle", "templates_cmake/**"]
precedence = "closest"
comment = "double check"
SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd."
diff --git a/src/android/templates/build.gradle b/src/android/templates/build.gradle
index 6595cb5358f..b6c4797fde7 100644
--- a/src/android/templates/build.gradle
+++ b/src/android/templates/build.gradle
@@ -70,8 +70,8 @@ android {
abortOnError = false
}
- // Do not compress Qt binary resources file
aaptOptions {
+ // Do not compress Qt binary resources file
noCompress 'rcc'
}
diff --git a/src/android/templates_cmake/CMakeLists.txt b/src/android/templates_cmake/CMakeLists.txt
new file mode 100644
index 00000000000..546a4fc50f3
--- /dev/null
+++ b/src/android/templates_cmake/CMakeLists.txt
@@ -0,0 +1,46 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+set(templates_files
+ "${CMAKE_CURRENT_SOURCE_DIR}/settings.gradle.in"
+ "${CMAKE_CURRENT_SOURCE_DIR}/gradle.properties.in"
+)
+
+set(app_template_files
+ "${CMAKE_CURRENT_SOURCE_DIR}/app/gradle.properties.in"
+ "${CMAKE_CURRENT_SOURCE_DIR}/app/build.gradle.in"
+ "${CMAKE_CURRENT_SOURCE_DIR}/app/AndroidManifest.xml.in"
+)
+
+set(dynamic_feature_files
+ "${CMAKE_CURRENT_SOURCE_DIR}/dynamic_feature/AndroidManifest.xml.in"
+ "${CMAKE_CURRENT_SOURCE_DIR}/dynamic_feature/build.gradle.in"
+)
+
+add_custom_target(Qt6AndroidCMakeTemplates
+ SOURCES
+ ${templates_files}
+)
+
+qt_path_join(destination ${QT_INSTALL_DIR} ${INSTALL_DATADIR} "src/android/templates_cmake")
+
+qt_copy_or_install(FILES ${templates_files} DESTINATION "${destination}")
+qt_copy_or_install(FILES ${app_template_files} DESTINATION "${destination}/app")
+qt_copy_or_install(FILES ${dynamic_feature_files} DESTINATION "${destination}/dynamic_feature")
+
+if(NOT QT_WILL_INSTALL)
+ qt_internal_copy_at_build_time(TARGET Qt6AndroidCMakeTemplates
+ FILES ${templates_files}
+ DESTINATION ${destination}
+ )
+
+ qt_internal_copy_at_build_time(TARGET Qt6AndroidCMakeTemplates
+ FILES ${app_templates_files}
+ DESTINATION ${destination}/app
+ )
+
+ qt_internal_copy_at_build_time(TARGET Qt6AndroidCMakeTemplates
+ FILES ${dynamic_feature_files}
+ DESTINATION ${destination}/dynamic_feature
+ )
+endif()
diff --git a/src/android/templates_cmake/app/AndroidManifest.xml.in b/src/android/templates_cmake/app/AndroidManifest.xml.in
new file mode 100644
index 00000000000..61c33cc7657
--- /dev/null
+++ b/src/android/templates_cmake/app/AndroidManifest.xml.in
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:dist="http://schemas.android.com/apk/distribution"
+ package="@APP_PACKAGE_NAME@"
+ android:installLocation="auto"
+ android:versionCode="@APP_VERSION_CODE@"
+ android:versionName="@APP_VERSION_NAME@">
+ @APP_PERMISSIONS@
+ @APP_FEATURES@
+ <dist:module dist:instant="true"/>
+ <supports-screens
+ android:anyDensity="true"
+ android:largeScreens="true"
+ android:normalScreens="true"
+ android:smallScreens="true" />
+ <application
+ android:name="org.qtproject.qt.android.bindings.QtApplication"
+ android:hardwareAccelerated="true"
+ android:label="@APP_NAME@"
+ @APP_ICON@
+ android:requestLegacyExternalStorage="true"
+ android:allowBackup="true"
+ android:fullBackupOnly="false">
+ <activity
+ android:name="org.qtproject.qt.android.bindings.QtActivity"
+ android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
+ android:launchMode="singleTop"
+ android:screenOrientation="unspecified"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ <meta-data
+ android:name="android.app.lib_name"
+ android:value="@APP_LIB_NAME@" />
+
+ <meta-data
+ android:name="android.app.arguments"
+ android:value="@APP_ARGUMENTS@" />
+ </activity>
+
+ <provider
+ android:name="androidx.core.content.FileProvider"
+ android:authorities="${applicationId}.qtprovider"
+ android:exported="false"
+ android:grantUriPermissions="true">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/qtprovider_paths"/>
+ </provider>
+ </application>
+</manifest>
diff --git a/src/android/templates_cmake/app/build.gradle.in b/src/android/templates_cmake/app/build.gradle.in
new file mode 100644
index 00000000000..917f371e46f
--- /dev/null
+++ b/src/android/templates_cmake/app/build.gradle.in
@@ -0,0 +1,53 @@
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:8.10.1'
+ }
+}
+
+apply plugin: '@GRADLE_PLUGIN_TYPE@'
+
+dependencies {
+ @GRADLE_DEPENDENCIES@
+}
+
+android {
+ namespace '@PACKAGE_NAME@'
+ compileSdkVersion '@ANDROID_COMPILE_SDK_VERSION@'
+ buildToolsVersion '@ANDROID_BUILD_TOOLS_VERSION@'
+ ndkVersion '@ANDROID_NDK_REVISION@'
+
+ defaultConfig {
+ @DEFAULT_CONFIG_VALUES@
+ }
+
+ sourceSets {
+ main {
+@SOURCE_SETS@
+ }
+ }
+
+ tasks.withType(JavaCompile) {
+ options.incremental = true
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ aaptOptions {
+ // Do not compress Qt binary resources file
+ noCompress 'rcc'
+ }
+
+ @ANDROID_DEPLOYMENT_EXTRAS@
+}
diff --git a/src/android/templates_cmake/app/gradle.properties.in b/src/android/templates_cmake/app/gradle.properties.in
new file mode 100644
index 00000000000..1136551f3fa
--- /dev/null
+++ b/src/android/templates_cmake/app/gradle.properties.in
@@ -0,0 +1 @@
+# Extend this template with the extra gradle properties applicable for Android app.
diff --git a/src/android/templates_cmake/dynamic_feature/AndroidManifest.xml.in b/src/android/templates_cmake/dynamic_feature/AndroidManifest.xml.in
new file mode 100644
index 00000000000..9945ec76f27
--- /dev/null
+++ b/src/android/templates_cmake/dynamic_feature/AndroidManifest.xml.in
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:dist="http://schemas.android.com/apk/distribution"
+ split="@APP_TARGET@"
+ android:isFeatureSplit="true">
+ <dist:module
+ dist:instant="true"
+ dist:title="@TITLE_VAR@">
+ <dist:delivery>
+ <dist:on-demand />
+ </dist:delivery>
+ <dist:fusing dist:include="false" />
+ </dist:module>
+ <application android:hasCode="false"/>
+</manifest>
diff --git a/src/android/templates_cmake/dynamic_feature/build.gradle.in b/src/android/templates_cmake/dynamic_feature/build.gradle.in
new file mode 100644
index 00000000000..917f371e46f
--- /dev/null
+++ b/src/android/templates_cmake/dynamic_feature/build.gradle.in
@@ -0,0 +1,53 @@
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:8.10.1'
+ }
+}
+
+apply plugin: '@GRADLE_PLUGIN_TYPE@'
+
+dependencies {
+ @GRADLE_DEPENDENCIES@
+}
+
+android {
+ namespace '@PACKAGE_NAME@'
+ compileSdkVersion '@ANDROID_COMPILE_SDK_VERSION@'
+ buildToolsVersion '@ANDROID_BUILD_TOOLS_VERSION@'
+ ndkVersion '@ANDROID_NDK_REVISION@'
+
+ defaultConfig {
+ @DEFAULT_CONFIG_VALUES@
+ }
+
+ sourceSets {
+ main {
+@SOURCE_SETS@
+ }
+ }
+
+ tasks.withType(JavaCompile) {
+ options.incremental = true
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ aaptOptions {
+ // Do not compress Qt binary resources file
+ noCompress 'rcc'
+ }
+
+ @ANDROID_DEPLOYMENT_EXTRAS@
+}
diff --git a/src/android/templates_cmake/gradle.properties.in b/src/android/templates_cmake/gradle.properties.in
new file mode 100644
index 00000000000..b751946190a
--- /dev/null
+++ b/src/android/templates_cmake/gradle.properties.in
@@ -0,0 +1,12 @@
+# Project-wide Gradle settings.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2500m -XX:MaxMetaspaceSize=768m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# Enable building projects in parallel
+org.gradle.parallel=true
+
+# Allow AndroidX usage
+android.useAndroidX=true
diff --git a/src/android/templates_cmake/settings.gradle.in b/src/android/templates_cmake/settings.gradle.in
new file mode 100644
index 00000000000..03954ae5f9f
--- /dev/null
+++ b/src/android/templates_cmake/settings.gradle.in
@@ -0,0 +1,18 @@
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "@ROOT_PROJECT_NAME@"
+include(":app")
+@SUBPROJECTS@
diff --git a/src/assets/CMakeLists.txt b/src/assets/CMakeLists.txt
index da9c0c14eea..ab07d27696e 100644
--- a/src/assets/CMakeLists.txt
+++ b/src/assets/CMakeLists.txt
@@ -1,6 +1,5 @@
# Copyright (C) 2024 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
-add_subdirectory(icons)
if (NOT INTEGRITY AND TARGET Qt6::Network AND TARGET Qt6::Concurrent)
add_subdirectory(downloader)
diff --git a/src/assets/icons/128x128/document-new.png b/src/assets/icons/128x128/document-new.png
deleted file mode 100644
index 8d86a4827a7..00000000000
--- a/src/assets/icons/128x128/document-new.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/document-open.png b/src/assets/icons/128x128/document-open.png
deleted file mode 100644
index 2183dbbea64..00000000000
--- a/src/assets/icons/128x128/document-open.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/document-print.png b/src/assets/icons/128x128/document-print.png
deleted file mode 100644
index 9e7378aab2a..00000000000
--- a/src/assets/icons/128x128/document-print.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/document-save.png b/src/assets/icons/128x128/document-save.png
deleted file mode 100644
index e8b28406433..00000000000
--- a/src/assets/icons/128x128/document-save.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/edit-copy.png b/src/assets/icons/128x128/edit-copy.png
deleted file mode 100644
index 7585f4baa0c..00000000000
--- a/src/assets/icons/128x128/edit-copy.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/edit-cut.png b/src/assets/icons/128x128/edit-cut.png
deleted file mode 100644
index 51ede2fe37e..00000000000
--- a/src/assets/icons/128x128/edit-cut.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/edit-delete.png b/src/assets/icons/128x128/edit-delete.png
deleted file mode 100644
index bdf785c8285..00000000000
--- a/src/assets/icons/128x128/edit-delete.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/edit-paste.png b/src/assets/icons/128x128/edit-paste.png
deleted file mode 100644
index 690ffa172d9..00000000000
--- a/src/assets/icons/128x128/edit-paste.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/edit-redo.png b/src/assets/icons/128x128/edit-redo.png
deleted file mode 100644
index f1c97f71c25..00000000000
--- a/src/assets/icons/128x128/edit-redo.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/edit-undo.png b/src/assets/icons/128x128/edit-undo.png
deleted file mode 100644
index e728cbf6e03..00000000000
--- a/src/assets/icons/128x128/edit-undo.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/format-justify-center.png b/src/assets/icons/128x128/format-justify-center.png
deleted file mode 100644
index 44ceb2af4d5..00000000000
--- a/src/assets/icons/128x128/format-justify-center.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/format-justify-fill.png b/src/assets/icons/128x128/format-justify-fill.png
deleted file mode 100644
index b99a8507046..00000000000
--- a/src/assets/icons/128x128/format-justify-fill.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/format-justify-left.png b/src/assets/icons/128x128/format-justify-left.png
deleted file mode 100644
index 2b63887b495..00000000000
--- a/src/assets/icons/128x128/format-justify-left.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/format-justify-right.png b/src/assets/icons/128x128/format-justify-right.png
deleted file mode 100644
index 6c61889d595..00000000000
--- a/src/assets/icons/128x128/format-justify-right.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/format-text-bold.png b/src/assets/icons/128x128/format-text-bold.png
deleted file mode 100644
index 96a5ca88a22..00000000000
--- a/src/assets/icons/128x128/format-text-bold.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/format-text-italic.png b/src/assets/icons/128x128/format-text-italic.png
deleted file mode 100644
index 2bb71b4a4d3..00000000000
--- a/src/assets/icons/128x128/format-text-italic.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128/format-text-underline.png b/src/assets/icons/128x128/format-text-underline.png
deleted file mode 100644
index ecf6830c929..00000000000
--- a/src/assets/icons/128x128/format-text-underline.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index 32776b51a96..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index 06e188b93b9..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index 644e3c149af..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index 16fa70493a2..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index b18bead117f..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index d9454cebf1c..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index 4081cdb2ca7..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index 3358426818d..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index e28b28542c6..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index fe10f57a398..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index d4ad74b0d07..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index bf0dd84bbb0..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index dde68c8514a..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index 8a5e7518bdc..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index 665d3ce37b5..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index 4b6846a6b98..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/128x128@2/[email protected] b/src/assets/icons/128x128@2/[email protected]
deleted file mode 100644
index 601f73216a3..00000000000
--- a/src/assets/icons/128x128@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/document-new.png b/src/assets/icons/16x16/document-new.png
deleted file mode 100644
index 893e7e1aec4..00000000000
--- a/src/assets/icons/16x16/document-new.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/document-open.png b/src/assets/icons/16x16/document-open.png
deleted file mode 100644
index b07906f40bd..00000000000
--- a/src/assets/icons/16x16/document-open.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/document-print.png b/src/assets/icons/16x16/document-print.png
deleted file mode 100644
index 9341060076f..00000000000
--- a/src/assets/icons/16x16/document-print.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/document-save.png b/src/assets/icons/16x16/document-save.png
deleted file mode 100644
index 6238718191b..00000000000
--- a/src/assets/icons/16x16/document-save.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/edit-copy.png b/src/assets/icons/16x16/edit-copy.png
deleted file mode 100644
index 585f5bfc8d8..00000000000
--- a/src/assets/icons/16x16/edit-copy.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/edit-cut.png b/src/assets/icons/16x16/edit-cut.png
deleted file mode 100644
index 661ef1ad030..00000000000
--- a/src/assets/icons/16x16/edit-cut.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/edit-delete.png b/src/assets/icons/16x16/edit-delete.png
deleted file mode 100644
index 7b5998df8a4..00000000000
--- a/src/assets/icons/16x16/edit-delete.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/edit-paste.png b/src/assets/icons/16x16/edit-paste.png
deleted file mode 100644
index 6318a22caf3..00000000000
--- a/src/assets/icons/16x16/edit-paste.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/edit-redo.png b/src/assets/icons/16x16/edit-redo.png
deleted file mode 100644
index 7eb10fe899c..00000000000
--- a/src/assets/icons/16x16/edit-redo.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/edit-undo.png b/src/assets/icons/16x16/edit-undo.png
deleted file mode 100644
index 108712547cb..00000000000
--- a/src/assets/icons/16x16/edit-undo.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/format-justify-center.png b/src/assets/icons/16x16/format-justify-center.png
deleted file mode 100644
index 6b0951fa5dd..00000000000
--- a/src/assets/icons/16x16/format-justify-center.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/format-justify-fill.png b/src/assets/icons/16x16/format-justify-fill.png
deleted file mode 100644
index 6e1c10d7c45..00000000000
--- a/src/assets/icons/16x16/format-justify-fill.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/format-justify-left.png b/src/assets/icons/16x16/format-justify-left.png
deleted file mode 100644
index 9dfdc89b68a..00000000000
--- a/src/assets/icons/16x16/format-justify-left.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/format-justify-right.png b/src/assets/icons/16x16/format-justify-right.png
deleted file mode 100644
index 36a52081f18..00000000000
--- a/src/assets/icons/16x16/format-justify-right.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/format-text-bold.png b/src/assets/icons/16x16/format-text-bold.png
deleted file mode 100644
index a079317a947..00000000000
--- a/src/assets/icons/16x16/format-text-bold.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/format-text-italic.png b/src/assets/icons/16x16/format-text-italic.png
deleted file mode 100644
index 04202b2842f..00000000000
--- a/src/assets/icons/16x16/format-text-italic.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16/format-text-underline.png b/src/assets/icons/16x16/format-text-underline.png
deleted file mode 100644
index a80368212d8..00000000000
--- a/src/assets/icons/16x16/format-text-underline.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index 482ae52024e..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index 9858b146f44..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index 1672ec58971..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index f04de746731..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index bbb34cc4c22..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index d89ef6c0167..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index 4c97ee24952..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index 299fa776867..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index 4f8849c7110..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index b3d366c53f6..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index 80c3afd9a6e..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index 33589ea25d0..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index ba028211355..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index 8e15d0cb44f..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index 754efdd9755..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index 6db31a4f697..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/16x16@2/[email protected] b/src/assets/icons/16x16@2/[email protected]
deleted file mode 100644
index 977cde9d974..00000000000
--- a/src/assets/icons/16x16@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/document-new.png b/src/assets/icons/256x256/document-new.png
deleted file mode 100644
index 32776b51a96..00000000000
--- a/src/assets/icons/256x256/document-new.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/document-open.png b/src/assets/icons/256x256/document-open.png
deleted file mode 100644
index 06e188b93b9..00000000000
--- a/src/assets/icons/256x256/document-open.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/document-print.png b/src/assets/icons/256x256/document-print.png
deleted file mode 100644
index 644e3c149af..00000000000
--- a/src/assets/icons/256x256/document-print.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/document-save.png b/src/assets/icons/256x256/document-save.png
deleted file mode 100644
index 16fa70493a2..00000000000
--- a/src/assets/icons/256x256/document-save.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/edit-copy.png b/src/assets/icons/256x256/edit-copy.png
deleted file mode 100644
index b18bead117f..00000000000
--- a/src/assets/icons/256x256/edit-copy.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/edit-cut.png b/src/assets/icons/256x256/edit-cut.png
deleted file mode 100644
index d9454cebf1c..00000000000
--- a/src/assets/icons/256x256/edit-cut.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/edit-delete.png b/src/assets/icons/256x256/edit-delete.png
deleted file mode 100644
index 4081cdb2ca7..00000000000
--- a/src/assets/icons/256x256/edit-delete.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/edit-paste.png b/src/assets/icons/256x256/edit-paste.png
deleted file mode 100644
index 3358426818d..00000000000
--- a/src/assets/icons/256x256/edit-paste.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/edit-redo.png b/src/assets/icons/256x256/edit-redo.png
deleted file mode 100644
index e28b28542c6..00000000000
--- a/src/assets/icons/256x256/edit-redo.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/edit-undo.png b/src/assets/icons/256x256/edit-undo.png
deleted file mode 100644
index fe10f57a398..00000000000
--- a/src/assets/icons/256x256/edit-undo.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/format-justify-center.png b/src/assets/icons/256x256/format-justify-center.png
deleted file mode 100644
index d4ad74b0d07..00000000000
--- a/src/assets/icons/256x256/format-justify-center.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/format-justify-fill.png b/src/assets/icons/256x256/format-justify-fill.png
deleted file mode 100644
index bf0dd84bbb0..00000000000
--- a/src/assets/icons/256x256/format-justify-fill.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/format-justify-left.png b/src/assets/icons/256x256/format-justify-left.png
deleted file mode 100644
index dde68c8514a..00000000000
--- a/src/assets/icons/256x256/format-justify-left.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/format-justify-right.png b/src/assets/icons/256x256/format-justify-right.png
deleted file mode 100644
index 8a5e7518bdc..00000000000
--- a/src/assets/icons/256x256/format-justify-right.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/format-text-bold.png b/src/assets/icons/256x256/format-text-bold.png
deleted file mode 100644
index 665d3ce37b5..00000000000
--- a/src/assets/icons/256x256/format-text-bold.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/format-text-italic.png b/src/assets/icons/256x256/format-text-italic.png
deleted file mode 100644
index 4b6846a6b98..00000000000
--- a/src/assets/icons/256x256/format-text-italic.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256/format-text-underline.png b/src/assets/icons/256x256/format-text-underline.png
deleted file mode 100644
index 601f73216a3..00000000000
--- a/src/assets/icons/256x256/format-text-underline.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index bfec6d0e6d1..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index 630a05f622c..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index c8611c31c49..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index 6f460959818..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index 2f350041a05..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index e11cf6d2347..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index efe6b90bf59..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index 32f54b39598..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index 1f6e366535b..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index 980ed370621..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index af7044ddee1..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index da14563bd68..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index c1025bf0102..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index 3a07e06e0f3..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index b0f4cb09958..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index 85f0cfc1d65..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/256x256@2/[email protected] b/src/assets/icons/256x256@2/[email protected]
deleted file mode 100644
index 51ee0aa7783..00000000000
--- a/src/assets/icons/256x256@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/document-new.png b/src/assets/icons/32x32/document-new.png
deleted file mode 100644
index 482ae52024e..00000000000
--- a/src/assets/icons/32x32/document-new.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/document-open.png b/src/assets/icons/32x32/document-open.png
deleted file mode 100644
index 9858b146f44..00000000000
--- a/src/assets/icons/32x32/document-open.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/document-print.png b/src/assets/icons/32x32/document-print.png
deleted file mode 100644
index 1672ec58971..00000000000
--- a/src/assets/icons/32x32/document-print.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/document-save.png b/src/assets/icons/32x32/document-save.png
deleted file mode 100644
index f04de746731..00000000000
--- a/src/assets/icons/32x32/document-save.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/edit-copy.png b/src/assets/icons/32x32/edit-copy.png
deleted file mode 100644
index bbb34cc4c22..00000000000
--- a/src/assets/icons/32x32/edit-copy.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/edit-cut.png b/src/assets/icons/32x32/edit-cut.png
deleted file mode 100644
index d89ef6c0167..00000000000
--- a/src/assets/icons/32x32/edit-cut.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/edit-delete.png b/src/assets/icons/32x32/edit-delete.png
deleted file mode 100644
index 4c97ee24952..00000000000
--- a/src/assets/icons/32x32/edit-delete.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/edit-paste.png b/src/assets/icons/32x32/edit-paste.png
deleted file mode 100644
index 299fa776867..00000000000
--- a/src/assets/icons/32x32/edit-paste.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/edit-redo.png b/src/assets/icons/32x32/edit-redo.png
deleted file mode 100644
index 4f8849c7110..00000000000
--- a/src/assets/icons/32x32/edit-redo.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/edit-undo.png b/src/assets/icons/32x32/edit-undo.png
deleted file mode 100644
index b3d366c53f6..00000000000
--- a/src/assets/icons/32x32/edit-undo.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/format-justify-center.png b/src/assets/icons/32x32/format-justify-center.png
deleted file mode 100644
index 80c3afd9a6e..00000000000
--- a/src/assets/icons/32x32/format-justify-center.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/format-justify-fill.png b/src/assets/icons/32x32/format-justify-fill.png
deleted file mode 100644
index 33589ea25d0..00000000000
--- a/src/assets/icons/32x32/format-justify-fill.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/format-justify-left.png b/src/assets/icons/32x32/format-justify-left.png
deleted file mode 100644
index ba028211355..00000000000
--- a/src/assets/icons/32x32/format-justify-left.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/format-justify-right.png b/src/assets/icons/32x32/format-justify-right.png
deleted file mode 100644
index 8e15d0cb44f..00000000000
--- a/src/assets/icons/32x32/format-justify-right.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/format-text-bold.png b/src/assets/icons/32x32/format-text-bold.png
deleted file mode 100644
index 754efdd9755..00000000000
--- a/src/assets/icons/32x32/format-text-bold.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/format-text-italic.png b/src/assets/icons/32x32/format-text-italic.png
deleted file mode 100644
index 6db31a4f697..00000000000
--- a/src/assets/icons/32x32/format-text-italic.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32/format-text-underline.png b/src/assets/icons/32x32/format-text-underline.png
deleted file mode 100644
index 977cde9d974..00000000000
--- a/src/assets/icons/32x32/format-text-underline.png
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index c9245760612..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index 68e75b549a0..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index b7843367393..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index f4cca4b3238..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index 9690d6bb041..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index 408b0ae19b0..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index 58abfc1fa53..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index b8c288f6c70..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index 89fcd33c300..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index 6f7ad2cb402..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index 9b2cc1ed160..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index 1212e9f7613..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index 8c0eca3037e..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index fb0ed702525..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index 0e67ead0b8c..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index f746f8956f8..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/32x32@2/[email protected] b/src/assets/icons/32x32@2/[email protected]
deleted file mode 100644
index 47d6fced026..00000000000
--- a/src/assets/icons/32x32@2/[email protected]
+++ /dev/null
Binary files differ
diff --git a/src/assets/icons/CMakeLists.txt b/src/assets/icons/CMakeLists.txt
deleted file mode 100644
index f5adb229d85..00000000000
--- a/src/assets/icons/CMakeLists.txt
+++ /dev/null
@@ -1,174 +0,0 @@
-# Copyright (C) 2023 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
-
-qt_internal_add_module(ExampleIconsPrivate
- CONFIG_MODULE_NAME example_icons
- STATIC
- INTERNAL_MODULE
- NO_GENERATE_CPP_EXPORTS
-)
-
-set(icons_resource_files
- index.theme
- 16x16/document-new.png
- 16x16/document-open.png
- 16x16/document-print.png
- 16x16/document-save.png
- 16x16/edit-copy.png
- 16x16/edit-cut.png
- 16x16/edit-delete.png
- 16x16/edit-paste.png
- 16x16/edit-redo.png
- 16x16/edit-undo.png
- 16x16/format-justify-center.png
- 16x16/format-justify-fill.png
- 16x16/format-justify-left.png
- 16x16/format-justify-right.png
- 16x16/format-text-bold.png
- 16x16/format-text-italic.png
- 16x16/format-text-underline.png
- 32x32/document-new.png
- 32x32/document-open.png
- 32x32/document-print.png
- 32x32/document-save.png
- 32x32/edit-copy.png
- 32x32/edit-cut.png
- 32x32/edit-delete.png
- 32x32/edit-paste.png
- 32x32/edit-redo.png
- 32x32/edit-undo.png
- 32x32/format-justify-center.png
- 32x32/format-justify-fill.png
- 32x32/format-justify-left.png
- 32x32/format-justify-right.png
- 32x32/format-text-bold.png
- 32x32/format-text-italic.png
- 32x32/format-text-underline.png
- 128x128/document-new.png
- 128x128/document-open.png
- 128x128/document-print.png
- 128x128/document-save.png
- 128x128/edit-copy.png
- 128x128/edit-cut.png
- 128x128/edit-delete.png
- 128x128/edit-paste.png
- 128x128/edit-redo.png
- 128x128/edit-undo.png
- 128x128/format-justify-center.png
- 128x128/format-justify-fill.png
- 128x128/format-justify-left.png
- 128x128/format-justify-right.png
- 128x128/format-text-bold.png
- 128x128/format-text-italic.png
- 128x128/format-text-underline.png
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 128x128@2/[email protected]
- 256x256/document-new.png
- 256x256/document-open.png
- 256x256/document-print.png
- 256x256/document-save.png
- 256x256/edit-copy.png
- 256x256/edit-cut.png
- 256x256/edit-delete.png
- 256x256/edit-paste.png
- 256x256/edit-redo.png
- 256x256/edit-undo.png
- 256x256/format-justify-center.png
- 256x256/format-justify-fill.png
- 256x256/format-justify-left.png
- 256x256/format-justify-right.png
- 256x256/format-text-bold.png
- 256x256/format-text-italic.png
- 256x256/format-text-underline.png
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- 256x256@2/[email protected]
- scalable/document-new.svg
- scalable/document-open.svg
- scalable/document-print.svg
- scalable/document-save.svg
- scalable/edit-copy.svg
- scalable/edit-cut.svg
- scalable/edit-delete.svg
- scalable/edit-paste.svg
- scalable/edit-redo.svg
- scalable/edit-undo.svg
- scalable/format-justify-center.svg
- scalable/format-justify-fill.svg
- scalable/format-justify-left.svg
- scalable/format-justify-right.svg
- scalable/format-text-bold.svg
- scalable/format-text-italic.svg
- scalable/format-text-underline.svg
-)
-
-qt_internal_add_resource(ExampleIconsPrivate "example_icons"
- PREFIX
- "/qt-project.org/icons/example_icons"
- FILES
- ${icons_resource_files}
-)
-
diff --git a/src/assets/icons/README b/src/assets/icons/README
deleted file mode 100644
index 26d94e9ff13..00000000000
--- a/src/assets/icons/README
+++ /dev/null
@@ -1,29 +0,0 @@
-Copyright (C) 2023 The Qt Company Ltd.
-SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
-
-Setting up a project for using Example icon library
-
-1. Add ExampleIconsPrivate component to your project CMakeList.txt file
- ...
- find_package(Qt6
- REQUIRED COMPONENTS Core Gui Widgets ExampleIconsPrivate
- )
-
- target_link_libraries(imageviewer PRIVATE
- Qt6::Core
- Qt6::Gui
- Qt6::Widgets
- Qt6::ExampleIconsPrivate
- )
- ...
-
-2. Load the theme
- ...
- QIcon::setThemeSearchPaths(QIcon::themeSearchPaths() << u":/qt-project.org/icons"_s);
- QIcon::setFallbackThemeName(u"example_icons"_s);
- ...
-
-3. Use the icons
- ...
- const QIcon openIcon = QIcon::fromTheme("document-open");
- ...
diff --git a/src/assets/icons/index.theme b/src/assets/icons/index.theme
deleted file mode 100644
index e389719e01c..00000000000
--- a/src/assets/icons/index.theme
+++ /dev/null
@@ -1,46 +0,0 @@
-[Icon Theme]
-Name=example_icons
-
-Directories=16x16,16x16@2,32x32,32x32@2,128x128,128x128@2,256x256,256x256@2,scalable
-
-[16x16]
-Size=16
-Type=Fixed
-
-[16x16@2]
-Size=16
-Scale=2
-Type=Fixed
-
-[32x32]
-Size=32
-Type=Fixed
-
-[32x32@2]
-Size=32
-Scale=2
-Type=Fixed
-
-[128x128]
-Size=128
-Type=Fixed
-
-[128x128@2]
-Size=128
-Scale=2
-Type=Fixed
-
-[256x256]
-Size=256
-Type=Fixed
-
-[256x256@2]
-Size=256
-Scale=2
-Type=Fixed
-
-[scalable]
-Size=512
-Type=Scalable
-MinSize=16
-MaxSize=512
diff --git a/src/assets/icons/scalable/document-new.svg b/src/assets/icons/scalable/document-new.svg
deleted file mode 100644
index b926a7b0e11..00000000000
--- a/src/assets/icons/scalable/document-new.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_New" d="m15,13c0,.28-.22.5-.5.5h-2v2c0,.28-.22.5-.5.5s-.5-.22-.5-.5v-2h-2c-.28,0-.5-.22-.5-.5s.22-.5.5-.5h2v-2c0-.28.22-.5.5-.5s.5.22.5.5v2h2c.28,0,.5.22.5.5Zm-12,2h5v1H3c-1.1,0-2-.9-2-2V2C1,.9,1.9,0,3,0h7c1.14,1.14,2.93,2.93,4,4v5h-1v-4h-2c-1.1,0-2-.9-2-2V1H3c-.55,0-1,.45-1,1v12c0,.55.45,1,1,1ZM10,1.41v1.59c0,.55.45,1,1,1h1.59l-.82-.82-1.76-1.76Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/document-open.svg b/src/assets/icons/scalable/document-open.svg
deleted file mode 100644
index 778c1b7c6e9..00000000000
--- a/src/assets/icons/scalable/document-open.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Open" d="m14.5,5h-1.5v-1c0-1.1-.9-2-2-2h-5L4,0h-2C.9,0,0,.9,0,2v12c0,1.1.9,2,2,2h9s0,0,0,0c.12,0,.25-.01.36-.03.98-.16,1.94-.94,2.24-1.87l2.29-7.19c.33-1.05-.29-1.91-1.39-1.91ZM1,14V2c0-.55.45-1,1-1h1.59l1.71,1.71c.19.19.44.29.71.29h5c.55,0,1,.45,1,1v1h-5.5c-1.1,0-2.27.86-2.61,1.91l-2.29,7.19c-.09.28-.11.54-.07.78-.32-.17-.54-.49-.54-.87Zm13.94-7.4l-2.29,7.19c-.2.63-.99,1.21-1.65,1.21H3c-.2,0-.36-.05-.43-.15-.07-.1-.07-.26-.01-.45l2.29-7.19c.2-.63.99-1.21,1.65-1.21h8c.2,0,.36.05.43.15.07.1.07.26.01.45Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/document-print.svg b/src/assets/icons/scalable/document-print.svg
deleted file mode 100644
index fb8436af81a..00000000000
--- a/src/assets/icons/scalable/document-print.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Print" d="m14,4h-2v-2c0-1.1-.9-2-2-2h-4c-1.1,0-2,.9-2,2v2h-2c-1.1,0-2,.9-2,2v4c0,1.1.9,2,2,2h2v2c0,1.1.9,2,2,2h4c1.1,0,2-.9,2-2v-2h2c1.1,0,2-.9,2-2v-4c0-1.1-.9-2-2-2ZM5,2c0-.55.45-1,1-1h4c.55,0,1,.45,1,1v2h-6v-2Zm5,13h-4c-.55,0-1-.45-1-1v-5h6v5c0,.55-.45,1-1,1Zm5-5c0,.55-.45,1-1,1h-2v-2h.5c.28,0,.5-.22.5-.5s-.22-.5-.5-.5h-.5s-8,0-8,0h0s-.5,0-.5,0c-.28,0-.5.22-.5.5s.22.5.5.5h.5v2h-2c-.55,0-1-.45-1-1v-4c0-.55.45-1,1-1h12c.55,0,1,.45,1,1v4Zm-5,1.5c0,.28-.22.5-.5.5h-3c-.28,0-.5-.22-.5-.5s.22-.5.5-.5h3c.28,0,.5.22.5.5Zm0,2c0,.28-.22.5-.5.5h-3c-.28,0-.5-.22-.5-.5s.22-.5.5-.5h3c.28,0,.5.22.5.5Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/document-save.svg b/src/assets/icons/scalable/document-save.svg
deleted file mode 100644
index 03675f4dab0..00000000000
--- a/src/assets/icons/scalable/document-save.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Save" d="m16,11h0V2.29c0-1.26-1.02-2.29-2.29-2.29H2.29C1.02,0,0,1.02,0,2.29v8.71h0v1h0v1.71c0,1.26,1.02,2.29,2.29,2.29h11.43c1.26,0,2.29-1.02,2.29-2.29v-1.71h0v-1ZM5.71,1h5.29v4.5c0,.28-.22.5-.5.5h-5c-.28,0-.5-.22-.5-.5V1h.71ZM1,2.29c0-.71.58-1.29,1.29-1.29h1.71v4.5c0,.83.67,1.5,1.5,1.5h5c.83,0,1.5-.67,1.5-1.5V1h1.71c.71,0,1.29.58,1.29,1.29v8.71H1V2.29Zm14,11.43c0,.71-.58,1.29-1.29,1.29H2.29c-.71,0-1.29-.58-1.29-1.29v-1.71h14v1.71Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/edit-copy.svg b/src/assets/icons/scalable/edit-copy.svg
deleted file mode 100644
index db53ff11624..00000000000
--- a/src/assets/icons/scalable/edit-copy.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Copy" d="m12,0h-5c-1.1,0-2,.9-2,2h1c0-.55.45-1,1-1h4v2c0,1.1.9,2,2,2h2v6c0,.55-.45,1-1,1h-2v1h2c1.1,0,2-.9,2-2v-7c-1.07-1.07-2.86-2.86-4-4Zm1,4c-.55,0-1-.45-1-1v-1.59l1.29,1.29,1.29,1.29h-1.59Zm-6-1H2c-1.1,0-2,.9-2,2v9c0,1.1.9,2,2,2h7c1.1,0,2-.9,2-2v-7c-1.07-1.07-2.86-2.86-4-4Zm3,6v5c0,.55-.45,1-1,1H2c-.55,0-1-.45-1-1V5c0-.55.45-1,1-1h4v2c0,1.1.9,2,2,2h2v1Zm-2-2c-.55,0-1-.45-1-1v-1.59l1.29,1.29,1.29,1.29h-1.59Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/edit-cut.svg b/src/assets/icons/scalable/edit-cut.svg
deleted file mode 100644
index 7f75d0b829d..00000000000
--- a/src/assets/icons/scalable/edit-cut.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Cut" d="m15.22,12.05l-7.39-3.55,7.39-3.55c.25-.12.35-.42.23-.67-.12-.25-.42-.35-.67-.23l-8.12,3.9-2.48-1.19c1.07-.46,1.81-1.52,1.81-2.75,0-1.66-1.34-3-3-3S0,2.34,0,4c0,1.28.81,2.36,1.93,2.8.1.05.22.1.35.15l3.23,1.55-3.23,1.55c-.1.05-.18.09-.26.13-1.18.41-2.02,1.51-2.02,2.82,0,1.66,1.34,3,3,3s3-1.34,3-3c0-1.24-.75-2.29-1.81-2.75l2.48-1.19,8.12,3.9c.07.03.14.05.22.05.19,0,.37-.1.45-.28.12-.25.01-.55-.23-.67ZM3,2c1.1,0,2,.9,2,2s-.9,2-2,2-2-.9-2-2,.9-2,2-2Zm2,11c0,1.1-.9,2-2,2s-2-.9-2-2,.9-2,2-2,2,.9,2,2Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/edit-delete.svg b/src/assets/icons/scalable/edit-delete.svg
deleted file mode 100644
index 15d1a9c7fd6..00000000000
--- a/src/assets/icons/scalable/edit-delete.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Delete" d="m8,0C3.58,0,0,3.58,0,8s3.58,8,8,8,8-3.58,8-8S12.42,0,8,0Zm0,15c-3.86,0-7-3.14-7-7S4.14,1,8,1s7,3.14,7,7-3.14,7-7,7Zm2.83-9.12l-2.12,2.12,2.12,2.12c.2.2.2.51,0,.71-.1.1-.23.15-.35.15s-.26-.05-.35-.15l-2.12-2.12-2.12,2.12c-.1.1-.23.15-.35.15s-.26-.05-.35-.15c-.2-.2-.2-.51,0-.71l2.12-2.12-2.12-2.12c-.2-.2-.2-.51,0-.71s.51-.2.71,0l2.12,2.12,2.12-2.12c.2-.2.51-.2.71,0s.2.51,0,.71Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/edit-paste.svg b/src/assets/icons/scalable/edit-paste.svg
deleted file mode 100644
index 57e94d917d2..00000000000
--- a/src/assets/icons/scalable/edit-paste.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Paste" d="m14.09,6.09c-.71-.74-1.44-1.5-2.09-2.09h-3.78c-1.23,0-2.22.9-2.22,2v8c0,1.1.99,2,2.22,2h5.56c1.23,0,2.22-.9,2.22-2v-6c-.52-.52-1.21-1.21-1.91-1.91Zm-2.09-.68l1.38,1.38c.41.43.8.83,1.18,1.21h-1.56c-.55,0-1-.45-1-1v-1.59Zm3,5.59v3c0,.55-.55,1-1.22,1h-5.56c-.67,0-1.22-.45-1.22-1V6c0-.55.55-1,1.22-1h2.78v2c0,1.1.9,2,2,2h2v2Zm-6.5,0h5c.28,0,.5.22.5.5s-.22.5-.5.5h-5c-.28,0-.5-.22-.5-.5s.22-.5.5-.5ZM5.5,3h1c.83,0,1.5-.67,1.5-1.5v-.5h2c.55,0,1,.45,1,1v1h1v-1C12,.9,11.1,0,10,0h-2s-4,0-4,0h0s-2,0-2,0C.9,0,0,.9,0,2v10c0,1.1.9,2,2,2h3v-1h-3c-.55,0-1-.45-1-1V2c0-.55.45-1,1-1h2v.5c0,.83.67,1.5,1.5,1.5Zm1.5-1.5c0,.28-.22.5-.5.5h-1c-.28,0-.5-.22-.5-.5v-.5h2v.5Zm7,12c0,.28-.22.5-.5.5h-5c-.28,0-.5-.22-.5-.5s.22-.5.5-.5h5c.28,0,.5.22.5.5Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/edit-redo.svg b/src/assets/icons/scalable/edit-redo.svg
deleted file mode 100644
index 92d60e1dd8c..00000000000
--- a/src/assets/icons/scalable/edit-redo.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Redo" d="m15.85,4.68l-3.54-3.54c-.2-.2-.51-.2-.71,0s-.2.51,0,.71l2.68,2.68H2.5c-1.38,0-2.5,1.12-2.5,2.5v4c0,1.38,1.12,2.5,2.5,2.5h7c.28,0,.5-.22.5-.5s-.22-.5-.5-.5H2.5c-.83,0-1.5-.67-1.5-1.5v-4c0-.83.67-1.5,1.5-1.5h11.79l-2.68,2.68c-.2.2-.2.51,0,.71.1.1.23.15.35.15s.26-.05.35-.15l3.54-3.54c.2-.2.2-.51,0-.71Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/edit-undo.svg b/src/assets/icons/scalable/edit-undo.svg
deleted file mode 100644
index 91731bb86fa..00000000000
--- a/src/assets/icons/scalable/edit-undo.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Undo" d="m13.5,4.54H1.71l2.68-2.68c.2-.2.2-.51,0-.71s-.51-.2-.71,0L.15,4.68c-.2.2-.2.51,0,.71l3.54,3.54c.1.1.23.15.35.15s.26-.05.35-.15c.2-.2.2-.51,0-.71l-2.68-2.68h11.79c.83,0,1.5.67,1.5,1.5v4c0,.83-.67,1.5-1.5,1.5h-7c-.28,0-.5.22-.5.5s.22.5.5.5h7c1.38,0,2.5-1.12,2.5-2.5v-4c0-1.38-1.12-2.5-2.5-2.5Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/format-justify-center.svg b/src/assets/icons/scalable/format-justify-center.svg
deleted file mode 100644
index 9822c95f2fa..00000000000
--- a/src/assets/icons/scalable/format-justify-center.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_alignCenter" d="m15.5,8H.5c-.28,0-.5-.22-.5-.5h0c0-.28.22-.5.5-.5h15c.28,0,.5.22.5.5h0c0,.28-.22.5-.5.5Zm-2,3.5h0c0-.28-.22-.5-.5-.5H3c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Zm2.5,4h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5Zm-2.5-12h0c0-.28-.22-.5-.5-.5H3c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/format-justify-fill.svg b/src/assets/icons/scalable/format-justify-fill.svg
deleted file mode 100644
index 2fa7ddfa40d..00000000000
--- a/src/assets/icons/scalable/format-justify-fill.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_alignJustify" d="m15.5,8H.5c-.28,0-.5-.22-.5-.5h0c0-.28.22-.5.5-.5h15c.28,0,.5.22.5.5h0c0,.28-.22.5-.5.5Zm.5,3.5h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5Zm0,4h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5Zm0-12h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/format-justify-left.svg b/src/assets/icons/scalable/format-justify-left.svg
deleted file mode 100644
index 99d666428d9..00000000000
--- a/src/assets/icons/scalable/format-justify-left.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_alignLeft" d="m15.5,8H.5c-.28,0-.5-.22-.5-.5h0c0-.28.22-.5.5-.5h15c.28,0,.5.22.5.5h0c0,.28-.22.5-.5.5Zm-4.5,3.5h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Zm5,4h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5ZM11,3.5h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/format-justify-right.svg b/src/assets/icons/scalable/format-justify-right.svg
deleted file mode 100644
index 7041f5e3f88..00000000000
--- a/src/assets/icons/scalable/format-justify-right.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_alignRight" d="m15.5,8H.5c-.28,0-.5-.22-.5-.5h0c0-.28.22-.5.5-.5h15c.28,0,.5.22.5.5h0c0,.28-.22.5-.5.5Zm.5,3.5h0c0-.28-.22-.5-.5-.5H5.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Zm0,4h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5Zm0-12h0c0-.28-.22-.5-.5-.5H5.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/format-text-bold.svg b/src/assets/icons/scalable/format-text-bold.svg
deleted file mode 100644
index c0f43e0a692..00000000000
--- a/src/assets/icons/scalable/format-text-bold.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_Bold" d="m12.06,7.75c.65-.36,1.13-.81,1.44-1.35.3-.55.46-1.29.46-2.24,0-1.45-.4-2.5-1.21-3.16-.81-.66-2.03-.99-3.67-.99H3v16h6.26c3.39,0,5.09-1.51,5.09-4.53,0-1.88-.76-3.12-2.29-3.71ZM5.59,2.24h3.34c1.59,0,2.38.74,2.38,2.22,0,1.57-.76,2.36-2.29,2.36h-3.43V2.24Zm5.45,10.98c-.43.36-1.07.54-1.93.54h-3.53v-4.74h3.48c.75,0,1.37.17,1.87.53.5.35.75.96.75,1.83s-.21,1.49-.64,1.85Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/format-text-italic.svg b/src/assets/icons/scalable/format-text-italic.svg
deleted file mode 100644
index 43df7ca54dc..00000000000
--- a/src/assets/icons/scalable/format-text-italic.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><polygon id="iconTextEditor_Italic" points="6.63 0 6.18 2.01 8.18 2.01 5.45 13.99 3.45 13.99 3 16 9.56 16 10.01 13.99 8.01 13.99 10.74 2.01 12.74 2.01 13.19 0 6.63 0"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/format-text-underline.svg b/src/assets/icons/scalable/format-text-underline.svg
deleted file mode 100644
index 62778fc579e..00000000000
--- a/src/assets/icons/scalable/format-text-underline.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_Underline" d="m3.38,11.88c-.92-.75-1.38-1.94-1.38-3.57V0h2.44v8.35c0,1.79,1.02,2.69,3.06,2.69s3.06-.9,3.06-2.69V0h2.44v8.31c0,1.63-.46,2.82-1.39,3.57-.92.75-2.3,1.12-4.13,1.12s-3.2-.37-4.11-1.12Zm10.12,3.12H1.5c-.28,0-.5.22-.5.5s.22.5.5.5h12c.28,0,.5-.22.5-.5s-.22-.5-.5-.5Z"/></svg> \ No newline at end of file
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index 4d83bbf794e..249b9b8c1ee 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -16,7 +16,11 @@ qt_internal_extend_sbom(WrapZLIB::WrapZLIB
if(ANDROID)
set(corelib_extra_cmake_files
- "${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidMacros.cmake")
+ "${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidMacros.cmake"
+ "${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidDynamicFeatureHelpers.cmake"
+ "${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidGradleHelpers.cmake"
+ "${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidPermissionHelpers.cmake"
+ )
endif()
if(WASM)
set(corelib_extra_cmake_files
diff --git a/src/corelib/Qt6AndroidDynamicFeatureHelpers.cmake b/src/corelib/Qt6AndroidDynamicFeatureHelpers.cmake
new file mode 100644
index 00000000000..e8a81bde1d7
--- /dev/null
+++ b/src/corelib/Qt6AndroidDynamicFeatureHelpers.cmake
@@ -0,0 +1,152 @@
+# Copyright (C) 2025 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+# Collects the dynamic features for the target
+
+function(_qt_internal_android_add_dynamic_feature_deployment target)
+ get_target_property(dynamic_features ${target} _qt_android_dynamic_features)
+ if(NOT dynamic_features)
+ return()
+ endif()
+
+ foreach(dynamic_feature IN LISTS dynamic_features)
+ get_target_property(is_imported ${dynamic_feature} IMPORTED)
+ if(is_imported)
+ message(FATAL_ERROR "Imported target ${dynamic_feature} can not be a"
+ " 'DYNAMIC_FEATURE'.")
+ endif()
+
+ get_target_property(type ${dynamic_feature} TYPE)
+ if(NOT type STREQUAL "SHARED_LIBRARY")
+ message(FATAL_ERROR "Cannot make ${dynamic_feature} 'DYNAMIC_FEATURE'."
+ " The target must be the 'SHARED_LIBRARY'.")
+ endif()
+
+ get_target_property(android_type ${dynamic_feature} _qt_android_target_type)
+ if(NOT android_type STREQUAL "" AND NOT android_type MATCHES "-NOTFOUND$"
+ AND NOT android_type STREQUAL "DYNAMIC_FEATURE")
+ message(FATAL_ERROR "Cannot make ${dynamic_feature} 'DYNAMIC_FEATURE',"
+ " it's already '${android_type}'. The target must be the plain 'SHARED_LIBRARY'.")
+ endif()
+
+ # Mark the target as DYNAMIC_FEATURE, since we used it in this role once.
+ set_target_properties(${dynamic_feature} PROPERTIES _qt_android_target_type DYNAMIC_FEATURE)
+ _qt_internal_set_android_dynamic_feature_gradle_defaults(${dynamic_feature})
+
+ _qt_internal_android_get_dynamic_feature_deployment_dir(dynamic_feature_deployment_dir
+ ${target} ${dynamic_feature})
+ _qt_internal_android_generate_target_build_gradle(${dynamic_feature}
+ DEPLOYMENT_DIR "${dynamic_feature_deployment_dir}")
+ _qt_internal_android_generate_dynamic_feature_manifest(${target} ${dynamic_feature})
+ _qt_internal_android_copy_dynamic_feature(${target} ${dynamic_feature})
+ endforeach()
+endfunction()
+
+# Sets the default values of the gradle properties for the Android dynamic feature target.
+function(_qt_internal_set_android_dynamic_feature_gradle_defaults target)
+ _qt_internal_android_java_dir(android_java_dir)
+
+ # TODO: make androidx.core:core versionc configurable.
+ # Currently, it is hardcoded to 1.16.0.
+ set(implementation_dependencies "project(':app')" "'androidx.core:core:1.16.0'")
+
+ set_target_properties(${target} PROPERTIES
+ _qt_android_gradle_java_source_dirs "src;java"
+ _qt_android_gradle_aidl_source_dirs "src;aidl"
+ _qt_android_gradle_res_source_dirs "res"
+ _qt_android_gradle_resources_source_dirs "resources"
+ _qt_android_gradle_renderscript_source_dirs "src"
+ _qt_android_gradle_assets_source_dirs "assets"
+ _qt_android_gradle_jniLibs_source_dirs "libs"
+ _qt_android_manifest "AndroidManifest.xml"
+ _qt_android_gradle_implementation_dependencies "${implementation_dependencies}"
+ )
+endfunction()
+
+# Copies the dynamic feature library to the respective gradle build tree.
+function(_qt_internal_android_copy_dynamic_feature target dynamic_feature)
+ if(NOT TARGET ${dynamic_feature})
+ message(FATAL_ERROR "${dynamic_feature} is not a target.")
+ endif()
+
+ _qt_internal_android_get_dynamic_feature_deployment_dir(dynamic_feature_deployment_dir
+ ${target} ${dynamic_feature})
+
+ set(dynamic_feature_libs_dir "${dynamic_feature_deployment_dir}/libs/${CMAKE_ANDROID_ARCH_ABI}")
+ get_target_property(output_name ${dynamic_feature} OUTPUT_NAME)
+ if(NOT output_name)
+ get_target_property(suffix "${dynamic_feature}" SUFFIX)
+ set(output_name "lib${dynamic_feature}${suffix}")
+ endif()
+ set(output_file_path "${dynamic_feature_libs_dir}/${output_name}")
+ _qt_internal_copy_file_if_different_command(copy_command
+ "$<TARGET_FILE:${dynamic_feature}>"
+ "${output_file_path}"
+ )
+ add_custom_command(OUTPUT ${output_file_path}
+ COMMAND ${copy_command}
+ DEPENDS ${dynamic_feature}
+ COMMENT "Copying ${dynamic_feature} dynamic feature to ${target} deployment directory"
+ )
+ add_custom_target(${target}_deploy_dynamic_features DEPENDS "${output_file_path}")
+endfunction()
+
+# Generates the feature name strings and copy them to the respective deployment directory.
+function(_qt_internal_android_generate_dynamic_feature_names target)
+ get_target_property(dynamic_features ${target} _qt_android_dynamic_features)
+ if(NOT dynamic_features)
+ return()
+ endif()
+
+ # Collect the titles
+ string(JOIN "\n" content
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<resources>"
+ )
+ foreach(feature IN LISTS dynamic_features)
+ string(APPEND content "\n <string name=\"${feature}_title\">${feature}</string>")
+ endforeach()
+ string(APPEND content "\n</resources>")
+
+ _qt_internal_android_get_target_deployment_dir(deployment_dir ${target})
+ # TODO: androiddeployqt wipes the android build directory. Generate feature_names.xml target
+ # build dir and copy after androiddeployqt run. We should skip feature_names.xml copying when
+ # androiddeployqt is not involved into the deployment process anymore.
+ #
+ # set(output_file "${deployment_dir}/res/values/feature_names.xml")
+ set(output_file "$<TARGET_PROPERTY:${target},BINARY_DIR>/res/values/feature_names.xml")
+ _qt_internal_configure_file(GENERATE OUTPUT "${output_file}" CONTENT "${content}")
+ set(output_file_in_deployment_dir "${deployment_dir}/res/values/feature_names.xml")
+ add_custom_command(OUTPUT "${output_file_in_deployment_dir}"
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ "${output_file}"
+ "${output_file_in_deployment_dir}"
+ DEPENDS "${output_file}" ${target}_android_deploy_aux
+ VERBATIM
+ )
+ add_custom_target(${target}_copy_feature_names
+ DEPENDS
+ "${output_file_in_deployment_dir}"
+ )
+endfunction()
+
+# Returns the dynamic feature deployment directory in the target build tree.
+function(_qt_internal_android_get_dynamic_feature_deployment_dir out_var target dynamic_feature)
+ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
+ set(${out_var} "${android_build_dir}/${dynamic_feature}" PARENT_SCOPE)
+endfunction()
+
+# Generates the AndroidManifest.xml file for the dynamic_feature.
+function(_qt_internal_android_generate_dynamic_feature_manifest target dynamic_feature)
+ set(android_manifest_filename AndroidManifest.xml)
+ _qt_internal_android_get_dynamic_feature_deployment_dir(dynamic_feature_deployment_dir ${target}
+ ${dynamic_feature})
+
+ _qt_internal_android_get_template_path(template_file ${target}
+ "dynamic_feature/${android_manifest_filename}")
+
+ set(APP_TARGET "${target}")
+ set(TITLE_VAR "@string/${dynamic_feature}_title")
+
+ set(output_file "${dynamic_feature_deployment_dir}/AndroidManifest.xml")
+ _qt_internal_configure_file(CONFIGURE OUTPUT "${output_file}" INPUT "${template_file}")
+endfunction()
diff --git a/src/corelib/Qt6AndroidGradleHelpers.cmake b/src/corelib/Qt6AndroidGradleHelpers.cmake
new file mode 100644
index 00000000000..09184c93b69
--- /dev/null
+++ b/src/corelib/Qt6AndroidGradleHelpers.cmake
@@ -0,0 +1,631 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Returns the path to the template file from either user defined template directory, or
+# Qt default template directory.
+function(_qt_internal_android_get_template_path out_var target template_name)
+ if(template_name STREQUAL "")
+ message(FATAL_ERROR "Template name is empty."
+ " This is the Qt issue, please report a bug at https://bugreports.qt.io.")
+ endif()
+
+ _qt_internal_android_template_dir(template_directory)
+ get_filename_component(template_directory "${template_directory}" ABSOLUTE)
+
+ # The paths are ordered according to their priority, from highest to lowest.
+ set(possible_paths
+ "${template_directory}/${template_name}.in"
+ )
+
+ get_target_property(android_target_type ${target} _qt_android_target_type)
+ if(android_target_type STREQUAL "APPLICATION")
+ _qt_internal_android_get_package_source_dir(user_template_directory ${target})
+ get_filename_component(user_template_directory "${user_template_directory}" ABSOLUTE)
+
+ # Add user template with the higher priority
+ list(PREPEND possible_paths "${user_template_directory}/${template_name}.in")
+ endif()
+
+ set(template_path "")
+ foreach(possible_path IN LISTS possible_paths)
+ if(EXISTS "${possible_path}")
+ set(template_path "${possible_path}")
+ break()
+ endif()
+ endforeach()
+
+ if(template_path STREQUAL "")
+ message(FATAL_ERROR "'${template_name}' is not found."
+ " This is the Qt issue, please report a bug at https://bugreports.qt.io.")
+ endif()
+
+ set(${out_var} "${template_path}" PARENT_SCOPE)
+endfunction()
+
+# Generates the settings.gradle file for the target. Writes the result to the target android build
+# directory.
+function(_qt_internal_android_generate_bundle_settings_gradle target)
+ set(settings_gradle_filename "settings.gradle")
+ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
+ set(settings_gradle_file "${android_build_dir}/${settings_gradle_filename}")
+
+ # Skip generating the file if it's already provided by user.
+ get_target_property(deployment_files ${target} _qt_android_deployment_files)
+ if("${settings_gradle_file}" IN_LIST deployment_files)
+ return()
+ endif()
+
+ _qt_internal_android_get_template_path(template_file ${target} "${settings_gradle_filename}")
+
+ set(android_app_name "$<TARGET_PROPERTY:${target},QT_ANDROID_APP_NAME>")
+ string(JOIN "" ROOT_PROJECT_NAME
+ "$<IF:$<BOOL:${android_app_name}>,"
+ "${android_app_name},"
+ "${target}"
+ ">"
+ )
+
+ set(target_dynamic_features "$<TARGET_PROPERTY:${target},_qt_android_dynamic_features>")
+ set(include_prefix "include(\":")
+ set(include_suffix "\")")
+ set(include_glue "${include_suffix}\n${include_prefix}")
+ string(JOIN "" SUBPROJECTS
+ "$<$<BOOL:${target_dynamic_features}>:"
+ "${include_prefix}"
+ "$<JOIN:${target_dynamic_features},${include_glue}>"
+ "${include_suffix}"
+ ">"
+ )
+
+ _qt_internal_configure_file(GENERATE OUTPUT ${settings_gradle_file}
+ INPUT "${template_file}")
+ set_property(TARGET ${target} APPEND PROPERTY _qt_android_deployment_files
+ "${settings_gradle_file}")
+endfunction()
+
+# Generates the source sets for the target.
+function(_qt_internal_android_get_gradle_source_sets out_var target)
+ set(known_types java aidl res resources renderscript assets jniLibs)
+ set(source_set "")
+ set(indent " ")
+ foreach(type IN LISTS known_types)
+ set(source_dirs
+ "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},_qt_android_gradle_${type}_source_dirs>>")
+ string(JOIN "" source_set
+ "${source_set}"
+ "$<$<BOOL:${source_dirs}>:"
+ "${indent}${type}.srcDirs = ['$<JOIN:${source_dirs},'$<COMMA> '>']\n"
+ ">"
+ )
+ endforeach()
+
+ set(manifest
+ "$<TARGET_PROPERTY:${target},_qt_android_manifest>")
+ string(JOIN "" source_set
+ "${source_set}"
+ "$<$<BOOL:${manifest}>:"
+ "${indent}manifest.srcFile '${manifest}'\n"
+ ">"
+ )
+ set(${out_var} "${source_set}" PARENT_SCOPE)
+endfunction()
+
+# Generates the gradle dependency list for the target.
+function(_qt_internal_android_get_gradle_dependencies out_var target)
+ # Use dependencies from file tree by default
+ set(known_dependencies
+ "implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])")
+ foreach(dep_type implementation api)
+ string(JOIN "\n " dep_prefix
+ "\n //noinspection GradleDependency"
+ "${dep_type} "
+ )
+ set(dep_postfix "")
+ set(dep_property "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},_qt_android_gradle_${dep_type}_dependencies>>")
+ string(JOIN "" known_dependencies
+ "${known_dependencies}"
+ "$<$<BOOL:${dep_property}>:"
+ "${dep_prefix}$<JOIN:${dep_property},${dep_postfix}${dep_prefix}>${dep_postfix}"
+ ">"
+ )
+ endforeach()
+ set(${out_var} "${known_dependencies}" PARENT_SCOPE)
+endfunction()
+
+# Sets the default values of the gradle properties for the Android executable target.
+function(_qt_internal_set_android_application_gradle_defaults target)
+ _qt_internal_android_java_dir(android_java_dir)
+
+ set(target_dynamic_features "$<TARGET_PROPERTY:${target},_qt_android_dynamic_features>")
+ string(JOIN "" implementation_dependencies
+ "$<$<BOOL:${target_dynamic_features}>:'com.google.android.play:feature-delivery:2.1.0'>"
+ )
+ # TODO: make androidx.core:core version configurable.
+ # Currently, it is hardcoded to 1.16.0.
+ list(APPEND implementation_dependencies "'androidx.core:core:1.16.0'")
+
+ set_target_properties(${target} PROPERTIES
+ _qt_android_gradle_java_source_dirs "${android_java_dir}/src;src;java"
+ _qt_android_gradle_aidl_source_dirs "${android_java_dir}/src;src;aidl"
+ _qt_android_gradle_res_source_dirs "${android_java_dir}/res;res"
+ _qt_android_gradle_resources_source_dirs "resources"
+ _qt_android_gradle_renderscript_source_dirs "src"
+ _qt_android_gradle_assets_source_dirs "assets"
+ _qt_android_gradle_jniLibs_source_dirs "libs"
+ _qt_android_manifest "AndroidManifest.xml"
+ _qt_android_gradle_implementation_dependencies "${implementation_dependencies}"
+ )
+endfunction()
+
+# Generates the build.gradle file for the target. Writes the result to the target app deployment
+# directory.
+function(_qt_internal_android_generate_target_build_gradle target)
+ cmake_parse_arguments(PARSE_ARGV 1 arg "" "DEPLOYMENT_DIR" "")
+
+ if(NOT arg_DEPLOYMENT_DIR)
+ message(FATAL_ERROR "DEPLOYMENT_DIR is not specified.")
+ endif()
+
+ set(build_gradle_filename "build.gradle")
+ set(out_file "${arg_DEPLOYMENT_DIR}/${build_gradle_filename}")
+
+ # Skip generating the file if it's already provided by user.
+ get_target_property(deployment_files ${target} _qt_android_deployment_files)
+ if("${out_file}" IN_LIST deployment_files)
+ return()
+ endif()
+
+ # TODO: The current build.gradle.in templates hardcodes couple values that needs to be
+ # configurable in the future. For example the buildscript dependencies, or the use of
+ # androidx.core:core:1.13.1 and the dependency for all user applications.
+
+ _qt_internal_android_get_gradle_property(PACKAGE_NAME ${target}
+ QT_ANDROID_PACKAGE_NAME "org.qtproject.example.$<MAKE_C_IDENTIFIER:${target}>")
+
+ _qt_internal_android_get_target_sdk_build_tools_revision(ANDROID_BUILD_TOOLS_VERSION
+ ${target})
+
+ _qt_internal_detect_latest_android_platform(ANDROID_COMPILE_SDK_VERSION)
+ if(NOT ANDROID_COMPILE_SDK_VERSION)
+ message(FATAL_ERROR "Unable to detect the android platform in ${ANDROID_SDK_ROOT}. "
+ "Please check your Android SDK installation.")
+ endif()
+
+ _qt_internal_android_get_gradle_source_sets(SOURCE_SETS ${target})
+ _qt_internal_android_get_gradle_dependencies(GRADLE_DEPENDENCIES ${target})
+
+ _qt_internal_android_get_gradle_property(min_sdk_version ${target}
+ QT_ANDROID_MIN_SDK_VERSION "28")
+
+ _qt_internal_android_get_gradle_property(target_sdk_version ${target}
+ QT_ANDROID_TARGET_SDK_VERSION "34")
+
+ set(target_abis "$<TARGET_PROPERTY:${target},_qt_android_abis>")
+ set(target_abi_list "$<JOIN:${target_abis};${CMAKE_ANDROID_ARCH_ABI},'$<COMMA> '>")
+
+ string(JOIN "\n " DEFAULT_CONFIG_VALUES
+ "resConfig 'en'"
+ "minSdkVersion ${min_sdk_version}"
+ "targetSdkVersion ${target_sdk_version}"
+ "ndk.abiFilters = ['${target_abi_list}']"
+ )
+
+ set(target_dynamic_features "$<TARGET_PROPERTY:${target},_qt_android_dynamic_features>")
+ set(include_prefix "\":")
+ set(include_suffix "\"")
+ set(include_glue "${include_suffix}$<COMMA>${include_prefix}")
+ string(APPEND ANDROID_DEPLOYMENT_EXTRAS
+ "$<$<BOOL:${target_dynamic_features}>:dynamicFeatures = ["
+ "${include_prefix}"
+ "$<JOIN:${target_dynamic_features},${include_glue}>"
+ "${include_suffix}]"
+ ">"
+ )
+
+ get_target_property(android_target_type ${target} _qt_android_target_type)
+ if(android_target_type STREQUAL "APPLICATION")
+ set(GRADLE_PLUGIN_TYPE "com.android.application")
+ set(template_subdir "app")
+ elseif(android_target_type STREQUAL "DYNAMIC_FEATURE")
+ set(GRADLE_PLUGIN_TYPE "com.android.dynamic-feature")
+ set(template_subdir "dynamic_feature")
+ else()
+ message(FATAL_ERROR "Unsupported target type for android bundle deployment ${target}")
+ endif()
+
+ _qt_internal_android_get_template_path(template_file ${target}
+ "${template_subdir}/${build_gradle_filename}")
+ _qt_internal_configure_file(GENERATE
+ OUTPUT "${out_file}"
+ INPUT "${template_file}"
+ )
+ set_property(TARGET ${target} APPEND PROPERTY _qt_android_deployment_files "${out_file}")
+endfunction()
+
+# Prepares the artifacts for the gradle build of the target.
+function(_qt_internal_android_prepare_gradle_build target)
+ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
+ _qt_internal_android_get_target_deployment_dir(deployment_dir ${target})
+
+ _qt_internal_android_copy_gradle_files(${target} "${android_build_dir}")
+ _qt_internal_android_copy_target_package_sources(${target})
+
+ _qt_internal_android_generate_bundle_gradle_properties(${target})
+ _qt_internal_android_generate_bundle_settings_gradle(${target})
+ _qt_internal_android_generate_bundle_local_properties(${target})
+ _qt_internal_android_generate_target_build_gradle(${target} DEPLOYMENT_DIR "${deployment_dir}")
+ _qt_internal_android_generate_target_gradle_properties(${target}
+ DEPLOYMENT_DIR "${deployment_dir}")
+ _qt_internal_android_generate_target_android_manifest(${target}
+ DEPLOYMENT_DIR "${deployment_dir}")
+
+
+ _qt_internal_android_add_gradle_build(${target} apk)
+ _qt_internal_android_add_gradle_build(${target} aab)
+
+ # Make global apk, aab, and aar targets depend on the respective targets.
+ _qt_internal_android_add_global_package_dependencies(${target})
+ _qt_internal_create_global_apk_all_target_if_needed()
+endfunction()
+
+# Adds the modern gradle build targets.
+# These targets use the settings.gradle based build directory structure.
+function(_qt_internal_android_add_gradle_build target type)
+ _qt_internal_android_get_deployment_type_option(android_deployment_type_option
+ "assembleRelease" "assembleDebug")
+
+ _qt_internal_android_gradlew_name(gradlew_file_name)
+ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
+ set(gradlew "${android_build_dir}/${gradlew_file_name}")
+
+ set(extra_args "")
+ if(type STREQUAL "aab")
+ set(extra_args "bundle")
+ endif()
+
+ set(package_file_path "${android_build_dir}/${target}.${type}")
+
+ _qt_internal_android_package_path(package_build_dir ${target} ${type})
+ _qt_internal_android_get_deployment_type_option(deployment_type_suffix
+ "release" "debug")
+ set(package_build_file_path
+ "${package_build_dir}/${deployment_type_suffix}/app-${deployment_type_suffix}.${type}")
+
+ set(extra_deps "")
+ if(TARGET ${target}_copy_feature_names)
+ list(APPEND extra_deps ${target}_copy_feature_names)
+ endif()
+
+ if(TARGET ${target}_deploy_dynamic_features)
+ list(APPEND extra_deps ${target}_deploy_dynamic_features)
+ endif()
+
+ set(gradle_scripts "$<TARGET_PROPERTY:${target},_qt_android_deployment_files>")
+ add_custom_command(OUTPUT "${package_file_path}"
+ BYPRODUCTS "${package_build_file_path}"
+ COMMAND
+ "${gradlew}" ${android_deployment_type_option} ${extra_args}
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_if_different
+ "${package_build_file_path}" "${package_file_path}"
+ DEPENDS
+ ${target}
+ ${gradle_scripts}
+ ${target}_copy_gradle_files
+ ${target}_android_deploy_aux
+ ${extra_deps}
+ WORKING_DIRECTORY
+ "${android_build_dir}"
+ VERBATIM
+ )
+
+ add_custom_target(${target}_make_${type} DEPENDS "${package_file_path}")
+endfunction()
+
+# Returns the path to the android executable package either apk or aab.
+function(_qt_internal_android_package_path out_var target type)
+ set(supported_package_types apk aab)
+ if(NOT type IN_LIST supported_package_types)
+ message(FATAL_ERROR "Invalid package type, supported types: ${supported_package_types}")
+ endif()
+
+ # aab packages are located in the bundle directory
+ if(type STREQUAL "aab")
+ set(type "bundle")
+ endif()
+
+ _qt_internal_android_get_target_deployment_dir(deployment_dir ${target})
+
+ set(${out_var} "${deployment_dir}/build/outputs/${type}" PARENT_SCOPE)
+endfunction()
+
+# Returns the path to the gradle build directory.
+function(_qt_internal_android_gradle_template_dir out_var)
+ if(PROJECT_NAME STREQUAL "QtBase" OR QT_SUPERBUILD)
+ set(${out_var} "${QtBase_SOURCE_DIR}/src/3rdparty/gradle" PARENT_SCOPE)
+ else()
+ set(${out_var} "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_DATA}/src/3rdparty/gradle" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Returns the path to the android java dir.
+function(_qt_internal_android_java_dir out_var)
+ if(PROJECT_NAME STREQUAL "QtBase" OR QT_SUPERBUILD)
+ set(${out_var} "${QtBase_SOURCE_DIR}/src/android/java" PARENT_SCOPE)
+ else()
+ set(${out_var} "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_DATA}/src/android/java" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Returns the platform-spefic name of the gradlew script.
+function(_qt_internal_android_gradlew_name out_var)
+ if(CMAKE_HOST_WIN32)
+ set(gradlew_file_name "gradlew.bat")
+ else()
+ set(gradlew_file_name "gradlew")
+ endif()
+
+ set(${out_var} "${gradlew_file_name}" PARENT_SCOPE)
+endfunction()
+
+# Return the path to the gradlew script.
+function(_qt_internal_android_gradlew_path out_var target)
+ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
+ set(${out_var} "${android_build_dir}/${gradlew_file_name}" PARENT_SCOPE)
+endfunction()
+
+# Returns the generator expression for the gradle_property value. Defaults to the default_value
+# argument.
+function(_qt_internal_android_get_gradle_property out_var target target_property default_value)
+ set(target_property_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},${target_property}>>")
+ string(JOIN "" result
+ "$<IF:$<BOOL:${target_property_genex}>,"
+ "${target_property_genex},"
+ "${default_value}"
+ ">"
+ )
+ set(${out_var} "${result}" PARENT_SCOPE)
+endfunction()
+
+# Generates gradle.properties for the specific target. Usually contains the
+# target build type(executable, dynamic feature, library).
+function(_qt_internal_android_generate_target_gradle_properties target)
+ cmake_parse_arguments(PARSE_ARGV 1 arg "" "DEPLOYMENT_DIR" "")
+
+ if(NOT arg_DEPLOYMENT_DIR)
+ message(FATAL_ERROR "DEPLOYMENT_DIR is not specified.")
+ endif()
+
+ set(gradle_properties_file_name "gradle.properties")
+ set(out_file "${arg_DEPLOYMENT_DIR}/${gradle_properties_file_name}")
+ # Skip generating the file if it's already provided by user.
+ get_target_property(deployment_files ${target} _qt_android_deployment_files)
+ if("${out_file}" IN_LIST deployment_files)
+ return()
+ endif()
+
+ _qt_internal_android_get_template_path(template_file ${target}
+ "app/${gradle_properties_file_name}")
+ _qt_internal_configure_file(CONFIGURE
+ OUTPUT "${out_file}"
+ INPUT "${template_file}"
+ )
+ set_property(TARGET ${target} APPEND PROPERTY _qt_android_deployment_files "${out_file}")
+endfunction()
+
+# Constucts generator expression that returns either target property or the default value
+function(_qt_internal_android_get_manifest_property out_var target property default)
+ set(target_property "$<TARGET_PROPERTY:${target},${property}>")
+ string(JOIN "" out_genex
+ "$<IF:$<BOOL:${target_property}>,"
+ "${target_property},"
+ "${default}"
+ ">"
+ )
+
+ set(${out_var} "${out_genex}" PARENT_SCOPE)
+endfunction()
+
+# Generates the target AndroidManifest.xml
+function(_qt_internal_android_generate_target_android_manifest target)
+ cmake_parse_arguments(PARSE_ARGV 1 arg "" "DEPLOYMENT_DIR" "")
+
+ if(NOT arg_DEPLOYMENT_DIR)
+ message(FATAL_ERROR "DEPLOYMENT_DIR is not specified.")
+ endif()
+
+ set(android_manifest_filename "AndroidManifest.xml")
+ set(out_file "${arg_DEPLOYMENT_DIR}/${android_manifest_filename}")
+
+ # Skip generating the file if it's already provided by user.
+ get_target_property(deployment_files ${target} _qt_android_deployment_files)
+ if("${out_file}" IN_LIST deployment_files)
+ return()
+ endif()
+
+ _qt_internal_android_get_template_path(template_file ${target}
+ "app/${android_manifest_filename}")
+ set(temporary_file "${out_file}.tmp")
+
+ # The file cannot be generated at cmake configure time, because androiddeployqt
+ # will override it at build time. We use this trick with temporary file to override
+ # it after the aux run of androiddeployqt.
+ add_custom_command(OUTPUT "${out_file}"
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ "${temporary_file}"
+ "${out_file}"
+ DEPENDS
+ "${template_file}"
+ "${temporary_file}"
+ ${target}_android_deploy_aux
+ )
+
+ _qt_internal_android_get_manifest_property(APP_PACKAGE_NAME ${target}
+ QT_ANDROID_PACKAGE_NAME "org.qtproject.example.$<MAKE_C_IDENTIFIER:${target}>")
+ _qt_internal_android_get_manifest_property(APP_NAME ${target}
+ QT_ANDROID_APP_NAME "${target}")
+ _qt_internal_android_get_manifest_property(APP_VERSION_CODE ${target}
+ QT_ANDROID_VERSION_CODE "1")
+ _qt_internal_android_get_manifest_property(APP_VERSION_NAME ${target}
+ QT_ANDROID_VERSION_NAME "1")
+ _qt_internal_android_get_manifest_property(APP_LIB_NAME ${target} OUTPUT_NAME "${target}")
+
+ # For application icon we substitute the whole attribute definition, but not only value
+ # otherwise it leads to the Manifest processing issue.
+ set(target_property "$<TARGET_PROPERTY:${target},QT_ANDROID_APP_ICON>")
+ string(JOIN "" APP_ICON
+ "$<$<BOOL:${target_property}>:"
+ "android:icon=\"${target_property}\""
+ ">"
+ )
+
+ file(READ "${template_file}" manifest_content)
+ string(REPLACE ">" "$<ANGLE-R>" manifest_content "${manifest_content}")
+ string(REPLACE ";" "$<SEMICOLON>" manifest_content "${manifest_content}")
+ string(REPLACE "," "$<COMMA>" manifest_content "${manifest_content}")
+
+ _qt_internal_android_convert_permissions(APP_PERMISSIONS ${target} XML)
+
+ set(feature_prefix "\n <uses-feature android:name=\"")
+ set(feature_suffix " \" android:required=\"false\" /$<ANGLE-R>")
+ set(feature_property "$<TARGET_PROPERTY:${target},QT_ANDROID_FEATURES>")
+ string(JOIN "" APP_FEATURES
+ "$<$<BOOL:${feature_property}>:"
+ "${feature_prefix}"
+ "$<JOIN:${feature_property},${feature_suffix},${feature_prefix}>"
+ "${feature_suffix}"
+ ">"
+ )
+
+ set(APP_ARGUMENTS "${QT_ANDROID_APPLICATION_ARGUMENTS}")
+
+ _qt_internal_configure_file(GENERATE OUTPUT "${temporary_file}"
+ CONTENT "${manifest_content}")
+
+ set_property(TARGET ${target} APPEND PROPERTY
+ _qt_android_deployment_files "${out_file}" "${temporary_file}")
+endfunction()
+
+# Generates the top-level gradle.properties in the android-build directory
+# The file contains the information about the versions of the android build
+# tools, the list of supported ABIs.
+function(_qt_internal_android_generate_bundle_gradle_properties target)
+ set(EXTRA_PROPERTIES "")
+
+ set(gradle_properties_file_name "gradle.properties")
+ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
+ set(out_file "${android_build_dir}/${gradle_properties_file_name}")
+
+ # Skip generating the file if it's already provided by user.
+ get_target_property(deployment_files ${target} _qt_android_deployment_files)
+ if("${out_file}" IN_LIST deployment_files)
+ return()
+ endif()
+
+ _qt_internal_android_get_template_path(template_file ${target} "${gradle_properties_file_name}")
+ _qt_internal_configure_file(CONFIGURE
+ OUTPUT "${out_file}"
+ INPUT "${template_file}"
+ )
+ set_property(TARGET ${target} APPEND PROPERTY _qt_android_deployment_files "${out_file}")
+endfunction()
+
+# Generates the local.properties for gradle builds. Contains the path to the
+# Android SDK root.
+function(_qt_internal_android_generate_bundle_local_properties target)
+ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
+ set(out_file "${android_build_dir}/local.properties")
+
+ # Skip generating the file if it's already provided by user.
+ get_target_property(deployment_files ${target} _qt_android_deployment_files)
+ if("${out_file}" IN_LIST deployment_files)
+ return()
+ endif()
+
+ file(TO_CMAKE_PATH "${ANDROID_SDK_ROOT}" ANDROID_SDK_ROOT_NATIVE)
+ _qt_internal_configure_file(CONFIGURE OUTPUT "${out_file}"
+ CONTENT "sdk.dir=${ANDROID_SDK_ROOT_NATIVE}\n")
+endfunction()
+
+# Copies the customized Android package sources to the Android build directory
+function(_qt_internal_android_copy_target_package_sources target)
+ _qt_internal_android_get_package_source_dir(package_source_dir ${target})
+
+ if(NOT package_source_dir)
+ return()
+ endif()
+ get_filename_component(package_source_dir "${package_source_dir}" ABSOLUTE)
+
+ # Collect deployment files from use-defined package source directory
+ file(GLOB_RECURSE package_files
+ LIST_DIRECTORIES false
+ RELATIVE "${package_source_dir}"
+ "${package_source_dir}/*"
+ )
+
+ # Do not copy files that we treat as CMake templates, having '.in' extention.
+ #
+ # TODO: If it ever will be an issue we may exclude only templates that are
+ # known by our build system.
+ list(FILTER package_files EXCLUDE REGEX ".+\\.in$")
+
+ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
+ list(TRANSFORM package_files PREPEND "${android_build_dir}/" OUTPUT_VARIABLE out_package_files)
+ list(TRANSFORM package_files PREPEND "${package_source_dir}/" OUTPUT_VARIABLE in_package_files)
+
+ if(in_package_files)
+ # TODO: Add cmake < 3.26 support
+ if(CMAKE_VERSION VERSION_LESS 3.26)
+ message(FATAL_ERROR "The use of QT_ANDROID_PACKAGE_SOURCE_DIR property with
+ the QT_USE_ANDROID_MODERN_BUNDLE option enabled requires CMake version >= 3.26.")
+ endif()
+ set(copy_commands COMMAND "${CMAKE_COMMAND}" -E copy_directory_if_different
+ "${package_source_dir}" "${android_build_dir}")
+ else()
+ # We actually have nothing to deploy.
+ return()
+ endif()
+
+ add_custom_command(OUTPUT ${out_package_files}
+ ${copy_commands}
+ DEPENDS
+ ${in_package_files}
+ VERBATIM
+ )
+
+ set_target_properties(${target} PROPERTIES _qt_android_deployment_files "${out_package_files}")
+endfunction()
+
+# Copies gradle scripts to a build directory.
+function(_qt_internal_android_copy_gradle_files target output_directory)
+ _qt_internal_android_gradlew_name(gradlew_file_name)
+ _qt_internal_android_gradle_template_dir(gradle_template_dir)
+
+ set(gradlew_file_src "${gradle_template_dir}/${gradlew_file_name}")
+ set(gradlew_file_dst "${output_directory}/${gradlew_file_name}")
+
+ add_custom_command(OUTPUT "${gradlew_file_dst}"
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_if_different "${gradlew_file_src}" "${gradlew_file_dst}"
+ DEPENDS "${gradlew_file_src}"
+ COMMENT "Copying gradlew script for ${target}"
+ VERBATIM
+ )
+
+ # TODO: make a more precise directory copying
+ set(gradle_dir_src "${gradle_template_dir}/gradle")
+ set(gradle_dir_dst "${output_directory}/gradle")
+ add_custom_command(OUTPUT "${gradle_dir_dst}"
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_directory "${gradle_dir_src}" "${gradle_dir_dst}"
+ DEPENDS "${gradle_dir_src}"
+ COMMENT "Copying gradle support files for ${target}"
+ VERBATIM
+ )
+
+ add_custom_target(${target}_copy_gradle_files
+ DEPENDS
+ "${gradlew_file_dst}"
+ "${gradle_dir_dst}"
+ )
+endfunction()
diff --git a/src/corelib/Qt6AndroidMacros.cmake b/src/corelib/Qt6AndroidMacros.cmake
index aa0e5bfed24..ed97a42c83f 100644
--- a/src/corelib/Qt6AndroidMacros.cmake
+++ b/src/corelib/Qt6AndroidMacros.cmake
@@ -120,6 +120,29 @@ function(_qt_internal_generate_android_permissions_json out_result target)
set(${out_result} "${result}" PARENT_SCOPE)
endfunction()
+# Add the specific dynamic library as the dynamic feature for the Android application target.
+function(qt6_add_android_dynamic_features target)
+ cmake_parse_arguments(PARSE_ARGV 1 arg "" "" "FEATURE_TARGETS")
+ if(NOT QT_USE_ANDROID_MODERN_BUNDLE)
+ message(FATAL_ERROR "qt6_add_android_dynamic_features is only supported with"
+ " 'QT_USE_ANDROID_MODERN_BUNDLE' enabled.")
+ endif()
+ if(NOT TARGET ${target})
+ message(FATAL_ERROR "${target} is not a target. Cannot add the dynamic features.")
+ endif()
+ get_target_property(android_type ${target} _qt_android_target_type)
+ if(NOT android_type STREQUAL "APPLICATION")
+ message(FATAL_ERROR "${target} is not an android executable target."
+ " Cannot add the dynamic features.")
+ endif()
+ if(arg_FEATURE_TARGETS)
+ set_property(TARGET ${target}
+ APPEND PROPERTY _qt_android_dynamic_features ${arg_FEATURE_TARGETS})
+ else()
+ message(WARNING "No dynamic features provided.")
+ endif()
+endfunction()
+
# Generate the deployment settings json file for a cmake target.
function(qt6_android_generate_deployment_settings target)
# Information extracted from mkspecs/features/android/android_deployment_settings.prf
@@ -324,8 +347,9 @@ function(qt6_android_generate_deployment_settings target)
__qt_internal_collect_plugin_library_files_v2("${target}" "${plugin_targets}" plugin_targets)
string(APPEND file_contents " \"android-deploy-plugins\":\"${plugin_targets}\",\n")
- _qt_internal_generate_android_permissions_json(permissions_json_array "${target}")
- string(APPEND file_contents " \"permissions\": ${permissions_json_array},\n")
+
+ _qt_internal_android_convert_permissions(permissions_genex ${target} JSON)
+ string(APPEND file_contents " \"permissions\": ${permissions_genex},\n")
# App binary
string(APPEND file_contents
@@ -415,44 +439,6 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
endfunction()
endif()
-function(_qt_internal_add_android_permission target)
- if(NOT TARGET ${target})
- message(FATAL_ERROR "Empty or invalid target for adding Android permission: (${target})")
- endif()
-
- cmake_parse_arguments(arg "" "NAME" "ATTRIBUTES" ${ARGN})
-
- if(NOT arg_NAME)
- message(FATAL_ERROR "NAME for adding Android permission cannot be empty (${target})")
- endif()
-
- set(permission_entry "${arg_NAME}")
-
- if(arg_ATTRIBUTES)
- # Permission with additional attributes
- list(LENGTH arg_ATTRIBUTES attributes_len)
- math(EXPR attributes_modulus "${attributes_len} % 2")
- if(NOT (attributes_len GREATER 1 AND attributes_modulus EQUAL 0))
- message(FATAL_ERROR "Android permission: ${arg_NAME} attributes: ${arg_ATTRIBUTES} must"
- " be name-value pairs (for example: minSdkVersion 30)")
- endif()
- # Combine name-value pairs
- set(index 0)
- set(attributes "")
- while(index LESS attributes_len)
- list(GET arg_ATTRIBUTES ${index} name)
- math(EXPR index "${index} + 1")
- list(GET arg_ATTRIBUTES ${index} value)
- string(APPEND attributes "android:${name}=\'${value}\' ")
- math(EXPR index "${index} + 1")
- endwhile()
- set(permission_entry "${permission_entry}\;${attributes}")
- endif()
-
- # Append the permission to the target's property
- set_property(TARGET ${target} APPEND PROPERTY QT_ANDROID_PERMISSIONS "${permission_entry}")
-endfunction()
-
function(qt6_add_android_permission target)
_qt_internal_add_android_permission(${ARGV})
endfunction()
@@ -519,18 +505,6 @@ function(qt6_android_add_apk_target target)
">"
)
- # Make global apk and aab targets depend on the current apk target.
- if(TARGET aab)
- add_dependencies(aab ${target}_make_aab)
- endif()
- if(TARGET aar)
- add_dependencies(aar ${target}_make_aar)
- endif()
- if(TARGET apk)
- add_dependencies(apk ${target}_make_apk)
- _qt_internal_create_global_apk_all_target_if_needed()
- endif()
-
_qt_internal_android_get_deployment_tool(deployment_tool)
# No need to use genex for the BINARY_DIR since it's read-only.
@@ -719,6 +693,10 @@ function(qt6_android_add_apk_target target)
)
add_dependencies(${target}_make_aab ${target}_prepare_apk_dir)
+ # Make global apk, aab, and aar targets depend on the respective targets.
+ _qt_internal_android_add_global_package_dependencies(${target})
+ _qt_internal_create_global_apk_all_target_if_needed()
+
if(QT_IS_ANDROID_MULTI_ABI_EXTERNAL_PROJECT)
# When building per-ABI external projects we only need to copy ABI-specific libraries and
# resources to the "main" ABI android build folder.
@@ -1661,13 +1639,26 @@ endfunction()
# module and is executed implicitly when configuring user projects.
function(_qt_internal_android_executable_finalizer target)
set_property(TARGET ${target} PROPERTY _qt_android_executable_finalizer_called TRUE)
+ set_property(TARGET ${target} PROPERTY _qt_android_in_finalizer "EXECUTABLE")
_qt_internal_expose_android_package_source_dir_to_ide(${target})
_qt_internal_configure_android_multiabi_target("${target}")
qt6_android_generate_deployment_settings("${target}")
- qt6_android_add_apk_target("${target}")
+ if(QT_USE_ANDROID_MODERN_BUNDLE)
+ _qt_internal_android_generate_dynamic_feature_names("${target}")
+ _qt_internal_android_add_dynamic_feature_deployment("${target}")
+
+ _qt_internal_android_prepare_gradle_build("${target}")
+ _qt_internal_android_add_aux_deployment("${target}")
+
+ _qt_internal_collect_apk_dependencies_defer()
+ _qt_internal_collect_apk_imported_dependencies_defer("${target}")
+ else()
+ qt6_android_add_apk_target("${target}")
+ endif()
_qt_internal_android_create_runner_wrapper("${target}")
+ set_property(TARGET ${target} PROPERTY _qt_android_in_finalizer "")
endfunction()
# Helper to add the android executable finalizer.
@@ -1737,8 +1728,9 @@ function(_qt_internal_android_app_runner_arguments target out_runner_path out_ar
set(${out_runner_path} "${runner_dir}/qt-android-runner.py" PARENT_SCOPE)
_qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
+ _qt_internal_android_get_platform_tools_path(platform_tools)
set(${out_arguments}
- "--adb" "${ANDROID_SDK_ROOT}/platform-tools/adb"
+ "--adb" "${platform_tools}/adb"
"--build-path" "${android_build_dir}"
"--apk" "${android_build_dir}/${target}.apk"
PARENT_SCOPE
@@ -1754,8 +1746,13 @@ function(_qt_internal_android_get_target_android_build_dir out_build_dir target)
endif()
endfunction()
+function(_qt_internal_android_get_target_deployment_dir out_deploy_dir target)
+ _qt_internal_android_get_target_android_build_dir(build_dir ${target})
+ set(${out_deploy_dir} "${build_dir}/app" PARENT_SCOPE)
+endfunction()
+
function(_qt_internal_expose_android_package_source_dir_to_ide target)
- get_target_property(android_package_source_dir ${target} QT_ANDROID_PACKAGE_SOURCE_DIR)
+ _qt_internal_android_get_package_source_dir(android_package_source_dir ${target})
if(android_package_source_dir)
get_target_property(target_source_dir ${target} SOURCE_DIR)
if(NOT IS_ABSOLUTE "${android_package_source_dir}")
@@ -1778,6 +1775,71 @@ function(_qt_internal_expose_android_package_source_dir_to_ide target)
endif()
endfunction()
+function(_qt_internal_android_add_aux_deployment target)
+ cmake_parse_arguments(arg "" "OUTPUT_TARGET_NAME;DEPLOYMENT_DIRECTORY" "EXTRA_ARGS" ${ARGN})
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ string(JOIN "" deployment_file
+ "$<GENEX_EVAL:"
+ "$<TARGET_PROPERTY:${target},QT_ANDROID_DEPLOYMENT_SETTINGS_FILE>"
+ ">"
+ )
+
+ _qt_internal_android_get_deployment_tool(deployment_tool)
+ if(arg_DEPLOYMENT_DIRECTORY)
+ set(deployment_dir "${arg_DEPLOYMENT_DIRECTORY}")
+ else()
+ _qt_internal_android_get_target_deployment_dir(deployment_dir ${target})
+ endif()
+
+ cmake_policy(PUSH)
+ if(POLICY CMP0116)
+ # Without explicitly setting this policy to NEW, we get a warning
+ # even though we ensure there's actually no problem here.
+ # See https://gitlab.kitware.com/cmake/cmake/-/issues/21959
+ cmake_policy(SET CMP0116 NEW)
+ set(relative_to_dir ${CMAKE_CURRENT_BINARY_DIR})
+ else()
+ set(relative_to_dir ${CMAKE_BINARY_DIR})
+ endif()
+
+ set(target_file_copy_relative_path
+ "libs/${CMAKE_ANDROID_ARCH_ABI}/$<TARGET_FILE_NAME:${target}>")
+ _qt_internal_copy_file_if_different_command(copy_command
+ "$<TARGET_FILE:${target}>"
+ "${deployment_dir}/${target_file_copy_relative_path}"
+ )
+
+ _qt_internal_android_get_use_terminal_for_deployment(uses_terminal)
+
+ # TODO: We use androiddeployqt to collect target depdenencies and produce the lib.xml file
+ # which autoloads the collected libraries. Should be done using GRE and transitive properties
+ # in the future.
+ set(libs_xml "${deployment_dir}/res/values/libs.xml")
+ add_custom_command(OUTPUT "${libs_xml}"
+ COMMAND ${copy_command}
+ COMMAND "${deployment_tool}"
+ --input "${deployment_file}"
+ --output "${deployment_dir}"
+ --builddir "${relative_to_dir}"
+ --aux-mode
+ ${arg_EXTRA_ARGS}
+ #TODO: Support signing
+ COMMENT "Deploying Android artifacts for ${target}"
+ DEPENDS "${target}" "${deployment_file}"
+ VERBATIM
+ ${uses_terminal}
+ )
+
+ if(NOT arg_OUTPUT_TARGET_NAME)
+ set(arg_OUTPUT_TARGET_NAME ${target}_android_deploy_aux)
+ endif()
+
+ add_custom_target(${arg_OUTPUT_TARGET_NAME} DEPENDS "${libs_xml}")
+
+ cmake_policy(POP)
+endfunction()
+
# Enables the terminal usage for the add_custom_command calls when verbose deployment is enabled.
function(_qt_internal_android_get_use_terminal_for_deployment out_var)
if(QT_ENABLE_VERBOSE_DEPLOYMENT)
@@ -1822,6 +1884,45 @@ function(_qt_internal_android_get_deployment_type_option out_var release_flag de
endif()
endfunction()
+# Returns the path to the android template directory, that are used by CMake
+# deployment procedures.
+function(_qt_internal_android_template_dir out_var)
+ if(PROJECT_NAME STREQUAL "QtBase" OR QT_SUPERBUILD)
+ set(${out_var} "${QtBase_SOURCE_DIR}/src/android/templates_cmake" PARENT_SCOPE)
+ else()
+ set(${out_var}
+ "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_DATA}/src/android/templates_cmake" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Return the path to the target template directory if it's set for the target.
+# Then this path is stored in the target QT_ANDROID_PACKAGE_SOURCE_DIR property
+# and can only be effectively read in android finalizers.
+function(_qt_internal_android_get_package_source_dir out_var target)
+ get_target_property(in_finalizer ${target} _qt_android_in_finalizer)
+ if(NOT in_finalizer)
+ message(FATAL_ERROR "The '_qt_internal_android_get_package_source_dir' function is"
+ " called outside the Android finalizer."
+ " This is the Qt issue, please report a bug at https://bugreports.qt.io.")
+ endif()
+ get_target_property(package_src_dir ${target} QT_ANDROID_PACKAGE_SOURCE_DIR)
+ if(NOT package_src_dir)
+ set(package_src_dir "")
+ endif()
+ set(${out_var} "${package_src_dir}" PARENT_SCOPE)
+endfunction()
+
+# Add target_make_<apk|aab> as the depednecy for the respective global apk/aab
+# target.
+function(_qt_internal_android_add_global_package_dependencies target)
+ foreach(type apk aab aar)
+ # Make global apk and aab targets depend on the current apk target.
+ if(TARGET ${type} AND TARGET ${target}_make_${type})
+ add_dependencies(${type} ${target}_make_${type})
+ endif()
+ endforeach()
+endfunction()
+
function(_qt_internal_android_get_target_abis out_abis target)
get_target_property(target_abis ${target} QT_ANDROID_ABIS)
if(target_abis)
@@ -1840,5 +1941,10 @@ function(_qt_internal_android_get_target_abis out_abis target)
set(${out_abis} "${android_abis}" PARENT_SCOPE)
endfunction()
+# Returns the path to the Android platform-tools(adb is located there).
+function(_qt_internal_android_get_platform_tools_path out_var)
+ set(${out_var} "${ANDROID_SDK_ROOT}/platform-tools" PARENT_SCOPE)
+endfunction()
+
set(QT_INTERNAL_ANDROID_TARGET_BUILD_DIR_SUPPORT ON CACHE INTERNAL
"Indicates that Qt supports per-target Android build directories")
diff --git a/src/corelib/Qt6AndroidPermissionHelpers.cmake b/src/corelib/Qt6AndroidPermissionHelpers.cmake
new file mode 100644
index 00000000000..7f851e14667
--- /dev/null
+++ b/src/corelib/Qt6AndroidPermissionHelpers.cmake
@@ -0,0 +1,126 @@
+# Copyright (C) 2025 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Generates the generator expression that converts the 'target'
+# QT_ANDROID_PERMISSIONS property to the specific 'type'.
+#
+# It's expected that each element in QT_ANDROID_PERMISSIONS list has specific
+# format:
+# <name>\;<permission>\\\;<extra1>\;<value>\\\;<extra2>\;<value>
+#
+# Synopsis
+# _qt_internal_android_convert_permissions(out_var target <JSON|XML>)
+#
+# Arguments
+#
+# `out_var`
+# The name of the variable where the resulting generator expression is
+# stored.
+#
+# `target`
+# The name of the target.
+#
+# `JSON`
+# Generate JSON array known by androiddeployqt.
+#
+# `XML`
+# Generate XML content compatible with AndroidManifest.xml.
+function(_qt_internal_android_convert_permissions out_var target type)
+ set(permissions_property "$<TARGET_PROPERTY:${target},QT_ANDROID_PERMISSIONS>")
+ set(permissions_genex "$<$<BOOL:${permissions_property}>:")
+ if(type STREQUAL "JSON")
+ set(pref "{ \"")
+ set(post "\" }")
+ set(indent "\n ")
+ string(APPEND permissions_genex
+ "[${indent}$<JOIN:"
+ "$<JOIN:"
+ "${pref}$<JOIN:"
+ "${permissions_property},"
+ "${post}$<COMMA>${indent}${pref}"
+ ">${post},"
+ "\": \""
+ ">,"
+ "\"$<COMMA> \""
+ ">\n ]"
+ )
+ elseif(type STREQUAL "XML")
+ set(pref "<uses-permission\n android:")
+ set(post "' /$<ANGLE-R>\n")
+ string(APPEND permissions_genex
+ "$<JOIN:"
+ "$<JOIN:"
+ "${pref}$<JOIN:"
+ "${permissions_property},"
+ "${post}${pref}"
+ ">${post}\n,"
+ "='"
+ ">,"
+ "' android:"
+ ">"
+ )
+ else()
+ message(FATAL_ERROR "Invalid type ${type}. Supported types: JSON, XML")
+ endif()
+ string(APPEND permissions_genex ">")
+
+ set(${out_var} "${permissions_genex}" PARENT_SCOPE)
+endfunction()
+
+# Add the specific Android permission to the target. The permission is stored
+# in the QT_ANDROID_PERMISSIONS property(the property is not a public API)
+# and has the following format:
+# <name>\;<permission>\\\;<extra1>\;<value>\\\;<extra2>\;<value>
+#
+# Synopsis
+# _qt_internal_add_android_permission(target NAME <permission>
+# ATTRIBUTES <extra1> <value1>
+# [<extra2> <value2>]...
+# )
+#
+# Arguments
+#
+# `target`
+# The Android target.
+#
+# `NAME`
+# The permission name. E.g. 'android.permission.CAMERA'.
+#
+# `ATTRIBUTES`
+# Extra permission attribute key-value pairs.
+# See https://developer.android.com/guide/topics/manifest/uses-permission-element
+# for details.
+function(_qt_internal_add_android_permission target)
+ if(NOT TARGET ${target})
+ message(FATAL_ERROR "Empty or invalid target for adding Android permission: (${target})")
+ endif()
+
+ cmake_parse_arguments(arg "" "NAME" "ATTRIBUTES" ${ARGN})
+
+ if(NOT arg_NAME)
+ message(FATAL_ERROR "NAME for adding Android permission cannot be empty (${target})")
+ endif()
+
+ set(permission_entry "name\;${arg_NAME}")
+ if(arg_ATTRIBUTES)
+ # Permission with additional attributes
+ list(LENGTH arg_ATTRIBUTES attributes_len)
+ math(EXPR attributes_modulus "${attributes_len} % 2")
+ if(NOT (attributes_len GREATER 1 AND attributes_modulus EQUAL 0))
+ message(FATAL_ERROR "Android permission: ${arg_NAME} attributes: ${arg_ATTRIBUTES}"
+ " must be name-value pairs (for example: minSdkVersion 30)")
+ endif()
+ # Combine name-value pairs
+ set(index 0)
+ while(index LESS attributes_len)
+ list(GET arg_ATTRIBUTES ${index} name)
+ math(EXPR index "${index} + 1")
+ list(GET arg_ATTRIBUTES ${index} value)
+ string(APPEND permission_entry "\\\;${name}\;${value}")
+ math(EXPR index "${index} + 1")
+ endwhile()
+ endif()
+
+ # Append the permission to the target's property
+ set_property(TARGET ${target} APPEND PROPERTY QT_ANDROID_PERMISSIONS "${permission_entry}")
+endfunction()
diff --git a/src/corelib/Qt6CoreConfigExtras.cmake.in b/src/corelib/Qt6CoreConfigExtras.cmake.in
index 15405197a61..8a88d558fa8 100644
--- a/src/corelib/Qt6CoreConfigExtras.cmake.in
+++ b/src/corelib/Qt6CoreConfigExtras.cmake.in
@@ -30,6 +30,10 @@ _qt_internal_setup_deploy_support()
if(ANDROID_PLATFORM)
include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
+ include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
+ include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
+ include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
+
_qt_internal_create_global_android_targets()
_qt_internal_collect_default_android_abis()
if(__qt_Core_targets_file_included)
diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake
index 7b522f99abb..5bc85ae7f7a 100644
--- a/src/corelib/Qt6CoreMacros.cmake
+++ b/src/corelib/Qt6CoreMacros.cmake
@@ -683,6 +683,9 @@ function(_qt_internal_create_executable target)
)
qt6_android_apply_arch_suffix("${target}")
+ if(QT_USE_ANDROID_MODERN_BUNDLE)
+ _qt_internal_set_android_application_gradle_defaults(${target})
+ endif()
else()
cmake_policy(PUSH)
__qt_internal_set_cmp0156()
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp
index d74894e1e42..4388122b7b9 100644
--- a/src/corelib/animation/qabstractanimation.cpp
+++ b/src/corelib/animation/qabstractanimation.cpp
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
/*!
\class QAbstractAnimation
diff --git a/src/corelib/animation/qabstractanimation.h b/src/corelib/animation/qabstractanimation.h
index 69a30556a3a..b4b43e64a1d 100644
--- a/src/corelib/animation/qabstractanimation.h
+++ b/src/corelib/animation/qabstractanimation.h
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QABSTRACTANIMATION_H
#define QABSTRACTANIMATION_H
diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h
index d6c245f36f0..51c635f1bed 100644
--- a/src/corelib/animation/qabstractanimation_p.h
+++ b/src/corelib/animation/qabstractanimation_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QABSTRACTANIMATION_P_H
#define QABSTRACTANIMATION_P_H
diff --git a/src/corelib/animation/qanimationgroup.cpp b/src/corelib/animation/qanimationgroup.cpp
index d2572a7462b..ae96069e86f 100644
--- a/src/corelib/animation/qanimationgroup.cpp
+++ b/src/corelib/animation/qanimationgroup.cpp
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
/*!
\class QAnimationGroup
diff --git a/src/corelib/animation/qanimationgroup.h b/src/corelib/animation/qanimationgroup.h
index 412e2d442ea..07d24ae1f73 100644
--- a/src/corelib/animation/qanimationgroup.h
+++ b/src/corelib/animation/qanimationgroup.h
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QANIMATIONGROUP_H
#define QANIMATIONGROUP_H
diff --git a/src/corelib/animation/qanimationgroup_p.h b/src/corelib/animation/qanimationgroup_p.h
index 334f780968a..a09bc6ebcc6 100644
--- a/src/corelib/animation/qanimationgroup_p.h
+++ b/src/corelib/animation/qanimationgroup_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QANIMATIONGROUP_P_H
#define QANIMATIONGROUP_P_H
diff --git a/src/corelib/animation/qparallelanimationgroup.cpp b/src/corelib/animation/qparallelanimationgroup.cpp
index 86e9417b595..0b43a73434f 100644
--- a/src/corelib/animation/qparallelanimationgroup.cpp
+++ b/src/corelib/animation/qparallelanimationgroup.cpp
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
/*!
\class QParallelAnimationGroup
diff --git a/src/corelib/animation/qparallelanimationgroup.h b/src/corelib/animation/qparallelanimationgroup.h
index 77bc6eabac7..9442f4f7355 100644
--- a/src/corelib/animation/qparallelanimationgroup.h
+++ b/src/corelib/animation/qparallelanimationgroup.h
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QPARALLELANIMATIONGROUP_H
#define QPARALLELANIMATIONGROUP_H
diff --git a/src/corelib/animation/qparallelanimationgroup_p.h b/src/corelib/animation/qparallelanimationgroup_p.h
index 62c53d36097..482b9555c7d 100644
--- a/src/corelib/animation/qparallelanimationgroup_p.h
+++ b/src/corelib/animation/qparallelanimationgroup_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QPARALLELANIMATIONGROUP_P_H
#define QPARALLELANIMATIONGROUP_P_H
diff --git a/src/corelib/animation/qpauseanimation.cpp b/src/corelib/animation/qpauseanimation.cpp
index 344b21946e3..74e22e2f053 100644
--- a/src/corelib/animation/qpauseanimation.cpp
+++ b/src/corelib/animation/qpauseanimation.cpp
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
/*!
\class QPauseAnimation
diff --git a/src/corelib/animation/qpauseanimation.h b/src/corelib/animation/qpauseanimation.h
index f661459f835..bf7863a171c 100644
--- a/src/corelib/animation/qpauseanimation.h
+++ b/src/corelib/animation/qpauseanimation.h
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QPAUSEANIMATION_H
#define QPAUSEANIMATION_H
diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp
index 04f048af753..b4c6b6ff8a6 100644
--- a/src/corelib/animation/qpropertyanimation.cpp
+++ b/src/corelib/animation/qpropertyanimation.cpp
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
/*!
\class QPropertyAnimation
diff --git a/src/corelib/animation/qpropertyanimation.h b/src/corelib/animation/qpropertyanimation.h
index 038c202b8f3..590a6ddaf15 100644
--- a/src/corelib/animation/qpropertyanimation.h
+++ b/src/corelib/animation/qpropertyanimation.h
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QPROPERTYANIMATION_H
#define QPROPERTYANIMATION_H
diff --git a/src/corelib/animation/qpropertyanimation_p.h b/src/corelib/animation/qpropertyanimation_p.h
index ef5534cd9c3..c1918ae1bf8 100644
--- a/src/corelib/animation/qpropertyanimation_p.h
+++ b/src/corelib/animation/qpropertyanimation_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QPROPERTYANIMATION_P_H
#define QPROPERTYANIMATION_P_H
diff --git a/src/corelib/animation/qsequentialanimationgroup.cpp b/src/corelib/animation/qsequentialanimationgroup.cpp
index 260481dbef5..d11249ca7ed 100644
--- a/src/corelib/animation/qsequentialanimationgroup.cpp
+++ b/src/corelib/animation/qsequentialanimationgroup.cpp
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
/*!
\class QSequentialAnimationGroup
diff --git a/src/corelib/animation/qsequentialanimationgroup.h b/src/corelib/animation/qsequentialanimationgroup.h
index 6786078170d..b7f9c1b17a1 100644
--- a/src/corelib/animation/qsequentialanimationgroup.h
+++ b/src/corelib/animation/qsequentialanimationgroup.h
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QSEQUENTIALANIMATIONGROUP_H
#define QSEQUENTIALANIMATIONGROUP_H
diff --git a/src/corelib/animation/qsequentialanimationgroup_p.h b/src/corelib/animation/qsequentialanimationgroup_p.h
index cbdf204d0a6..131902b5aa5 100644
--- a/src/corelib/animation/qsequentialanimationgroup_p.h
+++ b/src/corelib/animation/qsequentialanimationgroup_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QSEQUENTIALANIMATIONGROUP_P_H
#define QSEQUENTIALANIMATIONGROUP_P_H
diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp
index be5c09519e9..bd12d5dae95 100644
--- a/src/corelib/animation/qvariantanimation.cpp
+++ b/src/corelib/animation/qvariantanimation.cpp
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#include "qvariantanimation.h"
#include "qvariantanimation_p.h"
diff --git a/src/corelib/animation/qvariantanimation.h b/src/corelib/animation/qvariantanimation.h
index 4bdb9713578..172ee0d6090 100644
--- a/src/corelib/animation/qvariantanimation.h
+++ b/src/corelib/animation/qvariantanimation.h
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QVARIANTANIMATION_H
#define QVARIANTANIMATION_H
diff --git a/src/corelib/animation/qvariantanimation_p.h b/src/corelib/animation/qvariantanimation_p.h
index 0ac238a882b..5fdd9666dba 100644
--- a/src/corelib/animation/qvariantanimation_p.h
+++ b/src/corelib/animation/qvariantanimation_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
#ifndef QVARIANTANIMATION_P_H
#define QVARIANTANIMATION_P_H
diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake
index 909041cf44b..096dce9e84e 100644
--- a/src/corelib/configure.cmake
+++ b/src/corelib/configure.cmake
@@ -591,6 +591,7 @@ qt_config_compile_test(cpp_winrt
runtimeobject
CODE
"// Including winrt/base.h causes an error in some configurations (Windows 10 SDK + c++20)
+# include <guiddef.h> // required by clang-cl: https://github.com/microsoft/cppwinrt/issues/1179
# include <winrt/base.h>
int main(void)
diff --git a/src/corelib/doc/snippets/qprocess/CMakeLists.txt b/src/corelib/doc/snippets/qprocess/CMakeLists.txt
index 07b66d0b36b..d410d479f7f 100644
--- a/src/corelib/doc/snippets/qprocess/CMakeLists.txt
+++ b/src/corelib/doc/snippets/qprocess/CMakeLists.txt
@@ -1,3 +1,5 @@
+set(CMAKE_UNITY_BUILD OFF)
+
add_library(snippets_qprocess OBJECT
qprocess-createprocessargumentsmodifier.cpp
qprocess-simpleexecution.cpp
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index 6f995fe082e..5a0be1d895e 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -893,6 +893,12 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
{
Q_CHECK_FILE_NAME(entry, false);
+ // Detection of WasDeletedAttribute is imperfect: in general, if we can
+ // successfully stat() or access() a file, it hasn't been deleted (though
+ // there are exceptions, like /proc/XXX/fd/ entries on Linux). So we have
+ // to restore this flag in case we fail to stat() anything.
+ auto hadBeenDeleted = data.entryFlags & QFileSystemMetaData::WasDeletedAttribute;
+
#if defined(Q_OS_DARWIN)
if (what & (QFileSystemMetaData::BundleType | QFileSystemMetaData::CaseSensitive)) {
if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
@@ -1103,6 +1109,11 @@ bool QFileSystemEngine::fillMetaData(const QFileSystemEntry &entry, QFileSystemM
if (entryErrno != 0) {
what &= ~QFileSystemMetaData::LinkType; // don't clear link: could be broken symlink
data.clearFlags(what);
+
+ // see comment at the top
+ data.entryFlags |= hadBeenDeleted;
+ data.knownFlagsMask |= hadBeenDeleted;
+
return false;
}
return true;
diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp
index 0886f63b810..9c1bb45dd2d 100644
--- a/src/corelib/io/qiodevice.cpp
+++ b/src/corelib/io/qiodevice.cpp
@@ -1309,8 +1309,11 @@ QByteArray QIODevice::readAll()
The newline character ('\\n') is included in the buffer. If a
newline is not encountered before maxSize - 1 bytes are read, a
- newline will not be inserted into the buffer. On windows newline
- characters are replaced with '\\n'.
+ newline will not be inserted into the buffer.
+
+ \note Newline translation(e.g., converting \r to \n) is performed
+ only when the device is opened for reading with QIODevice::Text
+ flag.
Note that on sequential devices, data may not be immediately available,
which may result in a partial line being returned. By calling the
diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp
index c1f01267949..038db4d857e 100644
--- a/src/corelib/io/qtemporaryfile.cpp
+++ b/src/corelib/io/qtemporaryfile.cpp
@@ -1,6 +1,7 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2017 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:critical reason:data-parser
#include "qtemporaryfile.h"
@@ -881,6 +882,11 @@ void QTemporaryFile::setFileTemplate(const QString &name)
be used for a similar purpose too, particularly if the destination file is
not temporary.
+ \note Calling rename() does not disable autoRemove. If you want the renamed
+ file to persist, you must call setAutoRemove and set it to \c false after
+ calling rename(). Otherwise, the file will be deleted when the QTemporaryFile
+ object is destroyed.
+
\sa QSaveFile, QSaveFile::commit(), QFile::rename()
*/
bool QTemporaryFile::rename(const QString &newName)
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index 565ce04c6ce..a4fbf69da8b 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -3660,17 +3660,29 @@ QList<QUrl> QUrl::fromStringList(const QStringList &urls, ParsingMode mode)
*/
size_t qHash(const QUrl &url, size_t seed) noexcept
{
+ QtPrivate::QHashCombineWithSeed hasher(seed);
+
+ // non-commutative, we must hash the port first
if (!url.d)
- return qHash(-1, seed); // the hash of an unset port (-1)
-
- return qHash(url.d->scheme) ^
- qHash(url.d->userName) ^
- qHash(url.d->password) ^
- qHash(url.d->host) ^
- qHash(url.d->port, seed) ^
- qHash(url.d->path) ^
- qHash(url.d->query) ^
- qHash(url.d->fragment);
+ return hasher(0, -1);
+ size_t state = hasher(0, url.d->port);
+
+ if (url.d->hasScheme())
+ state = hasher(state, url.d->scheme);
+ if (url.d->hasUserInfo()) {
+ // see presentSections(), appendUserName(), etc.
+ state = hasher(state, url.d->userName);
+ state = hasher(state, url.d->password);
+ }
+ if (url.d->hasHost() || url.d->isLocalFile()) // for XDG compatibility
+ state = hasher(state, url.d->host);
+ if (url.d->hasPath())
+ state = hasher(state, url.d->path);
+ if (url.d->hasQuery())
+ state = hasher(state, url.d->query);
+ if (url.d->hasFragment())
+ state = hasher(state, url.d->fragment);
+ return state;
}
static QUrl adjustFtpPath(QUrl url)
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index a19e39685f1..3b92c5f48f2 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -2189,7 +2189,7 @@ bool QCoreApplication::installTranslator(QTranslator *translationFile)
QCoreApplicationPrivate *d = self->d_func();
{
- QMutexLocker locker(&d->translateMutex);
+ QWriteLocker locker(&d->translateMutex);
d->translators.prepend(translationFile);
}
@@ -2221,7 +2221,7 @@ bool QCoreApplication::removeTranslator(QTranslator *translationFile)
if (!QCoreApplicationPrivate::checkInstance("removeTranslator"))
return false;
QCoreApplicationPrivate *d = self->d_func();
- QMutexLocker locker(&d->translateMutex);
+ QWriteLocker locker(&d->translateMutex);
if (d->translators.removeAll(translationFile)) {
#ifndef QT_NO_QOBJECT
locker.unlock();
@@ -2306,7 +2306,7 @@ QString QCoreApplication::translate(const char *context, const char *sourceText,
if (self) {
QCoreApplicationPrivate *d = self->d_func();
- QMutexLocker locker(&d->translateMutex);
+ QReadLocker locker(&d->translateMutex);
if (!d->translators.isEmpty()) {
QList<QTranslator*>::ConstIterator it;
QTranslator *translationFile;
@@ -2332,23 +2332,13 @@ QString qtTrId(const char *id, int n)
return QCoreApplication::translate(nullptr, id, nullptr, n);
}
-/*!
- \internal
- Returns a locked mutex handle if \a translator is registered in QCoreApplication,
- and might be therefore queried for translations from other threads.
- Returns an unlocked/dummy QMutexLocker otherwise.
- */
-std::unique_lock<QMutex> QCoreApplicationPrivate::mutexLockerForTranslator(QTranslator *translator)
+bool QCoreApplicationPrivate::isTranslatorInstalled(QTranslator *translator)
{
if (!QCoreApplication::self)
- return std::unique_lock<QMutex>();
-
+ return false;
QCoreApplicationPrivate *d = QCoreApplication::self->d_func();
- std::unique_lock<QMutex> locker(d->translateMutex);
- if (!d->translators.contains(translator))
- locker.unlock();
-
- return locker;
+ QReadLocker locker(&d->translateMutex);
+ return d->translators.contains(translator);
}
#else
diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h
index 4cb6254e98d..0027b1ad57f 100644
--- a/src/corelib/kernel/qcoreapplication_p.h
+++ b/src/corelib/kernel/qcoreapplication_p.h
@@ -30,12 +30,10 @@
#include "private/qcore_mac_p.h"
#endif
-#ifndef QT_NO_TRANSLATION
-#include <mutex>
-#endif
-
QT_BEGIN_NAMESPACE
+typedef QList<QTranslator*> QTranslatorList;
+
class QAbstractEventDispatcher;
#ifndef QT_NO_QOBJECT
@@ -149,9 +147,9 @@ public:
static bool is_app_closing;
#endif
#ifndef QT_NO_TRANSLATION
- QList<QTranslator*> translators;
- QMutex translateMutex;
- static std::unique_lock<QMutex> mutexLockerForTranslator(QTranslator *translator);
+ QTranslatorList translators;
+ QReadWriteLock translateMutex;
+ static bool isTranslatorInstalled(QTranslator *translator);
#endif
static bool setuidAllowed;
diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp
index 60bcdedba13..7fe36d37bce 100644
--- a/src/corelib/kernel/qmetaobjectbuilder.cpp
+++ b/src/corelib/kernel/qmetaobjectbuilder.cpp
@@ -2080,6 +2080,17 @@ bool QMetaPropertyBuilder::isBindable() const
else
return false;
}
+/*!
+ Returns \c true if the property is required.
+ The default is \c false.
+ */
+bool QMetaPropertyBuilder::isRequired() const
+{
+ if (auto d = d_func())
+ return d->flag(Bindable);
+ else
+ return false;
+}
/*!
Sets this property to readable if \a value is true.
@@ -2236,6 +2247,15 @@ void QMetaPropertyBuilder::setBindable(bool value)
}
/*!
+ Sets the\c REQUIRED flag on this property to \a value
+ */
+void QMetaPropertyBuilder::setRequired(bool value)
+{
+ if (auto d = d_func())
+ d->setFlag(Required, value);
+}
+
+/*!
Returns the revision of this property.
\sa setRevision()
diff --git a/src/corelib/kernel/qmetaobjectbuilder_p.h b/src/corelib/kernel/qmetaobjectbuilder_p.h
index cf64e51c30c..36cd08d908c 100644
--- a/src/corelib/kernel/qmetaobjectbuilder_p.h
+++ b/src/corelib/kernel/qmetaobjectbuilder_p.h
@@ -216,6 +216,7 @@ public:
bool isFinal() const;
bool isAlias() const;
bool isBindable() const;
+ bool isRequired() const;
void setReadable(bool value);
void setWritable(bool value);
@@ -230,6 +231,7 @@ public:
void setFinal(bool value);
void setAlias(bool value);
void setBindable(bool value);
+ void setRequired(bool value);
int revision() const;
void setRevision(int revision);
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 1242a40f185..45c947004f5 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -981,12 +981,6 @@ void QMetaType::unregisterMetaType(QMetaType type)
than the QMetaType \a rhs, otherwise returns \c false.
*/
-/*! \internal */
-bool QMetaTypeModuleHelper::convert(const void *, int, void *, int) const
-{
- return false;
-}
-
static constexpr auto createStaticTypeToIdMap()
{
#define QT_ADD_STATIC_METATYPE(MetaTypeName, MetaTypeId, RealName) \
@@ -1049,8 +1043,8 @@ static bool qIntegerConversionFromFPHelper(From from, To *to)
return true;
}
-// NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor): this is not a base class
-static constexpr struct : QMetaTypeModuleHelper
+namespace {
+struct QCoreVariantHelper : QMetaTypeModuleHelper
{
template<typename T, typename LiteralWrapper =
std::conditional_t<std::is_same_v<T, QString>, QLatin1StringView, const char *>>
@@ -1060,7 +1054,8 @@ static constexpr struct : QMetaTypeModuleHelper
return !(str.isEmpty() || str == LiteralWrapper("0") || str == LiteralWrapper("false"));
}
- const QtPrivate::QMetaTypeInterface *interfaceForType(int type) const override {
+ static const QtPrivate::QMetaTypeInterface *interfaceForType(int type)
+ {
switch (type) {
QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(QT_METATYPE_CONVERT_ID_TO_TYPE)
QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_METATYPE_CONVERT_ID_TO_TYPE)
@@ -1072,11 +1067,14 @@ static constexpr struct : QMetaTypeModuleHelper
}
}
-#ifndef QT_BOOTSTRAPPED
- bool convert(const void *from, int fromTypeId, void *to, int toTypeId) const override
+ static bool convert(const void *from, int fromTypeId, void *to, int toTypeId)
{
Q_ASSERT(fromTypeId != toTypeId);
+#ifdef QT_BOOTSTRAPPED
+ Q_UNUSED(from);
+ Q_UNUSED(to);
+#else
// canConvert calls with two nullptr
bool onlyCheck = (from == nullptr && to == nullptr);
@@ -1747,26 +1745,28 @@ QT_WARNING_DISABLE_CLANG("-Wtautological-compare")
QT_WARNING_POP
}
+#endif // !QT_BOOTSTRAPPED
return false;
}
-#endif // !QT_BOOTSTRAPPED
-} metatypeHelper = {};
+};
+} // unnamed namespace
-Q_CONSTINIT Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeGuiHelper = nullptr;
-Q_CONSTINIT Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeWidgetsHelper = nullptr;
+Q_CONSTINIT Q_CORE_EXPORT QMetaTypeModuleHelper qMetaTypeGuiHelper = {};
+Q_CONSTINIT Q_CORE_EXPORT QMetaTypeModuleHelper qMetaTypeWidgetsHelper = {};
-static const QMetaTypeModuleHelper *qModuleHelperForType(int type)
+#ifndef QT_BOOTSTRAPPED
+static bool tryConvertBuiltinTypes(const void *from, int fromTypeId, void *to, int toTypeId)
{
+ int type = qMax(fromTypeId, toTypeId);
if (type <= QMetaType::LastCoreType)
- return &metatypeHelper;
+ return QCoreVariantHelper::convert(from, fromTypeId, to, toTypeId);
if (type >= QMetaType::FirstGuiType && type <= QMetaType::LastGuiType)
- return qMetaTypeGuiHelper;
+ return qMetaTypeGuiHelper.convert(from, fromTypeId, to, toTypeId);
else if (type >= QMetaType::FirstWidgetsType && type <= QMetaType::LastWidgetsType)
- return qMetaTypeWidgetsHelper;
- return nullptr;
+ return qMetaTypeWidgetsHelper.convert(from, fromTypeId, to, toTypeId);
+ return false;
}
-#ifndef QT_BOOTSTRAPPED
template<typename T, typename Key>
class QMetaTypeFunctionRegistry
{
@@ -2471,10 +2471,8 @@ bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType,
int fromTypeId = fromType.id();
int toTypeId = toType.id();
- if (auto moduleHelper = qModuleHelperForType(qMax(fromTypeId, toTypeId))) {
- if (moduleHelper->convert(from, fromTypeId, to, toTypeId))
- return true;
- }
+ if (tryConvertBuiltinTypes(from, fromTypeId, to, toTypeId))
+ return true;
const auto f = customTypesConversionRegistry()->function({fromTypeId, toTypeId});
if (f)
return (*f)(from, to);
@@ -2676,10 +2674,9 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType)
if (fromTypeId == toTypeId)
return true;
- if (auto moduleHelper = qModuleHelperForType(qMax(fromTypeId, toTypeId))) {
- if (moduleHelper->convert(nullptr, fromTypeId, nullptr, toTypeId))
- return true;
- }
+ if (tryConvertBuiltinTypes(nullptr, fromTypeId, nullptr, toTypeId))
+ return true;
+
const ConverterFunction * const f =
customTypesConversionRegistry()->function(std::make_pair(fromTypeId, toTypeId));
if (f)
@@ -2879,8 +2876,12 @@ void QMetaType::registerNormalizedTypedef(const NS(QByteArray) & normalizedTypeN
static const QtPrivate::QMetaTypeInterface *interfaceForStaticType(int typeId)
{
Q_ASSERT(typeId < QMetaType::User);
- if (auto moduleHelper = qModuleHelperForType(typeId))
- return moduleHelper->interfaceForType(typeId);
+ if (typeId <= QMetaType::LastCoreType)
+ return QCoreVariantHelper::interfaceForType(typeId);
+ if (typeId >= QMetaType::FirstGuiType && typeId <= QMetaType::LastGuiType)
+ return qMetaTypeGuiHelper.interfaceForType(typeId);
+ if (typeId >= QMetaType::FirstWidgetsType && typeId <= QMetaType::LastWidgetsType)
+ return qMetaTypeWidgetsHelper.interfaceForType(typeId);
return nullptr;
}
@@ -2909,40 +2910,18 @@ bool QMetaType::isRegistered(int type)
return interfaceForTypeNoWarning(type) != nullptr;
}
-namespace {
-enum NormalizeTypeMode {
- DontNormalizeType,
- TryNormalizeType
-};
-}
-template <NormalizeTypeMode tryNormalizedType> static inline
-const QtPrivate::QMetaTypeInterface *qMetaTypeTypeImpl(QByteArrayView name)
+static const QtPrivate::QMetaTypeInterface *findMetaTypeByName(QByteArrayView name)
{
- if (name.isEmpty())
- return nullptr;
-
+ Q_PRE(!name.isEmpty());
int type = qMetaTypeStaticType(name);
if (type != QMetaType::UnknownType) {
return interfaceForStaticType(type);
#ifndef QT_BOOTSTRAPPED
- } else {
- QReadLocker locker(&customTypeRegistry()->lock);
+ } else if (customTypeRegistry.exists()) {
+ QReadLocker locker(&customTypeRegistry->lock);
auto it = customTypeRegistry->aliases.constFind(name);
if (it != customTypeRegistry->aliases.constEnd())
return it.value().data();
-
-#ifndef QT_NO_QOBJECT
- if (tryNormalizedType) {
- const char *typeName = name.constData();
- const NS(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName);
- type = qMetaTypeStaticType(normalizedTypeName);
- if (type == QMetaType::UnknownType) {
- return customTypeRegistry->aliases.value(normalizedTypeName).data();
- } else {
- return interfaceForStaticType(type);
- }
- }
-#endif
#endif
}
return nullptr;
@@ -2969,7 +2948,9 @@ const QtPrivate::QMetaTypeInterface *qMetaTypeTypeImpl(QByteArrayView name)
*/
int qMetaTypeTypeInternal(QByteArrayView name)
{
- const QtPrivate::QMetaTypeInterface *iface = qMetaTypeTypeImpl<DontNormalizeType>(name);
+ const QtPrivate::QMetaTypeInterface *iface = nullptr;
+ if (!name.isEmpty())
+ iface = findMetaTypeByName(name);
return iface ? iface->typeId.loadRelaxed() : QMetaType::UnknownType;
}
@@ -3138,7 +3119,20 @@ QMetaType QMetaType::underlyingType() const
*/
QMetaType QMetaType::fromName(QByteArrayView typeName)
{
- return QMetaType(qMetaTypeTypeImpl<TryNormalizeType>(typeName));
+ if (typeName.isEmpty())
+ return QMetaType();
+
+ const QtPrivate::QMetaTypeInterface *iface = findMetaTypeByName(typeName);
+ if (iface)
+ return QMetaType(iface);
+
+#if !defined(QT_NO_QOBJECT)
+ const NS(QByteArray) normalizedTypeName = QMetaObject::normalizedType(typeName.constData());
+ if (normalizedTypeName != typeName)
+ iface = findMetaTypeByName(normalizedTypeName);
+#endif
+
+ return QMetaType(iface);
}
/*!
diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h
index c05bce5fc8f..b39e1de0be2 100644
--- a/src/corelib/kernel/qmetatype_p.h
+++ b/src/corelib/kernel/qmetatype_p.h
@@ -40,25 +40,29 @@ QT_BEGIN_NAMESPACE
assign_and_return \
}
-class Q_CORE_EXPORT QMetaTypeModuleHelper
+struct QMetaTypeModuleHelper
{
- Q_DISABLE_COPY_MOVE(QMetaTypeModuleHelper)
-protected:
- QMetaTypeModuleHelper() = default;
- ~QMetaTypeModuleHelper() = default;
-public:
- Q_WEAK_OVERLOAD // prevent it from entering the ABI and rendering constexpr useless
static constexpr auto makePair(int from, int to) -> quint64
{
return (quint64(from) << 32) + quint64(to);
}
- virtual const QtPrivate::QMetaTypeInterface *interfaceForType(int) const = 0;
- virtual bool convert(const void *, int, void *, int) const;
+ static const QtPrivate::QMetaTypeInterface *interfaceForType_dummy(int)
+ {
+ return nullptr;
+ }
+
+ static bool convert_dummy(const void *, int, void *, int)
+ {
+ return false;
+ }
+
+ decltype(&interfaceForType_dummy) interfaceForType = &interfaceForType_dummy;
+ decltype(&convert_dummy) convert = &convert_dummy;
};
-extern Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeGuiHelper;
-extern Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeWidgetsHelper;
+extern Q_CORE_EXPORT QMetaTypeModuleHelper qMetaTypeGuiHelper;
+extern Q_CORE_EXPORT QMetaTypeModuleHelper qMetaTypeWidgetsHelper;
namespace QtMetaTypePrivate {
template<typename T>
diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp
index 47483dc6470..c8348aba16a 100644
--- a/src/corelib/kernel/qtranslator.cpp
+++ b/src/corelib/kernel/qtranslator.cpp
@@ -39,6 +39,8 @@
#include <vector>
#include <memory>
+#include <QtCore/qmutex.h>
+
QT_BEGIN_NAMESPACE
Q_STATIC_LOGGING_CATEGORY(lcTranslator, "qt.core.qtranslator")
@@ -259,6 +261,8 @@ class QTranslatorPrivate : public QObjectPrivate
public:
enum { Contexts = 0x2f, Hashes = 0x42, Messages = 0x69, NumerusRules = 0x88, Dependencies = 0x96, Language = 0xa7 };
+ mutable QMutex lock;
+
QTranslatorPrivate() :
#if defined(QT_USE_MMAP)
used_mmap(0),
@@ -463,12 +467,7 @@ bool QTranslator::load(const QString & filename, const QString & directory,
const QString & suffix)
{
Q_D(QTranslator);
-
- std::unique_lock locker = QCoreApplicationPrivate::mutexLockerForTranslator(this);
- if (locker.owns_lock())
- QCoreApplication::postEvent(QCoreApplication::instance(),
- new QEvent(QEvent::LanguageChange));
-
+ QMutexLocker locker(&d->lock);
d->clear();
QString prefix;
@@ -744,12 +743,7 @@ bool QTranslator::load(const QLocale & locale,
const QString & suffix)
{
Q_D(QTranslator);
-
- std::unique_lock locker = QCoreApplicationPrivate::mutexLockerForTranslator(this);
- if (locker.owns_lock())
- QCoreApplication::postEvent(QCoreApplication::instance(),
- new QEvent(QEvent::LanguageChange));
-
+ QMutexLocker locker(&d->lock);
d->clear();
return d->load_translation(locale, filename, prefix, directory, suffix);
}
@@ -769,12 +763,7 @@ bool QTranslator::load(const QLocale & locale,
bool QTranslator::load(const uchar *data, int len, const QString &directory)
{
Q_D(QTranslator);
-
- std::unique_lock locker = QCoreApplicationPrivate::mutexLockerForTranslator(this);
- if (locker.owns_lock())
- QCoreApplication::postEvent(QCoreApplication::instance(),
- new QEvent(QEvent::LanguageChange));
-
+ QMutexLocker locker(&d->lock);
d->clear();
if (!data || len < MagicLength || memcmp(data, magic, MagicLength))
@@ -1048,6 +1037,7 @@ searchDependencies:
void QTranslatorPrivate::clear()
{
+ Q_Q(QTranslator);
if (unmapPointer && unmapLength) {
#if defined(QT_USE_MMAP)
if (used_mmap) {
@@ -1075,9 +1065,15 @@ void QTranslatorPrivate::clear()
language.clear();
filePath.clear();
+
+ if (QCoreApplicationPrivate::isTranslatorInstalled(q))
+ QCoreApplication::postEvent(QCoreApplication::instance(),
+ new QEvent(QEvent::LanguageChange));
}
/*!
+ \threadsafe
+
Returns the translation for the key (\a context, \a sourceText,
\a disambiguation). If none is found, also tries (\a context, \a
sourceText, ""). If that still fails, returns a null string.
@@ -1099,7 +1095,14 @@ QString QTranslator::translate(const char *context, const char *sourceText, cons
int n) const
{
Q_D(const QTranslator);
- return d->do_translate(context, sourceText, disambiguation, n);
+
+ // Return early to avoid a deadlock in case translate() is called
+ // from a code path triggered by QTranslator::load()
+ if (!d->lock.tryLock())
+ return QString();
+ QString result = d->do_translate(context, sourceText, disambiguation, n);
+ d->lock.unlock();
+ return result;
}
/*!
diff --git a/src/corelib/platform/windows/qt_winrtbase_p.h b/src/corelib/platform/windows/qt_winrtbase_p.h
index fb7366f93de..79c2bdf6b1c 100644
--- a/src/corelib/platform/windows/qt_winrtbase_p.h
+++ b/src/corelib/platform/windows/qt_winrtbase_p.h
@@ -18,6 +18,7 @@
#include <QtCore/qglobal.h>
#if QT_CONFIG(cpp_winrt)
+# include <guiddef.h> // required by clang-cl: https://github.com/microsoft/cppwinrt/issues/1179
# include <winrt/base.h>
# include <QtCore/private/qfactorycacheregistration_p.h>
// Workaround for Windows SDK bug.
diff --git a/src/corelib/thread/qatomicwait.cpp b/src/corelib/thread/qatomicwait.cpp
index 3d70333ca7b..25ca771643b 100644
--- a/src/corelib/thread/qatomicwait.cpp
+++ b/src/corelib/thread/qatomicwait.cpp
@@ -4,6 +4,7 @@
#include "qatomicwait_p.h"
#include <qendian.h>
+#include "qfutex_p.h"
#include "qwaitcondition_p.h"
#include <array>
@@ -96,8 +97,21 @@ struct QAtomicWaitLocks
};
} // unnamed namespace
+static inline void checkFutexUse()
+{
+#if !defined(QATOMICWAIT_USE_FALLBACK)
+ if (QtFutex::futexAvailable()) {
+ // This will disable the code and data on systems where futexes are
+ // always available (currently: FreeBSD, Linux, Windows).
+ qFatal("Implementation should have used futex!");
+ }
+#endif
+}
+
static QAtomicWaitLocks &atomicLocks() noexcept
{
+ checkFutexUse();
+
static QAtomicWaitLocks global {};
return global;
}
diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp
index bd3b269c0b7..832d87332b0 100644
--- a/src/corelib/thread/qmutex.cpp
+++ b/src/corelib/thread/qmutex.cpp
@@ -120,8 +120,8 @@ void QBasicMutex::destroyInternal(void *ptr)
Locks the mutex. If another thread has locked the mutex then this
call will block until that thread has unlocked it.
- Calling this function multiple times on the same mutex from the
- same thread will cause a \e dead-lock.
+ If the mutex was already locked by the current thread, this call will
+ never return, causing a \e dead-lock.
\sa unlock()
*/
@@ -140,9 +140,6 @@ void QBasicMutex::destroyInternal(void *ptr)
If the lock was obtained, the mutex must be unlocked with unlock()
before another thread can successfully lock it.
- Calling this function multiple times on the same mutex from the
- same thread will cause a \e dead-lock.
-
\sa lock(), unlock()
*/
@@ -157,9 +154,6 @@ void QBasicMutex::destroyInternal(void *ptr)
If the lock was obtained, the mutex must be unlocked with unlock()
before another thread can successfully lock it.
- Calling this function multiple times on the same mutex from the
- same thread will cause a \e dead-lock.
-
\sa lock(), unlock()
*/
@@ -172,9 +166,6 @@ void QBasicMutex::destroyInternal(void *ptr)
If the lock was obtained, the mutex must be unlocked with unlock()
before another thread can successfully lock it.
- Calling this function multiple times on the same mutex from the
- same thread will cause a \e dead-lock.
-
\sa lock(), unlock()
*/
@@ -202,9 +193,6 @@ void QBasicMutex::destroyInternal(void *ptr)
If the lock was obtained, the mutex must be unlocked with unlock()
before another thread can successfully lock it.
- Calling this function multiple times on the same mutex from the
- same thread will cause a \e dead-lock.
-
\sa lock(), unlock()
*/
@@ -222,9 +210,6 @@ void QBasicMutex::destroyInternal(void *ptr)
If the lock was obtained, the mutex must be unlocked with unlock()
before another thread can successfully lock it.
- Calling this function multiple times on the same mutex from the
- same thread will cause a \e dead-lock.
-
\sa lock(), unlock()
*/
diff --git a/src/corelib/tools/qatomicscopedvaluerollback.h b/src/corelib/tools/qatomicscopedvaluerollback.h
index 8f653acba5e..929a2e2d466 100644
--- a/src/corelib/tools/qatomicscopedvaluerollback.h
+++ b/src/corelib/tools/qatomicscopedvaluerollback.h
@@ -11,6 +11,7 @@
#include <QtCore/qtconfigmacros.h>
#include <atomic>
+#include <type_traits>
QT_BEGIN_NAMESPACE
@@ -122,6 +123,33 @@ template <typename T>
QAtomicScopedValueRollback(QBasicAtomicPointer<T> &, std::memory_order)
-> QAtomicScopedValueRollback<T*>;
+template <typename T, typename V,
+ std::enable_if_t<std::is_convertible_v<V, T>, bool> = true>
+QAtomicScopedValueRollback(std::atomic<T>&, V)
+ -> QAtomicScopedValueRollback<T>;
+template <typename T, typename V,
+ std::enable_if_t<std::is_convertible_v<V, T>, bool> = true>
+QAtomicScopedValueRollback(std::atomic<T>&, V, std::memory_order)
+ -> QAtomicScopedValueRollback<T>;
+
+template <typename T, typename V,
+ std::enable_if_t<std::is_convertible_v<V, T>, bool> = true>
+QAtomicScopedValueRollback(QBasicAtomicInteger<T>&, V)
+ -> QAtomicScopedValueRollback<T>;
+template <typename T, typename V,
+ std::enable_if_t<std::is_convertible_v<V, T>, bool> = true>
+QAtomicScopedValueRollback(QBasicAtomicInteger<T>&, V, std::memory_order)
+ -> QAtomicScopedValueRollback<T>;
+
+template <typename T, typename V,
+ std::enable_if_t<std::is_convertible_v<V, T*>, bool> = true>
+QAtomicScopedValueRollback(QBasicAtomicPointer<T>&, V)
+ -> QAtomicScopedValueRollback<T*>;
+template <typename T, typename V,
+ std::enable_if_t<std::is_convertible_v<V, T*>, bool> = true>
+QAtomicScopedValueRollback(QBasicAtomicPointer<T>&, V, std::memory_order)
+ -> QAtomicScopedValueRollback<T*>;
+
QT_END_NAMESPACE
#endif // QATOMICASCOPEDVALUEROLLBACK_H
diff --git a/src/corelib/tools/qfreelist_p.h b/src/corelib/tools/qfreelist_p.h
index cc12fb9c8d0..ecefd1f55df 100644
--- a/src/corelib/tools/qfreelist_p.h
+++ b/src/corelib/tools/qfreelist_p.h
@@ -199,27 +199,27 @@ inline typename QFreeList<T, ConstantsType>::ReferenceType QFreeList<T, Constant
template <typename T, typename ConstantsType>
inline int QFreeList<T, ConstantsType>::next()
{
- int id, newid, at;
- ElementType *v;
+ int newid;
+ int id = _next.loadAcquire();
do {
- id = _next.loadAcquire();
-
- at = id & ConstantsType::IndexMask;
+ int at = id & ConstantsType::IndexMask;
const int block = blockfor(at);
- v = _v[block].loadAcquire();
+ ElementType *v = _v[block].loadAcquire();
if (!v) {
- v = allocate((id & ConstantsType::IndexMask) - at, ConstantsType::Sizes[block]);
- if (!_v[block].testAndSetRelease(nullptr, v)) {
+ ElementType* const alloced = allocate((id & ConstantsType::IndexMask) - at,
+ ConstantsType::Sizes[block]);
+ if (_v[block].testAndSetRelease(nullptr, alloced, v)) {
+ v = alloced;
+ } else {
// race with another thread lost
- delete[] v;
- v = _v[block].loadAcquire();
+ delete[] alloced;
Q_ASSERT(v != nullptr);
}
}
newid = v[at].next.loadRelaxed() | (id & ~ConstantsType::IndexMask);
- } while (!_next.testAndSetRelease(id, newid));
+ } while (!_next.testAndSetOrdered(id, newid, id));
// qDebug("QFreeList::next(): returning %d (_next now %d, serial %d)",
// id & ConstantsType::IndexMask,
// newid & ConstantsType::IndexMask,
diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h
index cbe217db11e..3e44f5f3442 100644
--- a/src/corelib/tools/qhashfunctions.h
+++ b/src/corelib/tools/qhashfunctions.h
@@ -298,19 +298,32 @@ bool qHashEquals(const T1 &a, const T2 &b)
}
namespace QtPrivate {
-template <typename Mixer> struct QHashCombiner : private Mixer
+template <typename Mixer> struct QHashCombinerWithSeed : private Mixer
{
- using result_type = typename Mixer::result_type ;
+ using result_type = typename Mixer::result_type;
+ size_t seed;
+ constexpr QHashCombinerWithSeed(result_type s) noexcept : seed(s) {}
+
+ template <typename T>
+ constexpr result_type operator()(result_type result, const T &t) const
+ noexcept(noexcept(qHash(t, seed)))
+ {
+ return Mixer::operator()(result, qHash(t, seed));
+ }
+};
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED)
- // Qt 6.x didn't use to pass the seed; bootstrap has no seed
+// Earlier Qt 6.x versions of qHashMulti() failed to pass the seed as the seed
+// argument of qHash(), so this class exists for compatibility with user and
+// inline code that relies on the old behavior. For Qt 7, we'll replace with
+// the above version, except for the bootstrapped tools (which have no seed).
+template <typename Mixer> struct QHashCombiner : private Mixer
+{
+ using result_type = typename Mixer::result_type;
+
static constexpr size_t seed = 0;
constexpr QHashCombiner(result_type) noexcept {}
Q_DECL_DEPRECATED_X("pass the seed argument") constexpr QHashCombiner() noexcept {}
-#else
- size_t seed;
- constexpr QHashCombiner(result_type s) : seed(s) noexcept {}
-#endif
template <typename T>
constexpr result_type operator()(result_type result, const T &t) const
@@ -319,6 +332,9 @@ template <typename Mixer> struct QHashCombiner : private Mixer
return Mixer::operator()(result, qHash(t, seed));
}
};
+#else
+template <typename Mixer> using QHashCombiner = QHashCombinerWithSeed<Mixer>;
+#endif
struct QHashCombineMixer
{
@@ -330,6 +346,7 @@ struct QHashCombineMixer
}
};
using QHashCombine = QHashCombiner<QHashCombineMixer>;
+using QHashCombineWithSeed = QHashCombinerWithSeed<QHashCombineMixer>;
struct QHashCombineCommutativeMixer : std::plus<size_t>
{
@@ -341,6 +358,7 @@ struct QHashCombineCommutativeMixer : std::plus<size_t>
typedef size_t result_type;
};
using QHashCombineCommutative = QHashCombiner<QHashCombineCommutativeMixer>;
+using QHashCombineCommutativeWithSeed = QHashCombinerWithSeed<QHashCombineCommutativeMixer>;
template <typename... T>
using QHashMultiReturnType = decltype(
diff --git a/src/gui/kernel/qguivariant.cpp b/src/gui/kernel/qguivariant.cpp
index c6462dfed7b..6da0c4d387b 100644
--- a/src/gui/kernel/qguivariant.cpp
+++ b/src/gui/kernel/qguivariant.cpp
@@ -52,14 +52,13 @@
QT_BEGIN_NAMESPACE
namespace {
-
-// NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor): this is not a base class
struct QVariantGuiHelper : QMetaTypeModuleHelper
{
#define QT_IMPL_METATYPEINTERFACE_GUI_TYPES(MetaTypeName, MetaTypeId, RealName) \
QT_METATYPE_INTERFACE_INIT(RealName),
- const QtPrivate::QMetaTypeInterface *interfaceForType(int type) const override {
+ static const QtPrivate::QMetaTypeInterface *interfaceForType(int type)
+ {
switch (type) {
QT_FOR_EACH_STATIC_GUI_CLASS(QT_METATYPE_CONVERT_ID_TO_TYPE)
default: return nullptr;
@@ -67,7 +66,7 @@ struct QVariantGuiHelper : QMetaTypeModuleHelper
}
#undef QT_IMPL_METATYPEINTERFACE_GUI_TYPES
- bool convert(const void *from, int fromTypeId, void *to, int toTypeId) const override
+ static bool convert(const void *from, int fromTypeId, void *to, int toTypeId)
{
Q_ASSERT(fromTypeId != toTypeId);
@@ -133,14 +132,14 @@ struct QVariantGuiHelper : QMetaTypeModuleHelper
return false;
}
};
-
-static constexpr QVariantGuiHelper qVariantGuiHelper;
-
} // namespace used to hide QVariant handler
void qRegisterGuiVariant()
{
- qMetaTypeGuiHelper = &qVariantGuiHelper;
+ qMetaTypeGuiHelper = QMetaTypeModuleHelper{
+ &QVariantGuiHelper::interfaceForType,
+ &QVariantGuiHelper::convert,
+ };
}
Q_CONSTRUCTOR_FUNCTION(qRegisterGuiVariant)
diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp
index afe6de35305..caf4cb7fe5b 100644
--- a/src/gui/kernel/qscreen.cpp
+++ b/src/gui/kernel/qscreen.cpp
@@ -34,6 +34,12 @@ QT_BEGIN_NAMESPACE
\note Both physical and logical DPI are expressed in device-independent dots.
Multiply by QScreen::devicePixelRatio() to get device-dependent density.
+ To obtain a QScreen object, use QGuiApplication::primaryScreen() for the
+ primary screen, or QGuiApplication::screens() to get a list of all screens.
+
+ \sa QGuiApplication::primaryScreen()
+ \sa QGuiApplication::screens()
+
\inmodule QtGui
*/
diff --git a/src/gui/kernel/qtestsupport_gui.cpp b/src/gui/kernel/qtestsupport_gui.cpp
index ca62798ddfd..dfcea928fd8 100644
--- a/src/gui/kernel/qtestsupport_gui.cpp
+++ b/src/gui/kernel/qtestsupport_gui.cpp
@@ -24,8 +24,19 @@ QT_BEGIN_NAMESPACE
/*!
\since 5.0
+ \overload
- Returns \c true, if \a window is active within \a timeout milliseconds. Otherwise returns \c false.
+ The \a timeout is in milliseconds.
+*/
+bool QTest::qWaitForWindowActive(QWindow *window, int timeout)
+{
+ return qWaitForWindowActive(window, QDeadlineTimer{timeout, Qt::TimerType::PreciseTimer});
+}
+
+/*!
+ \since 6.10
+
+ Returns \c true, if \a window is active within \a timeout. Otherwise returns \c false.
The method is useful in tests that call QWindow::show() and rely on the window actually being
active (i.e. being visible and having focus) before proceeding.
@@ -38,7 +49,7 @@ QT_BEGIN_NAMESPACE
\sa qWaitForWindowExposed(), qWaitForWindowFocused(), QWindow::isActive()
*/
-Q_GUI_EXPORT bool QTest::qWaitForWindowActive(QWindow *window, int timeout)
+bool QTest::qWaitForWindowActive(QWindow *window, QDeadlineTimer timeout)
{
if (Q_UNLIKELY(!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))) {
qWarning() << "qWaitForWindowActive was called on a platform that doesn't support window"
@@ -52,6 +63,17 @@ Q_GUI_EXPORT bool QTest::qWaitForWindowActive(QWindow *window, int timeout)
}
/*!
+ \since 6.10
+ \overload
+
+ This function uses the default timeout of 5 seconds.
+*/
+bool QTest::qWaitForWindowActive(QWindow *window)
+{
+ return qWaitForWindowActive(window, Internal::defaultTryTimeout);
+}
+
+/*!
\since 6.7
Returns \c true, if \a window is the focus window within \a timeout. Otherwise returns \c false.
@@ -73,9 +95,31 @@ Q_GUI_EXPORT bool QTest::qWaitForWindowFocused(QWindow *window, QDeadlineTimer t
}
/*!
+ \since 6.10
+ \overload
+
+ This function uses the default timeout of 5 seconds.
+*/
+bool QTest::qWaitForWindowFocused(QWindow *window)
+{
+ return qWaitForWindowFocused(window, Internal::defaultTryTimeout);
+}
+
+/*!
\since 5.0
+ \overload
+
+ The \a timeout is in milliseconds.
+*/
+bool QTest::qWaitForWindowExposed(QWindow *window, int timeout)
+{
+ return qWaitForWindowExposed(window, std::chrono::milliseconds(timeout));
+}
- Returns \c true, if \a window is exposed within \a timeout milliseconds. Otherwise returns \c false.
+/*!
+ \since 6.10
+
+ Returns \c true, if \a window is exposed within \a timeout. Otherwise returns \c false.
The method is useful in tests that call QWindow::show() and rely on the window actually being
being visible before proceeding.
@@ -86,11 +130,22 @@ Q_GUI_EXPORT bool QTest::qWaitForWindowFocused(QWindow *window, QDeadlineTimer t
\sa qWaitForWindowActive(), QWindow::isExposed()
*/
-Q_GUI_EXPORT bool QTest::qWaitForWindowExposed(QWindow *window, int timeout)
+bool QTest::qWaitForWindowExposed(QWindow *window, QDeadlineTimer timeout)
{
return QTest::qWaitFor([&]() { return window->isExposed(); }, timeout);
}
+/*!
+ \since 6.10
+ \overload
+
+ This function uses the default timeout of 5 seconds.
+*/
+bool QTest::qWaitForWindowExposed(QWindow *window)
+{
+ return qWaitForWindowExposed(window, Internal::defaultTryTimeout);
+}
+
namespace QTest {
QTouchEventSequence::~QTouchEventSequence()
diff --git a/src/gui/kernel/qtestsupport_gui.h b/src/gui/kernel/qtestsupport_gui.h
index 951d9df1c7c..39278c2f034 100644
--- a/src/gui/kernel/qtestsupport_gui.h
+++ b/src/gui/kernel/qtestsupport_gui.h
@@ -23,12 +23,16 @@ Q_GUI_EXPORT bool qt_handleTouchEventv2(QWindow *w, const QPointingDevice *devic
namespace QTest {
-[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowActive(QWindow *window,
- int timeout = static_cast<int>(Internal::defaultTryTimeout.count()));
-[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowFocused(QWindow *window,
- QDeadlineTimer timeout = Internal::defaultTryTimeout);
-[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowExposed(QWindow *window,
- int timeout = static_cast<int>(Internal::defaultTryTimeout.count()));
+[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowActive(QWindow *window, int timeout);
+[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowActive(QWindow *window, QDeadlineTimer timeout);
+[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowActive(QWindow *window);
+
+[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowFocused(QWindow *window, QDeadlineTimer timeout);
+[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowFocused(QWindow *window);
+
+[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowExposed(QWindow *window, int timeout);
+[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowExposed(QWindow *window, QDeadlineTimer timeout);
+[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowExposed(QWindow *window);
Q_GUI_EXPORT QPointingDevice * createTouchDevice(QInputDevice::DeviceType devType = QInputDevice::DeviceType::TouchScreen,
QInputDevice::Capabilities caps = QInputDevice::Capability::Position);
diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp
index 66f1cf2a985..148d40b8361 100644
--- a/src/gui/painting/qtransform.cpp
+++ b/src/gui/painting/qtransform.cpp
@@ -784,7 +784,7 @@ bool QTransform::operator==(const QTransform &o) const
*/
size_t qHash(const QTransform &key, size_t seed) noexcept
{
- QtPrivate::QHashCombine hash(seed);
+ QtPrivate::QHashCombineWithSeed hash(seed);
seed = hash(seed, key.m11());
seed = hash(seed, key.m12());
seed = hash(seed, key.m21());
diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp
index b9312f6b304..7a3d4974e53 100644
--- a/src/gui/rhi/qrhi.cpp
+++ b/src/gui/rhi/qrhi.cpp
@@ -6543,7 +6543,7 @@ bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
size_t qHash(const QRhiShaderResourceBinding &b, size_t seed) noexcept
{
const QRhiShaderResourceBinding::Data *d = QRhiImplementation::shaderResourceBindingData(b);
- QtPrivate::QHashCombine hash(seed);
+ QtPrivate::QHashCombineWithSeed hash(seed);
seed = hash(seed, d->binding);
seed = hash(seed, d->stage);
seed = hash(seed, d->type);
diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp
index 5e967c62e40..1234d01b6ec 100644
--- a/src/gui/rhi/qshader.cpp
+++ b/src/gui/rhi/qshader.cpp
@@ -812,7 +812,7 @@ bool operator==(const QShader &lhs, const QShader &rhs) noexcept
size_t qHash(const QShader &s, size_t seed) noexcept
{
if (s.d) {
- QtPrivate::QHashCombine hash(seed);
+ QtPrivate::QHashCombineWithSeed hash(seed);
seed = hash(seed, s.stage());
if (!s.d->shaders.isEmpty()) {
seed = hash(seed, s.d->shaders.firstKey());
diff --git a/src/gui/text/qfontdatabase_p.h b/src/gui/text/qfontdatabase_p.h
index 4cd6996aab8..27fb34aecdd 100644
--- a/src/gui/text/qfontdatabase_p.h
+++ b/src/gui/text/qfontdatabase_p.h
@@ -51,7 +51,7 @@ inline bool operator!=(const QtFontFallbacksCacheKey &lhs, const QtFontFallbacks
inline size_t qHash(const QtFontFallbacksCacheKey &key, size_t seed = 0) noexcept
{
- QtPrivate::QHashCombine hash(seed);
+ QtPrivate::QHashCombineWithSeed hash(seed);
seed = hash(seed, key.family);
seed = hash(seed, int(key.style));
seed = hash(seed, int(key.styleHint));
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index 6949eec9560..b78d2829704 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -822,6 +822,12 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
recvResult = getsockopt(socketDescriptor, SOL_SOCKET, SO_NREAD, &value, &valuelen);
if (recvResult != -1)
recvResult = value;
+#elif defined(Q_OS_VXWORKS)
+ // VxWorks: use ioctl(FIONREAD) to query the number of bytes available
+ int available = 0;
+ int ioctlResult = ::ioctl(socketDescriptor, FIONREAD, &available);
+ if (ioctlResult != -1)
+ recvResult = available;
#else
// We need to grow the buffer to fit the entire datagram.
// We start at 1500 bytes (the MTU for Ethernet V2), which should catch
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
index 9f19e649f85..59265daa127 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmdevice.cpp
@@ -10,6 +10,7 @@
#include <private/qeglfskmsintegration_p.h>
#include <QtCore/QLoggingCategory>
+#include <QtCore/qtimer.h>
#include <QtCore/private/qcore_unix_p.h>
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 38b3bdadd35..3fe837a2c03 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -1219,6 +1219,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::FocusInEvent: // see QWindowsWindow::requestActivateWindow().
if (platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus)
return false;
+ [[fallthrough]];
case QtWindows::FocusOutEvent:
handleFocusEvent(et, platformWindow);
return true;
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 81a3f1d37b7..a4bb59cf42c 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -1191,6 +1191,11 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, const QRect &geometry,
bool QWindowsGeometryHint::handleCalculateSize(const QWindow *window, const QMargins &customMargins, const MSG &msg, LRESULT *result)
{
+ // Prevent adding any border for frameless window
+ if (msg.wParam && window->flags() & Qt::FramelessWindowHint) {
+ *result = 0;
+ return true;
+ }
// Return 0 to remove the window's border
const bool clientAreaExpanded = window->flags() & Qt::ExpandedClientAreaHint;
if (msg.wParam && clientAreaExpanded) {
diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp
index 3f40dea5eb9..e2e4fce357e 100644
--- a/src/plugins/styles/modernwindows/qwindows11style.cpp
+++ b/src/plugins/styles/modernwindows/qwindows11style.cpp
@@ -1662,128 +1662,123 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op
}
case CE_ItemViewItem: {
if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
- if (qobject_cast<const QAbstractItemView *>(widget)) {
- QRect checkRect = proxy()->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget);
- QRect iconRect = proxy()->subElementRect(SE_ItemViewItemDecoration, vopt, widget);
- QRect textRect = proxy()->subElementRect(SE_ItemViewItemText, vopt, widget);
+ QRect checkRect = proxy()->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget);
+ QRect iconRect = proxy()->subElementRect(SE_ItemViewItemDecoration, vopt, widget);
+ QRect textRect = proxy()->subElementRect(SE_ItemViewItemText, vopt, widget);
- // draw the background
- proxy()->drawPrimitive(PE_PanelItemViewItem, option, painter, widget);
+ // draw the background
+ proxy()->drawPrimitive(PE_PanelItemViewItem, option, painter, widget);
- const QRect &rect = vopt->rect;
- const bool isRtl = option->direction == Qt::RightToLeft;
- bool onlyOne = vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne ||
- vopt->viewItemPosition == QStyleOptionViewItem::Invalid;
- bool isFirst = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
- bool isLast = vopt->viewItemPosition == QStyleOptionViewItem::End;
+ const QRect &rect = vopt->rect;
+ const bool isRtl = option->direction == Qt::RightToLeft;
+ bool onlyOne = vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne ||
+ vopt->viewItemPosition == QStyleOptionViewItem::Invalid;
+ bool isFirst = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
+ bool isLast = vopt->viewItemPosition == QStyleOptionViewItem::End;
- // the tree decoration already painted the left side of the rounded rect
- if (vopt->features.testFlag(QStyleOptionViewItem::IsDecoratedRootColumn) &&
- vopt->showDecorationSelected) {
- isFirst = false;
- if (onlyOne) {
- onlyOne = false;
- isLast = true;
- }
+ // the tree decoration already painted the left side of the rounded rect
+ if (vopt->features.testFlag(QStyleOptionViewItem::IsDecoratedRootColumn) &&
+ vopt->showDecorationSelected) {
+ isFirst = false;
+ if (onlyOne) {
+ onlyOne = false;
+ isLast = true;
}
+ }
- if (isRtl) {
- if (isFirst) {
- isFirst = false;
- isLast = true;
- } else if (isLast) {
- isFirst = true;
- isLast = false;
- }
+ if (isRtl) {
+ if (isFirst) {
+ isFirst = false;
+ isLast = true;
+ } else if (isLast) {
+ isFirst = true;
+ isLast = false;
}
- const bool highlightCurrent = vopt->state.testAnyFlags(State_Selected | State_MouseOver);
- if (highlightCurrent) {
- const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget);
- if (highContrastTheme)
- painter->setBrush(vopt->palette.highlight());
- else
- painter->setBrush(view->alternatingRowColors() ? vopt->palette.highlight() : WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
- QWidget *editorWidget = view ? view->indexWidget(view->currentIndex()) : nullptr;
- if (editorWidget) {
- QPalette pal = editorWidget->palette();
- QColor editorBgColor = vopt->backgroundBrush == Qt::NoBrush ? vopt->palette.color(widget->backgroundRole()) : vopt->backgroundBrush.color();
- editorBgColor.setAlpha(255);
- pal.setColor(editorWidget->backgroundRole(), editorBgColor);
- editorWidget->setPalette(pal);
- }
- } else {
- painter->setBrush(vopt->backgroundBrush);
+ }
+ const bool highlightCurrent = vopt->state.testAnyFlags(State_Selected | State_MouseOver);
+ if (highlightCurrent) {
+ const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget);
+ if (highContrastTheme)
+ painter->setBrush(vopt->palette.highlight());
+ else
+ painter->setBrush(view->alternatingRowColors() ? vopt->palette.highlight() : WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ QWidget *editorWidget = view ? view->indexWidget(view->currentIndex()) : nullptr;
+ if (editorWidget) {
+ QPalette pal = editorWidget->palette();
+ QColor editorBgColor = vopt->backgroundBrush == Qt::NoBrush ? vopt->palette.color(widget->backgroundRole()) : vopt->backgroundBrush.color();
+ editorBgColor.setAlpha(255);
+ pal.setColor(editorWidget->backgroundRole(), editorBgColor);
+ editorWidget->setPalette(pal);
}
- painter->setPen(Qt::NoPen);
+ } else {
+ painter->setBrush(vopt->backgroundBrush);
+ }
+ painter->setPen(Qt::NoPen);
- if (onlyOne) {
- painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, 2, 2)),
- secondLevelRoundingRadius, secondLevelRoundingRadius);
- } else if (isFirst) {
- painter->save();
- painter->setClipRect(rect);
- painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)),
- secondLevelRoundingRadius, secondLevelRoundingRadius);
- painter->restore();
- } else if (isLast) {
- painter->save();
- painter->setClipRect(rect);
- painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)),
- secondLevelRoundingRadius, secondLevelRoundingRadius);
- painter->restore();
- } else {
- painter->drawRect(rect.marginsRemoved(QMargins(0, 2, 0, 2)));
- }
+ if (onlyOne) {
+ painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, 2, 2)),
+ secondLevelRoundingRadius, secondLevelRoundingRadius);
+ } else if (isFirst) {
+ painter->save();
+ painter->setClipRect(rect);
+ painter->drawRoundedRect(rect.marginsRemoved(QMargins(2, 2, -secondLevelRoundingRadius, 2)),
+ secondLevelRoundingRadius, secondLevelRoundingRadius);
+ painter->restore();
+ } else if (isLast) {
+ painter->save();
+ painter->setClipRect(rect);
+ painter->drawRoundedRect(rect.marginsRemoved(QMargins(-secondLevelRoundingRadius, 2, 2, 2)),
+ secondLevelRoundingRadius, secondLevelRoundingRadius);
+ painter->restore();
+ } else {
+ painter->drawRect(rect.marginsRemoved(QMargins(0, 2, 0, 2)));
+ }
- // draw the check mark
- if (vopt->features & QStyleOptionViewItem::HasCheckIndicator) {
- QStyleOptionViewItem option(*vopt);
- option.rect = checkRect;
- option.state = option.state & ~QStyle::State_HasFocus;
+ // draw the check mark
+ if (vopt->features & QStyleOptionViewItem::HasCheckIndicator) {
+ QStyleOptionViewItem option(*vopt);
+ option.rect = checkRect;
+ option.state = option.state & ~QStyle::State_HasFocus;
- switch (vopt->checkState) {
- case Qt::Unchecked:
- option.state |= QStyle::State_Off;
- break;
- case Qt::PartiallyChecked:
- option.state |= QStyle::State_NoChange;
- break;
- case Qt::Checked:
- option.state |= QStyle::State_On;
- break;
- }
- proxy()->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &option, painter, widget);
+ switch (vopt->checkState) {
+ case Qt::Unchecked:
+ option.state |= QStyle::State_Off;
+ break;
+ case Qt::PartiallyChecked:
+ option.state |= QStyle::State_NoChange;
+ break;
+ case Qt::Checked:
+ option.state |= QStyle::State_On;
+ break;
}
+ proxy()->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &option, painter, widget);
+ }
- // draw the icon
- QIcon::Mode mode = QIcon::Normal;
- if (!(vopt->state & QStyle::State_Enabled))
- mode = QIcon::Disabled;
- else if (vopt->state & QStyle::State_Selected)
- mode = QIcon::Selected;
- QIcon::State state = vopt->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
- vopt->icon.paint(painter, iconRect, vopt->decorationAlignment, mode, state);
-
- painter->setPen(highlightCurrent && highContrastTheme ? vopt->palette.base().color()
- : vopt->palette.text().color());
- d->viewItemDrawText(painter, vopt, textRect);
-
- // paint a vertical marker for QListView
- if (vopt->state & State_Selected) {
- if (const QListView *lv = qobject_cast<const QListView *>(widget);
- lv && lv->viewMode() != QListView::IconMode && !highContrastTheme) {
- painter->setPen(vopt->palette.accent().color());
- const auto xPos = isRtl ? rect.right() - 1 : rect.left();
- const QLineF lines[2] = {
- QLineF(xPos, rect.y() + 2, xPos, rect.y() + rect.height() - 2),
- QLineF(xPos + 1, rect.y() + 2, xPos + 1, rect.y() + rect.height() - 2),
- };
- painter->drawLines(lines, 2);
- }
+ // draw the icon
+ QIcon::Mode mode = QIcon::Normal;
+ if (!(vopt->state & QStyle::State_Enabled))
+ mode = QIcon::Disabled;
+ else if (vopt->state & QStyle::State_Selected)
+ mode = QIcon::Selected;
+ QIcon::State state = vopt->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
+ vopt->icon.paint(painter, iconRect, vopt->decorationAlignment, mode, state);
+
+ painter->setPen(highlightCurrent && highContrastTheme ? vopt->palette.base().color()
+ : vopt->palette.text().color());
+ d->viewItemDrawText(painter, vopt, textRect);
+
+ // paint a vertical marker for QListView
+ if (vopt->state & State_Selected) {
+ if (const QListView *lv = qobject_cast<const QListView *>(widget);
+ lv && lv->viewMode() != QListView::IconMode && !highContrastTheme) {
+ painter->setPen(vopt->palette.accent().color());
+ const auto xPos = isRtl ? rect.right() - 1 : rect.left();
+ const QLineF lines[2] = {
+ QLineF(xPos, rect.y() + 2, xPos, rect.y() + rect.height() - 2),
+ QLineF(xPos + 1, rect.y() + 2, xPos + 1, rect.y() + rect.height() - 2),
+ };
+ painter->drawLines(lines, 2);
}
- } else {
- QRect textRect = proxy()->subElementRect(SE_ItemViewItemText, vopt, widget);
- d->viewItemDrawText(painter, vopt, textRect);
}
}
break;
@@ -2217,8 +2212,9 @@ void QWindows11Style::polish(QWidget* widget)
pal.setColor(scrollarea->viewport()->backgroundRole(), Qt::transparent);
scrollarea->viewport()->setPalette(pal);
scrollarea->viewport()->setProperty("_q_original_background_palette", originalPalette);
- if (qobject_cast<QTableView *>(widget))
- widget->setAttribute(Qt::WA_Hover, true);
+ // QTreeView & QListView are already set in the base windowsvista style
+ if (auto table = qobject_cast<QTableView *>(widget))
+ table->viewport()->setAttribute(Qt::WA_Hover, true);
}
}
diff --git a/src/sql/models/qsqlquerymodel.cpp b/src/sql/models/qsqlquerymodel.cpp
index 6f4611d9139..d8e10343854 100644
--- a/src/sql/models/qsqlquerymodel.cpp
+++ b/src/sql/models/qsqlquerymodel.cpp
@@ -561,9 +561,9 @@ QSqlError QSqlQueryModel::lastError() const
\sa lastError()
*/
-void QSqlQueryModel::setLastError(const QSqlError &error) const
+void QSqlQueryModel::setLastError(const QSqlError &error)
{
- Q_D(const QSqlQueryModel);
+ Q_D(QSqlQueryModel);
d->error = error;
}
diff --git a/src/sql/models/qsqlquerymodel.h b/src/sql/models/qsqlquerymodel.h
index 24877118865..72b9b053f03 100644
--- a/src/sql/models/qsqlquerymodel.h
+++ b/src/sql/models/qsqlquerymodel.h
@@ -79,7 +79,7 @@ protected:
virtual void queryChange();
virtual QModelIndex indexInQuery(const QModelIndex &item) const;
- void setLastError(const QSqlError &error) const;
+ void setLastError(const QSqlError &error);
QSqlQueryModel(QSqlQueryModelPrivate &dd, QObject *parent = nullptr);
};
diff --git a/src/testlib/3rdparty/valgrind/qt_attribution.json b/src/testlib/3rdparty/valgrind/qt_attribution.json
index 3146fd82c57..262bc8380b4 100644
--- a/src/testlib/3rdparty/valgrind/qt_attribution.json
+++ b/src/testlib/3rdparty/valgrind/qt_attribution.json
@@ -11,7 +11,7 @@
"Description": "An instrumentation framework for building dynamic analysis tools.",
"Homepage": "http://valgrind.org/",
- "Version": "3.24.0",
+ "Version": "3.25.1",
"PURL": "pkg:generic/valgrind@$<VERSION>?download_url=https://valgrind.org/",
"License": "BSD 4-clause \"Original\" or \"Old\" License",
"LicenseId": "BSD-4-Clause",
diff --git a/src/testlib/3rdparty/valgrind/valgrind_p.h b/src/testlib/3rdparty/valgrind/valgrind_p.h
index 77ca3ad8692..ab49937ccd4 100644
--- a/src/testlib/3rdparty/valgrind/valgrind_p.h
+++ b/src/testlib/3rdparty/valgrind/valgrind_p.h
@@ -89,7 +89,7 @@
|| (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6))
*/
#define __VALGRIND_MAJOR__ 3
-#define __VALGRIND_MINOR__ 24
+#define __VALGRIND_MINOR__ 25
#include <stdarg.h>
@@ -126,6 +126,7 @@
#undef PLAT_mips32_linux
#undef PLAT_mips64_linux
#undef PLAT_nanomips_linux
+#undef PLAT_riscv64_linux
#undef PLAT_x86_solaris
#undef PLAT_amd64_solaris
@@ -172,6 +173,8 @@
# define PLAT_mips32_linux 1
#elif defined(__linux__) && defined(__nanomips__)
# define PLAT_nanomips_linux 1
+#elif defined(__linux__) && defined(__riscv) && (__riscv_xlen == 64)
+# define PLAT_riscv64_linux 1
#elif defined(__sun) && defined(__i386__)
# define PLAT_x86_solaris 1
#elif defined(__sun) && defined(__x86_64__)
@@ -1129,6 +1132,87 @@ typedef
} while (0)
#endif
+
+/* ----------------------- riscv64-linux ------------------------ */
+
+#if defined(PLAT_riscv64_linux)
+
+typedef
+ struct {
+ unsigned long int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ ".option push\n\t" \
+ ".option norvc\n\t" \
+ "srli zero, zero, 3\n\t" \
+ "srli zero, zero, 13\n\t" \
+ "srli zero, zero, 51\n\t" \
+ "srli zero, zero, 61\n\t"
+
+#define __SPECIAL_INSTRUCTION_POSTAMBLE \
+ ".option pop\n\t" \
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ \
+ __extension__ \
+ ({volatile unsigned long int _zzq_args[6]; \
+ volatile unsigned long int _zzq_result; \
+ _zzq_args[0] = (unsigned long int)(_zzq_request); \
+ _zzq_args[1] = (unsigned long int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned long int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned long int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned long int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned long int)(_zzq_arg5); \
+ __asm__ volatile("mv a3, %1\n\t" /*default*/ \
+ "mv a4, %2\n\t" /*ptr*/ \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* a3 = client_request ( a4 ) */ \
+ "or a0, a0, a0\n\t" \
+ __SPECIAL_INSTRUCTION_POSTAMBLE \
+ "mv %0, a3" /*result*/ \
+ : "=r" (_zzq_result) \
+ : "r" ((unsigned long int)(_zzq_default)), \
+ "r" (&_zzq_args[0]) \
+ : "memory", "a3", "a4"); \
+ _zzq_result; \
+ })
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ unsigned long int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* a3 = guest_NRADDR */ \
+ "or a1, a1, a1\n\t" \
+ __SPECIAL_INSTRUCTION_POSTAMBLE \
+ "mv %0, a3" \
+ : "=r" (__addr) \
+ : \
+ : "memory", "a3" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_T0 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* branch-and-link-to-noredir t0 */ \
+ "or a2, a2, a2\n\t" \
+ __SPECIAL_INSTRUCTION_POSTAMBLE
+
+#define VALGRIND_VEX_INJECT_IR() \
+ do { \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ "or a3, a3, a3\n\t" \
+ __SPECIAL_INSTRUCTION_POSTAMBLE \
+ : : : "memory" \
+ ); \
+ } while (0)
+
+#endif /* PLAT_riscv64_linux */
+
/* Insert assembly code for other platforms here... */
#endif /* NVALGRIND */
@@ -6606,6 +6690,456 @@ typedef
#endif /* PLAT_mips64_linux */
+/* ----------------------- riscv64-linux ----------------------- */
+
+#if defined(PLAT_riscv64_linux)
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS \
+ "ra", \
+ "t0", "t1", "t2", "t3", "t4", "t5", "t6", \
+ "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", \
+ "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", \
+ "ft8", "ft9", "ft10", "ft11", \
+ "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6", "fa7"
+
+/* s11 is callee-saved, so we can use it to save and restore sp around
+ the hidden call. */
+#define VALGRIND_ALIGN_STACK \
+ "mv s11, sp\n\t" \
+ "andi sp, sp, 0xfffffffffffffff0\n\t"
+#define VALGRIND_RESTORE_STACK \
+ "mv sp, s11\n\t"
+
+/* These CALL_FN_ macros assume that on riscv64-linux,
+ sizeof(unsigned long) == 8. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ld t0, 0(%1) \n\t" /* target->t0 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_T0 \
+ VALGRIND_RESTORE_STACK \
+ "mv %0, a0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS, "s11" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ld a0, 8(%1) \n\t" \
+ "ld t0, 0(%1) \n\t" /* target->t0 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_T0 \
+ VALGRIND_RESTORE_STACK \
+ "mv %0, a0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS, "s11" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ld a0, 8(%1) \n\t" \
+ "ld a1, 16(%1) \n\t" \
+ "ld t0, 0(%1) \n\t" /* target->t0 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_T0 \
+ VALGRIND_RESTORE_STACK \
+ "mv %0, a0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS, "s11" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ld a0, 8(%1) \n\t" \
+ "ld a1, 16(%1) \n\t" \
+ "ld a2, 24(%1) \n\t" \
+ "ld t0, 0(%1) \n\t" /* target->t0 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_T0 \
+ VALGRIND_RESTORE_STACK \
+ "mv %0, a0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS, "s11" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ld a0, 8(%1) \n\t" \
+ "ld a1, 16(%1) \n\t" \
+ "ld a2, 24(%1) \n\t" \
+ "ld a3, 32(%1) \n\t" \
+ "ld t0, 0(%1) \n\t" /* target->t0 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_T0 \
+ VALGRIND_RESTORE_STACK \
+ "mv %0, a0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS, "s11" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ld a0, 8(%1) \n\t" \
+ "ld a1, 16(%1) \n\t" \
+ "ld a2, 24(%1) \n\t" \
+ "ld a3, 32(%1) \n\t" \
+ "ld a4, 40(%1) \n\t" \
+ "ld t0, 0(%1) \n\t" /* target->t0 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_T0 \
+ VALGRIND_RESTORE_STACK \
+ "mv %0, a0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS, "s11" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ld a0, 8(%1) \n\t" \
+ "ld a1, 16(%1) \n\t" \
+ "ld a2, 24(%1) \n\t" \
+ "ld a3, 32(%1) \n\t" \
+ "ld a4, 40(%1) \n\t" \
+ "ld a5, 48(%1) \n\t" \
+ "ld t0, 0(%1) \n\t" /* target->t0 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_T0 \
+ VALGRIND_RESTORE_STACK \
+ "mv %0, a0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS, "s11" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ld a0, 8(%1) \n\t" \
+ "ld a1, 16(%1) \n\t" \
+ "ld a2, 24(%1) \n\t" \
+ "ld a3, 32(%1) \n\t" \
+ "ld a4, 40(%1) \n\t" \
+ "ld a5, 48(%1) \n\t" \
+ "ld a6, 56(%1) \n\t" \
+ "ld t0, 0(%1) \n\t" /* target->t0 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_T0 \
+ VALGRIND_RESTORE_STACK \
+ "mv %0, a0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS, "s11" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "ld a0, 8(%1) \n\t" \
+ "ld a1, 16(%1) \n\t" \
+ "ld a2, 24(%1) \n\t" \
+ "ld a3, 32(%1) \n\t" \
+ "ld a4, 40(%1) \n\t" \
+ "ld a5, 48(%1) \n\t" \
+ "ld a6, 56(%1) \n\t" \
+ "ld a7, 64(%1) \n\t" \
+ "ld t0, 0(%1) \n\t" /* target->t0 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_T0 \
+ VALGRIND_RESTORE_STACK \
+ "mv %0, a0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS, "s11" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "addi sp, sp, -16 \n\t" \
+ "ld a0, 8(%1) \n\t" \
+ "ld a1, 16(%1) \n\t" \
+ "ld a2, 24(%1) \n\t" \
+ "ld a3, 32(%1) \n\t" \
+ "ld a4, 40(%1) \n\t" \
+ "ld a5, 48(%1) \n\t" \
+ "ld a6, 56(%1) \n\t" \
+ "ld a7, 64(%1) \n\t" \
+ "ld t0, 72(%1) \n\t" \
+ "sd t0, 0(sp) \n\t" \
+ "ld t0, 0(%1) \n\t" /* target->t0 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_T0 \
+ VALGRIND_RESTORE_STACK \
+ "mv %0, a0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS, "s11" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "addi sp, sp, -16 \n\t" \
+ "ld a0, 8(%1) \n\t" \
+ "ld a1, 16(%1) \n\t" \
+ "ld a2, 24(%1) \n\t" \
+ "ld a3, 32(%1) \n\t" \
+ "ld a4, 40(%1) \n\t" \
+ "ld a5, 48(%1) \n\t" \
+ "ld a6, 56(%1) \n\t" \
+ "ld a7, 64(%1) \n\t" \
+ "ld t0, 72(%1) \n\t" \
+ "sd t0, 0(sp) \n\t" \
+ "ld t0, 80(%1) \n\t" \
+ "sd t0, 8(sp) \n\t" \
+ "ld t0, 0(%1) \n\t" /* target->t0 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_T0 \
+ VALGRIND_RESTORE_STACK \
+ "mv %0, a0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS, "s11" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "addi sp, sp, -32 \n\t" \
+ "ld a0, 8(%1) \n\t" \
+ "ld a1, 16(%1) \n\t" \
+ "ld a2, 24(%1) \n\t" \
+ "ld a3, 32(%1) \n\t" \
+ "ld a4, 40(%1) \n\t" \
+ "ld a5, 48(%1) \n\t" \
+ "ld a6, 56(%1) \n\t" \
+ "ld a7, 64(%1) \n\t" \
+ "ld t0, 72(%1) \n\t" \
+ "sd t0, 0(sp) \n\t" \
+ "ld t0, 80(%1) \n\t" \
+ "sd t0, 8(sp) \n\t" \
+ "ld t0, 88(%1) \n\t" \
+ "sd t0, 16(sp) \n\t" \
+ "ld t0, 0(%1) \n\t" /* target->t0 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_T0 \
+ VALGRIND_RESTORE_STACK \
+ "mv %0, a0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS, "s11" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11, \
+ arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ _argvec[12] = (unsigned long)(arg12); \
+ __asm__ volatile( \
+ VALGRIND_ALIGN_STACK \
+ "addi sp, sp, -32 \n\t" \
+ "ld a0, 8(%1) \n\t" \
+ "ld a1, 16(%1) \n\t" \
+ "ld a2, 24(%1) \n\t" \
+ "ld a3, 32(%1) \n\t" \
+ "ld a4, 40(%1) \n\t" \
+ "ld a5, 48(%1) \n\t" \
+ "ld a6, 56(%1) \n\t" \
+ "ld a7, 64(%1) \n\t" \
+ "ld t0, 72(%1) \n\t" \
+ "sd t0, 0(sp) \n\t" \
+ "ld t0, 80(%1) \n\t" \
+ "sd t0, 8(sp) \n\t" \
+ "ld t0, 88(%1) \n\t" \
+ "sd t0, 16(sp) \n\t" \
+ "ld t0, 96(%1) \n\t" \
+ "sd t0, 24(sp) \n\t" \
+ "ld t0, 0(%1) \n\t" /* target->t0 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_T0 \
+ VALGRIND_RESTORE_STACK \
+ "mv %0, a0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "memory", __CALLER_SAVED_REGS, "s11" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_riscv64_linux */
+
/* ------------------------------------------------------------------ */
/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */
/* */
@@ -7162,6 +7696,7 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
#undef PLAT_mips32_linux
#undef PLAT_mips64_linux
#undef PLAT_nanomips_linux
+#undef PLAT_riscv64_linux
#undef PLAT_x86_solaris
#undef PLAT_amd64_solaris
diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp
index e93c3038fca..a27c52f5a99 100644
--- a/src/tools/androiddeployqt/main.cpp
+++ b/src/tools/androiddeployqt/main.cpp
@@ -1475,10 +1475,23 @@ bool readInputFile(Options *options)
for (const QJsonValue &value : permissions) {
if (value.isObject()) {
QJsonObject permissionObj = value.toObject();
- QString name = permissionObj.value("name"_L1).toString();
+ QString name;
QString extras;
- if (permissionObj.contains("extras"_L1))
- extras = permissionObj.value("extras"_L1).toString().trimmed();
+ for (auto it = permissionObj.begin(); it != permissionObj.end(); ++it) {
+ if (it.key() == "name"_L1) {
+ name = it.value().toString();
+ } else {
+ extras.append(" android:"_L1)
+ .append(it.key())
+ .append("=\""_L1)
+ .append(it.value().toString())
+ .append("\""_L1);
+ }
+ }
+ if (name.isEmpty()) {
+ fprintf(stderr, "Missing permission 'name' in permission specification");
+ return false;
+ }
options->applicationPermissions.insert(name, extras);
}
}
@@ -1580,8 +1593,11 @@ bool copyAndroidTemplate(const Options &options)
if (options.verbose)
fprintf(stdout, "Copying Android package template.\n");
- if (!copyGradleTemplate(options))
- return false;
+ if (!options.auxMode) {
+ // Gradle is not configured and is not running in aux mode
+ if (!copyGradleTemplate(options))
+ return false;
+ }
if (!copyAndroidTemplate(options, "/src/android/templates"_L1))
return false;
diff --git a/src/tools/androidtestrunner/main.cpp b/src/tools/androidtestrunner/main.cpp
index eb4c84fbd75..564a332c091 100644
--- a/src/tools/androidtestrunner/main.cpp
+++ b/src/tools/androidtestrunner/main.cpp
@@ -40,6 +40,7 @@ struct Options
QString buildPath;
QString manifestPath;
QString adbCommand{"adb"_L1};
+ QString bundletoolPath;
QString serial;
QString makeCommand;
QString package;
@@ -48,7 +49,7 @@ struct Options
QString stdoutFileName;
QHash<QString, QString> outFiles;
QStringList amStarttestArgs;
- QString apkPath;
+ QString packagePath;
QString ndkStackPath;
QList<QStringList> preTestRunAdbCommands;
bool showLogcatOutput = false;
@@ -114,6 +115,24 @@ static bool execAdbCommand(const QStringList &args, QByteArray *output = nullptr
return execCommand(g_options.adbCommand, argsWithSerial, output, verbose);
}
+static bool execBundletoolCommand(const QStringList &args, QByteArray *output = nullptr,
+ bool verbose = true)
+{
+ QString java("java"_L1);
+ QStringList argsFull = QStringList() << "-jar"_L1 << g_options.bundletoolPath << args;
+ return execCommand(java, argsFull, output, verbose);
+}
+
+static void setPackagePath(const QString &path)
+{
+ if (!g_options.packagePath.isEmpty()) {
+ qCritical("Both --aab and --apk options provided. This is not supported.");
+ g_options.helpRequested = true;
+ return;
+ }
+ g_options.packagePath = path;
+}
+
static bool execCommand(const QString &command, QByteArray *output = nullptr, bool verbose = true)
{
auto args = QProcess::splitCommand(command);
@@ -133,6 +152,11 @@ static bool parseOptions()
g_options.helpRequested = true;
else
g_options.adbCommand = arguments.at(++i);
+ } else if (argument.compare("--bundletool"_L1, Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ g_options.helpRequested = true;
+ else
+ g_options.bundletoolPath = arguments.at(++i);
} else if (argument.compare("--path"_L1, Qt::CaseInsensitive) == 0) {
if (i + 1 == arguments.size())
g_options.helpRequested = true;
@@ -152,7 +176,12 @@ static bool parseOptions()
if (i + 1 == arguments.size())
g_options.helpRequested = true;
else
- g_options.apkPath = arguments.at(++i);
+ setPackagePath(arguments.at(++i));
+ } else if (argument.compare("--aab"_L1, Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ g_options.helpRequested = true;
+ else
+ setPackagePath(arguments.at(++i));
} else if (argument.compare("--activity"_L1, Qt::CaseInsensitive) == 0) {
if (i + 1 == arguments.size())
g_options.helpRequested = true;
@@ -200,7 +229,7 @@ static bool parseOptions()
for (;i < arguments.size(); ++i)
g_options.testArgsList << arguments.at(i);
- if (g_options.helpRequested || g_options.buildPath.isEmpty() || g_options.apkPath.isEmpty())
+ if (g_options.helpRequested || g_options.buildPath.isEmpty() || g_options.packagePath.isEmpty())
return false;
g_options.serial = qEnvironmentVariable("ANDROID_SERIAL");
@@ -222,52 +251,57 @@ static bool parseOptions()
static void printHelp()
{
- qWarning( "Syntax: %s <options> -- [TESTARGS] \n"
- "\n"
- " Runs a Qt for Android test on an emulator or a device. Specify a device\n"
- " using the environment variables ANDROID_SERIAL or ANDROID_DEVICE_SERIAL.\n"
- " Returns the number of failed tests, -1 on test runner deployment related\n"
- " failures or zero on success."
- "\n"
- " Mandatory arguments:\n"
- " --path <path>: The path where androiddeployqt builds the android package.\n"
- "\n"
- " --make <make cmd>: make command to create an APK, for example:\n"
- " \"cmake --build <build-dir> --target <target>_make_apk\".\n"
- "\n"
- " --apk <apk path>: The test apk path. The apk has to exist already, if it\n"
- " does not exist the make command must be provided for building the apk.\n"
- "\n"
- " Optional arguments:\n"
- " --adb <adb cmd>: The Android ADB command. If missing the one from\n"
- " $PATH will be used.\n"
- "\n"
- " --activity <acitvity>: The Activity to run. If missing the first\n"
- " activity from AndroidManifest.qml file will be used.\n"
- "\n"
- " --timeout <seconds>: Timeout to run the test. Default is 10 minutes.\n"
- "\n"
- " --skip-install-root: Do not append INSTALL_ROOT=... to the make command.\n"
- "\n"
- " --show-logcat: Print Logcat output to stdout. If an ANR occurs during\n"
- " the test run, logs from the system_server process are included.\n"
- " This argument is implied if a test crashes.\n"
- "\n"
- " --ndk-stack: Path to ndk-stack tool that symbolizes crash stacktraces.\n"
- " By default, ANDROID_NDK_ROOT env var is used to deduce the tool path.\n"
- "\n"
- " -- Arguments that will be passed to the test application.\n"
- "\n"
- " --verbose: Prints out information during processing.\n"
- "\n"
- " --pre-test-adb-command <command>: call the adb <command> after\n"
- " installation and before the test run.\n"
- "\n"
- " --manifest <path>: Custom path to the AndroidManifest.xml.\n"
- "\n"
- " --help: Displays this information.\n",
- qPrintable(QCoreApplication::arguments().at(0))
- );
+ qWarning("Syntax: %s <options> -- [TESTARGS] \n"
+ "\n"
+ " Runs a Qt for Android test on an emulator or a device. Specify a device\n"
+ " using the environment variables ANDROID_SERIAL or ANDROID_DEVICE_SERIAL.\n"
+ " Returns the number of failed tests, -1 on test runner deployment related\n"
+ " failures or zero on success."
+ "\n"
+ " Mandatory arguments:\n"
+ " --path <path>: The path where androiddeployqt builds the android package.\n"
+ "\n"
+ " --make <make cmd>: make command to create an APK, for example:\n"
+ " \"cmake --build <build-dir> --target <target>_make_apk\".\n"
+ "\n"
+ " --apk <apk path>: The test apk path. The apk has to exist already, if it\n"
+ " does not exist the make command must be provided for building the apk.\n"
+ "\n"
+ " --aab <aab path>: The test aab path. The aab has to exist already, if it\n"
+ " does not exist the make command must be provided for building the aab.\n"
+ "\n"
+ " Optional arguments:\n"
+ " --adb <adb cmd>: The Android ADB command. If missing the one from\n"
+ " $PATH will be used.\n"
+ "\n"
+ " --activity <acitvity>: The Activity to run. If missing the first\n"
+ " activity from AndroidManifest.qml file will be used.\n"
+ "\n"
+ " --timeout <seconds>: Timeout to run the test. Default is 10 minutes.\n"
+ "\n"
+ " --skip-install-root: Do not append INSTALL_ROOT=... to the make command.\n"
+ "\n"
+ " --show-logcat: Print Logcat output to stdout. If an ANR occurs during\n"
+ " the test run, logs from the system_server process are included.\n"
+ " This argument is implied if a test crashes.\n"
+ "\n"
+ " --ndk-stack: Path to ndk-stack tool that symbolizes crash stacktraces.\n"
+ " By default, ANDROID_NDK_ROOT env var is used to deduce the tool path.\n"
+ "\n"
+ " -- Arguments that will be passed to the test application.\n"
+ "\n"
+ " --verbose: Prints out information during processing.\n"
+ "\n"
+ " --pre-test-adb-command <command>: call the adb <command> after\n"
+ " installation and before the test run.\n"
+ "\n"
+ " --manifest <path>: Custom path to the AndroidManifest.xml.\n"
+ "\n"
+ " --bundletool <bundletool path>: The path to Android bundletool.\n"
+ " See https://developer.android.com/tools/bundletool for details.\n"
+ "\n"
+ " --help: Displays this information.\n",
+ qPrintable(QCoreApplication::arguments().at(0)));
}
static QString packageNameFromAndroidManifest(const QString &androidManifestPath)
@@ -850,10 +884,10 @@ int main(int argc, char *argv[])
return EXIT_ERROR;
}
- if (!QFile::exists(g_options.apkPath)) {
+ if (!QFile::exists(g_options.packagePath)) {
qCritical("No apk \"%s\" found after running the make command. "
"Check the provided path and the make command.",
- qPrintable(g_options.apkPath));
+ qPrintable(g_options.packagePath));
return EXIT_ERROR;
}
@@ -886,11 +920,22 @@ int main(int argc, char *argv[])
// do not install or run packages while another test is running
testRunnerLock.acquire();
- const QStringList installArgs = { "install"_L1, "-r"_L1, "-g"_L1, g_options.apkPath };
- g_testInfo.isPackageInstalled.store(execAdbCommand(installArgs, nullptr));
- if (!g_testInfo.isPackageInstalled)
- return EXIT_ERROR;
+ if (g_options.packagePath.endsWith(".apk"_L1)) {
+ const QStringList installArgs = { "install"_L1, "-r"_L1, "-g"_L1, g_options.packagePath };
+ g_testInfo.isPackageInstalled.store(execAdbCommand(installArgs, nullptr));
+ if (!g_testInfo.isPackageInstalled)
+ return EXIT_ERROR;
+ } else if (g_options.packagePath.endsWith(".aab"_L1)) {
+ QFileInfo aab(g_options.packagePath);
+ const auto apksFilePath = aab.absoluteDir().absoluteFilePath(aab.baseName() + ".apks"_L1);
+ if (!execBundletoolCommand({ "build-apks"_L1, "--bundle"_L1, g_options.packagePath,
+ "--output"_L1, apksFilePath, "--local-testing"_L1,
+ "--overwrite"_L1 }))
+ return EXIT_ERROR;
+ if (!execBundletoolCommand({ "install-apks"_L1, "--apks"_L1, apksFilePath }))
+ return EXIT_ERROR;
+ }
// Call additional adb command if set after installation and before starting the test
for (const auto &command : g_options.preTestRunAdbCommands) {
QByteArray output;
diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp
index b2fa08e406f..06912d41582 100644
--- a/src/widgets/itemviews/qheaderview.cpp
+++ b/src/widgets/itemviews/qheaderview.cpp
@@ -3671,10 +3671,8 @@ void QHeaderViewPrivate::resizeSections(QHeaderView::ResizeMode globalMode, bool
executePostedLayout();
- if (noSectionMemoryUsage() &&
- (hasAutoResizeSections() || (useGlobalMode && globalResizeMode != QHeaderView::Fixed))) {
+ if (noSectionMemoryUsage() && (hasAutoResizeSections() || globalMode != QHeaderView::Fixed))
setHeaderMode(HeaderMode::FlexibleWithSectionMemoryUsage);
- }
if (sectionCount() == 0 )
return;
diff --git a/src/widgets/kernel/qtestsupport_widgets.cpp b/src/widgets/kernel/qtestsupport_widgets.cpp
index 5a7200e58aa..ce40ba8c6dd 100644
--- a/src/widgets/kernel/qtestsupport_widgets.cpp
+++ b/src/widgets/kernel/qtestsupport_widgets.cpp
@@ -31,6 +31,17 @@ static bool qWaitForWidgetWindow(QWidget *w, Predicate predicate, QDeadlineTimer
/*!
\since 5.0
+ \overload
+
+ The \a timeout is in milliseconds.
+*/
+bool QTest::qWaitForWindowActive(QWidget *widget, int timeout)
+{
+ return qWaitForWindowActive(widget, QDeadlineTimer{timeout, Qt::TimerType::PreciseTimer});
+}
+
+/*!
+ \since 6.10
Returns \c true if \a widget is active within \a timeout milliseconds. Otherwise returns \c false.
@@ -45,7 +56,7 @@ static bool qWaitForWidgetWindow(QWidget *w, Predicate predicate, QDeadlineTimer
\sa qWaitForWindowExposed(), QWidget::isActiveWindow()
*/
-Q_WIDGETS_EXPORT bool QTest::qWaitForWindowActive(QWidget *widget, int timeout)
+bool QTest::qWaitForWindowActive(QWidget *widget, QDeadlineTimer timeout)
{
if (Q_UNLIKELY(!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))) {
qWarning() << "qWaitForWindowActive was called on a platform that doesn't support window"
@@ -57,9 +68,19 @@ Q_WIDGETS_EXPORT bool QTest::qWaitForWindowActive(QWidget *widget, int timeout)
}
return qWaitForWidgetWindow(widget,
[&](QWindow *window) { return window->isActive(); },
- QDeadlineTimer{timeout, Qt::TimerType::PreciseTimer});
+ timeout);
}
+/*!
+ \since 6.10
+ \overload
+
+ This function uses the default timeout of 5 seconds.
+*/
+bool QTest::qWaitForWindowActive(QWidget *widget)
+{
+ return qWaitForWindowActive(widget, Internal::defaultTryTimeout);
+}
/*!
\since 6.7
@@ -86,7 +107,30 @@ Q_WIDGETS_EXPORT bool QTest::qWaitForWindowFocused(QWidget *widget, QDeadlineTim
}
/*!
+ \since 6.10
+ \overload
+
+ This function uses the default timeout of 5 seconds.
+*/
+bool QTest::qWaitForWindowFocused(QWidget *widget)
+{
+ return qWaitForWindowFocused(widget, Internal::defaultTryTimeout);
+}
+
+/*!
\since 5.0
+ \overload
+
+ The \a timeout is in milliseconds.
+*/
+bool QTest::qWaitForWindowExposed(QWidget *widget, int timeout)
+{
+ return qWaitForWindowExposed(widget, std::chrono::milliseconds(timeout));
+}
+
+
+/*!
+ \since 6.10
Returns \c true if \a widget is exposed within \a timeout milliseconds. Otherwise returns \c false.
@@ -99,11 +143,22 @@ Q_WIDGETS_EXPORT bool QTest::qWaitForWindowFocused(QWidget *widget, QDeadlineTim
\sa qWaitForWindowActive(), QWidget::isVisible(), QWindow::isExposed()
*/
-Q_WIDGETS_EXPORT bool QTest::qWaitForWindowExposed(QWidget *widget, int timeout)
+bool QTest::qWaitForWindowExposed(QWidget *widget, QDeadlineTimer timeout)
{
return qWaitForWidgetWindow(widget,
[&](QWindow *window) { return window->isExposed(); },
- QDeadlineTimer{timeout, Qt::TimerType::PreciseTimer});
+ timeout);
+}
+
+/*!
+ \since 6.10
+ \overload
+
+ This function uses the default timeout of 5 seconds.
+*/
+bool QTest::qWaitForWindowExposed(QWidget *widget)
+{
+ return qWaitForWindowExposed(widget, Internal::defaultTryTimeout);
}
namespace QTest {
diff --git a/src/widgets/kernel/qtestsupport_widgets.h b/src/widgets/kernel/qtestsupport_widgets.h
index b49e68db651..4b5e5ff7772 100644
--- a/src/widgets/kernel/qtestsupport_widgets.h
+++ b/src/widgets/kernel/qtestsupport_widgets.h
@@ -14,9 +14,16 @@ class QWidget;
namespace QTest {
-[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowActive(QWidget *widget, int timeout = 5000);
-[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowFocused(QWidget *widget, QDeadlineTimer timeout = std::chrono::seconds{5});
-[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowExposed(QWidget *widget, int timeout = 5000);
+[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowActive(QWidget *widget, int timeout);
+[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowActive(QWidget *widget, QDeadlineTimer timeout);
+[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowActive(QWidget *widget);
+
+[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowFocused(QWidget *widget, QDeadlineTimer timeout);
+[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowFocused(QWidget *widget);
+
+[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowExposed(QWidget *widget, int timeout);
+[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowExposed(QWidget *widget, QDeadlineTimer timeout);
+[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowExposed(QWidget *widget);
class Q_WIDGETS_EXPORT QTouchEventWidgetSequence : public QTouchEventSequence
{
diff --git a/src/widgets/kernel/qwidgetsvariant.cpp b/src/widgets/kernel/qwidgetsvariant.cpp
index 17a19aa780d..c843927d366 100644
--- a/src/widgets/kernel/qwidgetsvariant.cpp
+++ b/src/widgets/kernel/qwidgetsvariant.cpp
@@ -11,18 +11,16 @@
QT_BEGIN_NAMESPACE
namespace {
-
-// NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor): this is not a base class
-static constexpr struct : QMetaTypeModuleHelper
+struct QVariantWidgetsHelper : QMetaTypeModuleHelper
{
- const QtPrivate::QMetaTypeInterface *interfaceForType(int type) const override {
+ static const QtPrivate::QMetaTypeInterface *interfaceForType(int type)
+ {
switch (type) {
QT_FOR_EACH_STATIC_WIDGETS_CLASS(QT_METATYPE_CONVERT_ID_TO_TYPE)
default: return nullptr;
}
}
-} qVariantWidgetsHelper;
-
+};
#undef QT_IMPL_METATYPEINTERFACE_WIDGETS_TYPES
@@ -30,7 +28,9 @@ static constexpr struct : QMetaTypeModuleHelper
void qRegisterWidgetsVariant()
{
- qMetaTypeWidgetsHelper = &qVariantWidgetsHelper;
+ qMetaTypeWidgetsHelper = QMetaTypeModuleHelper{
+ &QVariantWidgetsHelper::interfaceForType,
+ };
}
Q_CONSTRUCTOR_FUNCTION(qRegisterWidgetsVariant)
diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp
index e9cc250c517..c341a025115 100644
--- a/src/widgets/styles/qfusionstyle.cpp
+++ b/src/widgets/styles/qfusionstyle.cpp
@@ -591,7 +591,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange)
painter->setPen(highlightedOutline);
else
- painter->setPen(colorScheme() == Qt::ColorScheme::Dark ? outline.lighter(150)
+ painter->setPen(colorScheme() == Qt::ColorScheme::Dark ? outline.lighter(240)
: outline.lighter(110));
painter->drawRect(rect);
diff --git a/src/widgets/styles/qfusionstyle_p_p.h b/src/widgets/styles/qfusionstyle_p_p.h
index 67abdd74dc8..62641609d59 100644
--- a/src/widgets/styles/qfusionstyle_p_p.h
+++ b/src/widgets/styles/qfusionstyle_p_p.h
@@ -70,10 +70,7 @@ public:
}
if (pal.window().style() == Qt::TexturePattern)
return QColor(0, 0, 0, 160);
- if (colorScheme() == Qt::ColorScheme::Dark)
- return pal.window().color().lighter(140);
- else
- return pal.window().color().darker(140);
+ return pal.window().color().darker(140);
}
QColor highlightedOutline(const QPalette &pal) const {
diff --git a/src/widgets/widgets/qdockarealayout.cpp b/src/widgets/widgets/qdockarealayout.cpp
index f5d92094f54..c1ce675d75a 100644
--- a/src/widgets/widgets/qdockarealayout.cpp
+++ b/src/widgets/widgets/qdockarealayout.cpp
@@ -3327,7 +3327,8 @@ int QDockAreaLayout::separatorMove(const QList<int> &separator, const QPoint &or
{
int delta = 0;
const auto dockPosition = static_cast<QInternal::DockPosition>(separator.last());
- const bool isHorizontal = dockPosition == QInternal::LeftDock || dockPosition == QInternal::TopDock;
+ const bool isHorizontal =
+ dockPosition == QInternal::LeftDock || dockPosition == QInternal::RightDock;
const bool isLeftOrTop = dockPosition == QInternal::LeftDock || dockPosition == QInternal::TopDock;
const bool separatorIsWithinDock = separator.size() > 1;
diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp
index 781f64a31ab..66c3db2e2f0 100644
--- a/tests/auto/corelib/io/qfile/tst_qfile.cpp
+++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp
@@ -228,6 +228,7 @@ private slots:
void getCharFF();
void remove_and_exists();
void removeOpenFile();
+ void removedFileDoesntExist();
void fullDisk();
void writeLargeDataBlock_data();
void writeLargeDataBlock();
@@ -2526,6 +2527,37 @@ void tst_QFile::removeOpenFile()
}
}
+void tst_QFile::removedFileDoesntExist()
+{
+#ifdef Q_OS_WIN
+ QSKIP("Not relevant for Windows - can't remove still-open files");
+#endif
+ QFile::remove("remove_unclosed.txt");
+ QFile f("remove_unclosed.txt");
+ QVERIFY(!f.exists());
+ bool opened = f.open(QIODevice::ReadWrite | QIODevice::Unbuffered);
+ QVERIFY(opened);
+ f.write("blah blah blah");
+
+ QVERIFY(f.exists());
+
+ // delete by path, not using f.remove() (that's tested above)
+ QVERIFY(QFile::remove(f.fileName()));
+ QVERIFY(!QFile::exists(f.fileName()));
+ QVERIFY(!f.exists());
+
+#ifdef Q_OS_LINUX
+ QString procPath = u"/proc/self/fd/"_s;
+ if (QFile::exists(procPath)) {
+ // reopen the deleted file
+ procPath += QString::number(f.handle());
+ QFile f2(procPath);
+ QVERIFY(f2.open(QIODevice::ReadOnly));
+ QVERIFY(!f2.exists());
+ }
+#endif
+}
+
void tst_QFile::fullDisk()
{
QFile file("/dev/full");
diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
index 761f0552eec..e2190477441 100644
--- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
+++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
@@ -141,6 +141,7 @@ private slots:
void exists_data();
void exists();
+ void deletedFileLinuxProcExists();
void absolutePath_data();
void absolutePath();
@@ -615,6 +616,34 @@ void tst_QFileInfo::exists()
QVERIFY(!exists);
}
+void tst_QFileInfo::deletedFileLinuxProcExists()
+{
+#ifdef Q_OS_LINUX
+ static const char msg[] = "Hello, World\n";
+ QFileInfo fi("/proc/self/fd/");
+ if (!fi.isDir())
+ QSKIP("/proc appears not to be mounted");
+
+ QFile f("removed_file.txt");
+ QVERIFY(f.open(QIODevice::ReadWrite | QIODevice::Unbuffered));
+ f.write(msg, strlen(msg));
+
+ fi.setFile(fi.filePath() + QString::number(f.handle()));
+ QVERIFY(fi.exists());
+ QCOMPARE(fi.size(), strlen(msg));
+
+ QFile::remove("removed_file.txt");
+ fi.refresh();
+ QVERIFY(fi.exists());
+
+ fi.refresh();
+ QCOMPARE(fi.size(), strlen(msg)); // this stats, so may change flags
+ QVERIFY(fi.exists());
+#else
+ QSKIP("Linux-only test");
+#endif
+}
+
void tst_QFileInfo::absolutePath_data()
{
QTest::addColumn<QString>("file");
diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp
index 282c7f2e360..71389abc976 100644
--- a/tests/auto/corelib/io/qurl/tst_qurl.cpp
+++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp
@@ -513,6 +513,7 @@ void tst_QUrl::comparison2()
QCOMPARE(url1.toString(), url2.toString());
QCOMPARE(url1, url2);
QCOMPARE(qHash(url1), qHash(url2));
+ QCOMPARE(qHash(url1, 1), qHash(url2, 1));
} else if (ordering < 0) {
QCOMPARE_LT(url1.toString(), url2.toString());
QCOMPARE_NE(url1, url2);
@@ -1387,12 +1388,14 @@ void tst_QUrl::toString_constructed()
QUrl parsed(asString);
QCOMPARE(url, parsed);
QCOMPARE(qHash(url), qHash(parsed));
+ QCOMPARE(qHash(url, 1), qHash(parsed, 1));
}
// clear it and ensure no memory of the previous state remains
url.setUrl(QString());
QCOMPARE(url, QUrl());
QCOMPARE(qHash(url), qHash(QUrl()));
+ QCOMPARE(qHash(url, 1), qHash(QUrl(), 1));
}
void tst_QUrl::toDisplayString_PreferLocalFile_data()
@@ -4265,6 +4268,7 @@ void tst_QUrl::setComponents()
QUrl recreated(toString);
QCOMPARE(copy, recreated);
QCOMPARE(qHash(copy), qHash(recreated));
+ QCOMPARE(qHash(copy, 1), qHash(recreated, 1));
} else {
QVERIFY(copy.toString().isEmpty());
}
diff --git a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
index b1e2e8164af..f2d281ae0a4 100644
--- a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
+++ b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
@@ -708,6 +708,8 @@ void tst_QMetaObjectBuilder::property()
prop2.setEnumOrFlag(false); \
prop2.setConstant(false); \
prop2.setFinal(false); \
+ prop2.setBindable(false); \
+ prop2.setRequired(false); \
} while (0)
#define COUNT_FLAGS() \
((prop2.isReadable() ? 1 : 0) + \
@@ -720,7 +722,9 @@ void tst_QMetaObjectBuilder::property()
(prop2.hasStdCppSet() ? 1 : 0) + \
(prop2.isEnumOrFlag() ? 1 : 0) + \
(prop2.isConstant() ? 1 : 0) + \
- (prop2.isFinal() ? 1 : 0))
+ (prop2.isFinal() ? 1 : 0) + \
+ (prop2.isBindable() ? 1 : 0) + \
+ (prop2.isRequired() ? 1 : 0))
#define CHECK_FLAG(setFunc,isFunc) \
do { \
CLEAR_FLAGS(); \
diff --git a/tests/auto/corelib/platform/CMakeLists.txt b/tests/auto/corelib/platform/CMakeLists.txt
index 3a66ec2eae6..9810947e3c6 100644
--- a/tests/auto/corelib/platform/CMakeLists.txt
+++ b/tests/auto/corelib/platform/CMakeLists.txt
@@ -5,7 +5,9 @@ if(ANDROID)
add_subdirectory(android)
add_subdirectory(android_appless)
add_subdirectory(androiditemmodel)
- add_subdirectory(android_legacy_packaging)
+ if(NOT QT_USE_ANDROID_MODERN_BUNDLE)
+ add_subdirectory(android_legacy_packaging)
+ endif()
endif()
if(WIN32)
add_subdirectory(windows)
diff --git a/tests/auto/corelib/platform/android_legacy_packaging/testdata/build.gradle b/tests/auto/corelib/platform/android_legacy_packaging/testdata/build.gradle
index cbdd833e2ae..1d796d9b6b9 100644
--- a/tests/auto/corelib/platform/android_legacy_packaging/testdata/build.gradle
+++ b/tests/auto/corelib/platform/android_legacy_packaging/testdata/build.gradle
@@ -70,8 +70,8 @@ android {
abortOnError = false
}
- // Do not compress Qt binary resources file
aaptOptions {
+ // Do not compress Qt binary resources file
noCompress 'rcc'
}
diff --git a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
index 3756937c94a..bfc6074689b 100644
--- a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
+++ b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
@@ -2470,7 +2470,8 @@ void tst_QLocale::formatTimeZone()
// Time definitely in Standard Time
const QStringList knownCETus = {
u"GMT+1"_s, // ICU
- u"CET"_s // Standard abbreviation
+ u"CET"_s, // Standard abbreviation
+ u"UTC+0100"_s, // used by Emscripten
};
const QString cet = enUS.toString(QDate(2013, 1, 1).startOfDay(), u"t");
QVERIFY2(knownCETus.contains(cet), cet.isEmpty() ? "[empty]" : qPrintable(cet));
@@ -2478,7 +2479,8 @@ void tst_QLocale::formatTimeZone()
// Time definitely in Daylight Time
const QStringList knownCESTus = {
u"GMT+2"_s, // ICU
- u"CEST"_s // Standard abbreviation
+ u"CEST"_s, // Standard abbreviation
+ u"UTC+0200"_s, // used by Emscripten
};
const QString cest = enUS.toString(QDate(2013, 6, 1).startOfDay(), u"t");
QVERIFY2(knownCESTus.contains(cest), cest.isEmpty() ? "[empty]" : qPrintable(cest));
diff --git a/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp b/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp
index 89bd1d7ff61..b53362b43e9 100644
--- a/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp
+++ b/tests/auto/corelib/tools/qatomicscopedvaluerollback/tst_qatomicscopedvaluerollback.cpp
@@ -5,6 +5,10 @@
#include <QTest>
+#include <chrono>
+
+using namespace std::chrono_literals;
+
class tst_QAtomicScopedValueRollback : public QObject
{
Q_OBJECT
@@ -15,6 +19,7 @@ private Q_SLOTS:
void rollbackToPreviousCommit();
void exceptions();
void earlyExitScope();
+ void mixedTypes();
private:
void earlyExitScope_helper(int exitpoint, std::atomic<int> &member);
};
@@ -132,6 +137,90 @@ void tst_QAtomicScopedValueRollback::earlyExitScope()
}
}
+template <typename T>
+struct Wrap {
+#if __cpp_deduction_guides < 201907L // no CTAD for aggregates
+ Q_IMPLICIT Wrap(T &t) : t{t} {}
+ Q_IMPLICIT Wrap(T &&t) : t{std::move(t)} {}
+#endif
+ T t;
+ Q_IMPLICIT operator T() const { return t; }
+};
+
+void tst_QAtomicScopedValueRollback::mixedTypes()
+{
+ const auto relaxed = std::memory_order_relaxed;
+ {
+ std::atomic a{10'000ms};
+ {
+ QAtomicScopedValueRollback rb(a, 5s);
+ QCOMPARE(a.load(relaxed), 5s);
+ }
+ QCOMPARE(a.load(relaxed), 10s);
+ {
+ QAtomicScopedValueRollback rb(a, 5s, relaxed);
+ QCOMPARE(a.load(relaxed), 5s);
+ }
+ QCOMPARE(a.load(relaxed), 10s);
+ }
+ {
+ QBasicAtomicInteger a{10'000};
+ {
+ QAtomicScopedValueRollback rb(a, Wrap{5'000});
+ QCOMPARE(a.loadRelaxed(), 5'000);
+ }
+ QCOMPARE(a.loadRelaxed(), 10'000);
+ {
+ QAtomicScopedValueRollback rb(a, Wrap{5'000}, relaxed);
+ QCOMPARE(a.loadRelaxed(), 5'000);
+ }
+ QCOMPARE(a.loadRelaxed(), 10'000);
+ }
+ {
+ QAtomicInteger a{10'000};
+ {
+ QAtomicScopedValueRollback rb(a, Wrap{5'000});
+ QCOMPARE(a.loadRelaxed(), 5'000);
+ }
+ QCOMPARE(a.loadRelaxed(), 10'000);
+ {
+ QAtomicScopedValueRollback rb(a, Wrap{5'000}, relaxed);
+ QCOMPARE(a.loadRelaxed(), 5'000);
+ }
+ QCOMPARE(a.loadRelaxed(), 10'000);
+ }
+ {
+ int i = 10'000;
+ int j = 5'000;
+ QBasicAtomicPointer a{&i};
+ {
+ QAtomicScopedValueRollback rb(a, Wrap{&j});
+ QCOMPARE(a.loadRelaxed(), &j);
+ }
+ QCOMPARE(a.loadRelaxed(), &i);
+ {
+ QAtomicScopedValueRollback rb(a, Wrap{&j}, relaxed);
+ QCOMPARE(a.loadRelaxed(), &j);
+ }
+ QCOMPARE(a.loadRelaxed(), &i);
+ }
+ {
+ int i = 10'000;
+ int j = 5'000;
+ QAtomicPointer a{&i};
+ {
+ QAtomicScopedValueRollback rb(a, Wrap{&j});
+ QCOMPARE(a.loadRelaxed(), &j);
+ }
+ QCOMPARE(a.loadRelaxed(), &i);
+ {
+ QAtomicScopedValueRollback rb(a, Wrap{&j}, relaxed);
+ QCOMPARE(a.loadRelaxed(), &j);
+ }
+ QCOMPARE(a.loadRelaxed(), &i);
+ }
+}
+
static void operator*=(std::atomic<int> &lhs, int rhs)
{
int expected = lhs.load();
diff --git a/tests/auto/gui/kernel/qwindow/BLACKLIST b/tests/auto/gui/kernel/qwindow/BLACKLIST
index a92d89c6123..4f994fb3059 100644
--- a/tests/auto/gui/kernel/qwindow/BLACKLIST
+++ b/tests/auto/gui/kernel/qwindow/BLACKLIST
@@ -25,6 +25,5 @@ android
windows-10
windows-11
android
-rhel
[windowExposedAfterReparent]
xcb ubuntu-24.04 # QTBUG-129023
diff --git a/tests/auto/other/android/CMakeLists.txt b/tests/auto/other/android/CMakeLists.txt
index bcbf5b657d7..0eb2d00b46a 100644
--- a/tests/auto/other/android/CMakeLists.txt
+++ b/tests/auto/other/android/CMakeLists.txt
@@ -2,3 +2,11 @@
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(deployment_settings)
+add_subdirectory(permissions)
+
+if(QT_USE_TARGET_ANDROID_BUILD_DIR)
+ add_subdirectory(package_source_dir)
+ if(QT_USE_ANDROID_MODERN_BUNDLE)
+ add_subdirectory(dynamic_feature)
+ endif()
+endif()
diff --git a/tests/auto/other/android/deployment_settings/tst_android_deployment_settings.cpp b/tests/auto/other/android/deployment_settings/tst_android_deployment_settings.cpp
index 1687ed9de92..571570e370f 100644
--- a/tests/auto/other/android/deployment_settings/tst_android_deployment_settings.cpp
+++ b/tests/auto/other/android/deployment_settings/tst_android_deployment_settings.cpp
@@ -83,10 +83,11 @@ void tst_android_deployment_settings::DeploymentSettings_data()
<< "org.qtproject.android_deployment_settings_test";
QTest::newRow("android-app-name") << "android-app-name"
<< "Android Deployment Settings Test";
- QTest::newRow("permissions") << "permissions"
- << "[{\"name\":\"PERMISSION_WITH_ATTRIBUTES\","
- "\"extras\":\"android:minSdkVersion='32' android:maxSdkVersion='34' \"},"
- "{\"name\":\"PERMISSION_WITHOUT_ATTRIBUTES\"}]";
+ QTest::newRow("permissions")
+ << "permissions"
+ << "[{\"maxSdkVersion\":\"34\",\"minSdkVersion\":\"32\",\"name\":\"PERMISSION_WITH_"
+ "ATTRIBUTES\"},{\"name\":\"PERMISSION_WITHOUT_ATTRIBUTES\"},{\"name\":\"android."
+ "permission.INTERNET\"},{\"name\":\"android.permission.WRITE_EXTERNAL_STORAGE\"}]";
}
void tst_android_deployment_settings::DeploymentSettings()
diff --git a/tests/auto/other/android/dynamic_feature/CMakeLists.txt b/tests/auto/other/android/dynamic_feature/CMakeLists.txt
new file mode 100644
index 00000000000..b12c2af4dc7
--- /dev/null
+++ b/tests/auto/other/android/dynamic_feature/CMakeLists.txt
@@ -0,0 +1,33 @@
+# Copyright (C) 2025 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_android_dynamic_feature LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+add_subdirectory(feature)
+
+qt_internal_add_test(tst_android_dynamic_feature
+ SOURCES
+ tst_android_dynamic_feature.cpp
+ storeloader/storeloader.h
+ storeloader/storeloader.cpp
+ INCLUDE_DIRECTORIES
+ storeloader
+ LIBRARIES
+ Qt6::Test
+ Qt6::Gui
+ Qt6::CorePrivate
+)
+
+set_property(TARGET tst_android_dynamic_feature PROPERTY
+ QT_ANDROID_PACKAGE_NAME "org.qtproject.example.android_dynamic_feature")
+set_property(TARGET tst_android_dynamic_feature APPEND PROPERTY
+ _qt_android_gradle_java_source_dirs "${CMAKE_CURRENT_SOURCE_DIR}/storeloader/java")
+
+qt6_add_android_dynamic_features(tst_android_dynamic_feature FEATURE_TARGETS
+ tst_android_dynamic_feature_resources)
diff --git a/tests/auto/other/android/dynamic_feature/feature/CMakeLists.txt b/tests/auto/other/android/dynamic_feature/feature/CMakeLists.txt
new file mode 100644
index 00000000000..bfe29cc0f5e
--- /dev/null
+++ b/tests/auto/other/android/dynamic_feature/feature/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 3.16)
+
+qt6_add_library(tst_android_dynamic_feature_resources SHARED)
+qt6_add_resources(tst_android_dynamic_feature_resources "dynamic_resources"
+ PREFIX "/dynamic_resources"
+ FILES "qtlogo.png")
+
+target_link_libraries(tst_android_dynamic_feature_resources PRIVATE Qt6::Core)
diff --git a/tests/auto/other/android/dynamic_feature/feature/qtlogo.png b/tests/auto/other/android/dynamic_feature/feature/qtlogo.png
new file mode 100644
index 00000000000..b63f1384b11
--- /dev/null
+++ b/tests/auto/other/android/dynamic_feature/feature/qtlogo.png
Binary files differ
diff --git a/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoader.java b/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoader.java
new file mode 100644
index 00000000000..5a72351c802
--- /dev/null
+++ b/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoader.java
@@ -0,0 +1,175 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+package org.qtproject.example.android_dynamic_feature;
+
+import com.google.android.play.core.splitcompat.SplitCompat;
+import com.google.android.play.core.splitinstall.SplitInstallManager;
+import com.google.android.play.core.splitinstall.SplitInstallManagerFactory;
+import com.google.android.play.core.splitinstall.SplitInstallRequest;
+import com.google.android.play.core.splitinstall.SplitInstallHelper;
+import com.google.android.play.core.splitinstall.testing.FakeSplitInstallManagerFactory;
+import android.content.pm.PackageManager.NameNotFoundException;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.io.File;
+import android.util.Log;
+import android.content.Context;
+import android.os.Build;
+
+/**
+ * Android implementation of store loader.
+ */
+public class StoreLoader implements StoreLoaderListenerCallback
+{
+ private static final String TAG = "StoreLoader";
+ private final SplitInstallManager m_splitInstallManager;
+ private HashMap<String, StoreLoaderListener> m_listeners =
+ new HashMap();
+ private Context m_context;
+ private String m_moduleName;
+
+ public static native void stateChangedNative(String callId, int state);
+ public static native void errorOccurredNative(String callId, int errorCode,
+ String errorMessage);
+ public static native void userConfirmationRequestedNative(String callId, int errorCode,
+ String errorMessage);
+ public static native void downloadProgressChangedNative(String callId, long bytes, long total);
+ public static native void finishedNative(String callId);
+
+ public StoreLoader(Context context) {
+ m_context = context;
+
+ SplitCompat.install(context);
+
+ m_splitInstallManager = SplitInstallManagerFactory.create(context);
+ if (m_splitInstallManager == null)
+ Log.e(TAG,"Constructor: Did not get splitInstallManager");
+ }
+
+ /**
+ * Loads Feature Delivery module from a play store.
+ */
+ public void installModuleFromStore(String moduleName, String callId) {
+ Log.d(TAG, "installModuleFromStore: " + moduleName + " " + callId);
+ m_moduleName = moduleName;
+
+ registerListener(callId);
+
+ SplitInstallRequest request =
+ SplitInstallRequest.newBuilder().addModule(m_moduleName).build();
+ if (request == null)
+ Log.e(TAG, "Null request");
+
+ if (m_splitInstallManager == null)
+ Log.e(TAG, "Null m_splitInstallManager");
+
+ m_splitInstallManager.startInstall(request)
+ .addOnSuccessListener(sessionId -> {
+ Log.d(TAG, "Install start call succesfull");
+ StoreLoaderListener listener = m_listeners.get(callId);
+ if (listener != null) {
+ if (!listener.isCancelled())
+ listener.setSessionId(sessionId);
+ else
+ m_splitInstallManager.cancelInstall(sessionId);
+ } else {
+ Log.d(TAG, "Listener for callId '" + callId + "' is not found");
+ }
+ });
+ }
+
+ public void onStateChanged(String callId, int state) {
+ stateChangedNative(callId, state);
+ if (state == StoreLoaderListenerCallback.LOADED ||
+ state == StoreLoaderListenerCallback.CANCELED) {
+ finished(callId);
+ }
+ }
+
+ public void onErrorOccurred(String callId, int errorCode, String errorMessage) {
+ onStateChanged(callId, ERROR);
+
+ Log.e(TAG, "Error occurred " + errorCode + " " + errorMessage);
+ errorOccurredNative(callId, errorCode, errorMessage);
+ finished(callId);
+ }
+
+ public void onUserConfirmationRequested(String callId, int errorCode, String errorMessage) {
+ Log.d(TAG, "Requires user confirmation " + errorCode);
+ userConfirmationRequestedNative(callId, errorCode, errorMessage);
+ }
+
+ public void onDownloadProgressChanged(String callId, long bytes, long total) {
+ Log.d(TAG, "Downloading " + bytes + "/" + total);
+ downloadProgressChangedNative(callId, bytes, total);
+ }
+
+ public void onLoadLibrary(String callId) {
+ Log.d(TAG, "Load library for the module " + m_moduleName);
+
+ stateChangedNative(callId, StoreLoaderListenerCallback.LOADING);
+ // update context.
+ try {
+ m_context = m_context.createPackageContext(m_context.getPackageName(), 0);
+ } catch (NameNotFoundException ignored) {
+ Log.e(TAG, "Could not get package name");
+ }
+ // install splitcompat for new context.
+ SplitCompat.install(m_context);
+ // try to load new library
+ boolean isLoaded = false;
+ for (String abi : Build.SUPPORTED_ABIS) {
+ String fullLibraryName = m_moduleName + "_" + abi;
+ try {
+ System.loadLibrary(fullLibraryName);
+ isLoaded = true;
+ break;
+ } catch (Exception e) {
+ Log.d(TAG, "Exception occurred when loading the library " + fullLibraryName + ":" +
+ e.getClass().getCanonicalName());
+ }
+ }
+
+ if (isLoaded)
+ onStateChanged(callId, StoreLoaderListenerCallback.LOADED);
+ else
+ onErrorOccurred(callId, -1, "Error loading library. Check logcat for details.");
+
+ }
+
+ public void cancelInstall(String callId) {
+ StoreLoaderListener listener = m_listeners.get(callId);
+ if (listener == null) {
+ Log.e(TAG, "The listener for callId " + callId + " is not found");
+ return;
+ }
+
+ if (listener.getSessionId() < 0)
+ listener.postponeCancel();
+ else
+ m_splitInstallManager.cancelInstall(listener.getSessionId());
+ }
+
+ private void finished(String callId) {
+ unregisterListener(callId);
+ finishedNative(callId);
+ }
+
+ private void registerListener(String callId) {
+ Log.d(TAG, "registerListener");
+ StoreLoaderListener listener = new StoreLoaderListener(this, callId);
+ if (listener != null) {
+ m_listeners.put(callId, listener);
+ m_splitInstallManager.registerListener(listener);
+ }
+ }
+
+ private void unregisterListener(String callId) {
+ Log.d(TAG, "unregisterListener");
+ StoreLoaderListener listener = m_listeners.remove(callId);
+ if (listener != null)
+ m_splitInstallManager.unregisterListener(listener);
+ }
+}
diff --git a/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoaderListener.java b/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoaderListener.java
new file mode 100644
index 00000000000..3e83a0fa7f9
--- /dev/null
+++ b/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoaderListener.java
@@ -0,0 +1,92 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+package org.qtproject.example.android_dynamic_feature;
+
+import com.google.android.play.core.splitinstall.SplitInstallStateUpdatedListener;
+import com.google.android.play.core.splitinstall.SplitInstallSessionState;
+import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus;
+
+import android.util.Log;
+
+public class StoreLoaderListener implements SplitInstallStateUpdatedListener {
+
+ private final StoreLoaderListenerCallback m_callback;
+ private final String m_callId;
+ private int m_installSessionId = -1;
+ private static final String TAG = "StoreLoaderListener";
+ private int m_currentStatus = SplitInstallSessionStatus.UNKNOWN;
+ private boolean m_postponeCancel = false;
+
+ public StoreLoaderListener(StoreLoaderListenerCallback callback, String callId) {
+ m_callback = callback;
+ m_callId = callId;
+ }
+
+ public void setSessionId(int sessionId) { m_installSessionId = sessionId; }
+ public int getSessionId() { return m_installSessionId; }
+
+ public void postponeCancel() { m_postponeCancel = true; }
+ public boolean isCancelled() { return m_postponeCancel; }
+
+ @Override
+ public void onStateUpdate(SplitInstallSessionState state) {
+ Log.d(TAG,
+ "onStateUpdate, status: " + state.status() + " session id: " + state.sessionId());
+ if (state.sessionId() != m_installSessionId) {
+ // Not mine
+ return;
+ }
+
+ switch (state.status()) {
+ case SplitInstallSessionStatus.DOWNLOADING:
+ Log.d(TAG,
+ "SplitInstallSessionState: DOWNLOADING " + state.bytesDownloaded() + "/"
+ + state.totalBytesToDownload());
+ if (m_currentStatus != SplitInstallSessionStatus.DOWNLOADING)
+ m_callback.onStateChanged(m_callId, StoreLoaderListenerCallback.DOWNLOADING);
+
+ m_callback.onDownloadProgressChanged(m_callId, state.bytesDownloaded(),
+ state.totalBytesToDownload());
+ break;
+ case SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION:
+ Log.d(TAG, "SplitInstallSessionState: REQUIRES_USER_CONFIRMATION");
+ m_callback.onStateChanged(m_callId,
+ StoreLoaderListenerCallback.REQUIRES_USER_CONFIRMATION);
+
+ m_callback.onUserConfirmationRequested(m_callId, state.errorCode(), "" /*noop for now*/);
+ break;
+ case SplitInstallSessionStatus.INSTALLED:
+ Log.d(TAG, "SplitInstallSessionState: INSTALLED");
+ m_callback.onStateChanged(m_callId, StoreLoaderListenerCallback.INSTALLED);
+ m_callback.onLoadLibrary(m_callId);
+ break;
+ case SplitInstallSessionStatus.INSTALLING:
+ Log.d(TAG, "SplitInstallSessionState: INSTALLING");
+ m_callback.onStateChanged(m_callId, StoreLoaderListenerCallback.INSTALLING);
+ break;
+ case SplitInstallSessionStatus.FAILED:
+ Log.d(TAG,
+ "SplitInstallSessionState: FAILED with error code: " + state.errorCode());
+ m_callback.onErrorOccurred(m_callId, state.errorCode(), "" /*noop for now*/);
+ break;
+ case SplitInstallSessionStatus.PENDING:
+ Log.d(TAG, "SplitInstallSessionState: PENDING");
+ m_callback.onStateChanged(m_callId, StoreLoaderListenerCallback.PENDING);
+ break;
+ case SplitInstallSessionStatus.DOWNLOADED:
+ Log.d(TAG, "SplitInstallSessionState: DOWNLOADED");
+ m_callback.onStateChanged(m_callId, StoreLoaderListenerCallback.DOWNLOADED);
+ break;
+ case SplitInstallSessionStatus.CANCELED:
+ Log.d(TAG, "SplitInstallSessionState: CANCELED");
+ m_callback.onStateChanged(m_callId, StoreLoaderListenerCallback.CANCELED);
+ break;
+ case SplitInstallSessionStatus.CANCELING:
+ Log.d(TAG, "SplitInstallSessionState: CANCELING");
+ m_callback.onStateChanged(m_callId, StoreLoaderListenerCallback.CANCELING);
+ break;
+ }
+ m_currentStatus = state.status();
+ }
+}
diff --git a/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoaderListenerCallback.java b/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoaderListenerCallback.java
new file mode 100644
index 00000000000..99c7327e328
--- /dev/null
+++ b/tests/auto/other/android/dynamic_feature/storeloader/java/src/main/java/org/qtproject/example/android_dynamic_feature/StoreLoaderListenerCallback.java
@@ -0,0 +1,26 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+package org.qtproject.example.android_dynamic_feature;
+
+public interface StoreLoaderListenerCallback {
+ public static final int UNKNOWN = 0; // Unused but native part has and uses one.
+ public static final int INITIALIZED = 1;
+ public static final int PENDING = 2;
+ public static final int DOWNLOADING = 3;
+ public static final int DOWNLOADED = 4;
+ public static final int REQUIRES_USER_CONFIRMATION = 5;
+ public static final int CANCELING = 6;
+ public static final int CANCELED = 7;
+ public static final int INSTALLING = 8;
+ public static final int INSTALLED = 9;
+ public static final int LOADING = 10;
+ public static final int LOADED = 11;
+ public static final int ERROR = 12;
+
+ public void onStateChanged(String callId, int state);
+ public void onErrorOccurred(String callId, int errorCode, String errorMessage);
+ public void onUserConfirmationRequested(String callId, int errorCode, String errorMessage);
+ public void onDownloadProgressChanged(String callId, long bytes, long total);
+ public void onLoadLibrary(String callId);
+}
diff --git a/tests/auto/other/android/dynamic_feature/storeloader/storeloader.cpp b/tests/auto/other/android/dynamic_feature/storeloader/storeloader.cpp
new file mode 100644
index 00000000000..7abce59b79e
--- /dev/null
+++ b/tests/auto/other/android/dynamic_feature/storeloader/storeloader.cpp
@@ -0,0 +1,227 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#include "storeloader.h"
+
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qjniobject.h>
+#include <QtCore/qlogging.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/quuid.h>
+
+#include <jni.h>
+
+Q_DECLARE_JNI_CLASS(StoreLoader,
+ "org/qtproject/example/android_dynamic_feature/StoreLoader");
+
+class StoreLoaderHandlerPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(StoreLoaderHandler)
+public:
+ void setState(StoreLoader::State state)
+ {
+ if (m_state == state)
+ return;
+ Q_Q(StoreLoaderHandler);
+ m_state = state;
+ q->stateChanged(m_state);
+ }
+
+ const QString &callId() const & noexcept { return m_callId; }
+
+private:
+ StoreLoader::State m_state = StoreLoader::State::Unknown;
+ QString m_callId = QUuid::createUuid().toString();
+};
+
+namespace QtPrivate {
+QString asString(const jstring &s)
+{
+ return QJniObject(s).toString();
+}
+} // namespace QtPrivate
+
+namespace {
+
+class StoreLoaderImpl
+{
+public:
+ StoreLoaderImpl();
+ bool registerNatives() const;
+
+ void addHandler(StoreLoaderHandler *handler);
+ StoreLoaderHandler *findHandler(const jstring &callId);
+ void removeHandler(const jstring &callId);
+
+ QtJniTypes::StoreLoader loader = nullptr;
+
+private:
+ QHash<QString, QPointer<StoreLoaderHandler>> m_handlers;
+ QMutex m_lock;
+};
+
+Q_GLOBAL_STATIC(StoreLoaderImpl, loaderInstance)
+
+void stateChangedNative(JNIEnv *, jobject, jstring callId, int state)
+{
+ qDebug("State changed %s.", qPrintable(callId));
+
+ if (auto *handler = loaderInstance->findHandler(callId))
+ emit handler->stateChanged(static_cast<StoreLoader::State>(state));
+}
+
+void errorOccurredNative(JNIEnv *, jobject, jstring callId, int errorCode, jstring errorMessage)
+{
+ qDebug("Error occurred %s %d %s.", qPrintable(callId), errorCode, qPrintable(errorMessage));
+ auto *handler = loaderInstance->findHandler(callId);
+ if (!handler)
+ return;
+
+ emit handler->errorOccured(errorCode, QJniObject(errorMessage).toString());
+}
+
+void userConfirmationRequestedNative(JNIEnv *, jobject, jstring callId, int errorCode,
+ jstring errorMessage)
+{
+ qDebug("User confirmation requested %s %d %s.", qPrintable(callId), errorCode,
+ qPrintable(errorMessage));
+ auto *handler = loaderInstance->findHandler(callId);
+ if (!handler)
+ return;
+
+ emit handler->confirmationRequest(errorCode, QJniObject(errorMessage).toString());
+}
+
+void downloadProgressChangedNative(JNIEnv *, jobject, jstring callId, long bytes, long total)
+{
+ qDebug("Download progress changed %ld/%ld.", bytes, total);
+ auto *handler = loaderInstance->findHandler(callId);
+ if (!handler)
+ return;
+
+ emit handler->downloadProgress(bytes, total);
+}
+
+void finishedNative(JNIEnv *, jobject, jstring callId)
+{
+ auto *handler = loaderInstance->findHandler(callId);
+ if (!handler)
+ return;
+
+ emit handler->finished();
+}
+
+} // namespace
+
+Q_DECLARE_JNI_NATIVE_METHOD(stateChangedNative)
+Q_DECLARE_JNI_NATIVE_METHOD(errorOccurredNative)
+Q_DECLARE_JNI_NATIVE_METHOD(userConfirmationRequestedNative)
+Q_DECLARE_JNI_NATIVE_METHOD(downloadProgressChangedNative)
+Q_DECLARE_JNI_NATIVE_METHOD(finishedNative)
+
+StoreLoaderImpl::StoreLoaderImpl()
+{
+ loader = QJniObject::construct<QtJniTypes::StoreLoader, QtJniTypes::Context>(
+ QNativeInterface::QAndroidApplication::context());
+}
+
+bool StoreLoaderImpl::registerNatives() const
+{
+ static bool result = [] {
+ return QtJniTypes::StoreLoader::registerNativeMethods({
+ Q_JNI_NATIVE_METHOD(stateChangedNative),
+ Q_JNI_NATIVE_METHOD(errorOccurredNative),
+ Q_JNI_NATIVE_METHOD(userConfirmationRequestedNative),
+ Q_JNI_NATIVE_METHOD(downloadProgressChangedNative),
+ Q_JNI_NATIVE_METHOD(finishedNative),
+ });
+ }();
+
+ if (!result)
+ qCritical("Unable to register native methods.");
+
+ return result;
+}
+
+void StoreLoaderImpl::addHandler(StoreLoaderHandler *handler)
+{
+ Q_ASSERT(handler);
+
+ QMutexLocker lock(&m_lock);
+ const auto &callId = handler->callId();
+ Q_ASSERT_X(m_handlers.constFind(callId) != m_handlers.constEnd(), "StoreLoaderImpl::addHandler",
+ qPrintable(QString("Handler with callId %1 already exists.").arg(callId)));
+
+ m_handlers[callId] = QPointer(handler);
+}
+
+
+StoreLoaderHandler *StoreLoaderImpl::findHandler(const jstring &callId)
+{
+ QMutexLocker lock(&m_lock);
+ const auto it = m_handlers.constFind(QJniObject(callId).toString());
+ if (it == m_handlers.constEnd()) {
+ qCritical("The handler for the call %s was not found.", qPrintable(callId));
+ return nullptr;
+ }
+
+ if (it.value().isNull()) {
+ qCritical("The handler for the call %s expired.", qPrintable(callId));
+ m_handlers.erase(it);
+ }
+
+ return it.value().get();
+}
+
+void StoreLoaderImpl::removeHandler(const jstring &callId)
+{
+ QMutexLocker lock(&m_lock);
+ m_handlers.remove(QJniObject(callId).toString());
+}
+
+std::unique_ptr<StoreLoaderHandler>
+StoreLoader::loadModule(const QString &moduleName)
+{
+ if (moduleName.isEmpty())
+ return {};
+
+ if (!loaderInstance->registerNatives())
+ return {};
+
+ if (!loaderInstance->loader.isValid()) {
+ qCritical("StoreLoader not constructed");
+ return {};
+ }
+
+ auto handlerPtr = std::make_unique<StoreLoaderHandler>(
+ nullptr, StoreLoaderHandler::PrivateConstructor{});
+ loaderInstance->addHandler(handlerPtr.get());
+
+ const auto &callId = handlerPtr->callId();
+ qDebug("Loading module %s, callId: %s.", qPrintable(moduleName), qPrintable(callId));
+
+ loaderInstance->loader.callMethod<void>("installModuleFromStore", moduleName, callId);
+ return handlerPtr;
+}
+
+StoreLoaderHandler::StoreLoaderHandler(QObject *parent, PrivateConstructor)
+ : QObject(*new StoreLoaderHandlerPrivate(), parent)
+{
+}
+
+StoreLoaderHandler::~StoreLoaderHandler() = default;
+
+const QString &StoreLoaderHandler::callId() const & noexcept
+{
+ Q_D(const StoreLoaderHandler);
+ return d->callId();
+}
+
+void StoreLoaderHandler::cancel()
+{
+ Q_D(StoreLoaderHandler);
+ loaderInstance->loader.callMethod<void>("cancelInstall", d->callId());
+}
+
+#include "moc_storeloader.cpp"
diff --git a/tests/auto/other/android/dynamic_feature/storeloader/storeloader.h b/tests/auto/other/android/dynamic_feature/storeloader/storeloader.h
new file mode 100644
index 00000000000..be4e103207e
--- /dev/null
+++ b/tests/auto/other/android/dynamic_feature/storeloader/storeloader.h
@@ -0,0 +1,65 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef STORELOADER_H
+#define STORELOADER_H
+
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qobject.h>
+
+#include <memory>
+
+class StoreLoaderHandler;
+
+namespace StoreLoader {
+ Q_NAMESPACE
+enum class State {
+ Unknown,
+ Initialized,
+ Pending,
+ Downloading,
+ Downloaded,
+ RequiresUserConfirmation,
+ Canceling,
+ Canceled,
+ Installing,
+ Installed,
+ Loading,
+ Loaded,
+ Error,
+};
+Q_ENUM_NS(State)
+
+std::unique_ptr<StoreLoaderHandler> loadModule(const QString &moduleName);
+}; // namespace StoreLoader
+
+class StoreLoaderHandlerPrivate;
+
+class StoreLoaderHandler : public QObject
+{
+ Q_OBJECT
+ QT_DEFINE_TAG_STRUCT(PrivateConstructor);
+
+public:
+ explicit StoreLoaderHandler(QObject *parent, PrivateConstructor);
+ ~StoreLoaderHandler() override;
+
+ const QString &callId() const & noexcept;
+
+ void cancel();
+signals:
+ void stateChanged(StoreLoader::State state);
+ void downloadProgress(qsizetype bytes, qsizetype total);
+ void errorOccured(int errorCode, const QString &errorString);
+ void confirmationRequest(int errorCode, const QString &errorString);
+ void finished();
+
+private:
+ Q_DISABLE_COPY_MOVE(StoreLoaderHandler)
+ Q_DECLARE_PRIVATE(StoreLoaderHandler)
+
+ friend std::unique_ptr<StoreLoaderHandler>
+ StoreLoader::loadModule(const QString &);
+};
+
+#endif // STORELOADER_H
diff --git a/tests/auto/other/android/dynamic_feature/tst_android_dynamic_feature.cpp b/tests/auto/other/android/dynamic_feature/tst_android_dynamic_feature.cpp
new file mode 100644
index 00000000000..739a645c5d5
--- /dev/null
+++ b/tests/auto/other/android/dynamic_feature/tst_android_dynamic_feature.cpp
@@ -0,0 +1,37 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <storeloader.h>
+
+#include <QtTest/QTest>
+#include <QtTest/QSignalSpy>
+
+#include <QtCore/QVariant>
+
+using namespace Qt::Literals::StringLiterals;
+
+class QtDynamicFeatureTest : public QObject
+{
+ Q_OBJECT
+public:
+ QtDynamicFeatureTest(){}
+
+private Q_SLOTS:
+ void loadResourcesFeature();
+};
+
+void QtDynamicFeatureTest::loadResourcesFeature()
+{
+ QVERIFY(!QFile::exists(":/dynamic_resources/qtlogo.png"));
+
+ auto handler = StoreLoader::loadModule("tst_android_dynamic_feature_resources"_L1);
+
+ QSignalSpy spy(handler.get(), &StoreLoaderHandler::finished);
+
+ QVERIFY(spy.wait(20000));
+ QVERIFY(QFile::exists(":/dynamic_resources/qtlogo.png"));
+}
+
+QTEST_MAIN(QtDynamicFeatureTest)
+
+#include "tst_android_dynamic_feature.moc"
diff --git a/tests/auto/other/android/package_source_dir/CMakeLists.txt b/tests/auto/other/android/package_source_dir/CMakeLists.txt
new file mode 100644
index 00000000000..360aa50d87d
--- /dev/null
+++ b/tests/auto/other/android/package_source_dir/CMakeLists.txt
@@ -0,0 +1,54 @@
+# Copyright (C) 2025 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_android_package_source_dir LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+# Package name is generated and written to AndroidManifest.xml
+qt_internal_add_test(tst_package_source_dir_not_defined
+ SOURCES
+ tst_android_package_source_dir.cpp
+ DEFINES
+ EXPECTED_APP_NAME="tst_package_source_dir_not_defined"
+)
+
+# Package name from user-provided AndroidManifest.xml
+qt_internal_add_test(tst_package_source_dir_custom_android_manifest
+ SOURCES
+ tst_android_package_source_dir.cpp
+ DEFINES
+ EXPECTED_APP_NAME="tst_package_source_dir_custom_android_manifest_my"
+)
+
+if(QT_USE_ANDROID_MODERN_BUNDLE)
+ set_target_properties(tst_package_source_dir_custom_android_manifest
+ PROPERTIES
+ QT_ANDROID_PACKAGE_SOURCE_DIR
+ "${CMAKE_CURRENT_SOURCE_DIR}/custom_android_manifest_bundle"
+ )
+else()
+ set_target_properties(tst_package_source_dir_custom_android_manifest
+ PROPERTIES
+ QT_ANDROID_PACKAGE_SOURCE_DIR
+ "${CMAKE_CURRENT_SOURCE_DIR}/custom_android_manifest"
+ )
+endif()
+
+if(QT_USE_ANDROID_MODERN_BUNDLE)
+ # Partial gradle template is only supported by QT_USE_ANDROID_MODERN_BUNDLE
+ #
+ # Package name from user-provided gradle.build.in
+ qt_internal_add_test(tst_package_source_dir_partial_template
+ SOURCES
+ tst_android_package_source_dir.cpp
+ DEFINES
+ EXPECTED_APP_NAME="tst_package_source_dir_partial_template_my"
+ )
+ set_target_properties(tst_package_source_dir_partial_template
+ PROPERTIES
+ QT_ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/partial_template"
+ )
+endif()
diff --git a/tests/auto/other/android/package_source_dir/custom_android_manifest/AndroidManifest.xml b/tests/auto/other/android/package_source_dir/custom_android_manifest/AndroidManifest.xml
new file mode 100644
index 00000000000..4f53295e979
--- /dev/null
+++ b/tests/auto/other/android/package_source_dir/custom_android_manifest/AndroidManifest.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.qtproject.example.tst_package_source_dir_custom_android_manifest"
+ android:installLocation="auto"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <supports-screens
+ android:anyDensity="true"
+ android:largeScreens="true"
+ android:normalScreens="true"
+ android:smallScreens="true" />
+ <application
+ android:name="org.qtproject.qt.android.bindings.QtApplication"
+ android:hardwareAccelerated="true"
+ android:label="tst_package_source_dir_custom_android_manifest_my"
+ android:requestLegacyExternalStorage="true"
+ android:allowBackup="true"
+ android:fullBackupOnly="false">
+ <activity
+ android:name="org.qtproject.qt.android.bindings.QtActivity"
+ android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
+ android:launchMode="singleTop"
+ android:screenOrientation="unspecified"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ <meta-data
+ android:name="android.app.lib_name"
+ android:value="tst_package_source_dir_custom_android_manifest" />
+
+ <meta-data
+ android:name="android.app.arguments"
+ android:value="" />
+ </activity>
+
+ <provider
+ android:name="androidx.core.content.FileProvider"
+ android:authorities="${applicationId}.qtprovider"
+ android:exported="false"
+ android:grantUriPermissions="true">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/qtprovider_paths"/>
+ </provider>
+ </application>
+</manifest>
diff --git a/tests/auto/other/android/package_source_dir/custom_android_manifest_bundle/app/AndroidManifest.xml b/tests/auto/other/android/package_source_dir/custom_android_manifest_bundle/app/AndroidManifest.xml
new file mode 100644
index 00000000000..4f53295e979
--- /dev/null
+++ b/tests/auto/other/android/package_source_dir/custom_android_manifest_bundle/app/AndroidManifest.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.qtproject.example.tst_package_source_dir_custom_android_manifest"
+ android:installLocation="auto"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <supports-screens
+ android:anyDensity="true"
+ android:largeScreens="true"
+ android:normalScreens="true"
+ android:smallScreens="true" />
+ <application
+ android:name="org.qtproject.qt.android.bindings.QtApplication"
+ android:hardwareAccelerated="true"
+ android:label="tst_package_source_dir_custom_android_manifest_my"
+ android:requestLegacyExternalStorage="true"
+ android:allowBackup="true"
+ android:fullBackupOnly="false">
+ <activity
+ android:name="org.qtproject.qt.android.bindings.QtActivity"
+ android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
+ android:launchMode="singleTop"
+ android:screenOrientation="unspecified"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ <meta-data
+ android:name="android.app.lib_name"
+ android:value="tst_package_source_dir_custom_android_manifest" />
+
+ <meta-data
+ android:name="android.app.arguments"
+ android:value="" />
+ </activity>
+
+ <provider
+ android:name="androidx.core.content.FileProvider"
+ android:authorities="${applicationId}.qtprovider"
+ android:exported="false"
+ android:grantUriPermissions="true">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/qtprovider_paths"/>
+ </provider>
+ </application>
+</manifest>
diff --git a/tests/auto/other/android/package_source_dir/partial_template/app/AndroidManifest.xml b/tests/auto/other/android/package_source_dir/partial_template/app/AndroidManifest.xml
new file mode 100644
index 00000000000..838d239e5f4
--- /dev/null
+++ b/tests/auto/other/android/package_source_dir/partial_template/app/AndroidManifest.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.qtproject.example.tst_package_source_dir_partial_template"
+ android:installLocation="auto"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <supports-screens
+ android:anyDensity="true"
+ android:largeScreens="true"
+ android:normalScreens="true"
+ android:smallScreens="true" />
+ <application
+ android:name="org.qtproject.qt.android.bindings.QtApplication"
+ android:hardwareAccelerated="true"
+ android:label="${appName}"
+ android:requestLegacyExternalStorage="true"
+ android:allowBackup="true"
+ android:fullBackupOnly="false">
+ <activity
+ android:name="org.qtproject.qt.android.bindings.QtActivity"
+ android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
+ android:launchMode="singleTop"
+ android:screenOrientation="unspecified"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ <meta-data
+ android:name="android.app.lib_name"
+ android:value="tst_package_source_dir_partial_template" />
+
+ <meta-data
+ android:name="android.app.arguments"
+ android:value="" />
+ </activity>
+
+ <provider
+ android:name="androidx.core.content.FileProvider"
+ android:authorities="${applicationId}.qtprovider"
+ android:exported="false"
+ android:grantUriPermissions="true">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/qtprovider_paths"/>
+ </provider>
+ </application>
+</manifest>
diff --git a/tests/auto/other/android/package_source_dir/partial_template/app/build.gradle.in b/tests/auto/other/android/package_source_dir/partial_template/app/build.gradle.in
new file mode 100644
index 00000000000..538f1ca6217
--- /dev/null
+++ b/tests/auto/other/android/package_source_dir/partial_template/app/build.gradle.in
@@ -0,0 +1,54 @@
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:8.6.0'
+ }
+}
+
+apply plugin: '@GRADLE_PLUGIN_TYPE@'
+
+dependencies {
+ @GRADLE_DEPENDENCIES@
+}
+
+android {
+ namespace '@PACKAGE_NAME@'
+ compileSdkVersion '@ANDROID_COMPILE_SDK_VERSION@'
+ buildToolsVersion '@ANDROID_BUILD_TOOLS_VERSION@'
+ ndkVersion '@ANDROID_NDK_REVISION@'
+
+ defaultConfig {
+ @DEFAULT_CONFIG_VALUES@
+ manifestPlaceholders = [ appName:"tst_package_source_dir_partial_template_my" ]
+ }
+
+ sourceSets {
+ main {
+@SOURCE_SETS@
+ }
+ }
+
+ tasks.withType(JavaCompile) {
+ options.incremental = true
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ aaptOptions {
+ // Do not compress Qt binary resources file
+ noCompress 'rcc'
+ }
+
+ @ANDROID_DEPLOYMENT_EXTRAS@
+}
diff --git a/tests/auto/other/android/package_source_dir/tst_android_package_source_dir.cpp b/tests/auto/other/android/package_source_dir/tst_android_package_source_dir.cpp
new file mode 100644
index 00000000000..d74d388371f
--- /dev/null
+++ b/tests/auto/other/android/package_source_dir/tst_android_package_source_dir.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QCoreApplication>
+#include <QJniObject>
+#include <QTest>
+#include <QDebug>
+
+using namespace QNativeInterface;
+
+Q_DECLARE_JNI_CLASS(ApplicationInfo, "android/content/pm/ApplicationInfo")
+Q_DECLARE_JNI_CLASS(PackageManager, "android/content/pm/PackageManager")
+Q_DECLARE_JNI_CLASS(CharSequence, "java/lang/CharSequence")
+
+class tst_android_package_source_dir : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void applicationName();
+
+private:
+};
+
+void tst_android_package_source_dir::applicationName()
+{
+ QJniObject appCtx = QAndroidApplication::context();
+ QVERIFY(appCtx.isValid());
+
+ const auto appInfo = appCtx.callMethod<QtJniTypes::ApplicationInfo>("getApplicationInfo");
+ QVERIFY(appInfo.isValid());
+
+ const auto packageManager = appCtx.callMethod<QtJniTypes::PackageManager>("getPackageManager");
+ QVERIFY(packageManager.isValid());
+
+ const auto appNameLabel =
+ appInfo.callMethod<QtJniTypes::CharSequence>("loadLabel", packageManager);
+ QVERIFY(appNameLabel.isValid());
+
+ const auto appName = appNameLabel.callMethod<jstring>("toString").toString();
+
+ QCOMPARE_EQ(appName, QString::fromLatin1(EXPECTED_APP_NAME));
+}
+
+QTEST_MAIN(tst_android_package_source_dir);
+
+#include "tst_android_package_source_dir.moc"
diff --git a/tests/auto/other/android/permissions/CMakeLists.txt b/tests/auto/other/android/permissions/CMakeLists.txt
new file mode 100644
index 00000000000..0424c674e1b
--- /dev/null
+++ b/tests/auto/other/android/permissions/CMakeLists.txt
@@ -0,0 +1,23 @@
+# Copyright (C) 2025 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_android_permissions LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_android_permissions
+ SOURCES
+ tst_android_permissions.cpp
+)
+
+qt_add_android_permission(tst_android_permissions
+ NAME android.permission.ACCESS_COARSE_LOCATION
+)
+
+qt_add_android_permission(tst_android_permissions
+ NAME android.permission.ACCESS_FINE_LOCATION
+ ATTRIBUTES
+ maxSdkVersion 31
+)
diff --git a/tests/auto/other/android/permissions/tst_android_permissions.cpp b/tests/auto/other/android/permissions/tst_android_permissions.cpp
new file mode 100644
index 00000000000..5d7a255d3ac
--- /dev/null
+++ b/tests/auto/other/android/permissions/tst_android_permissions.cpp
@@ -0,0 +1,80 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QCoreApplication>
+#include <QJniObject>
+#include <QSet>
+#include <QString>
+#include <QTest>
+
+constexpr int GET_PERMISSIONS(0x00001000);
+
+using namespace QNativeInterface;
+using namespace Qt::StringLiterals;
+
+Q_DECLARE_JNI_CLASS(PackageManager, "android/content/pm/PackageManager")
+Q_DECLARE_JNI_CLASS(PackageInfo, "android/content/pm/PackageInfo")
+
+class tst_android_permissions : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void initTestCase();
+ void checkExpectedDefaults();
+ void checkNonExisting();
+ void checkNonDefaultPermissions();
+
+private:
+ QJniArray<QString> m_requestedPermissions;
+};
+
+void tst_android_permissions::initTestCase()
+{
+ QJniObject appCtx = QAndroidApplication::context();
+ QVERIFY(appCtx.isValid());
+
+ const auto packageName = appCtx.callMethod<QString>("getPackageName");
+ const auto packageManager = appCtx.callMethod<QtJniTypes::PackageManager>("getPackageManager");
+ QVERIFY(packageManager.isValid());
+
+ const auto packageInfo = QJniObject(packageManager.callMethod<QtJniTypes::PackageInfo>(
+ "getPackageInfo", packageName, jint(GET_PERMISSIONS)));
+ QVERIFY(packageInfo.isValid());
+
+ m_requestedPermissions = packageInfo.getField<QJniArray<QString>>("requestedPermissions");
+ QVERIFY(m_requestedPermissions.isValid());
+}
+
+void tst_android_permissions::checkExpectedDefaults()
+{
+ QSet<QString> expectedDefaults{ { "android.permission.INTERNET"_L1 },
+ { "android.permission.WRITE_EXTERNAL_STORAGE"_L1 },
+ { "android.permission.READ_EXTERNAL_STORAGE"_L1 } };
+
+ for (const auto &permission : m_requestedPermissions)
+ expectedDefaults.remove(permission);
+
+ QVERIFY(expectedDefaults.empty());
+}
+
+void tst_android_permissions::checkNonExisting()
+{
+ for (const auto &permission : m_requestedPermissions)
+ QCOMPARE_NE(permission, "android.permission.BLUETOOTH_SCAN");
+}
+
+void tst_android_permissions::checkNonDefaultPermissions()
+{
+ bool hasNonDefaultPermissions = false;
+ for (const auto &permission : m_requestedPermissions) {
+ if (permission == "android.permission.ACCESS_COARSE_LOCATION")
+ hasNonDefaultPermissions = true;
+ }
+
+ QVERIFY(hasNonDefaultPermissions);
+}
+
+QTEST_MAIN(tst_android_permissions);
+
+#include "tst_android_permissions.moc"
diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp
index 03be7aa0fe9..b651668cabd 100644
--- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp
+++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp
@@ -213,6 +213,7 @@ private slots:
void storeRestoreLowMemoryMode();
void setSectionResizeModeWithSectionWillTakeMemory();
void setModelWithAutoSizeWillSwitchToMemoryMode();
+ void tableViewResizeSectionsWillSwitchToMemoryMode();
void setDefaultSectionSizeRespectsColumnWidth();
@@ -3559,12 +3560,17 @@ struct TableViewWithBasicModel : public QTableView
emptyState = verticalHeader()->saveState();
setModel(&m);
header = verticalHeader();
+ horizontal_header = horizontalHeader();
}
bool hasLowMemoryUsage() const {
return emptyState.size() == header->saveState().size();
}
+ bool horizontalLowMememorUsage() const {
+ return emptyState.size() == horizontal_header->saveState().size();
+ }
+
bool hasHigherMemoryUsage() const {
const int delta = 1000;
return header->saveState().size() > delta + emptyState.size();
@@ -3572,6 +3578,7 @@ struct TableViewWithBasicModel : public QTableView
BasicModel m;
QHeaderView *header;
+ QHeaderView *horizontal_header;
QByteArray emptyState;
};
@@ -3770,6 +3777,15 @@ void tst_QHeaderView::setModelWithAutoSizeWillSwitchToMemoryMode()
QCOMPARE_GT(nonEmptyState.size(), emptyState.size() + delta);
}
+void tst_QHeaderView::tableViewResizeSectionsWillSwitchToMemoryMode()
+{
+ TableViewWithBasicModel tv;
+ QVERIFY(tv.horizontalLowMememorUsage());
+ tv.horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
+ tv.resizeColumnsToContents();
+ QVERIFY(!tv.horizontalLowMememorUsage());
+}
+
void tst_QHeaderView::setDefaultSectionSizeRespectsColumnWidth()
{
QTreeWidget tree;