From 69a8dda75ad506045db7696be45f01b718d10149 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 8 Apr 2026 15:26:40 -0300 Subject: [PATCH] Add scripts for taking localized screenshots --- .../ui/screenshots/LocalizedScreenshotTest.kt | 9 ++-- tools/screenshot-demo-mode.sh | 31 ++++++++++++ tools/take-screenshots.py | 47 +++++++++++++++++++ 3 files changed, 83 insertions(+), 4 deletions(-) create mode 100755 tools/screenshot-demo-mode.sh create mode 100755 tools/take-screenshots.py diff --git a/app/src/androidTest/java/org/fdroid/ui/screenshots/LocalizedScreenshotTest.kt b/app/src/androidTest/java/org/fdroid/ui/screenshots/LocalizedScreenshotTest.kt index 2f3e153e3..645af2519 100644 --- a/app/src/androidTest/java/org/fdroid/ui/screenshots/LocalizedScreenshotTest.kt +++ b/app/src/androidTest/java/org/fdroid/ui/screenshots/LocalizedScreenshotTest.kt @@ -28,14 +28,13 @@ import org.junit.Assume.assumeTrue import org.junit.Before import org.junit.Rule -private const val ENABLED = false - @OptIn(DelicateCoilApi::class) abstract class LocalizedScreenshotTest(val localeName: String) { @get:Rule val composeRule = createComposeRule() companion object { val locales: List by lazy { + if (!enabled) return@lazy emptyList() val fallback = listOf("en-US", "de-DE", "ar-SA", "he", "zh-CN") if (SDK_INT >= 33) { val localeConfig = LocaleConfig(InstrumentationRegistry.getInstrumentation().targetContext) @@ -51,6 +50,8 @@ abstract class LocalizedScreenshotTest(val localeName: String) { fallback } } + val enabled: Boolean + get() = InstrumentationRegistry.getArguments().getString("fdroid_screenshots") == "true" } private val context = InstrumentationRegistry.getInstrumentation().targetContext @@ -66,7 +67,7 @@ abstract class LocalizedScreenshotTest(val localeName: String) { @Before fun before() { - assumeTrue(ENABLED) + assumeTrue(enabled) } protected fun screenshotTest( @@ -106,7 +107,7 @@ abstract class LocalizedScreenshotTest(val localeName: String) { val dir = context.getExternalFilesDir("screenshots") ?: fail("Could not create screenshots dir") assertTrue(dir.isDirectory) val subDir = - File(dir, "${FLAVOR_variant}/fastlane/metadata/$localeName/images/phoneScreenshots") + File(dir, "${FLAVOR_variant}/fastlane/metadata/android/$localeName/images/phoneScreenshots") subDir.mkdirs() assertTrue(subDir.isDirectory) diff --git a/tools/screenshot-demo-mode.sh b/tools/screenshot-demo-mode.sh new file mode 100755 index 000000000..c24959ab3 --- /dev/null +++ b/tools/screenshot-demo-mode.sh @@ -0,0 +1,31 @@ +#!/bin/sh +CMD=$1 + +if [[ $ADB == "" ]]; then + ADB=adb +fi + +if [[ $CMD != "on" && $CMD != "off" ]]; then + echo "Usage: $0 [on|off]" >&2 + exit +fi + +$ADB root || exit +$ADB wait-for-devices +$ADB shell settings put system time_12_24 24 +$ADB shell settings put global sysui_demo_allowed 1 + +if [ $CMD == "on" ]; then + $ADB shell settings put system screen_off_timeout 2147483647 + $ADB shell am broadcast -a com.android.systemui.demo -e command enter || exit + $ADB shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm 1337 + $ADB shell am broadcast -a com.android.systemui.demo -e command battery -e plugged false + $ADB shell am broadcast -a com.android.systemui.demo -e command battery -e level 100 + $ADB shell am broadcast -a com.android.systemui.demo -e command network -e wifi show -e fully true -e level 4 + $ADB shell am broadcast -a com.android.systemui.demo -e command network -e mobile show -e fully true -e datatype none -e level 4 + $ADB shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false +elif [ $CMD == "off" ]; then + $ADB shell am broadcast -a com.android.systemui.demo -e command exit + $ADB shell settings put system screen_off_timeout 30000 + $ADB shell settings put global sysui_demo_allowed 0 +fi diff --git a/tools/take-screenshots.py b/tools/take-screenshots.py new file mode 100755 index 000000000..1b988ab38 --- /dev/null +++ b/tools/take-screenshots.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# +# Takes localized screenshots on a device and saves them to the proper directory. +# +# Careful: this removes ../screenshots folder if it exists. Also removes screenshots from device. +# +import shutil +import subprocess +from pathlib import Path + +script_dir = Path(__file__).parent.resolve() +screenshots_dir = script_dir.parent / 'screenshots' + +shutil.rmtree(screenshots_dir, ignore_errors=True) +subprocess.run(["adb", "shell", "rm", "-r", "/sdcard/Android/data/org.fdroid.basic.debug/files/screenshots"]) +subprocess.run(["./screenshot-demo-mode.sh", "on"], cwd=script_dir) +try: + print("Running connectedAndroidTest to take screenshots...") + subprocess.run(["./gradlew", ":app:connectedBasicDefaultDebugAndroidTest", + "-Pandroid.testInstrumentationRunnerArguments.fdroid_screenshots=true"], + cwd=script_dir.parent, check=True) + + print("Downloading screenshots...") + screenshots_dir = script_dir.parent / 'screenshots' + subprocess.run( + ["adb", "pull", "/sdcard/Android/data/org.fdroid.basic.debug/files/screenshots", script_dir.parent], + cwd=script_dir.parent, check=True) + + print("Running pngquant on screenshots...") + screenshots = [str(f) for f in screenshots_dir.glob('basic/fastlane/metadata/android/*/images/*/*')] + for screenshot in screenshots: + subprocess.run(["pngquant", "--force", "--ext", ".png", "--skip-if-larger", "--speed", "1", screenshot]) + + target_dir = script_dir.parent / 'src' + old_screenshots = [str(f) for f in target_dir.glob('basic/fastlane/metadata/android/*/images/phoneScreenshots/*')] + for s in old_screenshots: + print(f"Removing old screenshot {s}") + Path(s).unlink() + + print("Copying new screenshots to target directory...") + shutil.copytree(screenshots_dir, target_dir, dirs_exist_ok=True) + + subprocess.run(["git", "add", target_dir], cwd=script_dir.parent) + subprocess.run(["git", "status"], cwd=script_dir.parent) + +finally: + subprocess.run(["./screenshot-demo-mode.sh", "off"], cwd=script_dir)