fix(android): isolate debug app installs (#125099)

This commit is contained in:
Peter Steinberger
2026-08-16 23:36:57 -07:00
committed by GitHub
parent ac5c8be001
commit 3010318ba3
14 changed files with 66 additions and 25 deletions
+27 -1
View File
@@ -2,6 +2,7 @@ import com.android.build.api.variant.impl.VariantOutputImpl
import org.gradle.api.DefaultTask
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.tasks.Exec
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputDirectory
@@ -16,6 +17,7 @@ import java.util.Properties
import javax.inject.Inject
val dnsjavaInetAddressResolverService = "META-INF/services/java.net.spi.InetAddressResolverProvider"
val openClawAndroidApplicationId = "ai.openclaw.app"
val openClawAndroidVersionFile = rootProject.file("Config/Version.properties")
val thirdPartyLicensesDir = rootProject.file("THIRD_PARTY_LICENSES")
val openClawRepositoryRoot = rootProject.projectDir.resolve("../..").canonicalFile
@@ -214,7 +216,8 @@ android {
}
defaultConfig {
applicationId = "ai.openclaw.app"
applicationId = openClawAndroidApplicationId
resValue("string", "application_id", openClawAndroidApplicationId)
minSdk = 31
targetSdk = 36
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@@ -254,6 +257,9 @@ android {
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
debug {
applicationIdSuffix = ".debug"
versionNameSuffix = "-debug"
resValue("string", "application_id", "$openClawAndroidApplicationId.debug")
isMinifyEnabled = false
}
}
@@ -269,6 +275,7 @@ android {
buildFeatures {
compose = true
buildConfig = true
resValues = true
}
androidResources {
@@ -333,6 +340,7 @@ android {
}
androidComponents {
val adbExecutable = sdkComponents.adb
onVariants { variant ->
variant.sources.assets?.addGeneratedSourceDirectory(
stageCanvasA2ui,
@@ -352,6 +360,24 @@ androidComponents {
}
output.outputFileName = outputFileName
}
if (variant.buildType == "debug") {
val variantNameCapitalized = variant.name.replaceFirstChar(Char::titlecase)
tasks.register<Exec>("run$variantNameCapitalized") {
group = "install"
description = "Installs and launches the ${variant.name} app."
dependsOn("install$variantNameCapitalized")
commandLine(
adbExecutable.get().asFile.absolutePath,
"shell",
"am",
"start",
"-W",
"-n",
"${variant.applicationId.get()}/$openClawAndroidApplicationId.MainActivity",
)
}
}
}
}
kotlin {
@@ -22,7 +22,7 @@
android:permission="${applicationId}.permission.RUN_VOICE_E2E"
android:exported="false">
<intent-filter>
<action android:name="ai.openclaw.app.debug.RUN_VOICE_E2E" />
<action android:name="${applicationId}.RUN_VOICE_E2E" />
</intent-filter>
</receiver>
<service
@@ -0,0 +1,3 @@
<resources>
<string name="app_name" translatable="false">OpenClaw Dev</string>
</resources>
@@ -10,7 +10,7 @@ import java.util.Locale
const val actionAskOpenClaw = "ai.openclaw.app.action.ASK_OPENCLAW"
/** Debug action that opens the Voice tab directly for Android E2E automation. */
const val actionOpenVoiceE2e = "ai.openclaw.app.debug.OPEN_VOICE_E2E"
val actionOpenVoiceE2e = "${BuildConfig.APPLICATION_ID}.OPEN_VOICE_E2E"
/** Intent extra that carries an optional assistant prompt for app actions. */
const val extraAssistantPrompt = "prompt"
@@ -5,7 +5,7 @@
app:queryPatterns="@array/ask_openclaw_query_patterns">
<intent
android:action="ai.openclaw.app.action.ASK_OPENCLAW"
android:targetPackage="ai.openclaw.app"
android:targetPackage="@string/application_id"
android:targetClass="ai.openclaw.app.MainActivity">
<parameter
android:name="prompt"
@@ -16,13 +16,15 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class CronJobNavigationTest {
private lateinit var device: UiDevice
private val packageName: String
get() = InstrumentationRegistry.getInstrumentation().targetContext.packageName
@Before
fun setUp() {
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
device.executeShellCommand("am force-stop $packageName")
device.executeShellCommand(
"am start -W -n $packageName/.MainActivity " +
"am start -W -n $packageName/ai.openclaw.app.MainActivity " +
"--ez openclaw.screenshotMode true --es openclaw.screenshotScene settings",
)
assertNotNull(device.wait(Until.findObject(By.text("Settings")), waitTimeoutMs))
@@ -72,7 +74,6 @@ class CronJobNavigationTest {
}
private companion object {
const val packageName = "ai.openclaw.app"
const val waitTimeoutMs = 10_000L
const val shortWaitMs = 1_000L
const val maxScrolls = 6
@@ -18,7 +18,8 @@ class StartupMacrobenchmark {
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
private val packageName = "ai.openclaw.app"
private val packageName: String
get() = InstrumentationRegistry.getInstrumentation().targetContext.packageName
@Test
fun coldStartup() {
@@ -5,8 +5,8 @@ SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
ANDROID_DIR="$(cd -- "$SCRIPT_DIR/.." && pwd)"
RESULTS_DIR="$ANDROID_DIR/benchmark/results"
PACKAGE="ai.openclaw.app"
ACTIVITY=".MainActivity"
PACKAGE="ai.openclaw.app.debug"
ACTIVITY="ai.openclaw.app.MainActivity"
DEVICE_SERIAL=""
INSTALL_APP="1"
LAUNCH_RUNS="4"
@@ -27,8 +27,8 @@ Assumes the app can reach a live gateway and will show "Connected" in the UI.
Options:
--device <serial> adb device serial
--package <pkg> package name (default: ai.openclaw.app)
--activity <activity> launch activity (default: .MainActivity)
--package <pkg> package name (default: ai.openclaw.app.debug)
--activity <activity> launch activity (default: ai.openclaw.app.MainActivity)
--skip-install skip :app:installPlayDebug
--launch-runs <n> launch-to-connected runs (default: 4)
--screen-loops <n> screen benchmark loops (default: 6)
@@ -4,8 +4,8 @@ set -euo pipefail
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
ANDROID_DIR="$(cd -- "$SCRIPT_DIR/.." && pwd)"
PACKAGE="ai.openclaw.app"
ACTIVITY=".MainActivity"
PACKAGE="ai.openclaw.app.debug"
ACTIVITY="ai.openclaw.app.MainActivity"
DURATION_SECONDS="10"
OUTPUT_PERF_DATA=""
+7 -5
View File
@@ -3,10 +3,12 @@ set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
ANDROID_DIR="$ROOT_DIR/apps/android"
PACKAGE_NAME="ai.openclaw.app"
RECEIVER="$PACKAGE_NAME/.VoiceE2eReceiver"
RUN_ACTION="ai.openclaw.app.debug.RUN_VOICE_E2E"
OPEN_ACTION="ai.openclaw.app.debug.OPEN_VOICE_E2E"
APP_NAMESPACE="ai.openclaw.app"
PACKAGE_NAME="$APP_NAMESPACE.debug"
MAIN_ACTIVITY="$PACKAGE_NAME/$APP_NAMESPACE.MainActivity"
RECEIVER="$PACKAGE_NAME/$APP_NAMESPACE.VoiceE2eReceiver"
RUN_ACTION="$PACKAGE_NAME.RUN_VOICE_E2E"
OPEN_ACTION="$PACKAGE_NAME.OPEN_VOICE_E2E"
PORT=18789
HOST="127.0.0.1"
MODE="both"
@@ -146,7 +148,7 @@ fi
adb shell pm grant "$PACKAGE_NAME" android.permission.RECORD_AUDIO >/dev/null 2>&1 || true
adb shell am force-stop "$PACKAGE_NAME" >/dev/null
adb shell am start -a "$OPEN_ACTION" -n "$PACKAGE_NAME/.MainActivity" >/dev/null
adb shell am start -a "$OPEN_ACTION" -n "$MAIN_ACTIVITY" >/dev/null
adb logcat -c
run_mode() {
+4
View File
@@ -51,6 +51,10 @@ android {
}
buildTypes {
debug {
applicationIdSuffix = ".debug"
versionNameSuffix = "-debug"
}
release {
if (phoneReleaseSigning != null) {
signingConfig = phoneReleaseSigning
@@ -0,0 +1,3 @@
<resources>
<string name="app_name" translatable="false">OpenClaw Dev</string>
</resources>
+2 -2
View File
@@ -1482,8 +1482,8 @@
"android:install:third-party": "node --import tsx scripts/run-android-gradle.mts :app:installThirdPartyDebug",
"android:lint": "cd apps/android && ./gradlew :app:ktlintCheck :benchmark:ktlintCheck :wear:ktlintCheck :wear-shared:ktlintCheck",
"android:lint:android": "node --import tsx scripts/run-android-gradle.mts :app:lintPlayDebug :app:lintThirdPartyDebug :wear:lintDebug :wear-shared:lintDebug",
"android:run": "node --import tsx scripts/run-android-gradle.mts :app:installPlayDebug -- adb shell am start -n ai.openclaw.app/.MainActivity",
"android:run:third-party": "node --import tsx scripts/run-android-gradle.mts :app:installThirdPartyDebug -- adb shell am start -n ai.openclaw.app/.MainActivity",
"android:run": "node --import tsx scripts/run-android-gradle.mts :app:runPlayDebug",
"android:run:third-party": "node --import tsx scripts/run-android-gradle.mts :app:runThirdPartyDebug",
"android:release": "bash scripts/android-release.sh",
"android:release:archive": "bash -lc 'source ./scripts/lib/android-fastlane.sh && cd apps/android && run_android_fastlane android play_store_archive'",
"android:release:auth:check": "bash -lc 'source ./scripts/lib/android-fastlane.sh && cd apps/android && run_android_fastlane android auth_check'",
+6 -5
View File
@@ -46,7 +46,8 @@ DRY_RUN=0
SCENES=(home chat settings gateway voice-wake)
OUTPUT_TYPE="phoneScreenshots"
GRADLE_ASSEMBLE_TASK=":app:assemblePlayDebug"
ACTIVITY_COMPONENT="ai.openclaw.app/.MainActivity"
APP_PACKAGE="ai.openclaw.app.debug"
ACTIVITY_COMPONENT="$APP_PACKAGE/ai.openclaw.app.MainActivity"
EMULATOR_PID=""
EMULATOR_LOG=""
STARTED_EMULATOR=0
@@ -147,7 +148,7 @@ case "$FORM_FACTOR" in
SCENES=(chat voice controls)
OUTPUT_TYPE="wearScreenshots"
GRADLE_ASSEMBLE_TASK=":wear:assembleDebug"
ACTIVITY_COMPONENT="ai.openclaw.app/ai.openclaw.wear.MainActivity"
ACTIVITY_COMPONENT="$APP_PACKAGE/ai.openclaw.wear.MainActivity"
ARTIFACT_DIR="${ARTIFACT_ROOT}/wear"
;;
*)
@@ -729,8 +730,8 @@ elif [[ "$SKIP_BUILD" != "1" ]]; then
)
fi
"$ADB_BIN" -s "$ADB_SERIAL" shell pm clear ai.openclaw.app >/dev/null
"$ADB_BIN" -s "$ADB_SERIAL" shell pm grant ai.openclaw.app android.permission.RECORD_AUDIO >/dev/null
"$ADB_BIN" -s "$ADB_SERIAL" shell pm clear "$APP_PACKAGE" >/dev/null
"$ADB_BIN" -s "$ADB_SERIAL" shell pm grant "$APP_PACKAGE" android.permission.RECORD_AUDIO >/dev/null
"$ADB_BIN" -s "$ADB_SERIAL" logcat -c >/dev/null 2>&1 || true
for scene in "${SCENES[@]}"; do
@@ -739,7 +740,7 @@ for scene in "${SCENES[@]}"; do
artifact_path="${ARTIFACT_DIR}/screenshots/openclaw-${scene}.jpg"
ui_dump_path="${ARTIFACT_DIR}/ui-dumps/openclaw-${scene}.xml"
activity_start_path="${ARTIFACT_DIR}/activity-start/openclaw-${scene}.txt"
"$ADB_BIN" -s "$ADB_SERIAL" shell am force-stop ai.openclaw.app >/dev/null
"$ADB_BIN" -s "$ADB_SERIAL" shell am force-stop "$APP_PACKAGE" >/dev/null
"$ADB_BIN" -s "$ADB_SERIAL" shell input keyevent 224 >/dev/null 2>&1 || true
"$ADB_BIN" -s "$ADB_SERIAL" shell wm dismiss-keyguard >/dev/null 2>&1 || true
"$ADB_BIN" -s "$ADB_SERIAL" shell am start -W \