new sync bt works better

1.2-legacy
geeksville 2020-02-04 13:24:04 -08:00
rodzic dc8cb8446c
commit 27d0d2aa40
6 zmienionych plików z 106 dodań i 12 usunięć

Wyświetl plik

@ -24,6 +24,8 @@
# Medium priority
* test with oldest android
* stop using a foreground service
* change info() log strings to debug()
* use platform theme (dark or light)
* remove mixpanel analytics

Wyświetl plik

@ -27,6 +27,9 @@
<!-- Only for debug log writing, disable for production FIXME -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- We run our mesh code as a foreground service - FIXME, find a way to stop doing this -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />

Wyświetl plik

@ -8,6 +8,7 @@ import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Debug
import android.os.IBinder
@ -171,9 +172,10 @@ class MainActivity : AppCompatActivity(), Logging {
requestPermission()
}
var meshService: IMeshService? = null
private var meshService: IMeshService? = null
private var isBound = false
private val serviceConnection = object : ServiceConnection {
private var serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
val m = IMeshService.Stub.asInterface(service)
meshService = m
@ -201,14 +203,25 @@ class MainActivity : AppCompatActivity(), Logging {
logAssert(meshService == null)
// bind to our service using the same mechanism an external client would use (for testing coverage)
val intent = Intent()
intent.setClassName("com.geeksville.mesh", "com.geeksville.mesh.MeshService")
// The following would work for us, but not external users
//val intent = Intent(this, MeshService::class.java)
//intent.action = IMeshService::class.java.name
val intent = Intent()
intent.setClassName("com.geeksville.mesh", "com.geeksville.mesh.MeshService")
// Before binding we want to explicitly create - so the service stays alive forever (so it can keep
// listening for the bluetooth packets arriving from the radio. And when they arrive forward them
// to Signal or whatever.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}
// ALSO bind so we can use the api
logAssert(bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE))
isBound = true;
}
private fun unbindMeshService() {
@ -216,7 +229,8 @@ class MainActivity : AppCompatActivity(), Logging {
// it, then now is the time to unregister.
// if we never connected, do nothing
debug("Unbinding from mesh service!")
unbindService(serviceConnection)
if (isBound)
unbindService(serviceConnection)
meshService = null
}

Wyświetl plik

@ -1,16 +1,26 @@
package com.geeksville.mesh
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.*
import android.graphics.Color
import android.os.Build
import android.os.IBinder
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.PRIORITY_MIN
import com.geeksville.android.Logging
import com.geeksville.mesh.MeshProtos.MeshPacket
import com.geeksville.mesh.MeshProtos.ToRadio
import com.geeksville.util.exceptionReporter
import com.geeksville.util.toOneLineString
import com.geeksville.util.toRemoteExceptions
import com.google.protobuf.ByteString
import java.nio.charset.Charset
class RadioNotConnectedException() : Exception("Can't find radio")
/**
@ -106,13 +116,74 @@ class MeshService : Service(), Logging {
}
}
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(): String {
val channelId = "my_service"
val channelName = "My Background Service"
val chan = NotificationChannel(
channelId,
channelName, NotificationManager.IMPORTANCE_HIGH
)
chan.lightColor = Color.BLUE
chan.importance = NotificationManager.IMPORTANCE_NONE
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
service.createNotificationChannel(chan)
return channelId
}
private fun startForeground() {
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channelId =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel()
} else {
// If earlier version channel ID is not used
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
""
}
val notificationBuilder = NotificationCompat.Builder(this, channelId)
val notification = notificationBuilder.setOngoing(true)
.setPriority(PRIORITY_MIN)
.setCategory(Notification.CATEGORY_SERVICE)
.setSmallIcon(android.R.drawable.stat_sys_data_bluetooth)
//.setContentTitle("Meshtastic") // leave this off for now so our notification looks smaller
//.setContentText("Listening for mesh...")
.build()
startForeground(101, notification)
}
override fun onCreate() {
super.onCreate()
info("Creating mesh service")
/*
// This intent will be used if the user clicks on the item in the status bar
val notificationIntent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(
this, 0,
notificationIntent, 0
)
val notification: Notification = NotificationCompat.Builder(this)
.setSmallIcon(android.R.drawable.stat_sys_data_bluetooth)
.setContentTitle("Meshtastic")
.setContentText("Listening for mesh...")
.setContentIntent(pendingIntent).build()
// We are required to call this within a few seconds of create
startForeground(1337, notification)
*/
startForeground()
// we listen for messages from the radio receiver _before_ trying to create the service
val filter = IntentFilter(RadioInterfaceService.RECEIVE_FROMRADIO_ACTION)
val filter = IntentFilter()
filter.addAction(RadioInterfaceService.RECEIVE_FROMRADIO_ACTION)
filter.addAction(RadioInterfaceService.CONNECTCHANGED_ACTION)
registerReceiver(radioInterfaceReceiver, filter)
// We in turn need to use the radiointerface service
@ -303,6 +374,7 @@ class MeshService : Service(), Logging {
/// Called when we gain/lose connection to our radio
private fun onConnectionChanged(c: Boolean) {
debug("onConnectionChanged connected=$c")
isConnected = c
if (c) {
// Do our startup init
@ -342,7 +414,6 @@ class MeshService : Service(), Logging {
infoBytes = connectedRadio.readNodeInfo()
}
}
TODO("FIXME - set our owner, get node infos, set our local nodenum, dont process received packets until we have the full node db")
}
/**
@ -351,8 +422,10 @@ class MeshService : Service(), Logging {
*/
private val radioInterfaceReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// Important to never throw exceptions out of onReceive
override fun onReceive(context: Context, intent: Intent) = exceptionReporter {
debug("Received broadcast ${intent.action}")
when (intent.action) {
RadioInterfaceService.CONNECTCHANGED_ACTION -> {
onConnectionChanged(intent.getBooleanExtra(EXTRA_CONNECTED, false))
@ -428,7 +501,7 @@ class MeshService : Service(), Logging {
override fun isConnected(): Boolean = toRemoteExceptions {
val r = this@MeshService.isConnected
info("in isConnected=r")
info("in isConnected=$r")
r
}
}

Wyświetl plik

@ -150,6 +150,7 @@ class RadioInterfaceService : Service(), Logging {
private val clientOperations = DeferredExecution()
private fun broadcastConnectionChanged(isConnected: Boolean) {
debug("Broadcasting connection=$isConnected")
val intent = Intent(CONNECTCHANGED_ACTION)
intent.putExtra(EXTRA_CONNECTED, isConnected)
sendBroadcast(intent)
@ -195,14 +196,14 @@ class RadioInterfaceService : Service(), Logging {
override fun onCreate() {
super.onCreate()
info("Creating radio interface service")
// FIXME, let user GUI select which device we are talking to
// Note: this call does no comms, it just creates the device object (even if the
// device is off/not connected)
val usetbeam = false
val address = if (usetbeam) "B4:E6:2D:EA:32:B7" else "24:6F:28:96:C9:2A"
info("Creating radio interface service. device=$address")
device = bluetoothAdapter.getRemoteDevice(address)
// Note this constructor also does no comm
safe = SafeBluetooth(this, device)

Wyświetl plik

@ -135,6 +135,7 @@ class SafeBluetooth(private val context: Context, private val device: BluetoothD
w
}
debug("work ${work.tag} is completed, resuming with status $status")
if (status != 0)
work.completion.resumeWithException(IOException("Bluetooth status=$status"))
else