mirror of
https://github.com/twinksoftware/Gearslip.git
synced 2026-11-12 16:52:24 +01:00
- First run now asks for permissions one at a time, each on its own screen with an Allow or Skip, instead of firing every system dialog at once from a cold start - The head unit certificate can be downloaded straight from the opencardev/aasdk repository with one tap, on top of the existing adb-staged and file-import paths; Settings shows which source is active and lets an imported or downloaded certificate be removed - A phone app on the car screen: a keypad and a searchable contacts list, with a confirmation card before every call - The web browser draws its own on-screen keyboard for a page's text fields, so a search box or address bar can be typed into from the car screen - Media player rework: a dedicated Now Playing tab with a bigger, screen-size-aware layout, an Up Next tab showing the app's real queue, and Browse/Lyrics tabs that share the same rail - Waze and Google Messages are marked broken instead of pretending to work; Google's own dialer, Assistant, and Android Auto entries are hidden from the car launcher entirely; Aardvark and Vivi Music are marked tested and working - A help screen replaces the old wall of setup text on the home screen - The display-calibration screen is gone - it did its job
52 lines
2.0 KiB
Kotlin
52 lines
2.0 KiB
Kotlin
package app.seb3thehacker.gearslip
|
|
|
|
import java.io.ByteArrayOutputStream
|
|
import java.net.HttpURLConnection
|
|
import java.net.URL
|
|
|
|
/**
|
|
* Fetches the publicly available head unit certificate and key from the opencardev/aasdk
|
|
* repository on GitHub. The app ships no certificates; it downloads them only when the
|
|
* user chooses to, the same way a browser would.
|
|
*/
|
|
object CertDownloader {
|
|
|
|
private val log = GearslipLog.tagged("DOWNL")
|
|
|
|
private const val BASE = "https://raw.githubusercontent.com/opencardev/aasdk/main/cert"
|
|
private const val CRT = "$BASE/headunit.crt"
|
|
private const val KEY = "$BASE/headunit.key"
|
|
private const val CONNECT_TIMEOUT_MS = 10_000
|
|
private const val READ_TIMEOUT_MS = 15_000
|
|
|
|
class Downloaded(val certificatePem: String, val privateKeyPem: String)
|
|
|
|
/** Fetches both files; throws with a readable message on any failure. */
|
|
fun fetch(): Downloaded {
|
|
log.i("fetching certificate from $BASE")
|
|
val crt = fetch(CRT, "certificate")
|
|
val key = fetch(KEY, "private key")
|
|
log.i("downloaded certificate (${crt.length} bytes) and key (${key.length} bytes)")
|
|
return Downloaded(crt, key)
|
|
}
|
|
|
|
private fun fetch(url: String, label: String): String {
|
|
val body = try {
|
|
val conn = (URL(url).openConnection() as HttpURLConnection).apply {
|
|
connectTimeout = CONNECT_TIMEOUT_MS
|
|
readTimeout = READ_TIMEOUT_MS
|
|
}
|
|
conn.inputStream.use { input ->
|
|
val out = ByteArrayOutputStream()
|
|
val buf = ByteArray(4096)
|
|
var n: Int
|
|
while (input.read(buf).also { n = it } != -1) out.write(buf, 0, n)
|
|
out.toString(Charsets.UTF_8)
|
|
}
|
|
} catch (e: Exception) {
|
|
throw RuntimeException("could not download the $label: ${e.message}", e)
|
|
}
|
|
if (body.isBlank()) throw RuntimeException("the $label file is empty")
|
|
return body
|
|
}
|
|
} |