Simplify Iris app initialization and task updates

This commit is contained in:
iris committed 2026-09-11 12:28:33 -04:00
1 parent b5666cdef9
commit 166bac2a93
25 files changed
+330 -282

No files matched your search

+31 -19
View File
@@ -1,5 +1,5 @@
use crate::prelude::*;
use crate::task::RequestRedraw;
use crate::task::WakeTaskQueue;
use accesskit_android::Adapter as AccessAdapter;
use android_view::{
AccessibilityNodeInfo, AccessibilityNodeProvider, Bundle, CallbackCtx, Context,
@@ -16,7 +16,7 @@ use std::{cell::RefCell, marker::Sized, rc::Rc, sync::Arc, time::Instant};
use super::{
access::{AndroidAccessSource, NullActionHandler, raise_if_enabled},
insets::{Insets, Shared},
render::{AndroidRedrawHandle, AndroidRenderer},
render::{AndroidRenderer, AndroidTaskWake},
};
/// Android host state. The renderer follows the `SurfaceView` lifecycle.
@@ -100,6 +100,16 @@ pub trait HasAndroidUiState: Sized + 'static {
fn android_state_mut(&mut self) -> &mut AndroidUiState;
}
impl HasAndroidUiState for AndroidUiState {
fn android_state(&self) -> &AndroidUiState {
self
}
fn android_state_mut(&mut self) -> &mut AndroidUiState {
self
}
}
/// Application state retained for the lifetime of one Android `View`.
///
/// [`StdRsc`] is the usual [`AndroidResources`] implementation, but the host only
@@ -118,6 +128,10 @@ pub trait AndroidAppState: HasAndroidUiState {
fn on_insets_changed(&mut self, rsc: &mut Self::Resources, insets: WindowInsets) {}
}
impl AndroidAppState for AndroidUiState {
type Resources = StdRsc<Self>;
}
/// Resources the Android host needs to draw and dispatch application events.
///
/// This deliberately names capabilities rather than storage. Custom bundles
@@ -128,12 +142,12 @@ pub trait AndroidResources<State>:
where
State: 'static,
{
fn new(redraw: Arc<dyn RequestRedraw>) -> (Self, TaskMsgReceiver<Self>);
fn new(wake: Arc<dyn WakeTaskQueue>) -> (Self, TaskMsgReceiver<Self>);
}
impl<State: 'static> AndroidResources<State> for StdRsc<State> {
fn new(redraw: Arc<dyn RequestRedraw>) -> (Self, TaskMsgReceiver<Self>) {
StdRsc::new(redraw)
fn new(wake: Arc<dyn WakeTaskQueue>) -> (Self, TaskMsgReceiver<Self>) {
StdRsc::new(wake)
}
}
@@ -223,8 +237,12 @@ impl<State: AndroidAppState> IrisViewPeer<State> {
self.update_ime_selection(ctx);
let ui_state = self.state.android_state_mut();
ui_state.cursor.end_frame();
self.state.android_state_mut().cursor.end_frame();
self.request_frame_if_needed(ctx);
}
fn request_frame_if_needed(&self, ctx: &mut CallbackCtx) {
let ui_state = self.state.android_state();
let render_state = self.rsc.ui().render_state();
if render_state
.get()
@@ -720,18 +738,12 @@ impl<State: AndroidAppState> ViewPeer for IrisViewPeer<State> {
self.render(ctx, now);
}
/// Where `AndroidRedrawHandle::request_redraw` (`android/render.rs`)
/// actually lands: `View.postDelayed`'s Runnable resolves to this, on
/// the UI thread, which is what makes it safe to call from a background
/// task's own thread when `post_frame_callback`'s `Choreographer`
/// requirement (a `Looper` on the *calling* thread) is not. Same body
/// as `do_frame` -- draining tasks and rendering immediately is a
/// perfectly good answer to "a background fetch has new state," and
/// avoids a second frame-scheduling path to keep in sync with the real
/// one.
/// Where `AndroidTaskWake::wake` lands on the UI thread. Applying an
/// update and drawing it are deliberately separate: retained widget
/// invalidation decides whether this wake needs a frame.
fn delayed_callback(&mut self, ctx: &mut CallbackCtx) {
self.drain_tasks();
self.render(ctx, Instant::now());
self.request_frame_if_needed(ctx);
}
fn as_input_connection(&mut self) -> Option<&mut dyn InputConnection> {
@@ -835,8 +847,8 @@ pub fn new_peer<'local, State: AndroidAppState>(
log::info!("iris: new_peer content_scale={content_scale}");
let vm = env.get_java_vm().unwrap();
let global_view = env.new_global_ref(&view.0).unwrap();
let redraw: Arc<dyn RequestRedraw> = Arc::new(AndroidRedrawHandle::new(vm, global_view));
let (mut rsc, task_recv) = State::Resources::new(redraw);
let wake: Arc<dyn WakeTaskQueue> = Arc::new(AndroidTaskWake::new(vm, global_view));
let (mut rsc, task_recv) = State::Resources::new(wake);
rsc.ui_mut().set_density(content_scale);
let shared = Rc::new(RefCell::new(Shared::default()));
let ui_state = AndroidUiState::new(shared.clone(), content_scale);