keys.scala, etc.: Make merging public keys have a progress bar.
[tripe-android] / app.scala
CommitLineData
ad64fbfa
MW
1/* -*-scala-*-
2 *
3 * Setting up the Android environment
4 *
5 * (c) 2018 Straylight/Edgeware
6 */
7
8/*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the Trivial IP Encryption (TrIPE) Android app.
11 *
12 * TrIPE is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 3 of the License, or (at your
15 * option) any later version.
16 *
17 * TrIPE is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with TrIPE. If not, see <https://www.gnu.org/licenses/>.
24 */
25
26package uk.org.distorted.tripe; package object app {
27
28/*----- Imports -----------------------------------------------------------*/
29
30import java.io.{File, IOException};
31
32import scala.collection.mutable.HashMap;
33
34import android.content.Context; import Context.MODE_WORLD_READABLE;
35import android.os.Build; import Build.{CPU_ABI, CPU_ABI2};
36import android.util.Log;
37
38import sys.FileImplicits._;
39
40/*----- Regular expressions for parsing the `.installed file --------------*/
41
42private final val RX_COMMENT = """(?x) ^ \s* (?: \# .* )? $""".r;
43private final val RX_KEYVAL = """(?x) ^ \s*
44 ([-\w]+)
45 (?:\s+(?!=)|\s*=\s*)
46 (|\S|\S.*\S)
47 \s* $""".r;
48
49/*----- Main code ---------------------------------------------------------*/
50
51private final val TAG = "TrIPE";
52
53var root: File = null;
54
55private def install(ctx: Context, inst: HashMap[String, String]) {
56
57 /* First, figure out which ABIs are wanted on this device. Unfortunately,
58 * the good way of doing this isn't available in our minimum API level, so
59 * we must use reflection.
60 */
61 val abis = try {
62 classOf[Build].getField("SUPPORTED_ABIS").get(null).
63 asInstanceOf[Array[String]]
64 } catch { case _: NoSuchFieldException =>
65 Array(CPU_ABI, CPU_ABI2) flatMap {
66 case null | "" => None
67 case s => Some(s)
68 }
69 }
70 Log.d(TAG, s"abis = ${abis.mkString(", ")}");
71
72 /* Clear out whatever might be there already. */
73 val bindir = root/"bin";
74 bindir.rmTree();
75 bindir.mkdir_!();
76
77 /* Now extract each of our binaries using the best available ABI. */
78 val assets = ctx.getAssets;
79 for (abi <- abis) {
80 val binsrc = s"bin/$abi";
81 for (base <- assets.list(binsrc)) {
82 val outfile = bindir/base;
83 if (!outfile.exists_!) {
84 Log.d(TAG, s"install: extract `$base' using abi `$abi'");
85 outfile.withOutput { out =>
86 closing(assets.open(s"$binsrc/$base")) { in =>
87 for ((buf, n) <- blocks(in)) out.write(buf, 0, n);
88 }
89 }
90 }
91 outfile.chmod_!(0x1ed);
92 }
93 }
94
95 /* Write out a new install file. */
96 val infofile = root/".installed";
97 val newinfofile = root/".installed.new";
98 newinfofile.withWriter { out =>
99 out.write(s"""### -*-conf-*-
100
101uuid = ${ctx.getString(R.string.auto_build_uuid)}
102""");
103 }
104 newinfofile.rename_!(infofile);
105}
106
107def setup(ctx: Context) {
108
109 /* Make our root directory and remember where it is. */
110 root = ctx.getFilesDir;
111 if (!root.isdir_!) {
112 throw new IOException("system failed to create `files' " +
113 "(but didn't tell us)");
114 }
115
116 /* Find out which build, if any, corresponds to what's there already. */
117 val inst = HashMap[String, String]();
118 try { root/".installed" withReader { in =>
119 var lno = 1;
120 for (line <- lines(in)) {
121 line match {
122 case RX_COMMENT() => ok;
123 case RX_KEYVAL(k, v) => inst(k) = v;
124 case _ => Log.w(TAG, s".installed:$lno: ignored unparseable line");
125 }
126 lno += 1;
127 }
128 } } catch {
129 case e: IOException =>
130 Log.w(TAG, s".installed: I/O error: ${e.getMessage}");
131 }
132
133 /* If this doesn't match, then we have some work to do. */
134 if (inst.getOrElse("uuid", "<nothing>") !=
135 ctx.getString(R.string.auto_build_uuid))
136 install(ctx, inst);
137}
138
139/*----- That's all, folks -------------------------------------------------*/
140
141}