mirror of
https://github.com/twinksoftware/Gearslip.git
synced 2026-11-10 16:02:25 +01:00
protocol: service discovery sends Gearslip's icon at three sizes and a session ID, like a real phone
This commit is contained in:
1 parent
37d56be59a
commit
327d6fd40a
3 files changed
+50
-3
No files matched your search
@@ -401,6 +401,7 @@ class GearslipActivity : ComponentActivity(), Projection {
|
||||
identityProvider = { CertProvider.load(this) },
|
||||
projection = this,
|
||||
vehicleProfileFor = { info -> VehicleProfiles.find(VehicleProfiles.load(this), info) },
|
||||
phoneIcons = { PhoneIcons.pngs(this) },
|
||||
)
|
||||
this.runner = runner
|
||||
worker = Thread { runner.run() }.apply { name = "gearslip"; start() }
|
||||
@@ -423,6 +424,7 @@ class GearslipActivity : ComponentActivity(), Projection {
|
||||
projection = this,
|
||||
vehicleProfileFor = { info -> VehicleProfiles.find(VehicleProfiles.load(this), info) },
|
||||
wireless = true,
|
||||
phoneIcons = { PhoneIcons.pngs(this) },
|
||||
)
|
||||
this.runner = runner
|
||||
worker = Thread { runner.run() }.apply { name = "gearslip"; start() }
|
||||
|
||||
@@ -48,6 +48,8 @@ class GearslipRunner(
|
||||
private val vehicleProfileFor: (ServiceDiscovery.HeadUnitInfo) -> VehicleProfile? = { null },
|
||||
/** Over Wi-Fi rather than USB: the video is sent smaller so the link keeps up. */
|
||||
private val wireless: Boolean = false,
|
||||
/** Gearslip's icon as 32, 64 and 128 px PNGs, for the car's phone tile. See [PhoneIcons]. */
|
||||
private val phoneIcons: () -> List<ByteArray> = { emptyList() },
|
||||
) {
|
||||
private val log = GearslipLog.tagged("PROTO")
|
||||
|
||||
@@ -446,11 +448,20 @@ class GearslipRunner(
|
||||
if (authenticationFailed) running = false
|
||||
}
|
||||
|
||||
/**
|
||||
* What a real phone sends here: its icon at three sizes (fields 1 to 3), a label, its model,
|
||||
* and a session ID that's new each connection (field 6). A 2017 Hyundai on protocol 1.0
|
||||
* never answered the request when it had only the label and model (issue #47).
|
||||
*/
|
||||
private fun sendServiceDiscoveryRequest() {
|
||||
val body = Protobuf.stringField(4, "Gearslip") + // label_text
|
||||
Protobuf.stringField(5, Build.MODEL) // device_name
|
||||
val icons = runCatching(phoneIcons).getOrDefault(emptyList())
|
||||
var body = ByteArray(0)
|
||||
icons.take(3).forEachIndexed { i, png -> body += Protobuf.bytesField(i + 1, png) } // small, medium, large icon
|
||||
body += Protobuf.stringField(4, "Gearslip") + // label_text
|
||||
Protobuf.stringField(5, Build.MODEL) + // device_name
|
||||
Protobuf.bytesField(6, Protobuf.stringField(1, java.util.UUID.randomUUID().toString())) // session ID
|
||||
send(MSG_SERVICE_DISCOVERY_REQUEST, body, encrypted = true)
|
||||
log.i("-> ServiceDiscoveryRequest (encrypted)")
|
||||
log.i("-> ServiceDiscoveryRequest (encrypted, ${icons.size} icons, ${body.size} bytes)")
|
||||
}
|
||||
|
||||
private fun onServiceDiscoveryResponse(body: ByteArray) {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package app.seb3thehacker.gearslip
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
/**
|
||||
* Gearslip's own icon as the PNGs a phone hands the car in its ServiceDiscoveryRequest, at the
|
||||
* 32, 64 and 128 px a real phone sends. Cars draw the phone's tile on their home screen from
|
||||
* them, and older head units may wait for them before answering at all.
|
||||
*/
|
||||
object PhoneIcons {
|
||||
|
||||
private val SIZES = intArrayOf(32, 64, 128)
|
||||
|
||||
@Volatile private var cached: List<ByteArray>? = null
|
||||
|
||||
/** The three PNGs, smallest first; empty if the icon can't be drawn. */
|
||||
fun pngs(context: Context): List<ByteArray> = cached ?: runCatching {
|
||||
val icon = context.packageManager.getApplicationIcon(context.applicationInfo).mutate()
|
||||
SIZES.map { size ->
|
||||
val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
|
||||
icon.setBounds(0, 0, size, size)
|
||||
icon.draw(Canvas(bitmap))
|
||||
val png = ByteArrayOutputStream()
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, png)
|
||||
bitmap.recycle()
|
||||
png.toByteArray()
|
||||
}
|
||||
}.onFailure { GearslipLog.w("phone icons: couldn't draw them (${it.message})") }
|
||||
.getOrDefault(emptyList())
|
||||
.also { if (it.isNotEmpty()) cached = it }
|
||||
}
|
||||
Reference in new issue
Block a user