diff --git a/app/build.gradle b/app/build.gradle index 389288879df8214d5dab193fbc21897b4751915c..88ed1bea0734099fcae924c09f33a024c9e6c70d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,8 +11,8 @@ android { applicationId "de.ccc.events.badge.card10" minSdkVersion 21 targetSdkVersion 29 - versionCode 1 - versionName "0.1" + versionCode 2 + versionName "0.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { diff --git a/app/src/main/java/de/ccc/events/badge/card10/common/ConnectionService.kt b/app/src/main/java/de/ccc/events/badge/card10/common/ConnectionService.kt index 007473bc65f86069a885fef7353d939849a4b972..a5d97c3b4d0bf0979160d021a33605fe7a928bf8 100644 --- a/app/src/main/java/de/ccc/events/badge/card10/common/ConnectionService.kt +++ b/app/src/main/java/de/ccc/events/badge/card10/common/ConnectionService.kt @@ -42,7 +42,7 @@ object ConnectionService { private var connection: BluetoothGatt? = null private var connectionState = BluetoothGatt.STATE_DISCONNECTED - private var gattListeners = mutableListOf<GattListener>() + private var gattListeners = mutableMapOf<String, GattListener>() private val fileServiceUuid = UUID.fromString("42230100-2342-2342-2342-234223422342") @@ -58,8 +58,8 @@ object ConnectionService { fun isConnected() = connectionState == BluetoothGatt.STATE_CONNECTED - fun addGattListener(listener: GattListener) { - gattListeners.add(listener) + fun addGattListener(tag: String, listener: GattListener) { + gattListeners[tag] = listener } fun connect(context: Context) { @@ -113,8 +113,6 @@ object ConnectionService { connectionState = newState connection = gatt - gattListeners.map { it.onConnectionStateChange(newState) } - when (newState) { BluetoothGatt.STATE_CONNECTED -> { gatt?.discoverServices() @@ -132,6 +130,8 @@ object ConnectionService { mtu = newMtu - 3 // Very precise science leService?.enableNotify(gatt) + + gattListeners.values.map { it.onConnectionReady() } } override fun onCharacteristicWrite( @@ -145,7 +145,7 @@ object ConnectionService { connection = gatt - gattListeners.map { it.onCharacteristicWrite(characteristic, status) } + gattListeners.values.map { it.onCharacteristicWrite(characteristic, status) } } override fun onCharacteristicChanged(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?) { @@ -155,7 +155,7 @@ object ConnectionService { throw IllegalStateException() } - gattListeners.map { it.onCharacteristicChanged(characteristic) } + gattListeners.values.map { it.onCharacteristicChanged(characteristic) } } } diff --git a/app/src/main/java/de/ccc/events/badge/card10/common/GattListener.kt b/app/src/main/java/de/ccc/events/badge/card10/common/GattListener.kt index a05fd2ca0ad85677df48c7a034b5c8bf211fc95e..0dc4b7504ac845cf039804f3ddb330ded7ffc96b 100644 --- a/app/src/main/java/de/ccc/events/badge/card10/common/GattListener.kt +++ b/app/src/main/java/de/ccc/events/badge/card10/common/GattListener.kt @@ -27,5 +27,5 @@ import android.bluetooth.BluetoothGattCharacteristic interface GattListener { fun onCharacteristicWrite(characteristic: BluetoothGattCharacteristic, status: Int) {} fun onCharacteristicChanged(characteristic: BluetoothGattCharacteristic) {} - fun onConnectionStateChange(state: Int) {} + fun onConnectionReady() {} } \ No newline at end of file diff --git a/app/src/main/java/de/ccc/events/badge/card10/filetransfer/BatchTransferFragment.kt b/app/src/main/java/de/ccc/events/badge/card10/filetransfer/BatchTransferFragment.kt index c1503eaa04ca5d090707a9a63a479c11372dabfb..5fd1fd17b32920ed82c213085142f0e4f235c73a 100644 --- a/app/src/main/java/de/ccc/events/badge/card10/filetransfer/BatchTransferFragment.kt +++ b/app/src/main/java/de/ccc/events/badge/card10/filetransfer/BatchTransferFragment.kt @@ -61,8 +61,7 @@ class BatchTransferFragment : Fragment(), FileTransferListener, GattListener { progress.max = 5 button_cancel.setOnClickListener { -// isCancelled = true - startTransfer() + isCancelled = true } button_done.setOnClickListener { @@ -78,6 +77,7 @@ class BatchTransferFragment : Fragment(), FileTransferListener, GattListener { private fun initConnection() { val ctx = context ?: throw IllegalStateException() + ConnectionService.addGattListener("batchfiletransfer", this) ConnectionService.connect(ctx) } @@ -91,6 +91,7 @@ class BatchTransferFragment : Fragment(), FileTransferListener, GattListener { } private fun transferNext() { + Thread.sleep(1000) val item = queue.dequeue() if (item == null || isCancelled) { @@ -115,16 +116,15 @@ class BatchTransferFragment : Fragment(), FileTransferListener, GattListener { val reader = ChunkedReader(ctx, transferJob.sourceUri, ConnectionService.mtu) val service = ConnectionService.leService ?: throw IllegalStateException() transfer = FileTransfer(service, reader,this, transferJob.destPath) + transfer?.start() } catch (e: Exception) { Log.e(TAG, "Failed to initialize transfer") return } } - override fun onConnectionStateChange(state: Int) { - if (state == BluetoothGatt.STATE_CONNECTED) { - startTransfer() - } + override fun onConnectionReady() { + startTransfer() } override fun onError() { diff --git a/app/src/main/java/de/ccc/events/badge/card10/filetransfer/FileTransfer.kt b/app/src/main/java/de/ccc/events/badge/card10/filetransfer/FileTransfer.kt index 413fdc68ddd64fff4621ed2b84762f7141dc9daa..1ce612075333b58834f9addc38a63198727ccd02 100644 --- a/app/src/main/java/de/ccc/events/badge/card10/filetransfer/FileTransfer.kt +++ b/app/src/main/java/de/ccc/events/badge/card10/filetransfer/FileTransfer.kt @@ -41,7 +41,7 @@ class FileTransfer( private var currentState = TransferState.IDLE init { - service.addOnPacketReceivedListener(this) + service.setOnPacketReceivedListener(this) } override fun onPacketReceived(packet: Packet) { @@ -98,13 +98,13 @@ class FileTransfer( throw IllegalStateException() } + currentState = TransferState.START_SENT service.sendPacket( Packet( PacketType.START, destinationPath.toByteArray(Charset.forName("ASCII")) ) ) - currentState = TransferState.START_SENT } private fun sendNext() { diff --git a/app/src/main/java/de/ccc/events/badge/card10/filetransfer/FileTransferFragment.kt b/app/src/main/java/de/ccc/events/badge/card10/filetransfer/FileTransferFragment.kt index acc94330a9f8959ff025f0fd89a5cec0cc8dda5f..0730711d4eeae9413d1b3e3290e6844803863ffd 100644 --- a/app/src/main/java/de/ccc/events/badge/card10/filetransfer/FileTransferFragment.kt +++ b/app/src/main/java/de/ccc/events/badge/card10/filetransfer/FileTransferFragment.kt @@ -34,11 +34,14 @@ import android.widget.EditText import android.widget.ProgressBar import android.widget.TextView import androidx.annotation.UiThread +import androidx.appcompat.app.AlertDialog import androidx.fragment.app.Fragment import de.ccc.events.badge.card10.CARD10_BLUETOOTH_MAC_PREFIX import de.ccc.events.badge.card10.R +import de.ccc.events.badge.card10.common.ConnectionException import de.ccc.events.badge.card10.common.ConnectionService import de.ccc.events.badge.card10.common.GattListener +import de.ccc.events.badge.card10.main.MainFragment import java.lang.Exception import java.lang.IllegalStateException @@ -76,8 +79,15 @@ class FileTransferFragment : Fragment(), GattListener, FileTransferListener{ buttonStartStop = view.findViewById(R.id.button_start_stop_transfer) - initConnection() - toggleControls() + try { + initConnection() + toggleControls() + } catch (e: ConnectionException) { + showError(e.message) + } catch (e: Exception) { + showError(getString(R.string.connection_error_generic)) + } + } private fun initConnection() { @@ -160,4 +170,21 @@ class FileTransferFragment : Fragment(), GattListener, FileTransferListener{ } toggleControls() } + + private fun showError(message: String?) { + val ctx = context ?: throw IllegalStateException() + val fm = fragmentManager ?: throw IllegalStateException() + + val errorDialog = + AlertDialog.Builder(ctx) + .setMessage(message ?: getString(R.string.connection_error_generic)) + .setPositiveButton(R.string.dialog_action_ok) { + dialog, _ -> dialog.dismiss() + fm.beginTransaction() + .replace(R.id.fragment_container, MainFragment()) + .addToBackStack(null) + .commit() + } + .show() + } } \ No newline at end of file diff --git a/app/src/main/java/de/ccc/events/badge/card10/filetransfer/LowEffortService.kt b/app/src/main/java/de/ccc/events/badge/card10/filetransfer/LowEffortService.kt index d76380ba4fa6c41e0ee789474dfda4fde116d53b..c77e23ca5f1cafe58afa437d4b80aa9f83641ac7 100644 --- a/app/src/main/java/de/ccc/events/badge/card10/filetransfer/LowEffortService.kt +++ b/app/src/main/java/de/ccc/events/badge/card10/filetransfer/LowEffortService.kt @@ -43,7 +43,7 @@ class LowEffortService( private val centralRxCharacteristicUuid = UUID.fromString("42230102-2342-2342-2342-234223422342") private var notifyEnabled = false - private val listeners = mutableListOf<OnPacketReceivedListener>() + private var listener: OnPacketReceivedListener? = null init { val tx = service.getCharacteristic(centralTxCharacteristicUuid) @@ -58,7 +58,7 @@ class LowEffortService( centralTx = tx centralRx = rx - ConnectionService.addGattListener(this) + ConnectionService.addGattListener("filetransfer",this) } fun enableNotify(gatt: BluetoothGatt) { @@ -89,8 +89,8 @@ class LowEffortService( return status } - fun addOnPacketReceivedListener(listener: OnPacketReceivedListener) { - listeners.add(listener) + fun setOnPacketReceivedListener(packetListener: OnPacketReceivedListener) { + listener = packetListener } // GattListener methods @@ -99,6 +99,6 @@ class LowEffortService( } override fun onCharacteristicChanged(characteristic: BluetoothGattCharacteristic) { - listeners.map { it.onPacketReceived(Packet.fromBytes(characteristic.value)) } + listener?.onPacketReceived(Packet.fromBytes(characteristic.value)) } } \ No newline at end of file diff --git a/app/src/main/java/de/ccc/events/badge/card10/hatchery/AppDetailFragment.kt b/app/src/main/java/de/ccc/events/badge/card10/hatchery/AppDetailFragment.kt index fe19dd4faaf32081a13e898bb1fb5143f580977f..6bb2de7f646a17a7690c71bcab8061cf2f92bf90 100644 --- a/app/src/main/java/de/ccc/events/badge/card10/hatchery/AppDetailFragment.kt +++ b/app/src/main/java/de/ccc/events/badge/card10/hatchery/AppDetailFragment.kt @@ -116,7 +116,7 @@ class AppDetailFragment : Fragment() { targetFile.createNewFile() Log.d(TAG, "Extracting ${entry.name} to ${targetFile.absolutePath}") tarStream.copyTo(targetFile.outputStream()) - appFiles.add(TransferJob(targetFile.toUri(), "apps/${entry.name}")) + appFiles.add(TransferJob(targetFile.toUri(), "/apps/${entry.name}")) } val launcher = createLauncher(app.slug, cacheDir) @@ -156,12 +156,12 @@ class AppDetailFragment : Fragment() { val src = """ # Launcher script for $slug import os - os.exec("apps/$slug/__init__.py") + os.exec("/apps/$slug/__init__.py") """.trimIndent() file.writeText(src) - return TransferJob(file.toUri(), fileName) + return TransferJob(file.toUri(), "/$fileName") } } } diff --git a/app/src/main/res/drawable-hdpi/ic_launcher.png b/app/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..b4ad371c074af03eb310d9a7ea1f6ff3733e89f1 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/layout/main_fragment.xml b/app/src/main/res/layout/main_fragment.xml index 561d2d5deb6556fca58efa525d2776d3177fd42a..5151484721f2e56c89a3d5f19b0d16ba693e7d76 100644 --- a/app/src/main/res/layout/main_fragment.xml +++ b/app/src/main/res/layout/main_fragment.xml @@ -52,8 +52,7 @@ android:text="@string/main_button_browse_apps" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" - app:layout_constraintTop_toTopOf="parent" - android:enabled="false"/> + app:layout_constraintTop_toTopOf="parent"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content"