From 4fa52298e5e29f7d3b35bb7a0bfb19cfe75f42a8 Mon Sep 17 00:00:00 2001 From: Bart Louwers Date: Mon, 23 Feb 2026 23:01:38 +0100 Subject: [PATCH] Show progress on device when Android render test is running (#4119) --- .../android/src/test/render_test_runner.cpp | 26 ++++++-- .../default/src/mbgl/render-test/main.cpp | 2 +- .../java/android/app/NativeActivityTest.java | 2 +- .../android/app/src/main/AndroidManifest.xml | 2 +- .../java/android/app/RenderTestActivity.java | 60 +++++++++++++++++++ render-test/include/mbgl/render_test.hpp | 7 ++- render-test/ios/ios_test_runner.cpp | 6 +- render-test/render_test.cpp | 6 +- 8 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 render-test/android/app/src/main/java/android/app/RenderTestActivity.java diff --git a/platform/android/src/test/render_test_runner.cpp b/platform/android/src/test/render_test_runner.cpp index b94d696ef..91d43a74c 100644 --- a/platform/android/src/test/render_test_runner.cpp +++ b/platform/android/src/test/render_test_runner.cpp @@ -1,11 +1,24 @@ #include #include "test_runner_common.hpp" -#include - using namespace mbgl; using namespace mbgl::android; +void updateProgress(JNIEnv* env, struct android_app* app, int completed, int total) { + jobject nativeActivity = app->activity->clazz; + jclass acl = env->GetObjectClass(nativeActivity); + jmethodID updateMethod = env->GetMethodID(acl, "updateProgress", "(II)V"); + if (env->ExceptionCheck()) { + env->ExceptionClear(); + env->DeleteLocalRef(acl); + return; + } + if (updateMethod != nullptr) { + env->CallVoidMethod(nativeActivity, updateMethod, completed, total); + } + env->DeleteLocalRef(acl); +} + void android_main(struct android_app* app) { mbgl::android::theJVM = app->activity->vm; JNIEnv* env = nullptr; @@ -24,7 +37,7 @@ void android_main(struct android_app* app) { unZipFile(env, zipFile, storagePath); auto runTestWithManifest = - [&storagePath, &app, &outFd, &outEvents, &source](const std::string& manifest) -> bool { + [&storagePath, &app, &env, &outFd, &outEvents, &source](const std::string& manifest) -> bool { const std::string configFile = storagePath + manifest; std::vector arguments = {"mbgl-render-test-runner", "-p", configFile, "-u", "rebaseline"}; std::vector argv; @@ -33,8 +46,7 @@ void android_main(struct android_app* app) { } argv.push_back(nullptr); - int finishedTestCount = 0; - std::function testStatus = [&]() { + std::function testStatus = [&](mbgl::TestStatus status) { auto result = ALooper_pollOnce(0, &outFd, &outEvents, reinterpret_cast(&source)); if (result == ALOOPER_POLL_ERROR) { throw std::runtime_error("ALooper_pollOnce returned an error"); @@ -45,7 +57,9 @@ void android_main(struct android_app* app) { } mbgl::Log::Info(mbgl::Event::General, - "Current finished tests number is '" + std::to_string(++finishedTestCount) + "'"); + "Current finished tests number is '" + std::to_string(status.completed) + "/" + + std::to_string(status.total) + "'"); + updateProgress(env, app, static_cast(status.completed), static_cast(status.total)); }; mbgl::Log::Info(mbgl::Event::General, "Start running RenderTestRunner with manifest: '" + manifest + "'"); bool result = mbgl::runRenderTests(argv.size() - 1, argv.data(), testStatus) == 0; diff --git a/platform/default/src/mbgl/render-test/main.cpp b/platform/default/src/mbgl/render-test/main.cpp index 88247aeea..e8df75bde 100644 --- a/platform/default/src/mbgl/render-test/main.cpp +++ b/platform/default/src/mbgl/render-test/main.cpp @@ -12,7 +12,7 @@ int main(int argc, char* argv[]) { #ifdef IS_IOS try { #endif - return mbgl::runRenderTests(argc, argv, []() {}); + return mbgl::runRenderTests(argc, argv, [](mbgl::TestStatus) {}); #ifdef IS_IOS } catch (std::exception const& e) { std::cerr << "Caught an exception while running tests\n" << e.what() << '\n'; diff --git a/render-test/android/app/src/androidTest/java/android/app/NativeActivityTest.java b/render-test/android/app/src/androidTest/java/android/app/NativeActivityTest.java index 8264bebb0..c917247b4 100644 --- a/render-test/android/app/src/androidTest/java/android/app/NativeActivityTest.java +++ b/render-test/android/app/src/androidTest/java/android/app/NativeActivityTest.java @@ -16,7 +16,7 @@ import org.junit.runner.RunWith; public class NativeActivityTest { @Rule - public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(NativeActivity.class, false, false); + public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(RenderTestActivity.class, false, false); @Test(timeout = 600000L) public void runRenderTests() throws Exception { diff --git a/render-test/android/app/src/main/AndroidManifest.xml b/render-test/android/app/src/main/AndroidManifest.xml index c091e7bf3..d173d45b8 100644 --- a/render-test/android/app/src/main/AndroidManifest.xml +++ b/render-test/android/app/src/main/AndroidManifest.xml @@ -13,7 +13,7 @@ android:debuggable="true" tools:ignore="HardcodedDebugMode"> - diff --git a/render-test/android/app/src/main/java/android/app/RenderTestActivity.java b/render-test/android/app/src/main/java/android/app/RenderTestActivity.java new file mode 100644 index 000000000..9d297f356 --- /dev/null +++ b/render-test/android/app/src/main/java/android/app/RenderTestActivity.java @@ -0,0 +1,60 @@ +package android.app; + +import android.graphics.PixelFormat; +import android.os.Bundle; +import android.view.Gravity; +import android.view.WindowManager; +import android.widget.TextView; + +public class RenderTestActivity extends NativeActivity { + + private TextView progressTextView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + progressTextView = new TextView(this); + progressTextView.setText("Starting tests..."); + progressTextView.setTextSize(18f); + progressTextView.setTextColor(0xFFFFFFFF); + progressTextView.setShadowLayer(2f, 1f, 1f, 0xFF000000); + progressTextView.setPadding(24, 24, 24, 24); + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + + WindowManager.LayoutParams params = new WindowManager.LayoutParams( + WindowManager.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, + PixelFormat.TRANSLUCENT + ); + params.gravity = Gravity.TOP | Gravity.START; + params.token = getWindow().getDecorView().getWindowToken(); + + getWindowManager().addView(progressTextView, params); + } + + @Override + public void onDetachedFromWindow() { + if (progressTextView != null) { + getWindowManager().removeView(progressTextView); + } + super.onDetachedFromWindow(); + } + + /** + * Called from C++ via JNI to update the progress display. + */ + public void updateProgress(final int completed, final int total) { + runOnUiThread(() -> { + if (progressTextView != null) { + progressTextView.setText(completed + " / " + total + " tests complete"); + } + }); + } +} diff --git a/render-test/include/mbgl/render_test.hpp b/render-test/include/mbgl/render_test.hpp index 1669e5993..8f83ece69 100644 --- a/render-test/include/mbgl/render_test.hpp +++ b/render-test/include/mbgl/render_test.hpp @@ -4,6 +4,11 @@ namespace mbgl { -int runRenderTests(int argc, char* argv[], std::function); +struct TestStatus { + size_t completed; + size_t total; +}; + +int runRenderTests(int argc, char* argv[], std::function); } // namespace mbgl diff --git a/render-test/ios/ios_test_runner.cpp b/render-test/ios/ios_test_runner.cpp index 66cac4981..2fa7b4dd6 100644 --- a/render-test/ios/ios_test_runner.cpp +++ b/render-test/ios/ios_test_runner.cpp @@ -18,10 +18,10 @@ bool TestRunner::startTest(const std::string& manifestBasePath) { } argv.push_back(nullptr); - int finishedTestCount = 0; - std::function testStatus = [&]() { + std::function testStatus = [&](mbgl::TestStatus status) { mbgl::Log::Info(mbgl::Event::General, - "Current finished tests number is '" + std::to_string(++finishedTestCount) + "' "); + "Current finished tests number is '" + std::to_string(status.completed) + "/" + + std::to_string(status.total) + "' "); }; mbgl::Log::Info(mbgl::Event::General, "Start running RenderTestRunner with manifest: '" + manifest + "' "); diff --git a/render-test/render_test.cpp b/render-test/render_test.cpp index b9e504e5a..d427f3fcb 100644 --- a/render-test/render_test.cpp +++ b/render-test/render_test.cpp @@ -185,7 +185,7 @@ void runWithAlternateSources(TestRunner& runner, TestMetadata& metadata, bool& e } // namespace namespace mbgl { -int runRenderTests(int argc, char** argv, std::function testStatus) { +int runRenderTests(int argc, char** argv, std::function testStatus) { int returnCode = 0; bool recycleMap; bool shuffle; @@ -226,6 +226,8 @@ int runRenderTests(int argc, char** argv, std::function testStatus) { metadatas.reserve(testPaths.size()); TestStatistics stats; + const uint32_t totalTests = static_cast(testPaths.size()); + uint32_t completedTests = 0; for (auto& testPath : testPaths) { TestMetadata metadata = parseTestMetadata(testPath); @@ -324,7 +326,7 @@ int runRenderTests(int argc, char** argv, std::function testStatus) { metadatas.push_back(std::move(metadata)); if (testStatus) { - testStatus(); + testStatus({.completed = ++completedTests, .total = totalTests}); } }