Skip to content

Commit 6ad9ad6

Browse files
committed
Add Android platform support (stub implementation)
1 parent 904eec9 commit 6ad9ad6

17 files changed

+1151
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
.vscode/
44
build/
55
cmake-build-debug/
6+
build-android/
67

78
# Generated test binaries and object files
89
*.o

examples/menu_c_example/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ if(APPLE)
1818
target_link_libraries(menu_c_example ${COCOA_LIBRARY})
1919
elseif(WIN32)
2020
target_link_libraries(menu_c_example user32 kernel32)
21-
elseif(UNIX)
21+
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
2222
find_package(PkgConfig REQUIRED)
2323
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
2424
target_include_directories(menu_c_example PRIVATE ${GTK3_INCLUDE_DIRS})
2525
target_link_libraries(menu_c_example ${GTK3_LIBRARIES})
26+
elseif(ANDROID)
27+
target_link_libraries(menu_c_example log android)
2628
endif()

examples/menu_example/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ if(APPLE)
1818
target_link_libraries(menu_example ${COCOA_LIBRARY})
1919
elseif(WIN32)
2020
target_link_libraries(menu_example user32 kernel32)
21-
elseif(UNIX)
21+
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
2222
find_package(PkgConfig REQUIRED)
2323
pkg_check_modules(GTK3 REQUIRED gtk+-3.0)
2424
target_include_directories(menu_example PRIVATE ${GTK3_INCLUDE_DIRS})
2525
target_link_libraries(menu_example ${GTK3_LIBRARIES})
26+
elseif(ANDROID)
27+
target_link_libraries(menu_example log android)
2628
endif()

src/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ elseif(APPLE)
3434
file(GLOB PLATFORM_SOURCES "platform/macos/*.mm")
3535
elseif(WIN32)
3636
file(GLOB PLATFORM_SOURCES "platform/windows/*.cpp")
37+
elseif(ANDROID)
38+
file(GLOB PLATFORM_SOURCES "platform/android/*.cpp")
3739
else()
3840
set(PLATFORM_SOURCES "")
3941
endif()
@@ -68,4 +70,6 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
6870
target_link_libraries(nativeapi PUBLIC PkgConfig::GTK PkgConfig::X11 PkgConfig::XI PkgConfig::AYATANA_APPINDICATOR pthread)
6971
elseif(WIN32)
7072
target_link_libraries(nativeapi PUBLIC user32 shell32 dwmapi gdiplus crypt32)
73+
elseif(ANDROID)
74+
target_link_libraries(nativeapi PUBLIC log android)
7175
endif ()

src/accessibility_manager.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,31 @@
11
#include "accessibility_manager.h"
22

3+
#ifdef ANDROID
4+
#include <android/log.h>
5+
#define LOG_TAG "NativeApi"
6+
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
7+
#endif
8+
39
namespace nativeapi {
410

511
AccessibilityManager& AccessibilityManager::GetInstance() {
612
static AccessibilityManager instance;
713
return instance;
814
}
915

10-
AccessibilityManager::AccessibilityManager() {}
16+
AccessibilityManager::AccessibilityManager() : enabled_(false) {}
1117

1218
AccessibilityManager::~AccessibilityManager() {}
1319

20+
void AccessibilityManager::Enable() {
21+
#ifdef ANDROID
22+
ALOGW("AccessibilityManager::Enable requires AccessibilityService on Android");
23+
#endif
24+
enabled_ = true;
25+
}
26+
27+
bool AccessibilityManager::IsEnabled() {
28+
return enabled_;
29+
}
30+
1431
} // namespace nativeapi

src/platform/android/README.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# Android Platform Implementation
2+
3+
This directory contains Android-specific implementations of the nativeapi library.
4+
5+
## Overview
6+
7+
The Android implementation uses the Android NDK to provide access to native system APIs. Due to Android's unique application model, some desktop concepts are mapped differently:
8+
9+
- **Windows** → Activities/Views (`ANativeWindow`)
10+
- **Menus** → Context menus or ActionBar menus
11+
- **Tray Icons** → System notifications
12+
- **Display Management** → Display Manager API
13+
- **Keyboard Monitoring** → Accessibility Services
14+
15+
## Files
16+
17+
- `window_android.cpp` - Window management using `ANativeWindow`
18+
- `window_manager_android.cpp` - Window manager for Activity lifecycle
19+
- `display_android.cpp` - Display information (stub)
20+
- `display_manager_android.cpp` - Display manager (stub)
21+
- `menu_android.cpp` - Menu implementation (stub)
22+
- `tray_icon_android.cpp` - Tray icon using notifications (stub)
23+
- `tray_manager_android.cpp` - Tray manager (stub)
24+
- `keyboard_monitor_android.cpp` - Keyboard monitoring via AccessibilityService (stub)
25+
- `accessibility_manager_android.cpp` - Accessibility manager (stub)
26+
- `application_android.cpp` - Application lifecycle (stub)
27+
- `image_android.cpp` - Image loading (stub)
28+
29+
## Building
30+
31+
These files are automatically included when building with the Android NDK:
32+
33+
```bash
34+
cmake -DCMAKE_SYSTEM_NAME=Android \
35+
-DCMAKE_ANDROID_NDK=/path/to/android-ndk \
36+
..
37+
```
38+
39+
## Android NDK Requirements
40+
41+
- Android NDK r21 or later
42+
- Minimum Android SDK: API level 24 (Android 7.0)
43+
- Recommended: API level 29+ (Android 10.0+)
44+
45+
## Key Differences from Desktop
46+
47+
### Window Management
48+
49+
Android uses `ANativeWindow` instead of platform-specific window handles:
50+
51+
```cpp
52+
// Desktop: HWND (Windows), NSWindow* (macOS), GdkWindow* (Linux)
53+
// Android: ANativeWindow*
54+
55+
void* Window::GetNativeObjectInternal() const {
56+
return static_cast<void*>(pimpl_->native_window_);
57+
}
58+
```
59+
60+
### Activity Lifecycle
61+
62+
Windows in Android are created and managed through the Activity lifecycle. Window creation happens automatically when the Activity creates a native window surface.
63+
64+
### Logging
65+
66+
Android uses the logging API instead of standard output:
67+
68+
```cpp
69+
#include <android/log.h>
70+
71+
#define LOG_TAG "NativeApi"
72+
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
73+
```
74+
75+
## Implementation Status
76+
77+
| Component | Status | Notes |
78+
|-----------|--------|-------|
79+
| Window | ✅ Implemented | Uses ANativeWindow API |
80+
| Window Manager | ✅ Implemented | Activity lifecycle integration |
81+
| Display | ⚠️ Stub | Basic implementation |
82+
| Display Manager | ⚠️ Stub | Basic implementation |
83+
| Menu | ⚠️ Stub | Needs Context menu integration |
84+
| Tray Icon | ⚠️ Stub | Needs Notification API |
85+
| Tray Manager | ⚠️ Stub | Needs Notification API |
86+
| Keyboard Monitor | ⚠️ Stub | Needs AccessibilityService |
87+
| Accessibility Manager | ⚠️ Stub | Needs Android permissions |
88+
| Application | ⚠️ Stub | Basic lifecycle |
89+
| Image | ⚠️ Stub | Needs Bitmap loading |
90+
91+
## See Also
92+
93+
- [Android NDK Documentation](https://developer.android.com/ndk)
94+
- [ANativeWindow API](https://developer.android.com/ndk/reference/group/native-activity#anativewindow)
95+
- [docs/ANDROID.md](../../../docs/ANDROID.md) - User-facing Android documentation
96+
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#include <android/log.h>
2+
#include "../../application.h"
3+
4+
#define LOG_TAG "NativeApi"
5+
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
6+
7+
namespace nativeapi {
8+
9+
class Application::Impl {
10+
public:
11+
Impl() {}
12+
};
13+
14+
Application::Application() : pimpl_(std::make_unique<Impl>()) {}
15+
Application::~Application() {}
16+
17+
int Application::Run() {
18+
ALOGW("Application::Run not applicable on Android (handled by Activity lifecycle)");
19+
return 0;
20+
}
21+
22+
int Application::Run(std::shared_ptr<Window> window) {
23+
ALOGW("Application::Run with window not applicable on Android");
24+
return 0;
25+
}
26+
27+
void Application::Quit(int exit_code) {
28+
ALOGW("Application::Quit requests Activity finish");
29+
}
30+
31+
bool Application::IsRunning() const {
32+
return true;
33+
}
34+
35+
bool Application::IsSingleInstance() const {
36+
return false;
37+
}
38+
39+
bool Application::SetIcon(const std::string& icon_path) {
40+
ALOGW("Application::SetIcon not implemented on Android");
41+
return false;
42+
}
43+
44+
bool Application::SetDockIconVisible(bool visible) {
45+
ALOGW("Application::SetDockIconVisible not applicable on Android");
46+
return false;
47+
}
48+
49+
bool Application::SetMenuBar(std::shared_ptr<Menu> menu) {
50+
ALOGW("Application::SetMenuBar not implemented on Android");
51+
return false;
52+
}
53+
54+
std::shared_ptr<Window> Application::GetPrimaryWindow() const {
55+
return nullptr;
56+
}
57+
58+
void Application::SetPrimaryWindow(std::shared_ptr<Window> window) {
59+
ALOGW("Application::SetPrimaryWindow not implemented on Android");
60+
}
61+
62+
} // namespace nativeapi
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#include <android/log.h>
2+
#include "../../display.h"
3+
4+
#define LOG_TAG "NativeApi"
5+
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
6+
7+
namespace nativeapi {
8+
9+
class Display::Impl {
10+
public:
11+
Impl() {}
12+
};
13+
14+
Display::Display() : pimpl_(std::make_unique<Impl>()) {}
15+
Display::Display(void* display) : pimpl_(std::make_unique<Impl>()) {}
16+
Display::~Display() {}
17+
18+
Display::Display(const Display& other) : pimpl_(std::make_unique<Impl>()) {}
19+
Display& Display::operator=(const Display& other) { return *this; }
20+
Display::Display(Display&& other) noexcept : pimpl_(std::move(other.pimpl_)) {}
21+
Display& Display::operator=(Display&& other) noexcept {
22+
pimpl_ = std::move(other.pimpl_);
23+
return *this;
24+
}
25+
26+
void* Display::GetNativeObjectInternal() const {
27+
return nullptr;
28+
}
29+
30+
std::string Display::GetId() const {
31+
return "android_display_0";
32+
}
33+
34+
std::string Display::GetName() const {
35+
return "Android Display";
36+
}
37+
38+
Point Display::GetPosition() const {
39+
return Point{0, 0};
40+
}
41+
42+
Size Display::GetSize() const {
43+
return Size{1080, 1920};
44+
}
45+
46+
Rectangle Display::GetWorkArea() const {
47+
return Rectangle{0, 0, 1080, 1920};
48+
}
49+
50+
double Display::GetScaleFactor() const {
51+
return 2.0;
52+
}
53+
54+
bool Display::IsPrimary() const {
55+
return true;
56+
}
57+
58+
DisplayOrientation Display::GetOrientation() const {
59+
return DisplayOrientation::kPortrait;
60+
}
61+
62+
int Display::GetRefreshRate() const {
63+
return 60;
64+
}
65+
66+
int Display::GetBitDepth() const {
67+
return 24;
68+
}
69+
70+
} // namespace nativeapi
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include <android/log.h>
2+
#include "../../display_manager.h"
3+
4+
#define LOG_TAG "NativeApi"
5+
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
6+
7+
namespace nativeapi {
8+
9+
DisplayManager::DisplayManager() {}
10+
DisplayManager::~DisplayManager() {}
11+
12+
std::vector<Display> DisplayManager::GetAll() {
13+
return {Display()};
14+
}
15+
16+
Display DisplayManager::GetPrimary() {
17+
return Display();
18+
}
19+
20+
Point DisplayManager::GetCursorPosition() {
21+
return Point{0, 0};
22+
}
23+
24+
} // namespace nativeapi
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <android/log.h>
2+
#include "../../image.h"
3+
4+
#define LOG_TAG "NativeApi"
5+
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
6+
7+
namespace nativeapi {
8+
9+
class Image::Impl {
10+
public:
11+
Impl() {}
12+
};
13+
14+
Image::Image() : pimpl_(std::make_unique<Impl>()) {}
15+
Image::~Image() {}
16+
Image::Image(const Image& other) : pimpl_(std::make_unique<Impl>()) {}
17+
Image::Image(Image&& other) noexcept : pimpl_(std::move(other.pimpl_)) {}
18+
19+
std::shared_ptr<Image> Image::FromFile(const std::string& file_path) {
20+
ALOGW("Image::FromFile not implemented on Android");
21+
return nullptr;
22+
}
23+
24+
std::shared_ptr<Image> Image::FromBase64(const std::string& base64_data) {
25+
ALOGW("Image::FromBase64 not implemented on Android");
26+
return nullptr;
27+
}
28+
29+
Size Image::GetSize() const {
30+
return Size{0, 0};
31+
}
32+
33+
std::string Image::GetFormat() const {
34+
return "";
35+
}
36+
37+
void* Image::GetNativeObjectInternal() const {
38+
return nullptr;
39+
}
40+
41+
} // namespace nativeapi

0 commit comments

Comments
 (0)