--- /dev/null
+/* -*-scala-*-
+ *
+ * Setting up the Android environment
+ *
+ * (c) 2018 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of the Trivial IP Encryption (TrIPE) Android app.
+ *
+ * TrIPE is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * TrIPE is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with TrIPE. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package uk.org.distorted.tripe; package object app {
+
+/*----- Imports -----------------------------------------------------------*/
+
+import java.io.{File, IOException};
+
+import scala.collection.mutable.HashMap;
+
+import android.content.Context; import Context.MODE_WORLD_READABLE;
+import android.os.Build; import Build.{CPU_ABI, CPU_ABI2};
+import android.util.Log;
+
+import sys.FileImplicits._;
+
+/*----- Regular expressions for parsing the `.installed file --------------*/
+
+private final val RX_COMMENT = """(?x) ^ \s* (?: \# .* )? $""".r;
+private final val RX_KEYVAL = """(?x) ^ \s*
+ ([-\w]+)
+ (?:\s+(?!=)|\s*=\s*)
+ (|\S|\S.*\S)
+ \s* $""".r;
+
+/*----- Main code ---------------------------------------------------------*/
+
+private final val TAG = "TrIPE";
+
+var root: File = null;
+
+private def install(ctx: Context, inst: HashMap[String, String]) {
+
+ /* First, figure out which ABIs are wanted on this device. Unfortunately,
+ * the good way of doing this isn't available in our minimum API level, so
+ * we must use reflection.
+ */
+ val abis = try {
+ classOf[Build].getField("SUPPORTED_ABIS").get(null).
+ asInstanceOf[Array[String]]
+ } catch { case _: NoSuchFieldException =>
+ Array(CPU_ABI, CPU_ABI2) flatMap {
+ case null | "" => None
+ case s => Some(s)
+ }
+ }
+ Log.d(TAG, s"abis = ${abis.mkString(", ")}");
+
+ /* Clear out whatever might be there already. */
+ val bindir = root/"bin";
+ bindir.rmTree();
+ bindir.mkdir_!();
+
+ /* Now extract each of our binaries using the best available ABI. */
+ val assets = ctx.getAssets;
+ for (abi <- abis) {
+ val binsrc = s"bin/$abi";
+ for (base <- assets.list(binsrc)) {
+ val outfile = bindir/base;
+ if (!outfile.exists_!) {
+ Log.d(TAG, s"install: extract `$base' using abi `$abi'");
+ outfile.withOutput { out =>
+ closing(assets.open(s"$binsrc/$base")) { in =>
+ for ((buf, n) <- blocks(in)) out.write(buf, 0, n);
+ }
+ }
+ }
+ outfile.chmod_!(0x1ed);
+ }
+ }
+
+ /* Write out a new install file. */
+ val infofile = root/".installed";
+ val newinfofile = root/".installed.new";
+ newinfofile.withWriter { out =>
+ out.write(s"""### -*-conf-*-
+
+uuid = ${ctx.getString(R.string.auto_build_uuid)}
+""");
+ }
+ newinfofile.rename_!(infofile);
+}
+
+def setup(ctx: Context) {
+
+ /* Make our root directory and remember where it is. */
+ root = ctx.getFilesDir;
+ if (!root.isdir_!) {
+ throw new IOException("system failed to create `files' " +
+ "(but didn't tell us)");
+ }
+
+ /* Find out which build, if any, corresponds to what's there already. */
+ val inst = HashMap[String, String]();
+ try { root/".installed" withReader { in =>
+ var lno = 1;
+ for (line <- lines(in)) {
+ line match {
+ case RX_COMMENT() => ok;
+ case RX_KEYVAL(k, v) => inst(k) = v;
+ case _ => Log.w(TAG, s".installed:$lno: ignored unparseable line");
+ }
+ lno += 1;
+ }
+ } } catch {
+ case e: IOException =>
+ Log.w(TAG, s".installed: I/O error: ${e.getMessage}");
+ }
+
+ /* If this doesn't match, then we have some work to do. */
+ if (inst.getOrElse("uuid", "<nothing>") !=
+ ctx.getString(R.string.auto_build_uuid))
+ install(ctx, inst);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
+
+}