start mesh service on boot, store device macaddr in prefs

pull/8/head
geeksville 2020-02-12 15:47:06 -08:00
rodzic 55d4d769f8
commit 4e6d1be954
8 zmienionych plików z 105 dodań i 53 usunięć

Wyświetl plik

@ -1,11 +1,13 @@
# High priority
MVP features required for first public alpha
* start bt receive on boot
* when a text arrives, move that node info card to the bottom on the window - put the text to the left of the card. with a small arrow/distance/shortname
* let the user type texts somewhere
* include a background behind our cloud graphics, so redraws work properly
* show direction and distance on the nodeinfo cards
* show radio config screen, it shows past channels (and the current one)
* use this for preferences? https://developer.android.com/guide/topics/ui/settings/
* do setOwner every time we connect to the radio, use our settings, radio should ignore if unchanged
* send location data for devices that don't have a GPS - https://developer.android.com/training/location/change-location-settings
* make nodeinfo card not look like ass

Wyświetl plik

@ -75,7 +75,7 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.0.0'
testImplementation 'junit:junit:4.12'

Wyświetl plik

@ -33,6 +33,9 @@
<!-- 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" />
<!-- Needed to open our bluetooth connection to our paired device (after reboot) -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />
@ -108,7 +111,15 @@
<receiver android:name="com.geeksville.mesh.service.BootCompleteReceiver">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<!--For HTC devices per https://stackoverflow.com/questions/20441308/boot-completed-not-working-android/46294732#46294732 -->
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
<!-- for testing -->
<action android:name="com.geeksville.mesh.SIM_BOOT" />
</intent-filter>
</receiver>
</application>

Wyświetl plik

@ -6,9 +6,7 @@ import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.content.*
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Debug
import android.os.IBinder
import android.provider.ContactsContract
import android.provider.ContactsContract.CommonDataKinds.Phone
@ -25,7 +23,6 @@ import com.geeksville.mesh.ui.MeshApp
import com.geeksville.mesh.ui.TextMessage
import com.geeksville.mesh.ui.UIState
import com.geeksville.util.exceptionReporter
import com.google.firebase.crashlytics.FirebaseCrashlytics
import java.nio.charset.Charset
import java.util.*
@ -157,11 +154,6 @@ class MainActivity : AppCompatActivity(), Logging,
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// We default to off in the manifest, FIXME turn on only if user approves
// leave off when running in the debugger
if (false && !Debug.isDebuggerConnected())
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(true)
setContent {
MeshApp()
}
@ -177,6 +169,11 @@ class MainActivity : AppCompatActivity(), Logging,
Toast.makeText(this, "Error - this app requires bluetooth", Toast.LENGTH_LONG).show()
}
/* Do this better FIXME */
val usetbeam = false
val address = if (usetbeam) "B4:E6:2D:EA:32:B7" else "24:6F:28:96:C9:2A"
RadioInterfaceService.setBondedDeviceAddress(this, address)
requestPermission()
}
@ -292,26 +289,12 @@ class MainActivity : AppCompatActivity(), Logging,
// we bind using the well known name, to make sure 3rd party apps could also
logAssert(meshService == null)
// bind to our service using the same mechanism an external client would use (for testing coverage)
// 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.service.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)
val intent = MeshService.startService(this)
if (intent != null) {
// ALSO bind so we can use the api
logAssert(bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE))
isBound = true;
}
// ALSO bind so we can use the api
logAssert(bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE))
isBound = true;
}
private fun unbindMeshService() {

Wyświetl plik

@ -1,7 +1,19 @@
package com.geeksville.mesh
import android.os.Debug
import com.geeksville.android.GeeksvilleApplication
import com.google.firebase.crashlytics.FirebaseCrashlytics
class MeshUtilApplication : GeeksvilleApplication(null, "58e72ccc361883ea502510baa46580e3") {
override fun onCreate() {
super.onCreate()
// We default to off in the manifest, FIXME turn on only if user approves
// leave off when running in the debugger
if (false && !Debug.isDebuggerConnected())
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(true)
}
}

Wyświetl plik

@ -3,12 +3,13 @@ package com.geeksville.mesh.service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.geeksville.android.Logging
class BootCompleteReceiver : BroadcastReceiver() {
class BootCompleteReceiver : BroadcastReceiver(), Logging {
override fun onReceive(mContext: Context, intent: Intent) {
if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
// FIXME - start listening for bluetooth messages from our device
}
// FIXME - start listening for bluetooth messages from our device
info("Received boot complete announcement, starting mesh service")
MeshService.startService(mContext)
}
}

Wyświetl plik

@ -33,7 +33,7 @@ class RadioNotConnectedException() : Exception("Can't find radio")
*/
class MeshService : Service(), Logging {
companion object {
companion object : Logging {
/// Intents broadcast by MeshService
const val ACTION_RECEIVED_DATA = "$prefix.RECEIVED_DATA"
@ -50,7 +50,38 @@ class MeshService : Service(), Logging {
/// If the radio hasn't yet joined a mesh (i.e. no nodenum assigned)
private const val NODE_NUM_NO_MESH = -1
/// Helper function to start running our service, returns the intent used to reach it
/// or null if the service could not be started (no bluetooth or no bonded device set)
fun startService(context: Context): Intent? {
if (RadioInterfaceService.getBondedDeviceAddress(context) == null) {
warn("No mesh radio is bonded, not starting service")
return null
} else {
// bind to our service using the same mechanism an external client would use (for testing coverage)
// 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.service.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.
logAssert(
(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
} else {
context.startService(intent)
}) != null
)
return intent
}
}
}
/// A mapping of receiver class name to package name - used for explicit broadcasts

Wyświetl plik

@ -7,6 +7,7 @@ import android.bluetooth.BluetoothManager
import android.content.Context
import android.content.Intent
import android.os.IBinder
import androidx.core.content.edit
import com.geeksville.android.BinaryLogFile
import com.geeksville.android.Logging
import com.geeksville.concurrent.DeferredExecution
@ -126,6 +127,15 @@ class RadioInterfaceService : Service(), Logging {
intent.putExtra(EXTRA_PAYLOAD, payload)
context.sendBroadcast(intent)
}
private fun getPrefs(context: Context) =
context.getSharedPreferences("radio-prefs", Context.MODE_PRIVATE)
/// Return the device we are configured to use, or null for none
fun getBondedDeviceAddress(context: Context) = getPrefs(context).getString("devAddr", null)
fun setBondedDeviceAddress(context: Context, addr: String) =
getPrefs(context).edit(commit = true) { putString("devAddr", addr) }
}
private val bluetoothAdapter: BluetoothAdapter? by lazy(LazyThreadSafetyMode.NONE) {
@ -244,30 +254,32 @@ class RadioInterfaceService : Service(), Logging {
// 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"
val address = getBondedDeviceAddress(this)
if (address == null)
error("No bonded mesh radio, can't create service")
else {
// Note: this call does no comms, it just creates the device object (even if the
// device is off/not connected)
val device = bluetoothAdapter?.getRemoteDevice(address)
if (device != null) {
info("Creating radio interface service. device=$address")
val device = bluetoothAdapter?.getRemoteDevice(address)
if (device != null) {
info("Creating radio interface service. device=$address")
// Note this constructor also does no comm
val s = SafeBluetooth(this, device)
safe = s
// Note this constructor also does no comm
val s = SafeBluetooth(this, device)
safe = s
// FIXME, pass in true for autoconnect - so we will autoconnect whenever the radio
// comes in range (even if we made this connect call long ago when we got powered on)
// see https://stackoverflow.com/questions/40156699/which-correct-flag-of-autoconnect-in-connectgatt-of-ble for
// more info
s.asyncConnect(true, ::onConnect, ::onDisconnect)
} else {
error("Bluetooth adapter not found, assuming running on the emulator!")
}
// FIXME, pass in true for autoconnect - so we will autoconnect whenever the radio
// comes in range (even if we made this connect call long ago when we got powered on)
// see https://stackoverflow.com/questions/40156699/which-correct-flag-of-autoconnect-in-connectgatt-of-ble for
// more info
s.asyncConnect(true, ::onConnect, ::onDisconnect)
} else {
error("Bluetooth adapter not found, assuming running on the emulator!")
if (logSends)
sentPacketsLog = BinaryLogFile(this, "sent_log.pb")
}
if (logSends)
sentPacketsLog = BinaryLogFile(this, "sent_log.pb")
}
override fun onDestroy() {