diff options
| author | ruki <[email protected]> | 2025-12-16 17:57:11 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-12-16 17:57:11 +0800 |
| commit | d1485fa867ebb3b661a16ec043f33537a7f9f0cd (patch) | |
| tree | 351a965dfb03438caf4a5a55620a11108ffabcac /tests/projects/android/native_app/lvgl_basic | |
| parent | d3acb6ca0d74d506d4a7da0fb7c055344591cb7a (diff) | |
| parent | 7b542ebe22e833bd56dd1eb0271aa5aa7c0b45a8 (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.xml | 30 | ||||
| -rw-r--r-- | tests/projects/android/native_app/lvgl_basic/android/debug.jks | bin | 0 -> 2148 bytes | |||
| -rw-r--r-- | tests/projects/android/native_app/lvgl_basic/android/res/mipmap-mdpi/icon.png | bin | 0 -> 2643 bytes | |||
| -rw-r--r-- | tests/projects/android/native_app/lvgl_basic/android/res/mipmap/icon.png | bin | 0 -> 2643 bytes | |||
| -rw-r--r-- | tests/projects/android/native_app/lvgl_basic/android/res/values/strings.xml | 4 | ||||
| -rw-r--r-- | tests/projects/android/native_app/lvgl_basic/android/res/values/styles.xml | 9 | ||||
| -rw-r--r-- | tests/projects/android/native_app/lvgl_basic/src/main.c | 169 | ||||
| -rw-r--r-- | tests/projects/android/native_app/lvgl_basic/xmake.lua | 23 |
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 Binary files differnew file mode 100644 index 000000000..0a18aa012 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_basic/android/debug.jks 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 Binary files differnew file mode 100644 index 000000000..743413831 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_basic/android/res/mipmap-mdpi/icon.png 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 Binary files differnew file mode 100644 index 000000000..743413831 --- /dev/null +++ b/tests/projects/android/native_app/lvgl_basic/android/res/mipmap/icon.png 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"} + }) |
