summaryrefslogtreecommitdiff
path: root/tests/projects/android/native_app/lvgl_basic
diff options
context:
space:
mode:
authorruki <[email protected]>2025-12-16 17:57:11 +0800
committerGitHub <[email protected]>2025-12-16 17:57:11 +0800
commitd1485fa867ebb3b661a16ec043f33537a7f9f0cd (patch)
tree351a965dfb03438caf4a5a55620a11108ffabcac /tests/projects/android/native_app/lvgl_basic
parentd3acb6ca0d74d506d4a7da0fb7c055344591cb7a (diff)
parent7b542ebe22e833bd56dd1eb0271aa5aa7c0b45a8 (diff)
Merge pull request #7139 from xmake-io/android
Add android native app support
Diffstat (limited to 'tests/projects/android/native_app/lvgl_basic')
-rw-r--r--tests/projects/android/native_app/lvgl_basic/android/AndroidManifest.xml30
-rw-r--r--tests/projects/android/native_app/lvgl_basic/android/debug.jksbin0 -> 2148 bytes
-rw-r--r--tests/projects/android/native_app/lvgl_basic/android/res/mipmap-mdpi/icon.pngbin0 -> 2643 bytes
-rw-r--r--tests/projects/android/native_app/lvgl_basic/android/res/mipmap/icon.pngbin0 -> 2643 bytes
-rw-r--r--tests/projects/android/native_app/lvgl_basic/android/res/values/strings.xml4
-rw-r--r--tests/projects/android/native_app/lvgl_basic/android/res/values/styles.xml9
-rw-r--r--tests/projects/android/native_app/lvgl_basic/src/main.c169
-rw-r--r--tests/projects/android/native_app/lvgl_basic/xmake.lua23
8 files changed, 235 insertions, 0 deletions
diff --git a/tests/projects/android/native_app/lvgl_basic/android/AndroidManifest.xml b/tests/projects/android/native_app/lvgl_basic/android/AndroidManifest.xml
new file mode 100644
index 000000000..98c3d3795
--- /dev/null
+++ b/tests/projects/android/native_app/lvgl_basic/android/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.lvgl.basic"
+
+ android:versionCode="15"
+ android:versionName="1.5">
+
+ <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
+
+ <uses-permission android:name="android.permission.SET_RELEASE_APP"/>
+
+ <application
+ android:label="LvglBasic" android:debuggable="true" android:hasCode="false"
+ tools:replace="android:icon,android:theme,android:allowBackup,label"
+ android:icon="@mipmap/icon">
+
+ <activity android:name="android.app.NativeActivity"
+ android:label="LvglBasic"
+ android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
+ <meta-data android:name="android.app.lib_name"
+ android:value="main" />
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest> \ No newline at end of file
diff --git a/tests/projects/android/native_app/lvgl_basic/android/debug.jks b/tests/projects/android/native_app/lvgl_basic/android/debug.jks
new file mode 100644
index 000000000..0a18aa012
--- /dev/null
+++ b/tests/projects/android/native_app/lvgl_basic/android/debug.jks
Binary files differ
diff --git a/tests/projects/android/native_app/lvgl_basic/android/res/mipmap-mdpi/icon.png b/tests/projects/android/native_app/lvgl_basic/android/res/mipmap-mdpi/icon.png
new file mode 100644
index 000000000..743413831
--- /dev/null
+++ b/tests/projects/android/native_app/lvgl_basic/android/res/mipmap-mdpi/icon.png
Binary files differ
diff --git a/tests/projects/android/native_app/lvgl_basic/android/res/mipmap/icon.png b/tests/projects/android/native_app/lvgl_basic/android/res/mipmap/icon.png
new file mode 100644
index 000000000..743413831
--- /dev/null
+++ b/tests/projects/android/native_app/lvgl_basic/android/res/mipmap/icon.png
Binary files differ
diff --git a/tests/projects/android/native_app/lvgl_basic/android/res/values/strings.xml b/tests/projects/android/native_app/lvgl_basic/android/res/values/strings.xml
new file mode 100644
index 000000000..7dc865540
--- /dev/null
+++ b/tests/projects/android/native_app/lvgl_basic/android/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">Lvgl Basic</string>
+</resources> \ No newline at end of file
diff --git a/tests/projects/android/native_app/lvgl_basic/android/res/values/styles.xml b/tests/projects/android/native_app/lvgl_basic/android/res/values/styles.xml
new file mode 100644
index 000000000..621547380
--- /dev/null
+++ b/tests/projects/android/native_app/lvgl_basic/android/res/values/styles.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <style name="AppTheme" parent="android:Theme.NoTitleBar.Fullscreen">
+ <item name="android:windowBackground">@android:color/black</item>
+ <item name="android:colorPrimary">#FF6200EE</item>
+ <item name="android:colorPrimaryDark">#FF3700B3</item>
+ <item name="android:colorAccent">#FF03DAC5</item>
+ </style>
+</resources> \ No newline at end of file
diff --git a/tests/projects/android/native_app/lvgl_basic/src/main.c b/tests/projects/android/native_app/lvgl_basic/src/main.c
new file mode 100644
index 000000000..f07036e9b
--- /dev/null
+++ b/tests/projects/android/native_app/lvgl_basic/src/main.c
@@ -0,0 +1,169 @@
+#include <lvgl/lvgl.h>
+#include <android/native_window.h>
+#include <android/log.h>
+#include <android_native_app_glue.h>
+#include <time.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define LOG_TAG "lvgl_basic"
+#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+
+static lv_display_t * display = NULL;
+static lv_indev_t * indev = NULL;
+static void * disp_buf = NULL;
+static ANativeWindow * native_window = NULL;
+static int32_t window_width = 0;
+static int32_t window_height = 0;
+static lv_obj_t * label_fps = NULL;
+
+static bool touch_down = false;
+static int32_t touch_x = 0;
+static int32_t touch_y = 0;
+
+static void my_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map) {
+ if (!native_window) {
+ lv_display_flush_ready(disp);
+ return;
+ }
+
+ ANativeWindow_Buffer buffer;
+ if (ANativeWindow_lock(native_window, &buffer, NULL) < 0) {
+ lv_display_flush_ready(disp);
+ return;
+ }
+
+ int32_t width = lv_area_get_width(area);
+ int32_t height = lv_area_get_height(area);
+
+ // Assume 32-bit RGBA
+ uint32_t * dst_base = (uint32_t *)buffer.bits;
+ uint32_t * src = (uint32_t *)px_map;
+ int stride = buffer.stride;
+
+ for (int y = 0; y < height; y++) {
+ uint32_t * dst_line = dst_base + (area->y1 + y) * stride + area->x1;
+ memcpy(dst_line, src + y * width, width * sizeof(uint32_t));
+ }
+
+ ANativeWindow_unlockAndPost(native_window);
+ lv_display_flush_ready(disp);
+}
+
+static void my_input_read(lv_indev_t * indev, lv_indev_data_t * data) {
+ data->point.x = touch_x;
+ data->point.y = touch_y;
+ data->state = touch_down ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
+}
+
+static void create_ui(void) {
+ lv_obj_t * label = lv_label_create(lv_screen_active());
+ lv_label_set_text(label, "Hello Xmake + LVGL!");
+ lv_obj_set_style_text_font(label, &lv_font_montserrat_14, 0);
+ lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 50);
+
+ // FPS label
+ label_fps = lv_label_create(lv_screen_active());
+ lv_label_set_text(label_fps, "FPS: 0");
+ lv_obj_set_style_text_font(label_fps, &lv_font_montserrat_14, 0);
+ lv_obj_align(label_fps, LV_ALIGN_TOP_MID, 0, 100);
+}
+
+static void handle_cmd(struct android_app* app, int32_t cmd) {
+ switch (cmd) {
+ case APP_CMD_INIT_WINDOW:
+ LOGI("Init Window");
+ native_window = app->window;
+ window_width = ANativeWindow_getWidth(native_window);
+ window_height = ANativeWindow_getHeight(native_window);
+ ANativeWindow_setBuffersGeometry(native_window, window_width, window_height, WINDOW_FORMAT_RGBA_8888);
+
+ if (!display) {
+ display = lv_display_create(window_width, window_height);
+ lv_display_set_color_format(display, LV_COLOR_FORMAT_ARGB8888);
+ lv_display_set_flush_cb(display, my_flush_cb);
+
+ size_t buf_size = window_width * window_height * 4;
+ disp_buf = malloc(buf_size);
+ lv_display_set_buffers(display, disp_buf, NULL, buf_size, LV_DISPLAY_RENDER_MODE_FULL);
+
+ indev = lv_indev_create();
+ lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
+ lv_indev_set_read_cb(indev, my_input_read);
+
+ create_ui();
+ } else {
+ lv_display_set_resolution(display, window_width, window_height);
+ lv_obj_invalidate(lv_scr_act());
+ }
+ break;
+ case APP_CMD_TERM_WINDOW:
+ native_window = NULL;
+ break;
+ case APP_CMD_DESTROY:
+ if (display) {
+ lv_display_delete(display);
+ display = NULL;
+ }
+ if (indev) {
+ lv_indev_delete(indev);
+ indev = NULL;
+ }
+ if (disp_buf) {
+ free(disp_buf);
+ disp_buf = NULL;
+ }
+ break;
+ }
+}
+
+static int32_t handle_input(struct android_app* app, AInputEvent* event) {
+ if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
+ int action = AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK;
+ touch_x = AMotionEvent_getX(event, 0);
+ touch_y = AMotionEvent_getY(event, 0);
+ if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_MOVE) {
+ touch_down = true;
+ } else {
+ touch_down = false;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+void android_main(struct android_app* app) {
+ lv_init();
+
+ app->onAppCmd = handle_cmd;
+ app->onInputEvent = handle_input;
+
+ int frame_count = 0;
+ time_t last_time = time(NULL);
+
+ while (1) {
+ int ident;
+ int events;
+ struct android_poll_source* source;
+
+ uint32_t timeout = lv_timer_handler();
+ if (timeout > 50) timeout = 50;
+
+ while ((ident = ALooper_pollAll(timeout, NULL, &events, (void**)&source)) >= 0) {
+ if (source != NULL) source->process(app, source);
+ if (app->destroyRequested != 0) return;
+ }
+
+ lv_tick_inc(timeout);
+
+ frame_count++;
+ time_t current_time = time(NULL);
+ if (current_time - last_time >= 1) {
+ if (label_fps) {
+ lv_label_set_text_fmt(label_fps, "FPS: %d", frame_count);
+ }
+ frame_count = 0;
+ last_time = current_time;
+ }
+ }
+}
diff --git a/tests/projects/android/native_app/lvgl_basic/xmake.lua b/tests/projects/android/native_app/lvgl_basic/xmake.lua
new file mode 100644
index 000000000..659d04f45
--- /dev/null
+++ b/tests/projects/android/native_app/lvgl_basic/xmake.lua
@@ -0,0 +1,23 @@
+add_rules("mode.debug", "mode.release")
+
+add_requires("lvgl 9.1.0")
+
+target("lvgl_basic")
+ set_kind("binary")
+ set_languages("c99")
+ add_files("src/main.c")
+ add_syslinks("log", "android", "EGL", "GLESv2")
+ add_packages("lvgl")
+
+ -- define LV_CONF_INCLUDE_SIMPLE to include lv_conf.h
+ add_defines("LV_CONF_INCLUDE_SIMPLE")
+
+ add_rules("android.native_app", {
+ android_sdk_version = "35",
+ android_manifest = "android/AndroidManifest.xml",
+ android_res = "android/res",
+ keystore = "android/debug.jks",
+ keystore_pass = "123456",
+ package_name = "com.lvgl.basic",
+ logcat_filters = {"lvgl_basic", "lvgl"}
+ })