mirror of
https://github.com/twinksoftware/Gearslip.git
synced 2026-11-10 16:02:25 +01:00
A wireless drive keeps Gearslip in the foreground
From the moment the car's Bluetooth channel opens until the drive ends, a quiet notification keeps Gearslip in the foreground, so Android lets it join the car's Wi-Fi with the phone locked.
This commit is contained in:
1 parent
cc78020eda
commit
07e398cf79
3 files changed
+76
No files matched your search
@@ -19,6 +19,8 @@
|
|||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
|
||||||
|
<!-- Keeps a wireless start going with the phone locked; see WirelessKeepAlive. -->
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Wireless Android Auto: Bluetooth reaches the paired car's Android Auto service, which
|
Wireless Android Auto: Bluetooth reaches the paired car's Android Auto service, which
|
||||||
@@ -204,6 +206,11 @@
|
|||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:foregroundServiceType="location" />
|
android:foregroundServiceType="location" />
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".wireless.WirelessKeepAlive"
|
||||||
|
android:exported="false"
|
||||||
|
android:foregroundServiceType="connectedDevice" />
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Holds the capture session that carries a media app's audio to the car. It also claims
|
Holds the capture session that carries a media app's audio to the car. It also claims
|
||||||
the microphone, so voice replies can hear the driver with the phone locked.
|
the microphone, so voice replies can hear the driver with the phone locked.
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package app.seb3thehacker.gearslip.wireless
|
||||||
|
|
||||||
|
import android.app.Notification
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.ServiceInfo
|
||||||
|
import android.os.IBinder
|
||||||
|
import app.seb3thehacker.gearslip.GearslipLog
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps Gearslip in the foreground while a wireless car is connected, from the moment its
|
||||||
|
* Bluetooth channel opens until the drive ends. Android treats an app in the background as
|
||||||
|
* unwanted and may refuse its Wi-Fi request or kill it, which is what happens to a start-up with
|
||||||
|
* the phone locked in a pocket. It does no work of its own; the notification is the cost.
|
||||||
|
*/
|
||||||
|
class WirelessKeepAlive : Service() {
|
||||||
|
|
||||||
|
override fun onBind(intent: Intent?): IBinder? = null
|
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
val manager = getSystemService(NotificationManager::class.java)
|
||||||
|
manager.createNotificationChannel(
|
||||||
|
NotificationChannel(CHANNEL, "Wireless car connection", NotificationManager.IMPORTANCE_LOW),
|
||||||
|
)
|
||||||
|
val notification = Notification.Builder(this, CHANNEL)
|
||||||
|
.setSmallIcon(android.R.drawable.stat_sys_data_bluetooth)
|
||||||
|
.setContentTitle("Gearslip is connected to the car wirelessly")
|
||||||
|
.setOngoing(true)
|
||||||
|
.build()
|
||||||
|
// Refused if Android thinks Gearslip may not start one now; the start-up carries on
|
||||||
|
// without it, as it did before this service existed.
|
||||||
|
runCatching {
|
||||||
|
startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE)
|
||||||
|
}.onFailure {
|
||||||
|
GearslipLog.w("wireless keep-alive: could not start the foreground service - ${it.message}")
|
||||||
|
stopSelf()
|
||||||
|
}
|
||||||
|
return START_NOT_STICKY
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val CHANNEL = "gearslip_wireless"
|
||||||
|
private const val NOTIFICATION_ID = 45
|
||||||
|
|
||||||
|
fun start(context: Context) {
|
||||||
|
runCatching { context.startForegroundService(Intent(context, WirelessKeepAlive::class.java)) }
|
||||||
|
.onFailure { GearslipLog.w("wireless keep-alive: start refused - ${it.message}") }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stop(context: Context) {
|
||||||
|
runCatching { context.stopService(Intent(context, WirelessKeepAlive::class.java)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -132,6 +132,15 @@ object WirelessLink {
|
|||||||
*/
|
*/
|
||||||
private fun startUp(context: Context, device: BluetoothDevice) {
|
private fun startUp(context: Context, device: BluetoothDevice) {
|
||||||
val me = Thread.currentThread()
|
val me = Thread.currentThread()
|
||||||
|
try {
|
||||||
|
tryAndRetry(context, device, me)
|
||||||
|
} finally {
|
||||||
|
// A newer start-up has the service now; stop() already ended this one's.
|
||||||
|
if (worker === me) WirelessKeepAlive.stop(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tryAndRetry(context: Context, device: BluetoothDevice, me: Thread) {
|
||||||
var tries = 0
|
var tries = 0
|
||||||
while (true) {
|
while (true) {
|
||||||
handedOver = false
|
handedOver = false
|
||||||
@@ -165,6 +174,7 @@ object WirelessLink {
|
|||||||
worker?.interrupt()
|
worker?.interrupt()
|
||||||
worker = null
|
worker = null
|
||||||
release(context)
|
release(context)
|
||||||
|
WirelessKeepAlive.stop(context)
|
||||||
// Stopped before the car's session began, so nothing else resets Home's card.
|
// Stopped before the car's session began, so nothing else resets Home's card.
|
||||||
if (starting) {
|
if (starting) {
|
||||||
log.i("wireless start-up stopped")
|
log.i("wireless start-up stopped")
|
||||||
@@ -219,6 +229,8 @@ object WirelessLink {
|
|||||||
}
|
}
|
||||||
rfcomm = socket
|
rfcomm = socket
|
||||||
log.i("Bluetooth: channel open")
|
log.i("Bluetooth: channel open")
|
||||||
|
// Before the Wi-Fi request: Android may refuse one from an app it sees as in the background.
|
||||||
|
WirelessKeepAlive.start(context)
|
||||||
SessionStatus.connecting("Bluetooth: talking to $name")
|
SessionStatus.connecting("Bluetooth: talking to $name")
|
||||||
|
|
||||||
val input = DataInputStream(socket.inputStream)
|
val input = DataInputStream(socket.inputStream)
|
||||||
|
|||||||
Reference in new issue
Block a user