Skip to content

Commit

Permalink
Implement android bridge using pigeon (#98)
Browse files Browse the repository at this point in the history
  • Loading branch information
Izchomatik authored and gavv committed Oct 5, 2024
1 parent 8a272e7 commit ed28af7
Show file tree
Hide file tree
Showing 31 changed files with 769 additions and 93 deletions.
22 changes: 22 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ if (flutterVersionName == null) {
flutterVersionName = "1.0"
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
namespace = "org.rocstreaming.rocdroid"
compileSdk = flutter.compileSdkVersion
Expand All @@ -33,6 +37,10 @@ android {
targetCompatibility = JavaVersion.VERSION_1_8
}

kotlinOptions {
jvmTarget = '1.8'
}

defaultConfig {
applicationId = "org.rocstreaming.rocdroid"
// You can update the following values to match your application needs.
Expand All @@ -41,6 +49,7 @@ android {
targetSdk = flutter.targetSdkVersion
versionCode = flutterVersionCode.toInteger()
versionName = flutterVersionName
minSdkVersion = 26
}

applicationVariants.all { variant ->
Expand All @@ -61,3 +70,16 @@ android {
flutter {
source = "../.."
}

dependencies {
implementation 'org.roc-streaming.roctoolkit:roc-android:0.2.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.3.0'
implementation 'androidx.activity:activity-ktx:1.2.4'
implementation 'androidx.fragment:fragment-ktx:1.3.6'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.viewpager2:viewpager2:1.0.0'
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.25'
}
11 changes: 10 additions & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.rocstreaming.rocdroid"
android:versionCode="2002"
android:versionName="0.2.2">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<application
android:label="Roc Droid"
android:name="${applicationName}"
Expand Down
176 changes: 176 additions & 0 deletions android/app/src/main/kotlin/org/rocstreaming/connector/Connector.g.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// Autogenerated from Pigeon (v21.1.0), do not edit directly.
// See also: https://pub.dev/packages/pigeon
@file:Suppress("UNCHECKED_CAST", "ArrayInDataClass")


import android.util.Log
import io.flutter.plugin.common.BasicMessageChannel
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.MessageCodec
import io.flutter.plugin.common.StandardMessageCodec
import java.io.ByteArrayOutputStream
import java.nio.ByteBuffer

private fun wrapResult(result: Any?): List<Any?> {
return listOf(result)
}

private fun wrapError(exception: Throwable): List<Any?> {
return if (exception is FlutterError) {
listOf(
exception.code,
exception.message,
exception.details
)
} else {
listOf(
exception.javaClass.simpleName,
exception.toString(),
"Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception)
)
}
}

/**
* Error class for passing custom error details to Flutter via a thrown PlatformException.
* @property code The error code.
* @property message The error message.
* @property details The error details. Must be a datatype supported by the api codec.
*/
class FlutterError (
val code: String,
override val message: String? = null,
val details: Any? = null
) : Throwable()
private object ConnectorPigeonCodec : StandardMessageCodec() {
override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? {
return super.readValueOfType(type, buffer)
}
override fun writeValue(stream: ByteArrayOutputStream, value: Any?) {
super.writeValue(stream, value)
}
}

/**
* ???.
*
* Generated interface from Pigeon that represents a handler of messages from Flutter.
*/
interface Backend {
fun startReceiver()
fun stopReceiver()
fun isReceiverAlive(): Boolean
fun startSender(ip: String)
fun stopSender()
fun isSenderAlive(): Boolean

companion object {
/** The codec used by Backend. */
val codec: MessageCodec<Any?> by lazy {
ConnectorPigeonCodec
}
/** Sets up an instance of `Backend` to handle messages through the `binaryMessenger`. */
@JvmOverloads
fun setUp(binaryMessenger: BinaryMessenger, api: Backend?, messageChannelSuffix: String = "") {
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.roc_droid_package.Backend.startReceiver$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
val wrapped: List<Any?> = try {
api.startReceiver()
listOf(null)
} catch (exception: Throwable) {
wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.roc_droid_package.Backend.stopReceiver$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
val wrapped: List<Any?> = try {
api.stopReceiver()
listOf(null)
} catch (exception: Throwable) {
wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.roc_droid_package.Backend.isReceiverAlive$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
val wrapped: List<Any?> = try {
listOf(api.isReceiverAlive())
} catch (exception: Throwable) {
wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.roc_droid_package.Backend.startSender$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val ipArg = args[0] as String
val wrapped: List<Any?> = try {
api.startSender(ipArg)
listOf(null)
} catch (exception: Throwable) {
wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.roc_droid_package.Backend.stopSender$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
val wrapped: List<Any?> = try {
api.stopSender()
listOf(null)
} catch (exception: Throwable) {
wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.roc_droid_package.Backend.isSenderAlive$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
val wrapped: List<Any?> = try {
listOf(api.isSenderAlive())
} catch (exception: Throwable) {
wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
}
}

fun getHostLanguage(): String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.rocstreaming.connector

import Backend
import org.rocstreaming.service.SenderReceiverService

private class Connector : Backend {
override fun getHostLanguage(): String {
return "Kotlin"
}

private var senderReceiverService: SenderReceiverService = SenderReceiverService()

override fun startReceiver() {
senderReceiverService.startReceiver()
}

override fun stopReceiver() {
senderReceiverService.stopReceiver()
}

override fun isReceiverAlive(): Boolean {
return senderReceiverService.isReceiverAlive()
}

override fun startSender(ip: String) {
senderReceiverService.startSender(ip, null)
}

override fun stopSender() {
senderReceiverService.stopSender()
}

override fun isSenderAlive(): Boolean {
return senderReceiverService.isSenderAlive()
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package org.rocstreaming.rocdroid

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.plugins.FlutterPlugin

class MainActivity: FlutterActivity()
class MainActivity: FlutterActivity(){
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
}}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.rocstreaming.rocdroid
package org.rocstreaming.service

import android.app.Notification
import android.app.NotificationChannel
Expand All @@ -23,6 +23,8 @@ import android.os.IBinder
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import org.rocstreaming.rocdroid.MainActivity
import org.rocstreaming.rocdroid.R
import org.rocstreaming.roctoolkit.ChannelSet
import org.rocstreaming.roctoolkit.ClockSource
import org.rocstreaming.roctoolkit.Endpoint
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions android/app/src/main/res/drawable/ic_stop.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M6,6h12v12H6z"/>
</vector>
58 changes: 58 additions & 0 deletions android/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<resources>
<string name="app_name">Roc Droid</string>

<string name="receiver">Receiver</string>
<string name="start_receiver">Start receiver</string>
<string name="stop_receiver">Stop receiver</string>

<string name="sender">Sender</string>
<string name="receiver_ip">Receiver IP</string>
<string name="default_receiver_ip">192.168.0.1</string>
<string name="start_sender">Start sender</string>
<string name="stop_sender">Stop sender</string>
<string name="invalid_ip_title">Invalid IP address</string>
<string name="invalid_ip_message">The receiver IP address looks invalid.</string>
<string name="allow_mic_title">Mic permission</string>
<string name="allow_mic_message">The app needs permission to record audio from your phone mic.</string>
<string name="allow_mic_ok_message">Thanks! The sender will now start.</string>

<string name="ok">OK</string>

<string name="notification_channel_name">Sender and Receiver foreground service</string>
<string name="notification_receiver_running">Receiver running</string>
<string name="notification_sender_running">Sender running</string>
<string name="notification_sender_and_receiver_running">Sender and Receiver running</string>
<string name="notification_sender_and_receiver_not_running">Neither Sender or Receiver running</string>
<string name="notification_title">Roc State</string>
<string name="notification_stop_sender_action">Stop Sender</string>
<string name="notification_stop_receiver_action">Stop Receiver</string>

<string name="receiver_start_remote_sender">1. Start sender on the remote device</string>
<string name="receiver_use_IP">2. Use one of IP addresses of this device as the remote on the sender</string>
<string name="receiver_start_receiver">5. Start receiver on this device</string>

<string name="sender_start_remote_receiver">1. Start receiver on the remote device</string>
<string name="sender_put_IP_address">4. Put IP address of the remote receiver device below</string>
<string name="sender_choose_audio_source">5. Choose source to capture audio from</string>
<string name="sender_audio_source_current_apps">Currently playing apps</string>
<string name="sender_audio_source_microphone">Microphone</string>
<string name="sender_start_sender">6. Start sender on this device</string>
<string name="dialog_choose_audio_source">Source to capture audio from</string>

<string name="receiver_sender_port_for_source">%s. Use this port for source stream</string>
<string name="receiver_sender_port_for_repair">%s. Use this port for repair stream</string>
<string name="app_about">About</string>
<string name="about_source_code">Source Code</string>
<string name="about_bug_tracker">Bug Tracker</string>
<string name="about_contributors">Contributors</string>
<string name="app_license">Mozilla Public License 2.0</string>

<string name="url_repo">https://github.com/roc-streaming/roc-droid</string>
<string name="url_bugs">https://github.com/roc-streaming/roc-droid/issues</string>
<string name="url_contributors">https://github.com/roc-streaming/roc-droid/graphs/contributors</string>
<string name="uri_license">https://github.com/roc-streaming/roc-droid/blob/main/LICENSE</string>
<string name="app_logo">App Logo</string>
<string name="icon_copy">Copy</string>
<string name="open_dropdown_icon">Open dropdown</string>
<string name="quick_tile_receiver">Roc Droid receiver</string>
</resources>
Loading

0 comments on commit ed28af7

Please sign in to comment.