feat(bridge,android): BridgeEvent::PermissionState + JNI publish hook + c++_shared link

Per SDD-106 §5 add BridgeEvent::PermissionState{permission, state}
with the PermissionStateKind enum (Granted, Denied, PermanentlyDenied,
Unknown). The Kotlin side publishes mid-session permission changes
through a new JNI entry point Java_app_chanora_chanora_1flutter
_MainActivity_publishPermissionState routed by the new
permission_jni.rs module; the Rust audio engine subscribes and
authoritatively clamps the transmit gate (see SDD-106 §6).

Adds crates/chanora_bridge/build.rs to emit
cargo:rustc-link-lib=dylib=c++_shared on Android so libchanora_bridge
.so carries DT_NEEDED libc++_shared.so; this is required by Android
API 24+ per-library linker namespaces to resolve __cxa_pure_virtual
and friends at System.loadLibrary time.

Includes the FRB-regenerated Dart counterparts so each commit is
independently buildable.

Trace: SDD-105, SDD-106 §5, SDD-118 item 6 (extended).
This commit is contained in:
EdisonJwa
2026-05-18 12:32:01 +08:00
parent 56222d190e
commit 7966a7c8c6
12 changed files with 594 additions and 33 deletions
@@ -1418,6 +1418,14 @@ impl SseDecode for crate::api::BridgeEvent {
should_resume: var_shouldResume,
};
}
10 => {
let mut var_permission = <String>::sse_decode(deserializer);
let mut var_state = <crate::api::PermissionStateKind>::sse_decode(deserializer);
return crate::api::BridgeEvent::PermissionState {
permission: var_permission,
state: var_state,
};
}
_ => {
unimplemented!("");
}
@@ -1555,6 +1563,20 @@ impl SseDecode for Vec<u8> {
}
}
impl SseDecode for crate::api::PermissionStateKind {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
let mut inner = <i32>::sse_decode(deserializer);
return match inner {
0 => crate::api::PermissionStateKind::Granted,
1 => crate::api::PermissionStateKind::Denied,
2 => crate::api::PermissionStateKind::PermanentlyDenied,
3 => crate::api::PermissionStateKind::Unknown,
_ => unreachable!("Invalid variant for PermissionStateKind: {}", inner),
};
}
}
impl SseDecode for (String, String) {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
@@ -1836,6 +1858,12 @@ impl flutter_rust_bridge::IntoDart for crate::api::BridgeEvent {
should_resume.into_into_dart().into_dart(),
]
.into_dart(),
crate::api::BridgeEvent::PermissionState { permission, state } => [
10.into_dart(),
permission.into_into_dart().into_dart(),
state.into_into_dart().into_dart(),
]
.into_dart(),
_ => {
unimplemented!("");
}
@@ -1935,6 +1963,29 @@ impl flutter_rust_bridge::IntoIntoDart<crate::api::BridgeTransmitMode>
self
}
}
// Codec=Dco (DartCObject based), see doc to use other codecs
impl flutter_rust_bridge::IntoDart for crate::api::PermissionStateKind {
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
match self {
Self::Granted => 0.into_dart(),
Self::Denied => 1.into_dart(),
Self::PermanentlyDenied => 2.into_dart(),
Self::Unknown => 3.into_dart(),
_ => unreachable!(),
}
}
}
impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive
for crate::api::PermissionStateKind
{
}
impl flutter_rust_bridge::IntoIntoDart<crate::api::PermissionStateKind>
for crate::api::PermissionStateKind
{
fn into_into_dart(self) -> crate::api::PermissionStateKind {
self
}
}
impl SseEncode for flutter_rust_bridge::for_generated::anyhow::Error {
// Codec=Sse (Serialization based), see doc to use other codecs
@@ -2110,6 +2161,11 @@ impl SseEncode for crate::api::BridgeEvent {
<bool>::sse_encode(began, serializer);
<bool>::sse_encode(should_resume, serializer);
}
crate::api::BridgeEvent::PermissionState { permission, state } => {
<i32>::sse_encode(10, serializer);
<String>::sse_encode(permission, serializer);
<crate::api::PermissionStateKind>::sse_encode(state, serializer);
}
_ => {
unimplemented!("");
}
@@ -2242,6 +2298,24 @@ impl SseEncode for Vec<u8> {
}
}
impl SseEncode for crate::api::PermissionStateKind {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
<i32>::sse_encode(
match self {
crate::api::PermissionStateKind::Granted => 0,
crate::api::PermissionStateKind::Denied => 1,
crate::api::PermissionStateKind::PermanentlyDenied => 2,
crate::api::PermissionStateKind::Unknown => 3,
_ => {
unimplemented!("");
}
},
serializer,
);
}
}
impl SseEncode for (String, String) {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {