diff --git a/.github/workflows/post-build-selective.yml b/.github/workflows/post-build-selective.yml index 0abed682c93..346c38e9330 100644 --- a/.github/workflows/post-build-selective.yml +++ b/.github/workflows/post-build-selective.yml @@ -60,6 +60,10 @@ jobs: sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm + - name: Cleanup any previous avd's to avoid signing key conflicts + if : ${{ inputs.install-android-sdk }} + run: rm -rf /home/runner/.config/.android/avd + - name: Set AVD environment variable globally if: ${{ inputs.install-android-sdk }} run: echo "ANDROID_AVD_HOME=/home/runner/.config/.android/avd" >> $GITHUB_ENV diff --git a/example/android/javalib/1-hello-world/build.mill b/example/android/javalib/1-hello-world/build.mill index 878cd3fc3a4..cf29c0213af 100644 --- a/example/android/javalib/1-hello-world/build.mill +++ b/example/android/javalib/1-hello-world/build.mill @@ -123,7 +123,7 @@ object app extends AndroidAppModule { > ./mill show app.startAndroidEmulator -> sleep 20 && ./mill show app.adbDevices +> ./mill show app.adbDevices ...emulator-5554...device... > ./mill show app.it | grep '"OK (1 test)"' diff --git a/example/android/kotlinlib/1-hello-kotlin/build.mill b/example/android/kotlinlib/1-hello-kotlin/build.mill index 283ee38953d..2d78a34e0ae 100644 --- a/example/android/kotlinlib/1-hello-kotlin/build.mill +++ b/example/android/kotlinlib/1-hello-kotlin/build.mill @@ -121,7 +121,7 @@ object app extends AndroidAppKotlinModule { > ./mill show app.startAndroidEmulator -> sleep 20 && ./mill show app.adbDevices +> ./mill show app.adbDevices ...emulator-5556...device... > ./mill show app.it | grep '"OK (1 test)"' diff --git a/scalalib/src/mill/javalib/android/AndroidAppBundle.scala b/scalalib/src/mill/javalib/android/AndroidAppBundle.scala index 1dc6dca18e9..6e19de3cff2 100644 --- a/scalalib/src/mill/javalib/android/AndroidAppBundle.scala +++ b/scalalib/src/mill/javalib/android/AndroidAppBundle.scala @@ -3,6 +3,7 @@ package mill.javalib.android import mill._ import mill.scalalib._ import mill.api.PathRef +import os.zip.ZipSource /** * A Trait for Android App Bundle Creation @@ -54,7 +55,7 @@ trait AndroidAppBundle extends AndroidAppModule with JavaModule { } } - os.zip(Task.dest / "bundle.zip", Seq(baseDir)) + os.zip(Task.dest / "bundle.zip", os.list(baseDir).map(ZipSource.fromPath)) PathRef(Task.dest / "bundle.zip") } diff --git a/scalalib/src/mill/javalib/android/AndroidAppModule.scala b/scalalib/src/mill/javalib/android/AndroidAppModule.scala index f3a655d4b2b..f235cb42a57 100644 --- a/scalalib/src/mill/javalib/android/AndroidAppModule.scala +++ b/scalalib/src/mill/javalib/android/AndroidAppModule.scala @@ -3,7 +3,7 @@ package mill.javalib.android import coursier.Repository import mill._ import mill.scalalib._ -import mill.api.PathRef +import mill.api.{Logger, PathRef} import mill.define.ModuleRef import mill.util.Jvm import os.RelPath @@ -810,7 +810,7 @@ trait AndroidAppModule extends JavaModule { * * @return The log line that indicates the emulator is ready */ - def startAndroidEmulator: T[String] = Task { + def startAndroidEmulator(): Command[String] = Task.Command(exclusive = true) { val ciSettings = Seq( "-no-snapshot-save", "-no-window", @@ -837,7 +837,7 @@ trait AndroidAppModule extends JavaModule { command ) - val bootMessage = startEmuCmd.stdout.buffered.lines().filter(l => { + val bootMessage: Option[String] = startEmuCmd.stdout.buffered.lines().filter(l => { T.log.debug(l.trim()) l.contains("Boot completed in") }).findFirst().toScala @@ -846,7 +846,9 @@ trait AndroidAppModule extends JavaModule { throw new Exception(s"Emulator failed to start: ${startEmuCmd.exitCode()}") } - T.log.info(s"Emulator started with message $bootMessage") + val emulator: String = waitForDevice(androidSdkModule().adbPath(), runningEmulator(), T.log) + + T.log.info(s"Emulator ${emulator} started with message $bootMessage") bootMessage.get } @@ -855,30 +857,6 @@ trait AndroidAppModule extends JavaModule { os.call((androidSdkModule().adbPath().path, "devices", "-l")).out.text() } - def waitForDevice: Target[String] = Task { - val emulator = runningEmulator() - os.call(( - androidSdkModule().adbPath().path, - "-s", - emulator, - "wait-for-device" - )) - val bootflag = os.call( - ( - androidSdkModule().adbPath().path, - "-s", - emulator, - "shell", - "getprop", - "sys.boot_completed" - ) - ) - - T.log.info(s"$emulator, bootflag is $bootflag") - - emulator - } - /** * Stops the android emulator */ @@ -976,6 +954,42 @@ trait AndroidAppModule extends JavaModule { relPath.last == "module-info.class" } + private def waitForDevice(adbPath: PathRef, emulator: String, logger: Logger): String = { + val BootedIndicator = "1" + def getBootflag: String = { + val result = os.call( + ( + adbPath.path, + "-s", + emulator, + "shell", + "getprop", + "sys.boot_completed" + ), + check = false + ) + if (result.exitCode != 0) + "0" + else + result.out.trim() + } + + var bootflag = getBootflag + var triesLeft = 25 + + while (bootflag != BootedIndicator && triesLeft > 0) { + logger.debug(s"Waiting for device to boot. Bootflag: $bootflag . Tries left ${triesLeft}") + Thread.sleep(1000) + triesLeft -= 1 + bootflag = getBootflag + } + + if (bootflag == BootedIndicator) + emulator + else + throw new Exception("Device failed to boot") + } + trait AndroidAppTests extends JavaTests { private def testPath = parent.millSourcePath / "src/test"