add remote_ui to ui auto test

This commit is contained in:
lixianjing 2023-11-05 18:33:21 +08:00
parent 37bdd202c4
commit 4997b13211
31 changed files with 3317 additions and 53 deletions

3
.gitignore vendored
View File

@ -37,3 +37,6 @@ tools/idl_gen/idl.json
tools/idl_gen/tkc.json
t.*
test.png
README.md.download
manifest.txt
test.xml

View File

@ -76,6 +76,7 @@ if complie_helper.get_value('BUILD_TOOLS', True) :
'tools/preview_ui/SConscript',
'tools/fdb/SConscript',
'tools/dltest/SConscript',
'tools/ui_test/SConscript',
'src/hal/tools/network_shell/SConscript',
]

View File

@ -27,6 +27,7 @@
#include "ext_widgets.h"
#include "base/font_manager.h"
#include "base/event_recorder_player.h"
#include "remote_ui/service/remote_ui_service.h"
#define DEMOUI_MAIN_WINDOW_NAME "main"
#define SCROLL_BAR_H_WIDGT_NAME "bar_h"
@ -1416,6 +1417,12 @@ ret_t application_init() {
fs_get_user_storage_path(os_fs(), path);
log_debug("user storage path:%s\n", path);
#ifndef REMOTE_UI_URL
#define REMOTE_UI_URL "tcp://localhost:2233"
#endif/*REMOTE_UI_URL*/
tk_service_start(main_loop_get_event_source_manager(main_loop()), REMOTE_UI_URL, remote_ui_service_create, NULL);
return show_preload_res_window();
}

View File

@ -1,4 +1,11 @@
# 最新动态
2023/11/5
* 完善UI自动测试框架 src/remote\_ui
* 增加服务接口 src/service
2023/11/4
* 增加UI自动测试框架 src/remote\_ui
2023/11/03
* 修复子进程继承句柄机制有概率导致父进程异常的问题(感谢智明提供补丁)
* 修复ui\_loader\_load\_widget接口加载edit控件时打印大量警告的问题(感谢雨欣提供补丁)

View File

@ -23,6 +23,10 @@ BASE_SOURCES = Glob('layouters/*.c') + \
Glob('widget_animators/*.c') + \
Glob('window_animators/*.c') + \
Glob('dialog_highlighters/*.c') + \
Glob('service/*.c') + \
Glob('remote_ui/service/*.c') + \
Glob('remote_ui/client/*.c') + \
Glob('remote_ui/shared/*.c') + \
Glob('window_manager/window_manager_default.c')
if GRAPHIC_BUFFER == "default" :

View File

@ -5275,3 +5275,51 @@ ret_t widget_dispatch_model_event(widget_t* widget, const char* name, const char
return RET_OK;
}
widget_t* widget_find_by_path(widget_t* widget, const char* path, bool_t recursive) {
bool_t is_first = TRUE;
tokenizer_t tokenizer;
widget_t* iter = widget;
tokenizer_t* t = NULL;
return_value_if_fail(widget != NULL && path != NULL, NULL);
if (strchr(path, '.') == NULL) {
const char* name = path;
if (tk_str_eq(name, STR_PROP_PARENT)) {
return widget->parent;
} else if (tk_str_eq(name, STR_PROP_SELF)) {
return widget;
} else if (tk_str_eq(name, STR_PROP_WINDOW)) {
return widget_get_window(widget);
} else if (tk_str_eq(name, STR_PROP_WINDOW_MANAGER)) {
return widget_get_window_manager(widget);
} else {
return widget_lookup(widget, name, recursive);
}
}
t = tokenizer_init(&tokenizer, path, strlen(path), ".");
return_value_if_fail(t != NULL, NULL);
while (tokenizer_has_more(t) && iter != NULL) {
const char* name = tokenizer_next(t);
if (is_first) {
if (tk_str_eq(name, STR_PROP_PARENT)) {
iter = widget->parent;
} else if (tk_str_eq(name, STR_PROP_SELF)) {
iter = widget;
} else if (tk_str_eq(name, STR_PROP_WINDOW)) {
iter = widget_get_window(widget);
} else if (tk_str_eq(name, STR_PROP_WINDOW_MANAGER)) {
iter = widget_get_window_manager(widget);
} else {
iter = widget_child(iter, name);
}
is_first = FALSE;
} else {
iter = widget_child(iter, name);
}
}
tokenizer_deinit(t);
return iter;
}

View File

@ -3390,6 +3390,8 @@ ret_t widget_draw_image_with_region(widget_t* widget, canvas_t* c, bitmap_t* img
const char* region, const rect_t* dst,
image_draw_type_t draw_type);
widget_t* widget_find_by_path(widget_t* widget, const char* path, bool_t recursive);
END_C_DECLS
#endif /*TK_WIDGET_H*/

View File

@ -31,54 +31,6 @@
#include "file_browser/file_dialog.h"
#include "ui_loader/ui_builder_default.h"
static widget_t* find_target_widget(widget_t* widget, const char* path, uint32_t len,
bool_t recursive) {
bool_t is_first = TRUE;
tokenizer_t tokenizer;
widget_t* iter = widget;
tokenizer_t* t = NULL;
return_value_if_fail(widget != NULL && path != NULL, NULL);
if (strchr(path, '.') == NULL) {
const char* name = path;
if (tk_str_eq(name, STR_PROP_PARENT)) {
return widget->parent;
} else if (tk_str_eq(name, STR_PROP_SELF)) {
return widget;
} else if (tk_str_eq(name, STR_PROP_WINDOW)) {
return widget_get_window(widget);
} else if (tk_str_eq(name, STR_PROP_WINDOW_MANAGER)) {
return widget_get_window_manager(widget);
} else {
return widget_lookup(widget, name, recursive);
}
}
t = tokenizer_init(&tokenizer, path, len, ".");
return_value_if_fail(t != NULL, NULL);
while (tokenizer_has_more(t) && iter != NULL) {
const char* name = tokenizer_next(t);
if (is_first) {
if (tk_str_eq(name, STR_PROP_PARENT)) {
iter = widget->parent;
} else if (tk_str_eq(name, STR_PROP_SELF)) {
iter = widget;
} else if (tk_str_eq(name, STR_PROP_WINDOW)) {
iter = widget_get_window(widget);
} else if (tk_str_eq(name, STR_PROP_WINDOW_MANAGER)) {
iter = widget_get_window_manager(widget);
} else {
iter = widget_child(iter, name);
}
is_first = FALSE;
} else {
iter = widget_child(iter, name);
}
}
tokenizer_deinit(t);
return iter;
}
static widget_t* to_widget(fscript_t* fscript, const value_t* v) {
widget_t* widget = NULL;
if (v->type == VALUE_TYPE_STRING) {
@ -86,9 +38,9 @@ static widget_t* to_widget(fscript_t* fscript, const value_t* v) {
const char* path = value_str(v);
return_value_if_fail(path != NULL, NULL);
widget = find_target_widget(self, path, strlen(path), TRUE);
widget = widget_find_by_path(self, path, TRUE);
if (widget == NULL) {
widget = find_target_widget(widget_get_window(self), path, strlen(path), TRUE);
widget = widget_find_by_path(widget_get_window(self), path, TRUE);
}
return widget;
@ -189,7 +141,10 @@ static ret_t widget_set(widget_t* self, const char* path, const value_t* v) {
widget_t* widget = self;
const char* prop = strrchr(path, '.');
if (prop != NULL) {
widget = find_target_widget(self, path, prop - path, TRUE);
char name[MAX_PATH+1] = {0};
int32_t len = tk_min_int(prop - path, MAX_PATH);
tk_strncpy(name, path, len);
widget = widget_find_by_path(self, name, TRUE);
prop++;
} else {
prop = path;
@ -204,7 +159,10 @@ static ret_t widget_get(widget_t* self, const char* path, value_t* v) {
widget_t* widget = self;
const char* prop = strrchr(path, '.');
if (prop != NULL) {
widget = find_target_widget(self, path, prop - path, TRUE);
char name[MAX_PATH+1] = {0};
int32_t len = tk_min_int(prop - path, MAX_PATH);
tk_strncpy(name, path, len);
widget = widget_find_by_path(self, name, TRUE);
prop++;
} else {
prop = path;
@ -286,7 +244,7 @@ static ret_t func_widget_lookup(fscript_t* fscript, fscript_args_t* args, value_
}
FSCRIPT_FUNC_CHECK(widget != NULL && path != NULL, RET_BAD_PARAMS);
widget = find_target_widget(widget, path, strlen(path), recursive);
widget = widget_find_by_path(widget, path, recursive);
if (widget == NULL) {
result->type = VALUE_TYPE_INVALID;
return RET_NOT_FOUND;

2
src/remote_ui/README.md Normal file
View File

@ -0,0 +1,2 @@
# 自动化测试框架

View File

@ -0,0 +1,609 @@
/**
* File: remote_ui.c
* Author: AWTK Develop Team
* Brief: remote ui client
*
* Copyright (c) 2018 - 2023 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2023-11-04 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "tkc/fs.h"
#include "tkc/mem.h"
#include "tkc/crc.h"
#include "tkc/utils.h"
#include "base/keys.h"
#include "base/events.h"
#include "conf_io/conf_ubjson.h"
#include "tkc/object_default.h"
#include "remote_ui/client/remote_ui.h"
#include "remote_ui/shared/remote_ui_types_def.h"
#define REMOTE_UI_ISTREAM_TIMEOUT 100 * 1000
remote_ui_t* remote_ui_create(tk_iostream_t* io) {
remote_ui_t* ui = NULL;
return_value_if_fail(io != NULL, NULL);
ui = (remote_ui_t*)TKMEM_ZALLOC(remote_ui_t);
return_value_if_fail(ui != NULL, NULL);
ui->io = io;
ui->event_handlers = object_default_create_ex(FALSE);
wbuffer_init_extendable(&(ui->wb));
return ui;
}
static ret_t remote_ui_send_req(tk_iostream_t* io, uint32_t type, uint32_t data_type,
wbuffer_t* wb) {
int32_t ret = 0;
const void* data = NULL;
uint32_t size = 0;
uint32_t timeout = TK_OSTREAM_DEFAULT_TIMEOUT;
uint16_t crc_value = PPPINITFCS16;
remote_ui_msg_header_t header;
memset(&header, 0x00, sizeof(header));
return_value_if_fail(io != NULL && wb != NULL, RET_BAD_PARAMS);
size = wb->cursor;
data = wb->data;
if (size > 0) {
return_value_if_fail(data != NULL, RET_BAD_PARAMS);
}
header.type = type;
header.size = size;
header.data_type = data_type;
crc_value = tk_crc16(crc_value, &header, sizeof(header));
if (data != NULL && size > 0) {
crc_value = tk_crc16(crc_value, data, size);
}
ret = tk_iostream_write_len(io, &header, sizeof(header), timeout);
return_value_if_fail(ret == sizeof(header), RET_IO);
if (size > 0) {
timeout = TK_OSTREAM_DEFAULT_TIMEOUT * (size / 10240) + TK_OSTREAM_DEFAULT_TIMEOUT;
ret = tk_iostream_write_len(io, data, size, timeout);
return_value_if_fail(ret == size, RET_IO);
}
ret = tk_iostream_write_len(io, &crc_value, sizeof(crc_value), TK_OSTREAM_DEFAULT_TIMEOUT);
return_value_if_fail(ret == sizeof(crc_value), RET_IO);
return RET_OK;
}
static ret_t remote_ui_read_resp(tk_iostream_t* io, remote_ui_msg_header_t* header, wbuffer_t* wb) {
int32_t ret = 0;
uint16_t crc_value = 0;
uint16_t real_crc_value = PPPINITFCS16;
return_value_if_fail(io != NULL && header != NULL && wb != NULL, RET_BAD_PARAMS);
wbuffer_rewind(wb);
ret = tk_iostream_read_len(io, header, sizeof(*header), REMOTE_UI_ISTREAM_TIMEOUT);
return_value_if_fail(ret == sizeof(*header), RET_IO);
real_crc_value = tk_crc16(real_crc_value, header, sizeof(*header));
if (header->size > 0) {
return_value_if_fail(wbuffer_extend_capacity(wb, header->size) == RET_OK, RET_OOM);
ret = tk_iostream_read_len(io, wb->data, header->size, REMOTE_UI_ISTREAM_TIMEOUT);
return_value_if_fail(ret == header->size, RET_IO);
real_crc_value = tk_crc16(real_crc_value, wb->data, header->size);
}
ret = tk_iostream_read_len(io, &crc_value, sizeof(crc_value), REMOTE_UI_ISTREAM_TIMEOUT);
return_value_if_fail(ret == sizeof(crc_value), RET_IO);
return_value_if_fail(real_crc_value == crc_value, RET_CRC);
wb->cursor = header->size;
return header->resp_code;
}
static ret_t remote_ui_request(tk_iostream_t* io, uint32_t type, uint32_t data_type,
wbuffer_t* wb) {
ret_t ret = remote_ui_send_req(io, type, data_type, wb);
if (ret == RET_OK) {
remote_ui_msg_header_t header;
memset(&header, 0x00, sizeof(header));
ret = remote_ui_read_resp(io, &header, wb);
}
return ret;
}
static ubjson_writer_t* remote_ui_client_get_writer(remote_ui_t* ui) {
wbuffer_t* wb = &(ui->wb);
ubjson_writer_t* writer = &(ui->writer);
wb->cursor = 0;
return ubjson_writer_init(writer, (ubjson_write_callback_t)wbuffer_write_binary, wb);
}
ret_t remote_ui_login(remote_ui_t* ui, const char* username, const char* password) {
ubjson_writer_t* writer = NULL;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(username != NULL, RET_BAD_PARAMS);
return_value_if_fail(password != NULL, RET_BAD_PARAMS);
writer = remote_ui_client_get_writer(ui);
ubjson_writer_write_object_begin(writer);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_USERNAME, username);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_PASSWORD, password);
ubjson_writer_write_object_end(writer);
return remote_ui_request(ui->io, REMOTE_UI_REQ_LOGIN, REMOTE_UI_DATA_TYPE_UBJSON, &(ui->wb));
}
ret_t remote_ui_logout(remote_ui_t* ui) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
wbuffer_rewind(&(ui->wb));
return remote_ui_request(ui->io, REMOTE_UI_REQ_LOGOUT, REMOTE_UI_DATA_TYPE_NONE, &(ui->wb));
}
ret_t remote_ui_get_dev_info(remote_ui_t* ui, remote_ui_dev_info_t* info) {
ret_t ret = RET_FAIL;
wbuffer_t* wb = NULL;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(info != NULL, RET_BAD_PARAMS);
wb = &(ui->wb);
wbuffer_rewind(wb);
memset(info, 0x00, sizeof(*info));
ret = remote_ui_request(ui->io, REMOTE_UI_REQ_GET_DEV_INFO, REMOTE_UI_DATA_TYPE_UBJSON, wb);
if (ret == RET_OK) {
tk_object_t* obj = conf_ubjson_load_from_buff(wb->data, wb->cursor, FALSE);
if (obj != NULL) {
const char* p = NULL;
p = tk_object_get_prop_str(obj, REMOTE_UI_KEY_DEV_NAME);
if (p != NULL) {
tk_strncpy(info->name, p, sizeof(info->name) - 1);
}
p = tk_object_get_prop_str(obj, REMOTE_UI_KEY_DEV_VERSION);
if (p != NULL) {
tk_strncpy(info->version, p, sizeof(info->version) - 1);
}
p = tk_object_get_prop_str(obj, REMOTE_UI_KEY_DEV_OS);
if (p != NULL) {
tk_strncpy(info->os, p, sizeof(info->os) - 1);
}
p = tk_object_get_prop_str(obj, REMOTE_UI_KEY_DEV_ARCH);
if (p != NULL) {
tk_strncpy(info->arch, p, sizeof(info->arch) - 1);
}
info->screen_width = tk_object_get_prop_int(obj, REMOTE_UI_KEY_DEV_SCREEN_WIDTH, 0);
info->screen_height = tk_object_get_prop_int(obj, REMOTE_UI_KEY_DEV_SCREEN_HEIGHT, 0);
info->dpi = tk_object_get_prop_int(obj, REMOTE_UI_KEY_DEV_DPI, 0);
TK_OBJECT_UNREF(obj);
}
}
return ret;
}
ret_t remote_ui_reboot(remote_ui_t* ui, remote_ui_reboot_type_t reboot_type) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
wbuffer_rewind(&(ui->wb));
wbuffer_write_int32(&(ui->wb), reboot_type);
return remote_ui_request(ui->io, REMOTE_UI_REQ_REBOOT, REMOTE_UI_DATA_TYPE_NONE, &(ui->wb));
}
ret_t remote_ui_upload_file(remote_ui_t* ui, const char* remote_file, const char* local_file) {
wbuffer_t wb;
int32_t len = 0;
ret_t ret = RET_OK;
fs_file_t* file = NULL;
uint8_t buff[4096] = {0};
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(remote_file != NULL, RET_BAD_PARAMS);
return_value_if_fail(local_file != NULL, RET_BAD_PARAMS);
file = fs_open_file(os_fs(), local_file, "rb");
return_value_if_fail(file != NULL, RET_BAD_PARAMS);
wbuffer_init(&wb, (void*)remote_file, strlen(remote_file) + 1);
wb.cursor = wb.capacity;
ret = remote_ui_request(ui->io, REMOTE_UI_REQ_UPLOAD_FILE_BEGIN, REMOTE_UI_DATA_TYPE_STRING, &wb);
goto_error_if_fail(ret == RET_OK);
while ((len = fs_file_read(file, buff, sizeof(buff))) > 0) {
wbuffer_init(&wb, buff, len);
wb.cursor = len;
ret =
remote_ui_request(ui->io, REMOTE_UI_REQ_UPLOAD_FILE_DATA, REMOTE_UI_DATA_TYPE_BINARY, &wb);
break_if_fail(ret == RET_OK);
}
wbuffer_rewind(&wb);
ret = remote_ui_request(ui->io, REMOTE_UI_REQ_UPLOAD_FILE_END, REMOTE_UI_DATA_TYPE_NONE, &wb);
fs_file_close(file);
return ret;
error:
fs_file_close(file);
return RET_FAIL;
}
ret_t remote_ui_download_file(remote_ui_t* ui, const char* remote_file, const char* local_file) {
int32_t len = 0;
ret_t ret = RET_OK;
fs_file_t* file = NULL;
wbuffer_t* wb = NULL;
remote_ui_msg_header_t header;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(remote_file != NULL, RET_BAD_PARAMS);
return_value_if_fail(local_file != NULL, RET_BAD_PARAMS);
file = fs_open_file(os_fs(), local_file, "wb+");
return_value_if_fail(file != NULL, RET_BAD_PARAMS);
wb = &(ui->wb);
wbuffer_rewind(wb);
wbuffer_write_string(wb, remote_file);
ret =
remote_ui_request(ui->io, REMOTE_UI_REQ_DOWNLOAD_FILE_BEGIN, REMOTE_UI_DATA_TYPE_STRING, wb);
goto_error_if_fail(ret == RET_OK);
memset(&header, 0x00, sizeof(header));
while ((ret = remote_ui_read_resp(ui->io, &header, wb)) == RET_OK) {
if (header.type == REMOTE_UI_RESP_DOWNLOAD_FILE_DATA) {
len = fs_file_write(file, wb->data, wb->cursor);
break_if_fail(len == wb->cursor);
} else if (header.type == REMOTE_UI_RESP_DOWNLOAD_FILE_END) {
ret = RET_OK;
break;
} else {
assert(!"impossible");
ret = RET_FAIL;
break;
}
}
fs_file_close(file);
return ret;
error:
fs_file_close(file);
return ret;
}
ret_t remote_ui_create_dir(remote_ui_t* ui, const char* remote_dir) {
ret_t ret = RET_OK;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(remote_dir != NULL, RET_BAD_PARAMS);
wbuffer_rewind(&(ui->wb));
wbuffer_write_string(&(ui->wb), remote_dir);
ret = remote_ui_request(ui->io, REMOTE_UI_REQ_CREATE_DIR, REMOTE_UI_DATA_TYPE_STRING, &(ui->wb));
return ret;
}
ret_t remote_ui_remove_dir(remote_ui_t* ui, const char* remote_dir) {
ret_t ret = RET_OK;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(remote_dir != NULL, RET_BAD_PARAMS);
wbuffer_rewind(&(ui->wb));
wbuffer_write_string(&(ui->wb), remote_dir);
ret = remote_ui_request(ui->io, REMOTE_UI_REQ_REMOVE_DIR, REMOTE_UI_DATA_TYPE_STRING, &(ui->wb));
return ret;
}
ret_t remote_ui_remove_file(remote_ui_t* ui, const char* remote_file) {
ret_t ret = RET_OK;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(remote_file != NULL, RET_BAD_PARAMS);
wbuffer_rewind(&(ui->wb));
wbuffer_write_string(&(ui->wb), remote_file);
ret = remote_ui_request(ui->io, REMOTE_UI_REQ_REMOVE_FILE, REMOTE_UI_DATA_TYPE_STRING, &(ui->wb));
return ret;
}
ret_t remote_ui_take_screen_shot(remote_ui_t* ui, const char* file) {
return remote_ui_download_file(ui, REMOTE_UI_FILE_SCREEN_SHOT, file);
}
ret_t remote_ui_get_manifest(remote_ui_t* ui, const char* file) {
return remote_ui_download_file(ui, REMOTE_UI_FILE_MANIFEST, file);
}
ret_t remote_ui_get_xml_source(remote_ui_t* ui, const char* file) {
return remote_ui_download_file(ui, REMOTE_UI_FILE_XML_SOURCE, file);
}
ret_t remote_ui_on_event(remote_ui_t* ui, const char* target, uint32_t event, event_func_t func,
void* ctx) {
emitter_t* emitter = NULL;
ubjson_writer_t* writer = NULL;
return_value_if_fail(ui != NULL && ui->event_handlers != NULL, RET_BAD_PARAMS);
return_value_if_fail(target != NULL, RET_BAD_PARAMS);
return_value_if_fail(func != NULL, RET_BAD_PARAMS);
emitter = tk_object_get_prop_pointer(ui->event_handlers, target);
if (emitter == NULL) {
emitter = emitter_create();
return_value_if_fail(emitter != NULL, RET_OOM);
tk_object_set_prop_pointer_ex(ui->event_handlers, target, emitter,
(tk_destroy_t)emitter_destroy);
}
emitter_on(emitter, event, func, ctx);
writer = remote_ui_client_get_writer(ui);
ubjson_writer_write_object_begin(writer);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_TARGET, target);
ubjson_writer_write_kv_int(writer, REMOTE_UI_KEY_EVENT, event);
ubjson_writer_write_object_end(writer);
return remote_ui_request(ui->io, REMOTE_UI_REQ_ON_EVENT, REMOTE_UI_DATA_TYPE_UBJSON, &(ui->wb));
}
ret_t remote_ui_off_event(remote_ui_t* ui, const char* target, uint32_t event) {
emitter_t* emitter = NULL;
ubjson_writer_t* writer = NULL;
return_value_if_fail(ui != NULL && ui->event_handlers != NULL, RET_BAD_PARAMS);
return_value_if_fail(target != NULL, RET_BAD_PARAMS);
emitter = tk_object_get_prop_pointer(ui->event_handlers, target);
if (emitter != NULL) {
emitter_off(emitter, event);
}
writer = remote_ui_client_get_writer(ui);
ubjson_writer_write_object_begin(writer);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_TARGET, target);
ubjson_writer_write_kv_int(writer, REMOTE_UI_KEY_EVENT, event);
ubjson_writer_write_object_end(writer);
return remote_ui_request(ui->io, REMOTE_UI_REQ_OFF_EVENT, REMOTE_UI_DATA_TYPE_UBJSON, &(ui->wb));
}
ret_t remote_ui_send_event(remote_ui_t* ui, const char* target, event_t* event) {
ubjson_writer_t* writer = NULL;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(target != NULL, RET_BAD_PARAMS);
return_value_if_fail(event != NULL, RET_BAD_PARAMS);
writer = remote_ui_client_get_writer(ui);
ubjson_writer_write_object_begin(writer);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_TARGET, target);
ubjson_writer_write_kv_int(writer, REMOTE_UI_KEY_EVENT, event->type);
switch (event->type) {
case EVT_CLICK:
case EVT_POINTER_DOWN:
case EVT_POINTER_UP:
case EVT_POINTER_MOVE: {
pointer_event_t* e = (pointer_event_t*)event;
ubjson_writer_write_kv_int(writer, REMOTE_UI_KEY_X, e->x);
ubjson_writer_write_kv_int(writer, REMOTE_UI_KEY_Y, e->y);
break;
}
case EVT_KEY_DOWN:
case EVT_KEY_UP: {
key_event_t* e = (key_event_t*)event;
ubjson_writer_write_kv_int(writer, REMOTE_UI_KEY_CODE, e->key);
break;
}
default: {
log_debug("not supported event type:%d\n", event->type);
return RET_NOT_IMPL;
}
}
ubjson_writer_write_object_end(writer);
return remote_ui_request(ui->io, REMOTE_UI_REQ_SEND_EVENT, REMOTE_UI_DATA_TYPE_UBJSON, &(ui->wb));
}
ret_t remote_ui_open_window(remote_ui_t* ui, const char* name, const char* xml,
const char* init_json) {
ubjson_writer_t* writer = NULL;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(name != NULL, RET_BAD_PARAMS);
writer = remote_ui_client_get_writer(ui);
ubjson_writer_write_object_begin(writer);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_NAME, name);
if (xml != NULL) {
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_XML, xml);
}
if (init_json != NULL) {
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_INIT, init_json);
}
ubjson_writer_write_object_end(writer);
return remote_ui_request(ui->io, REMOTE_UI_REQ_OPEN_WINDOW, REMOTE_UI_DATA_TYPE_UBJSON,
&(ui->wb));
}
static ret_t remote_ui_show_dialog(remote_ui_t* ui, const char* type, const char* title,
const char* content, uint32_t duration) {
ubjson_writer_t* writer = NULL;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(type != NULL, RET_BAD_PARAMS);
writer = remote_ui_client_get_writer(ui);
ubjson_writer_write_object_begin(writer);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_TYPE, type);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_TITLE, title);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_CONTENT, content);
ubjson_writer_write_kv_int(writer, REMOTE_UI_KEY_DURATION, duration);
ubjson_writer_write_object_end(writer);
return remote_ui_request(ui->io, REMOTE_UI_REQ_OPEN_DIALOG, REMOTE_UI_DATA_TYPE_UBJSON,
&(ui->wb));
}
ret_t remote_ui_show_confirm(remote_ui_t* ui, const char* title, const char* content) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(title != NULL, RET_BAD_PARAMS);
return_value_if_fail(content != NULL, RET_BAD_PARAMS);
return remote_ui_show_dialog(ui, REMOTE_UI_DIALOG_TYPE_CONFIRM, title, content, 0);
}
ret_t remote_ui_show_warn(remote_ui_t* ui, const char* title, const char* content) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(title != NULL, RET_BAD_PARAMS);
return_value_if_fail(content != NULL, RET_BAD_PARAMS);
return remote_ui_show_dialog(ui, REMOTE_UI_DIALOG_TYPE_WARN, title, content, 0);
}
ret_t remote_ui_show_info(remote_ui_t* ui, const char* title, const char* content) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(title != NULL, RET_BAD_PARAMS);
return_value_if_fail(content != NULL, RET_BAD_PARAMS);
return remote_ui_show_dialog(ui, NULL, title, content, 0);
}
ret_t remote_ui_show_toast(remote_ui_t* ui, uint32_t duration, const char* content) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(content != NULL, RET_BAD_PARAMS);
return remote_ui_show_dialog(ui, REMOTE_UI_DIALOG_TYPE_TOAST, "", content, duration);
}
ret_t remote_ui_close_window(remote_ui_t* ui, const char* name) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(name != NULL, RET_BAD_PARAMS);
wbuffer_rewind(&(ui->wb));
wbuffer_write_string(&(ui->wb), name);
return remote_ui_request(ui->io, REMOTE_UI_REQ_CLOSE_WINDOW, REMOTE_UI_DATA_TYPE_STRING,
&(ui->wb));
}
ret_t remote_ui_back_to_prev(remote_ui_t* ui) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
wbuffer_rewind(&(ui->wb));
return remote_ui_request(ui->io, REMOTE_UI_REQ_BACK_TO_PREV, REMOTE_UI_DATA_TYPE_NONE, &(ui->wb));
}
ret_t remote_ui_back_to_home(remote_ui_t* ui) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
wbuffer_rewind(&(ui->wb));
return remote_ui_request(ui->io, REMOTE_UI_REQ_BACK_TO_HOME, REMOTE_UI_DATA_TYPE_NONE, &(ui->wb));
}
ret_t remote_ui_set_prop(remote_ui_t* ui, const char* target, const char* name,
const value_t* value) {
ubjson_writer_t* writer = NULL;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(target != NULL, RET_BAD_PARAMS);
return_value_if_fail(name != NULL, RET_BAD_PARAMS);
return_value_if_fail(value != NULL, RET_BAD_PARAMS);
writer = remote_ui_client_get_writer(ui);
ubjson_writer_write_object_begin(writer);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_TARGET, target);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_NAME, name);
ubjson_writer_write_kv_value(writer, REMOTE_UI_KEY_VALUE, value);
ubjson_writer_write_object_end(writer);
return remote_ui_request(ui->io, REMOTE_UI_REQ_SET_PROP, REMOTE_UI_DATA_TYPE_UBJSON, &(ui->wb));
}
ret_t remote_ui_get_prop(remote_ui_t* ui, const char* target, const char* name, value_t* value) {
ret_t ret = RET_OK;
ubjson_writer_t* writer = NULL;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(target != NULL, RET_BAD_PARAMS);
return_value_if_fail(name != NULL, RET_BAD_PARAMS);
return_value_if_fail(value != NULL, RET_BAD_PARAMS);
writer = remote_ui_client_get_writer(ui);
ubjson_writer_write_object_begin(writer);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_TARGET, target);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_NAME, name);
ubjson_writer_write_kv_value(writer, REMOTE_UI_KEY_VALUE, value);
ubjson_writer_write_object_end(writer);
ret = remote_ui_request(ui->io, REMOTE_UI_REQ_GET_PROP, REMOTE_UI_DATA_TYPE_UBJSON, &(ui->wb));
return_value_if_fail(ret == RET_OK, ret);
value_dup_str_with_len(value, (char*)(ui->wb.data), ui->wb.cursor);
return RET_OK;
}
ret_t remote_ui_set_theme(remote_ui_t* ui, const char* theme) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(theme != NULL, RET_BAD_PARAMS);
wbuffer_rewind(&(ui->wb));
wbuffer_write_string(&(ui->wb), theme);
return remote_ui_request(ui->io, REMOTE_UI_REQ_SET_THEME, REMOTE_UI_DATA_TYPE_STRING, &(ui->wb));
}
ret_t remote_ui_set_language(remote_ui_t* ui, const char* language) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(language != NULL, RET_BAD_PARAMS);
wbuffer_rewind(&(ui->wb));
wbuffer_write_string(&(ui->wb), language);
return remote_ui_request(ui->io, REMOTE_UI_REQ_SET_LANGUAGE, REMOTE_UI_DATA_TYPE_STRING,
&(ui->wb));
}
ret_t remote_ui_exec_fscript(remote_ui_t* ui, const char* script, str_t* str) {
ret_t ret = RET_OK;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(script != NULL, RET_BAD_PARAMS);
wbuffer_rewind(&(ui->wb));
wbuffer_write_string(&(ui->wb), script);
ret =
remote_ui_request(ui->io, REMOTE_UI_REQ_EXEC_FSCRIPT, REMOTE_UI_DATA_TYPE_STRING, &(ui->wb));
if (ret == RET_OK) {
str_set_with_len(str, (char*)(ui->wb.data), ui->wb.cursor);
}
return ret;
}
ret_t remote_ui_dispatch(remote_ui_t* ui) {
/*TODO*/
return RET_OK;
}
ret_t remote_ui_destroy(remote_ui_t* ui) {
return_value_if_fail(ui != NULL, RET_BAD_PARAMS);
TK_OBJECT_UNREF(ui->io);
TK_OBJECT_UNREF(ui->event_handlers);
wbuffer_deinit(&(ui->wb));
TKMEM_FREE(ui);
return RET_OK;
}

View File

@ -0,0 +1,398 @@
/**
* File: remote_ui.h
* Author: AWTK Develop Team
* Brief: remote ui client
*
* Copyright (c) 2018 - 2023 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2023-11-04 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_REMOTE_UI_H
#define TK_REMOTE_UI_H
#include "tkc/buffer.h"
#include "tkc/darray.h"
#include "tkc/iostream.h"
#include "ubjson/ubjson_writer.h"
#include "remote_ui/shared/remote_ui_types_def.h"
BEGIN_C_DECLS
/**
* @class remote_ui_t
* remote ui客户端
*/
typedef struct _remote_ui_t {
/**
* @property {tk_iostream_t*} io
* @annotation ["readable"]
* IO stream
*/
tk_iostream_t* io;
/*private*/
wbuffer_t wb;
ubjson_writer_t writer;
tk_object_t* event_handlers;
} remote_ui_t;
/**
* @method remote_ui_create
* remote ui客户端
*
* @param {tk_iostream_t*} io IO流
*
* @return {remote_ui_t*} remote ui客户端对象
*/
remote_ui_t* remote_ui_create(tk_iostream_t* io);
/**
* @method remote_ui_login
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} username
* @param {const char*} password
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_login(remote_ui_t* ui, const char* username, const char* password);
/**
* @method remote_ui_logout
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_logout(remote_ui_t* ui);
/**
* @method remote_ui_get_dev_info
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {remote_ui_dev_info_t*} info
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_get_dev_info(remote_ui_t* ui, remote_ui_dev_info_t* info);
/**
* @method remote_ui_reboot
* @param {remote_ui_t*} ui remote ui客户端对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_reboot(remote_ui_t* ui, remote_ui_reboot_type_t type);
/**
* @method remote_ui_upload_file
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} remote_file
* @param {const char*} local_file
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_upload_file(remote_ui_t* ui, const char* remote_file, const char* local_file);
/**
* @method remote_ui_download_file
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} remote_file
* @param {const char*} local_file
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_download_file(remote_ui_t* ui, const char* remote_file, const char* local_file);
/**
* @method remote_ui_create_dir
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} remote_dir
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_create_dir(remote_ui_t* ui, const char* remote_dir);
/**
* @method remote_ui_remove_dir
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} remote_dir
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_remove_dir(remote_ui_t* ui, const char* remote_dir);
/**
* @method remote_ui_remove_file
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} remote_file
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_remove_file(remote_ui_t* ui, const char* remote_file);
/**
* @method remote_ui_take_screen_shot
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} file
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_take_screen_shot(remote_ui_t* ui, const char* file);
/**
* @method remote_ui_get_manifest
* manifest
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} file
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_get_manifest(remote_ui_t* ui, const char* file);
/**
* @method remote_ui_get_xml_source
* XML源码
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} file
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_get_xml_source(remote_ui_t* ui, const char* file);
/**
* @method remote_ui_on_event
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} target
* @param {uint32_t} event
* @param {event_func_t} func
* @param {void*} ctx
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_on_event(remote_ui_t* ui, const char* target, uint32_t event, event_func_t func,
void* ctx);
/**
* @method remote_ui_off_event
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} target
* @param {uint32_t} event
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_off_event(remote_ui_t* ui, const char* target, uint32_t event);
/**
* @method remote_ui_send_event
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} target
* @param {event_t*} event
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_send_event(remote_ui_t* ui, const char* target, event_t* event);
/**
* @method remote_ui_open_window
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} name
* @param {const char*} xml XML
* @param {const char*} init_json JSON
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_open_window(remote_ui_t* ui, const char* name, const char* xml,
const char* init_json);
/**
* @method remote_ui_show_confirm
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} title
* @param {const char*} content
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_show_confirm(remote_ui_t* ui, const char* title,
const char* content);
/**
* @method remote_ui_show_warn
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} title
* @param {const char*} content
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_show_warn(remote_ui_t* ui, const char* title,
const char* content);
/**
* @method remote_ui_show_info
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} title
* @param {const char*} content
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_show_info(remote_ui_t* ui, const char* title,
const char* content);
/**
* @method remote_ui_show_toast
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {uint32_t} duration
* @param {const char*} content
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_show_toast(remote_ui_t* ui, uint32_t duration,
const char* content);
/**
* @method remote_ui_close_window
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} name
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_close_window(remote_ui_t* ui, const char* name);
/**
* @method remote_ui_back_to_prev
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_back_to_prev(remote_ui_t* ui);
/**
* @method remote_ui_back_to_home
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_back_to_home(remote_ui_t* ui);
/**
* @method remote_ui_set_prop
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} target
* @param {const char*} name
* @param {const value_t*} value
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_set_prop(remote_ui_t* ui, const char* target, const char* name,
const value_t* value);
/**
* @method remote_ui_get_prop
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} target
* @param {const char*} name
* @param {value_t*} value
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_get_prop(remote_ui_t* ui, const char* target, const char* name, value_t* value);
/**
* @method remote_ui_set_theme
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} theme
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_set_theme(remote_ui_t* ui, const char* theme);
/**
* @method remote_ui_set_language
*
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} language
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_set_language(remote_ui_t* ui, const char* language);
/**
* @method remote_ui_exec_fscript
* fscript脚本
* @param {remote_ui_t*} ui remote ui客户端对象
* @param {const char*} script
* @param {str_t*} result
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_exec_fscript(remote_ui_t* ui, const char* script, str_t* result);
/**
* @method remote_ui_dispatch
*
*
* @param {remote_ui_t*} ui remote ui客户端对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_dispatch(remote_ui_t* ui);
/**
* @method remote_ui_destroy
* remote ui客户端
*
* @param {remote_ui_t*} ui remote ui客户端对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t remote_ui_destroy(remote_ui_t* ui);
END_C_DECLS
#endif /*TK_REMOTE_UI_H*/

View File

@ -0,0 +1,816 @@
/**
* File: remote_ui_service.c
* Author: AWTK Develop Team
* Brief: remote ui service
*
* Copyright (c) 2018 - 2023 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2023-11-04 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "tkc/fs.h"
#include "tkc/mem.h"
#include "tkc/crc.h"
#include "tkc/path.h"
#include "tkc/utils.h"
#include "tkc/fscript.h"
#include "base/bitmap.h"
#include "base/window.h"
#include "base/window_manager.h"
#include "base/ui_loader.h"
#include "base/dialog.h"
#include "conf_io/conf_ubjson.h"
#include "tkc/object_default.h"
#include "ui_loader/ui_serializer.h"
#include "remote_ui/shared/remote_ui_types_def.h"
#include "remote_ui/service/remote_ui_service.h"
#include "base/events.h"
#include "base/keys.h"
static ret_t remote_ui_service_dispatch(remote_ui_service_t* ui);
static ret_t remote_ui_service_destroy(remote_ui_service_t* ui);
tk_service_t* remote_ui_service_create(tk_iostream_t* io, void* args) {
remote_ui_service_t* ui = NULL;
remote_ui_service_args_t* service_args = (remote_ui_service_args_t*)args;
return_value_if_fail(io != NULL, NULL);
ui = (remote_ui_service_t*)TKMEM_ZALLOC(remote_ui_service_t);
return_value_if_fail(ui != NULL, NULL);
ui->io = io;
ui->service.dispatch = (tk_service_dispatch_t)remote_ui_service_dispatch;
ui->service.destroy = (tk_service_destroy_t)remote_ui_service_destroy;
wbuffer_init_extendable(&(ui->wb));
if (service_args != NULL && service_args->auth != NULL) {
ui->auth = service_args->auth;
}
return (tk_service_t*)ui;
}
static ret_t remote_ui_service_send_resp(tk_iostream_t* io, uint32_t type, uint32_t data_type,
uint32_t resp_code, wbuffer_t* wb) {
int32_t ret = 0;
uint32_t size = 0;
const void* data = NULL;
remote_ui_msg_header_t header;
uint16_t crc_value = PPPINITFCS16;
uint32_t timeout = TK_OSTREAM_DEFAULT_TIMEOUT;
memset(&header, 0x00, sizeof(header));
return_value_if_fail(io != NULL && wb != NULL, RET_BAD_PARAMS);
data = wb->data;
size = wb->cursor;
if (size > 0) {
return_value_if_fail(data != NULL, RET_BAD_PARAMS);
}
header.type = type;
header.size = size;
header.data_type = data_type;
header.resp_code = resp_code;
crc_value = tk_crc16(crc_value, &header, sizeof(header));
if (data != NULL && size > 0) {
crc_value = tk_crc16(crc_value, data, size);
}
ret = tk_iostream_write_len(io, &header, sizeof(header), timeout);
return_value_if_fail(ret == sizeof(header), RET_IO);
if (size > 0) {
timeout = TK_OSTREAM_DEFAULT_TIMEOUT * (size / 10240) + TK_OSTREAM_DEFAULT_TIMEOUT;
ret = tk_iostream_write_len(io, data, size, timeout);
return_value_if_fail(ret == size, RET_IO);
}
ret = tk_iostream_write_len(io, &crc_value, sizeof(crc_value), TK_OSTREAM_DEFAULT_TIMEOUT);
return_value_if_fail(ret == sizeof(crc_value), RET_IO);
return RET_OK;
}
static ret_t remote_ui_service_read_req(tk_iostream_t* io, remote_ui_msg_header_t* header,
wbuffer_t* wb) {
int32_t ret = 0;
uint16_t crc_value = 0;
uint16_t real_crc_value = PPPINITFCS16;
return_value_if_fail(io != NULL && header != NULL && wb != NULL, RET_BAD_PARAMS);
wbuffer_rewind(wb);
ret = tk_iostream_read_len(io, header, sizeof(*header), TK_ISTREAM_DEFAULT_TIMEOUT);
if (ret == 0) {
return RET_IO;
}
return_value_if_fail(ret == sizeof(*header), RET_IO);
real_crc_value = tk_crc16(real_crc_value, header, sizeof(*header));
if (header->size > 0) {
return_value_if_fail(wbuffer_extend_capacity(wb, header->size) == RET_OK, RET_OOM);
ret = tk_iostream_read_len(io, wb->data, header->size, TK_ISTREAM_DEFAULT_TIMEOUT);
return_value_if_fail(ret == header->size, RET_IO);
real_crc_value = tk_crc16(real_crc_value, wb->data, header->size);
}
ret = tk_iostream_read_len(io, &crc_value, sizeof(crc_value), TK_ISTREAM_DEFAULT_TIMEOUT);
return_value_if_fail(ret == sizeof(crc_value), RET_IO);
return_value_if_fail(crc_value == real_crc_value, RET_CRC);
wb->cursor = header->size;
return header->resp_code;
}
static ubjson_writer_t* remote_ui_service_get_writer(remote_ui_service_t* ui) {
wbuffer_t* wb = &(ui->wb);
ubjson_writer_t* writer = &(ui->writer);
wb->cursor = 0;
return ubjson_writer_init(writer, (ubjson_write_callback_t)wbuffer_write_binary, wb);
}
static ret_t remote_ui_service_login(remote_ui_service_t* ui, const char* username, const char* password) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
if (ui->auth != NULL) {
if (ui->auth((tk_service_t*)ui, username, password) == RET_OK) {
ui->is_login = TRUE;
return RET_OK;
} else {
return RET_FAIL;
}
} else {
return RET_OK;
}
}
static ret_t remote_ui_service_logout(remote_ui_service_t* ui) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
ui->is_login = FALSE;
return RET_OK;
}
static ret_t remote_ui_service_get_dev_info(remote_ui_service_t* ui, remote_ui_dev_info_t* info) {
ret_t ret = RET_OK;
widget_t* wm = window_manager();
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(info != NULL, RET_BAD_PARAMS);
memset(info, 0x00, sizeof(*info));
info->screen_width = wm->w;
info->screen_height = wm->h;
/*TODO*/
return ret;
}
static ret_t remote_ui_service_reboot(remote_ui_service_t* ui, remote_ui_reboot_type_t reboot_type) {
/*TODO*/
return RET_OK;
}
static ret_t remote_ui_service_upload_file(remote_ui_service_t* ui, const char* filename) {
int32_t len = 0;
ret_t ret = RET_OK;
fs_file_t* file = NULL;
wbuffer_t* wb = NULL;
remote_ui_msg_header_t header;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(filename != NULL, RET_BAD_PARAMS);
wb = &(ui->wb);
wbuffer_rewind(wb);
file = fs_open_file(os_fs(), filename, "wb+");
if (file != NULL) {
remote_ui_service_send_resp(ui->io, REMOTE_UI_RESP_UPLOAD_FILE_BEGIN, REMOTE_UI_DATA_TYPE_NONE,
RET_OK, wb);
} else {
remote_ui_service_send_resp(ui->io, REMOTE_UI_RESP_UPLOAD_FILE_BEGIN, REMOTE_UI_DATA_TYPE_NONE,
RET_FAIL, wb);
}
return_value_if_fail(file != NULL, RET_BAD_PARAMS);
memset(&header, 0x00, sizeof(header));
while ((ret = remote_ui_service_read_req(ui->io, &header, wb)) == RET_OK) {
if (header.type == REMOTE_UI_REQ_UPLOAD_FILE_DATA) {
len = fs_file_write(file, wb->data, wb->cursor);
ret = (len == wb->cursor) ? RET_OK : RET_FAIL;
remote_ui_service_send_resp(ui->io, REMOTE_UI_RESP_UPLOAD_FILE_DATA, REMOTE_UI_DATA_TYPE_NONE,
ret, wb);
break_if_fail(ret == RET_OK);
} else if (header.type == REMOTE_UI_REQ_UPLOAD_FILE_END) {
ret = RET_OK;
ret = remote_ui_service_send_resp(ui->io, REMOTE_UI_RESP_UPLOAD_FILE_END,
REMOTE_UI_DATA_TYPE_NONE, ret, wb);
break_if_fail(ret == RET_OK);
break;
} else {
assert(!"impossible");
ret = RET_FAIL;
remote_ui_service_send_resp(ui->io, REMOTE_UI_RESP_UPLOAD_FILE_END, REMOTE_UI_DATA_TYPE_NONE,
ret, wb);
break;
}
}
fs_file_close(file);
return RET_OK;
}
static ret_t remote_ui_service_download_file(remote_ui_service_t* ui, const char* filename) {
wbuffer_t wb;
int32_t len = 0;
ret_t ret = RET_OK;
fs_file_t* file = NULL;
uint8_t buff[4096] = {0};
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(filename != NULL, RET_BAD_PARAMS);
wbuffer_init(&wb, buff, sizeof(buff));
file = fs_open_file(os_fs(), filename, "rb");
if (file != NULL) {
remote_ui_service_send_resp(ui->io, REMOTE_UI_RESP_DOWNLOAD_FILE_BEGIN,
REMOTE_UI_DATA_TYPE_NONE, RET_OK, &wb);
} else {
remote_ui_service_send_resp(ui->io, REMOTE_UI_RESP_DOWNLOAD_FILE_BEGIN,
REMOTE_UI_DATA_TYPE_NONE, RET_FAIL, &wb);
}
return_value_if_fail(file != NULL, RET_BAD_PARAMS);
while ((len = fs_file_read(file, buff, sizeof(buff))) > 0) {
wbuffer_init(&wb, buff, len);
wb.cursor = len;
ret = remote_ui_service_send_resp(ui->io, REMOTE_UI_RESP_DOWNLOAD_FILE_DATA,
REMOTE_UI_DATA_TYPE_BINARY, RET_OK, &wb);
break_if_fail(ret == RET_OK);
}
wbuffer_rewind(&wb);
ret = remote_ui_service_send_resp(ui->io, REMOTE_UI_RESP_DOWNLOAD_FILE_END,
REMOTE_UI_DATA_TYPE_NONE, ret, &wb);
fs_file_close(file);
return RET_OK;
}
static ret_t remote_ui_service_create_dir(remote_ui_service_t* ui, const char* path) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(path != NULL, RET_BAD_PARAMS);
return fs_create_dir_r(os_fs(), path);
}
static ret_t remote_ui_service_remove_dir(remote_ui_service_t* ui, const char* path) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(path != NULL, RET_BAD_PARAMS);
return fs_remove_dir_r(os_fs(), path);
}
static ret_t remote_ui_service_remove_file(remote_ui_service_t* ui, const char* filename) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(filename != NULL, RET_BAD_PARAMS);
return fs_remove_file(os_fs(), filename);
}
static ret_t remote_ui_service_get_manifest(remote_ui_service_t* ui, str_t* result) {
ret_t ret = RET_OK;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(result != NULL, RET_BAD_PARAMS);
str_set(result, "todo");
/*TODO*/
return ret;
}
static ret_t remote_ui_service_take_screen_shot(remote_ui_service_t* ui, const char* filename) {
ret_t ret = RET_OK;
bitmap_t* image = NULL;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(filename != NULL, RET_BAD_PARAMS);
image = widget_take_snapshot(window_manager());
if (image != NULL) {
ret = bitmap_save_png(image, filename);
} else {
fs_remove_file(os_fs(), filename);
}
return ret;
}
static ret_t remote_ui_service_prepare_manifest(remote_ui_service_t* ui, const char* filename) {
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(filename != NULL, RET_BAD_PARAMS);
return file_write(filename, "TODO", 5);
}
static ret_t remote_ui_service_prepare_xml_source(remote_ui_service_t* ui, const char* filename) {
str_t str;
ret_t ret = RET_OK;
widget_t* win = window_manager_get_top_window(window_manager());
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(filename != NULL, RET_BAD_PARAMS);
str_init(&str, 10000);
widget_to_xml(win, &str);
ret = file_write(filename, str.str, str.size);
str_reset(&str);
return ret;
}
static ret_t remote_ui_service_on_event_func(void* ctx, event_t* e) {
remote_ui_service_t* ui = (remote_ui_service_t*)ctx;
return_value_if_fail(ui != NULL, RET_BAD_PARAMS);
/*TODO*/
return RET_OK;
}
static ret_t remote_ui_service_on_event(remote_ui_service_t* ui, const char* target, uint32_t event) {
widget_t* win = window_manager_get_top_window(window_manager());
widget_t* widget = widget_find_by_path(win, target, TRUE);
return_value_if_fail(widget != NULL, RET_BAD_PARAMS);
widget_on(widget, event, remote_ui_service_on_event_func, ui);
return RET_OK;
}
static ret_t remote_ui_service_off_event(remote_ui_service_t* ui, const char* target, uint32_t event) {
widget_t* win = window_manager_get_top_window(window_manager());
widget_t* widget = widget_find_by_path(win, target, TRUE);
return_value_if_fail(widget != NULL, RET_BAD_PARAMS);
widget_off_by_func(widget, event, remote_ui_service_on_event_func, ui);
return RET_OK;
}
static ret_t remote_ui_service_send_event(remote_ui_service_t* ui, const char* target, event_t* event) {
widget_t* win = window_manager_get_top_window(window_manager());
widget_t* widget = widget_find_by_path(win, target, TRUE);
return_value_if_fail(widget != NULL, RET_BAD_PARAMS);
switch (event->type) {
case EVT_CLICK: {
event->type = EVT_POINTER_DOWN;
widget_on_pointer_down(widget, pointer_event_cast(event));
event->type = EVT_POINTER_UP;
return widget_on_pointer_up(widget, pointer_event_cast(event));
}
case EVT_POINTER_DOWN: {
return widget_on_pointer_down(widget, pointer_event_cast(event));
}
case EVT_POINTER_MOVE: {
return widget_on_pointer_move(widget, pointer_event_cast(event));
}
case EVT_POINTER_UP: {
return widget_on_pointer_up(widget, pointer_event_cast(event));
}
case EVT_KEY_DOWN: {
return widget_on_keydown(widget, key_event_cast(event));
}
case EVT_KEY_UP: {
return widget_on_keyup(widget, key_event_cast(event));
}
default: {
break;
}
}
return RET_FAIL;
}
static ret_t remote_ui_service_open_dialog(remote_ui_service_t* ui, const char* type, const char* title,
const char* content, uint32_t duration) {
if (tk_str_eq(type, REMOTE_UI_DIALOG_TYPE_CONFIRM)) {
return dialog_confirm(title, content);
} else if (tk_str_eq(type, REMOTE_UI_DIALOG_TYPE_INFO)) {
return dialog_info(title, content);
} else if (tk_str_eq(type, REMOTE_UI_DIALOG_TYPE_WARN)) {
return dialog_warn(title, content);
} else {
return dialog_toast(content, duration);
}
return RET_OK;
}
static ret_t remote_ui_service_open_window(remote_ui_service_t* ui, const char* name, const char* xml,
const char* init_json) {
widget_t* win = NULL;
if (TK_STR_IS_NOT_EMPTY(xml)) {
win = ui_loader_load_widget_from_xml(NULL, xml, strlen(xml));
} else {
win = window_open(name);
}
return_value_if_fail(win != NULL, RET_BAD_PARAMS);
if (init_json != NULL) {
/*TODO*/
}
return RET_OK;
}
static ret_t remote_ui_service_close_window(remote_ui_service_t* ui, const char* name) {
widget_t* win = widget_child(window_manager(), name);
return_value_if_fail(win != NULL, RET_BAD_PARAMS);
return window_manager_close_window(window_manager(), win);
}
static ret_t remote_ui_service_back_to_prev(remote_ui_service_t* ui) {
window_manager_back(window_manager());
return RET_OK;
}
static ret_t remote_ui_service_back_to_home(remote_ui_service_t* ui) {
window_manager_back_to_home(window_manager());
return RET_OK;
}
static ret_t remote_ui_service_set_prop(remote_ui_service_t* ui, const char* target, const char* name,
const value_t* value) {
widget_t* win = window_manager_get_top_window(window_manager());
widget_t* widget = widget_find_by_path(win, target, TRUE);
return_value_if_fail(widget != NULL, RET_BAD_PARAMS);
return widget_set_prop(widget, name, value);
}
static ret_t remote_ui_service_get_prop(remote_ui_service_t* ui, const char* target, const char* name,
value_t* value) {
widget_t* win = window_manager_get_top_window(window_manager());
widget_t* widget = widget_find_by_path(win, target, TRUE);
return_value_if_fail(widget != NULL, RET_BAD_PARAMS);
return widget_get_prop(widget, name, value);
}
static ret_t remote_ui_service_set_theme(remote_ui_service_t* ui, const char* theme) {
return widget_set_theme(window_manager(), theme);
}
static ret_t remote_ui_service_exec_script(remote_ui_service_t* ui, const char* script, value_t* v) {
tk_object_t* obj = object_default_create();
ret_t ret = fscript_eval(obj, script, v);
TK_OBJECT_UNREF(obj);
return ret;
}
static ret_t remote_ui_service_set_language(remote_ui_service_t* ui, const char* language) {
const char* p = NULL;
char lang[TK_NAME_LEN + 1] = {0};
char country[TK_NAME_LEN + 1] = {0};
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(language != NULL, RET_BAD_PARAMS);
p = strchr(language, '_');
if (p != NULL) {
tk_strncpy(lang, language, p - language);
tk_strcpy(country, p + 1);
} else {
tk_strcpy(lang, language);
}
return locale_info_change(locale_info(), lang, country);
}
static ret_t remote_ui_dev_info_write(ubjson_writer_t* writer, remote_ui_dev_info_t* info) {
return_value_if_fail(writer != NULL && info != NULL, RET_BAD_PARAMS);
ubjson_writer_write_object_begin(writer);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_DEV_NAME, info->name);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_DEV_OS, info->os);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_DEV_VERSION, info->version);
ubjson_writer_write_kv_str(writer, REMOTE_UI_KEY_DEV_ARCH, info->arch);
ubjson_writer_write_kv_int(writer, REMOTE_UI_KEY_DEV_SCREEN_WIDTH, info->screen_width);
ubjson_writer_write_kv_int(writer, REMOTE_UI_KEY_DEV_SCREEN_HEIGHT, info->screen_height);
ubjson_writer_write_kv_int(writer, REMOTE_UI_KEY_DEV_DPI, info->dpi);
ubjson_writer_write_object_end(writer);
return RET_OK;
}
static ret_t remote_ui_service_dispatch_impl(remote_ui_service_t* ui, remote_ui_msg_header_t* req,
wbuffer_t* wb) {
value_t v;
char buff[1024] = {0};
ret_t ret = RET_FAIL;
tk_object_t* obj = NULL;
ubjson_writer_t* writer = NULL;
remote_ui_msg_header_t resp;
char local_file[MAX_PATH + 1] = {0};
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
return_value_if_fail(req != NULL && wb != NULL, RET_BAD_PARAMS);
memset(&resp, 0x00, sizeof(resp));
if (req->data_type == REMOTE_UI_DATA_TYPE_UBJSON) {
obj = conf_ubjson_load_from_buff(wb->data, wb->cursor, FALSE);
}
switch (req->type) {
case REMOTE_UI_REQ_LOGIN: {
const char* username = tk_object_get_prop_str(obj, "username");
const char* password = tk_object_get_prop_str(obj, "password");
resp.resp_code = remote_ui_service_login(ui, username, password);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_LOGIN;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_LOGOUT: {
resp.resp_code = remote_ui_service_logout(ui);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_LOGOUT;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_GET_DEV_INFO: {
remote_ui_dev_info_t info;
memset(&info, 0x00, sizeof(info));
resp.resp_code = remote_ui_service_get_dev_info(ui, &info);
resp.data_type = REMOTE_UI_DATA_TYPE_UBJSON;
resp.type = REMOTE_UI_RESP_GET_DEV_INFO;
writer = remote_ui_service_get_writer(ui);
ret = remote_ui_dev_info_write(writer, &info);
break;
}
case REMOTE_UI_REQ_REBOOT: {
rbuffer_t rb;
uint32_t reboot_type = REMOTE_UI_REBOOT_DEFAULT;
rbuffer_init(&rb, wb->data, wb->cursor);
rbuffer_read_uint32(&rb, &reboot_type);
resp.resp_code = remote_ui_service_reboot(ui, reboot_type);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_REBOOT;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_UPLOAD_FILE_BEGIN: {
const char* filename = (const char*)(wb->data);
filename = path_prepend_app_root(local_file, filename);
resp.resp_code = remote_ui_service_upload_file(ui, filename);
return RET_OK;
break;
}
case REMOTE_UI_REQ_DOWNLOAD_FILE_BEGIN: {
const char* filename = (const char*)(wb->data);
if (tk_str_eq(filename, REMOTE_UI_FILE_SCREEN_SHOT)) {
filename = path_prepend_temp_path(local_file, filename);
resp.resp_code = remote_ui_service_take_screen_shot(ui, filename);
} else if (tk_str_eq(filename, REMOTE_UI_FILE_MANIFEST)) {
filename = path_prepend_temp_path(local_file, filename);
resp.resp_code = remote_ui_service_prepare_manifest(ui, filename);
} else if (tk_str_eq(filename, REMOTE_UI_FILE_XML_SOURCE)) {
filename = path_prepend_temp_path(local_file, filename);
resp.resp_code = remote_ui_service_prepare_xml_source(ui, filename);
} else {
filename = path_prepend_app_root(local_file, filename);
}
resp.resp_code = remote_ui_service_download_file(ui, filename);
return RET_OK;
}
case REMOTE_UI_REQ_CREATE_DIR: {
const char* filename = (const char*)(wb->data);
filename = path_prepend_app_root(local_file, filename);
resp.resp_code = remote_ui_service_create_dir(ui, filename);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_CREATE_DIR;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_REMOVE_DIR: {
const char* filename = (const char*)(wb->data);
filename = path_prepend_app_root(local_file, filename);
resp.resp_code = remote_ui_service_remove_dir(ui, filename);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_REMOVE_DIR;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_REMOVE_FILE: {
const char* filename = (const char*)(wb->data);
filename = path_prepend_app_root(local_file, filename);
resp.resp_code = remote_ui_service_remove_file(ui, filename);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_REMOVE_FILE;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_OPEN_WINDOW: {
const char* name = tk_object_get_prop_str(obj, REMOTE_UI_KEY_NAME);
const char* xml = tk_object_get_prop_str(obj, REMOTE_UI_KEY_XML);
const char* init_json = tk_object_get_prop_str(obj, REMOTE_UI_KEY_INIT);
resp.resp_code = remote_ui_service_open_window(ui, name, xml, init_json);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_OPEN_WINDOW;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_OPEN_DIALOG: {
const char* type = tk_object_get_prop_str(obj, REMOTE_UI_KEY_TYPE);
const char* title = tk_object_get_prop_str(obj, REMOTE_UI_KEY_TITLE);
const char* content = tk_object_get_prop_str(obj, REMOTE_UI_KEY_CONTENT);
uint32_t duration = tk_object_get_prop_uint32(obj, REMOTE_UI_KEY_DURATION, 3000);
resp.resp_code = remote_ui_service_open_dialog(ui, type, title, content, duration);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_OPEN_WINDOW;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_BACK_TO_PREV: {
resp.resp_code = remote_ui_service_back_to_prev(ui);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_BACK_TO_PREV;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_BACK_TO_HOME: {
resp.resp_code = remote_ui_service_back_to_home(ui);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_BACK_TO_HOME;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_CLOSE_WINDOW: {
const char* name = (const char*)(wb->data);
resp.resp_code = remote_ui_service_close_window(ui, name);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_CLOSE_WINDOW;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_SET_PROP: {
value_t v;
const char* target = tk_object_get_prop_str(obj, REMOTE_UI_KEY_TARGET);
const char* name = tk_object_get_prop_str(obj, REMOTE_UI_KEY_NAME);
if (tk_object_get_prop(obj, REMOTE_UI_KEY_VALUE, &v) == RET_OK) {
resp.resp_code = remote_ui_service_set_prop(ui, target, name, &v);
} else {
resp.resp_code = RET_FAIL;
}
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_GET_PROP: {
const char* str = NULL;
const char* target = tk_object_get_prop_str(obj, REMOTE_UI_KEY_TARGET);
const char* name = tk_object_get_prop_str(obj, REMOTE_UI_KEY_NAME);
value_set_int(&v, 0);
resp.resp_code = remote_ui_service_get_prop(ui, target, name, &v);
resp.data_type = REMOTE_UI_DATA_TYPE_STRING;
str = value_str_ex(&v, buff, sizeof(buff));
wbuffer_rewind(wb);
wbuffer_write_string(wb, str);
break;
}
case REMOTE_UI_REQ_SET_LANGUAGE: {
const char* language = (const char*)(wb->data);
resp.resp_code = remote_ui_service_set_language(ui, language);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_SET_LANGUAGE;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_SET_THEME: {
const char* theme = (const char*)(wb->data);
resp.resp_code = remote_ui_service_set_theme(ui, theme);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_SET_THEME;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_EXEC_FSCRIPT: {
const char* script = (const char*)(wb->data);
value_set_int(&v, 0);
resp.resp_code = remote_ui_service_exec_script(ui, script, &v);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_EXEC_FSCRIPT;
wbuffer_rewind(wb);
wbuffer_write_string(wb, value_str_ex(&v, buff, sizeof(buff)));
break;
}
case REMOTE_UI_REQ_ON_EVENT: {
const char* target = tk_object_get_prop_str(obj, REMOTE_UI_KEY_TARGET);
uint32_t event_type = tk_object_get_prop_int(obj, REMOTE_UI_KEY_EVENT, 0);
resp.resp_code = remote_ui_service_on_event(ui, target, event_type);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_ON_EVENT;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_OFF_EVENT: {
const char* target = tk_object_get_prop_str(obj, REMOTE_UI_KEY_TARGET);
uint32_t event_type = tk_object_get_prop_int(obj, REMOTE_UI_KEY_EVENT, 0);
resp.resp_code = remote_ui_service_off_event(ui, target, event_type);
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_OFF_EVENT;
wbuffer_rewind(wb);
break;
}
case REMOTE_UI_REQ_SEND_EVENT: {
event_t* e = NULL;
const char* target = tk_object_get_prop_str(obj, REMOTE_UI_KEY_TARGET);
uint32_t event_type = tk_object_get_prop_int(obj, REMOTE_UI_KEY_EVENT, 0);
switch (event_type) {
case EVT_CLICK:
case EVT_POINTER_DOWN:
case EVT_POINTER_UP:
case EVT_POINTER_MOVE: {
pointer_event_t evt;
int x = tk_object_get_prop_int(obj, REMOTE_UI_KEY_X, 0);
int y = tk_object_get_prop_int(obj, REMOTE_UI_KEY_Y, 0);
e = pointer_event_init(&evt, event_type, NULL, x, y);
break;
}
case EVT_KEY_DOWN:
case EVT_KEY_UP: {
key_event_t evt;
uint32_t key = tk_object_get_prop_int(obj, REMOTE_UI_KEY_CODE, 0);
e = key_event_init(&evt, event_type, NULL, key);
break;
}
default:
break;
}
if (e != NULL) {
resp.resp_code = remote_ui_service_send_event(ui, target, e);
} else {
resp.resp_code = RET_FAIL;
}
resp.data_type = REMOTE_UI_DATA_TYPE_NONE;
resp.type = REMOTE_UI_RESP_SEND_EVENT;
wbuffer_rewind(wb);
break;
}
default: {
ret = RET_NOT_IMPL;
break;
}
}
TK_OBJECT_UNREF(obj);
return remote_ui_service_send_resp(ui->io, resp.type, resp.data_type, resp.resp_code, wb);
}
static ret_t remote_ui_service_dispatch(remote_ui_service_t* ui) {
ret_t ret = RET_OK;
remote_ui_msg_header_t header;
return_value_if_fail(ui != NULL && ui->io != NULL, RET_BAD_PARAMS);
memset(&header, 0x00, sizeof(header));
ret = remote_ui_service_read_req(ui->io, &header, &(ui->wb));
return_value_if_fail(ret == RET_OK, ret);
return remote_ui_service_dispatch_impl(ui, &header, &(ui->wb));
}
static ret_t remote_ui_service_destroy(remote_ui_service_t* ui) {
return_value_if_fail(ui != NULL, RET_BAD_PARAMS);
wbuffer_deinit(&(ui->wb));
TKMEM_FREE(ui);
return RET_OK;
}

View File

@ -0,0 +1,82 @@
/**
* File: remote_ui_service.h
* Author: AWTK Develop Team
* Brief: remote ui service
*
* Copyright (c) 2018 - 2023 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2023-11-04 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_REMOTE_UI_SERVICE_H
#define TK_REMOTE_UI_SERVICE_H
#include "tkc/buffer.h"
#include "tkc/darray.h"
#include "tkc/iostream.h"
#include "ubjson/ubjson_writer.h"
#include "service/service.h"
#include "remote_ui/shared/remote_ui_types_def.h"
BEGIN_C_DECLS
/**
* @class remote_ui_service_args_t
* remote ui服务端启动参数
*/
typedef struct _remote_ui_service_args_t {
/**
* @property {tk_service_auth_t} auth
* @annotation ["readable"]
*
*/
tk_service_auth_t auth;
} remote_ui_service_args_t;
/**
* @class remote_ui_service_t
* remote ui服务端
*/
typedef struct _remote_ui_service_t {
tk_service_t service;
/**
* @property {tk_iostream_t*} io
* @annotation ["readable"]
* IO stream
*/
tk_iostream_t* io;
/*private*/
wbuffer_t wb;
ubjson_writer_t writer;
tk_object_t* event_handlers;
bool_t is_login;
tk_service_auth_t auth;
} remote_ui_service_t;
/**
* @method remote_ui_service_create
* remote ui客户端
*
* @param {tk_iostream_t*} io IO流(service释放)
* @param {void*} args
*
* @return {tk_service_t*} service对象
*/
tk_service_t* remote_ui_service_create(tk_iostream_t* io, void* args);
END_C_DECLS
#endif /*TK_REMOTE_UI_SERVICE_H*/

View File

@ -0,0 +1,465 @@
/**
* File: remote_ui_types_def.h
* Author: AWTK Develop Team
* Brief: remote ui types def
*
* Copyright (c) 2018 - 2023 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2023-11-04 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_REMOTE_UI_TYPES_DEF_H
#define TK_REMOTE_UI_TYPES_DEF_H
#include "tkc/types_def.h"
BEGIN_C_DECLS
/**
* @enum remote_ui_msg_code_t
* @prefix REMOTE_UI_
*
*
*/
typedef enum _remote_ui_msg_code_t {
/**
* @const REMOTE_UI_MSG_NONE
*
*/
REMOTE_UI_MSG_NONE = 0,
/**
* @const REMOTE_UI_REQ_LOGIN
*
*/
REMOTE_UI_REQ_LOGIN,
/**
* @const REMOTE_UI_REQ_LOGOUT
*
*/
REMOTE_UI_REQ_LOGOUT,
/**
* @const REMOTE_UI_REQ_GET_DEV_INFO
*
*/
REMOTE_UI_REQ_GET_DEV_INFO,
/**
* @const REMOTE_UI_REQ_REBOOT
*
*/
REMOTE_UI_REQ_REBOOT,
/**
* @const REMOTE_UI_REQ_UPLOAD_FILE_BEGIN
*
*/
REMOTE_UI_REQ_UPLOAD_FILE_BEGIN,
/**
* @const REMOTE_UI_REQ_UPLOAD_FILE_DATA
*
*/
REMOTE_UI_REQ_UPLOAD_FILE_DATA,
/**
* @const REMOTE_UI_REQ_UPLOAD_FILE_END
*
*/
REMOTE_UI_REQ_UPLOAD_FILE_END,
/**
* @const REMOTE_UI_REQ_DOWNLOAD_FILE_BEGIN
*
*/
REMOTE_UI_REQ_DOWNLOAD_FILE_BEGIN,
/**
* @const REMOTE_UI_REQ_CREATE_DIR
*
*/
REMOTE_UI_REQ_CREATE_DIR,
/**
* @const REMOTE_UI_REQ_REMOVE_DIR
*
*/
REMOTE_UI_REQ_REMOVE_DIR,
/**
* @const REMOTE_UI_REQ_REMOVE_FILE
*
*/
REMOTE_UI_REQ_REMOVE_FILE,
/**
* @const REMOTE_UI_REQ_ON_EVENT
*
*/
REMOTE_UI_REQ_ON_EVENT,
/**
* @const REMOTE_UI_REQ_OFF_EVENT
*
*/
REMOTE_UI_REQ_OFF_EVENT,
/**
* @const REMOTE_UI_REQ_SEND_EVENT
*
*/
REMOTE_UI_REQ_SEND_EVENT,
/**
* @const REMOTE_UI_REQ_OPEN_WINDOW
*
*/
REMOTE_UI_REQ_OPEN_WINDOW,
/**
* @const REMOTE_UI_REQ_OPEN_DIALOG
*
*/
REMOTE_UI_REQ_OPEN_DIALOG,
/**
* @const REMOTE_UI_REQ_CLOSE_WINDOW
*
*/
REMOTE_UI_REQ_CLOSE_WINDOW,
/**
* @const REMOTE_UI_REQ_BACK_TO_PREV
*
*/
REMOTE_UI_REQ_BACK_TO_PREV,
/**
* @const REMOTE_UI_REQ_BACK_TO_HOME
*
*/
REMOTE_UI_REQ_BACK_TO_HOME,
/**
* @const REMOTE_UI_REQ_SET_PROP
*
*/
REMOTE_UI_REQ_SET_PROP,
/**
* @const REMOTE_UI_REQ_GET_PROP
*
*/
REMOTE_UI_REQ_GET_PROP,
/**
* @const REMOTE_UI_REQ_SET_THEME
*
*/
REMOTE_UI_REQ_SET_THEME,
/**
* @const REMOTE_UI_REQ_SET_LANGUAGE
*
*/
REMOTE_UI_REQ_SET_LANGUAGE,
/**
* @const REMOTE_UI_REQ_GET_XML_SOURCE
* xml源码请求
*/
REMOTE_UI_REQ_GET_XML_SOURCE,
/**
* @const REMOTE_UI_REQ_EXEC_FSCRIPT
*
*/
REMOTE_UI_REQ_EXEC_FSCRIPT,
/**
* @const REMOTE_UI_RESP_LOGIN
*
*/
REMOTE_UI_RESP_LOGIN,
/**
* @const REMOTE_UI_RESP_LOGOUT
*
*/
REMOTE_UI_RESP_LOGOUT,
/**
* @const REMOTE_UI_RESP_GET_DEV_INFO
*
*/
REMOTE_UI_RESP_GET_DEV_INFO,
/**
* @const REMOTE_UI_RESP_REBOOT
*
*/
REMOTE_UI_RESP_REBOOT,
/**
* @const REMOTE_UI_RESP_UPLOAD_FILE_BEGIN
*
*/
REMOTE_UI_RESP_UPLOAD_FILE_BEGIN,
/**
* @const REMOTE_UI_RESP_UPLOAD_FILE_DATA
*
*/
REMOTE_UI_RESP_UPLOAD_FILE_DATA,
/**
* @const REMOTE_UI_RESP_UPLOAD_FILE_END
*
*/
REMOTE_UI_RESP_UPLOAD_FILE_END,
/**
* @const REMOTE_UI_RESP_DOWNLOAD_FILE_BEGIN
*
*/
REMOTE_UI_RESP_DOWNLOAD_FILE_BEGIN,
/**
* @const REMOTE_UI_RESP_DOWNLOAD_FILE_DATA
*
*/
REMOTE_UI_RESP_DOWNLOAD_FILE_DATA,
/**
* @const REMOTE_UI_RESP_DOWNLOAD_FILE_END
*
*/
REMOTE_UI_RESP_DOWNLOAD_FILE_END,
/**
* @const REMOTE_UI_RESP_CREATE_DIR
*
*/
REMOTE_UI_RESP_CREATE_DIR,
/**
* @const REMOTE_UI_RESP_REMOVE_DIR
*
*/
REMOTE_UI_RESP_REMOVE_DIR,
/**
* @const REMOTE_UI_RESP_REMOVE_FILE
*
*/
REMOTE_UI_RESP_REMOVE_FILE,
/**
* @const REMOTE_UI_RESP_ON_EVENT
*
*/
REMOTE_UI_RESP_ON_EVENT,
/**
* @const REMOTE_UI_RESP_OFF_EVENT
*
*/
REMOTE_UI_RESP_OFF_EVENT,
/**
* @const REMOTE_UI_RESP_SEND_EVENT
*
*/
REMOTE_UI_RESP_SEND_EVENT,
/**
* @const REMOTE_UI_RESP_OPEN_WINDOW
*
*/
REMOTE_UI_RESP_OPEN_WINDOW,
/**
* @const REMOTE_UI_RESP_OPEN_DIALOG
*
*/
REMOTE_UI_RESP_OPEN_DIALOG,
/**
* @const REMOTE_UI_RESP_CLOSE_WINDOW
*
*/
REMOTE_UI_RESP_CLOSE_WINDOW,
/**
* @const REMOTE_UI_RESP_BACK_TO_PREV
*
*/
REMOTE_UI_RESP_BACK_TO_PREV,
/**
* @const REMOTE_UI_RESP_BACK_TO_HOME
*
*/
REMOTE_UI_RESP_BACK_TO_HOME,
/**
* @const REMOTE_UI_RESP_SET_PROP
*
*/
REMOTE_UI_RESP_SET_PROP,
/**
* @const REMOTE_UI_RESP_GET_PROP
*
*/
REMOTE_UI_RESP_GET_PROP,
/**
* @const REMOTE_UI_RESP_SET_THEME
*
*/
REMOTE_UI_RESP_SET_THEME,
/**
* @const REMOTE_UI_RESP_SET_LANGUAGE
*
*/
REMOTE_UI_RESP_SET_LANGUAGE,
/**
* @const REMOTE_UI_RESP_GET_XML_SOURCE
* xml源码响应
*/
REMOTE_UI_RESP_GET_XML_SOURCE,
/**
* @const REMOTE_UI_RESP_EXEC_FSCRIPT
*
*/
REMOTE_UI_RESP_EXEC_FSCRIPT,
/**
* @const REMOTE_UI_NOTIFY
*
*/
REMOTE_UI_NOTIFY,
} remote_ui_msg_code_t;
/**
* @enum remote_ui_data_type_t
* @prefix REMOTE_UI_DATA_TYPE_
*
*/
typedef enum _remote_ui_data_type_t {
/**
* @const REMOTE_UI_DATA_TYPE_NONE
*
*/
REMOTE_UI_DATA_TYPE_NONE = 0,
/**
* @const REMOTE_UI_DATA_TYPE_UBJSON
* JSON数据类型
*/
REMOTE_UI_DATA_TYPE_UBJSON,
/**
* @const REMOTE_UI_DATA_TYPE_STRING
*
*/
REMOTE_UI_DATA_TYPE_STRING,
/**
* @const REMOTE_UI_DATA_TYPE_BINARY
*
*/
REMOTE_UI_DATA_TYPE_BINARY
} remote_ui_data_type_t;
/**
* @class remote_ui_msg_header_t
*
*/
typedef struct _remote_ui_msg_header_t {
/**
* @property {uint32_t} size
*
*/
uint32_t size;
/**
* @property {uint16_t} type
*
*/
uint16_t type;
/**
* @property {uint8_t} data_type
*
*/
uint8_t data_type;
/**
* @property {uint8_t} resp_code
* (resp)
*/
uint8_t resp_code;
} remote_ui_msg_header_t;
/**
* @class remote_ui_dev_info_t
*
*/
typedef struct _remote_ui_dev_info_t {
/**
* @property {char*} name
*
*/
char name[64];
/**
* @property {char*} version
*
*/
char version[64];
/**
* @property {char*} os
*
*/
char os[16];
/**
* @property {char*} arch
* CPU架构
*/
char arch[16];
/**
* @property {uint32_t} screen_width
*
*/
uint32_t screen_width;
/**
* @property {uint32_t} screen_height
*
*/
uint32_t screen_height;
/**
* @property {uint32_t} dpi
* DPI
*/
uint32_t dpi;
} remote_ui_dev_info_t;
/**
* @enum remote_ui_reboot_type_t
* @prefix REMOTE_UI_REBOOT_
*
*/
typedef enum _remote_ui_reboot_type_t {
/**
* @const REMOTE_UI_REBOOT_DEFAULT
*
*/
REMOTE_UI_REBOOT_DEFAULT = 0,
/**
* @const REMOTE_UI_REBOOT_RELOAD
*
*/
REMOTE_UI_REBOOT_RELOAD,
/**
* @const REMOTE_UI_REBOOT_POWEROFF
*
*/
REMOTE_UI_REBOOT_POWEROFF
} remote_ui_reboot_type_t;
#define REMOTE_UI_KEY_USERNAME "username"
#define REMOTE_UI_KEY_PASSWORD "password"
#define REMOTE_UI_KEY_DEV_NAME "dev_name"
#define REMOTE_UI_KEY_DEV_OS "dev_os"
#define REMOTE_UI_KEY_DEV_ARCH "dev_arch"
#define REMOTE_UI_KEY_DEV_VERSION "dev_version"
#define REMOTE_UI_KEY_DEV_SCREEN_WIDTH "dev_screen_width"
#define REMOTE_UI_KEY_DEV_SCREEN_HEIGHT "dev_screen_height"
#define REMOTE_UI_KEY_DEV_DPI "dev_dpi"
#define REMOTE_UI_KEY_TARGET "target"
#define REMOTE_UI_KEY_NAME "name"
#define REMOTE_UI_KEY_VALUE "value"
#define REMOTE_UI_KEY_EVENT "event"
#define REMOTE_UI_KEY_XML "xml"
#define REMOTE_UI_KEY_INIT "init"
#define REMOTE_UI_KEY_X "x"
#define REMOTE_UI_KEY_Y "y"
#define REMOTE_UI_KEY_CODE "code"
#define REMOTE_UI_KEY_TYPE "type"
#define REMOTE_UI_KEY_TITLE "title"
#define REMOTE_UI_KEY_CONTENT "content"
#define REMOTE_UI_KEY_DURATION "duration"
#define REMOTE_UI_FILE_MANIFEST "__manifest__.txt"
#define REMOTE_UI_FILE_XML_SOURCE "__xml_source__.xml"
#define REMOTE_UI_FILE_SCREEN_SHOT "__screen_shot__.png"
#define REMOTE_UI_DIALOG_TYPE_CONFIRM "confirm"
#define REMOTE_UI_DIALOG_TYPE_WARN "warn"
#define REMOTE_UI_DIALOG_TYPE_INFO "info"
#define REMOTE_UI_DIALOG_TYPE_TOAST "toast"
END_C_DECLS
#endif /*TK_REMOTE_UI_TYPES_DEF_H*/

147
src/service/service.c Normal file
View File

@ -0,0 +1,147 @@
/**
* File: service.h
* Author: AWTK Develop Team
* Brief: service interface
*
* Copyright (c) 2018 - 2023 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2023-11-05 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "tkc/url.h"
#include "tkc/utils.h"
#include "service/service.h"
#include "tkc/event_source_fd.h"
#include "streams/inet/iostream_tcp.h"
#include "streams/serial/iostream_serial.h"
#include "tkc/socket_helper.h"
ret_t tk_service_dispatch(tk_service_t* service) {
return_value_if_fail(service != NULL && service->dispatch != NULL, RET_BAD_PARAMS);
return service->dispatch(service);
}
ret_t tk_service_destroy(tk_service_t* service) {
return_value_if_fail(service != NULL && service->destroy != NULL, RET_BAD_PARAMS);
return service->destroy(service);
}
static ret_t tk_service_on_data(event_source_t* source) {
event_source_fd_t* event_source_fd = (event_source_fd_t*)source;
tk_service_t* service = (tk_service_t*)(event_source_fd->ctx);
if (tk_service_dispatch(service) != RET_OK) {
tk_service_destroy(service);
log_debug("client disconnected\n");
return RET_REMOVE;
} else {
return RET_OK;
}
}
static ret_t tk_service_tcp_on_client(event_source_t* source) {
event_source_fd_t* event_source_fd = (event_source_fd_t*)source;
tk_service_create_t create = (tk_service_create_t)(event_source_fd->ctx);
int listen_sock = event_source_get_fd(source);
int sock = tcp_accept(listen_sock);
if (sock >= 0) {
log_debug("client connected:%d\n", sock);
tk_iostream_t* io = tk_iostream_tcp_create(sock);
if (io != NULL) {
tk_service_t* service = create(io, event_source_fd->ctx2);
if (service != NULL) {
event_source_manager_t* esm = source->manager;
event_source_t* client_source = event_source_fd_create(sock, tk_service_on_data, service);
event_source_manager_add(esm, client_source);
TK_OBJECT_UNREF(client_source);
} else {
TK_OBJECT_UNREF(io);
}
} else {
log_debug("oom! disconnected:%d\n", sock);
tk_socket_close(sock);
}
} else {
log_debug("error disconnected:%d\n", sock);
tk_socket_close(sock);
}
return RET_OK;
}
static ret_t tk_service_start_tcp(event_source_manager_t* esm, const char* url,
tk_service_create_t create, void* args) {
int port = 0;
int listen_sock = -1;
event_source_t* source = NULL;
url_t* aurl = url_create(url);
return_value_if_fail(esm != NULL && aurl != NULL && create != NULL, RET_BAD_PARAMS);
port = aurl->port;
listen_sock = tcp_listen(port);
url_destroy(aurl);
return_value_if_fail(listen_sock >= 0, RET_BAD_PARAMS);
log_debug("listen on %d listen_sock=%d\n", port, listen_sock);
source = event_source_fd_create(listen_sock, tk_service_tcp_on_client, create);
return_value_if_fail(source != NULL, RET_OOM);
EVENT_SOURCE_FD(source)->ctx2 = args;
event_source_manager_add(esm, source);
OBJECT_UNREF(source);
log_debug("service start: %s\n", url);
return RET_OK;
}
static ret_t tk_service_start_serial(event_source_manager_t* esm, const char* url,
tk_service_create_t create, void* args) {
tk_iostream_t* io = NULL;
tk_service_t* service = NULL;
return_value_if_fail(esm != NULL && create != NULL, RET_BAD_PARAMS);
io = tk_iostream_serial_create_ex(url);
return_value_if_fail(io != NULL, RET_BAD_PARAMS);
service = create(io, args);
if (service != NULL) {
int fd = tk_object_get_prop_int(TK_OBJECT(io), TK_STREAM_PROP_FD, -1);
event_source_t* client_source = event_source_fd_create(fd, tk_service_on_data, service);
event_source_manager_add(esm, client_source);
TK_OBJECT_UNREF(client_source);
log_debug("service start: %s\n", url);
} else {
TK_OBJECT_UNREF(io);
}
return RET_OK;
}
ret_t tk_service_start(event_source_manager_t* esm, const char* url, tk_service_create_t create,
void* args) {
return_value_if_fail(esm != NULL && create != NULL, RET_BAD_PARAMS);
if (tk_str_start_with(url, STR_SCHEMA_TCP)) {
return tk_service_start_tcp(esm, url, create, args);
} else if (tk_str_start_with(url, STR_SCHEMA_SERIAL)) {
return tk_service_start_serial(esm, url, create, args);
} else {
log_debug("not supported: %s\n", url);
return RET_NOT_IMPL;
}
}

86
src/service/service.h Normal file
View File

@ -0,0 +1,86 @@
/**
* File: service.h
* Author: AWTK Develop Team
* Brief: service interface
*
* Copyright (c) 2018 - 2023 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2023-11-05 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_SERVICE_H
#define TK_SERVICE_H
#include "tkc/iostream.h"
#include "tkc/event_source_manager.h"
BEGIN_C_DECLS
struct _tk_service_t;
typedef struct _tk_service_t tk_service_t;
typedef tk_service_t* (*tk_service_create_t)(tk_iostream_t* io, void* args);
typedef ret_t (*tk_service_dispatch_t)(tk_service_t* service);
typedef ret_t (*tk_service_destroy_t)(tk_service_t* service);
typedef ret_t (*tk_service_auth_t)(tk_service_t* service, const char* username,
const char* password);
/**
* @class tk_service_t
*
*/
struct _tk_service_t {
tk_service_dispatch_t dispatch;
tk_service_destroy_t destroy;
tk_iostream_t* io;
};
/**
* @method tk_service_dispatch
*
*
* @param {tk_service_t*} service
*
* @return {ret_t} RET_OK表示成功
*/
ret_t tk_service_dispatch(tk_service_t* service);
/**
* @method tk_service_destroy
*
*
* @param {tk_service_t*} service
*
* @return {ret_t} RET_OK表示成功
*/
ret_t tk_service_destroy(tk_service_t* service);
/**
* @method tk_service_start
*
*
* @param {event_source_manager_t*} esm
* @param {const char*} url
* @param {tk_service_create_t} create
* @param {void*} args
*
* @return {ret_t} RET_OK表示成功
*/
ret_t tk_service_start(event_source_manager_t* esm, const char* url, tk_service_create_t create,
void* args);
END_C_DECLS
#endif /*TK_SERVICE_H*/

View File

@ -0,0 +1,68 @@
[create]
url=tcp://localhost:2233
[login]
username=admin
password=admin
[get_dev_info]
[create_dir]
path=abc/123
[upload]
remote = abc/123/test.txt
local = README.md
[download]
remote = abc/123/test.txt
local = README.md.download
ret=RET_OK
[remove_file]
filename=abc/123/test.txt
[remove_dir]
path=abc/123
[take_screen_shot]
filename=test.png
[get_manifest]
[open_window]
name=button
[sleep]
time=2000
[back]
[open_window]
name=edit
[sleep]
time=2000
[home]
[open_window]
name=rich_text
[sleep]
time=2000
[close_window]
name=rich_text
[set_prop]
target=open:button
name=text
value=Hello
[get_prop]
target=open:button
name=text
value=Hello
[logout]
[close]

View File

@ -0,0 +1,17 @@
[create]
url=tcp://localhost:2233
[login]
username=admin
password=admin
[confirm]
title=title
content=content
[back]
[logout]
[close]

View File

@ -0,0 +1,16 @@
[create]
url=tcp://localhost:2233
[login]
username=admin
password=admin
[exec_fscript]
fscript=print("hello");
[back]
[logout]
[close]

View File

@ -0,0 +1,15 @@
[create]
url=tcp://localhost:2233
[login]
username=admin
password=admin
[get_source]
filename=test.xml
[back]
[logout]
[close]

View File

@ -0,0 +1,17 @@
[create]
url=tcp://localhost:2233
[login]
username=admin
password=admin
[info]
title=title
content=content
[back]
[logout]
[close]

View File

@ -0,0 +1,19 @@
[create]
url=tcp://localhost:2233
[login]
username=admin
password=admin
[send_event]
target=window
type=click
x = 100
y = 300
[back]
[logout]
[close]

View File

@ -0,0 +1,19 @@
[create]
url=tcp://localhost:2233
[login]
username=admin
password=admin
[send_event]
type=key_down
key=RIGHT
[send_event]
type=key_up
key=RIGHT
[logout]
[close]

View File

@ -0,0 +1,31 @@
[create]
url=tcp://localhost:2233
[login]
username=admin
password=admin
[send_event]
target=window
type=pointer_down
x = 100
y = 300
[send_event]
target=window
type=pointer_move
x = 101
y = 301
[send_event]
target=window
type=pointer_up
x = 100
y = 300
[back]
[logout]
[close]

View File

@ -0,0 +1,21 @@
[create]
url=tcp://localhost:2233
[login]
username=admin
password=admin
[set_prop]
target=open:button
name=text
value=Hello
[get_prop]
target=open:button
name=text
value=Hello
[logout]
[close]

View File

@ -0,0 +1,17 @@
[create]
url=tcp://localhost:2233
[login]
username=admin
password=admin
[set_theme]
theme=default
[set_language]
language=zh_CN
[logout]
[close]

View File

@ -0,0 +1,17 @@
[create]
url=tcp://localhost:2233
[login]
username=admin
password=admin
[toast]
content=content
duration=3000
[back]
[logout]
[close]

View File

@ -0,0 +1,17 @@
[create]
url=tcp://localhost:2233
[login]
username=admin
password=admin
[warn]
title=title
content=content
[back]
[logout]
[close]

View File

@ -21,6 +21,7 @@
#include "base/theme_xml.h"
#include "base/style_factory.h"
#include "base/window.h"
#include "base/window_manager.h"
using std::string;
#include "common.h"
@ -68,6 +69,46 @@ TEST(Widget, move_to_center) {
ASSERT_EQ(b->x, 150);
ASSERT_EQ(b->y, 120);
widget_destroy(w);
}
TEST(Widget, find_by_path) {
widget_t* w = window_create(NULL, 0, 0, 400, 300);
widget_t* b = button_create(w, 0, 0, 100, 60);
widget_t* label = label_create(b, 0, 0, 100, 60);
widget_set_name(w, "win");
ASSERT_EQ(widget_find_by_path(w, STR_PROP_SELF, TRUE), w);
ASSERT_EQ(widget_find_by_path(w, STR_PROP_WINDOW, TRUE), w);
ASSERT_EQ(widget_find_by_path(w, STR_PROP_WINDOW_MANAGER, TRUE), window_manager());
widget_set_name(b, "foo");
ASSERT_EQ(widget_find_by_path(w, STR_PROP_SELF".foo", TRUE), b);
ASSERT_EQ(widget_find_by_path(w, STR_PROP_WINDOW".foo", TRUE), b);
ASSERT_EQ(widget_find_by_path(w, "foo", TRUE), b);
ASSERT_EQ(widget_find_by_path(w, "foo", TRUE), b);
widget_set_name(label, "bar");
ASSERT_EQ(widget_find_by_path(w, STR_PROP_SELF".bar", TRUE), (widget_t*)NULL);
ASSERT_EQ(widget_find_by_path(w, STR_PROP_WINDOW".bar", TRUE), (widget_t*)NULL);
ASSERT_EQ(widget_find_by_path(w, "foo.bar", TRUE), label);
ASSERT_EQ(widget_find_by_path(w, "foo.bar", TRUE), label);
ASSERT_EQ(widget_find_by_path(w, "foo.bar", FALSE), label);
ASSERT_EQ(widget_find_by_path(w, "foo.bar", FALSE), label);
ASSERT_EQ(widget_find_by_path(w, "bar", TRUE), label);
ASSERT_EQ(widget_find_by_path(w, "bar", TRUE), label);
ASSERT_EQ(widget_find_by_path(w, "bar", FALSE), (widget_t*)NULL);
ASSERT_EQ(widget_find_by_path(w, "bar", FALSE), (widget_t*)NULL);
ASSERT_EQ(widget_find_by_path(w, STR_PROP_WINDOW_MANAGER ".win.foo.bar", TRUE), label);
ASSERT_EQ(widget_find_by_path(w, STR_PROP_WINDOW_MANAGER ".win.foo.bar", TRUE), label);
widget_destroy(w);
}

6
tools/ui_test/SConscript Executable file
View File

@ -0,0 +1,6 @@
import os
env=DefaultEnvironment().Clone()
BIN_DIR=os.environ['BIN_DIR'];
env.Program(os.path.join(BIN_DIR, 'ui_test'), Glob('ui_test.c'))

308
tools/ui_test/ui_test.c Normal file
View File

@ -0,0 +1,308 @@
/**
* File: ui_test.c
* Author: AWTK Develop Team
* Brief: ui test
*
* Copyright (c) 2023 - 2023 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2023-11-04 Li XianJing <lixianjing@zlg.cn> created
*
*/
#include "tkc.h"
#include "base/enums.h"
#include "base/events.h"
#include "base/widget_consts.h"
#include "conf_io/conf_ini.h"
#include "conf_io/conf_node.h"
#include "remote_ui/client/remote_ui.h"
#include "streams/stream_factory.h"
static const char* fix_str(const char* str) {
return str != NULL ? str : "";
}
static void check_return_code(ret_t ret, const char* expected_ret, const char* name,
const char* arg1, const char* arg2, const char* arg3) {
if (expected_ret != NULL) {
if (ret != ret_code_from_name(expected_ret)) {
log_debug("%s failed(%s != %s)\n", name, ret_code_to_name(ret), expected_ret);
} else {
log_debug("%s (%s %s %s) ok\n", name, fix_str(arg1), fix_str(arg2), fix_str(arg3));
}
} else {
if (ret == RET_OK) {
log_debug("%s (%s %s %s) ok\n", name, fix_str(arg1), fix_str(arg2), fix_str(arg3));
} else {
log_debug("%s (%s %s %s) fail\n", name, fix_str(arg1), fix_str(arg2), fix_str(arg3));
}
}
}
static void run_script(conf_doc_t* doc, uint32_t times) {
ret_t ret = RET_OK;
remote_ui_t* ui = NULL;
const char* expected_ret = NULL;
conf_node_t* iter = conf_node_get_first_child(doc->root);
while (iter != NULL) {
const char* name = conf_node_get_name(iter);
if (tk_str_eq(name, "create")) {
const char* url = conf_node_get_child_value_str(iter, "url", "tcp://localhost:2233");
tk_iostream_t* io = tk_stream_factory_create_iostream(url);
break_if_fail(io != NULL);
if (ui != NULL) {
remote_ui_destroy(ui);
}
ui = remote_ui_create(io);
iter = iter->next;
continue;
}
if (ui == NULL) {
log_debug("ui is null.\n");
break;
}
expected_ret = conf_node_get_child_value_str(iter, "ret", NULL);
if (tk_str_eq(name, "login")) {
const char* user = conf_node_get_child_value_str(iter, "user", "admin");
const char* password = conf_node_get_child_value_str(iter, "password", "admin");
ret = remote_ui_login(ui, user, password);
check_return_code(ret, expected_ret, name, user, NULL, NULL);
} else if (tk_str_eq(name, "create_dir")) {
const char* path = conf_node_get_child_value_str(iter, "path", NULL);
ret = remote_ui_create_dir(ui, path);
check_return_code(ret, expected_ret, name, path, NULL, NULL);
} else if (tk_str_eq(name, "remove_dir")) {
const char* path = conf_node_get_child_value_str(iter, "path", NULL);
ret = remote_ui_remove_dir(ui, path);
check_return_code(ret, expected_ret, name, path, NULL, NULL);
} else if (tk_str_eq(name, "remove_file")) {
const char* filename = conf_node_get_child_value_str(iter, "filename", NULL);
ret = remote_ui_remove_file(ui, filename);
check_return_code(ret, expected_ret, name, filename, NULL, NULL);
} else if (tk_str_eq(name, "upload")) {
const char* remote = conf_node_get_child_value_str(iter, "remote", NULL);
const char* local = conf_node_get_child_value_str(iter, "local", NULL);
ret = remote_ui_upload_file(ui, remote, local);
check_return_code(ret, expected_ret, name, remote, local, NULL);
} else if (tk_str_eq(name, "download")) {
const char* remote = conf_node_get_child_value_str(iter, "remote", NULL);
const char* local = conf_node_get_child_value_str(iter, "local", NULL);
ret = remote_ui_download_file(ui, remote, local);
check_return_code(ret, expected_ret, name, remote, local, NULL);
} else if (tk_str_eq(name, "get_dev_info")) {
remote_ui_dev_info_t info;
ret = remote_ui_get_dev_info(ui, &info);
check_return_code(ret, expected_ret, name, info.name, info.os, info.arch);
log_debug("width=%d height=%d\n", info.screen_width, info.screen_height);
} else if (tk_str_eq(name, "take_screen_shot")) {
const char* filename = conf_node_get_child_value_str(iter, "filename", NULL);
ret = remote_ui_take_screen_shot(ui, filename);
check_return_code(ret, expected_ret, name, filename, NULL, NULL);
} else if (tk_str_eq(name, "get_source")) {
const char* filename = conf_node_get_child_value_str(iter, "filename", NULL);
ret = remote_ui_get_xml_source(ui, filename);
check_return_code(ret, expected_ret, name, filename, NULL, NULL);
} else if (tk_str_eq(name, "get_manifest")) {
const char* filename = conf_node_get_child_value_str(iter, "filename", "manifest.txt");
ret = remote_ui_get_manifest(ui, filename);
check_return_code(ret, expected_ret, name, filename, NULL, NULL);
} else if (tk_str_eq(name, "open_window")) {
const char* wname = conf_node_get_child_value_str(iter, "name", NULL);
const char* xml = conf_node_get_child_value_str(iter, "xml", NULL);
const char* init = conf_node_get_child_value_str(iter, "init", NULL);
ret = remote_ui_open_window(ui, wname, xml, init);
check_return_code(ret, expected_ret, name, wname, NULL, NULL);
} else if (tk_str_eq(name, "close_window")) {
const char* wname = conf_node_get_child_value_str(iter, "name", NULL);
ret = remote_ui_close_window(ui, wname);
check_return_code(ret, expected_ret, name, wname, NULL, NULL);
} else if (tk_str_eq(name, "back")) {
ret = remote_ui_back_to_prev(ui);
check_return_code(ret, expected_ret, name, NULL, NULL, NULL);
} else if (tk_str_eq(name, "home")) {
ret = remote_ui_back_to_home(ui);
check_return_code(ret, expected_ret, name, NULL, NULL, NULL);
} else if (tk_str_eq(name, "logout")) {
ret = remote_ui_logout(ui);
check_return_code(ret, expected_ret, name, NULL, NULL, NULL);
} else if (tk_str_eq(name, "set_prop")) {
value_t v;
const char* target = conf_node_get_child_value_str(iter, "target", NULL);
const char* prop = conf_node_get_child_value_str(iter, "name", NULL);
const char* value = conf_node_get_child_value_str(iter, "value", NULL);
value_set_str(&v, value);
ret = remote_ui_set_prop(ui, target, prop, &v);
check_return_code(ret, expected_ret, name, target, prop, value);
} else if (tk_str_eq(name, "get_prop")) {
value_t v;
const char* target = conf_node_get_child_value_str(iter, "target", NULL);
const char* prop = conf_node_get_child_value_str(iter, "name", NULL);
const char* value = conf_node_get_child_value_str(iter, "value", NULL);
value_set_str(&v, NULL);
ret = remote_ui_get_prop(ui, target, prop, &v);
if (value != NULL) {
if (!tk_str_eq(value, value_str(&v))) {
ret = RET_FAIL;
}
}
check_return_code(ret, expected_ret, name, target, prop, value_str(&v));
} else if (tk_str_eq(name, "set_theme")) {
const char* theme = conf_node_get_child_value_str(iter, "theme", NULL);
ret = remote_ui_set_theme(ui, theme);
check_return_code(ret, expected_ret, name, theme, NULL, NULL);
} else if (tk_str_eq(name, "set_language")) {
const char* language = conf_node_get_child_value_str(iter, "language", NULL);
ret = remote_ui_set_language(ui, language);
check_return_code(ret, expected_ret, name, language, NULL, NULL);
} else if (tk_str_eq(name, "exec_fscript")) {
str_t str;
const char* fscript = conf_node_get_child_value_str(iter, "fscript", NULL);
str_init(&str, 1000);
ret = remote_ui_exec_fscript(ui, fscript, &str);
check_return_code(ret, expected_ret, name, fscript, str.str, NULL);
str_reset(&str);
} else if (tk_str_eq(name, "send_event")) {
event_t* e = NULL;
const char* target = conf_node_get_child_value_str(iter, "target", NULL);
const char* type = conf_node_get_child_value_str(iter, "type", NULL);
const char* key = conf_node_get_child_value_str(iter, "key", NULL);
const char* x = conf_node_get_child_value_str(iter, "x", NULL);
const char* y = conf_node_get_child_value_str(iter, "y", NULL);
break_if_fail(type != NULL);
if (target == NULL) {
target = STR_PROP_WINDOW;
}
if (strstr(type, "pointer") != NULL || strstr(type, "click") != NULL) {
pointer_event_t event;
if (strstr(type, "down") != NULL) {
e = pointer_event_init(&event, EVT_POINTER_DOWN, NULL, tk_atoi(x), tk_atoi(y));
} else if (strstr(type, "up") != NULL) {
e = pointer_event_init(&event, EVT_POINTER_UP, NULL, tk_atoi(x), tk_atoi(y));
} else if (strstr(type, "click") != NULL) {
e = pointer_event_init(&event, EVT_CLICK, NULL, tk_atoi(x), tk_atoi(y));
} else {
e = pointer_event_init(&event, EVT_POINTER_MOVE, NULL, tk_atoi(x), tk_atoi(y));
}
ret = remote_ui_send_event(ui, target, e);
} else if (strstr(type, "key") != NULL) {
key_event_t event;
const key_type_value_t* kv = keys_type_find(key);
break_if_fail(kv != NULL);
if (strstr(type, "down") != NULL) {
e = key_event_init(&event, EVT_KEY_DOWN, NULL, kv->value);
} else {
e = key_event_init(&event, EVT_KEY_UP, NULL, kv->value);
}
ret = remote_ui_send_event(ui, target, e);
}
check_return_code(ret, expected_ret, name, target, type, NULL);
} else if (tk_str_eq(name, "confirm")) {
const char* title = conf_node_get_child_value_str(iter, "title", NULL);
const char* content = conf_node_get_child_value_str(iter, "content", NULL);
ret = remote_ui_show_confirm(ui, title, content);
check_return_code(ret, expected_ret, name, title, content, NULL);
} else if (tk_str_eq(name, "warn")) {
const char* title = conf_node_get_child_value_str(iter, "title", NULL);
const char* content = conf_node_get_child_value_str(iter, "content", NULL);
ret = remote_ui_show_warn(ui, title, content);
check_return_code(ret, expected_ret, name, title, content, NULL);
} else if (tk_str_eq(name, "info")) {
const char* title = conf_node_get_child_value_str(iter, "title", NULL);
const char* content = conf_node_get_child_value_str(iter, "content", NULL);
ret = remote_ui_show_info(ui, title, content);
check_return_code(ret, expected_ret, name, title, content, NULL);
} else if (tk_str_eq(name, "toast")) {
const char* content = conf_node_get_child_value_str(iter, "content", NULL);
int32_t duration = conf_node_get_child_value_int32(iter, "duration", 3000);
ret = remote_ui_show_toast(ui, duration, content);
check_return_code(ret, expected_ret, name, content, NULL, NULL);
} else if (tk_str_eq(name, "sleep")) {
int32_t time_ms = conf_node_get_child_value_int32(iter, "time", 1000);
sleep_ms(time_ms);
} else if (tk_str_eq(name, "close")) {
remote_ui_destroy(ui);
ui = NULL;
}
iter = iter->next;
if (iter == NULL) {
iter = conf_node_get_first_child(doc->root);
times--;
log_debug("=============%u===============\n", times);
}
if (times == 0) {
break;
}
}
if (ui != NULL) {
remote_ui_destroy(ui);
ui = NULL;
}
}
#include "tkc/data_reader_factory.h"
#include "tkc/data_writer_factory.h"
#include "tkc/data_writer_file.h"
#include "tkc/data_writer_wbuffer.h"
#include "tkc/data_reader_file.h"
#include "tkc/data_reader_mem.h"
int main(int argc, char* argv[]) {
char* data = NULL;
conf_doc_t* doc = NULL;
const char* input = argc > 1 ? argv[1] : "data/fs_default.ini";
uint32_t times = argc > 2 ? tk_atoi(argv[2]) : 1;
platform_prepare();
data_writer_factory_set(data_writer_factory_create());
data_reader_factory_set(data_reader_factory_create());
data_writer_factory_register(data_writer_factory(), "file", data_writer_file_create);
data_reader_factory_register(data_reader_factory(), "file", data_reader_file_create);
data_reader_factory_register(data_reader_factory(), "mem", data_reader_mem_create);
data_writer_factory_register(data_writer_factory(), "wbuffer", data_writer_wbuffer_create);
if (argc < 2) {
log_debug("Usage: %s config times\n", argv[0]);
log_debug(" ex: %s data/tcp.ini\n", argv[0]);
log_debug(" ex: %s data/tcp.ini 10\n", argv[0]);
return 0;
}
tk_socket_init();
data = (char*)file_read(input, NULL);
if (data != NULL) {
doc = conf_doc_load_ini(data);
if (doc != NULL) {
run_script(doc, times);
conf_doc_destroy(doc);
}
TKMEM_FREE(data);
}
tk_socket_deinit();
return 0;
}