meshtastic-android/app/src/main/java/com/geeksville/mesh/MainActivity.kt

208 wiersze
6.9 KiB
Kotlin
Czysty Zwykły widok Historia

2020-01-23 05:46:41 +00:00
package com.geeksville.mesh
2020-01-20 23:53:22 +00:00
2020-01-21 21:12:01 +00:00
import android.Manifest
2020-01-21 17:37:39 +00:00
import android.bluetooth.*
2020-01-23 16:09:50 +00:00
import android.content.ComponentName
2020-01-21 17:37:39 +00:00
import android.content.Context
import android.content.Intent
2020-01-23 16:09:50 +00:00
import android.content.ServiceConnection
2020-01-21 21:12:01 +00:00
import android.content.pm.PackageManager
2020-01-20 23:53:22 +00:00
import android.os.Bundle
2020-01-23 16:09:50 +00:00
import android.os.IBinder
import android.os.RemoteException
2020-01-20 23:53:22 +00:00
import androidx.appcompat.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
2020-01-22 21:02:24 +00:00
import android.widget.Toast
2020-01-22 22:48:06 +00:00
import androidx.compose.Composable
2020-01-23 16:09:50 +00:00
import androidx.compose.Model
2020-01-21 21:12:01 +00:00
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
2020-01-22 22:48:06 +00:00
import androidx.ui.core.Text
import androidx.ui.core.dp
import androidx.ui.core.setContent
import androidx.ui.layout.Column
import androidx.ui.layout.Spacing
import androidx.ui.material.Button
import androidx.ui.material.MaterialTheme
import androidx.ui.tooling.preview.Preview
2020-01-22 22:27:22 +00:00
import com.geeksville.android.Logging
2020-01-20 23:53:22 +00:00
2020-01-21 17:37:39 +00:00
2020-01-22 22:27:22 +00:00
class MainActivity : AppCompatActivity(), Logging {
2020-01-20 23:53:22 +00:00
2020-01-21 17:37:39 +00:00
companion object {
const val REQUEST_ENABLE_BT = 10
2020-01-21 21:12:01 +00:00
const val DID_REQUEST_PERM = 11
2020-01-21 17:37:39 +00:00
}
2020-01-23 16:09:50 +00:00
@Model
class MeshServiceState(var connected: Boolean = false, public var onlineIds: Array<String> = arrayOf())
val meshServiceState = MeshServiceState()
2020-01-22 21:02:24 +00:00
private val bluetoothAdapter: BluetoothAdapter? by lazy(LazyThreadSafetyMode.NONE) {
2020-01-21 17:37:39 +00:00
val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
2020-01-22 21:02:24 +00:00
bluetoothManager.adapter
2020-01-21 17:37:39 +00:00
}
2020-01-21 21:12:01 +00:00
fun requestPermission() {
2020-01-22 22:27:22 +00:00
debug("Checking permissions")
2020-01-23 00:45:27 +00:00
val perms = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
2020-01-21 21:12:01 +00:00
Manifest.permission.ACCESS_BACKGROUND_LOCATION,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN,
2020-01-23 00:45:27 +00:00
Manifest.permission.WAKE_LOCK
)
val missingPerms = perms.filter {
ContextCompat.checkSelfPermission(
this,
it
) != PackageManager.PERMISSION_GRANTED
}
2020-01-21 21:12:01 +00:00
if (missingPerms.isNotEmpty()) {
missingPerms.forEach {
// Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this, it)) {
// FIXME
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
}
}
// Ask for all the missing perms
ActivityCompat.requestPermissions(this, missingPerms.toTypedArray(), DID_REQUEST_PERM)
// DID_REQUEST_PERM is an
// app-defined int constant. The callback method gets the
// result of the request.
} else {
// Permission has already been granted
}
}
2020-01-23 00:45:27 +00:00
@Preview
2020-01-22 22:48:06 +00:00
@Composable
2020-01-23 16:09:50 +00:00
fun previewView() {
composeView(meshServiceState)
}
@Composable
fun composeView(meshServiceState: MeshServiceState) {
2020-01-22 22:48:06 +00:00
MaterialTheme {
2020-01-23 14:46:23 +00:00
Column(modifier = Spacing(8.dp)) {
Text(text = "Meshtastic", modifier = Spacing(8.dp))
2020-01-22 22:48:06 +00:00
2020-01-23 16:09:50 +00:00
Text("Radio connected: ${meshServiceState.connected}")
meshServiceState.onlineIds.forEach {
Text("User: $it")
}
2020-01-22 22:48:06 +00:00
Button(text = "Start scan",
onClick = {
if (bluetoothAdapter != null) {
2020-01-23 00:45:27 +00:00
SoftwareUpdateService.enqueueWork(
this@MainActivity,
SoftwareUpdateService.scanDevicesIntent
)
2020-01-22 22:48:06 +00:00
}
})
}
2020-01-23 00:45:27 +00:00
}
2020-01-22 22:48:06 +00:00
}
2020-01-22 22:27:22 +00:00
2020-01-22 22:48:06 +00:00
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
2020-01-23 16:09:50 +00:00
composeView(meshServiceState)
2020-01-21 17:37:39 +00:00
}
// Ensures Bluetooth is available on the device and it is enabled. If not,
// displays a dialog requesting user permission to enable Bluetooth.
2020-01-23 00:45:27 +00:00
if (bluetoothAdapter != null) {
2020-01-22 21:02:24 +00:00
bluetoothAdapter!!.takeIf { !it.isEnabled }?.apply {
val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT)
}
2020-01-23 00:45:27 +00:00
} else {
2020-01-22 21:02:24 +00:00
Toast.makeText(this, "Error - this app requires bluetooth", Toast.LENGTH_LONG).show()
2020-01-20 23:53:22 +00:00
}
2020-01-21 20:07:03 +00:00
2020-01-21 21:12:01 +00:00
requestPermission()
2020-01-20 23:53:22 +00:00
}
2020-01-23 16:09:50 +00:00
var meshService: IMeshService? = null
var isBound = false
private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
meshService = IMeshService.Stub.asInterface(service)
// FIXME this doesn't work because the model has already been copied into compose land?
runOnUiThread { // FIXME - this can be removed?
meshServiceState.connected = meshService!!.isConnected
meshServiceState.onlineIds = meshService!!.online
}
}
override fun onServiceDisconnected(name: ComponentName) {
meshService = null;
}
}
private fun bindMeshService() {
info("Binding to mesh service!")
// we bind using the well known name, to make sure 3rd party apps could also
logAssert(meshService == null)
val intent = Intent(this, MeshService::class.java)
intent.action = IMeshService::class.java.name
intent.setPackage("com.geeksville.mesh");
isBound = bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
logAssert(isBound)
}
private fun unbindMeshService() {
// If we have received the service, and hence registered with
// it, then now is the time to unregister.
// if we never connected, do nothing
if(isBound) {
info("Unbinding from mesh service!")
unbindService(serviceConnection)
meshService = null
}
}
override fun onPause() {
unbindMeshService()
super.onPause()
}
override fun onResume() {
super.onResume()
bindMeshService()
}
2020-01-20 23:53:22 +00:00
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
2020-01-21 00:13:40 +00:00
return when (item.itemId) {
2020-01-20 23:53:22 +00:00
R.id.action_settings -> true
else -> super.onOptionsItemSelected(item)
}
}
}
2020-01-21 17:37:39 +00:00