├── .gitignore
├── .idea
├── .name
├── ant.xml
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── highlighting.xml
├── misc.xml
├── modules.xml
├── scala_compiler.xml
├── scopes
│ └── scope_settings.xml
└── vcs.xml
├── README.md
├── install-genymotion.scala
├── install.scala
├── scala-libs-for-android-emulator.iml
└── scala
├── 2.10.1
├── lib
│ ├── akka-actors.jar
│ ├── scala-actors-migration.jar
│ ├── scala-actors.jar
│ ├── scala-collection.jar
│ ├── scala-immutable.jar
│ ├── scala-library.jar
│ ├── scala-mutable.jar
│ └── scala-reflect.jar
└── permissions
│ ├── scala.2-10-1.actors-migration.xml
│ ├── scala.2-10-1.actors.xml
│ ├── scala.2-10-1.akka-actors.xml
│ ├── scala.2-10-1.collection.xml
│ ├── scala.2-10-1.immutable.xml
│ ├── scala.2-10-1.library.xml
│ ├── scala.2-10-1.mutable.xml
│ └── scala.2-10-1.reflect.xml
└── 2.9.2
├── lib
├── scala-actors.jar
├── scala-collection.jar
├── scala-immutable.jar
├── scala-library.jar
└── scala-mutable.jar
└── permissions
├── scala.2-9-2.actors.xml
├── scala.2-9-2.collection.xml
├── scala.2-9-2.immutable.xml
├── scala.2-9-2.library.xml
└── scala.2-9-2.mutable.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | # IntelliJ specific
2 | .idea/workspace.xml
3 | atlassian-ide-plugin.xml
4 | dist/*
5 | out
6 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | scala-libs-for-android
--------------------------------------------------------------------------------
/.idea/ant.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/highlighting.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | http://www.w3.org/1999/xhtml
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/scala_compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/scopes/scope_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | scala-libs-for-android-emulator provides you an easy way to preinstall the scala libraries on your android emulator (from the SDK or genymotion), so
4 | to speed up your development as you do not need to include the scala libs into your debug builds then. I've tested this
5 | also on current emulator images (ICS and Jelly Bean, either ARM or x86 with hardware accelerated emulation).
6 |
7 | **Disclaimer:** I've only tested the script on Windows, but it should also run on Mac OS X and other Unix-platforms.
8 |
9 | ## The Problem
10 |
11 | If you are -- like me -- tired of writing verbose Java code, but want to develop for the Android platform, then Scala is
12 | a great choice. Unfortunately using the normal build process in conjunction with Scala is no good choice, as in each
13 | build the full scala libraries need to be processed, what takes quite a few minutes: You either have to feed the whole
14 | scala library to the `dx` tool (which converts java byte code to dalvik vm code) or the other choice is to use pro guard
15 | to remove all unreferenced artifacts, but this analysis requires some time.
16 |
17 | ## The Solution
18 |
19 | But there is a solution to bring down the turn around times to the same level as if you were using java: Preinstall
20 | the scala libraries on your emulator, so that you can exclude them from your debug build (you will still need to include
21 | them into your release!).
22 |
23 | I've found a few tutorials of how to modify the emulator's ramdisk and to include the scala libs into the `BOOTCLASSPATH`.
24 | This worked fine for emulators up to API level 10 (android 2.3.3), but when I tried it on API level 15 (ICS) or
25 | 16 (Jelly Bean) I've got a boot loop and the emulator never came up.
26 |
27 | While searching around in the web for a solution I've stumbled upon
28 | [jbrechtel's Android-Scala-Installer](https://github.com/jbrechtel/Android-Scala-Installer) which is an android app that
29 | preinstalls the scala libs on a rooted android device and uses another idea: Instead of modifying the `BOOTCLASSPATH`
30 | it installs the scala libs as system libraries which can then be used by your app using `` statements
31 | in the `AndroidManifest.xml`. I've tried this on the emulator and voila: It was working.
32 |
33 | To easily patch an emulator I then simply created this scala script which does everything for us -- from starting up
34 | the emulator to installing the libraries, adjusting the system image and putting it into the right AVD directory.
35 | All you need to do is to start the script and afterwards restart the emulator (cannot be automated on Windows).
36 |
37 | If you are intersted in the details, of how this works, simply take a look into the scala script...
38 |
39 | # Usage
40 |
41 | Using the script is easy:
42 | * Download the whole directory tree of this project to your system (either by cloning the repository or downloading it a ZIP)
43 | * Ensure that your `PATH` contains the scala compiler and the android tools
44 | * call the script without any parameters to get usage help and a list of available scala versions and AVDs:
45 | ```
46 | scala install.scala
47 | ```
48 |
49 | On my system the output looks like this:
50 | ```batch
51 | USAGE: scala install.scala
52 |
53 | Installs the scala libraries in the specified emulator to reduce turnaround
54 | times when developing with scala for android.
55 |
56 | the name of the android virtual device to install the libs on
57 | possible values:
58 | 4.0.3_HVGA, 4.1_HVGA, 4.2_Galaxy-Nexus
59 | the scala version to install. possible values:
60 | 2.10.1, 2.9.2
61 | ```
62 |
63 | * Call the script with the adequate parameters and wait until it's done (what may take a few minutes)
64 | * Add the `` statements outputed at the end of the script run to your `AndroidManifest.xml`
65 | * Enjoy developing android with scala!
66 |
67 | ## Support for Genymotion emulator
68 |
69 | Genymotion is a great alternative to the standard emulator, as it is very fast and the images include Google play and all it's services. There is a dedicated script for installing scala into the currently running genymotion device: ```scala install-genymotion.scala```. The script requires that there is exactly one genymotion emulator currently running and that you configured genymotion for ADB usage. Call it without further paramters to retrieve usage help -- this script only requires you to specify the requested scala version.
70 |
71 | # Supported Scala Versions
72 |
73 | Currently the script supports the following scala versions:
74 | * 2.9.2
75 | * 2.10.1
76 |
77 | It is quite easy to support additional versions:
78 | * Copy your `scala-library.jar` and split it up into several smaller jars based on a package level, so that they can
79 | be processed using the `dx` tool.
80 | * Use the `dx` tool to convert each of the resulting JVM-JARs into Dalvik-JARs as followed:
81 | ```batch
82 | dx -JXmx1024M -JXms1024M -JXss4M --no-optimize --debug --dex
83 | --output=\tmp\scala\android\scala-library.jar \tmp\scala\jvm\scala-library.jar
84 | ```
85 | * Clone an existing version directory inside the `scala` folder
86 | * Replace the JARs with your newly generated ones
87 | * Adjust the permission files for the version accordingly
88 |
89 | That's it. **And please don't forget to provide me the new version, so that I can include it into the distribution here
90 | at GitHub**
--------------------------------------------------------------------------------
/install-genymotion.scala:
--------------------------------------------------------------------------------
1 | import java.io.{FileReader, File}
2 | import java.nio.file.Files
3 | import scala.language.implicitConversions
4 | import scala.io.Source
5 | import sys.process.Process
6 |
7 | /**
8 | * Create an instance and call `install` to install the specified scala version on the specified emulator device.
9 | * @param scalaVersion the version number of the scala version to be installed
10 | */
11 | private class Installer(private val scalaVersion: String) {
12 |
13 | /**
14 | * Indicates a failed command line execution (e.g. the process returned an exit code != 0).
15 | * @param command the command that failed
16 | * @param exitCode the exit code returned by the command
17 | */
18 | private class ExecutionFailedException(val command: String, val exitCode: Int)
19 | extends Exception("Command '" + command + "' failed with exit code " + exitCode)
20 |
21 | implicit def file2Path(file: File) = file.toPath
22 |
23 | /**
24 | * Performs the installation.
25 | */
26 | def install() {
27 | println("Installing Scala " + scalaVersion + " for currently runny genymotion device")
28 |
29 | makeSystemPartitionWritable()
30 | pushScalaLibrary()
31 | pushPermissions()
32 | makeSystemPartitionReadable()
33 | done()
34 | }
35 |
36 | //
37 | // install
38 | //
39 |
40 | private def makeSystemPartitionWritable() {
41 | sudo("mount -o remount,rw /system", "making system partition writable")
42 | }
43 |
44 | private def makeSystemPartitionReadable() {
45 | sudo("mount -o remount,ro /system", "making system partition readable")
46 | }
47 |
48 | private def pushScalaLibrary() {
49 | val targetDir = "/system/framework/scala/" + scalaVersion + "/"
50 | sudo("rm -r " + targetDir, "removing existing Scala library")
51 | sudo("mkdir -p " + targetDir, "creating Scala library directory")
52 |
53 | printProgressHint("pushing Scala " + scalaVersion + " library")
54 | new File("scala/" + scalaVersion + "/lib").listFiles().filter(!_.isDirectory).foreach(pushFile(_, targetDir))
55 | }
56 |
57 | private def permissionFiles = new File("scala/" + scalaVersion + "/permissions").listFiles()
58 |
59 | private def pushPermissions() {
60 | val targetDir = "/system/etc/permissions/"
61 | printProgressHint("creating permission files")
62 | sudo("chmod 777 /system/etc/permissions", "Allowing write access to /system/etc/permissions")
63 | permissionFiles.foreach(pushFile(_, targetDir))
64 | sudo("chmod 755 /system/etc/permissions", "Permitting write access to /system/etc/permissions")
65 | }
66 |
67 | private def done() {
68 | println(
69 | """
70 | |You are done now!
71 | |
72 | |Restart your emulator and the Scala libraries will be available.
73 | |
74 | |Add the following library imports to your AndroidManifest.xml:
75 | """.stripMargin
76 | )
77 | permissionFiles.map(file => file.getName.substring(0, file.getName.lastIndexOf('.'))).foreach{fileName =>
78 | println("""""")
79 | }
80 | }
81 |
82 | //
83 | // helper methods
84 | //
85 |
86 | /**
87 | * Executes the specified command line and optionally prints a hint to the console.
88 | * @param command the command line to be executed
89 | * @param output the hint to be presented to the user or an empty string if no hint should be shown
90 | * @throws ExecutionFailedException if the command's return code is != 0
91 | */
92 | private def execute(command: String, output: String = "") {
93 | if (!output.isEmpty)
94 | printProgressHint(output)
95 | printCommand(command)
96 |
97 | val exitCode = Process(command).!
98 | if (exitCode != 0)
99 | throw new ExecutionFailedException(command, exitCode)
100 | }
101 |
102 | /**
103 | * Executes the specified adb command and optionally prints a hint to the console.
104 | * @param command the adb command to be executed
105 | * @param output the hint to be presented to the user or an empty string if no hint should be shown
106 | * @throws ExecutionFailedException if the command's return code is != 0
107 | */
108 | private def adb(command: String, output: String = "") {
109 | execute("adb " + command, output)
110 | }
111 |
112 | /**
113 | * Executes the specified command line in the emulator's shell and optionally prints a hint to the console.
114 | * @param command the command to be executed in the emulator's shell
115 | * @param output the hint to be presented to the user or an empty string if no hint should be shown
116 | * @throws ExecutionFailedException if the command's return code is != 0
117 | */
118 | private def adbShell(command: String, output: String = "") {
119 | adb("shell " + command, output)
120 | }
121 |
122 | /**
123 | * Executes the specified command line in the emulator's shell as a sudo command and optionally prints a hint to the console.
124 | * @param command the command to be executed in the emulator's shell
125 | * @param output the hint to be presented to the user or an empty string if no hint should be shown
126 | * @throws ExecutionFailedException if the command's return code is != 0
127 | */
128 | private def sudo(command: String, output: String = "") {
129 | adbShell("su -c \"" + command + "\"", output)
130 | }
131 |
132 | /**
133 | * Pushes the specified file into the emulator.
134 | * @param srcFile the local file to be pushed
135 | * @param target the target path of the file in the emulator's file system
136 | * @throws ExecutionFailedException if adb's return code is != 0
137 | */
138 | private def pushFile(srcFile: File, target: String) {
139 | adb("push \"" + srcFile.getAbsolutePath + "\" " + target)
140 | }
141 |
142 | /**
143 | * Prints a hint for the user into the console.
144 | * @param hint the hint to be presented to the user.
145 | */
146 | private def printProgressHint(hint: String) {
147 | println()
148 | println("==> " + hint)
149 | }
150 |
151 | /**
152 | * Prints the currently executed command into the console.
153 | * @param command the command to be shown to the user.
154 | */
155 | private def printCommand(command: String) {
156 | println("# " + command)
157 | }
158 | }
159 |
160 | /**
161 | * Processes and validates the command line arguments and -- if successful -- starts the installation.
162 | */
163 | private object Installer {
164 | /**
165 | * Indicates an invalid command line argument. A user readable error message is provided via `getMessage`.
166 | * @param name the name of the invalid argument as known by the user
167 | * @param value the invalid value
168 | * @param possibleValues the list of allowed values
169 | */
170 | private class InvalidArgumentException(
171 | private val name: String,
172 | private val value: String,
173 | private val possibleValues: Set[_]
174 | )
175 | extends Exception(name + ": invalid value '" + value + "'. Possible values are: " + makePossibleValuesString(possibleValues))
176 |
177 | private lazy val availableScalaVersions = new File("scala").list().toSet
178 |
179 | /**
180 | * Processes and validates the command line arguments and -- if successful -- starts the installation.
181 | * @param args the command line arguments
182 | */
183 | def main(args: Array[String]) {
184 | try {
185 | args match {
186 | case Array(scalaVersion) =>
187 | new Installer(validateScalaVersion(scalaVersion)).install()
188 | case _ => printUsageHelp()
189 | }
190 | } catch {
191 | case ex: InvalidArgumentException =>
192 | println()
193 | println("ERROR: " + ex.getMessage)
194 | printUsageHelp()
195 | case ex: Exception =>
196 | println(ex)
197 | printUsageHelp()
198 | }
199 | }
200 |
201 | private def validateArgument(name: String, value: String, possibleValues: Set[String]) =
202 | if (possibleValues.contains(value)) value else throw new InvalidArgumentException(name, value, possibleValues)
203 |
204 | private def validateScalaVersion(scalaVersion: String) =
205 | validateArgument("scala-version", scalaVersion, availableScalaVersions)
206 |
207 | /**
208 | * Formats a list of possible values for a command line argument, so that it can be presented to the user.
209 | * @param possibleValues the list of possible values.
210 | * @return a string representing the list of possible values.
211 | */
212 | private def makePossibleValuesString(possibleValues: Set[_]) = possibleValues.mkString(", ")
213 |
214 | /**
215 | * Prints out usage help.
216 | */
217 | private def printUsageHelp() {
218 | println((
219 | """
220 | |USAGE: scala install-genymotion.scala
221 | |
222 | |Installs the scala libraries in the currently running genymotion device to
223 | |reduce turnaround times when developing with scala for android.
224 | |
225 | | the scala version to install. possible values:
226 | | """ + makePossibleValuesString(availableScalaVersions) + """
227 | """).stripMargin)
228 | }
229 |
230 | }
231 |
232 | Installer.main(args)
--------------------------------------------------------------------------------
/install.scala:
--------------------------------------------------------------------------------
1 | import java.io.{FileReader, File}
2 | import java.nio.file.Files
3 | import scala.language.implicitConversions
4 | import scala.io.Source
5 | import sys.process.Process
6 |
7 | /**
8 | * Possible target platform
9 | */
10 | private object TargetPlatform extends Enumeration {
11 | type Platform = Value
12 | val arm, x86 = Value
13 | }
14 |
15 | /**
16 | * Represents a device specification
17 | * @param name the name of the device as used by android's `emulator` command
18 | * @param platform the platform of the device
19 | */
20 | private sealed case class Device(name: String, platform: TargetPlatform.Platform) {
21 | lazy val dir = System.getProperty("user.home") + """/.android/avd/""" + name + """.avd"""
22 | }
23 |
24 | /**
25 | * Supports easy creation of `Device`s based on the specification printed out by `android list avd`.
26 | */
27 | private object Device {
28 | private val SpecPattern = """(?s).*Name: (\S+).*ABI: (\S+).*""".r
29 | private val Arm = """arm.*""".r
30 | private val X86 = ".*x86".r
31 |
32 | /**
33 | * Creates a `Device`.
34 | * @param spec specification of a device as printed out by `android list avd`
35 | * @return the created device
36 | * @throws IllegalArgumentException if the platform of the device is unknown
37 | */
38 | def apply(spec: String) = {
39 | spec match {
40 | case SpecPattern(name, platform) => new Device(name, platform match {
41 | case Arm() => TargetPlatform.arm
42 | case X86() => TargetPlatform.x86
43 | case abi => throw new IllegalArgumentException("Unknown target platform '" + abi + "' for device '" + name + "'")
44 | })
45 | }
46 | }
47 | }
48 |
49 | /**
50 | * Create an instance and call `install` to install the specified scala version on the specified emulator device.
51 | * @param device the name of the `Device` to install scala on
52 | * @param scalaVersion the version number of the scala version to be installed
53 | */
54 | private class Installer(
55 | private val device: Device,
56 | private val scalaVersion: String) {
57 | private val systemImage = new File(device.dir, "system.img")
58 |
59 | /**
60 | * Indicates a failed command line execution (e.g. the process returned an exit code != 0).
61 | * @param command the command that failed
62 | * @param exitCode the exit code returned by the command
63 | */
64 | private class ExecutionFailedException(val command: String, val exitCode: Int)
65 | extends Exception("Command '" + command + "' failed with exit code " + exitCode)
66 |
67 | implicit def file2Path(file: File) = file.toPath
68 |
69 | /**
70 | * Performs the installation.
71 | */
72 | def install() {
73 | println("Installing Scala " + scalaVersion + " for " + device.name + " (" + device.platform + ")")
74 |
75 | prepareSystemImage()
76 | val emulatorProcess = startEmulator(systemImage)
77 | waitForEmulator()
78 | makeSystemPartitionWritable()
79 | pushScalaLibrary()
80 | pushPermissions()
81 | done()
82 | emulatorProcess.destroy()
83 | }
84 |
85 | //
86 | // install
87 | //
88 |
89 | private def getSystemImageSource: File = {
90 | val avdConfigFile = new File(device.dir, "hardware-qemu.ini")
91 | val avdConfig = Source.fromFile(avdConfigFile)
92 | val kernelPath = avdConfig.getLines() find { _.startsWith("kernel.path") } match {
93 | case None => throw new IllegalArgumentException("Haven't found kernel.path in " + avdConfigFile.getPath)
94 | case Some(pathDef) => new File(pathDef.split('=')(1).trim)
95 | }
96 | new File(kernelPath.getParentFile, "system.img")
97 | }
98 |
99 | private def prepareSystemImage() {
100 | val systemImage = new File(device.dir, "system.img")
101 | if (!systemImage.exists) {
102 | printProgressHint("copying system image from " + getSystemImageSource.getPath + " to " + systemImage.getPath)
103 | Files.copy(getSystemImageSource, systemImage)
104 | } else {
105 | printProgressHint("using existing image file at " + systemImage.getPath)
106 | }
107 | }
108 |
109 | private def startEmulator(systemImage: File) = {
110 | val targetImageSize = systemImage.length + 50 * 1024 * 1024 // assume about 50MB for the scala stuff
111 | val command = "emulator -avd " + device.name + " -partition-size 1024 -no-boot-anim -no-snapshot " +
112 | "-qemu -nand system,size=0x" + targetImageSize.toHexString + ",file=" + systemImage.getAbsolutePath
113 | printProgressHint("starting emulator ...")
114 | printCommand(command)
115 | Process(command).run()
116 | }
117 |
118 | private def waitForEmulator() {
119 | adb("wait-for-device", "waiting for emulator ...")
120 | }
121 |
122 | private def makeSystemPartitionWritable() {
123 | adbShell("mount -o remount,rw /system", "making system partition writable")
124 | }
125 |
126 | private def pushScalaLibrary() {
127 | val targetDir = "/system/framework/scala/" + scalaVersion + "/"
128 | adbShell("rm -r " + targetDir, "removing existing Scala library")
129 | adbShell("mkdir -p " + targetDir, "creating Scala library directory")
130 |
131 | printProgressHint("pushing Scala " + scalaVersion + " library")
132 | new File("scala/" + scalaVersion + "/lib").listFiles().filter(!_.isDirectory).foreach(pushFile(_, targetDir))
133 | }
134 |
135 | private def permissionFiles = new File("scala/" + scalaVersion + "/permissions").listFiles()
136 |
137 | private def pushPermissions() {
138 | val targetDir = "/system/etc/permissions/"
139 | printProgressHint("creating permission files")
140 | permissionFiles.foreach(pushFile(_, targetDir))
141 | }
142 |
143 | private def done() {
144 | println(
145 | """
146 | |You are done now!
147 | |
148 | |Restart your emulator and the Scala libraries will be available.
149 | |
150 | |Add the following library imports to your AndroidManifest.xml:
151 | """.stripMargin
152 | )
153 | permissionFiles.map(file => file.getName.substring(0, file.getName.lastIndexOf('.'))).foreach{fileName =>
154 | println("""""")
155 | }
156 | }
157 |
158 | //
159 | // helper methods
160 | //
161 |
162 | /**
163 | * Executes the specified command line and optionally prints a hint to the console.
164 | * @param command the command line to be executed
165 | * @param output the hint to be presented to the user or an empty string if no hint should be shown
166 | * @throws ExecutionFailedException if the command's return code is != 0
167 | */
168 | private def execute(command: String, output: String = "") {
169 | if (!output.isEmpty)
170 | printProgressHint(output)
171 | printCommand(command)
172 |
173 | val exitCode = Process(command).!
174 | if (exitCode != 0)
175 | throw new ExecutionFailedException(command, exitCode)
176 | }
177 |
178 | /**
179 | * Executes the specified adb command and optionally prints a hint to the console.
180 | * @param command the adb command to be executed
181 | * @param output the hint to be presented to the user or an empty string if no hint should be shown
182 | * @throws ExecutionFailedException if the command's return code is != 0
183 | */
184 | private def adb(command: String, output: String = "") {
185 | execute("adb " + command, output)
186 | }
187 |
188 | /**
189 | * Executes the specified command line in the emulator's shell and optionally prints a hint to the console.
190 | * @param command the command to be executed in the emulator's shell
191 | * @param output the hint to be presented to the user or an empty string if no hint should be shown
192 | * @throws ExecutionFailedException if the command's return code is != 0
193 | */
194 | private def adbShell(command: String, output: String = "") {
195 | adb("shell " + command, output)
196 | }
197 |
198 | /**
199 | * Pushes the specified file into the emulator.
200 | * @param srcFile the local file to be pushed
201 | * @param target the target path of the file in the emulator's file system
202 | * @throws ExecutionFailedException if adb's return code is != 0
203 | */
204 | private def pushFile(srcFile: File, target: String) {
205 | val systemImageSize = systemImage.length
206 | adb("push \"" + srcFile.getAbsolutePath + "\" " + target)
207 |
208 | // wait until the change is written back to the system image file
209 | while (systemImage.length() == systemImageSize) {
210 | Thread.sleep(1000)
211 | }
212 | }
213 |
214 | /**
215 | * Prints a hint for the user into the console.
216 | * @param hint the hint to be presented to the user.
217 | */
218 | private def printProgressHint(hint: String) {
219 | println()
220 | println("==> " + hint)
221 | }
222 |
223 | /**
224 | * Prints the currently executed command into the console.
225 | * @param command the command to be shown to the user.
226 | */
227 | private def printCommand(command: String) {
228 | println("# " + command)
229 | }
230 | }
231 |
232 | /**
233 | * Processes and validates the command line arguments and -- if successful -- starts the installation.
234 | */
235 | private object Installer {
236 | /**
237 | * Indicates an invalid command line argument. A user readable error message is provided via `getMessage`.
238 | * @param name the name of the invalid argument as known by the user
239 | * @param value the invalid value
240 | * @param possibleValues the list of allowed values
241 | */
242 | private class InvalidArgumentException(
243 | private val name: String,
244 | private val value: String,
245 | private val possibleValues: Set[_]
246 | )
247 | extends Exception(name + ": invalid value '" + value + "'. Possible values are: " + makePossibleValuesString(possibleValues))
248 |
249 | private lazy val isWindows = System.getProperties.get("os.name").toString.toLowerCase.contains("windows")
250 | private lazy val availableScalaVersions = new File("scala").list().toSet
251 | private lazy val availableDevicesByName = getAvailableDevicesByName
252 | private lazy val availableDeviceNames = availableDevicesByName.keySet
253 |
254 | /**
255 | * Processes and validates the command line arguments and -- if successful -- starts the installation.
256 | * @param args the command line arguments
257 | */
258 | def main(args: Array[String]) {
259 | try {
260 | args match {
261 | case Array(deviceName, scalaVersion) =>
262 | new Installer(validateDevice(deviceName), validateScalaVersion(scalaVersion)).install()
263 | case _ => printUsageHelp()
264 | }
265 | } catch {
266 | case ex: InvalidArgumentException =>
267 | println()
268 | println("ERROR: " + ex.getMessage)
269 | printUsageHelp()
270 | case ex: Exception =>
271 | println(ex)
272 | printUsageHelp()
273 | }
274 | }
275 |
276 | private def validateArgument(name: String, value: String, possibleValues: Set[String]) =
277 | if (possibleValues.contains(value)) value else throw new InvalidArgumentException(name, value, possibleValues)
278 | private def validateScalaVersion(scalaVersion: String) =
279 | validateArgument("scala-version", scalaVersion, availableScalaVersions)
280 | private def validateDevice(deviceName: String) = availableDevicesByName.get(deviceName) match {
281 | case Some(device) => device
282 | case None => throw new InvalidArgumentException("avd", deviceName, availableDeviceNames)
283 | }
284 |
285 | /**
286 | * The available `Device`s mapped by their names as provided by the `android list avd` command.
287 | * @return available `Device`s mapped by their names
288 | */
289 | private def getAvailableDevicesByName = {
290 | val lines = shellCommand("android list avd").lines.seq.mkString("\n")
291 | val specs = lines.split("---------")
292 | specs.map(Device(_)).map{device => (device.name, device)}.toMap
293 | }
294 |
295 | private def shellCommand(cmd: String) = {
296 | val fullCommand = if (isWindows) s"cmd /c $cmd" else cmd
297 | Process(fullCommand)
298 | }
299 |
300 | /**
301 | * Formats a list of possible values for a command line argument, so that it can be presented to the user.
302 | * @param possibleValues the list of possible values.
303 | * @return a string representing the list of possible values.
304 | */
305 | private def makePossibleValuesString(possibleValues: Set[_]) = possibleValues.mkString(", ")
306 |
307 | /**
308 | * Prints out usage help.
309 | */
310 | private def printUsageHelp() {
311 | println((
312 | """
313 | |USAGE: scala install.scala
314 | |
315 | |Installs the scala libraries in the specified emulator to reduce turnaround
316 | |times when developing with scala for android.
317 | |
318 | | the name of the android virtual device to install the libs on
319 | | possible values:
320 | | """ + makePossibleValuesString(availableDeviceNames) + """
321 | | the scala version to install. possible values:
322 | | """ + makePossibleValuesString(availableScalaVersions) + """
323 | """).stripMargin)
324 | }
325 |
326 | }
327 |
328 | Installer.main(args)
--------------------------------------------------------------------------------
/scala-libs-for-android-emulator.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/scala/2.10.1/lib/akka-actors.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svenwiegand/scala-libs-for-android-emulator/2fc837ecbd2f747cc71c71cee5905c5857db4694/scala/2.10.1/lib/akka-actors.jar
--------------------------------------------------------------------------------
/scala/2.10.1/lib/scala-actors-migration.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svenwiegand/scala-libs-for-android-emulator/2fc837ecbd2f747cc71c71cee5905c5857db4694/scala/2.10.1/lib/scala-actors-migration.jar
--------------------------------------------------------------------------------
/scala/2.10.1/lib/scala-actors.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svenwiegand/scala-libs-for-android-emulator/2fc837ecbd2f747cc71c71cee5905c5857db4694/scala/2.10.1/lib/scala-actors.jar
--------------------------------------------------------------------------------
/scala/2.10.1/lib/scala-collection.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svenwiegand/scala-libs-for-android-emulator/2fc837ecbd2f747cc71c71cee5905c5857db4694/scala/2.10.1/lib/scala-collection.jar
--------------------------------------------------------------------------------
/scala/2.10.1/lib/scala-immutable.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svenwiegand/scala-libs-for-android-emulator/2fc837ecbd2f747cc71c71cee5905c5857db4694/scala/2.10.1/lib/scala-immutable.jar
--------------------------------------------------------------------------------
/scala/2.10.1/lib/scala-library.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svenwiegand/scala-libs-for-android-emulator/2fc837ecbd2f747cc71c71cee5905c5857db4694/scala/2.10.1/lib/scala-library.jar
--------------------------------------------------------------------------------
/scala/2.10.1/lib/scala-mutable.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svenwiegand/scala-libs-for-android-emulator/2fc837ecbd2f747cc71c71cee5905c5857db4694/scala/2.10.1/lib/scala-mutable.jar
--------------------------------------------------------------------------------
/scala/2.10.1/lib/scala-reflect.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svenwiegand/scala-libs-for-android-emulator/2fc837ecbd2f747cc71c71cee5905c5857db4694/scala/2.10.1/lib/scala-reflect.jar
--------------------------------------------------------------------------------
/scala/2.10.1/permissions/scala.2-10-1.actors-migration.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/scala/2.10.1/permissions/scala.2-10-1.actors.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/scala/2.10.1/permissions/scala.2-10-1.akka-actors.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/scala/2.10.1/permissions/scala.2-10-1.collection.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/scala/2.10.1/permissions/scala.2-10-1.immutable.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/scala/2.10.1/permissions/scala.2-10-1.library.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/scala/2.10.1/permissions/scala.2-10-1.mutable.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/scala/2.10.1/permissions/scala.2-10-1.reflect.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/scala/2.9.2/lib/scala-actors.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svenwiegand/scala-libs-for-android-emulator/2fc837ecbd2f747cc71c71cee5905c5857db4694/scala/2.9.2/lib/scala-actors.jar
--------------------------------------------------------------------------------
/scala/2.9.2/lib/scala-collection.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svenwiegand/scala-libs-for-android-emulator/2fc837ecbd2f747cc71c71cee5905c5857db4694/scala/2.9.2/lib/scala-collection.jar
--------------------------------------------------------------------------------
/scala/2.9.2/lib/scala-immutable.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svenwiegand/scala-libs-for-android-emulator/2fc837ecbd2f747cc71c71cee5905c5857db4694/scala/2.9.2/lib/scala-immutable.jar
--------------------------------------------------------------------------------
/scala/2.9.2/lib/scala-library.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svenwiegand/scala-libs-for-android-emulator/2fc837ecbd2f747cc71c71cee5905c5857db4694/scala/2.9.2/lib/scala-library.jar
--------------------------------------------------------------------------------
/scala/2.9.2/lib/scala-mutable.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/svenwiegand/scala-libs-for-android-emulator/2fc837ecbd2f747cc71c71cee5905c5857db4694/scala/2.9.2/lib/scala-mutable.jar
--------------------------------------------------------------------------------
/scala/2.9.2/permissions/scala.2-9-2.actors.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/scala/2.9.2/permissions/scala.2-9-2.collection.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/scala/2.9.2/permissions/scala.2-9-2.immutable.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/scala/2.9.2/permissions/scala.2-9-2.library.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/scala/2.9.2/permissions/scala.2-9-2.mutable.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------