From a45640c5be8abdb04519e4a1096fe3d753ed4995 Mon Sep 17 00:00:00 2001 From: Cedric Beust Date: Tue, 24 Nov 2015 03:00:33 -0800 Subject: [PATCH] Add "run" to the Android plug-in. --- .../kobalt/plugin/android/AndroidFiles.kt | 5 ++ .../plugin/android/AndroidManifestXml.kt | 74 +++++++++++++++++++ .../kobalt/plugin/android/AndroidPlugin.kt | 19 ++++- .../plugin/application/ApplicationPlugin.kt | 4 +- 4 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 src/main/kotlin/com/beust/kobalt/plugin/android/AndroidManifestXml.kt diff --git a/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidFiles.kt b/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidFiles.kt index aeee62ca..5ba54f7f 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidFiles.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidFiles.kt @@ -1,6 +1,7 @@ package com.beust.kobalt.plugin.android import com.beust.kobalt.Variant +import com.beust.kobalt.api.KobaltContext import com.beust.kobalt.api.Project import com.beust.kobalt.misc.KFiles @@ -11,6 +12,10 @@ class AndroidFiles { fun intermediates(project: Project) = KFiles.joinDir(project.directory, project.buildDirectory, "intermediates") + fun manifest(project: Project, context: KobaltContext) : String { + return KFiles.joinDir(project.directory, "src/main", "AndroidManifest.xml") + } + fun mergedManifest(project: Project, variant: Variant) : String { val dir = KFiles.joinAndMakeDir(intermediates(project), "manifests", "full", variant.toIntermediateDir()) return KFiles.joinDir(dir, "AndroidManifest.xml") diff --git a/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidManifestXml.kt b/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidManifestXml.kt new file mode 100644 index 00000000..2a101d10 --- /dev/null +++ b/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidManifestXml.kt @@ -0,0 +1,74 @@ +package com.beust.kobalt.plugin.android + +import java.io.InputStream +import javax.xml.bind.JAXBContext +import javax.xml.bind.annotation.XmlAttribute +import javax.xml.bind.annotation.XmlElement +import javax.xml.bind.annotation.XmlRootElement + +/** + * Parse AndroidManifest.xml and expose its content. + */ +class AndroidManifest(val ins: InputStream) { + val manifest: AndroidManifestXml by lazy { + val jaxbContext = JAXBContext.newInstance(AndroidManifestXml::class.java) + jaxbContext.createUnmarshaller().unmarshal(ins) as AndroidManifestXml + } + + val pkg by lazy { + manifest.pkg + } + + val mainActivity: String? by lazy { + fun isLaunch(act: ActivityXml) : Boolean { + val r = act.intentFilters.filter { inf: IntentFilter -> + inf.action?.name == "android.intent.action.MAIN" && + inf.category?.name == "android.intent.category.LAUNCHER" + } + return r.size > 0 + } + val act = manifest.application?.activities?.filter { isLaunch(it) } + if (act != null && act.size > 0) { + act.get(0).name?.let { n -> + if (n.startsWith(".")) pkg + "." + n.substring(1) else n + } + } else { + null + } + } +} + +@XmlRootElement(name = "manifest") +class AndroidManifestXml { + @XmlAttribute(name = "package") @JvmField + val pkg: String? = null + var application: ApplicationXml? = null +} + +class ApplicationXml { + @XmlElement(name = "activity") @JvmField + var activities: List = arrayListOf() +} + +class ActivityXml { + @XmlAttribute(namespace = "http://schemas.android.com/apk/res/android", name = "name") @JvmField + var name: String? = null + + @XmlElement(name = "intent-filter") @JvmField + var intentFilters: List = arrayListOf() +} + +class IntentFilter { + var action: ActionXml? = null + var category: CategoryXml? = null +} + +class ActionXml { + @XmlAttribute(namespace = "http://schemas.android.com/apk/res/android", name = "name") @JvmField + var name: String? = null +} + +class CategoryXml { + @XmlAttribute(namespace = "http://schemas.android.com/apk/res/android", name = "name") @JvmField + var name: String? = null +} diff --git a/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidPlugin.kt index 283b3693..8fb43b7a 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidPlugin.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/android/AndroidPlugin.kt @@ -19,6 +19,7 @@ import com.google.common.collect.HashMultimap import com.google.inject.Inject import com.google.inject.Singleton import java.io.File +import java.io.FileInputStream import java.net.URI import java.nio.file.Path import java.nio.file.Paths @@ -43,7 +44,7 @@ fun Project.android(init: AndroidConfig.() -> Unit) : AndroidConfig { @Singleton public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler, val merger: Merger) : ConfigPlugin(), IClasspathContributor, IRepoContributor, ICompilerFlagContributor, - ICompilerInterceptor, IBuildDirectoryIncerceptor { + ICompilerInterceptor, IBuildDirectoryIncerceptor, IRunContributor { override val name = "android" fun isAndroid(project: Project) = configurationFor(project) != null @@ -371,5 +372,21 @@ public class AndroidPlugin @Inject constructor(val javaCompiler: JavaCompiler, v return result } + // IRunContributor + override fun runAffinity(project: Project, context: KobaltContext): Int { + val manifest = AndroidFiles.manifest(project, context) + return if (File(manifest).exists()) IRunContributor.DEFAULT_POSITIVE_AFFINITY else 0 + } + + override fun run(project: Project, context: KobaltContext): TaskResult { + val manifest = AndroidFiles.manifest(project, context) + FileInputStream(File(manifest)).use { ins -> + // adb shell am start -n com.package.name/com.package.name.ActivityName + val manifest = AndroidManifest(ins) + RunCommand(adb(project)).useErrorStreamAsErrorIndicator(false).run(args = listOf( + "shell", "am", "start", "-n", manifest.pkg + "/" + manifest.mainActivity)) + return TaskResult() + } + } } diff --git a/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt b/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt index aa4e6d4d..7b3e6de8 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/application/ApplicationPlugin.kt @@ -43,10 +43,10 @@ class ApplicationPlugin @Inject constructor(val executors: KobaltExecutors, override fun apply(project: Project, context: KobaltContext) { super.apply(project, context) - addVariantTasks(project, "run", runAfter = listOf("assemble"), runTask = { taskRun(project) }) + addVariantTasks(project, "run", runAfter = listOf("install"), runTask = { taskRun(project) }) } - @Task(name = "run", description = "Run the main class", runAfter = arrayOf("assemble")) + @Task(name = "run", description = "Run the main class", runAfter = arrayOf("install")) fun taskRun(project: Project): TaskResult { val runContributor = context.pluginInfo.runContributors.maxBy { it.runAffinity(project, context)} if (runContributor != null && runContributor.runAffinity(project, context) > 0) {