Skip to main content

blinc_platform_android/
lib.rs

1#![allow(unused, dead_code)]
2//! Blinc Android Platform
3//!
4//! Android platform implementation for Blinc UI framework.
5//!
6//! This crate implements the `blinc_platform` traits for Android,
7//! providing touch input, lifecycle management, and window handling
8//! via the Android NDK.
9//!
10//! # Example
11//!
12//! ```ignore
13//! use blinc_platform::prelude::*;
14//! use blinc_platform_android::AndroidPlatform;
15//!
16//! // AndroidPlatform is created internally by the android_main entry point
17//! // Use the event loop to handle events:
18//! event_loop.run(|event, window| {
19//!     match event {
20//!         Event::Frame => {
21//!             // Render frame
22//!         }
23//!         Event::Lifecycle(LifecycleEvent::Suspended) => {
24//!             // App going to background
25//!         }
26//!         _ => {}
27//!     }
28//!     ControlFlow::Continue
29//! })
30//! ```
31
32pub mod activity;
33pub mod assets;
34pub mod event_loop;
35pub mod input;
36pub mod jni_bridge;
37pub mod jni_utils;
38pub mod native_bridge;
39pub mod window;
40
41pub use assets::AndroidAssetLoader;
42pub use event_loop::{AndroidEventLoop, AndroidWakeProxy};
43pub use jni_utils::{get_display_density, get_display_dpi, is_dark_mode};
44pub use window::AndroidWindow;
45
46// Re-export native bridge types
47#[cfg(target_os = "android")]
48pub use native_bridge::{init_android_native_bridge, AndroidNativeBridgeAdapter};
49
50use blinc_platform::{Platform, PlatformError};
51
52/// Android platform implementation
53///
54/// Provides touch input and lifecycle management for Android apps.
55pub struct AndroidPlatform {
56    #[cfg(target_os = "android")]
57    app: android_activity::AndroidApp,
58}
59
60#[cfg(target_os = "android")]
61impl AndroidPlatform {
62    /// Create a new Android platform with the given AndroidApp
63    pub fn with_app(app: android_activity::AndroidApp) -> Result<Self, PlatformError> {
64        Ok(Self { app })
65    }
66}
67
68impl Platform for AndroidPlatform {
69    type Window = AndroidWindow;
70    type EventLoop = AndroidEventLoop;
71
72    fn new() -> Result<Self, PlatformError> {
73        // On Android, the platform must be created with an AndroidApp from android_main
74        Err(PlatformError::InitFailed(
75            "AndroidPlatform must be created with AndroidPlatform::with_app()".to_string(),
76        ))
77    }
78
79    #[cfg(target_os = "android")]
80    fn create_event_loop(&self) -> Result<Self::EventLoop, PlatformError> {
81        Ok(AndroidEventLoop::new(self.app.clone()))
82    }
83
84    #[cfg(not(target_os = "android"))]
85    fn create_event_loop(&self) -> Result<Self::EventLoop, PlatformError> {
86        Err(PlatformError::Unsupported(
87            "Android platform only available on Android".to_string(),
88        ))
89    }
90
91    fn name(&self) -> &'static str {
92        "android"
93    }
94
95    #[cfg(target_os = "android")]
96    fn scale_factor(&self) -> f64 {
97        get_display_density(&self.app)
98    }
99
100    #[cfg(not(target_os = "android"))]
101    fn scale_factor(&self) -> f64 {
102        1.0
103    }
104}
105
106// Placeholder implementation for non-Android builds
107#[cfg(not(target_os = "android"))]
108impl AndroidPlatform {
109    /// Create a placeholder platform (for cross-compilation checks)
110    pub fn with_app() -> Result<Self, PlatformError> {
111        Err(PlatformError::Unsupported(
112            "Android platform only available on Android".to_string(),
113        ))
114    }
115}
116
117// Android-specific entry point (only with default-activity feature)
118#[cfg(all(target_os = "android", feature = "default-activity"))]
119pub use activity::android_main;
120
121/// Input conversion utilities
122pub mod input_convert {
123    use super::input::{TouchEvent, TouchPointer};
124    use blinc_platform::{InputEvent, TouchEvent as BlincTouchEvent};
125
126    /// Convert Android TouchEvent to blinc_platform InputEvent
127    pub fn convert_touch_event(event: &TouchEvent) -> InputEvent {
128        match event {
129            TouchEvent::Down { pointer, .. } => InputEvent::Touch(BlincTouchEvent::Started {
130                id: pointer.id as u64,
131                x: pointer.x,
132                y: pointer.y,
133                pressure: pointer.pressure,
134            }),
135            TouchEvent::Move { pointers } => {
136                // Report first pointer for move events
137                if let Some(p) = pointers.first() {
138                    InputEvent::Touch(BlincTouchEvent::Moved {
139                        id: p.id as u64,
140                        x: p.x,
141                        y: p.y,
142                        pressure: p.pressure,
143                    })
144                } else {
145                    InputEvent::Touch(BlincTouchEvent::Cancelled { id: 0 })
146                }
147            }
148            TouchEvent::Up { pointer, .. } => InputEvent::Touch(BlincTouchEvent::Ended {
149                id: pointer.id as u64,
150                x: pointer.x,
151                y: pointer.y,
152            }),
153            TouchEvent::Cancel => InputEvent::Touch(BlincTouchEvent::Cancelled { id: 0 }),
154        }
155    }
156
157    /// Convert all touch pointers from a multi-touch move event
158    pub fn convert_multi_touch_move(pointers: &[TouchPointer]) -> Vec<InputEvent> {
159        pointers
160            .iter()
161            .map(|p| {
162                InputEvent::Touch(BlincTouchEvent::Moved {
163                    id: p.id as u64,
164                    x: p.x,
165                    y: p.y,
166                    pressure: p.pressure,
167                })
168            })
169            .collect()
170    }
171}
172
173// Re-export gesture detection
174pub use input::GestureDetector;