middleware文件夹1201patch合并 3349/1 3349/head 3353/target/1
authorluozheng <1732036298@qq.com>
Fri, 17 Apr 2026 09:43:56 +0000 (17:43 +0800)
committerluozheng <1732036298@qq.com>
Fri, 17 Apr 2026 09:43:56 +0000 (17:43 +0800)
443 files changed:
code/sdk/application/wearable/n9/nativeapp/nativeui/saveele/src/SaveBatPresenter.cpp
code/sdk/application/wearable/n9/service/msg_center/src/notify/debug_output_notification/debug_output_notification.cpp
code/sdk/middleware/chips/brandy/CMakeLists.txt
code/sdk/middleware/chips/brandy/dfx/include/log_def_app.h
code/sdk/middleware/chips/brandy/dfx/include/log_def_gui.h
code/sdk/middleware/chips/brandy/dfx/include/log_def_media.h
code/sdk/middleware/chips/brandy/nv/nv_config/cfg/eng/acore/app.json
code/sdk/middleware/chips/brandy/nv/nv_config/cfg/user/acore/app.json
code/sdk/middleware/chips/brandy/nv/nv_config/include/common.h
code/sdk/middleware/chips/brandy/nv/nv_config/include/key_id.h
code/sdk/middleware/chips/brandy/pm/pm_adapt/pm_lp_stub.c
code/sdk/middleware/chips/brandy/pm/service/pm_sleep.c
code/sdk/middleware/chips/brandy/uart_agent/CMakeLists.txt [new file with mode: 0644]
code/sdk/middleware/chips/brandy/uart_agent/app_uart_agent_demo.c [new file with mode: 0644]
code/sdk/middleware/chips/brandy/uart_agent/app_uart_agent_demo.h [new file with mode: 0644]
code/sdk/middleware/chips/brandy/uart_agent/uart_agent.c [new file with mode: 0644]
code/sdk/middleware/chips/brandy/uart_agent/uart_agent.h [new file with mode: 0644]
code/sdk/middleware/chips/brandy/uart_agent/uart_circ_buf.h [new file with mode: 0644]
code/sdk/middleware/services/gpu/api/rm/brandy-auto-ota-cli/libgfx_rm.a
code/sdk/middleware/services/gpu/api/rm/brandy-auto-ota-ser/libgfx_rm.a
code/sdk/middleware/services/gpu/api/rm/brandy-native-js-r/libgfx_rm.a
code/sdk/middleware/services/gpu/api/rm/brandy-native-js/libgfx_rm.a
code/sdk/middleware/services/gpu/api/rm/brandy-target1-r/libgfx_rm.a
code/sdk/middleware/services/gpu/api/rm/brandy-target1/libgfx_rm.a
code/sdk/middleware/services/gpu/api/rm/brandy-target3-r/libgfx_rm.a
code/sdk/middleware/services/gpu/api/rm/brandy-target3/libgfx_rm.a
code/sdk/middleware/services/gpu/api/rm/brandy-target4-r/libgfx_rm.a
code/sdk/middleware/services/gpu/api/rm/brandy-target4/libgfx_rm.a
code/sdk/middleware/services/gpu/api/rm/brandy-target5-r/libgfx_rm.a
code/sdk/middleware/services/gpu/api/rm/brandy-target5/libgfx_rm.a
code/sdk/middleware/services/gpu/api/rm/brandy-xts/libgfx_rm.a
code/sdk/middleware/services/gpu/api/rm/testsuite-brandy-sdk/libgfx_rm.a
code/sdk/middleware/services/gpu/drv/dpu/disp/dpu_disp.c
code/sdk/middleware/services/gpu/drv/dpu/disp/dpu_disp.h
code/sdk/middleware/services/gpu/drv/dpu/isr/dpu_isr.c
code/sdk/middleware/services/gpu/drv/dpu/isr/dpu_isr.h
code/sdk/middleware/services/gpu/drv/dpu/layer/dpu_layer.c
code/sdk/middleware/services/gui/hal/common/include/graphic_hardware_config.h
code/sdk/middleware/services/gui/hal/display/brandy-auto-ota-cli/libdisplay_gfx.a
code/sdk/middleware/services/gui/hal/display/brandy-auto-ota-ser/libdisplay_gfx.a
code/sdk/middleware/services/gui/hal/display/brandy-native-js/libdisplay_gfx.a
code/sdk/middleware/services/gui/hal/display/brandy-target1/libdisplay_gfx.a
code/sdk/middleware/services/gui/hal/display/brandy-target3/libdisplay_gfx.a
code/sdk/middleware/services/gui/hal/display/brandy-target5/libdisplay_gfx.a
code/sdk/middleware/services/gui/hal/display/brandy-xts/libdisplay_gfx.a
code/sdk/middleware/services/gui/lvgl/brandy-target1/liblvgl_proprietary_mini.a
code/sdk/middleware/services/gui/lvgl/brandy-target5/liblvgl_proprietary.a
code/sdk/middleware/services/gui/lvgl/proprietary/service/graphic_service_wrapper.h
code/sdk/middleware/services/gui/uikit/CMakeLists.txt
code/sdk/middleware/services/gui/uikit/brandy-auto-ota-cli/libuikit_ext.a
code/sdk/middleware/services/gui/uikit/brandy-auto-ota-ser/libuikit_ext.a
code/sdk/middleware/services/gui/uikit/brandy-native-js/libuikit_ext.a
code/sdk/middleware/services/gui/uikit/brandy-target3/libuikit_ext.a
code/sdk/middleware/services/gui/uikit/brandy-xts/libuikit_ext.a
code/sdk/middleware/services/gui/uikit/proprietary/include/common/graphic_cond_ext.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/include/common/image_cache_manager.h
code/sdk/middleware/services/gui/uikit/proprietary/include/common/lite_surface.h
code/sdk/middleware/services/gui/uikit/proprietary/include/common/periodicupdate_interface.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/include/common/ui_emoji_table.h
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_canvas_ext.h
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_chart_pillar_ext.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_coverflow_view.h
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_cross_view.h
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_custom_planet_list.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_float_box_view.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_foldable_view.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_kaleidoscope_view.h
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_list_nested.h
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_lite_surface_view.h
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_particle_view.h
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_planet_list.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_scatter_plot.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_scroll_view_nested.h
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_simple_list.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_slipflow_view.h
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_swipe_view_nested.h
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_transform_group.h
code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_transform_list.h
code/sdk/middleware/services/gui/uikit/proprietary/include/dfx/dfx_frame_trace.h
code/sdk/middleware/services/gui/uikit/proprietary/include/dfx/dfx_traceui.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_bezier.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_comp.h
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_ellipse.h
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_layer.h
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_math.h
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_parser.h
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_path.h
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_precomp_layer.h
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_property.h
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_rect.h
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_shape.h
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_shape_group.h
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_shape_layer.h
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_trim.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_trim_path.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/ui_lott_view.h
code/sdk/middleware/services/gui/uikit/proprietary/include/service/graphic_service.h
code/sdk/middleware/services/gui/uikit/proprietary/src/service/src/graphic_service.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/service/src/graphic_service_wrapper.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/common/graphic_cond_ext.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/common/lite_surface.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/common_adapter.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/common_adapter.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/ui_input_method.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/ui_list_ext.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/ui_lite_surface_view.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/ui_menu_item.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/ui_sweep_clock.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/ui_transform_button.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/ui_transform_button.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components_ext/map_svg_parser.h
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components_ext/ui_card_container.h
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/dfx_cmd.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/dfx_dom_dump.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/dfx_frame_trace.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/fps_task.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/fps_task.h
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_buf.c [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_buf.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_convert_perfetto_proto.c [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_core.c [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_core.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_os.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/draw/clip_img.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/draw/clip_img.h
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/draw/hw_draw_utils.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/draw/hw_draw_utils.h
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/engines/gfx/lite_m_gfx_engine.h
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/imgdecode/hw_jpeg_decoder.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/imgdecode/jpeg_img_decoder.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/imgdecode/jpeg_img_decoder.h
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/card_flip_effect.h
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/cube_effect.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/cube_effect.h
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/push_press_effect.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/push_press_effect.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/windmill_effect.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/windmill_effect.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/zoom_effect.h
code/sdk/middleware/services/gui/uikit/proprietary/src/ui/innerkits/input_method/ui_option_box.h
code/sdk/middleware/services/gui/uikit/proprietary/src/utils/frameworks/hals/display_dev.cpp
code/sdk/middleware/services/gui/uikit/proprietary/src/utils/innerkits/hals/display_dev.h
code/sdk/middleware/services/gui/uikit/sample/CMakeLists.txt
code/sdk/middleware/services/gui/uikit/sample/sample_ui.cpp
code/sdk/middleware/services/gui/uikit/sample/sample_ui.h
code/sdk/middleware/services/gui/uikit/sample/sample_util.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/sample_util.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_analog_clock/test_resource_config.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_analog_clock/ui_test_analog_clock.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_analog_clock/ui_test_analog_clock.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_animator/ui_test_animator.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_animator/ui_test_animator.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_bitmap_font/ui_test_bitmap_font.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_bitmap_font/ui_test_bitmap_font.h
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_border_margin_padding/ui_test_border_listener.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_border_margin_padding/ui_test_border_margin_padding.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_border_margin_padding/ui_test_border_margin_padding.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_button/ui_test_button.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_button/ui_test_button.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_canvas/ui_test_canvas.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_canvas/ui_test_canvas.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_chart/ui_test_chart_pillar.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_chart/ui_test_chart_pillar.h
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_chart/ui_test_chart_polyline.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_chart/ui_test_scatter_plot.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_chart/ui_test_scatter_plot.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_clock_dial/UiConfig.h
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_clock_dial/ui_test_clock_dial.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_clock_dial/ui_test_clock_dial.h
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_cross/ui_test_cross.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_digital_clock/ui_test_digital_clock.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_digital_clock/ui_test_digital_clock.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_draw/ui_test_canvas_ext.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_draw/ui_test_canvas_ext.h
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_draw_line/ui_test_draw_line.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_draw_line/ui_test_draw_line.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_dump_dom_tree/cJSON.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_dump_dom_tree/test_resource_config.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_dump_dom_tree/ui_dump_dom_tree.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_dump_dom_tree/ui_test_dump_dom.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_dump_dom_tree/ui_test_dump_dom.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_event_injector/ui_test_event_injector.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_event_injector/ui_test_event_injector_view.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_event_injector/ui_test_event_injector_view.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_float_box/ui_test_float_box.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_float_box/ui_test_float_box.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_focus_manager/ui_test_focus_manager.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_focus_manager/ui_test_focus_manager.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_foldable/ui_test_foldable.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_foldable/ui_test_foldable.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_font/ui_test_font.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_font/ui_test_font_global.h
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_image/ui_test_png.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_image/ui_test_png.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_image_animator/ui_test_image_animator.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_image_animator/ui_test_image_animator.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_input_event/ui_test_input_event.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_input_event/ui_test_input_event.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_kaleidoscope/ui_test_kaleidoscope.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_kaleidoscope/ui_test_kaleidoscope.h
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_list_fps/image_text_adapter.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_lottie/ui_test_lottie.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_lottie/ui_test_lottie.h
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_message/ui_test_message.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_message/ui_test_message.h
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_opacity/ui_test_opacity.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_opacity/ui_test_opacity.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_picker/ui_test_ui_picker.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_picker/ui_test_ui_picker.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_progress_bar/ui_test_box_progress.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_progress_bar/ui_test_box_progress.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_progress_bar/ui_test_circle_progress.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_progress_bar/ui_test_circle_progress.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_qrcode/ui_test_qrcode.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_render/ui_test_render.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_render/ui_test_render.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_roller_view/ui_test_roller_view.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_rotate_input/ui_test_rotate_input.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_rotate_input/ui_test_rotate_input.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_scroll_bar/ui_test_scroll_bar.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_scroll_bar/ui_test_scroll_bar.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_simple_list/ui_test_simple_list.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_simple_list/ui_test_simple_list.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_simple_list/ui_test_simple_transform_list.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_simple_list/ui_test_simple_transform_list.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_slipflow/ui_test_slipflow.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_slipflow/ui_test_slipflow.h
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_adapter.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_adapter.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_itemview.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_itemview.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_model.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_model.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_sample.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_view.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_view.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_list/ui_test_ui_list.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_list/ui_test_ui_list.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_list_view/ui_test_list_layout.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_list_view/ui_test_list_layout.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_scroll_view/test_on_scroll_listener.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_scroll_view/ui_test_ui_scroll_view.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_scroll_view/ui_test_ui_scroll_view.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_swipe_view/ui_test_ui_swipe_view.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_swipe_view/ui_test_ui_swipe_view.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_vector_font/ui_test_vector_font.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_vector_font/ui_test_vector_font.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_video_play/ui_test_video_play.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/alignment.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_dynamic.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_dynamic.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_external.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_external.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_internal.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_internal.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bitmap/test_resource_config.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bitmap/ui_test_view_bitmap.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bitmap/ui_test_view_bitmap.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bounds/test_resource_config.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bounds/ui_test_view_bounds.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bounds/ui_test_view_bounds.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_group/ui_test_view_group.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_group/ui_test_view_group.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_percent/ui_test_view_percent.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_percent/ui_test_view_percent.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_scale_rotate/test_resource_config.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_scale_rotate/ui_test_view_scale_rotate.cpp [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_scale_rotate/ui_test_view_scale_rotate.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/sample/uitest/framework/src/ui_test_app.cpp
code/sdk/middleware/services/gui/uikit/sample/uitest/framework/src/ui_test_group.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/animator/animator_manager.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/common/image.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/common/input_device_manager.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/common/screen.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/components/root_view.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/components/text_adapter.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/components/ui_box_progress.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/components/ui_button.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/components/ui_chart.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/components/ui_checkbox.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/components/ui_circle_progress.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/components/ui_digital_clock.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/components/ui_image_view.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/components/ui_label.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/components/ui_list.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/components/ui_scroll_view.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/components/ui_slider.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/components/ui_view.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/components/ui_view_group.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/core/render_manager.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/core/task_manager.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/default_resource/check_box_res.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/dock/pointer_input_device.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/engines/gfx/gfx_engine_manager.cpp
code/sdk/middleware/services/gui/uikit/ui/frameworks/imgdecode/cache_manager.cpp
code/sdk/middleware/services/gui/uikit/ui/interfaces/innerkits/engines/gfx/gfx_engine_manager.h
code/sdk/middleware/services/gui/uikit/ui/interfaces/kits/common/alignment.h [new file with mode: 0644]
code/sdk/middleware/services/gui/uikit/ui/interfaces/kits/common/screen.h
code/sdk/middleware/services/gui/uikit/ui/interfaces/kits/components/root_view.h
code/sdk/middleware/services/gui/uikit/ui/interfaces/kits/components/ui_chart.h
code/sdk/middleware/services/gui/uikit/ui/interfaces/kits/components/ui_label.h
code/sdk/middleware/services/gui/uikit/ui/interfaces/kits/components/ui_video.h
code/sdk/middleware/services/gui/uikit/ui/interfaces/kits/components/ui_view.h
code/sdk/middleware/services/gui/uikit/ui/interfaces/kits/components/ui_view_group.h
code/sdk/middleware/services/gui/uikit/utils/frameworks/graphic_math.cpp
code/sdk/middleware/services/gui/uikit/utils/frameworks/graphic_timer.cpp
code/sdk/middleware/services/gui/uikit/utils/frameworks/style.cpp
code/sdk/middleware/services/gui/uikit/utils/interfaces/innerkits/graphic_config.h
code/sdk/middleware/services/gui/uikit/utils/interfaces/innerkits/graphic_mutex.h
code/sdk/middleware/services/gui/uikit/utils/interfaces/kits/gfx_utils/style.h
code/sdk/middleware/services/media/CMakeLists.txt
code/sdk/middleware/services/media/foundation/CMakeLists.txt
code/sdk/middleware/services/media/foundation/audio_capturer/interfaces/kits/audio_capturer_lite/recording_module.cpp
code/sdk/middleware/services/media/foundation/audio_capturer/interfaces/kits/audio_capturer_lite/recording_module.h
code/sdk/middleware/services/media/foundation/audio_recorder/CMakeLists.txt [new file with mode: 0644]
code/sdk/middleware/services/media/foundation/audio_recorder/frameworks/CMakeLists.txt [new file with mode: 0644]
code/sdk/middleware/services/media/foundation/audio_recorder/frameworks/audio_recorder.c [new file with mode: 0644]
code/sdk/middleware/services/media/foundation/audio_recorder/frameworks/muxer/include/audio_recorder_muxer.h [new file with mode: 0644]
code/sdk/middleware/services/media/foundation/audio_recorder/frameworks/muxer/src/audio_recorder_muxer.c [new file with mode: 0644]
code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/audio_recorder.h [new file with mode: 0644]
code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/kits/audio_recorder_lite/CMakeLists.txt [new file with mode: 0644]
code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/kits/audio_recorder_lite/include/audio_recorder_listener.h [new file with mode: 0644]
code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/kits/audio_recorder_lite/include/audio_recorder_module.h [new file with mode: 0644]
code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/kits/audio_recorder_lite/src/audio_recorder_listener.cpp [new file with mode: 0644]
code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/kits/audio_recorder_lite/src/audio_recorder_module.cpp [new file with mode: 0644]
code/sdk/middleware/services/media/foundation/audiomanager/frameworks/audioservice/src/streammanager/include/source_handle.h
code/sdk/middleware/services/media/foundation/audiomanager/frameworks/audioservice/src/streammanager/src/source_handle.c
code/sdk/middleware/services/media/foundation/audiomanager/frameworks/audiostream/include/c/audio_stream_in.h
code/sdk/middleware/services/media/foundation/audiomanager/frameworks/audiostream/src/cpp/audio_stream_in.cpp
code/sdk/middleware/services/media/foundation/audiomanager/interfaces/kits/audiocommon/audio_base_type.h
code/sdk/middleware/services/media/foundation/audiomanager/interfaces/kits/audiocommon/audio_errors.h
code/sdk/middleware/services/media/foundation/player/frameworks/CMakeLists.txt
code/sdk/middleware/services/media/foundation/player/frameworks/player_control/include/hi_liteplayer.h
code/sdk/middleware/services/media/foundation/player/frameworks/player_control/include/player_define.h
code/sdk/middleware/services/media/foundation/player/frameworks/player_control/player/liteplayer.cpp
code/sdk/middleware/services/media/foundation/player/frameworks/player_control/player/liteplayer.h
code/sdk/middleware/services/media/foundation/player/frameworks/player_control/player/liteplayer_define.h
code/sdk/middleware/services/media/foundation/player/frameworks/player_control/sink/player_audio_sink.cpp
code/sdk/middleware/services/media/foundation/player/frameworks/player_control/sink/player_sink_manager.cpp
code/sdk/middleware/services/media/foundation/player/frameworks/player_control/sink/player_sync.cpp
code/sdk/middleware/services/media/foundation/player/frameworks/player_control/sink/player_sync.h
code/sdk/middleware/services/media/foundation/player/frameworks/player_control/sink/player_video_sink.cpp
code/sdk/middleware/services/media/foundation/player/frameworks/player_control/source/player_demux.cpp
code/sdk/middleware/services/media/foundation/player/frameworks/player_impl.cpp
code/sdk/middleware/services/media/foundation/player/frameworks/player_impl.h
code/sdk/middleware/services/media/foundation/player/interfaces/kits/player.h
code/sdk/middleware/services/media/foundation/sample/wrapper/CMakeLists.txt
code/sdk/middleware/services/media/foundation/sample/wrapper/audio_capture_wrapper.cpp
code/sdk/middleware/services/media/foundation/sample/wrapper/audio_manager_c_wrapper.cpp
code/sdk/middleware/services/media/foundation/sample/wrapper/audio_manager_c_wrapper.h
code/sdk/middleware/services/media/foundation/sample/wrapper/audio_player_service.h
code/sdk/middleware/services/media/foundation/sample/wrapper/audio_recorder_sample.cpp [new file with mode: 0644]
code/sdk/middleware/services/media/foundation/sample/wrapper/audio_recorder_sample.h [new file with mode: 0644]
code/sdk/middleware/services/media/foundation/sample/wrapper/player_sample_wrapper.cpp
code/sdk/middleware/services/media/foundation/sample/wrapper/video_play_wrapper.cpp
code/sdk/middleware/services/media/foundation/sample/wrapper/voice_call_volte_sample_wrapper.cpp
code/sdk/middleware/services/media/foundation/utils/src/media_thread_adapt.cpp
code/sdk/middleware/services/media/hal/audio/plugins/brandy/bluetooth/bluetooth_sub_port.c
code/sdk/middleware/services/media/hal/audio/plugins/brandy/common/include/plugin_common.h
code/sdk/middleware/services/media/hal/audio/plugins/brandy/common/src/plugin_common.c
code/sdk/middleware/services/media/hal/audio/plugins/brandy/primary/primary_sub_port_in.c
code/sdk/middleware/services/media/hal/audio/plugins/brandy/primary/primary_sub_port_out.c
code/sdk/middleware/services/media/hal/audio/src/audio_capture.c
code/sdk/middleware/services/media/hal/camera/hw_camera/src/virtual_camera_impl.c
code/sdk/middleware/services/media/hal/codec/plugins/brandy/video_decoder/native_vdec_jpeg.c
code/sdk/middleware/services/media/hal/common/include/media_hal_common.h
code/sdk/middleware/services/media/hal/common/src/media_hal_common.c
code/sdk/middleware/services/media/hal/common/src/media_hal_thread_adapt.c
code/sdk/middleware/services/media/hal/format/CMakeLists.txt
code/sdk/middleware/services/media/hal/format/include/demuxer_common.h
code/sdk/middleware/services/media/hal/format/include/demuxer_interface.h
code/sdk/middleware/services/media/hal/format/include/muxer_interface.h
code/sdk/middleware/services/media/hal/format/include/plugin_common.h
code/sdk/middleware/services/media/hal/format/plugins/common/dtcf/CMakeLists.txt [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/common/dtcf/include/dtcf.h [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/common/dtcf/include/dtcf_qsort.h [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/common/dtcf/src/dtcf.c [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/common/dtcf_manager/CMakeLists.txt [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/common/dtcf_manager/include/dtcf_manager.h [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/common/dtcf_manager/src/dtcf_manager.c [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/ffmpeg_demuxer/CMakeLists.txt [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/ffmpeg_demuxer/ff_demuxer_plugin.h [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/ffmpeg_demuxer/ff_format.h [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/ffmpeg_demuxer/ff_wrapper.h [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/ogg_muxer/CMakeLists.txt [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/ogg_muxer/ogg_manager.c [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/ogg_muxer/ogg_manager.h [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/ogg_muxer/ogg_muxer.c [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/ogg_muxer/ogg_muxer.h [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/raw_muxer/CMakeLists.txt [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/raw_muxer/raw_muxer.c [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/raw_muxer/raw_muxer.h [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/wav_muxer/CMakeLists.txt [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/wav_muxer/wav.c [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/wav_muxer/wav.h [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/wav_muxer/wav_muxer.c [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/plugins/wav_muxer/wav_muxer.h [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/src/demuxer_manager/src/demuxer_buffer.c [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/src/demuxer_manager/src/demuxer_buffer.h [new file with mode: 0644]
code/sdk/middleware/services/media/hal/format/src/demuxer_manager/src/demuxer_manager.c
code/sdk/middleware/services/media/hal/format/src/demuxer_plugins_manager/include/demuxer_plugins_manager.h
code/sdk/middleware/services/media/hal/format/src/demuxer_plugins_manager/src/demuxer_plugins_manager.c
code/sdk/middleware/services/media/hal/format/src/format_manager.c
code/sdk/middleware/services/media/hal/format/src/muxer_manager/src/muxer_manager.c
code/sdk/middleware/services/media/hal/format/src/muxer_plugins_manager/src/muxer_plugins_manager.c
code/sdk/middleware/services/media/hal_release/liteos/format/libs/js/libhmf_demuxer.a
code/sdk/middleware/services/media/hal_release/liteos/format/libs/js/libplugin_demuxer_hmf.a
code/sdk/middleware/services/media/hal_release/liteos/format/libs/js/libplugin_demuxer_mjpeg.a
code/sdk/middleware/services/media/hal_release/liteos/format/libs/js/libplugin_protocol_https.a
code/sdk/middleware/utils/fs/vfs/brandy-auto-ota-cli/libx_vfs_private.a
code/sdk/middleware/utils/fs/vfs/brandy-auto-ota-ser/libx_vfs_private.a
code/sdk/middleware/utils/fs/vfs/brandy-native-js-r/libx_vfs_private.a
code/sdk/middleware/utils/fs/vfs/brandy-native-js/libx_vfs_private.a
code/sdk/middleware/utils/fs/vfs/brandy-target1-r/libx_vfs_private.a
code/sdk/middleware/utils/fs/vfs/brandy-target1/libx_vfs_private.a
code/sdk/middleware/utils/fs/vfs/brandy-target3-r/libx_vfs_private.a
code/sdk/middleware/utils/fs/vfs/brandy-target3/libx_vfs_private.a
code/sdk/middleware/utils/fs/vfs/brandy-target4-r/libx_vfs_private.a
code/sdk/middleware/utils/fs/vfs/brandy-target4/libx_vfs_private.a
code/sdk/middleware/utils/fs/vfs/brandy-target5-r/libx_vfs_private.a
code/sdk/middleware/utils/fs/vfs/brandy-target5/libx_vfs_private.a
code/sdk/middleware/utils/fs/vfs/brandy-xts-r/libx_vfs_private.a
code/sdk/middleware/utils/fs/vfs/brandy-xts/libx_vfs_private.a
code/sdk/middleware/utils/fs/vfs/testsuite-brandy-sdk/libx_vfs_private.a
code/sdk/middleware/utils/fs/yaffs2/brandy-auto-ota-cli/libfs_yaffs2.a
code/sdk/middleware/utils/fs/yaffs2/brandy-auto-ota-ser/libfs_yaffs2.a
code/sdk/middleware/utils/fs/yaffs2/brandy-native-js-r/libfs_yaffs2.a
code/sdk/middleware/utils/fs/yaffs2/brandy-native-js/libfs_yaffs2.a
code/sdk/middleware/utils/fs/yaffs2/brandy-target1-r/libfs_yaffs2.a
code/sdk/middleware/utils/fs/yaffs2/brandy-target1/libfs_yaffs2.a
code/sdk/middleware/utils/fs/yaffs2/brandy-target3-r/libfs_yaffs2.a
code/sdk/middleware/utils/fs/yaffs2/brandy-target3/libfs_yaffs2.a
code/sdk/middleware/utils/fs/yaffs2/brandy-target4-r/libfs_yaffs2.a
code/sdk/middleware/utils/fs/yaffs2/brandy-target4/libfs_yaffs2.a
code/sdk/middleware/utils/fs/yaffs2/brandy-target5-r/libfs_yaffs2.a
code/sdk/middleware/utils/fs/yaffs2/brandy-target5/libfs_yaffs2.a
code/sdk/middleware/utils/fs/yaffs2/brandy-xts-r/libfs_yaffs2.a
code/sdk/middleware/utils/fs/yaffs2/brandy-xts/libfs_yaffs2.a
code/sdk/middleware/utils/fs/yaffs2/testsuite-brandy-sdk/libfs_yaffs2.a
code/sdk/zhihui/ai/media/ai_media_service_ext.cpp
code/sdk/zhihui/utils/custom_utils.c
code/sdk/zhihui/utils/custom_utils.h
code/sdk/zhihui/utils/custom_utils_at_cmd.c

index 985c67a..83b7d27 100644 (file)
@@ -49,22 +49,7 @@ SaveBatPresenter *SaveBatPresenter::GetInstance() {
   return g_pSaveBatPresenter;\r
 }\r
 \r
-/*\r
-  void enable_drag(uint8_t direction, uint8_t enable);\r
-  void set_drag_limit(uint8_t direction, uint16_t limit);\r
-  uint16_t get_drag_limit(uint8_t direction);\r
-*/\r
 void SaveBatPresenter::OnStart() {\r
-  Presenter<SaveBatView>::OnStart();\r
-  // 1.获取原drag\r
-  #ifdef CUSTOM_UTILS\r
-  // drag_x = get_drag_limit(0);\r
-  // drag_y = get_drag_limit(1);\r
- \r
-  WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "drag_x:%d,drag_y:%d", drag_x, drag_y);\r
-  // 2.设置drag\r
-  // enable_drag(0, 0);\r
-  // enable_drag(1, 0);\r
   #endif\r
 }\r
 \r
index 6185732..6dcd150 100644 (file)
@@ -1624,8 +1624,6 @@ namespace OHOS
             /* -------------------------------------------------------------------------- */
             NotificationManager::GetInstance()->RegisterNotifyCleanupFunction(FreeDebugOutputMainView);
             /* -------------------------------------------------------------------------- */
-            enable_drag(0, 1);
-            enable_drag(1, 1);
         }
         return DebugGroupView;
     }
@@ -1659,11 +1657,6 @@ namespace OHOS
             DebugGroupView = nullptr;
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "FreeDebugOutputMainView success!!");
         }
-        if (uapi_dev_runtime_get_saveele_status() == 1) // 如果省电模式开启,该调试窗口关闭时候恢复原状态
-        {
-            enable_drag(0, 0);
-            enable_drag(1, 0);
-        }
         return;
     }
 }
index 3ccd3bb..20f63d3 100644 (file)
@@ -9,3 +9,4 @@ add_subdirectory_if_exist(pm)
 add_subdirectory_if_exist(partition)
 add_subdirectory_if_exist(update)
 add_subdirectory_if_exist(nv)
+add_subdirectory_if_exist(uart_agent)
\ No newline at end of file
index f2f5628..9fcc8d1 100644 (file)
@@ -16,14 +16,11 @@ typedef enum {
     ABILITYSLICE_CPP,
     NATIVEABILITY_CPP,
     NATIVELAUNCHER_CPP,
-    SETTINGMAINPAGE_CPP,
     SLICEPAGE_CPP,
     VIEW_CPP,
     SLICEPAGEFACTORY_CPP,
     SLICEPAGEMANAGER_CPP,
     BACKDRAGLISTENER_CPP,
-    MAINVIEW_CPP,
-    MAINMODEL_CPP,
     ACTIVITYMODEL_CPP,
     ACTIVITYPRESENTER_CPP,
     ACTIVITYWEEKVIEW_CPP,
@@ -72,9 +69,6 @@ typedef enum {
     APPLISTMODEL_CPP,
     APPLISTPRESENTER_CPP,
     APPLISTVIEW_CPP,
-    BLOODBANDOFFVIEW_CPP,
-    BLOODOXYGENPRESENTER_CPP,
-    BLOODOXYGENVIEW_CPP,
     BLUETOOTHCASELISTADAPTER_CPP,
     BLUETOOTHDEVICECASELISTADAPTER_CPP,
     BLUETOOTHDEVICELISTVIEW_CPP,
@@ -90,9 +84,6 @@ typedef enum {
     TIPSCONNFAILMESSAGEVIEW_CPP,
     TIPSFAILMESSAGEVIEW_CPP,
     TIPSSUCCMESSAGEVIEW_CPP,
-    CALLERLOGMODEL_CPP,
-    CALLERLOGPRESENTER_CPP,
-    CALLERLOGVIEW_CPP,
     MAINCLOCKVIEW_CPP,
     AMBIENTCLOCKVIEW_CPP,
     AODVIEW_CPP,
@@ -106,40 +97,39 @@ typedef enum {
     CONNECTPHONEPRESENTER_CPP,
     CONNECTPHONEVIEW_CPP,
     CONNECTSELECTVIEW_CPP,
-    HEARTMODEL_CPP,
-    HEARTRATEVIEW_CPP,
     CUSTOMIZATIONVIEW_CPP,
-    DIALVIEW_CPP,
-    DIALVIEWGROUP_CPP,
-    DIALARCLABELVIEW_CPP,
+    DIALARCLABELVIEW_CPP, // main start
     DIALARCPROGRESSVIEW_CPP,
     DIALBOXPROGRESSVIEW_CPP,
+    DIALDATABASE_CPP,
     DIALDIGITALIMGVIEW_CPP,
     DIALLABELVIEW_CPP,
+    DIALMODELARCPROGRESS_CPP,
+    DIALMODELHEARTRATE_CPP,
+    DIALMODELPOWER_CPP,
+    DIALMODELSTEPS_CPP,
     DIALOPTIONIMGVIEW_CPP,
     DIALROTATEIMGVIEW_CPP,
     DIALSEQUENCEIMGVIEW_CPP,
     DIALSTATICIMGVIEW_CPP,
     DIALVIDEOVIEW_CPP,
+    DIALVIEWCONTAINER_CPP,
+    DIALVIEWGROUP_CPP,
+    MODELDIALDATAFACTORY_CPP,
     DIALBINPARSER_CPP,
-    INDOORWALKENDVIEW_CPP,
-    INDOORWALKMODEL_CPP,
-    INDOORWALKMOTIONVIEW_CPP,
-    INDOORWALKPREPAREDVIEW_CPP,
-    INDOORWALKPRESENTER_CPP,
-    INDOORWALKVIEW_CPP,
-    MOTIONPAGEFIFTH_CPP,
-    MOTIONPAGEFIRST_CPP,
-    MOTIONPAGEFOURTH_CPP,
-    MOTIONPAGESECOND_CPP,
-    MOTIONPAGETHIRD_CPP,
     HEALTHMODEL_CPP,
+    LOADIMG_CPP,
+    MAINMODEL_CPP,
     MAINPRESENTERSAMPLE_CPP,
     MAINVIEWSAMPLE_CPP,
+    MESSAGEDETAILSGROUP_CPP,
+    MESSAGEITEMVIEW_CPP,
+    MESSAGEMAINPAGE_CPP,
+    MESSAGEMODEL_CPP,
     MODELLISTENERSAMPLE_CPP,
     PULLUPDOWNVIEW_CPP,
     VOLUMESETTINGPRESENTER_CPP,
-    VOLUMESETTINGVIEW_CPP,
+    VOLUMESETTINGVIEW_CPP, // main end
     CALLERDISPLAYVIEW_CPP,
     CALLINGVIEW_CPP,
     DIALINGSCREENVIEW_CPP,
@@ -157,32 +147,9 @@ typedef enum {
     PLAYERSMODEL_CPP,
     PLAYERSPRESENTER_CPP,
     PLAYERSVIEW_CPP,
-    REBOOTDEVICEVIEW_CPP,
-    REBOOTPRESENTER_CPP,
-    REBOOTVIEW_CPP,
-    SHUTDOWNDEVICEVIEW_CPP,
     RTCSERVICE_CPP,
     UI_SCREENNOTIFY_CPP,
     SCREENMODELS_CPP,
-    SETTINGPRESENTER_CPP,
-    SETTINGVIEW_CPP,
-    TEMPCLICKMEA_CPP,
-    TEMPCONTINUEWARN_CPP,
-    TEMPEXITINTER_CPP,
-    TEMPEXITPROMPT_CPP,
-    TEMPINITINTER_CPP,
-    TEMPJOINSTUDY_CPP,
-    TEMPLITTLETIP_CPP,
-    TEMPMAINVIEW_CPP,
-    TEMPMEAPROCESS_CPP,
-    TEMPMEASURE_CPP,
-    TEMPMODEL_CPP,
-    TEMPPRESENTER_CPP,
-    TEMPPROMPTWEAR_CPP,
-    TEMPREMINDWEAR_CPP,
-    TEMPREPORT_CPP,
-    TEMPSTUDYABOUT_CPP,
-    TEMPWARN_CPP,
     UISAMPLEPRESENTER_CPP,
     UISAMPLEVIEW_CPP,
     UI_SERVICE_CPP,
@@ -211,27 +178,10 @@ typedef enum {
     XIAODU_VOICE_CPP,
     AUDIO_STREAM_CPP,
     APP_STORE_CPP,
+    DIAL_MARKET_CPP,
     SMART_VOICE_SERVICE_C,
     VOICE_ENGINE_HAL_C,
     OHOSFWK_AT_PROCESS_CPP,
-    SETCARDADAPTER_CPP,
-    SETCARDITEM_CPP,
-    SETCARDDELETEVIEW_CPP,
-    SETCARDVIEW_CPP,
-    SETCARDNOCARDVIEW_CPP,
-    SETCARDPRESENTER_CPP,
-    SETCARDMODEL_CPP,
-    ADDCARDPRESENTER_CPP,
-    ADDCARDADAPTER_CPP,
-    ADDCARDVIEW_CPP,
-    ADDCARDMODEL_CPP,
-    ADDCARDITEM_CPP,
-    SETDIALVIEW_CPP,
-    SETDIALMODEL_CPP,
-    SETDIALPRESENTER_CPP,
-    SETDESKTOPMODEL_CPP,
-    SETDESKTOPVIEW_CPP,
-    SETDESKTOPPRESENTER_CPP,
     DISPLAY_STATE_MACHINE_C,
     POWER_DISPLAY_SERVICE_C,
     GUI_EVENT_FILTER_C,
@@ -244,12 +194,193 @@ typedef enum {
     ALIPAY_BLUETOOTH_C,
     MSG_CENTER_COMMON_CPP,
     MSG_CENTER_HC_DEMO_CPP,
-    REBOOTMODEL_CPP,
     RESTOREDEFAULTSVIEW_CPP,
     RESTOREPRESENTER_CPP,
     RESTORESELECTVIEW_CPP,
     LOCATION_SAMPLE_CPP,
-       SENSOR_SAMPLE_CPP,
+    SENSOR_SAMPLE_CPP,
+    UI_LANGUAGE_CPP,
+    DEVICE_MSG_CPP,
+    DEVICE_PROXY_CPP,
+    MSG_CENTER_DEVICE_CPP,
+    MSG_CENTER_SELF_CMD_CPP,
+    PHONE_MSG_NOTIFICATION_CPP,
+    REMOTE_MSG_CPP,
+    APP_AT_PROCESS_C,
+    BLOODCHARTPAGE_CPP,
+    BLOODEXPLAINPAGE_CPP,
+    BLOODMAINPAGE_CPP,
+    BLOODMEASUREMENTPAGE_CPP,
+    BLOODMODEL_CPP,
+    BLOODPRESENTER_CPP,
+    BLOODREADYPAGE_CPP,
+    BLOODRESULTPAGE_CPP,
+    BREATHEXERPAGE_CPP,
+    BREATHMAINPAGE_CPP,
+    BREATHMODEL_CPP,
+    BREATHPRESENTER_CPP,
+    BREATHRESULTPAGE_CPP,
+    BREATHRHYTHMSETPAGE_CPP,
+    BREATHSTARTPAGE_CPP,
+    BREATHTIMESETPAGE_CPP,
+    BREATHTRAININGRECORDSPAGE_CPP,
+    CAMERAMAINVIEW_CPP,
+    CAMERAMODEL_CPP,
+    CAMERAPRESENTER_CPP,
+    DATEBUTTONITEMVIEW_CPP,
+    DATECONTENTITEMVIEW_CPP,
+    DATEMAINPAGE_CPP,
+    DATEMESSAGEPAGE_CPP,
+    DATEMODEL_CPP,
+    DATEPRESENTER_CPP,
+    EMPTYPAGE_CPP,
+    EMPTYPRESENTER_CPP,
+    FINDPHONEMAINPAGE_CPP,
+    FINDPHONEMODEL_CPP,
+    FINDPHONEPRESENTER_CPP,
+    FLASHLIGHTBLINKPAGE_CPP,
+    FLASHLIGHTCOLORPAGE_CPP,
+    FLASHLIGHTMODEL_CPP,
+    FLASHLIGHTPAGE_CPP,
+    FLASHLIGHTPLAYPAGE_CPP,
+    FLASHLIGHTPRESENTER_CPP,
+    FLASHLIGHTRECOVERPAGE_CPP,
+    FLASHLIGHTSETITEMVIEW_CPP,
+    FLASHLIGHTSETPAGE_CPP,
+    HEARTRATEMAINPAGE_CPP,
+    HEARTRATEMEASUREPAGE_CPP,
+    HEARTRATEMODEL_CPP,
+    HEARTRATEPRESENTER_CPP,
+    HEARTRATEREADYPAGE_CPP,
+    HEARTRATERESULTGROUP_CPP,
+    MONKEYMODEL_CPP,
+    MONKEYPAGE_CPP,
+    MONKEYPRESENTER_CPP,
+    PHONEMENUCALLERLOGITEMVIEW_CPP,
+    PHONEMENUCALLERLOGMODEL_CPP,
+    PHONEMENUCALLERLOGPAGE_CPP,
+    PHONEMENUCALLINGPAGE_CPP,
+    PHONEMENUCONTACTSITEMVIEW_CPP,
+    PHONEMENUCONTACTSPAGE_CPP,
+    PHONEMENUDIALPAGE_CPP,
+    PHONEMENUDISCONNECTPAGE_CPP,
+    PHONEMENUMAINITEMVIEW_CPP,
+    PHONEMENUMAINPAGE_CPP,
+    PHONEMENUNOCANTACTSPAGE_CPP,
+    PHONEMENUPRESENTER_CPP,
+    PHONEMENUSYNC_CPP,
+    SETTINGBLUETOOTHITEMGROUP_CPP,
+    SETTINGCARDADDITEMGROUP_CPP,
+    SETTINGCARDEFFECTITEMGROUP_CPP,
+    SETTINGCARDMGRITEMGROUP_CPP,
+    SETTINGDESKTOPHOMEITEMGROUP_CPP,
+    SETTINGTOGGLEBUTTON_CPP,
+    SETTINGUNIONITEMGROUP_CPP,
+    SETTINGABOUTMODEL_CPP,
+    SETTINGBLUETOOTHMODEL_CPP,
+    SETTINGCARDMODEL_CPP,
+    SETTINGDESKTOPMODEL_CPP,
+    SETTINGDISPLAYMODEL_CPP,
+    SETTINGMAINMODEL_CPP,
+    SETTINGPOWERMODEL_CPP,
+    SETTINGQRCODECONNMODEL_CPP,
+    SETTINGSYSTEMMODEL_CPP,
+    SETTINGABOUTPAGE_CPP,
+    SETTINGBLUETOOTHPAGE_CPP,
+    SETTINGBLUETOOTHWRAPPER_CPP,
+    SETTINGCARDADDPAGE_CPP,
+    SETTINGCARDEFFECTPAGE_CPP,
+    SETTINGCARDMGRPAGE_CPP,
+    SETTINGCARDPAGE_CPP,
+    SETTINGCONNECTBLUEFAIL_CPP,
+    SETTINGCONNECTBLUESUCCESS_CPP,
+    SETTINGCONNECTIONOPEN_CPP,
+    SETTINGCONNECTNEWPHONEPAGE_CPP,
+    SETTINGDESKTOPDIALPAGE_CPP,
+    SETTINGDESKTOPDIALSTYLEPAGE_CPP,
+    SETTINGDESKTOPHOMEPAGE_CPP,
+    SETTINGDESKTOPPAGE_CPP,
+    SETTINGDISPLAYBRIGHTNESSPAGE_CPP,
+    SETTINGDISPLAYPAGE_CPP,
+    SETTINGDISPLAYSCREENOFFPAGE_CPP,
+    SETTINGDISPLAYSTEADYONPAGE_CPP,
+    SETTINGMAINPAGE_CPP,
+    SETTINGPOWERPAGE_CPP,
+    SETTINGQRCODECONNPAGE_CPP,
+    SETTINGRECONNECTIONPAGE_CPP,
+    SETTINGRECONNECTSECONDCONFIRMPAGE_CPP,
+    SETTINGSYSTEMOPERATIONPAGE_CPP,
+    SETTINGSYSTEMOTAPAGE_CPP,
+    SETTINGSYSTEMPAGE_CPP,
+    UNPAIRSECONDCONFIRMPAGE_CPP,
+    SETTINGPRESENTER_CPP,
+    SLEEPDETAILSPAGE_CPP,
+    SLEEPMAINPAGE_CPP,
+    SLEEPMODEL_CPP,
+    SLEEPPRESENTER_CPP,
+    SLEEPSLEEPINGPAGE_CPP,
+    SLEEPTARGETTIME_CPP,
+    SPORTCOUNTDOWNPAGE_CPP,
+    SPORTDATAPAGE_CPP,
+    SPORTHEARTRATERANGEITEMVIEW_CPP,
+    SPORTHEARTRATERANGEPAGE_CPP,
+    SPORTMENUITEMVIEW_CPP,
+    SPORTMENUPAGE_CPP,
+    SPORTMISTOUCHPAGE_CPP,
+    SPORTMODEL_CPP,
+    SPORTPAUSEPAGE_CPP,
+    SPORTPREPAREPAGE_CPP,
+    SPORTPRESENTER_CPP,
+    SPORTPROMPTPAGE_CPP,
+    SPORTREMINDHEARTRATEITEMVIEW_CPP,
+    SPORTREMINDHEARTRATEPAGE_CPP,
+    SPORTREMINDINTERVALITEMVIEW_CPP,
+    SPORTREMINDINTERVALPAGE_CPP,
+    SPORTREMINDITEMVIEW_CPP,
+    SPORTREMINDPAGE_CPP,
+    SPORTSETTINGSITEMVIEW_CPP,
+    SPORTSETTINGSPAGE_CPP,
+    SPORTTARGETITEMVIEW_CPP,
+    SPORTTARGETPAGE_CPP,
+    SPORTTARGETPROMPTPAGE_CPP,
+    SPORTTARGETSETTINGPAGE_CPP,
+    STOPWATCHITEMVIEW_CPP,
+    STOPWATCHMODEL_CPP,
+    STOPWATCHPAGE_CPP,
+    STOPWATCHPRESENTER_CPP,
+    STOPWATCHRECORDPAGE_CPP,
+    TIMERCOUNTDOWN_CPP,
+    TIMERMAINPAGE_CPP,
+    TIMERMODEL_CPP,
+    TIMERPRESENTER_CPP,
+    TIMERSETTINGPAGE_CPP,
+    WEATHERITEMVIEW_CPP,
+    WEATHERMAINPAGE_CPP,
+    WEATHERMODEL_CPP,
+    WEATHERPAGEDAYS_CPP,
+    WEATHERPAGEHOURS_CPP,
+    WEATHERPAGEHOURSGROUP_CPP,
+    WEATHERPAGELUNARPHASE_CPP,
+    WEATHERPAGEMONTHRISE_CPP,
+    WEATHERPAGESUNRISE_CPP,
+    WEATHERPRESENTER_CPP,
+    BACKTOCROSSSHAPEDTRANSITION_CPP,
+    CROSSSHAPEDTRANSITION_CPP,
+    FADEINOUTTRANSITION_CPP,
+    GAUSSIANBLURTRANSITION_CPP,
+    THREEDFOLDTRANSITION_CPP,
+    TRANSPARENTGRADIENTTRANSITION_CPP,
+    ZOOMOUTTRANSITION_CPP,
+    GRADIENTAODVIEW_CPP,
+    GRADIENTCLOCKVIEW_CPP,
+    GRADIENTDATEVIEW_CPP,
+    PUSH_PRESS_EFFECT_CPP,
+    WINDMILL_EFFECT_CPP,
+    UI_TEST_TRANSITION_ADAPTER_CPP,
+    UI_TEST_TRANSITION_ITEMVIEW_CPP,
+    UI_TEST_TRANSITION_MODEL_CPP,
+    UI_TEST_TRANSITION_VIEW_CPP,
+
     APP_FILE_ID_MAX = 1024,
 } log_file_list_enum_app_t;
 
index 85fcd43..6b2ab99 100644 (file)
@@ -239,6 +239,7 @@ typedef enum {
     UI_TEST_COMPASS_CPP,
     UI_TEST_COUNTDOWN_CPP,
     UI_TEST_CANVAS_EXT_CPP,
+    UI_TEST_TRIM_PATH_CPP,
     UI_TEST_DRAW_CPP,
     UI_TEST_FONT_CPP,
     UI_TEST_MULTI_FONT_CPP,
@@ -429,13 +430,16 @@ typedef enum {
     UI_TEST_WATERFALL_LIST_CPP,
     UI_KALEIDOSCOPE_VIEW_CPP,
     KALEIDOSCOPE_UTILS_CPP,
+    UI_FLOAT_BOX_VIEW_CPP,
     UI_COVERFLOW_VIEW_CPP,
     UI_COVERFLOW_VIEW2_CPP,
     UI_SLIPFLOW_VIEW_CPP,
+    UI_FOLDABLE_VIEW_CPP,
     UI_ROLLER_VIEW_CPP,
     UI_CROSS_VIEW_CPP,
     UI_ICOSAHEDRON_VIEW_CPP,
     UI_MAP_VIEW_CPP,
+    UI_TEST_SIMPLE_TRANSFORM_LIST_CPP,
     MAP_SVG_PARSER_CPP,
     RECENTMANAGER_CPP,
     RECENTAPPVIEW_CPP,
@@ -459,6 +463,7 @@ typedef enum {
     UI_SCROLL_VIEW_NESTED_CPP,
     UI_LIST_NESTED_CPP,
     UI_PARTICLE_VIEW_CPP,
+    UI_CHART_PILLAR_EXT_CPP,
     PARTICLE_CELL_CPP,
     VIDEOCARD_CPP,
     DIALBINPARSERV3_CPP,
@@ -479,7 +484,15 @@ typedef enum {
     LOTT_SHAPE_LAYER_CPP,
     LOTT_SHAPE_CPP,
     LOTT_TRANSFORM_CPP,
+    LOTT_BEZIER_CPP,
+    LOTT_TRIM_PATH_CPP,
     UI_LOTT_VIEW_CPP,
+    SLIPFLOWRECENTAPPFRAGMENT_CPP,
+    ROLLERRECENTAPPFRAGMENT_CPP,
+    UI_PLANET_LIST_CPP,
+    PLANETDESKTOPFRAGMENT_CPP,
+    PNG_IMG_DECODER_CPP,
+    UI_TRANSFORM_BUTTON_CPP,
     FILE_ID_MAX = 1024,
 } log_file_list_enum_gui_t;
 #endif
index e2cfee2..0eed086 100644 (file)
@@ -98,6 +98,7 @@ typedef enum {
     RAW_FORMAT_C,
     SILK_DEMUXER_C,
     DEMUXER_MANAGER_C,
+    DEMUXER_BUFFER_C,
        DECRYPT_DATA_C,
     DEMUXER_PLUGINS_MANAGER_C,
     FORMAT_COMMON_C,
@@ -239,6 +240,18 @@ typedef enum {
     AUDIO_MANAGER_C_WRAPPER_CPP,
     MODEM_SUB_PORT_C,
     MODEM_PORT_C,
+    DTCF_MANAGER_C,
+    WAV_C,
+    AUDIO_RECORDER_C,
+    AUDIO_RECORDER_MUXER_C,
+    WAV_MUXER_C,
+       RAW_MUXER_C,
+       OGG_MUXER_C,
+       OGG_MANAGER_C,
+    DTCF_C,
+       AUDIO_RECORDER_MODULE_CPP,
+       AUDIO_RECORDER_LISTENER_CPP,
+       AUDIO_RECORDER_SAMPLE_CPP,
     SBC_DEMUXER_C,
     AUDIO_MODULE_CPP,
     AUDIO_PLAYER_CPP,
index 81d86da..00d097a 100644 (file)
             "key_status": "alive",
             "structure_type": "audio_aef_param_t",
             "attributions": 1,
-            "value": [162, [14, 0, 60, 0, 20, 0, 70, 70, 12, 12, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 
-            0, 0, 10, 10, 200, 200, 20, 20, 120, 120, 70, 70, 130, 130, 150, 150, 130, 130, 120, 120, 100, 100, 140, 140, 100, 100, 136, 19, 220, 5, 220, 5, 
-            184, 11, 160, 15, 72, 13, 40, 35, 64, 31, 220, 5, 134, 5, 208, 7, 134, 5, 136, 19, 220, 5, 220, 5, 184, 11, 160, 15, 72, 13, 40, 35, 
-            64, 31, 220, 5, 134, 5, 208, 7, 134, 5, 20, 5, 228, 12, 112, 23, 244, 1, 120, 30, 136, 19, 132, 3, 160, 15, 228, 12, 100, 0, 88, 2, 
-            44, 1, 20, 5, 228, 12, 112, 23, 244, 1, 120, 30, 136, 19, 132, 3, 160, 15, 228, 12, 100, 0, 88, 2, 44, 1, 0, 0, 100, 100, 100, 0, 
-            150, 0]]
+            "value": [81, [15, 316, 20, 12890, 3084, 1028, 257, 1285, 0, 0, 0, 0, 0, 0, 1542, 514, 771, 25700, 51400, 12850, 38550, 12850,
+            38550, 12850, 38550, 12850, 38550, 0, 25700, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000,
+            3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 300, 400, 600, 900, 1400, 2000, 3000, 5000,
+            8000, 9000, 12000, 16000, 800, 1100, 1500, 2000, 2300, 2800, 3500, 4500, 5600, 8000, 10000, 14000, 5, 100, 0, 150]]
+        },
+        "uikit_language_id": {
+            "key_id": "0x2105",
+            "key_status": "alive",
+            "structure_type": "sys_language_id_t",
+            "attributions": 1,
+            "value": [0]
+        },
+        "sys_product_info": {
+            "key_id": "0x2106",
+            "key_status": "alive",
+            "structure_type": "sys_product_info_t",
+            "attributions": 4,            
+            "value": [10, [87, 65, 84, 67, 72, 45, 66, 88, 57, 0]]
         }
     }
 }
index 300a589..3146ac5 100644 (file)
             "key_status": "alive",
             "structure_type": "audio_aef_param_t",
             "attributions": 1,
-            "value": [162, 
-                [14, 0, 60, 0, 20, 0, 70, 70, 12, 12, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 
-                0, 0, 10, 10, 200, 200, 20, 20, 120, 120, 70, 70, 130, 130, 150, 150, 130, 130, 120, 120, 100, 100, 140, 140, 100, 100, 136, 19, 220, 5, 220, 5, 
-                184, 11, 160, 15, 72, 13, 40, 35, 64, 31, 220, 5, 134, 5, 208, 7, 134, 5, 136, 19, 220, 5, 220, 5, 184, 11, 160, 15, 72, 13, 40, 35, 
-                64, 31, 220, 5, 134, 5, 208, 7, 134, 5, 20, 5, 228, 12, 112, 23, 244, 1, 120, 30, 136, 19, 132, 3, 160, 15, 228, 12, 100, 0, 88, 2, 
-                44, 1, 20, 5, 228, 12, 112, 23, 244, 1, 120, 30, 136, 19, 132, 3, 160, 15, 228, 12, 100, 0, 88, 2, 44, 1, 0, 0, 100, 100, 100, 0, 
-                150, 0]
-        ]
+            "value": [81, [15, 316, 20, 12890, 3084, 1028, 257, 1285, 0, 0, 0, 0, 0, 0, 1542, 514, 771, 25700, 51400, 12850, 38550, 12850,
+            38550, 12850, 38550, 12850, 38550, 0, 25700, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000,
+            3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 300, 400, 600, 900, 1400, 2000, 3000, 5000,
+            8000, 9000, 12000, 16000, 800, 1100, 1500, 2000, 2300, 2800, 3500, 4500, 5600, 8000, 10000, 14000, 5, 100, 0, 150]]
+        },
+        "uikit_language_id": {
+            "key_id": "0x2105",
+            "key_status": "alive",
+            "structure_type": "sys_language_id_t",
+            "attributions": 1,
+            "value": [0]
+        },
+        "sys_product_info": {
+            "key_id": "0x2106",
+            "key_status": "alive",
+            "structure_type": "sys_product_info_t",
+            "attributions": 4,            
+            "value": [10, [87, 65, 84, 67, 72, 45, 66, 88, 57, 0]]
         }
     }
 }
index 4a74249..601d49d 100644 (file)
@@ -106,7 +106,7 @@ typedef struct {
 #define NV_AUDIO_AEF_PARAM_SIZE 162\r
 typedef struct {\r
     uint32_t size;\r
-    uint8_t data[NV_AUDIO_AEF_PARAM_SIZE];\r
+    uint16_t data[NV_AUDIO_AEF_PARAM_SIZE];\r
 } audio_aef_param_t;\r
 \r
 /* sys language id */\r
index e1f4ffe..595117e 100644 (file)
@@ -1,11 +1,3 @@
-/*
- * @Author: penglei 1624952103@qq.com
- * @Date: 2025-07-29 09:33:56
- * @LastEditors: penglei 1624952103@qq.com
- * @LastEditTime: 2025-11-02 15:48:44
- * @FilePath: /FD230/code/sdk/middleware/chips/brandy/nv/nv_config/include/key_id.h
- * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
- */
 /*
  * Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved.
  * Description: NV - key_id.
 /* dial market key_id [0x2500,0x2600) */
 #define NV_ID_SECURE_DIAL               0x2500 /* secure dial */
 
+/* ace cipher key_id [0x2700,0x2900) */
+#define NV_ID_ACE_CIPHER                0x2700 /* ace cipher key id */
+// Use a special keyId to store the bitmap (before the key range)
+#define BITMAP_KEY_ID                   0x26FF
+
 /* user normal key_id [0x3000,0x4000) */
 #define NV_ID_AUDIO_VQE_PARAM           0x320C /* 3A params for VOIP scene, audio_vqe_param_t */
 #define NV_ID_AUDIO_VQE_KWS_PARAM       0x320D /* 3A params for KWS scene, audio_vqe_param_t */
@@ -57,4 +54,3 @@
 
 
 #endif /* __KEY_ID_H__ */
- 
\ No newline at end of file
index 5ec95f8..b52b753 100644 (file)
@@ -115,7 +115,7 @@ void display_suspend_power_off(void)
 void display_suspend(void)
 {
 #if defined(ENABLE_UIKIT) || defined(ENABLE_LVGL)
-    if (lcd_get_status() || g_frs_sleep_flag) {
+    if (uapi_is_lcd_connect() && (lcd_get_status() || g_frs_sleep_flag)) {
         if (g_resume_touch_flag != 0) { touch_suspend_for_i2c(); }
         int ret = drv_vau_suspend(NULL);
         if (ret != 0) { PRINT("drv vau suspend ret =%d\n", ret); }
@@ -149,7 +149,7 @@ void display_resume(void)
 #if defined(ENABLE_UIKIT) || defined(ENABLE_LVGL)
     hal_pmu1_dig_pg_l2m_gmmu_pwr_en(true); // The GMMU memory is set to the normal state.
     hal_pmu1_dig_pg_l2m_gmmu_ret1_en(false);
-    if (lcd_get_status() != 0) {
+    if ((uapi_is_lcd_connect()) && (lcd_get_status() != 0)) {
 #ifndef QSPI_DISPLAY
         pmu_ldo_power_on(PMU_LDO_AUXLDO3, TURN_ON);
 #endif
index 0342888..75e7969 100644 (file)
@@ -349,7 +349,8 @@ void pm_enter_sleep(uint32_t sleep_ms_val)
     pm_enter_deepsleep_set_flag();
     status = pm_os_irq_lock();
     if ((sleep_ms <= g_pm_sleep_threshold) || pm_get_sleep_veto() || hal_rtc_get_int_status(0) == 1 ||
-        ((readl(PM_RTC_LOAD_COUNT_REG) < PM_RTC_LOAD_THRESHOLD_MS) && (rtc_times_alert > PM_RTC_CUR_ALERT_US))) {
+        ((readl(PM_RTC_LOAD_COUNT_REG) < PM_RTC_LOAD_THRESHOLD_MS) && (rtc_times_alert > PM_RTC_CUR_ALERT_US)) ||
+        hal_ipc_get_core_clr_sts(CORES_BT_CORE)) {
         pm_enter_deepsleep_cancel_flag();
         pm_enter_light_sleep();
     } else {
diff --git a/code/sdk/middleware/chips/brandy/uart_agent/CMakeLists.txt b/code/sdk/middleware/chips/brandy/uart_agent/CMakeLists.txt
new file mode 100644 (file)
index 0000000..bf0dcfa
--- /dev/null
@@ -0,0 +1,47 @@
+#===============================================================================
+# @brief    cmake file
+# Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved.
+#===============================================================================
+set(COMPONENT_NAME "uart_agent")
+
+set(SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/uart_agent.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/app_uart_agent_demo.c
+)
+
+set(PUBLIC_HEADER
+     ${CMAKE_CURRENT_SOURCE_DIR}/
+)
+
+set(PRIVATE_HEADER
+)
+
+set(PRIVATE_DEFINES
+)
+
+set(PUBLIC_DEFINES
+    #SUPPORT_UART_AGENT_DEMO
+)
+
+# use this when you want to add ccflags like -include xxx
+set(COMPONENT_PUBLIC_CCFLAGS
+)
+
+set(COMPONENT_CCFLAGS
+    -Wno-implicit-function-declaration
+    -Wno-incompatible-pointer-types
+    -Wno-int-conversion
+    -Wno-enum-conversion
+    -Wno-unused-parameter
+    -Wno-unused-function
+)
+
+set(WHOLE_LINK
+    true
+)
+
+set(MAIN_COMPONENT
+    false
+)
+
+build_component()
diff --git a/code/sdk/middleware/chips/brandy/uart_agent/app_uart_agent_demo.c b/code/sdk/middleware/chips/brandy/uart_agent/app_uart_agent_demo.c
new file mode 100644 (file)
index 0000000..fbc3350
--- /dev/null
@@ -0,0 +1,127 @@
+/**\r
+ * Copyright (c) CompanyNameMagicTag 2022-2022. All rights reserved. \n\r
+ *\r
+ * Description: Provides uart agent usage demo\n\r
+ * Author: CompanyName \n\r
+ * History: \n\r
+ * 2022-11-17, Create file. \n\r
+ */\r
+#include "securec.h"\r
+#include "panic.h"\r
+#include "cmsis_os2.h"\r
+#include "soc_osal.h"\r
+#if defined(__FREERTOS__)\r
+#include "osal_adapt.h"\r
+#endif\r
+#include "common_def.h"\r
+#include "debug_print.h"\r
+#include "rtc.h"\r
+#include "ipc.h"\r
+#include "ipc_actions.h"\r
+#include "uart_agent.h"\r
+#include "app_uart_agent_demo.h"\r
+\r
+/**\r
+ * 本文件demo展示了使用uart agent的方法:\r
+ *  1. 需要在本模块CmakeList中定义SUPPORT_UART_AGENT_DEMO宏才会启动demo线程app_uart_agent_task_thread\r
+ *  2. app_uart_agent_task_init中:\r
+ *       (1)调用uart_agent_init完成uart agent模块的初始化\r
+ *       (2)初始化用于线程等待数据的信号量\r
+ *       (3)调用uart_agent_register_app_trigger注册uart_agent通知回调\r
+ *  3. 线程启动时启动了一个test定时器,1s周期向B核发送数据,用于测试uart_agent_write接口\r
+ *  4. app_uart_agent_task_thread等待uart_agent触发接收处理,测试uart_agent_read接口\r
+ */\r
+\r
+typedef enum {\r
+    FORMAT_CHAR,\r
+    FORMAT_HEX,\r
+    FORMAT_MAX,\r
+} print_format_t;\r
+\r
+static void print_data(uint8_t format, uint8_t* buff, uint32_t len)\r
+{\r
+    uint32_t i;\r
+    uint32_t width;\r
+\r
+    if (format >= FORMAT_MAX) {\r
+        return;\r
+    }\r
+    for (i = 0; i < len; i++) {\r
+        if (format == FORMAT_CHAR) {\r
+            width = 64;   // 每行打印64个字节\r
+            wstp_print("%c", buff[i]);\r
+        } else if (format == FORMAT_HEX) {\r
+            width = 32;   // 每行打印32个字节\r
+            wstp_print("%02x ", buff[i]);\r
+        }\r
+\r
+        if ((i + 1) % width == 0) {\r
+            wstp_print("\r\n");\r
+        }\r
+    }\r
+    wstp_print("\r\n");\r
+}\r
+\r
+static osSemaphoreId_t g_sema_uart_agent_demo = NULL;\r
+\r
+void uart_agent_demo_trigger(void)\r
+{\r
+    /* Give the semaphore to ensure the main logging task will be active */\r
+    (void)osSemaphoreRelease(g_sema_uart_agent_demo);\r
+}\r
+\r
+#define TEST_TIMER_TIMEOUT  1000\r
+static rtc_handle_t g_test_timer = NULL;\r
+static uint8_t g_test_buffer[] = "hello, uart_agent, this is a tx test message from brandy\r\n";\r
+\r
+static void test_timer_callback(uintptr_t data)\r
+{\r
+    PRINT("%s\r\n", __FUNCTION__);\r
+    uart_agent_write(g_test_buffer, sizeof(g_test_buffer));\r
+\r
+    uapi_rtc_start(g_test_timer, TEST_TIMER_TIMEOUT, test_timer_callback, 0);\r
+}\r
+\r
+void uart_agent_start_test_timer(void)\r
+{\r
+    uapi_rtc_create(RTC_0, &g_test_timer);\r
+    if (g_test_timer == NULL) {\r
+        PRINT("[%s:%d] create RTC timer fail!!\n", __FUNCTION__, __LINE__);\r
+        return;\r
+    }\r
+    uapi_rtc_start(g_test_timer, TEST_TIMER_TIMEOUT, test_timer_callback, 0);\r
+}\r
+\r
+static void app_uart_agent_task_init(void)\r
+{\r
+    uart_agent_init();\r
+\r
+    g_sema_uart_agent_demo = osSemaphoreNew(1, 0, NULL);\r
+    if (!g_sema_uart_agent_demo) {\r
+        panic(PANIC_UART, __LINE__);\r
+    }\r
+\r
+    uart_agent_register_app_trigger(uart_agent_demo_trigger);\r
+\r
+    uart_agent_start_test_timer();\r
+}\r
+\r
+void app_uart_agent_task_thread(void *param)\r
+{\r
+    unused(param);\r
+#define RCV_BUFF_SIZE                  512\r
+    int32_t ret = OSAL_FAILURE;\r
+\r
+    app_uart_agent_task_init();\r
+    while (1) {\r
+        if (osKernelGetState() == osKernelRunning) {\r
+            uint8_t rcv_buf[RCV_BUFF_SIZE];\r
+            uint32_t rcv_len = 0;\r
+            if (osSemaphoreAcquire(g_sema_uart_agent_demo, osWaitForever) != osOK) {\r
+                panic(PANIC_UART, __LINE__);\r
+            }\r
+            rcv_len = uart_agent_read(rcv_buf, RCV_BUFF_SIZE, osWaitForever);\r
+            print_data(FORMAT_CHAR, rcv_buf, rcv_len);\r
+        }\r
+    }\r
+}
\ No newline at end of file
diff --git a/code/sdk/middleware/chips/brandy/uart_agent/app_uart_agent_demo.h b/code/sdk/middleware/chips/brandy/uart_agent/app_uart_agent_demo.h
new file mode 100644 (file)
index 0000000..f67c00e
--- /dev/null
@@ -0,0 +1,32 @@
+/**\r
+ * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n\r
+ *\r
+ * Description: Provides uart agent usage demo \n\r
+ * Author: @CompanyNameTag \n\r
+ * History: \n\r
+ * 2022-07-20, Create file. \n\r
+ */\r
+#ifndef APP_UART_AGENT_PROCESS_H\r
+#define APP_UART_AGENT_PROCESS_H\r
+\r
+#include <stdint.h>\r
+#include <stdio.h>\r
+#include "errcode.h"\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+extern "C" {\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#define UART_AGENT_APP_STACK_SIZE        0xC00\r
+\r
+void app_uart_agent_task_thread(void *param);\r
+\r
+#ifdef __cplusplus\r
+#if __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* __cplusplus */\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/middleware/chips/brandy/uart_agent/uart_agent.c b/code/sdk/middleware/chips/brandy/uart_agent/uart_agent.c
new file mode 100644 (file)
index 0000000..5bfc1b3
--- /dev/null
@@ -0,0 +1,195 @@
+/**
+ * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n
+ *
+ * Description: Provides uart driver source \n
+ * Author: @CompanyNameTag \n
+ * History: \n
+ * 2022-06-09, Create file. \n
+ */
+#include <stdbool.h>
+#include "common_def.h"
+#include "debug_print.h"
+#include "soc_osal.h"
+#include "osal_addr.h"
+#include "lock/osal_spinlock.h"
+#include "ipc.h"
+#include "ipc_actions.h"
+#include "timer.h"
+#include "pm_veto.h"
+#include "pm_definition.h"
+#include "uart_circ_buf.h"
+#include "uart_agent.h"
+
+#pragma pack(1)
+typedef struct {
+    uint16_t data_len;
+} uart_ipc_hdr_t;
+
+typedef struct {
+    uart_ipc_hdr_t hdr;
+    uint8_t  data[0];
+} uart_ipc_msg_t;
+#pragma pack()
+
+#define UART_AGENT_BUF_SIZE   (512 + 1)  // 环形buffer可写空间512B, 留1个字节占位
+
+typedef struct {
+    circ_buf_t buf;
+    uint32_t buff_write;
+    uint32_t buff_read;
+    osal_spinlock lock;
+} uart_circ_buffer;
+
+static uint8_t g_buffer[UART_AGENT_BUF_SIZE];
+static uart_circ_buffer g_uart_circ_buff;
+
+static app_trigger_callback_t g_app_trigger_callback = NULL;
+
+static void uart_agent_app_trigger(void)
+{
+    if (g_app_trigger_callback != NULL) {
+        g_app_trigger_callback();
+    }
+}
+
+static bool uart_agent_ipc_rx_handler(ipc_action_t message, const volatile ipc_payload *payload,
+                                      cores_t src, uint32_t id)
+{
+    unused(message);
+    unused(id);
+    unused(src);
+
+    uint32_t write_len;
+    uint32_t free_len;
+    unsigned long flags;
+    uart_ipc_msg_t* ipc_msg = (uart_ipc_msg_t*)payload;
+
+    PRINT("uart_agent_ipc_rx_handler data len %d\r\n", ipc_msg->hdr.data_len);
+    osal_spin_lock_irqsave(&g_uart_circ_buff.lock, &flags);
+    free_len = circ_buf_query_free(&g_uart_circ_buff.buf);
+    if (free_len < ipc_msg->hdr.data_len) {
+        PRINT("uart_agent_ipc_rx_handler buff over flow, want %d, free %d\r\n", ipc_msg->hdr.data_len, free_len);
+        goto out;
+    }
+    write_len = circ_buf_write(&g_uart_circ_buff.buf, ipc_msg->data, ipc_msg->hdr.data_len);
+    if (write_len != ipc_msg->hdr.data_len) {
+        PRINT("uart_agent_ipc_rx_handler write abnormal, want %d, actual %d\r\n", ipc_msg->hdr.data_len, write_len);
+    }
+out:
+    osal_spin_unlock_irqrestore(&g_uart_circ_buff.lock, &flags);
+    uart_agent_app_trigger();
+
+    return true;
+}
+
+void uart_agent_init(void)
+{
+    (void)memset_s(g_buffer, sizeof(g_buffer), 0, sizeof(g_buffer));
+    circ_buf_init(&(g_uart_circ_buff.buf), &(g_uart_circ_buff.buff_write), &(g_uart_circ_buff.buff_read),
+                  g_buffer, sizeof(g_buffer));
+
+    osal_spin_lock_init(&g_uart_circ_buff.lock);
+
+    ipc_register_handler(IPC_ACTION_UART_AGENT_RX, uart_agent_ipc_rx_handler);
+}
+
+void uart_agent_deinit(void)
+{
+    ipc_unregister_handler(IPC_ACTION_UART_AGENT_RX);
+    circ_buf_flush(&(g_uart_circ_buff.buf));
+    osal_spin_lock_destroy(&g_uart_circ_buff.lock);
+}
+
+/**
+ * @if Eng
+ * @brief  Writes a buffer to uart agent, it will be send to B core uart by ipc msg.
+ * @param  [in]  buffer Pointer to the buffer to write through the UART.
+ * @param  [in]  length Length of the buffer to write.
+ * @return Amount of data write to UART.
+ * @else
+ * @brief  将数据发送到uart agent, 实际通过ipc消息转发到B核uart接口发送。
+ * @param  [in]  buffer 要发送的数据Buffer。
+ * @param  [in]  length 要发送的数据Buffer长度。
+ * @return 实际发送的数据长度。
+ * @endif
+ */
+uint32_t uart_agent_write(uint8_t* data, uint16_t data_len)
+{
+    if (data == NULL || data_len == 0) {
+        PRINT("uart_agent_write data is null!"NEWLINE);
+        return 0;
+    }
+    uart_ipc_msg_t* msg = osal_kmalloc(sizeof(uart_ipc_msg_t) + data_len, OSAL_GFP_KERNEL);
+    if (msg == NULL) {
+        return 0;
+    }
+    msg->hdr.data_len = data_len;
+    if (memcpy_s((void *)&(msg->data), data_len, data, data_len) != EOK) {
+        osal_kfree(msg);
+        return 0;
+    }
+
+    ipc_status_t ret;
+    ret = ipc_send_message(CORES_BT_CORE, IPC_ACTION_UART_AGENT_TX, (ipc_payload *)msg,
+                           sizeof(uart_ipc_msg_t) + data_len, IPC_PRIORITY_HIGHEST, false);
+    if (ret != IPC_STATUS_OK) {
+        PRINT("%s return %d\r\n", __FUNCTION__, ret);
+        osal_kfree(msg);
+        return 0;
+    }
+
+    osal_kfree(msg);
+    return data_len;
+}
+
+/**
+ * @if Eng
+ * @brief  Read data from uart agent.
+ * @param  [in]  buffer Pointer to the read buffer.
+ * @param  [in]  length the receive buffer lenth.
+ * @param  [in]  timeout Timeout duration.
+ * @return Amount of data read from uart agent
+ * @else
+ * @brief  从UART agent读取数据。
+ * @param  [in]  buffer 存储接收数据的Buffer。
+ * @param  [in]  length 存储接收数据的Buffer长度。
+ * @param  [in]  timeout 超时时间。
+ * @return 实际读到的数据长度。
+ * @endif
+ */
+uint32_t uart_agent_read(const uint8_t *buffer, uint32_t length, uint32_t timeout)
+{
+    unused(timeout);
+
+    unsigned long flags;
+
+    osal_spin_lock_irqsave(&g_uart_circ_buff.lock, &flags);
+
+    uint32_t data_len = circ_buf_query_data(&g_uart_circ_buff.buf);
+
+    uint32_t read_len = (data_len < length) ? data_len : length;
+
+    uint32_t actual_len = circ_buf_read(&g_uart_circ_buff.buf, buffer, read_len);
+
+    osal_spin_unlock_irqrestore(&g_uart_circ_buff.lock, &flags);
+
+    return actual_len;
+}
+
+/**
+ * @if Eng
+ * @brief  register the uart agent notify application thread to process data.
+ * @param  [in]  callback The application callback function
+ * @retval void
+ * @else
+ * @brief 注册uart agent通知应用线程进行数据处理。
+ * @param  [in]  callback 应用线程注册的回调函数 。
+ * @retval void。
+ * @endif
+ */
+void uart_agent_register_app_trigger(app_trigger_callback_t callback)
+{
+    if (callback != NULL) {
+        g_app_trigger_callback = callback;
+    }
+}
\ No newline at end of file
diff --git a/code/sdk/middleware/chips/brandy/uart_agent/uart_agent.h b/code/sdk/middleware/chips/brandy/uart_agent/uart_agent.h
new file mode 100644 (file)
index 0000000..759b77f
--- /dev/null
@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n
+ *
+ * Description: Provides UART driver api \n
+ * Author: @CompanyNameTag \n
+ * History: \n
+ * 2022-06-01, Create file. \n
+ */
+#ifndef UART_AGENT_H
+#define UART_AGENT_H
+
+typedef void (*app_trigger_callback_t)(void);
+
+/**
+ * @if Eng
+ * @brief  register the uart agent notify application thread to process data.
+ * @param  [in]  callback The application callback function
+ * @retval void
+ * @else
+ * @brief 注册uart agent通知应用线程进行数据处理。
+ * @param  [in]  callback 应用线程注册的回调函数 。
+ * @retval void。
+ * @endif
+ */
+void uart_agent_register_app_trigger(app_trigger_callback_t callback);
+
+/**
+ * @if Eng
+ * @brief  uart agent module init : rx circ buffer init, ipc msg register
+ * @param  [in]  void
+ * @retval void
+ * @else
+ * @brief uart agent模块初始化, 包括:接收环形buffer初始化,注册ipc消息处理程序
+ * @param  [in]  void
+ * @retval void。
+ * @endif
+ */
+void uart_agent_init(void);
+
+/**
+ * @if Eng
+ * @brief  uart agent module deinit
+ * @param  [in]  void
+ * @retval void
+ * @else
+ * @brief uart agent模块去初始化
+ * @param  [in]  void
+ * @retval void。
+ * @endif
+ */
+void uart_agent_deinit(void);
+
+/**
+ * @if Eng
+ * @brief  Read data from uart agent.
+ * @param  [in]  buffer Pointer to the read buffer.
+ * @param  [in]  length the receive buffer lenth.
+ * @param  [in]  timeout Timeout duration.
+ * @return Amount of data read from uart agent
+ * @else
+ * @brief  从UART agent读取数据。
+ * @param  [in]  buffer 存储接收数据的Buffer。
+ * @param  [in]  length 存储接收数据的Buffer长度。
+ * @param  [in]  timeout 超时时间。
+ * @return 实际读到的数据长度。
+ * @endif
+ */
+uint32_t uart_agent_read(const uint8_t *buffer, uint32_t length, uint32_t timeout);
+
+/**
+ * @if Eng
+ * @brief  Writes a buffer to uart agent, it will be send to B core uart by ipc msg.
+ * @param  [in]  buffer Pointer to the buffer to write through the UART.
+ * @param  [in]  length Length of the buffer to write.
+ * @return Amount of data write to UART.
+ * @else
+ * @brief  将数据发送到uart agent, 实际通过ipc消息转发到B核uart接口发送。
+ * @param  [in]  buffer 要发送的数据Buffer。
+ * @param  [in]  length 要发送的数据Buffer长度。
+ * @return 实际发送的数据长度。
+ * @endif
+ */
+uint32_t uart_agent_write(uint8_t* data, uint16_t data_len);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/middleware/chips/brandy/uart_agent/uart_circ_buf.h b/code/sdk/middleware/chips/brandy/uart_agent/uart_circ_buf.h
new file mode 100644 (file)
index 0000000..35a02b5
--- /dev/null
@@ -0,0 +1,178 @@
+/**
+ * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n
+ *
+ * Description: Provides circ buffer func \n
+ * Author: @CompanyNameTag \n
+ * History: \n
+ * 2022-07-20, Create file. \n
+ */
+
+#ifndef UART_CIRC_BUF_H
+#define UART_CIRC_BUF_H
+
+#include "securec.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif
+#endif /* __cplusplus */
+
+typedef struct {
+    volatile uint32_t *write; /* circle buffer write pointer */
+    volatile uint32_t *read;  /* circle buffer read pointer */
+    uint8_t *data;            /* circle buffer data virtual address */
+    uint32_t size;            /* circle buffer size */
+} circ_buf_t;
+
+static inline uint32_t circ_buf_min(uint32_t x, uint32_t y)
+{
+    return (x <= y) ? x : y;
+}
+
+static inline uint32_t circ_add(uint32_t x, uint32_t y, uint32_t full)
+{
+    /* add x and y, saturate to full */
+    uint32_t x_temp = x + y;
+
+    return (x_temp >= full) ? (x_temp - full) : x_temp;
+}
+
+static inline uint32_t circ_sub(uint32_t x, uint32_t y, uint32_t full)
+{
+    return (x < y) ? (full + x - y) : (x - y);
+}
+
+static inline void circ_buf_init(circ_buf_t *cb, uint32_t *write, uint32_t *read, void *data, uint32_t len)
+{
+    cb->write = write;
+    cb->read = read;
+    cb->data = (uint8_t*)data;
+    cb->size = len;
+
+    *cb->write = 0;
+    *cb->read = 0;
+}
+
+static inline void circ_buf_flush(circ_buf_t *cb)
+{
+    *cb->read = 0;
+    *cb->write = 0;
+}
+
+static inline uint32_t circ_buf_data_size(uint32_t write, uint32_t read, uint32_t size)
+{
+    return (write >= read) ? (write - read) : (size - read + write);
+}
+
+
+static inline uint32_t circ_buf_free_size(uint32_t write, uint32_t read, uint32_t size)
+{
+    /* free size是buff size减1 */
+    return size - 1 - circ_buf_data_size(write, read, size);
+}
+
+static inline uint32_t read_data(const circ_buf_t *cb, uint8_t *to, uint32_t len, uint32_t off)
+{
+    if ((len == 0) || (memcpy_s(to, len * sizeof(uint8_t), cb->data + off, len) != EOK)) {
+        return 0;
+    }
+
+    return len;
+}
+
+/* read data from circle buffer */
+static inline uint32_t circ_buf_read_data(const circ_buf_t *cb, uint8_t *to, uint32_t len, uint32_t off)
+{
+    uint32_t l = circ_buf_min(len, cb->size - off);
+
+    if (to == NULL) {
+        /* dump data in circle buffer */
+        return len;
+    }
+
+    return read_data(cb, to, l, off) + read_data(cb, to + l, len - l, 0);
+}
+
+static inline uint32_t write_zero(circ_buf_t *cb, const uint8_t *from, uint32_t len, uint32_t off)
+{
+    if ((len == 0) || (memset_s(cb->data + off, len, 0, len) != EOK)) {
+        return 0;
+    }
+    (void)from;
+    return len;
+}
+
+static inline uint32_t write_data(circ_buf_t *cb, const uint8_t *from, uint32_t len, uint32_t off)
+{
+    if ((len == 0) || (memcpy_s(cb->data + off, cb->size - off, from, len) != EOK)) {
+        return 0;
+    }
+
+    return len;
+}
+
+/*
+ * circ_buf_write_data - puts some data from kernel space into the circle buffer
+ * @cb: address of the circle buffer to be used
+ * @from: pointer to the data to be added
+ * @len: the length of the data to be added
+ * @off: data write offset in circle buffer
+ *
+ * Note: Check free space in circle buffer before calling this function
+ */
+static inline uint32_t circ_buf_write_data(circ_buf_t *cb, const uint8_t *from, uint32_t len, uint32_t off)
+{
+    uint32_t l = circ_buf_min(len, cb->size - off);
+
+    /* generate mute data if input buffer is NULL */
+    uint32_t (*action)(circ_buf_t *, const uint8_t *, uint32_t, uint32_t) =
+        (from == NULL) ? write_zero : write_data;
+
+    return action(cb, from, l, off) + action(cb, from + l, len - l, 0);
+}
+
+static inline uint32_t circ_buf_query_data(const circ_buf_t *cb)
+{
+    return circ_buf_data_size(*cb->write, *cb->read, cb->size);
+}
+
+static inline uint32_t circ_buf_query_free(const circ_buf_t *cb)
+{
+    return circ_buf_free_size(*cb->write, *cb->read, cb->size);
+}
+
+/* read data from circle buffer */
+static inline uint32_t circ_buf_read(circ_buf_t *cb, uint8_t *to, uint32_t len)
+{
+    uint32_t read = *cb->read;
+
+    if ((len == 0) || (circ_buf_data_size(*cb->write, read, cb->size) < len) ||
+        (circ_buf_read_data(cb, to, len, read) != len)) {
+        return 0;
+    }
+
+    *cb->read = circ_add(read, len, cb->size);
+    return len;
+}
+
+/* write data into circle buffer */
+static inline uint32_t circ_buf_write(circ_buf_t *cb, const uint8_t *from, uint32_t len)
+{
+    uint32_t write = *cb->write;
+
+    if ((len == 0) || (circ_buf_write_data(cb, from, len, write) != len)) {
+        return 0;
+    }
+
+    *cb->write = circ_add(write, len, cb->size);
+    return len;
+}
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif
+#endif /* __cplusplus */
+
+#endif
index cf2f437..e0f66b6 100644 (file)
Binary files a/code/sdk/middleware/services/gpu/api/rm/brandy-auto-ota-cli/libgfx_rm.a and b/code/sdk/middleware/services/gpu/api/rm/brandy-auto-ota-cli/libgfx_rm.a differ
index c384ab0..e261d1e 100644 (file)
Binary files a/code/sdk/middleware/services/gpu/api/rm/brandy-auto-ota-ser/libgfx_rm.a and b/code/sdk/middleware/services/gpu/api/rm/brandy-auto-ota-ser/libgfx_rm.a differ
index a731301..6977fba 100644 (file)
Binary files a/code/sdk/middleware/services/gpu/api/rm/brandy-native-js-r/libgfx_rm.a and b/code/sdk/middleware/services/gpu/api/rm/brandy-native-js-r/libgfx_rm.a differ
index 7337ef0..1dc614b 100644 (file)
Binary files a/code/sdk/middleware/services/gpu/api/rm/brandy-native-js/libgfx_rm.a and b/code/sdk/middleware/services/gpu/api/rm/brandy-native-js/libgfx_rm.a differ
index a24f28a..42fde02 100644 (file)
Binary files a/code/sdk/middleware/services/gpu/api/rm/brandy-target1-r/libgfx_rm.a and b/code/sdk/middleware/services/gpu/api/rm/brandy-target1-r/libgfx_rm.a differ
index 57524a6..1875744 100644 (file)
Binary files a/code/sdk/middleware/services/gpu/api/rm/brandy-target1/libgfx_rm.a and b/code/sdk/middleware/services/gpu/api/rm/brandy-target1/libgfx_rm.a differ
index 0058fbb..1bb189e 100644 (file)
Binary files a/code/sdk/middleware/services/gpu/api/rm/brandy-target3-r/libgfx_rm.a and b/code/sdk/middleware/services/gpu/api/rm/brandy-target3-r/libgfx_rm.a differ
index 3e1cbf2..c7a305e 100644 (file)
Binary files a/code/sdk/middleware/services/gpu/api/rm/brandy-target3/libgfx_rm.a and b/code/sdk/middleware/services/gpu/api/rm/brandy-target3/libgfx_rm.a differ
index 1a7ac64..40cfb3e 100644 (file)
Binary files a/code/sdk/middleware/services/gpu/api/rm/brandy-target4-r/libgfx_rm.a and b/code/sdk/middleware/services/gpu/api/rm/brandy-target4-r/libgfx_rm.a differ
index 071b1c1..373de55 100644 (file)
Binary files a/code/sdk/middleware/services/gpu/api/rm/brandy-target4/libgfx_rm.a and b/code/sdk/middleware/services/gpu/api/rm/brandy-target4/libgfx_rm.a differ
index 01b0f58..5415f9b 100644 (file)
Binary files a/code/sdk/middleware/services/gpu/api/rm/brandy-target5-r/libgfx_rm.a and b/code/sdk/middleware/services/gpu/api/rm/brandy-target5-r/libgfx_rm.a differ
index d55faab..ab930f1 100644 (file)
Binary files a/code/sdk/middleware/services/gpu/api/rm/brandy-target5/libgfx_rm.a and b/code/sdk/middleware/services/gpu/api/rm/brandy-target5/libgfx_rm.a differ
index a1b8c43..aa6e1d6 100644 (file)
Binary files a/code/sdk/middleware/services/gpu/api/rm/brandy-xts/libgfx_rm.a and b/code/sdk/middleware/services/gpu/api/rm/brandy-xts/libgfx_rm.a differ
index f845fbe..3cda536 100644 (file)
Binary files a/code/sdk/middleware/services/gpu/api/rm/testsuite-brandy-sdk/libgfx_rm.a and b/code/sdk/middleware/services/gpu/api/rm/testsuite-brandy-sdk/libgfx_rm.a differ
index e573bd6..c60cf0c 100644 (file)
@@ -72,9 +72,9 @@ static td_void disp_set_interrupt_thd(dpu_disp_timing *timing)
 {\r
 #ifdef GPU_SUPPORT_VIDEO_MODE\r
     td_u32 vtotal = timing->vact + timing->vbb + timing->vfb;\r
-    td_u32 vthd_percent_90 = vtotal * DPU_VTHD_PERCENT_90 / DPU_VTHD_PERCENT_100;\r
+    td_u32 vthd_percent_10 = vtotal * DPU_VTHD_PERCENT_10 / DPU_VTHD_PERCENT_100;\r
 \r
-    dpu_hal_disp_set_int_thd(DPU_DISP_INT_TYPE_SETTING, vthd_percent_90);\r
+    dpu_hal_disp_set_int_thd(DPU_DISP_INT_TYPE_SETTING, vthd_percent_10);\r
 #else\r
     td_u32 setting_thd;\r
     td_u32 finish_thd;\r
@@ -274,6 +274,13 @@ td_void dpu_disp_wait_frame_done(td_void)
     return;\r
 }\r
 \r
+#ifdef GPU_SUPPORT_VIDEO_MODE\r
+td_void dpu_disp_wait_vthd_percent_signal(td_void)\r
+{\r
+    dpu_isr_wait_vthd_percent_signal();\r
+}\r
+#endif\r
+\r
 td_void dpu_disp_wait_te_signal(td_void)\r
 {\r
     dpu_isr_wait_te_signal();\r
index 7eb31e2..643d44b 100644 (file)
@@ -34,7 +34,9 @@ td_void dpu_disp_open(td_void);
 td_void dpu_disp_close(td_void);\r
 \r
 td_void dpu_disp_chl_cfg(td_void);\r
-\r
+#ifdef GPU_SUPPORT_VIDEO_MODE\r
+td_void dpu_disp_wait_vthd_percent_signal(td_void);\r
+#endif\r
 td_void dpu_disp_wait_te_signal(td_void);\r
 td_void dpu_disp_wait_frame_done(td_void);\r
 td_u32 dpu_disp_get_srceen_width(td_void);\r
index e8214da..7bcade4 100644 (file)
@@ -13,6 +13,10 @@ typedef struct {
     osal_spinlock isr_lock;\r
     osal_wait finish_event;\r
     osal_wait te_signal_event;\r
+#ifdef GPU_SUPPORT_VIDEO_MODE\r
+    osal_wait vthd_percent_event;\r
+    volatile td_s32 vthd_percent_done;\r
+#endif\r
     volatile td_s32 finish_done;\r
     volatile td_s32 te_signal_done;\r
 } dpu_isr_info;\r
@@ -41,7 +45,7 @@ static td_void isr_disp_main(td_u32 param)
     }\r
 #ifdef GPU_SUPPORT_VIDEO_MODE\r
     if ((int_type & DPU_DISP_INT_TYPE_SETTING) == DPU_DISP_INT_TYPE_SETTING) {\r
-        g_dpu_isr_info.finish_done = 1;\r
+        g_dpu_isr_info.vthd_percent_done = 1;\r
     }\r
 #endif\r
     if ((int_type & DPU_DISP_INT_TYPE_TE_INT) == DPU_DISP_INT_TYPE_TE_INT) {\r
@@ -54,11 +58,7 @@ static td_void isr_disp_main(td_u32 param)
     }\r
 \r
     if ((int_type & DPU_DISP_INT_TYPE_FRM_DONE) == DPU_DISP_INT_TYPE_FRM_DONE) {\r
-#ifdef GPU_SUPPORT_VIDEO_MODE\r
-        g_dpu_isr_info.finish_done = 0;\r
-#else\r
         g_dpu_isr_info.finish_done = 1;\r
-#endif\r
         dfx_info->frm_done_cnt++;\r
         dfx_info->frm_done_total++;\r
         uapi_pm_remove_sleep_veto(PM_ID_DPU);\r
@@ -78,6 +78,11 @@ static td_void isr_disp_main(td_u32 param)
         dpu_dfx_print_info();\r
     }\r
     osal_spin_unlock_irqrestore(&g_dpu_isr_info.isr_lock, &flags);\r
+#ifdef GPU_SUPPORT_VIDEO_MODE\r
+    if (g_dpu_isr_info.vthd_percent_done == 1) {\r
+        osal_wait_wakeup(&g_dpu_isr_info.vthd_percent_event);\r
+    }\r
+#endif\r
 \r
     if (g_dpu_isr_info.finish_done == 1) {\r
         osal_wait_wakeup(&g_dpu_isr_info.finish_event);\r
@@ -104,6 +109,33 @@ static td_s32 isr_get_finish_done(const td_void *param)
     return g_dpu_isr_info.finish_done;\r
 }\r
 \r
+#ifdef GPU_SUPPORT_VIDEO_MODE\r
+static td_s32 isr_get_vthd_percent_signal_done(const td_void *param)\r
+{\r
+    uapi_unused(param);\r
+\r
+    return g_dpu_isr_info.vthd_percent_done;\r
+}\r
+\r
+static td_s32 dpu_init_vvthd_percent_event(void)\r
+{\r
+    td_s32 ret;\r
+    unsigned long flag = 0;\r
+\r
+    ret = osal_wait_init(&g_dpu_isr_info.vthd_percent_event);\r
+    if (ret != EXT_SUCCESS) {\r
+        dpu_err("dpu_init_vvthd_percent failed");\r
+        return DRV_ERR_DPU_OSAL_FAILED;\r
+    }\r
+\r
+    osal_spin_lock_irqsave(&g_dpu_isr_info.isr_lock, &flag);\r
+    g_dpu_isr_info.vthd_percent_done = 1;\r
+    osal_spin_unlock_irqrestore(&g_dpu_isr_info.isr_lock, &flag);\r
+\r
+    return EXT_SUCCESS;\r
+}\r
+#endif\r
+\r
 td_s32 dpu_isr_init(void)\r
 {\r
     td_s32 ret;\r
@@ -137,11 +169,24 @@ td_s32 dpu_isr_init(void)
     g_dpu_isr_info.finish_done = 1;\r
     osal_spin_unlock_irqrestore(&g_dpu_isr_info.isr_lock, &flag);\r
 \r
+#ifdef GPU_SUPPORT_VIDEO_MODE\r
+    ret = dpu_init_vvthd_percent_event();\r
+    if (ret != EXT_SUCCESS) {\r
+        osal_spin_lock_destroy(&g_dpu_isr_info.isr_lock);\r
+        osal_wait_destroy(&g_dpu_isr_info.finish_event);\r
+        osal_wait_destroy(&g_dpu_isr_info.te_signal_event);\r
+        return DRV_ERR_DPU_OSAL_FAILED;\r
+    }\r
+#endif\r
+\r
     ret = osal_irq_request(DPU_INT_DISP, (osal_irq_handler)isr_disp_main, TD_NULL, TD_NULL, TD_NULL);\r
     if (ret != EXT_SUCCESS) {\r
         osal_spin_lock_destroy(&g_dpu_isr_info.isr_lock);\r
         osal_wait_destroy(&g_dpu_isr_info.finish_event);\r
         osal_wait_destroy(&g_dpu_isr_info.te_signal_event);\r
+#ifdef GPU_SUPPORT_VIDEO_MODE\r
+        osal_wait_destroy(&g_dpu_isr_info.vthd_percent_event);\r
+#endif\r
         dpu_err("osal_irq_request failed, ret:0x%x", ret);\r
         return ret;\r
     }\r
@@ -194,6 +239,27 @@ td_void dpu_isr_wait_te_signal(void)
     return;\r
 }\r
 \r
+#ifdef GPU_SUPPORT_VIDEO_MODE\r
+td_void dpu_isr_wait_vthd_percent_signal(void)\r
+{\r
+    td_s32 ret;\r
+\r
+    ret = osal_wait_timeout_interruptible(&g_dpu_isr_info.vthd_percent_event,\r
+                                          isr_get_vthd_percent_signal_done, TD_NULL, 500); /* 500 ms */\r
+    if (ret <= 0) {\r
+        dpu_err("osal_wait_timeout!!!!");\r
+        return;\r
+    }\r
+\r
+    return;\r
+}\r
+\r
+td_void dpu_isr_clear_vthd_percent_flag(void)\r
+{\r
+    g_dpu_isr_info.vthd_percent_done = 0;\r
+}\r
+#endif\r
+\r
 td_void dpu_isr_clear_finish_flag(void)\r
 {\r
     g_dpu_isr_info.finish_done = 0;\r
@@ -204,11 +270,7 @@ td_s32 dpu_wait_all_finish(td_void)
 #ifndef GPU_SUPPORT_VIDEO_MODE\r
     unsigned long flag = 0;\r
     dpu_dfx_info *dfx_info = dpu_dfx_get_info();\r
-#ifdef BOARD_LEINIAO\r
-    const td_u32 wait_time = 1000;\r
-#else\r
     const td_u32 wait_time = 200;\r
-#endif\r
     td_u32 cnt = 0;\r
     static td_u32 dpu_timeout_cnt = 0;\r
 \r
index 4dedbc6..52ee08f 100644 (file)
@@ -18,6 +18,11 @@ extern "C" {
 td_s32 dpu_isr_init(void);\r
 td_void dpu_isr_deinit(void);\r
 \r
+#ifdef GPU_SUPPORT_VIDEO_MODE\r
+td_void dpu_isr_wait_vthd_percent_signal(void);\r
+td_void dpu_isr_clear_vthd_percent_flag(void);\r
+#endif\r
+\r
 td_void dpu_isr_wait_finish(void);\r
 td_void dpu_isr_wait_te_signal(void);\r
 td_void dpu_isr_clear_finish_flag(void);\r
index 599467c..feef105 100644 (file)
@@ -887,7 +887,9 @@ td_s32 dpu_layer_refresh(void)
     dfx_info->refresh_total++;\r
     dpu_dfx_get_time_us(&time_start);\r
 \r
-    dpu_disp_wait_frame_done();\r
+    dpu_disp_wait_vthd_percent_signal();\r
+    dpu_isr_clear_finish_flag();\r
+    dpu_isr_clear_vthd_percent_flag();\r
     dpu_layer_calculate_gp_region(&gp_region);\r
 \r
     for (layer_id = (td_u32)DRV_DPU_LAYER_ID1; layer_id <= (td_u32)DRV_DPU_MAX_LAYER_ID; layer_id++) {\r
@@ -908,6 +910,7 @@ td_s32 dpu_layer_refresh(void)
     }\r
     dpu_disp_set_chnl_reg_up();\r
 \r
+    dpu_disp_wait_frame_done();\r
     dpu_dfx_get_time_us(&time_end);\r
     dfx_info->refresh_intf_cost = (td_float)(time_end - time_start);\r
 #else\r
index a84928b..e994d4c 100644 (file)
 /**
  * @brief Hardware acceleration for drawing line. Prerequirement is ENABLE_VGU_ENGINE is 1.
  */
-#define CAPABILITY_HWDRAW_LINE            0
+#define CAPABILITY_HWDRAW_LINE            1
 /**
  * @brief Hardware acceleration for drawing arc. Prerequirement is ENABLE_VGU_ENGINE is 1.
  */
-#define CAPABILITY_HWDRAW_ARC             0
+#define CAPABILITY_HWDRAW_ARC             1
 /**
  * @brief Hardware acceleration for drawing cubic bezier curve. Prerequirement is ENABLE_VGU_ENGINE is 1.
  */
-#define CAPABILITY_HWDRAW_CURVE           0
+#define CAPABILITY_HWDRAW_CURVE           1
 /**
  * @brief Hardware acceleration for drawing rect. Prerequirement is ENABLE_VGU_ENGINE is 1.
  */
-#define CAPABILITY_HWDRAW_RECT           0
+#define CAPABILITY_HWDRAW_RECT           1
 /**
  * @brief Hardware acceleration for filling small size. Prerequirement is ENABLE_VGU_ENGINE is 1.
  */
-#define CAPABILITY_HWDRAW_SMALL_SIZE    0
+#define CAPABILITY_HWDRAW_SMALL_SIZE    1
 /**
  * @brief Whether open offline dial.
  */
-#define USE_OFFLINE_DIAL           1
+#define USE_OFFLINE_DIAL           0
 
 // if ENABLE_OPENVG is set to be 1, dislpay_vau.c should be compiled.
 #define ENABLE_OPENVG 0
 
 #define CAPABILITY_HW_SUPPORT_EMOJI 1
 #define CAPABILITY_SW_DFX_FRAME_TRACE 1
-
+#define ENABLE_DYNAMIC_FRAME_RATE 1
 #endif // GRAPHIC_HARDWARE_CONFIG_H
index 846db31..905fd92 100644 (file)
Binary files a/code/sdk/middleware/services/gui/hal/display/brandy-auto-ota-cli/libdisplay_gfx.a and b/code/sdk/middleware/services/gui/hal/display/brandy-auto-ota-cli/libdisplay_gfx.a differ
index 366791e..ad27789 100644 (file)
Binary files a/code/sdk/middleware/services/gui/hal/display/brandy-auto-ota-ser/libdisplay_gfx.a and b/code/sdk/middleware/services/gui/hal/display/brandy-auto-ota-ser/libdisplay_gfx.a differ
index 8864f8e..10dae95 100644 (file)
Binary files a/code/sdk/middleware/services/gui/hal/display/brandy-native-js/libdisplay_gfx.a and b/code/sdk/middleware/services/gui/hal/display/brandy-native-js/libdisplay_gfx.a differ
index 6c0dcec..e759632 100644 (file)
Binary files a/code/sdk/middleware/services/gui/hal/display/brandy-target1/libdisplay_gfx.a and b/code/sdk/middleware/services/gui/hal/display/brandy-target1/libdisplay_gfx.a differ
index 53a5e2d..bebd4ed 100644 (file)
Binary files a/code/sdk/middleware/services/gui/hal/display/brandy-target3/libdisplay_gfx.a and b/code/sdk/middleware/services/gui/hal/display/brandy-target3/libdisplay_gfx.a differ
index 2066cb7..8bae7ae 100644 (file)
Binary files a/code/sdk/middleware/services/gui/hal/display/brandy-target5/libdisplay_gfx.a and b/code/sdk/middleware/services/gui/hal/display/brandy-target5/libdisplay_gfx.a differ
index 17aa14c..1ea361e 100644 (file)
Binary files a/code/sdk/middleware/services/gui/hal/display/brandy-xts/libdisplay_gfx.a and b/code/sdk/middleware/services/gui/hal/display/brandy-xts/libdisplay_gfx.a differ
index 6001780..69e529f 100644 (file)
Binary files a/code/sdk/middleware/services/gui/lvgl/brandy-target1/liblvgl_proprietary_mini.a and b/code/sdk/middleware/services/gui/lvgl/brandy-target1/liblvgl_proprietary_mini.a differ
index 800c51c..1bcc7ca 100644 (file)
Binary files a/code/sdk/middleware/services/gui/lvgl/brandy-target5/liblvgl_proprietary.a and b/code/sdk/middleware/services/gui/lvgl/brandy-target5/liblvgl_proprietary.a differ
index 8f59074..cbec67e 100644 (file)
@@ -15,7 +15,7 @@ extern "C" {
 typedef void (*GraphicEventCb)(void*);
 
 /**
- * @brief Set frequence for graphic.
+ * @brief Set frequence for graphic, which is the max value during refresh
  */
 void SetFrequence(uint32_t freq);
 
index 19cce3e..9352deb 100644 (file)
@@ -122,9 +122,6 @@ list(REMOVE_ITEM COMPONENT_SRC ${UIKIT_ROOT_DIR}/ui/frameworks/components/ui_sur
 list(REMOVE_ITEM COMPONENT_SRC ${UIKIT_ROOT_DIR}/ui/frameworks/components/ui_video.cpp)\r
 list(REMOVE_ITEM COMPONENT_SRC ${UIKIT_ROOT_DIR}/ui/frameworks/dfx/performance_task.cpp)\r
 list(REMOVE_ITEM COMPONENT_SRC ${UIKIT_ROOT_DIR}/ui/frameworks/dfx/ui_screenshot.cpp)\r
-if(NOT "thunderbird_toys" IN_LIST TARGET_COMPONENT)\r
-    list(REMOVE_ITEM COMPONENT_SRC ${PROP_UI_SRC}/dfx/ws_net_task.cpp)\r
-endif()\r
 list(REMOVE_ITEM COMPONENT_SRC ${UIKIT_ROOT_DIR}/ui/frameworks/dock/lite_input_distributer.cpp)\r
 list(REMOVE_ITEM COMPONENT_SRC ${UIKIT_ROOT_DIR}/ui/frameworks/dock/ohos/ohos_input_device.cpp)\r
 list(REMOVE_ITEM COMPONENT_SRC ${UIKIT_ROOT_DIR}/ui/frameworks/dock/screen_device_proxy.cpp)\r
@@ -154,10 +151,6 @@ set(PRIVATE_HEADER
     ${ROOTDIR}/application/wearable/service/dial_market\r
     ${ROOTDIR}/open_source/openharmony/drivers/peripheral/format/interfaces/include\r
 )\r
-# 只有在雷鸟项目中才添加 ln_api.h 的头文件路径\r
-if("thunderbird_toys" IN_LIST TARGET_COMPONENT)\r
-    list(APPEND PRIVATE_HEADER ${ROOTDIR}/zhihui/leiniao/imsl_ln)\r
-endif()\r
 \r
 set(PRIVATE_DEFINES\r
 )\r
@@ -202,6 +195,7 @@ set(COMPONENT_SRC
     ${PROP_UI_SRC}/components_ext/image_cache_manager.cpp\r
     ${PROP_UI_SRC}/components_ext/ui_hexagons_list.cpp\r
     ${PROP_UI_SRC}/components_ext/ui_waterfall_list.cpp\r
+    ${PROP_UI_SRC}/components_ext/ui_planet_list.cpp\r
     ${PROP_UI_SRC}/components_ext/ui_canvas_ext.cpp\r
     ${PROP_UI_SRC}/components_ext/ui_card_container.cpp\r
     ${PROP_UI_SRC}/components_ext/ui_cross_view.cpp\r
@@ -211,6 +205,7 @@ set(COMPONENT_SRC
     ${PROP_UI_SRC}/components_ext/ui_map_view.cpp\r
     ${PROP_UI_SRC}/components_ext/map_svg_parser.cpp\r
     ${PROP_UI_SRC}/components_ext/ui_slipflow_view.cpp\r
+    ${PROP_UI_SRC}/components_ext/ui_foldable_view.cpp\r
     ${PROP_UI_SRC}/components_ext/ui_coverflow_view.cpp\r
     ${PROP_UI_SRC}/components_ext/ui_coverflow_view2.cpp\r
     ${PROP_UI_SRC}/components_ext/ui_icosahedron_view.cpp\r
@@ -219,6 +214,9 @@ set(COMPONENT_SRC
     ${PROP_UI_SRC}/components_ext/ui_sphere_view.cpp\r
     ${PROP_UI_SRC}/components_ext/particle_cell.cpp\r
     ${PROP_UI_SRC}/components_ext/ui_particle_view.cpp\r
+    ${PROP_UI_SRC}/components_ext/ui_float_box_view.cpp\r
+    ${PROP_UI_SRC}/components_ext/ui_scatter_plot.cpp\r
+    ${PROP_UI_SRC}/components_ext/ui_chart_pillar_ext.cpp\r
     ${lottie}\r
 )\r
 \r
@@ -263,3 +261,50 @@ set(MAIN_COMPONENT
 )\r
 \r
 build_component()\r
+\r
+# build traceui\r
+set(COMPONENT_NAME "graphics_ui_traceui")\r
+set(TRACEUI_SRC_DIR ${UIKIT_ROOT_DIR}/proprietary/src/ui/frameworks/dfx/traceui)\r
+\r
+if (DEFINES MATCHES "__LITEOS__")\r
+set(TRACEUI_SRC\r
+    ${TRACEUI_SRC_DIR}/traceui_buf.c\r
+    ${TRACEUI_SRC_DIR}/traceui_convert_perfetto_proto.c\r
+    ${TRACEUI_SRC_DIR}/traceui_core.c\r
+)\r
+endif()\r
+\r
+set(SOURCES\r
+    ${TRACEUI_SRC}\r
+)\r
+\r
+set(PUBLIC_HEADER\r
+    ${UIKIT_ROOT_DIR}/ui/interfaces/kits\r
+)\r
+\r
+set(PRIVATE_HEADER\r
+    ${public_headers}\r
+)\r
+\r
+set(PRIVATE_DEFINES\r
+)\r
+\r
+set(PUBLIC_DEFINES\r
+)\r
+\r
+# use this when you want to add ccflags like -include xxx\r
+set(COMPONENT_PUBLIC_CCFLAGS\r
+)\r
+\r
+set(COMPONENT_CCFLAGS\r
+)\r
+\r
+set(WHOLE_LINK\r
+    true\r
+)\r
+\r
+set(MAIN_COMPONENT\r
+    false\r
+)\r
+\r
+build_component()\r
index 7b71cd5..60abd6e 100644 (file)
Binary files a/code/sdk/middleware/services/gui/uikit/brandy-auto-ota-cli/libuikit_ext.a and b/code/sdk/middleware/services/gui/uikit/brandy-auto-ota-cli/libuikit_ext.a differ
index f8be69a..144a87c 100644 (file)
Binary files a/code/sdk/middleware/services/gui/uikit/brandy-auto-ota-ser/libuikit_ext.a and b/code/sdk/middleware/services/gui/uikit/brandy-auto-ota-ser/libuikit_ext.a differ
index 9d278be..e1bb71d 100644 (file)
Binary files a/code/sdk/middleware/services/gui/uikit/brandy-native-js/libuikit_ext.a and b/code/sdk/middleware/services/gui/uikit/brandy-native-js/libuikit_ext.a differ
index aa4d13d..5ec7776 100644 (file)
Binary files a/code/sdk/middleware/services/gui/uikit/brandy-target3/libuikit_ext.a and b/code/sdk/middleware/services/gui/uikit/brandy-target3/libuikit_ext.a differ
index 2cef996..2c8710a 100644 (file)
Binary files a/code/sdk/middleware/services/gui/uikit/brandy-xts/libuikit_ext.a and b/code/sdk/middleware/services/gui/uikit/brandy-xts/libuikit_ext.a differ
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/include/common/graphic_cond_ext.h b/code/sdk/middleware/services/gui/uikit/proprietary/include/common/graphic_cond_ext.h
new file mode 100644 (file)
index 0000000..ad2c3e3
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: GraphicCondExt
+ * Author: Hisi Graphic Team
+ * Created: 2025-8
+ */
+
+#include "graphic_mutex.h"
+
+namespace OHOS {
+class GraphicCondExt : public GraphicCond {
+public:
+    bool WaitTime(GraphicMutex &mutex, uint32_t time);
+};
+}  // namespace OHOS
index 72085c0..f4edfa3 100644 (file)
@@ -37,6 +37,7 @@
 #include "securec.h"
 #include "gfx_utils/image_info.h"
 #include "gfx_utils/heap_base.h"
+#include "gfx_utils/vector.h"
 #include "graphic_config.h"
 #include "hals/gralloc_engines.h"
 #include "graphic_mutex.h"
@@ -117,6 +118,13 @@ public:
      */
     void Dump();
 
+    void EnterAod();
+    void ExitAod();
+    bool IsInAod() const
+    {
+        return isInAod_;
+    }
+
 private:
     struct ImageNode;
     struct MultiImageInfo {
@@ -191,6 +199,11 @@ private:
         ListRemove(node);
         ListAdd(head, node);
     }
+
+    void RecordAodFile(const std::string &file);
+    bool IsRecordedAodFile(const std::string &file);
+    Graphic::Vector<std::string> recordedAodFiles_;
+    bool isInAod_ = false;
 };
 } // OHOS
 #endif // ENABLE_IMAGE_PACKER
index d8b6bbc..b58df71 100644 (file)
@@ -40,6 +40,7 @@
 #include "ibuffer_consumer_listener.h"\r
 #include "surface.h"\r
 #include "graphic_mutex.h"\r
+#include "common/graphic_cond_ext.h"\r
 \r
 namespace OHOS {\r
 enum class BufferState {\r
@@ -303,10 +304,13 @@ public:
      */\r
     void PrepareBuffers();\r
 \r
+    void AsyncClearBuffers();\r
+\r
     void ClearBuffers();\r
     SurfaceBuffer* GetBackBuf();\r
 \r
 protected:\r
+    void PrepareBuffersInner();\r
     void AddBuffer();\r
     BufferItem* GetBufferItem(const SurfaceBuffer* buffer);\r
     bool CanRequest(uint8_t wait);\r
@@ -320,7 +324,7 @@ protected:
     uint32_t strideAlignment_;\r
     uint32_t format_;\r
     GraphicMutex lock_;\r
-    GraphicCond cond_;\r
+    GraphicCondExt cond_;\r
     List<BufferItem*> buffers_;\r
     List<SurfaceBuffer*> freeList_;\r
     List<SurfaceBuffer*> dirtyList_;\r
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/include/common/periodicupdate_interface.h b/code/sdk/middleware/services/gui/uikit/proprietary/include/common/periodicupdate_interface.h
new file mode 100644 (file)
index 0000000..a198064
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) CompanyNameMagicTag 2025. All rights reserved.
+ * Description: PeriodicUpdateInterface
+ * Author:
+ * Create: 2025-10
+ */
+
+#ifndef PERIODIC_UPDATE_INTERFACE_H
+#define PERIODIC_UPDATE_INTERFACE_H
+
+namespace OHOS {
+class PeriodicUpdateInterface {
+public:
+    virtual void Update(void) = 0;
+    virtual uint32_t GetPeriod(void) = 0;
+    PeriodicUpdateInterface() = default;
+    virtual ~PeriodicUpdateInterface() = default;
+    PeriodicUpdateInterface(const PeriodicUpdateInterface&) = delete;
+    PeriodicUpdateInterface& operator=(const PeriodicUpdateInterface&) = delete;
+    PeriodicUpdateInterface(PeriodicUpdateInterface&&) = delete;
+    PeriodicUpdateInterface& operator=(PeriodicUpdateInterface&&) = delete;
+};
+}
+
+#endif // PERIODIC_UPDATE_INTERFACE_H
\ No newline at end of file
index ce3b1f0..12811a8 100644 (file)
@@ -23,49 +23,129 @@ const struct {
     uint32_t unicode;
     uint32_t resId;
 } EMOJI_TABLE[] = {
-    {0x1f600, 0x100001},
-    {0x1f601, 0x100002},
-    {0x1f602, 0x100003},
-    {0x1f603, 0x100004},
-    {0x1f604, 0x100005},
-    {0x1f605, 0x100006},
-    {0x1f606, 0x100007},
-    {0x1f607, 0x100008},
-    {0x1f608, 0x100009},
-    {0x1f609, 0x10000a},
-    {0x1f60a, 0x10000b},
-    {0x1f60b, 0x10000c},
-    {0x1f60c, 0x10000d},
-    {0x1f60d, 0x10000e},
-    {0x1f60e, 0x10000f},
-    {0x1f60f, 0x100010},
-    {0x1f610, 0x100011},
-    {0x1f611, 0x100012},
-    {0x1f612, 0x100013},
-    {0x1f613, 0x100014},
-    {0x1f614, 0x100015},
-    {0x1f615, 0x100016},
-    {0x1f616, 0x100017},
-    {0x1f617, 0x100018},
-    {0x1f618, 0x100019},
-    {0x1f619, 0x10001a},
-    {0x1f61a, 0x10001b},
-    {0x1f61b, 0x10001c},
-    {0x1f61c, 0x10001d},
-    {0x1f61d, 0x10001e},
-    {0x1f61e, 0x10001f},
-    {0x1f61f, 0x100020},
-    {0x1f620, 0x100021},
-    {0x1f621, 0x100022},
-    {0x1f622, 0x100023},
-    {0x1f623, 0x100024},
-    {0x1f624, 0x100025},
-    {0x1f625, 0x100026},
-    {0x1f626, 0x100027},
-    {0x1f627, 0x100028},
-    {0x1f628, 0x100029},
-    {0x1f629, 0x10002a},
+    {0x1f479, 0x10004f},
+    {0x1f47a, 0x100037},
+    {0x1f47b, 0x100036},
+    {0x1f47d, 0x100002},
+    {0x1f47e, 0x100001},
+    {0x1f47f, 0x100003},
+    {0x1f480, 0x100060},
+    {0x1f4a9, 0x100053},
+    {0x1f600, 0x10003e},
+    {0x1f601, 0x100008},
+    {0x1f602, 0x10002e},
+    {0x1f603, 0x10003b},
+    {0x1f604, 0x10003c},
+    {0x1f605, 0x10003d},
+    {0x1f606, 0x10003f},
+    {0x1f607, 0x100066},
+    {0x1f608, 0x100069},
+    {0x1f609, 0x10007a},
+    {0x1f60a, 0x10006a},
+    {0x1f60b, 0x10001e},
+    {0x1f60c, 0x100057},
+    {0x1f60d, 0x100067},
+    {0x1f60e, 0x10006b},
+    {0x1f60f, 0x10006e},
+    {0x1f610, 0x10004e},
+    {0x1f611, 0x100019},
+    {0x1f612, 0x100075},
+    {0x1f613, 0x100016},
+    {0x1f614, 0x100051},
+    {0x1f615, 0x10000e},
+    {0x1f616, 0x10000d},
+    {0x1f617, 0x100047},
+    {0x1f618, 0x10001a},
+    {0x1f619, 0x100046},
+    {0x1f61a, 0x100045},
+    {0x1f61b, 0x100030},
+    {0x1f61c, 0x100079},
+    {0x1f61d, 0x100071},
+    {0x1f61e, 0x100012},
+    {0x1f61f, 0x10007c},
+    {0x1f620, 0x100004},
+    {0x1f621, 0x100056},
+    {0x1f622, 0x100011},
+    {0x1f623, 0x100052},
+    {0x1f624, 0x10002c},
+    {0x1f625, 0x10005a},
+    {0x1f626, 0x100034},
+    {0x1f627, 0x100005},
+    {0x1f628, 0x100032},
+    {0x1f629, 0x100078},
+    {0x1f62a, 0x100062},
+    {0x1f62b, 0x100074},
+    {0x1f62c, 0x100038},
+    {0x1f62d, 0x100048},
+    {0x1f62e, 0x100027},
+    {0x1f62f, 0x100043},
+    {0x1f630, 0x100006},
+    {0x1f631, 0x10001f},
+    {0x1f632, 0x100007},
+    {0x1f633, 0x100033},
+    {0x1f634, 0x100061},
+    {0x1f635, 0x100014},
+    {0x1f636, 0x100031},
+    {0x1f637, 0x100024},
+    {0x1f638, 0x100039},
+    {0x1f639, 0x100009},
+    {0x1f63a, 0x10003a},
+    {0x1f63b, 0x100065},
+    {0x1f63c, 0x10000a},
+    {0x1f63d, 0x100044},
+    {0x1f63e, 0x100055},
+    {0x1f63f, 0x100010},
+    {0x1f640, 0x100077},
+    {0x1f641, 0x100063},
+    {0x1f642, 0x100064},
+    {0x1f643, 0x100076},
+    {0x1f644, 0x10002a},
+    {0x1f648, 0x10005c},
+    {0x1f649, 0x100040},
+    {0x1f64a, 0x100070},
+    {0x1f910, 0x10007f},
+    {0x1f911, 0x10004b},
+    {0x1f912, 0x10002f},
+    {0x1f913, 0x10004d},
+    {0x1f914, 0x100073},
+    {0x1f915, 0x100023},
+    {0x1f917, 0x100042},
+    {0x1f920, 0x10000f},
+    {0x1f921, 0x10000b},
+    {0x1f922, 0x10004c},
+    {0x1f923, 0x100059},
+    {0x1f924, 0x100017},
+    {0x1f925, 0x100049},
+    {0x1f927, 0x10006f},
+    {0x1f928, 0x100029},
+    {0x1f929, 0x100072},
+    {0x1f92a, 0x10007e},
+    {0x1f92b, 0x10005e},
+    {0x1f92c, 0x10002d},
+    {0x1f92d, 0x100022},
+    {0x1f92e, 0x100020},
+    {0x1f92f, 0x100018},
+    {0x1f970, 0x100068},
+    {0x1f971, 0x10007d},
+    {0x1f972, 0x10006c},
+    {0x1f973, 0x100050},
+    {0x1f974, 0x10007b},
+    {0x1f975, 0x100041},
+    {0x1f976, 0x10000c},
+    {0x1f978, 0x100013},
+    {0x1f979, 0x10001c},
+    {0x1f97a, 0x100054},
+    {0x1fae0, 0x10004a},
+    {0x1fae1, 0x10005b},
+    {0x1fae2, 0x100026},
+    {0x1fae3, 0x100028},
+    {0x1fae4, 0x100021},
+    {0x1fae5, 0x100015},
+    {0x1fae8, 0x10005d},
+    {0x1f64f, 0x100080},
+    {0x2764, 0x100081},
+    {0x1f44d, 0x100082},
 };
 } // OHOS
 
-#endif // UI_EMOJI_TABLE_H
\ No newline at end of file
+#endif // UI_EMOJI_TABLE_H
index 0b20002..7fe6056 100644 (file)
@@ -444,6 +444,8 @@ public:
      */
     void OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) override;
 
+    void ReMeasure() override;
+
 private:
     struct DrawCmd : public HeapBase {
         PaintExt* paint;
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_chart_pillar_ext.h b/code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_chart_pillar_ext.h
new file mode 100644 (file)
index 0000000..63515ec
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.
+ * Description: UIChartPillarExt
+ * Author: Hisi Graphic Team
+ * Created: 2025-9
+ */
+
+#ifndef GRAPHIC_LITE_UI_CHART_PILLAR_EXT_H
+#define GRAPHIC_LITE_UI_CHART_PILLAR_EXT_H
+
+#include "gfx_utils/vector.h"
+#include "components/ui_chart.h"
+
+namespace OHOS {
+/**
+ * @brief Provides special functions for implementing a bar chart.
+ */
+class UIChartPillarExt : public UIChartPillar {
+public:
+    /* *
+     * @brief Enumerates pillar chart types.
+     *
+     */
+    enum class PillarType {
+        PILLAR_NORMAL,
+        PILLAR_STACKED,
+        PILLAR_BUTT
+    };
+
+    /**
+     * @brief A constructor used to create a <b>UIChartPillarExt</b> instance.
+     */
+    UIChartPillarExt() {}
+
+    /**
+     * @brief A destructor used to delete the <b>UIChartPillarExt</b> instance.
+     */
+    ~UIChartPillarExt() override {}
+
+    /**
+     * @brief Obtains the view type.
+     *
+     * @return Returns <b>UI_CHART_PILLAR_EXT</b>, as defined in {@link UIViewType}.
+     */
+    UIViewType GetViewType() const override
+    {
+        return UI_CHART_PILLAR_EXT;
+    }
+
+    /**
+     * @brief Refreshes a bar chart and redraws the dirty region.
+     *
+     * Only the parts that need to be redrawn are refreshed, for example, new data points.
+     * This function provides better performance than {@link Invalidate}.
+     */
+    void RefreshChart() override;
+
+    /**
+     * @brief Set pillar type.
+     * @param type pillar type.
+     */
+    void SetPillarType(PillarType type)
+    {
+        pillarType_ = type;
+    }
+
+    /**
+     * @brief Get pillar type.
+     * @return pillar type.
+     */
+    PillarType GetPillarType()
+    {
+        return pillarType_;
+    }
+
+    /**
+     * @brief Set pillar percentage.
+     * @param percentage pillar percentage, range is 0 to 1.0.
+     */
+    void SetPillarPercentage(float percentage)
+    {
+        if (FloatLess(percentage, 0)) {
+            percentage = 0;
+            GRAPHIC_LOGW("Min percentage is 0, less than 0 should be set 0.");
+        }
+        if (FloatMore(percentage, 1)) {
+            percentage = 1;
+            GRAPHIC_LOGW("Max percentage is 1.0, more than 1.0 should be set 1.0.");
+        }
+        pillarPercentage_ = percentage;
+    }
+
+    /**
+     * @brief Get pillar percentage.
+     * @return pillar percentage.
+     */
+    float GetPillarPercentage()
+    {
+        return pillarPercentage_;
+    }
+
+protected:
+    void DrawDataSerials(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) override;
+
+private:
+    /**
+     * @brief Defines the font style.
+     */
+    struct StackedLineData {
+        /** Start Point. */
+        Point start;
+        /** End Point. */
+        Point end;
+        /** Width of each bar. */
+        uint16_t barWidth;
+        /** Index of the bar. */
+        uint16_t index;
+        /** Accumulate height of the bar. */
+        int16_t aclHeight;
+    };
+    float pillarPercentage_ = 0.4;
+    PillarType pillarType_ = PillarType::PILLAR_NORMAL;
+    void DrawNormalPillarData(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea);
+    void DrawStackedPillarData(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea);
+    void DrawStackedLine(BufferInfo& gfxDstBuffer, Rect mask,
+        StackedLineData lineData, ListNode<UIChartDataSerial*>* iter);
+    void DrawLine(BufferInfo& gfxDstBuffer, const Rect& mask, Point start, Point end, int16_t width,
+        ColorType color);
+    void DrawEllipse(BufferInfo& gfxDstBuffer, const Rect& mask, Point start, Point end, int16_t width,
+        ColorType color);
+#if ENABLE_VGU_ENGINE && CAPABILITY_HWDRAW_PATH
+    void HWDrawEllipse(BufferInfo& gfxDstBuffer, const Rect& mask, Point start, Point end, int16_t width,
+        uint32_t color);
+#endif
+};
+} // namespace OHOS
+#endif // GRAPHIC_LITE_UI_CHART_PILLAR_EXT_H
+/**
+ * @}
+ */
index 8c4b41b..68dea82 100644 (file)
@@ -42,6 +42,11 @@ public:
      */\r
     void Remove(const char* id);\r
 \r
+    /**\r
+     * @brief  Clear all items.\r
+     */\r
+    void ClearAll();\r
+\r
     /**\r
      * @brief Set image size.\r
      *\r
index 114ee72..c2f17c1 100644 (file)
@@ -238,6 +238,25 @@ public:
      */
     void SetSwipeACCLevel(uint8_t value, uint8_t direction = 0);
 
+    /**
+    * @brief Set scale factor for screen capture.
+    * @param scale The scale factor to set.
+    * @since 1.0
+    * @version 1.0
+    */
+    void SetScaleFactor(float scale);
+
+    /**
+    * @brief Retrieves the current scale factor.
+    * @return The current scale factor.
+    * @since 1.0
+    * @version 1.0
+    */
+    float GetScaleFactor() const
+    {
+        return scale_;
+    }
+
 private:
     using UIViewGroup::Remove;
     float blurRadius_ = 10.0f;
@@ -256,6 +275,7 @@ private:
     bool isNeedClip_ = false;
     std::shared_ptr<bool> exists_;
     bool waitProcessRes_ = false;
+    float scale_ = 1.0f;
 
     void RemoveAllInner(UISwipeView& view);
     void ProcessRes(bool loadAdjacent = true);
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_custom_planet_list.h b/code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_custom_planet_list.h
new file mode 100644 (file)
index 0000000..5839ec8
--- /dev/null
@@ -0,0 +1,36 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.\r
+ * Description: UICustomPlanetList\r
+ * Create: 2025-05\r
+ */\r
+\r
+#ifndef UI_CUSTOM_PLANET_LIST_H\r
+#define UI_CUSTOM_PLANET_LIST_H\r
+\r
+#include "components/ui_planet_list.h"\r
+#include "components/ui_label.h"\r
+#include "components/ui_transform_group.h"\r
+\r
+namespace OHOS {\r
+class UICustomPlanetList : public UIPlanetList {\r
+public:\r
+    UICustomPlanetList(uint16_t itemSize, uint16_t imgDistance)\r
+        : UIPlanetList(itemSize, imgDistance)\r
+    {\r
+    }\r
+    ~UICustomPlanetList() override {}\r
+    UICustomPlanetList(const UICustomPlanetList &) = delete;\r
+    UICustomPlanetList &operator=(const UICustomPlanetList &) = delete;\r
+    /**\r
+     * @brief Obtains the view type.\r
+     *\r
+     * @return Returns <b>UI_CUSTOM_PLANET_LIST</b>, as defined in {@link UIViewType}.\r
+     */\r
+    UIViewType GetViewType() const override\r
+    {\r
+        return UI_CUSTOM_PLANET_LIST;\r
+    }\r
+}; // class UICustomPlanetList\r
+} // namespace OHOS\r
+\r
+#endif // UI_CUSTOM_PLANET_VIEW_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_float_box_view.h b/code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_float_box_view.h
new file mode 100644 (file)
index 0000000..8781872
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: UIFloatBoxView
+ * Author: Hisi Graphic Team
+ * Created: 2025-8
+ */
+#ifndef UI_FLOAT_BOX_VIEW_H
+#define UI_FLOAT_BOX_VIEW_H
+
+#include <cstring>
+#include "components/ui_view.h"
+#include "components/ui_image_view.h"
+#include "common/graphic_hardware_types.h"
+#include "gfx_utils/image_info.h"
+#include "gfx_utils/list.h"
+#include "gfx_utils/vector.h"
+#include "animator/animator.h"
+
+namespace OHOS {
+struct FloatItem {
+    std::string name;
+    ImageInfo* imgInfo;
+};
+
+struct FloatItemInfo {
+    std::string name;
+    ImageInfo* imgInfo;
+    float angle;
+};
+
+class UIFloatBoxView : public UIView {
+public:
+    class OnItemClickListener : public HeapBase {
+    public:
+        /**
+         * @brief Called when an item is clicked.
+         * @param name Indicates the name of clicked item
+         */
+        virtual void OnItemClick(const std::string& name) = 0;
+
+        virtual ~OnItemClickListener() {}
+    };
+
+    UIFloatBoxView();
+
+    virtual ~UIFloatBoxView();
+
+    /**
+     * @brief  Set OnItemClickListener.
+     */
+    void SetOnItemClickListener(UIFloatBoxView::OnItemClickListener* listener);
+
+    /**
+     * @brief  Get OnItemClickListener.
+     */
+    UIFloatBoxView::OnItemClickListener*& GetOnItemClickListener();
+
+    /**
+     * @brief  Add items, each with a unique name. Count of floatItems must be in range [2, 3].
+     *         The image content should be in circle shape. ImageInfo will be deep copied.
+     */
+    bool AddItems(FloatItem* floatItems, uint8_t floatItemsCnt);
+
+    /**
+     * @brief  Clear all items.
+     */
+    void ClearItems();
+
+    /**
+     * @brief  Get current cnt of items.
+     */
+    uint16_t GetItemCnt() const;
+
+    /**
+     * @brief  Set an float item's size. Size is an item's width and height.
+     *         Item size must be set and should be greater than 0.
+     */
+    void SetItemSize(uint16_t size);
+
+    /**
+     * @brief  Set the spacing distance between float items. Item spacing must be set and should be greater than 0.
+     */
+    void SetItemSpacing(uint16_t spacing);
+
+    /**
+     * @brief  Set drag factor.
+     */
+    void SetDragFactor(float value);
+
+    /**
+     * @brief  Get drag factor.
+     */
+    float GetDragFactor() const;
+
+    /**
+     * @brief  Set swipe acceleration factor.
+     */
+    void SetAccFactor(float factor);
+
+    /**
+     * @brief  Get swipe acceleration factor.
+     */
+    float GetAccFactor() const;
+
+    /**
+     * @brief  Set rotate factor.
+     */
+    void SetRotateFactor(float value);
+
+    /**
+     * @brief  Get rotate factor.
+     */
+    float GetRotateFactor() const;
+
+    /**
+     * @brief  Set align anim's avg speed. Align offset / speed = Anim times.
+     */
+    void SetAlignAvgSpeed(float speed);
+
+    /**
+     * @brief  Get align anim's avg speed.
+     */
+    float GetAlignAvgSpeed() const;
+
+    /**
+     * @brief Set the color for background arc.
+     */
+    void SetBgArcColor(uint32_t color);
+
+    bool OnDragEvent(const DragEvent& event) override;
+    bool OnDragEndEvent(const DragEvent& event) override;
+#if ENABLE_ROTATE_INPUT
+    bool OnRotateEvent(const RotateEvent& event) override;
+    bool OnRotateEndEvent(const RotateEvent& event) override;
+#endif
+    bool OnClickEvent(const ClickEvent& event) override;
+    void ReMeasure() override;
+    void OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) override;
+
+    UIViewType GetViewType() const override
+    {
+        return UI_FLOAT_BOX_VIEW;
+    }
+
+private:
+    class AlignAnimatorCallback : public AnimatorCallback {
+    public:
+        AlignAnimatorCallback()
+            : curTime_(0),
+              animTime_(0),
+              previousAngle_(0),
+              angle_(0)
+        {
+        }
+
+        virtual ~AlignAnimatorCallback() {}
+
+        void SetAnimTimes(uint16_t times)
+        {
+            animTime_ = times;
+        }
+
+        void SetAngle(float angle)
+        {
+            angle_ = angle;
+        }
+
+        void ResetCallback()
+        {
+            angle_ = 0;
+            previousAngle_ = 0;
+            animTime_ = 0;
+            curTime_ = 0;
+        }
+
+        virtual void Callback(UIView* view) override;
+
+        uint16_t curTime_;
+        uint16_t animTime_;
+        float previousAngle_;
+        float angle_;
+    };
+
+    bool ParamCheck();
+    void PrepAlign(float angle = 0.0f);
+    bool RenderBgArc();
+    void BlitItem(ImageInfo* info, float x, float y);
+    void UpdateItem(float angle);
+    Vector2<float> GetItemPosFromAngle(float angle);
+    FloatItemInfo* GetClickedItem(Point point);
+    void StopAlignAnim();
+    float GetAdjustedAngle(float angle);
+    void PrepContentInfo();
+
+    Graphic::Vector<FloatItemInfo> items_;
+    ImageInfo contentImg_ = {0};
+    BufferInfo contentBuf_ = {{0, 0, 0, 0}};
+
+    float dragFactor_ = 1.0f;
+    float accFactor_ = 3.0f;
+    float rotateFactor_ = 3.0f;
+    float alignAvgSpeed_ = 5.0f;
+    uint32_t bgArcColor_ = Color::Gray().full;
+    Path bgPath_ = {0};
+
+    const float START_ANGLE = 115; // start angle without round cap
+    const uint16_t MIN_ALIGN_ANIM_TIMES = 3;
+    const uint8_t MIN_ITEM_CNT = 2;
+    const uint8_t MAX_ITEM_CNT = 3;
+    uint16_t itemSize_ = 0;
+    uint16_t itemSpacing_ = 0;
+    float radius_ = 0.0f;
+    float arcWidth_ = 0.0f;
+    float itemAngle_ = 0.0f;
+    float spacingAngle_ = 0.0f;
+    float roundCapAngle_ = 0.0f;
+    float startAngle_ = 0.0f;
+    float endAngle_ = 0.0f;
+    float totalAngle_ = 0.0f;
+    bool needRemeasure_ = true;
+    OnItemClickListener* onItemClickListener_ = nullptr;
+
+    Animator alignAnim_;
+    AlignAnimatorCallback alignCallback_;
+    Rect contentArea_;
+};
+}
+#endif
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_foldable_view.h b/code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_foldable_view.h
new file mode 100644 (file)
index 0000000..5c157ce
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) CompanyNameMagicTag 2025. All rights reserved.
+ * Description: UIFoldableView
+ * Author:
+ * Create: 2025-09
+ */
+
+#ifndef UI_FOLDABLE_VIEW_H
+#define UI_FOLDABLE_VIEW_H
+
+#include "components/ui_abstract_scroll.h"
+
+namespace OHOS {
+class UIFoldableView : public UIAbstractScroll {
+public:
+    explicit UIFoldableView();
+    ~UIFoldableView() override;
+
+    /**
+     * @brief Adds a child view.
+     *
+     * @param view Indicates the pointer to the child view to add.
+     */
+    void Add(UIView* view) override;
+
+    /**
+     * @brief remove a child view from foldable.
+     *
+     * @param view Indicates the pointer to the child view to remove.
+     */
+    void Remove(UIView* view) override;
+
+    /**
+     * @brief Removes all child views.
+     */
+    void RemoveAll() override;
+
+    /**
+     * @brief pin a child view on top.
+     *
+     * @param view Indicates the pointer to the child view to pin on top.
+     */
+    void PinOnTop(UIView* view);
+
+    /**
+     * @brief Set max page num.
+     *
+     * @param maxPageNum The max page num.
+     */
+    void SetMaxPageNum(uint8_t maxPageNum);
+
+    /**
+     * @brief Set page size.
+     *
+     * @param width The page width.
+     * @param height The page height.
+     */
+    void SetPageSize(uint16_t width, uint16_t height);
+
+    /**
+     * @brief Get the page width.
+     *
+     * @return Returns the page width
+     */
+    uint16_t GetPageWidth() const
+    {
+        return pageWidth_;
+    }
+
+    /**
+     * @brief Get the page height.
+     *
+     * @return Returns the page height
+     */
+    uint16_t GetPageHeight() const
+    {
+        return pageHeight_;
+    }
+
+    /**
+     * @brief Obtains the component type.
+     *
+     * @return Returns the component type, as defined in {@link UIViewType}.
+     */
+    UIViewType GetViewType() const override
+    {
+        return UI_FOLDABLE_VIEW;
+    }
+
+    /**
+     * @brief Set the gradient of the scaling coefficient decreases from the lower page to the upper page
+     *
+     * @param scaleGradient The gradient of the scaling coefficient decreases from the lower page to the upper page
+     */
+    void SetFoldScaleGradient(float scaleGradient);
+
+    /**
+     * @brief Set the opacity change for the folded page.
+     *
+     * @param expandPageOpacity The opacity of expand pages
+     * @param minFoldPageOpacity The min opacity of fold pages
+     * @param opacityGradient The gradient of the opacity decreases from the upper page to the lower page
+     */
+    void SetFoldOpacityChange(uint8_t expandPageOpacity, uint8_t minFoldPageOpacity, uint8_t opacityGradient);
+
+    /**
+     * @brief Set the blank space between expanded pages
+     *
+     * @param margin The blank space between expanded pages
+     */
+    void SetMarginBetweenExpandPages(uint16_t margin);
+
+    /**
+     * @brief Set the drag offset for the Y-axis
+     *
+     * @param offset The drag offset for the Y-axis
+     */
+    void SetDragYoffset(int16_t offset);
+
+    /**
+     * @brief Get the drag offset for the Y-axis
+     *
+     * @return Returns the drag offset for the Y-axis
+     */
+    int16_t GetDragYoffset()
+    {
+        return dragYoffset_;
+    }
+
+    /**
+     * @brief Get the fully expand drag offset for the Y-axis
+     *
+     * @return Returns the fully expand drag offset for the Y-axis
+     */
+    int16_t GetFullyExpandDragYoffset()
+    {
+        return maxExpandDragYoffset_;
+    }
+
+    /**
+     * @brief Get the drag offset for the Y-axis
+     *
+     * @param currentPos The current point
+     * @param offset The last point
+     *
+     * @return Returns the drag throw distance
+     */
+    int16_t CalculateDragThrowYDistance(Point currentPos, Point lastPos);
+
+    /**
+     * @brief Set the over scroll up limit
+     *
+     * @param limit The over scroll up limit
+     */
+    void SetOverScrollUpLimit(uint16_t limit);
+
+    /**
+     * @brief Set the over scroll down limit
+     *
+     * @param limit The over scroll down limit
+     */
+    void SetOverScrollDownLimit(uint16_t limit);
+
+    /**
+     * @brief Sliding out gradually from the top
+     */
+    void StartTopSlidOutAnimator();
+
+    /**
+     * @brief Sliding in gradually from the top
+     *
+     * @param startInPlace Indicates animotor start in place or not
+     */
+    void StartTopSlidInAnimator(bool startInPlace);
+
+    /**
+     * @brief Sliding out gradually from the bottom
+     */
+    void StartBottomSlidOutAnimator();
+
+    /**
+     * @brief Sliding in gradually from the bottom
+     *
+     * @param startInPlace Indicates animotor start in place or not
+     */
+    void StartBottomSlidInAnimator(bool startInPlace);
+
+    /**
+     * @brief realize drag event, Switch to specified view when drag
+     *
+     * @param event The drag event
+     * @return Returns <b>true</b> if the event is consumed; returns <b>false</b> otherwise.
+     *         (If an event is consumed, it is not transferred to the parent view. If an event is not consumed,
+     *         it is transferred to the parent view after local processing is complete.)
+     */
+    bool OnDragEvent(const DragEvent& event) override;
+
+    /**
+     * @brief realize drag start event, Switch to specified view when drag start
+     *
+     * @param event The drag event start
+     * @return Returns <b>true</b> if the event is consumed; returns <b>false</b> otherwise.
+     *         (If an event is consumed, it is not transferred to the parent view. If an event is not consumed,
+     *         it is transferred to the parent view after local processing is complete.)
+     */
+
+    bool OnDragStartEvent(const DragEvent& event) override;
+
+    /**
+     * @brief realize drag end event, Switch to specified view when drag end
+     *
+     * @param event The drag event end
+     * @return Returns <b>true</b> if the event is consumed; returns <b>false</b> otherwise.
+     *         (If an event is consumed, it is not transferred to the parent view. If an event is not consumed,
+     *         it is transferred to the parent view after local processing is complete.)
+     */
+    bool OnDragEndEvent(const DragEvent& event) override;
+
+    /**
+     * @brief Represents a listener for scroll of the foldable view.
+     */
+    class OnFoldableViewEventListener : public HeapBase {
+    public:
+        virtual ~OnFoldableViewEventListener() {};
+
+        /**
+        * @brief Notify the holder that the foldable view has been scrolled.
+        *
+        * @param dragYoffset The cumulative distance of the scroll.
+        */
+        virtual void OnScroll(int16_t dragYoffset) {};
+
+        /**
+        * @brief Notify the holder that the foldable view has been over scrolled up.
+        */
+        virtual void OnOverScrollUp(int16_t dragYoffset, int16_t overDistance)
+        {
+            OnScroll(dragYoffset);
+        }
+
+        /**
+        * @brief Notify the holder that the foldable view has been over scrolled up.
+        */
+        virtual void OnOverScrollDown(int16_t dragYoffset, int16_t overDistance)
+        {
+            OnScroll(dragYoffset);
+        }
+
+        /**
+        * @brief Notify the holder that the top slid out animator stoped.
+        */
+        virtual void OnTopSlidOutAnimatorStop() {};
+
+        /**
+        * @brief Notify the holder that the top slid in animator stoped.
+        */
+        virtual void OnTopSlidInAnimatorStop() {};
+
+        /**
+        * @brief Notify the holder that the bottom slid out animator stoped.
+        */
+        virtual void OnBottomSlidOutAnimatorStop() {};
+
+        /**
+        * @brief Notify the holder that the bottom slid int animator stoped.
+        */
+        virtual void OnBottomSlidInAnimatorStop() {};
+    };
+
+    /**
+     * @brief Sets the listener that contains a callback to be invoked upon a scroll event.
+     *
+     * @param listener Indicates the listener to set.
+     */
+    void SetFoldableScrollListener(OnFoldableViewEventListener* listener)
+    {
+        scrollListener_ = listener;
+    }
+
+    void SetDirection(uint8_t direction) = delete;
+    uint8_t GetDirection() const = delete;
+protected:
+    void LayoutChildPages();
+    bool DragYInner(int16_t distance) override;
+    bool DragXInner(int16_t distance) override;
+    void StopAnimator() override;
+    int16_t GetDragThrowYDistance(const DragEvent& event);
+    /* swipe acceleration calculation coefficient */
+    static constexpr uint8_t SWIPE_ACC_FACTOR = 10;
+    /* animation drag acceleration level */
+    static constexpr uint8_t ANIMATION_DRAG_ACC_LEVEL = 48;
+
+private:
+    bool CheckDragLimit(int16_t distance);
+    void CalculateTotalYoffset(int16_t distance);
+    void LayoutFoldPageByOffset(int16_t distance);
+    void LayoutFoldPageByExpandPage(UIView *tailInsidePage, UIView *headOutsidePage, int16_t offset);
+    void RecursionLayoutFoldPages(UIView *prePage, float &scale, uint8_t &opacity);
+    void RecursionLayoutExpandPages(UIView *prePage);
+    bool IsSlidingInOrOutFromEdge();
+
+    OnFoldableViewEventListener* scrollListener_;
+    uint8_t maxPageNum_;
+    uint16_t pageWidth_;
+    uint16_t pageHeight_;
+    float scaleGradient_ = 0.0;
+    uint8_t opacityGradient_ = 0;
+    uint8_t expandPageOpacity_ = 0;
+    uint8_t minFoldPageOpacity_ = 0;
+    uint16_t expandPageMargin_ = 0;
+    uint16_t overScrollUpLimit_ = 0;
+    uint16_t overScrollDownLimit_ = 0;
+    int16_t dragYoffset_ = 0;
+
+    int16_t maxExpandDragYoffset_ = 0;
+    int16_t startDragYoffset_ = 0;
+    float pitchCoe_ = 0.0;
+    uint16_t pitchOutsidePage_ = 0;
+    int8_t startDragDirection_ = 0;
+    bool topSlidingOut_ = false;
+    bool topSlidOutPending_ = false;
+    bool topSlidingIn_ = false;
+    bool bottomSlidingOut_ = false;
+    bool bottomSlidOutPending_ = false;
+    bool bottomSlidingIn_ = false;
+    UIView *tailInsidePage_ = NULL;
+    uint8_t orgDragAccCoefficient_ = 0;
+    bool disableCurDrag_ = false;
+};
+} // namespace OHOS
+#endif // UI_FOLDABLE_VIEW_H
index f2c5312..d405fd4 100644 (file)
@@ -110,6 +110,8 @@ private:
         float rotate_ = 0.0f;
     };
 
+    void BlitKaleidoscopeImg(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea);
+
 #if ENABLE_ROTATE_INPUT
     float factor_ = 1.0f;
 #endif
@@ -117,6 +119,7 @@ private:
     KaleidoscopeUtils kaleidoscope_;
     RotateCallback callback_;
     Animator* animator_ = nullptr;
+    bool directFb_ = false;
 };
 }
 #endif
index af0149d..daccec1 100644 (file)
@@ -17,6 +17,16 @@ public:
 
     ~UIListNested() override {}
 
+    /**
+     * @brief Obtains the view type.
+     *
+     * @return Returns <b>UI_LIST_NESTED</b>, as defined in {@link UIViewType}.
+     */
+    UIViewType GetViewType() const override
+    {
+        return UI_LIST_NESTED;
+    }
+
     bool OnDragStartEvent(const DragEvent& event) override;
 
     bool OnDragEvent(const DragEvent& event) override;
index b25856b..824ae81 100644 (file)
@@ -170,6 +170,8 @@ public:
 
     std::string GetGuiInfo() const override;
 
+    friend void GetYuv2RgbTimeByUILiteSurfaceView(UILiteSurfaceView*);
+
 private:
     UILiteSurfaceView(const UILiteSurfaceView&) = delete;
     UILiteSurfaceView &operator=(const UILiteSurfaceView&) = delete;
@@ -178,6 +180,7 @@ private:
     bool isLayerInit_ : 1;
     uint8_t flushCount_;
     std::shared_ptr<LiteSurface> surface_ = nullptr;
+    std::shared_ptr<bool> exist_;
     SurfaceBuffer* lastFlushedBuffer_ = nullptr;
     SurfaceBuffer* currentBuffer_ = nullptr;
     GraphicMutex lock_;
index d7e9fb3..59bf55d 100644 (file)
@@ -94,11 +94,6 @@ public:
      */
     uint32_t GetTime();
 
-    /**
-     * @brief  Specifies whether to repeat particle animation.
-     */
-    void SetRepeat(bool repeat);
-
     /**
      * @brief  Returns whether to repeat particle animation.
      */
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_planet_list.h b/code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_planet_list.h
new file mode 100644 (file)
index 0000000..cc52cbd
--- /dev/null
@@ -0,0 +1,248 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.\r
+ * Description: UIPlanetList\r
+ * Create: 2025-05\r
+ */\r
+\r
+#ifndef UI_PLANET_LIST_H\r
+#define UI_PLANET_LIST_H\r
+\r
+#include <map>\r
+#include "animator/animator.h"\r
+#include "animator/easing_equation.h"\r
+#include "components/ui_abstract_scroll.h"\r
+#include "components/ui_scroll_view.h"\r
+#include "components/ui_view.h"\r
+#include "components/ui_label.h"\r
+#include "gfx_utils/list.h"\r
+#include "gfx_utils/vector.h"\r
+\r
+namespace OHOS {\r
+class UIPlanetList : public UIAbstractScroll {\r
+public:\r
+    UIPlanetList(uint16_t itemSize, uint16_t imgDistance);\r
+    ~UIPlanetList();\r
+\r
+    void AddItemVIew(UIView* view);\r
+    void AddLabel(UIView* view);\r
+    void MoveChildTo(int16_t posX, int16_t posY);\r
+    bool OnDragStartEvent(const DragEvent& event) override;\r
+    bool OnDragEvent(const DragEvent& event) override;\r
+    bool OnDragEndEvent(const DragEvent& event) override;\r
+    bool OnRotateStartEvent(const RotateEvent& event) override;\r
+    bool OnRotateEvent(const RotateEvent& event) override;\r
+    bool OnRotateEndEvent(const RotateEvent& event) override;\r
+    void LayoutChildren(bool needInvalidate = false) override;\r
+    void MoveChildByOffset(int16_t offsetX, int16_t offsetY) override;\r
+    void SetItemClickListener(UIView::OnClickListener* itemClickListener);\r
+    void AddClickListenerToAppItems();\r
+    void RestoreItemState();\r
+\r
+    UIViewType GetViewType() const override\r
+    {\r
+        return UI_PLANET_LIST;\r
+    }\r
+\r
+    void SetImageDistance(uint16_t distance)\r
+    {\r
+        imgDistance_ = distance;\r
+    }\r
+\r
+    uint16_t GetImageDistance()\r
+    {\r
+        return imgDistance_;\r
+    }\r
+\r
+    void SetImageSize(uint16_t size)\r
+    {\r
+        itemSize_ = size;\r
+    }\r
+\r
+    uint16_t GetImageSize()\r
+    {\r
+        return itemSize_;\r
+    }\r
+\r
+    void SetLastOffset(int16_t x, int16_t y)\r
+    {\r
+        lastQuitOffset_.x_ = x;\r
+        lastQuitOffset_.y_ = y;\r
+    }\r
+\r
+    void GetLastOffset(int16_t& x, int16_t& y);\r
+\r
+protected:\r
+    enum SwipeEdge {\r
+        LEFT = 1,\r
+        RIGHT = 1 << 1,\r
+        UP = 1 << 2,\r
+        DOWN = 1 << 3\r
+    };\r
+\r
+    class RotateAnimatorCallback : public AnimatorCallback {\r
+    public:\r
+        RotateAnimatorCallback()\r
+            : startTimes_(0),\r
+              endTimes_(0),\r
+              startValueX_(0),\r
+              endValueX_(0),\r
+              startValueY_(0),\r
+              endValueY_(0)\r
+        {\r
+        }\r
+\r
+        virtual ~RotateAnimatorCallback() {}\r
+\r
+        void SetDragTimes(uint16_t times)\r
+        {\r
+            endTimes_ = times;\r
+        }\r
+\r
+        void SetDragStartValue(int16_t startValueX, int16_t startValueY)\r
+        {\r
+            startValueX_ = startValueX;\r
+            startValueY_ = startValueY;\r
+        }\r
+\r
+        void SetDragEndValue(int16_t endValueX, int16_t endValueY)\r
+        {\r
+            endValueX_ = endValueX;\r
+            endValueY_ = endValueY;\r
+        }\r
+\r
+        void ResetCallback()\r
+        {\r
+            startTimes_ = 0;\r
+            endTimes_ = 0;\r
+            startValueX_ = 0;\r
+            endValueX_ = 0;\r
+            startValueY_ = 0;\r
+            endValueY_ = 0;\r
+        }\r
+\r
+        virtual void Callback(UIView* view);\r
+\r
+        uint16_t startTimes_;\r
+        uint16_t endTimes_;\r
+        int16_t startValueX_;\r
+        int16_t endValueX_;\r
+        int16_t startValueY_;\r
+        int16_t endValueY_;\r
+    };\r
+\r
+    class ScaleAnimatorCallback : public AnimatorCallback {\r
+    public:\r
+        ScaleAnimatorCallback()\r
+            : curtTime_(0),\r
+              dragTimes_(0),\r
+              startImgDistance_(0),\r
+              endImgDistance_(0),\r
+              startItemSize_(0),\r
+              endItemSize_(0)\r
+        {\r
+        }\r
+\r
+        virtual ~ScaleAnimatorCallback() {}\r
+\r
+        void SetDragTimes(uint16_t times)\r
+        {\r
+            dragTimes_ = times;\r
+        }\r
+\r
+        void SetDragStartValue(int16_t startImgDistance, int16_t startItemSize)\r
+        {\r
+            startImgDistance_ = startImgDistance;\r
+            startItemSize_ = startItemSize;\r
+        }\r
+\r
+        void SetDragEndValue(int16_t endImgDistance, int16_t endItemSize)\r
+        {\r
+            endImgDistance_ = endImgDistance;\r
+            endItemSize_ = endItemSize;\r
+        }\r
+\r
+        void ResetCallback()\r
+        {\r
+            curtTime_ = 0;\r
+            dragTimes_ = 0;\r
+            startImgDistance_ = 0;\r
+            endImgDistance_ = 0;\r
+            startItemSize_ = 0;\r
+            endItemSize_ = 0;\r
+        }\r
+\r
+        virtual void Callback(UIView* view);\r
+\r
+        uint16_t curtTime_;\r
+        uint16_t dragTimes_;\r
+        int16_t startImgDistance_;\r
+        int16_t endImgDistance_;\r
+        int16_t startItemSize_;\r
+        int16_t endItemSize_;\r
+    };\r
+\r
+    class PlanetAnimator : public Animator {\r
+    public:\r
+        PlanetAnimator() {}\r
+        PlanetAnimator(AnimatorCallback* callback, UIView* view, uint32_t time, bool repeat)\r
+            : Animator(callback, view, time, repeat)\r
+        {}\r
+        virtual ~PlanetAnimator() {}\r
+    };\r
+\r
+private:\r
+    UIPlanetList();\r
+    void FillActiveView();\r
+    float GetPivotByOffset(int16_t offset);\r
+    bool OnPressEvent(const PressEvent& event) override;\r
+    float GetScaleFactor(int16_t dstCoordinate, int16_t& distance);\r
+    Vector2<float> GetPivot(UIView* view, int16_t dstX, int16_t dstY);\r
+    float ResizeItem(UIView* view, int16_t positionX, int16_t positionY);\r
+    void ScaleView(UIView* view, float scaleFactor, Vector2<float> pivot);\r
+    int16_t CalculateOffsetAfterMove(int16_t posDiff);\r
+    bool AutoAlignAnimator(Vector2<int16_t>& oriPos);\r
+    bool InertialAnimator(const DragEvent &event, Vector2<int16_t>& movedPos);\r
+    void ReCalculateDragEnd(int16_t& offsetX, int16_t& offsetY);\r
+    void StopAnimator() override;\r
+    Vector2<int16_t> GetHeadItemCurPosition();\r
+    void ReAlignWhenReachEdge();\r
+    void InitBorderLimits();\r
+    void NeedRebound();\r
+    void Showlabels();\r
+    void ScaleMiddleSize();\r
+    void AdjustScaleParameters(float scale, int16_t& dstImgDis, int16_t& dstItemSize);\r
+    UIView* GetViewByIndex(List<UIView*> list, uint16_t index);\r
+    void UpdateOriHeadPos();\r
+    void RecordAndRestoreOffset(bool isRecord);\r
+    bool PlayMoveAnimator(Vector2<int16_t> oriPos, int16_t dragTimesFactor);\r
+    bool PlayScaleAnimator(float scale);\r
+    bool DragXInner(int16_t distance) override;\r
+    bool DragYInner(int16_t distance) override;\r
+\r
+    Vector2<int16_t> singleDragDistance_;\r
+    TimeType dragStartTime_;\r
+    int16_t imgDistance_;\r
+    int16_t oriImgDistance_;\r
+    int16_t itemSize_;\r
+    int16_t oriItemSize_;\r
+    EasingFunc easingFunc_;\r
+    List<UIView*> appLists_;\r
+    List<UIView*> labelLists_;\r
+    bool isReCalculateDragEnd_;\r
+    uint16_t reAlignDirection_;\r
+    Vector2<int16_t> dragStartPos_;\r
+    OnClickListener* itemClickListener_;\r
+    std::map<SwipeEdge, int16_t> dragEndLimits_;\r
+    std::map<SwipeEdge, int16_t> reboundLimits_;\r
+    PlanetAnimator pltMoveAnimator_;\r
+    RotateAnimatorCallback moveCallback_;\r
+    PlanetAnimator pltScaleAnimator_;\r
+    ScaleAnimatorCallback scaleCallback_;\r
+    Vector2<int16_t> oriHeadItemPos_;\r
+    Vector2<int16_t> lastQuitOffset_{0, 0};\r
+    float globalScale_{1.0f};\r
+    float startScale_{0.0f};\r
+}; // class UIPlanetList\r
+} // namespace OHOS\r
+\r
+#endif // UI_PLANET_LIST_H\r
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_scatter_plot.h b/code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_scatter_plot.h
new file mode 100644 (file)
index 0000000..a8ca22a
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: UIScatterPlot
+ * Author: Hisi Graphic Team
+ * Created: 2025-9
+ */
+
+#ifndef UI_SCATTER_PLOT_H
+#define UI_SCATTER_PLOT_H
+
+#include "components/ui_chart.h"
+
+namespace OHOS {
+class UIScatterPlotDataSerial : public UIChartDataSerial {
+public:
+    UIScatterPlotDataSerial()
+    {
+        PointStyle style;
+        style.radius = 5; // 5 : default radius
+        style.strokeWidth = 0;
+        style.fillColor = Color::White();
+        style.strokeColor = Color::Black();
+
+        pointStyle_ = style;
+    }
+
+    ~UIScatterPlotDataSerial() override {}
+
+    void SetPointStyle(const PointStyle& style)
+    {
+        pointStyle_ = style;
+    }
+
+    const PointStyle& GetPointStyle() const
+    {
+        return pointStyle_;
+    }
+
+private:
+    PointStyle pointStyle_;
+};
+
+class UIScatterPlot : public UIChart {
+public:
+    /**
+     * @brief A constructor used to create a <b>UIScatterPlot</b> instance.
+              UIScatter plot is a chart that displays data points corresponding their x and y values.
+     */
+    UIScatterPlot() {}
+
+    /**
+     * @brief A destructor used to delete the <b>UIScatterPlot</b> instance.
+     */
+    ~UIScatterPlot() override {}
+
+    /**
+     * @brief Obtains the view type.
+     *
+     * @return Returns <b>UI_SCATTER_PLOT</b>, as defined in {@link UIViewType}.
+     */
+    UIViewType GetViewType() const override
+    {
+        return UI_SCATTER_PLOT;
+    }
+
+    /**
+     * @brief Refreshes a scatter plot and redraws the dirty region.
+     *        Only the parts that need to be redrawn are refreshed, for example, new data points.
+     *        This function provides better performance than {@link Invalidate}.
+     */
+    void RefreshChart() override;
+
+protected:
+    void DrawDataSerials(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) override;
+    void DrawPoints(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, UIScatterPlotDataSerial* data);
+    void DrawSinglePoint(BufferInfo& gfxDstBuffer, Point center,
+        const UIChartDataSerial::PointStyle& style, const Rect& mask);
+};
+} // namespace OHOS
+#endif // UI_SCATTER_PLOT_H
\ No newline at end of file
index 88a2378..70efce6 100644 (file)
@@ -17,6 +17,16 @@ public:
 
     ~UIScrollViewNested() override {}
 
+    /**
+     * @brief Obtains the view type.
+     *
+     * @return Returns <b>UI_SCROLL_VIEW_NESTED</b>, as defined in {@link UIViewType}.
+     */
+    UIViewType GetViewType() const override
+    {
+        return UI_SCROLL_VIEW_NESTED;
+    }
+
     bool OnDragStartEvent(const DragEvent& event) override;
 
     bool OnDragEvent(const DragEvent& event) override;
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_simple_list.h b/code/sdk/middleware/services/gui/uikit/proprietary/include/components/ui_simple_list.h
new file mode 100644 (file)
index 0000000..9c9ff7e
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: List with built-in adapter
+ * Author: Hisi Team
+ * Created: 2025-07
+ */
+#ifndef GRAPHIC_SIMPLE_LIST_H
+#define GRAPHIC_SIMPLE_LIST_H
+
+#include "common/graphic_hardware_types.h"
+#include "components/ui_list_nested.h"
+#include "components/ui_transform_list.h"
+#include "components/ui_view.h"
+#include "components/common_adapter.h"
+
+namespace OHOS {
+/**
+ * Create common views for special type, and set non-updating property for common views.
+ * This callback requires the user to implement the control combination for the item.
+ * And configure the control's non-updating property.
+ * If the controls within an item are identical,
+ * the same type value can be used to achieve memory reuse for that type of item.
+ * The type can't be 0.
+ * @param Type Current creation item type
+ * @return UIView* A pointer to the newly created view.
+ */
+typedef UIView* (*CreateViewCallback)(uint8_t type);
+
+/**
+ * Update differentiation properties for common views based on special data and type.
+ * The callback requires the user to update the control properties based on the item type.
+ * @param view The target view to update
+ * @param data Associated data for the update
+ * @param type The type of the item being updated.
+ */
+typedef void (*UpdateViewCallback)(UIView* view, void* data, uint8_t type);
+
+/**
+ * @brief Metadata structure for managing view content information.
+ * Contains callbacks and associated data for each view item.
+ */
+class Contents {
+public:
+    CreateViewCallback createFunc;
+    UpdateViewCallback updateFunc;
+    uint8_t type;                     // Unique view type identifier
+    void* data;                      // View-specific data payload
+};
+
+/**
+ * @brief Base class providing common adapter functionality.
+ * Wraps a custom adapter and provides methods for managing items.
+ */
+class AdapterWrapper : public HeapBase {
+public:
+    AdapterWrapper() {}
+    virtual ~AdapterWrapper() {}
+
+    /**
+     * @brief Adds a new view content configuration.
+     * Call RefreshList() after adding to update the list.
+     * @param metadata The metadata containing view creation and update callbacks.
+     */
+    void AddContent(Contents& metadata)
+    {
+        adapter_.AddContent(metadata);
+    }
+
+    /**
+     * @brief Updates an existing view at a specific index.
+     * Call RefreshList() after updating to reflect changes.
+     * @param index Index of the view to update.
+     * @param metadata New metadata to apply.
+     * @return true if the update was successful, false otherwise.
+     */
+    bool UpdateContent(int16_t index, Contents& metadata)
+    {
+        return adapter_.UpdateContent(index, metadata);
+    }
+
+    /**
+    * Removes the content at the specified index from the adapter.call the RefreshList() interface after remove
+    * @param index The zero-based index of the content to remove.
+    *              Must be between 0 and (GetCount() - 1).
+    * @return True if the content was successfully removed,
+    *         false if the index is out of bounds.
+    * @note This method clears the corresponding element in the contents vector.
+    *       If the index is invalid (e.g., negative or exceeds current size), the operation fails.
+    *       The memory of any pointers (like data in the Contents struct) is not managed here.
+    */
+    void RemoveContent(int16_t index)
+    {
+        adapter_.RemoveContent(index);
+    }
+
+    /**
+     * @brief Removes all view content from the adapter.
+     */
+    void ClearAll()
+    {
+        adapter_.ClearAll();
+    }
+
+protected:
+    CommonAdapter adapter_;
+};
+
+/**
+ * @brief Simple list component using a base adapter.
+ * Provides basic list functionality with a custom adapter.
+ */
+class UISimpleList : public AdapterWrapper, public UIListNested {
+public:
+    explicit UISimpleList()
+    {
+        SetAdapter(&adapter_);
+    }
+
+    ~UISimpleList() override = default;
+};
+
+/**
+ * @brief Transformable simple list component.
+ * Extends the simple list with transform capabilities.
+ */
+class UISimpleTransformList : public AdapterWrapper, public UITransformList {
+public:
+    explicit UISimpleTransformList()
+    {
+        SetAdapter(&adapter_);
+    }
+
+    ~UISimpleTransformList() override = default;
+};
+}
+#endif
index f07e85a..1cd0239 100644 (file)
@@ -28,7 +28,7 @@ public:
     ~UISlipflowView() override;\r
 \r
     /**\r
-     * @brief Adds a child view.\r
+     * @brief Adds a child view. All child views should have the same width and height.\r
      *\r
      * @param view Indicates the pointer to the child view to add.\r
      * @since 1.0\r
@@ -44,15 +44,7 @@ public:
     void Remove(UIView* view) override;\r
 \r
     /**\r
-     * @brief Set page size.\r
-     *\r
-     * @param width setting page width.\r
-     * @param height setting page height.\r
-     */\r
-    void SetPageSize(uint16_t width, uint16_t height);\r
-\r
-    /**\r
-     * @brief Get page width.\r
+     * @brief Get page width form width of the child view.\r
      */\r
     uint16_t GetPageWidth() const\r
     {\r
@@ -60,7 +52,7 @@ public:
     }\r
 \r
     /**\r
-     * @brief Get page height.\r
+     * @brief Get page height form height of the child view.\r
      */\r
     uint16_t GetPageHeight() const\r
     {\r
@@ -97,10 +89,7 @@ public:
      * @since 1.0\r
      * @version 1.0\r
      */\r
-    UIView* GetCurrentView() const\r
-    {\r
-        return curView_;\r
-    }\r
+    UIView* GetCurrentView() const;\r
 \r
     /**\r
      * @brief Obtains the component type.\r
@@ -122,7 +111,7 @@ public:
      * @since 1.0\r
      * @version 1.0\r
      */\r
-    UIView* GetViewByIndex(uint16_t index) const;\r
+    UIView* GetViewByIndex(uint16_t index);\r
 \r
     /**\r
      * @brief Indicates that the animation duration is 12 ticks.\r
@@ -221,6 +210,8 @@ protected:
     void CalculateInvalidate();\r
 \r
 private:\r
+    UIView* GetViewByIndexInner(uint16_t index);\r
+    void RemoveInner(UIView* view);\r
     void DeleteGroup(UIViewGroup* group);\r
     void AddTempXoffsetInfo();\r
     void ResetTempOffsetInfo();\r
@@ -244,7 +235,6 @@ private:
     UIView* deleteView_;\r
     uint16_t pageWidth_;\r
     uint16_t pageHeight_;\r
-    UIView* lastView_;\r
     uint16_t swipeMid_;\r
     int8_t dragDirection_;\r
     bool isSetPage_;\r
index 12ca861..70799f6 100644 (file)
@@ -19,6 +19,16 @@ public:
 
     ~UISwipeViewNested() override {}
 
+    /**
+     * @brief Obtains the view type.
+     *
+     * @return Returns <b>UI_SWIPE_VIEW_NESTED</b>, as defined in {@link UIViewType}.
+     */
+    UIViewType GetViewType() const override
+    {
+        return UI_SWIPE_VIEW_NESTED;
+    }
+
     bool OnDragStartEvent(const DragEvent& event) override;
 
     bool OnDragEvent(const DragEvent& event) override;
index 4695acc..06a3d2d 100644 (file)
@@ -75,14 +75,14 @@ public:
     void TransformChild(UIView* view, TransformMap transmap);\r
 \r
     /**\r
-     * @brief Sets a style.\r
+     * @brief Sets all child view style and self style.\r
      *\r
      * @param key Indicates the key of the style to set.\r
      * @param value Indicates the value matching the key.\r
      * @since 1.0\r
      * @version 1.0\r
      */\r
-    void SetStyle(uint8_t key, int64_t value) override;\r
+    void SetAllStyle(uint8_t key, int64_t value);\r
 \r
     /**\r
      * @brief Called when a view is drawn.\r
index 390007b..b36c7f3 100644 (file)
 #ifndef GRAPHIC_UI_TRANSFORM_LIST_H\r
 #define GRAPHIC_UI_TRANSFORM_LIST_H\r
 #include "graphic_config.h"\r
-#include "components/ui_list.h"\r
+#include "components/ui_list_nested.h"\r
 #include "components/ui_transform_group.h"\r
 #include "gfx_utils/vector.h"\r
 \r
 namespace OHOS {\r
-class UITransformList : public UIList {\r
+class UITransformList : public UIListNested {\r
 public:\r
     /**\r
      * @brief A constructor used to create a <b>UITransformList</b> instance.\r
index e1e1edb..8ba2b2d 100644 (file)
@@ -22,6 +22,7 @@
 #include "components/root_view.h"
 #include "common/graphic_utils.h"
 #include "graphic_service_wrapper.h"
+#include "dfx/dfx_traceui.h"
 
 #if ENABLE_DFX_CMD
 #define FRAME_TRACE_ENABLE 1
@@ -40,7 +41,8 @@
 #define EVENT_TRACE_END() DfxFrameTrace::GetInstance().EventTraceEnd()
 #define TASK_TRACE_START() DfxFrameTrace::GetInstance().TaskTraceStart()
 #define TASK_TRACE_END() DfxFrameTrace::GetInstance().TaskTraceEnd()
-#define SET_TRACE_PATH_TYPE(type) DfxFrameTrace::GetInstance().SetPathType(type)
+#define SET_TRACE_PATH_TYPE(type, attr) DfxFrameTrace::GetInstance().SetPathType((type), (attr))
+#define SET_TRACE_FLUSH_TYPE(isSram) DfxFrameTrace::GetInstance().SetFlushMemType(isSram)
 #else
 #define FRAME_TRACE_START(type)
 #define FRAME_TRACE_END(type, prect)
@@ -53,7 +55,8 @@
 #define EVENT_TRACE_END()
 #define TASK_TRACE_START()
 #define TASK_TRACE_END()
-#define SET_TRACE_PATH_TYPE(type)
+#define SET_TRACE_PATH_TYPE(type, attr)
+#define SET_TRACE_FLUSH_TYPE(isSram)
 #endif
 
 namespace OHOS {
@@ -81,6 +84,13 @@ enum class FrameTraceType {
     DRAW_MAX
 };
 
+enum class FrameTracePathAttr : uint8_t {
+    NONE = 0,
+    FILL = 1,
+    STROKE = 1 << 1,
+    BOTH = (1 << 1) | 1,
+};
+
 class DfxFrameTrace : public HeapBase {
 public:
     virtual ~DfxFrameTrace() {}
@@ -98,23 +108,30 @@ public:
         if (beginTrace_) {
             isNativeRunning_ = IsNativeRunning();
             freq_ = GetFrequence();
-            --traceCount_;
         }
     }
 
     void SetDrawRect(const Rect &rect)
     {
+        TRACEUI_LOG("SetDrawRect{%d,%d,%d,%d}", rect.GetX(), rect.GetY(), rect.GetWidth(), rect.GetHeight());
         drawRect_ = beginTrace_ ? rect : drawRect_;
     }
 
+    void SetFlushMemType(bool isSram)
+    {
+        TRACEUI_LOG("FlushType:%s", isSram ? "SRAM" : "PSRAM");
+        isSram_ = isSram;
+    }
+
     void EndTrace()
     {
         if (beginTrace_) {
+            traceCount_ -= (drawCount_ != 0);
             ClearState();
         }
     }
 
-    void SetPathType(FrameTraceType type);
+    void SetPathType(FrameTraceType type, FrameTracePathAttr attr);
     void FrameTraceStart(FrameTraceType type);
     void FrameTraceEnd(FrameTraceType type, const Rect *rect = nullptr);
     void ShowFrameTrace();
@@ -136,7 +153,8 @@ private:
     }
 
     void ClearState();
-    std::string ToString(FrameTraceType type) const;
+    const char *DrawTypeToString(FrameTraceType type) const;
+    const char *PathAttrToString(FrameTracePathAttr attr) const;
     uint64_t GetDuration(uint64_t start, uint64_t end) const;
     uint64_t ComputeTime() const;
     void RecordStart(FrameTraceType type);
@@ -151,7 +169,7 @@ private:
 
     struct FrameRecord {
         FrameRecord() : totalTime(0), isNativeRunning(0), freq(0), pathCnt(0),
-            drawCount(0), trace(nullptr), rect(nullptr)
+            drawCount(0), isSram(true), trace(nullptr), rect(nullptr), attr(nullptr)
         {
             ++frmCnt_;
         }
@@ -166,6 +184,10 @@ private:
                 delete []rect;
                 rect = nullptr;
             }
+            if (attr != nullptr) {
+                delete []attr;
+                attr = nullptr;
+            }
             --frmCnt_;
         }
         uint64_t totalTime;
@@ -174,8 +196,10 @@ private:
         int pathCnt;
         int drawCount;
         Rect drawRect;
+        bool isSram;
         FrameTrace *trace;
         Rect *rect;
+        FrameTracePathAttr *attr;
     };
 
     struct TaskRecord {
@@ -222,9 +246,11 @@ private:
     static int tskCnt_;
     static int frmCnt_;
     Rect rect_[DRAW_RECORD_MAX];
+    FrameTracePathAttr pathAttrs_[DRAW_RECORD_MAX];
     int pathCnt_ = 0;
     int pathIndex_ = -1;
     Rect drawRect_;
+    bool isSram_ = true;
     uint64_t firstDrawTime_ = 0;
     uint64_t startTime_ = 0;
     uint64_t endTime_ = 0;
@@ -239,6 +265,7 @@ private:
     bool eventRecording_ = false;
     bool taskRecording_ = false;
     FrameTraceType pathType_ = FrameTraceType::HW_DRAW_PATH;
+    FrameTracePathAttr pathAttr_ = FrameTracePathAttr::NONE;
 };
 } // OHOS
 #endif // GRAPHIC_LITE_DFX_FRAME_TRACE_H
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/include/dfx/dfx_traceui.h b/code/sdk/middleware/services/gui/uikit/proprietary/include/dfx/dfx_traceui.h
new file mode 100644 (file)
index 0000000..300c860
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: graphical performance trace analysis tool interface
+ * Author: Hisi Graphic Team
+ * Created: 2025-9
+ */
+
+#ifndef GRAPHIC_TRACEUI_H
+#define GRAPHIC_TRACEUI_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+#include "graphic_config.h"
+extern "C" {
+#endif
+
+// basic
+#if ENABLE_DFX_TRACEUI
+#define TRACEUI_BEGIN(nameStaticStr) TraceuiEventTraceBegin(nameStaticStr)
+#define TRACEUI_BEGIN_FORMAT(nameStaticStr, fmt, ...) TraceuiEventTraceBeginFormat(nameStaticStr, fmt, ##__VA_ARGS__)
+#define TRACEUI_END() TraceuiEventTraceEnd()
+#define TRACEUI_ASYNC_BEGIN(nameStaticStr, cookieInt) TraceuiEventTraceAsyncBegin(nameStaticStr, cookieInt)
+#define TRACEUI_ASYNC_END(nameStaticStr, cookieInt) TraceuiEventTraceAsyncEnd(nameStaticStr, cookieInt)
+#define TRACEUI_INT(nameStaticStr, valueInt) TraceuiEventTraceInt(nameStaticStr, valueInt)
+#define TRACEUI_LOG(fmt, ...) TraceuiEventLog(fmt, ##__VA_ARGS__)
+#else
+#define TRACEUI_BEGIN(nameStaticStr)
+#define TRACEUI_BEGIN_FORMAT(nameStaticStr, fmt, ...)
+#define TRACEUI_END()
+#define TRACEUI_ASYNC_BEGIN(nameStaticStr, cookiePtr)
+#define TRACEUI_ASYNC_END(nameStaticStr, cookiePtr)
+#define TRACEUI_INT(nameStaticStr, valueInt)
+#define TRACEUI_LOG(fmt, ...)
+#endif
+
+// traceui core
+typedef enum {
+    TRACEUI_EVENT_TASK_SWITCH,
+    TRACEUI_EVENT_TASK_WAKEUP,
+    TRACEUI_EVENT_HWI_ENTER,
+    TRACEUI_EVENT_HWI_EXIT,
+    TRACEUI_EVENT_TRACE_BEGIN,
+    TRACEUI_EVENT_TRACE_BEGIN_FORMAT,
+    TRACEUI_EVENT_TRACE_END,
+    TRACEUI_EVENT_TRACE_ASYNC_BEGIN,
+    TRACEUI_EVENT_TRACE_ASYNC_END,
+    TRACEUI_EVENT_TRACE_INT,
+    TRACEUI_EVENT_LOG,
+
+    TRACEUI_EVENT_MAX
+} TraceuiEventType;
+
+#define TRACEUI_EVENTS_ALL         0xFFFFFFFF
+#define TRACEUI_EVENT_MASK(event)  (1 << (event))
+
+/**
+ * @brief Start record trace. If the recording exceeds the buffer size, subsequent data will be ignored.
+ *
+ * @param events TraceuiEventType mask. mayge TRACEUI_EVENTS_ALL.
+ *                or: TRACEUI_EVENT_MASK(TRACEUI_EVENT_TASK_SWITCH) | TRACEUI_EVENT_MASK(TRACEUI_EVENT_LOG)
+ * @param buf Record to the target buffer.
+ * @param bufSize target buffer size.
+ * @return true for success.
+ */
+bool TraceuiRecordStart(uint32_t events, uint8_t *buf, uint32_t bufSize);
+
+/**
+ * @brief Stop record trace.
+ *
+ * @return Length of recording.
+ */
+uint32_t TraceuiRecordStop(void); // return trace size
+
+/**
+ * @brief Convert recording buffer to perfetto protobuf trace format.
+ *
+ * @param buf Input buffer of recording.
+ * @param bufSize Input buffer size.
+ * @param outPath Output trace file path.
+ * @return true for success.
+ */
+bool TraceuiConvertToPerfettoProto(const uint8_t *buf, uint32_t bufSize, const char *outPath);
+
+/**
+ * @brief Trace the beginning of a context. This is often used to time function execution.
+ *
+ * @param name Static string for identify the context. The pointer must remain valid before trace convert.
+ */
+void TraceuiEventTraceBegin(const char *name);
+
+/**
+ * @brief Trace the beginning of a context. This is often used to time function execution.
+ *
+ * @param name Static string for identify the context. The pointer must remain valid before trace convert.
+ * @param fmt Format string like printf. Name and format string together for identify the context.
+ */
+void TraceuiEventTraceBeginFormat(const char *name, const char *fmt, ...);
+
+/**
+ * @brief Trace the end of a context. This should match up (and occur after) a corresponding *TraceBegin*.
+ */
+void TraceuiEventTraceEnd(void);
+
+/**
+ * @brief Trace the beginning of an asynchronous event. The name and cookie used to begin an event must be
+ * used to end it.
+ *
+ * @param name Static string for identify the context. The pointer must remain valid before trace convert.
+ * @param cookie Provides a unique identifier for distinguishing simultaneous events.
+ */
+void TraceuiEventTraceAsyncBegin(const char *name, int cookie);
+
+/**
+ * @brief Trace the end of an asynchronous event. This should have a corresponding *TraceAsyncBegin*.
+ */
+void TraceuiEventTraceAsyncEnd(const char *name, int cookie);
+
+/**
+ * @brief Traces an integer value.  name is used to identify the counter.
+ * This can be used to track how a value changes over time.
+ *
+ * @param name Static string for identify the context. The pointer must remain valid before trace convert.
+ * @param value The current value at this moment.
+ */
+void TraceuiEventTraceInt(const char *name, int value);
+
+/**
+ * @brief Traces a log. To save recording memory, please keep the log as small as possible.
+ *
+ * @param fmt Format string like printf.
+ */
+void TraceuiEventLog(const char *fmt, ...);
+
+#ifdef __cplusplus
+}
+#endif
+#endif // GRAPHIC_TRACEUI_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_bezier.h b/code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_bezier.h
new file mode 100644 (file)
index 0000000..1a4717e
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.
+ * Description: Graphic Lottie Bezier
+ * Author: Hisi Graphic Team
+ * Created: 2025-5
+ */
+
+#ifndef LOTT_BEZIER_H
+#define LOTT_BEZIER_H
+#include "gfx_utils/heap_base.h"
+#include "gfx_utils/graphic_math.h"
+
+namespace OHOS {
+const static int INITIAL_COUNT = 4; // cache to speed up
+class LottBezier : public HeapBase {
+public:
+    LottBezier() = default;
+    LottBezier(Vector2<float> start, Vector2<float> ctrl1, Vector2<float> ctrl2, Vector2<float> end);
+    void Split(float t, LottBezier& leftBz);
+    void Split(LottBezier& leftBz, LottBezier& rightBz);
+    // length should be the actual bezier length if not use default value
+    void Split(float startLength, float endLength, LottBezier& clipBz, float length = 0.0f);
+    float Length(bool fast = true);
+    // length should be the actual bezier length if not use default value
+    float TAtLength(float subLength, float length = 0.0f, bool fast = true);
+    Vector2<float> PointAt(float t) const;
+    float Angle(float t) const;
+
+    Vector2<float> start_{};
+    Vector2<float> ctrl1_{};
+    Vector2<float> ctrl2_{};
+    Vector2<float> end_{};
+    float length_{0.0f};
+};
+} // namespace OHOS
+#endif // LOTT_BEZIER_H
\ No newline at end of file
index 1b1472f..6f2ff39 100644 (file)
@@ -21,6 +21,7 @@ public:
     void UpdateLottComp(float frameNo);\r
     void DrawLottComp(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, const Matrix3<float>& mat, uint8_t opa);\r
     float GetFrameCnt();\r
+    void OnStop();\r
 \r
     float width_ = 0.0f;\r
     float height_ = 0.0f;\r
index 4350cca..871c900 100644 (file)
@@ -18,7 +18,7 @@ public:
     LottEllipse();
     virtual ~LottEllipse();
 
-    void Update(LottShape* parent, float frameNo) override;
+    bool Update(float frameNo) override;
     bool GetPathData(Path& path) override;
 
     LottPositionProp position_;
index f1e98ff..fb546c0 100644 (file)
@@ -30,7 +30,7 @@ class LottLayer : public HeapBase {
 public:
     LottLayer();
     virtual ~LottLayer();
-
+    virtual void OnStop() {};
     virtual bool UpdateLottLayer(float frameNo);
     virtual void DrawLottLayer(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea,
         const Matrix3<float>& matrix, uint8_t opa) {};
index fea0746..5fa31ba 100644 (file)
@@ -27,26 +27,7 @@ static constexpr float CONST_COEFF_2 = 2.0f;
 static constexpr float CONST_COEFF_3 = 3.0f;
 static constexpr float CONST_COEFF_6 = 6.0f;
 static constexpr float RED2DEG_COEFF = 180.0f;
-
-class Bezier : public HeapBase {
-public:
-    Bezier() {}
-    Bezier(Vector2<float> start, Vector2<float> ctrl1, Vector2<float> ctrl2, Vector2<float> end);
-    void Split(float t, Bezier& left);
-    void Split(Bezier& left, Bezier& right) const;
-    void Split(float at, Bezier& left, Bezier& right) const;
-    float Length() const;
-    float LengthApprox() const;
-    float At(float at, float length) const;
-    float AtApprox(float at, float length) const;
-    Vector2<float> At(float t) const;
-    float Angle(float t) const;
-
-    Vector2<float> start_;
-    Vector2<float> ctrl1_;
-    Vector2<float> ctrl2_;
-    Vector2<float> end_;
-};
+const static float DISTANCE_COEFF = 0.375f;
 
 template <typename T>
 inline T Lerp(const T &start, const T &end, float t)
@@ -71,6 +52,15 @@ uint32_t Bsearch(T* frames, float frameNo)
     return low;
 }
 
+inline void Clamp(float& value, float min, float max)
+{
+    if (FloatLess(value, min)) {
+        value = min;
+    } else if (FloatMore(value, max)) {
+        value = max;
+    }
+}
+
 inline float ConstA(float aA1, float aA2)
 {
     return CONST_COEFF_1 - CONST_COEFF_3 * aA2 + CONST_COEFF_3 * aA1;
@@ -99,6 +89,17 @@ inline float Rad2deg(float radian)
     return radian * (RED2DEG_COEFF / MATH_PI);
 }
 
+inline float Distance(const Vector2<float>& pt1, const Vector2<float>& pt2, bool fast = true)
+{
+    Vector2<float> diff = pt2 - pt1;
+    if (fast) {
+        diff.x_ = (diff.x_ < 0 ? -diff.x_ : diff.x_);
+        diff.y_ = (diff.y_ < 0 ? -diff.y_ : diff.y_);
+        return (diff.x_ > diff.y_) ? (diff.x_ + diff.y_ * DISTANCE_COEFF) : (diff.y_ + diff.x_ * DISTANCE_COEFF);
+    }
+    return sqrtf(diff.x_ * diff.x_ + diff.y_ * diff.y_);
+}
+
 inline float Atan2(float y, float x)
 {
     if (y == 0.0f && x == 0.0f) return 0.0f;
index ecc095c..585b13f 100644 (file)
@@ -32,6 +32,7 @@ private:
         uint32_t fillIndex = 0;
         uint32_t strokeindex = 0;
         uint32_t transIndex = 0;
+        uint32_t trimIndex = 0;
         Graphic::Vector<uint32_t> shapes;
     };
 
@@ -69,6 +70,7 @@ private:
     LottFill* ParseFill(const void* shape, uint8_t type);
     LottStroke* ParseStroke(const void* shape, uint8_t type);
     LottTransform* ParseTransShape(const void* shape);
+    LottTrim* ParseTrimPath(const void* shape);
 
     void ParseSplitProp(const void* split, LottTransform::LottSplitPosition& lottSplit);
     void ParsePositionProp(const void* value,  LottieFlatBuffer::PositionProp type, LottPositionProp& lottPosition);
index cce29b0..d870ab4 100644 (file)
@@ -18,7 +18,7 @@ public:
     LottPath();\r
     virtual ~LottPath();\r
 \r
-    void Update(LottShape* parent, float frameNo) override;\r
+    bool Update(float frameNo) override;\r
     bool GetPathData(Path& path) override;\r
 \r
     LottPathDataProp pathData_;\r
index 493e0c8..06cabcc 100644 (file)
@@ -19,7 +19,7 @@ public:
     bool UpdateLottLayer(float frameNo) override;\r
     void DrawLottLayer(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea,\r
         const Matrix3<float>& matrix, uint8_t opa) override;\r
-\r
+    void OnStop() override;\r
     Graphic::Vector<LottLayer*> layers_;\r
 };\r
 }\r
index 68c509d..283cdbc 100644 (file)
@@ -35,6 +35,7 @@ public:
     void UpdateValue(float frameNo);\r
 \r
     float value_;\r
+    bool isUpdateValue_ = false;\r
 \r
 private:\r
     Graphic::Vector<LottFloatFrame*>* frames_;\r
@@ -58,6 +59,7 @@ public:
     void UpdateValue(float frameNo);\r
 \r
     int value_;\r
+    bool isUpdateValue_ = false;\r
 \r
 private:\r
     Graphic::Vector<LottIntegerFrame*>* frames_;\r
@@ -81,6 +83,7 @@ public:
     void UpdateValue(float frameNo);\r
 \r
     Color32 value_;\r
+    bool isUpdateValue_ = false;\r
 \r
 private:\r
     Graphic::Vector<LottColorFrame*>* frames_;\r
@@ -104,6 +107,7 @@ public:
     void UpdateValue(float frameNo);\r
 \r
     Vector2<float> value_;\r
+    bool isUpdateValue_ = false;\r
 \r
 private:\r
     Graphic::Vector<LottVectorFrame*>* frames_;\r
@@ -127,9 +131,13 @@ public:
     void UpdateValue(float frameNo);\r
 \r
     Graphic::Vector<ColorStop> value_;\r
+    bool isUpdateValue_ = false;\r
 \r
 private:\r
+    Graphic::Vector<ColorStop>* preValue_ = nullptr;\r
     Graphic::Vector<LottColorStopsFrame*>* frames_;\r
+\r
+    void CompareValueWithPre(Graphic::Vector<ColorStop>* curValue);\r
 };\r
 \r
 struct LottPositionFrame {\r
@@ -153,6 +161,7 @@ public:
     void PrepareLength();\r
 \r
     Vector2<float> value_;\r
+    bool isUpdateValue_ = false;\r
 \r
 private:\r
     Graphic::Vector<LottPositionFrame*>* frames_;\r
@@ -178,11 +187,14 @@ public:
     void UpdateValue(float frameNo);\r
 \r
     Path value_;\r
+    bool isUpdateValue_ = false;\r
 \r
 private:\r
+    Path* prePath_ = nullptr;\r
     Path innerPath_; // Store temporary path data to avoid allocate memory frequently\r
     Graphic::Vector<LottPathDataFrame*>* frames_;\r
 \r
+    void CompareValueWithPre(Path* path);\r
     bool UpdatePath(LottPathDataFrame* curFrame, LottPathDataFrame* nextFrame, float time);\r
 };\r
 \r
index 5714588..8be5dcb 100644 (file)
@@ -18,7 +18,7 @@ public:
     LottRect();
     virtual ~LottRect();
 
-    void Update(LottShape* parent, float frameNo) override;
+    bool Update(float frameNo) override;
     bool GetPathData(Path& path) override;
 
     LottPositionProp position_;
index ea80e2e..bbdaaa7 100644 (file)
@@ -10,6 +10,8 @@
 \r
 #include "common/graphic_hardware_types.h"\r
 #include "hals/gralloc_engines.h"\r
+#include "lottie/lott_trim_path.h"\r
+#include "lottie/lott_trim.h"\r
 \r
 namespace OHOS {\r
 enum class LottShapeType {\r
@@ -25,15 +27,23 @@ public:
     LottShape();\r
     virtual ~LottShape();\r
 \r
-    virtual void Update(LottShape* parent, float frameNo) {};\r
+    virtual void OnStop();\r
+    virtual bool Update(float frameNo);\r
     virtual bool GetPathData(Path& path);\r
     LottShapeType GetType();\r
+    bool ProcessTrim(const LottTrimValue& trimValue);\r
+    LottTrimPath* trimPath_ = nullptr;\r
+    Path trimmedPath_ = {0};\r
+    bool isPathUpdated_ = true;\r
+    void ResetUpdateState();\r
 \r
 protected:\r
+    friend class LottShapeGroup;\r
     void ClearPathInner();\r
-\r
+    bool isFirstFrame_ = true;\r
     Path path_ = {0};\r
     LottShapeType type_ = LottShapeType::INVALID;\r
+    bool isUpdated_ = false;\r
 };\r
 }\r
 #endif // LOTT_SHAPE_H
\ No newline at end of file
index 219de0b..8818828 100644 (file)
@@ -11,6 +11,7 @@
 #include "lottie/lott_shape.h"\r
 #include "lottie/lott_paint.h"\r
 #include "lottie/lott_transform.h"\r
+#include "lottie/lott_trim.h"\r
 #include "common/graphic_hardware_types.h"\r
 #include "gfx_utils/graphic_types.h"\r
 #include "display_vgu.h"\r
@@ -21,12 +22,14 @@ struct LottRenderContext {
     uint8_t opa;\r
     Matrix3<float> matrix;\r
     LottPaintValue paint;\r
+    LottTrimValue trim;\r
 \r
     void DeepCopy(LottRenderContext& ctx)\r
     {\r
+        opa = ctx.opa;\r
         matrix = ctx.matrix;\r
         paint.DeepCopy(ctx.paint);\r
-        opa = ctx.opa;\r
+        trim = ctx.trim;\r
     }\r
 };\r
 \r
@@ -35,7 +38,8 @@ public:
     LottShapeGroup();\r
     virtual ~LottShapeGroup();\r
 \r
-    void Update(LottShape* parent, float frameNo) override;\r
+    void OnStop() override;\r
+    bool Update(float frameNo) override;\r
     void DrawLottShape(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, LottRenderContext& ctx);\r
     void Prepare();\r
 \r
@@ -44,10 +48,11 @@ public:
     Matrix3<float> matrix_;\r
     bool mergeable_ = false;\r
     LottPaint* paint_ = nullptr;\r
+    LottTrim* trim_ = nullptr;\r
 \r
 private:\r
-    void DrawMerged(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, VGUStrokeAttr& strokeAttr,\r
-        VGUFillAttr& fillAttr, VGUMatrix3& vguMat, bool strokeEnabled, bool fillEnabled);\r
+    void DrawMerged(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, LottRenderContext& ctx);\r
+    void DrawSeparateShapes(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, LottRenderContext& ctx);\r
     bool UpdatePathInner();\r
     Graphic::Vector<float> datas_;\r
     Graphic::Vector<uint8_t> cmds_;\r
index 65b32b9..6a90555 100644 (file)
@@ -18,6 +18,7 @@ public:
     LottShapeLayer();\r
     virtual ~LottShapeLayer();\r
 \r
+    void OnStop() override;\r
     bool UpdateLottLayer(float frameNo) override;\r
     void DrawLottLayer(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea,\r
         const Matrix3<float>& matrix, uint8_t opa) override;\r
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_trim.h b/code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_trim.h
new file mode 100644 (file)
index 0000000..2cc9ae6
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-7
+ */
+
+#ifndef LOTT_TRIM_H
+#define LOTT_TRIM_H
+
+#include "lottie/lott_property.h"
+#include "lottie/lott_trim_path.h"
+#include "display_vgu.h"
+#include "gfx_utils/graphic_math.h"
+#include "gfx_utils/heap_base.h"
+
+namespace OHOS {
+
+enum class LottTrimType {
+    Simultaneous,
+    Individual,
+};
+
+struct LottTrimValue {
+    bool enable;
+    float start;
+    float end;
+    float offset;
+    LottTrimType type;
+};
+
+class LottTrim : public HeapBase {
+public:
+    LottTrim();
+    virtual ~LottTrim();
+
+    LottFloatProp start_;
+    LottFloatProp end_;
+    LottFloatProp offset_;
+    LottTrimValue trimValue_;
+    void Update(float frameNo);
+};
+}
+#endif // LOTT_TRIM_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_trim_path.h b/code/sdk/middleware/services/gui/uikit/proprietary/include/lottie/lott_trim_path.h
new file mode 100644 (file)
index 0000000..d9d342f
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.
+ * Description: Graphic Lott Trim Path
+ * Author: Hisi Graphic Team
+ * Created: 2025-5
+ */
+
+#ifndef LOTT_TRIM_PATH_H
+#define LOTT_TRIM_PATH_H
+#include "common/graphic_hardware_types.h"
+#include "gfx_utils/vector.h"
+
+namespace OHOS {
+using CmdVector = Graphic::Vector<uint8_t>;
+using DataVector = Graphic::Vector<float>;
+class LottTrimPath : public HeapBase {
+public:
+    LottTrimPath() = default;
+    ~LottTrimPath();
+    // if path is not changed, don't set it every frame to avoid unnecessary computation
+    void SetPath(const Path& inPath);
+    // Reset path and and clear its cached trim path
+    void ClearPath();
+    /**
+     * @brief trim path using parameters startRatio, endRatio and offset
+     * @param startRatio Indicates the start position ([0 ~ 1]) of trimed ratio range
+     * @param endRatio Indicates the end position ([0 ~ 1]) of trimed ratio range
+     * @param offset Indicates the offset position ([0 ~ 1]) based on range [startRatio, endRatio]
+     * @param isParallel Indicates whether trim multiple path in parallel
+     * @return Returns <b>Path</b> after trimming, it is created when the function was called firstly;
+     *         reused or recreated in subsequent function calls; and released when the LottTrimPath obj is released
+     */
+    Path& TrimPath(float startRatio, float endRatio, float offset, bool isParallel = false);
+    float Length();
+
+    LottTrimPath(const LottTrimPath &) = delete;
+    LottTrimPath &operator=(const LottTrimPath &) = delete;
+    LottTrimPath(LottTrimPath &&) = delete;
+    LottTrimPath &operator=(LottTrimPath &&) = delete;
+
+private:
+    struct PathScope {
+        uint32_t startCmdIndex;
+        uint32_t endCmdIndex;
+        uint32_t startDataIndex;
+        uint32_t endDataIndex;
+    };
+    void TrimPath();
+    void TrimPath(const PathScope& scope, CmdVector& cmds, DataVector& data, float length);
+    void TrimPathWithRange(const PathScope& scope, const Vector2<float> range, CmdVector& cmds, DataVector& data);
+    void FillTrimPath(CmdVector& cmds, DataVector& data);
+
+    float startRatio_{0.0f};
+    float endRatio_{0.0f};
+    bool isParallel_{false};
+    float* segLen_{nullptr};
+    float length_{0.0f};
+    Path path_{0};
+    Path trimPath_{0};
+    uint32_t closeNum_{0};
+    uint32_t moveNum_{0};
+    bool needTrim_{false};
+};
+} // namespace OHOS
+#endif // LOTT_TRIM_PATH_H
\ No newline at end of file
index 476c8b8..d777c5d 100644 (file)
@@ -19,9 +19,15 @@ namespace OHOS {
 
 class UILottView : public UIView {
 public:
+    /**
+     * @brief  Constructor of UILottView.
+     */
     UILottView();
+
+    /**
+     * @brief  Destructor of UILottView.
+     */
     virtual ~UILottView();
-    void OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) override;
 
     /**
      * @brief Set lottie source file.
@@ -50,6 +56,28 @@ public:
      */
     void Stop();
 
+    /**
+     * @brief Set whether lottie animation is played repeatedly.
+     */
+    void SetRepeat(bool repeat);
+
+    /**
+     * @brief Get whether lottie animation is played repeatedly.
+     */
+    bool IsRepeat() const;
+
+    /**
+     * @brief  Get lottie animation state.
+     */
+    uint8_t GetState() const;
+
+    void OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) override;
+
+    UIViewType GetViewType() const override
+    {
+        return UI_LOTT_VIEW;
+    }
+
 private:
 
     class LottAnimCb : public AnimatorCallback {
@@ -57,7 +85,7 @@ private:
         LottAnimCb() {}
         virtual ~LottAnimCb() {}
         void Callback(UIView* view) override;
-
+        void OnStop(UIView& view) override;
         void SetEndValue(float value)
         {
             endValue_ = value;
@@ -81,6 +109,7 @@ private:
 
     friend class LottAnimCb;
 
+    bool repeat_ = false;
     LottAnimCb lottAnimCb_;
     Animator animator_;
     LottComp* lottComp_ = nullptr;
index a1103ef..7e28492 100644 (file)
@@ -133,6 +133,8 @@ public:
 \r
     void ForceRefreshImmediately();\r
 \r
+    void ForceRefreshMore();\r
+\r
     static void NativeMainThread(void* args);\r
     static void RtcEventThread(void* args);\r
 \r
index 50bd341..89c87d9 100644 (file)
@@ -86,7 +86,9 @@ bool GraphicService::AsyncTriggerNativeGraphicTask()
         osal_atomic_inc(&graphicTaskTriggeredCount_);\r
         OHOS::GraphicEventHandler::GetInstance()->PostGraphicEvent(\r
             [] {\r
-                if (GraphicService::GetInstance()->IsScreenOn() && isJsTaskFinished_) {\r
+                if (GraphicService::GetInstance()->IsScreenOn() &&\r
+                    isJsTaskFinished_ && // ±ÜÃâJS->Native TaskderHander¶àÏß³ÌÖØÈë\r
+                    GraphicService::GetInstance()->IsNativeRunning()) { // ±ÜÃâNative->JS ¶àÏß³ÌÎÊÌâ\r
                     OHOS::TaskManager::GetInstance()->TaskHandler();\r
                 } else {\r
                     GRAPHIC_LOGW("ignore redundant task when screen is off or js task is not finished\n");\r
@@ -195,6 +197,22 @@ void GraphicService::ForceRefreshImmediately()
     });\r
 }\r
 \r
+void GraphicService::ForceRefreshMore()\r
+{\r
+    using namespace OHOS;\r
+    osal_atomic_inc(&graphicTaskTriggeredCount_);\r
+    GraphicEventHandler::GetInstance()->PostGraphicEvent([] {\r
+        if (GraphicService::GetInstance()->IsScreenOn() && isJsTaskFinished_) {\r
+            RootView::GetInstance()->Invalidate();\r
+            TaskManager::GetInstance()->TaskHandler();\r
+            LiteMGfxEngine::GetInstance()->SyncHwDraw();\r
+        } else {\r
+            GRAPHIC_LOGW("ignore redundant task when screen is off or js task is not finished");\r
+        }\r
+        GraphicService::GetInstance()->DecreaseTriggerCount();\r
+    });\r
+}\r
+\r
 void GraphicService::EnableAsyncMode(bool enable)\r
 {\r
     OHOS::LiteMGfxEngine::GetInstance()->EnableAsyncMode(enable);\r
index 7221f25..21987ab 100644 (file)
@@ -396,8 +396,13 @@ extern "C"
 
     void SetFrequence(int freq)
     {
-        GraphicService::GetInstance()->PostGraphicEvent([=]
-                                                        {OHOS::LowPowerManager::GetInstance()->SetMaxFrequence(freq);});
+        if (freq <= 0 || freq > FULL_FREQUENCE) {
+            GRAPHIC_LOGE("freq %d should be in (0, 60]", freq);
+            return;
+        }
+        GraphicService::GetInstance()->PostGraphicEvent([=] {
+            OHOS::LowPowerManager::GetInstance()->SetMaxFrequence(freq);
+        });
     }
 
     void NotifyScreenOn(void)
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/common/graphic_cond_ext.cpp b/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/common/graphic_cond_ext.cpp
new file mode 100644 (file)
index 0000000..adc4f18
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: GraphicCondExt
+ * Author: Hisi Graphic Team
+ * Created: 2025-8
+ */
+
+#include "common/graphic_cond_ext.h"
+
+namespace OHOS {
+bool GraphicCondExt::WaitTime(GraphicMutex &mutex, uint32_t time)
+{
+#ifdef _WIN32
+        mutex.Unlock();
+        WaitForSingleObject(cond_, time);
+        ResetEvent(cond_);
+        mutex.Lock();
+#elif defined(__FREERTOS__)
+        mutex.Unlock();
+        osEventFlagsClear(cond_, 0x0001U);
+        uint32_t ret = osEventFlagsWait(cond_, 0x0001U, osFlagsWaitAny, time);
+        mutex.Lock();
+        if ((ret == osFlagsErrorParameter) || (ret == osFlagsErrorResource) ||
+            (ret == osFlagsErrorTimeout) || (ret == osFlagsErrorUnknown)) {
+            return false;
+        }
+        return true;
+#elif defined __linux__ || defined __LITEOS__
+        pthread_mutex_t& lock = mutex.GetMutex();
+        struct timespec t;
+        t.tv_nsec = (time % 1000) * 1e6; // 1000: 1s = 1000ms
+        t.tv_sec = time / 1000; // 1000: 1s = 1000ms
+        return (pthread_cond_timedwait(&cond_, &lock, &t) == 0);
+#endif
+}
+} // namespace OHOS
index 3fb1585..168cb81 100644 (file)
  * limitations under the License.
  */
 
-#include "common/lite_surface.h"
+#include "hals/display_dev.h"
 #include "hals/gralloc_engines.h"
 #include "gfx_utils/graphic_log.h"
 #include "gfx_utils/graphic_math.h"
 #include "graphic_service.h"
+#include "common/lite_surface.h"
 
 namespace OHOS {
 LiteSurface::LiteSurface() : bufferCount_(0), queueSize_(0), size_(0),
@@ -31,6 +32,16 @@ LiteSurface::~LiteSurface()
     ClearBuffers();
 }
 
+void LiteSurface::AsyncClearBuffers()
+{
+    std::weak_ptr<bool> wp = waitPrepareBuffer_;
+    GraphicService::GetInstance()->PostGraphicEvent([this, wp]() {
+        if (!wp.expired()) {
+            ClearBuffers();
+        }
+    });
+}
+
 void LiteSurface::ClearBuffers()
 {
     lock_.Lock();
@@ -54,6 +65,24 @@ void LiteSurface::ClearBuffers()
 }
 
 void LiteSurface::PrepareBuffers()
+{
+    bool waitPrepareBuffer = *waitPrepareBuffer_;
+    if (!waitPrepareBuffer) {
+        *waitPrepareBuffer_ = true;
+        std::weak_ptr<bool> wp = waitPrepareBuffer_;
+        GraphicService::GetInstance()->PostGraphicEvent([this, wp]() {
+            if (!wp.expired()) {
+                PrepareBuffersInner();
+                *waitPrepareBuffer_ = false;
+            }
+        });
+        GRAPHIC_LOGD("Post PrepareBuffers Event. BufferCount: %d, QueueSize: %d.", bufferCount_, queueSize_);
+    } else {
+        GRAPHIC_LOGW("Waiting Preparing buffer!");
+    }
+}
+
+void LiteSurface::PrepareBuffersInner()
 {
     if (bufferCount_ != 0) {
         GRAPHIC_LOGD("Already prepared buffers, bufferCount_ is %u", bufferCount_);
@@ -113,25 +142,12 @@ bool LiteSurface::CanRequest(uint8_t wait)
         goto END;
     }
     if (bufferCount_ < queueSize_) {
-        bool waitPrepareBuffer = *waitPrepareBuffer_;
-        if (!waitPrepareBuffer) {
-            std::weak_ptr<bool> wp = waitPrepareBuffer_;
-            GraphicService::GetInstance()->PostGraphicEvent([this, wp]() {
-                if (!wp.expired()) {
-                    PrepareBuffers();
-                    *waitPrepareBuffer_ = false;
-                }
-            });
-            *waitPrepareBuffer_ = true;
-            GRAPHIC_LOGE("Post PrepareBuffers Event. BufferCount: %d, QueueSize: %d.", bufferCount_, queueSize_);
-        } else {
-            GRAPHIC_LOGW("Waiting Preparing buffer!");
-        }
+        PrepareBuffers();
         res = false;
         goto END;
     }
     if (wait) {
-        cond_.Wait(lock_);
+        cond_.WaitTime(lock_, 16); // 16: 16ms
         res = true;
     }
 END:
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/common_adapter.cpp b/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/common_adapter.cpp
new file mode 100644 (file)
index 0000000..c0eca80
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Generic type adapter for view management
+ * Author: Hisi Team
+ * Created: 2025-07
+ */
+#include "components/common_adapter.h"
+#include "components/ui_simple_list.h"
+namespace OHOS {
+CommonAdapter::CommonAdapter()
+{
+}
+
+CommonAdapter::~CommonAdapter()
+{
+    ClearAll();
+}
+
+uint16_t CommonAdapter::GetCount()
+{
+    return contents_.Size();
+}
+
+uint8_t CommonAdapter::GetViewType(int16_t index)
+{
+    if (index < 0 || index >= contents_.Size()) {
+        return 0;
+    }
+
+    auto& content = contents_[index];
+    return content.type;
+}
+
+UIView* CommonAdapter::GetView(UIView* inView, int16_t index)
+{
+    if (index < 0 || index >= contents_.Size()) {
+        return nullptr;
+    }
+
+    auto& content = contents_[index];
+
+    UIView* view = inView;
+    if (inView == nullptr) {
+        view = content.createFunc(content.type);
+    }
+
+    if (content.updateFunc && view) {
+        view->SetViewId(reinterpret_cast<char*>(content.type & 0xff));
+        content.updateFunc(view, content.data, content.type);
+        view->SetViewIndex(index);
+    }
+
+    return view;
+}
+
+void CommonAdapter::AddContent(Contents& data)
+{
+    contents_.PushBack(data);
+}
+
+bool CommonAdapter::UpdateContent(int16_t index, Contents& data)
+{
+    if (index < 0 || index >= contents_.Size()) {
+        return false;
+    }
+
+    auto& content = contents_[index];
+    content.createFunc = data.createFunc;
+    content.updateFunc = data.updateFunc;
+    content.type = data.type;
+    content.data = data.data;
+    return true;
+}
+
+void CommonAdapter::ClearAll()
+{
+    contents_.Clear();
+}
+
+bool CommonAdapter::RemoveContent(int16_t index)
+{
+    if (index < 0 || index >= contents_.Size()) {
+        return false;
+    }
+    contents_.Erase(index);
+    return true;
+}
+}
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/common_adapter.h b/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/common_adapter.h
new file mode 100644 (file)
index 0000000..371dc9c
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Generic type adapter for view management
+ * Author: Hisi Team
+ * Created: 2025-07
+ */
+#ifndef GRAPHIC_CUSTOM_ADPTER_H
+#define GRAPHIC_CUSTOM_ADPTER_H
+
+#include "components/abstract_adapter.h"
+#include "gfx_utils/vector.h"
+
+namespace OHOS {
+class Contents;
+/**
+ * Custom adapter implementation for view management
+ * Inherits from AbstractAdapter base class
+ */
+class CommonAdapter : public AbstractAdapter {
+public:
+    CommonAdapter();
+    ~CommonAdapter();
+
+    /**
+     * Gets total view count
+     * @return Number of views managed by this adapter
+     */
+    uint16_t GetCount();
+
+    /**
+     * Retrieves a view at specified index
+     * @param inView Recyclable view container
+     * @param index Index of view to retrieve
+     * @return View instance or new view when inView is null
+     */
+    UIView* GetView(UIView* inView, int16_t index);
+
+    /**
+     * Adds new view content configuration
+     * @param data Contents structure with callbacks and data
+     */
+    void AddContent(Contents& data);
+
+    /**
+     * Updates view content at specific index
+     * @param index Target view index to update
+     * @param data New content configuration to apply
+     * @return True if update successful
+     */
+    bool UpdateContent(int16_t index, Contents& data);
+
+    /**
+    * Removes the content at the specified index from the adapter.
+    * @param index The zero-based index of the content to remove.
+    *              Must be between 0 and (GetCount() - 1).
+    * @return True if the content was successfully removed,
+    *         false if the index is out of bounds.
+    * @note This method clears the corresponding element in the contents_ vector.
+    *       If the index is invalid (e.g., negative or exceeds current size), the operation fails.
+    *       The memory of any pointers (like data in the Contents struct) is not managed here.
+    */
+    bool RemoveContent(int16_t index);
+
+    /** Removes all view content from the adapter */
+    void ClearAll();
+
+    /** Retrieve the type value of the current index data */
+    uint8_t GetViewType(int16_t index);
+private:
+    Graphic::Vector<Contents> contents_;
+};
+}
+#endif
index 99d7182..7712b70 100644 (file)
@@ -323,10 +323,6 @@ void UIInputMethod::SetupHanziCandidate()
     int16_t y = 200;
     int16_t w = 398;
     int16_t h = 50;
-    int8_t gap = 2;
-    int16_t buttonGap = (w - gap) / DEFAULT_NUMPERPAGE;
-    int16_t btnWidth = buttonGap - gap;
-    int16_t btnHeight = h - gap * 2; // 2: half
 
     hanziAdapter_ = new HanziAdapter;
     // set height, set width, set data
index cb23c9e..e91e4db 100644 (file)
@@ -51,6 +51,9 @@ void UIListExt::ReMeasure()
 
 void UIListExt::ModifyMidAdjSpace(int16_t centerIndex, int16_t& prevIndex, int16_t& nextIndex)
 {
+    if (items_.Size() == 0) {
+        return;
+    }
     Rect centerRect = items_[centerIndex]->GetRect();
     if (direction_ == VERTICAL) {
         int16_t centerY = centerRect.GetTop() + (centerRect.GetHeight() >> 1);
index b3406e8..e84f7eb 100644 (file)
@@ -37,6 +37,7 @@ static constexpr int16_t YUV_WIDTH_ALIGNMENT = 128;
 UILiteSurfaceView::UILiteSurfaceView() : isLayerInit_(false), flushCount_(0)\r
 {\r
     surface_ = std::make_shared<LiteSurface>();\r
+    exist_ = std::make_shared<bool>(true);\r
     if (surface_ == nullptr) {\r
         GRAPHIC_LOGE("new LiteSurface failed\n");\r
         return;\r
@@ -182,6 +183,10 @@ void UILiteSurfaceView::InitLayer()
 #ifdef VERSION_IOT\r
 bool UILiteSurfaceView::GetSurfaceBufferBitmap(ImageInfo& bitmap)\r
 {\r
+    if (lastFlushedBuffer_ == nullptr) {\r
+        GRAPHIC_LOGE("lastFlushedBuffer_ is null.");\r
+        return false;\r
+    }\r
     CscYuvBuf yuv = {0};\r
     yuv.yAddr = reinterpret_cast<uint8_t*>(lastFlushedBuffer_->addr);\r
     yuv.uvAddr = static_cast<uint8_t*>(yuv.yAddr) + ALIGN_BYTE(lastFlushedBuffer_->width, YUV_WIDTH_ALIGNMENT) *\r
@@ -318,44 +323,41 @@ void UILiteSurfaceView::OnBufferAvailable()
         ++flushCount_;\r
     }\r
     lock_.Unlock();\r
-    std::weak_ptr<LiteSurface> ws = surface_;\r
+    std::weak_ptr<bool> ws = exist_;\r
     if (isLastFrame) {\r
         isStopped_ = true;\r
-        GraphicService::GetInstance()->PostGraphicEvent(\r
-            [&, ws] {\r
-                if (!ws.expired()) {\r
-                    DisplayDev::GetInstance()->SetLayerColorKey(LAYER_0, false, 0);\r
-                    LiteMGfxEngine::GetInstance()->ClearHardwareLayer(this);\r
-                    if (LiteMGfxEngine::GetInstance()->GetHardwareLayer() == nullptr) {\r
-                        GraphicService::GetInstance()->EnableAsyncMode(true);\r
-                    }\r
-                    surface_->ClearBuffers();\r
-                    currentBuffer_ = nullptr;\r
-                    lastFlushedBuffer_ = nullptr;\r
+        std::shared_ptr<LiteSurface> surface = surface_;\r
+        GraphicService::GetInstance()->PostGraphicEvent([&, ws, surface] {\r
+            if (!ws.expired()) {\r
+                DisplayDev::GetInstance()->SetLayerColorKey(LAYER_0, false, 0);\r
+                LiteMGfxEngine::GetInstance()->ClearHardwareLayer(this);\r
+                if (LiteMGfxEngine::GetInstance()->GetHardwareLayer() == nullptr) {\r
+                    GraphicService::GetInstance()->EnableAsyncMode(true);\r
                 }\r
-            });\r
+                currentBuffer_ = nullptr;\r
+                lastFlushedBuffer_ = nullptr;\r
+            }\r
+            DisplayDev::GetInstance()->SetPendingReleaseSurface(surface);\r
+        });\r
+        GraphicService::GetInstance()->ForceRefreshMore();\r
     } else if (isStopped_) {\r
         isStopped_ = false;\r
         LowPowerManager::GetInstance()->ExitLowPower();\r
-        GraphicService::GetInstance()->PostGraphicEvent(\r
-            [&, ws] {\r
-                if (!ws.expired()) {\r
-                    if (!GraphicService::GetInstance()->IsScreenOn()) {\r
-                        isStopped_ = true; // Do not process video frame, when screen off and dpu suspended.\r
-                        return;\r
-                    }\r
-                    LiteMGfxEngine::GetInstance()->EnableAsyncMode(false);\r
-                    LiteMGfxEngine::GetInstance()->AddHardwareLayer(this);\r
-                    DisplayDev::GetInstance()->SetLayerColorKey(LAYER_0, true, colorKey_.full);\r
-                    InitLayer();\r
+        GraphicService::GetInstance()->PostGraphicEvent([&, ws] {\r
+            if (!ws.expired()) {\r
+                if (!GraphicService::GetInstance()->IsScreenOn()) {\r
+                    isStopped_ = true;  // Do not process video frame, when screen off and dpu suspended.\r
+                    return;\r
                 }\r
-            });\r
+                LiteMGfxEngine::GetInstance()->EnableAsyncMode(false);\r
+                LiteMGfxEngine::GetInstance()->AddHardwareLayer(this);\r
+                DisplayDev::GetInstance()->SetLayerColorKey(LAYER_0, true, colorKey_.full);\r
+                InitLayer();\r
+            }\r
+        });\r
     }\r
 \r
-    GraphicService::GetInstance()->PostGraphicEvent(\r
-        [] {\r
-            RootView::GetInstance()->Invalidate();\r
-        });\r
+    GraphicService::GetInstance()->PostGraphicEvent([] { RootView::GetInstance()->Invalidate(); });\r
 }\r
 \r
 void UILiteSurfaceView::SetPreview(ImageInfo* info)\r
index 1659219..df4177f 100644 (file)
@@ -16,7 +16,6 @@
 #include "components/ui_menu_item.h"\r
 #include "components/root_view.h"\r
 namespace OHOS {\r
-constexpr uint32_t IMG_TO_TEXT_GAP = 20; // 20: the gap between img and text\r
 \r
 UIMenuItem::UIMenuItem() : image_(nullptr), label_(nullptr),\r
     labelLineBreakMode_(UILabel::LineBreakMode::LINE_BREAK_ELLIPSIS), needRefresh_(false)\r
@@ -40,8 +39,6 @@ UIMenuItem::~UIMenuItem()
 \r
 Vector2<float> UIMenuItem::GetScaleCenter()\r
 {\r
-    int16_t itemOrigX = GetOrigRect().GetX();\r
-    int16_t itemOrigY = GetOrigRect().GetY();\r
     if (transAlignMode_ == ScaleAlignMode::ALIGN_TEXT_LEFT) {\r
         return Vector2<float>{label_->GetX(), label_->GetHeight() / 2.0f};\r
     } else if (transAlignMode_ == ScaleAlignMode::ALIGN_IMAGE_LEFT) {\r
index ce7ded2..9a79f15 100644 (file)
@@ -264,6 +264,8 @@ void UISweepClock::DrawHand(BufferInfo& gfxDstBuffer, const Rect& current, const
                 GRAPHIC_LOGE("DrawHand failed. UpdateImageInfoIfNecessary failed.");
                 return;
             }
+        } else {
+            return;
         }
         DrawHandImage(gfxDstBuffer, current, invalidatedArea, hand);
     } else {
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/ui_transform_button.cpp b/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/ui_transform_button.cpp
new file mode 100644 (file)
index 0000000..85820f7
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: UITransformButton
+ * Author: Hisi Graphic Team
+ * Created: 2025-11
+ */
+
+#include "ui_transform_button.h"
+#include "animator/interpolation.h"
+#include "common/image.h"
+#include "draw/draw_image.h"
+#include "engines/gfx/gfx_engine_manager.h"
+#include "engines/gfx/lite_m_gfx_engine.h"
+#include "gfx_utils/graphic_log.h"
+#include "gfx_utils/style.h"
+#include "imgdecode/cache_manager.h"
+#include "themes/theme_manager.h"
+
+namespace OHOS {
+namespace {
+constexpr float FULL_SCALE = 1.0f;
+constexpr float SHRINK_SCALE = 0.8f;
+constexpr uint32_t SHRINK_DURATION = 150;
+constexpr uint32_t RECOVER_DURATION = 200;
+constexpr int64_t MASK_OPA = 25;
+constexpr float BEZIER_CONTROL = 0.2f;
+} // namespace
+
+UITransformButton::UITransformButton()
+    : contentWidth_(0),
+      contentHeight_(0),
+      state_(TransformButtonState::RELEASED),
+      styleState_(TransformButtonState::RELEASED),
+      enableAnimation_(true),
+      animator_(*this),
+      buttonStyleAllocFlag_(false),
+      shrinkScale_(SHRINK_SCALE),
+      shrinkDuration_(SHRINK_DURATION),
+      recoverDuration_(RECOVER_DURATION)
+{
+    touchable_ = true;
+    SetupThemeStyles();
+}
+
+UITransformButton::~UITransformButton()
+{
+    if (buttonStyleAllocFlag_) {
+        for (uint8_t i = 0; i < static_cast<uint8_t>(TransformButtonState::BTN_STATE_NUM); i++) {
+            delete buttonStyles_[i];
+            buttonStyles_[i] = nullptr;
+        }
+        buttonStyleAllocFlag_ = false;
+    }
+}
+
+void UITransformButton::SetShrinkScale(float scale)
+{
+    shrinkScale_ = scale;
+}
+
+float UITransformButton::GetShrinkScale() const
+{
+    return shrinkScale_;
+}
+
+void UITransformButton::SetShrinkDuration(uint32_t dur)
+{
+    shrinkDuration_ = dur;
+}
+
+uint32_t UITransformButton::GetShrinkDuration() const
+{
+    return shrinkDuration_;
+}
+
+void UITransformButton::SetRecoverDuration(uint32_t dur)
+{
+    recoverDuration_ = dur;
+}
+
+uint32_t UITransformButton::GetRecoverDuration() const
+{
+    return recoverDuration_;
+}
+
+void UITransformButton::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
+{
+    OpacityType opa = GetMixOpaScale();
+    LiteMGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, GetOrigRect(), invalidatedArea,
+        *buttonStyles_[static_cast<uint8_t>(state_)], opa, transMap_);
+}
+
+void UITransformButton::SetupThemeStyles()
+{
+    Theme* theme = ThemeManager::GetInstance().GetCurrent();
+
+    if (theme == nullptr) {
+        buttonStyles_[static_cast<uint8_t>(TransformButtonState::RELEASED)] = &(StyleDefault::GetButtonReleasedStyle());
+        buttonStyles_[static_cast<uint8_t>(TransformButtonState::PRESSED)] = &(StyleDefault::GetButtonPressedStyle());
+        buttonStyles_[static_cast<uint8_t>(TransformButtonState::INACTIVE)] = &(StyleDefault::GetButtonInactiveStyle());
+    } else {
+        buttonStyles_[static_cast<uint8_t>(TransformButtonState::RELEASED)] = &(theme->GetButtonStyle().released);
+        buttonStyles_[static_cast<uint8_t>(TransformButtonState::PRESSED)] = &(theme->GetButtonStyle().pressed);
+        buttonStyles_[static_cast<uint8_t>(TransformButtonState::INACTIVE)] = &(theme->GetButtonStyle().inactive);
+    }
+    style_ = buttonStyles_[static_cast<uint8_t>(TransformButtonState::RELEASED)];
+}
+
+int64_t UITransformButton::GetStyle(uint8_t key) const
+{
+    return GetStyleForState(key, styleState_);
+}
+
+void UITransformButton::SetStyle(uint8_t key, int64_t value)
+{
+    SetStyleForState(key, value, styleState_);
+}
+
+int64_t UITransformButton::GetStyleForState(uint8_t key, TransformButtonState state) const
+{
+    if (state < TransformButtonState::BTN_STATE_NUM) {
+        return (buttonStyles_[static_cast<uint8_t>(state)])->GetStyle(key);
+    }
+    return 0;
+}
+
+void UITransformButton::SetStyleForState(uint8_t key, int64_t value, TransformButtonState state)
+{
+    if (state >= TransformButtonState::BTN_STATE_NUM) {
+        return;
+    }
+
+    if (!buttonStyleAllocFlag_) {
+        uint8_t i = 0;
+        for (; i < static_cast<uint8_t>(TransformButtonState::BTN_STATE_NUM); i++) {
+            Style styleSaved = *buttonStyles_[i];
+            buttonStyles_[i] = new Style;
+            if (buttonStyles_[i] == nullptr) {
+                GRAPHIC_LOGE("new Style fail");
+                break;
+            }
+            *(buttonStyles_[i]) = styleSaved;
+        }
+        if (i < static_cast<uint8_t>(TransformButtonState::BTN_STATE_NUM)) {
+            for (uint8_t j = 0; j < i; ++j) {
+                delete buttonStyles_[j];
+                buttonStyles_[j] = nullptr;
+            }
+            SetupThemeStyles();
+            return;
+        }
+        buttonStyleAllocFlag_ = true;
+    }
+    style_ = buttonStyles_[static_cast<uint8_t>(TransformButtonState::RELEASED)];
+    int16_t width = GetWidth();
+    int16_t height = GetHeight();
+    int16_t x = GetX();
+    int16_t y = GetY();
+    buttonStyles_[static_cast<uint8_t>(state)]->SetStyle(key, value);
+    Rect rect(x, y, x + width - 1, y + height -  1);
+    UpdateRectInfo(key, rect);
+}
+
+bool UITransformButton::OnPressEvent(const PressEvent& event)
+{
+    SetState(TransformButtonState::PRESSED);
+    Resize(contentWidth_, contentHeight_);
+    Invalidate();
+    if (enableAnimation_) {
+        animator_.Start();
+    }
+    return UIView::OnPressEvent(event);
+}
+
+bool UITransformButton::OnReleaseEvent(const ReleaseEvent& event)
+{
+    SetState(TransformButtonState::RELEASED);
+    Resize(contentWidth_, contentHeight_);
+    Invalidate();
+    if (enableAnimation_) {
+        animator_.Start();
+    }
+    return UIView::OnReleaseEvent(event);
+}
+
+bool UITransformButton::OnCancelEvent(const CancelEvent& event)
+{
+    SetState(TransformButtonState::RELEASED);
+    Resize(contentWidth_, contentHeight_);
+    Invalidate();
+    if (enableAnimation_) {
+        animator_.Start();
+    }
+    return UIView::OnCancelEvent(event);
+}
+
+void UITransformButton::Disable()
+{
+    SetState(TransformButtonState::INACTIVE);
+    touchable_ = false;
+}
+
+void UITransformButton::Enable()
+{
+    SetState(TransformButtonState::RELEASED);
+    touchable_ = true;
+}
+
+void UITransformButton::SetState(TransformButtonState state)
+{
+    state_ = state;
+    style_ = buttonStyles_[static_cast<uint8_t>(state_)];
+    Invalidate();
+}
+
+bool UITransformButton::OnPreDraw(Rect& invalidatedArea) const
+{
+    Rect rect(GetRect());
+    int16_t topRadius = buttonStyles_[static_cast<uint8_t>(styleState_)]->GetStyle(STYLE_TOP_BORDER_RADIUS);
+    int16_t bottomRadius = buttonStyles_[static_cast<uint8_t>(styleState_)]->GetStyle(STYLE_BOTTOM_BORDER_RADIUS);
+    if (topRadius == bottomRadius && topRadius == COORD_MAX) {
+        return true;
+    }
+
+    if (topRadius != 0 || bottomRadius != 0) {
+        rect = GetInnerRect(rect, topRadius, bottomRadius);
+    }
+    if (rect.IsContains(invalidatedArea)) {
+        return true;
+    }
+    invalidatedArea.Intersect(invalidatedArea, rect);
+    return false;
+}
+
+void UITransformButton::ButtonAnimator::Start()
+{
+    bool isReverse = (button_.state_ == UITransformButton::TransformButtonState::PRESSED);
+    float targetScale = isReverse ? button_.shrinkScale_ : FULL_SCALE;
+    if ((animator_.GetState() == Animator::STOP) && FloatEqual(targetScale, scale_)) {
+        return;
+    }
+
+    if (isReverse) {
+        animator_.SetTime(button_.shrinkDuration_);
+    } else {
+        animator_.SetTime(button_.recoverDuration_);
+    }
+    animator_.Start();
+    /* reverse the animator direction */
+    float x = isReverseAnimation_ ? (FULL_SCALE - scale_) : (scale_ - button_.shrinkScale_);
+    float y = x / (FULL_SCALE - button_.shrinkScale_);
+    x = Interpolation::GetBezierY(FULL_SCALE - y, 0, BEZIER_CONTROL, FULL_SCALE, BEZIER_CONTROL);
+    animator_.SetRunTime(static_cast<uint32_t>(animator_.GetTime() * x));
+    isReverseAnimation_ = isReverse;
+}
+
+static inline void ScaleButton(UITransformButton& button, float scale)
+{
+    Vector2<float> scaleValue_ = {scale, scale};
+    Vector2<float> centrePoint(button.GetWidth() / 2.0f, button.GetHeight() / 2.0f);
+    button.Scale(scaleValue_, centrePoint);
+}
+
+void UITransformButton::ButtonAnimator::Callback(UIView* view)
+{
+    float x = static_cast<float>(animator_.GetRunTime()) / animator_.GetTime();
+    float offset = Interpolation::GetBezierY(x, BEZIER_CONTROL, 0, BEZIER_CONTROL, FULL_SCALE);
+    float scale = (FULL_SCALE - button_.shrinkScale_) * offset;
+
+    scale_ = isReverseAnimation_ ? (FULL_SCALE - scale) : (scale + button_.shrinkScale_);
+    ScaleButton(button_, scale_);
+}
+
+void UITransformButton::ButtonAnimator::OnStop(UIView& view)
+{
+    if (isReverseAnimation_) {
+        scale_ = button_.shrinkScale_;
+        ScaleButton(button_, button_.shrinkScale_);
+    } else {
+        scale_ = FULL_SCALE;
+        button_.ResetTransParameter();
+    }
+}
+} // namespace OHOS
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/ui_transform_button.h b/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/components/ui_transform_button.h
new file mode 100644 (file)
index 0000000..8005943
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: UITransformButton
+ * Author: Hisi Graphic Team
+ * Created: 2025-11
+ */
+
+#ifndef UI_TRANSFORM_BUTTON_H
+#define UI_TRANSFORM_BUTTON_H
+#include "animator/animator.h"
+#include "common/text.h"
+#include "components/ui_transform_group.h"
+#include "gfx_utils/graphic_log.h"
+
+namespace OHOS {
+class UITransformButton : public UITransformGroup {
+public:
+    UITransformButton();
+    ~UITransformButton() override;
+    /**
+     * @brief Obtains the component type.
+     *
+     * @return Returns the component type, as defined in {@link UIViewType}.
+     */
+    UIViewType GetViewType() const override
+    {
+        return UI_TRANSFORM_BUTTON;
+    }
+
+    /**
+     * Sets the scale factor for the shrink effect.
+     * @param scale The scaling factor to apply during shrink.
+     */
+    void SetShrinkScale(float scale);
+
+    /**
+     * Returns the current shrink scale factor.
+     * @return The current shrink scale factor.
+     */
+    float GetShrinkScale() const;
+
+    /**
+     * Sets the duration of the shrink effect.
+     * @param dur The duration of the shrink effect in milliseconds.
+     */
+    void SetShrinkDuration(uint32_t dur);
+
+    /**
+     * Returns the current shrink duration.
+     * @return The current shrink duration in milliseconds.
+     */
+    uint32_t GetShrinkDuration() const;
+
+    /**
+     * Sets the duration of the recover effect.
+     * @param dur The duration of the recover effect in milliseconds.
+     */
+    void SetRecoverDuration(uint32_t dur);
+
+    /**
+     * Returns the current recover duration.
+     * @return The current recover duration in milliseconds.
+     */
+    uint32_t GetRecoverDuration() const;
+
+    /**
+     * @fn virtual bool UITransformButton::OnPreDraw(Rect& invalidatedArea) override
+     *
+     * @brief Do something before draw, this function will be invoked mainly to check if this view need
+     *        to cover invalidate area so render manager can decide which layer to draw firstly.
+     * @param [in] invalidate area.
+     * @returns True if need cover.
+     */
+    bool OnPreDraw(Rect& invalidatedArea) const override;
+
+    /**
+     * @fn  virtual void UITransformButton::OnDraw(const Rect& invalidatedArea) override;
+     *
+     * @brief   Executes the draw action
+     *
+     * @param   [in] invalidatedArea The rectangle to draw, with coordinates relative to this drawable..
+     */
+    void OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) override;
+
+    /**
+     * @fn  virtual void UITransformButton::OnPressEvent(const PressEvent& event) override;
+     *
+     * @brief   Executes the press event action
+     *
+     * @param   [in] event   The press event, contain press position.
+     *
+     * @return Returns <b>true</b> if the event is consumed; returns <b>false</b> otherwise.
+     */
+    bool OnPressEvent(const PressEvent& event) override;
+
+    /**
+     * @fn  virtual void UITransformButton::OnReleaseEvent(const ReleaseEvent& event) override;
+     *
+     * @brief   Executes the press release event action
+     *
+     * @param   [in] event   The press release event.
+     */
+    bool OnReleaseEvent(const ReleaseEvent& event) override;
+
+    /**
+     * @fn  virtual void UITransformButton::OnCancelEvent(const CancelEvent& event) override;
+     *
+     * @brief   Executes the cancel event action
+     *
+     * @param   [in] event   The cancel event.
+     */
+    bool OnCancelEvent(const CancelEvent& event) override;
+
+    /**
+     * @brief Enumerates the states of this button.
+     *
+     * The button has three states.
+     */
+    enum class TransformButtonState : uint8_t {
+        /* An enum constant representing the Button state released option */
+        RELEASED = 0,
+        /* An enum constant representing the Button state pressed option */
+        PRESSED,
+        /* An enum constant representing the Button state inactive option */
+        INACTIVE,
+        /* An enum constant representing the Button state Number option */
+        BTN_STATE_NUM,
+    };
+
+    /**
+     * @brief Obtains the width of this button.
+     *
+     * @return Returns the button width.
+     */
+    int16_t GetWidth() override
+    {
+        Style* style = buttonStyles_[static_cast<uint8_t>(state_)];
+        return GetRelativeRect().GetWidth() - (style->paddingLeft_ + style->paddingRight_) -
+               (style->borderWidth_ * 2); /* 2: left and right border */
+    }
+
+    /**
+     * @brief Obtains the height of this button.
+     *
+     * @return Returns the button height.
+     */
+    int16_t GetHeight() override
+    {
+        Style* style = buttonStyles_[static_cast<uint8_t>(state_)];
+        return GetRelativeRect().GetHeight() - (style->paddingTop_ + style->paddingBottom_) -
+               (style->borderWidth_ * 2); /* 2: top and bottom border */
+    }
+
+    /**
+     * @brief Sets the width for this button.
+     *
+     * @param width Indicates the width to set.
+     */
+    void SetWidth(int16_t width) override
+    {
+        contentWidth_ = width;
+        UIView::SetWidth(width); /* 2: left and right border */
+    }
+
+    /**
+     * @brief Sets the height for this button.
+     *
+     * @param height Indicates the height to set.
+     */
+    void SetHeight(int16_t height) override
+    {
+        contentHeight_ = height;
+        UIView::SetHeight(height); /* 2: top and bottom border */
+    }
+
+    /**
+     * @brief Obtains a rectangular area that contains coordinate information.
+     *
+     * @return Returns the rectangle area.
+     */
+    virtual Rect GetContentRect() override
+    {
+        Rect contentRect;
+        Style* style = buttonStyles_[static_cast<uint8_t>(state_)];
+        contentRect.SetX(GetOrigRect().GetX() + style->paddingLeft_ + style->borderWidth_);
+        contentRect.SetY(GetOrigRect().GetY() + style->paddingTop_ + style->borderWidth_);
+        contentRect.SetWidth(GetWidth());
+        contentRect.SetHeight(GetHeight());
+        return contentRect;
+    }
+
+    /**
+     * @brief Obtains the value of a style.
+     *
+     * @param key Indicates the key of the style.
+     * @return Returns the value of the style.
+     */
+    int64_t GetStyle(uint8_t key) const override;
+
+    /**
+     * @brief Sets a style.
+     *
+     * @param key Indicates the key of the style to set.
+     * @param value Indicates the value matching the key.
+     */
+    void SetStyle(uint8_t key, int64_t value) override;
+
+    /**
+     * @brief Obtains the style of a button in a specific state.
+     *
+     * @param key Indicates the key of the style.
+     * @param state Indicates the button state, as enumerated in {@link TransformButtonState}.
+     * @return Returns the style of the button in the specific state.
+     */
+    int64_t GetStyleForState(uint8_t key, TransformButtonState state) const;
+
+    /**
+     * @brief Sets the style for a button in a specific state.
+     *
+     * @param key Indicates the key of the style to set.
+     * @param value Indicates the value matching the key.
+     * @param state Indicates the button state, as enumerated in {@link TransformButtonState}.
+     */
+    void SetStyleForState(uint8_t key, int64_t value, TransformButtonState state);
+
+    /**
+     * @brief Disables this button.
+     */
+    void Disable();
+
+    /**
+     * @brief Enables this button.
+     */
+    void Enable();
+
+    /**
+     * @brief Sets the state for a button. After the setting, calling {@link SetStyle}
+     *        will change the style of this button, but not its state.
+     *
+     * @param state Indicates the button state, as enumerated in {@link TransformButtonState}.
+     */
+    void SetStateForStyle(TransformButtonState state)
+    {
+        styleState_ = state;
+    }
+
+    /**
+    * Enables or disables the button animation feature.
+    * @param enable True to enable the animation, false to disable it.
+    */
+    void EnableButtonAnimation(bool enable)
+    {
+        enableAnimation_ = enable;
+    }
+
+protected:
+    int16_t contentWidth_;
+    int16_t contentHeight_;
+    void SetState(TransformButtonState state);
+
+    TransformButtonState state_;
+    TransformButtonState styleState_;
+    Style* buttonStyles_[static_cast<uint8_t>(TransformButtonState::BTN_STATE_NUM)];
+
+    bool enableAnimation_;
+    friend class ButtonAnimator;
+    class ButtonAnimator final : public AnimatorCallback {
+    public:
+        ButtonAnimator() = delete;
+        ButtonAnimator(const ButtonAnimator&) = delete;
+        ButtonAnimator& operator=(const ButtonAnimator&) = delete;
+        ButtonAnimator(ButtonAnimator&&) = delete;
+        ButtonAnimator& operator=(ButtonAnimator&&) = delete;
+        explicit ButtonAnimator(UITransformButton& button) : animator_(this, nullptr, 0, false), button_(button) {}
+        ~ButtonAnimator() override {}
+
+        void Start();
+        void Callback(UIView* view) override;
+        void OnStop(UIView& view) override;
+
+    private:
+        Animator animator_;
+        bool isReverseAnimation_ = false;
+        float scale_ = 1.0f;
+        UITransformButton& button_;
+    } animator_;
+
+    bool buttonStyleAllocFlag_;
+
+private:
+    /** Sets up the theme styles */
+    void SetupThemeStyles();
+    float shrinkScale_;
+    uint32_t shrinkDuration_;
+    uint32_t recoverDuration_;
+}; // class UITransformButton
+} // namespace OHOS
+#endif // UI_TRANSFORM_BUTTON_H
index 4cae676..25a2011 100644 (file)
@@ -164,7 +164,7 @@ private:
         &MapSVGParser::ReleaseMapPath, &MapSVGParser::ReleaseMapText, &MapSVGParser::ReleaseMapImg,\r
         &MapSVGParser::ReleaseMapRoad, &MapSVGParser::ReleaseMapPOI };\r
 \r
-    MapHeader mapHeader_ = {0};\r
+    MapHeader mapHeader_ = {{0}};\r
     MapNode* nodeArray_ = nullptr;\r
     PathStyle* pathStyleArray_ = nullptr;\r
     PathDetail* pathArray_ = nullptr;\r
index 7f572ff..44371e3 100644 (file)
@@ -18,7 +18,7 @@ public:
     ~UICardContainer() override;
     UICardContainer(const UICardContainer &) = delete;
     UICardContainer &operator=(const UICardContainer &) = delete;
-    void SwitchCardToBitmap(bool isNeedClip, bool bitMapFromFB = false);
+    void SwitchCardToBitmap(bool isNeedClip, bool bitMapFromFB = false, float scale = 1.0);
     void SwitchBitmapToCard(void);
 
     void SetCardPage(UICardPage* page)
@@ -41,6 +41,11 @@ public:
         return imgView_;
     }
 
+    UIViewType GetViewType() const override
+    {
+        return UI_CARD_CONTAINER;
+    }
+
     void PreLoad(void);
     void UnLoad(void);
 
@@ -62,6 +67,7 @@ private:
 #if ENABLE_ROTATE_INPUT
     bool OnRotateEvent(const RotateEvent& event) override;
 #endif
+    void ClipImg(ImageInfo &img, float scale);
 };
 }
 #endif
index 2700337..4b333bd 100644 (file)
@@ -17,6 +17,7 @@
 #include "graphic_config.h"
 #include "dfx/dfx_dom_dump.h"
 #include "graphic_service.h"
+#include "hal_tick.h"
 #include "dfx/dfx_cmd.h"
 #if ENABLE_DFX_CMD
 #include <unistd.h>
 #include "components/ui_view.h"
 #include "common/screen.h"
 #include "dfx/fps_task.h"
-#include "dfx/ws_net_task.h"
 #include "engines/gfx/lite_m_gfx_engine.h"
 #include "gfx_utils/mem_check.h"
 #include "gfx_utils/image_info.h"
 #include "securec.h"
 #include "dfx/dfx_record.h"
 #include "dfx/dfx_frame_trace.h"
+#include "dfx/dfx_traceui.h"
 #include "common/low_power_manager.h"
 #include "common/image_cache_manager.h"
 #include "common/input_device_manager.h"
@@ -57,6 +58,7 @@ constexpr int DEFAULT_FILE_PERMISSION = 0666;
 char* g_filePath = nullptr;
 UIView* g_capView = nullptr;
 Rect g_cropRect{0, 0, 0, 0};
+uint8_t *g_traceuiBuf = nullptr;
 
 void DumpViewId(UIView* view)
 {
@@ -408,6 +410,31 @@ void ForceRefresh(int argc, char *argv[])
     }
 }
 
+void GetYuv2RgbTimeByUILiteSurfaceView(UILiteSurfaceView* surfaceView)
+{
+    ImageInfo info;
+    uint32_t startTime = HALTick::GetInstance().GetTime();
+    surfaceView->GetSurfaceBufferBitmap(info);
+    uint32_t elapseTime = HALTick::GetInstance().GetElapseTime(startTime);
+    printf("Yuv2Rgb cost time : %u ms\n", elapseTime);
+    ImageCacheFree(info);
+}
+
+void GetYuv2RgbTime(int argc, char *argv[])
+{
+    printf("=== Begin Get Yuv2Rgb Time ===\n");
+    GraphicService::GetInstance()->PostGraphicEvent([]() {
+        UILiteSurfaceView* targetView =
+         dynamic_cast<UILiteSurfaceView*>(LiteMGfxEngine::GetInstance()->GetHardwareLayer());
+        if (targetView != nullptr) {
+            GetYuv2RgbTimeByUILiteSurfaceView(targetView);
+        } else {
+            printf("No Video View!\n");
+        }
+        printf("=== Get Yuv2Rgb Time End===\n");
+    });
+}
+
 void HideFPS(int argc, char *argv[])
 {
     FPSTask::GetInstance()->HideFPS();
@@ -435,39 +462,20 @@ void PrintFPS(int argc, char *argv[])
     }
 }
 
-#if defined (THUNDERBIRD_TOYS)
-extern "C" void ShowWSNet(int argc, char *argv[])
+void SetFreq(int argc, char *argv[])
 {
-    if (argc == 0) {
-        WSNetTask::GetInstance()->ShowWSNet();
-        return;
-    }
-
-    if ((argc == 1) && (strcmp(argv[0], "-h") == 0)) {
-        printf("---GUI showws [-p] [position]---\n");
-        printf("   -h: help, GUI showws descriptions.\n");
-        printf("   -p: position, where ws/net info are shown on screen, eg. showws -p x,y\n");
+    if (argc != 1) {
+        printf("Invalid format!");
         return;
     }
 
-    if ((argc == 2) && (strcmp(argv[0], "-p") == 0)) { // 2: param num
-        uint16_t left = 0;
-        uint16_t top = 0;
-        char* temp = nullptr;
-        if (!ConvertToInt(strtok_r(argv[1], ",", &temp), left) ||
-            !ConvertToInt(strtok_r(nullptr, ",", &temp), top)) {
-            GRAPHIC_LOGE("Please input position in correct value: x,y");
-            return;
-        }
-        WSNetTask::GetInstance()->ShowWSNet(left, top);
+    uint16_t freq = 0;
+    if (ConvertToInt(argv[0], freq)) {
+        SetFrequence(freq);
+        printf("Set Frequence: %u", freq);
     }
 }
 
-extern "C" void HideWSNet(int argc, char *argv[])
-{
-    WSNetTask::GetInstance()->HideWSNet();
-}
-#endif
 #if defined (SUPPORT_DIAL_DEBUG)
 void PrintWatchDialInfo(const watch_dial_info &info)
 {
@@ -481,7 +489,6 @@ void PrintWatchDialInfo(const watch_dial_info &info)
 
 void DebugGetAllWatchFaceInfo(int argc, char *argv[])
 {
-    #ifdef FD230_650_0723
     GraphicService::GetInstance()->PostGraphicEvent([]() {
         watch_dial_info *info = nullptr;
         uint8_t num = 0;
@@ -495,7 +502,6 @@ void DebugGetAllWatchFaceInfo(int argc, char *argv[])
         }
         free(info);
     });
-    #endif
 }
 
 void DebugGetWatchFaceInfo(int argc, char *argv[])
@@ -584,7 +590,6 @@ void DebugUninstallWatch(int argc, char *argv[])
 
 void DebugGetUuidByPath(int argc, char *argv[])
 {
-    #ifdef FD230_650_0723
     if (argc != 1) {
         printf("fmt: AT^UIKIT_DFX=debug_get_uuid <num>\n");
         return;
@@ -605,7 +610,6 @@ void DebugGetUuidByPath(int argc, char *argv[])
         return;
     }
     printf("Succuss to get file %s, uuid %u\n", path.c_str(), uuid);
-    #endif
 }
 #endif // defined (SUPPORT_DIAL_DEBUG)
 
@@ -736,6 +740,71 @@ void InjectLongPressEvent(int argc, char *argv[])
     OHOS::EventInjector::GetInstance()->SetLongPressEvent(point);
 }
 #endif
+
+#if ENABLE_DFX_TRACEUI
+#define TRACEUI_RECORDING_DEFAULT_SIZE (128 * 1024)
+#define TRACEUI_OUTPUT_TRACE_PATH "/user/res/1.trace"
+
+/*
+ * argv[0]: size of recording.
+ */
+void TraceuiStart(int argc, char *argv[])
+{
+    uint32_t bufSize = TRACEUI_RECORDING_DEFAULT_SIZE;
+    g_traceuiBuf = static_cast<uint8_t *>(UIMalloc(bufSize));
+    if (g_traceuiBuf == NULL) {
+        printf("malloc(%d) error!\n", bufSize);
+        return;
+    }
+    if (argc >= 1) {
+        uint16_t kb;
+        if (ConvertToInt(argv[0], kb)) {
+            bufSize = kb * 1024; // 1024: 1kb
+        } else {
+            printf("Parsing record size filed! %s\n", argv[0]);
+            return;
+        }
+    }
+
+    printf("traceui begin (bufSize: %u) ...\n", bufSize);
+    if (!TraceuiRecordStart(TRACEUI_EVENTS_ALL, g_traceuiBuf, bufSize)) {
+        printf("traceui start error!\n");
+        return;
+    }
+}
+
+/*
+ * argv[0]: output path.
+ */
+void TraceuiStop(int argc, char *argv[])
+{
+    uint32_t size;
+    bool isSuccess;
+    const char *outPath = TRACEUI_OUTPUT_TRACE_PATH;
+    if (g_traceuiBuf == NULL) {
+        printf("traceui not start!\n");
+        return;
+    }
+    size = TraceuiRecordStop();
+    if (argc >= 1) {
+        outPath = argv[0];
+        int32_t fd = open(outPath, O_RDWR | O_CREAT, DEFAULT_FILE_PERMISSION);
+        if (fd < 0) {
+            printf("file path error, please stop again!\n");
+            return;
+        }
+        close(fd);
+    }
+
+    printf("record size: %u, start convert ...\n", size);
+    isSuccess = TraceuiConvertToPerfettoProto(g_traceuiBuf, size, outPath);
+    UIFree(reinterpret_cast<void*>(g_traceuiBuf));
+    g_traceuiBuf = NULL;
+    if (isSuccess) {
+        printf("traceui record success: %s\n", outPath);
+    }
+}
+#endif // ENABLE_DFX_TRACEUI
 }
 
 struct DfxCmd {
@@ -746,15 +815,13 @@ struct DfxCmd {
 struct DfxCmd g_dfxCmdList[] = {{"screencap", OHOS::ScreencapCmd},
     {"dump_view_id", OHOS::DumpViewIdCmd},
     {"dump_root_view", OHOS::DumpRootView},
+    {"setfreq", OHOS::SetFreq},
     {"printfps", OHOS::PrintFPS},
     {"hidefps", OHOS::HideFPS},
     {"showfps", OHOS::ShowFPS},
-#if defined (THUNDERBIRD_TOYS)
-    {"showws", OHOS::ShowWSNet},
-    {"hidews", OHOS::HideWSNet},
-#endif
     {"showtime", OHOS::ShowTime},
     {"refresh", OHOS::ForceRefresh},
+    {"get_yuv2rgb_time", OHOS::GetYuv2RgbTime},
 #if defined (SUPPORT_DIAL_DEBUG)
     {"debug_get_all", OHOS::DebugGetAllWatchFaceInfo},
     {"debug_get_watch", OHOS::DebugGetWatchFaceInfo},
@@ -777,7 +844,11 @@ struct DfxCmd g_dfxCmdList[] = {{"screencap", OHOS::ScreencapCmd},
     {"inject_key", OHOS::InjectKeyEvent},
     {"inject_click", OHOS::InjectClickEvent},
     {"inject_drag", OHOS::InjectDragEvent},
-    {"inject_lp", OHOS::InjectLongPressEvent}
+    {"inject_lp", OHOS::InjectLongPressEvent},
+#endif
+#if ENABLE_DFX_TRACEUI
+    {"traceui_start", OHOS::TraceuiStart},
+    {"traceui_stop", OHOS::TraceuiStop},
 #endif
 };
 
index d50f6a3..0aaee8f 100644 (file)
@@ -77,6 +77,7 @@ static const struct {
     {UI_MENU_ITEM, "UI_MENU_ITEM"},
     {UI_CARD_PAGE, "UI_CARD_PAGE"},
     {UI_COVER_FLOW, "UI_COVER_FLOW"},
+    {UI_FOLDABLE_VIEW, "UI_FOLDABLE_VIEW"},
     {UI_CROSS_VIEW, "UI_CROSS_VIEW"},
     {UI_BARCODE, "UI_BARCODE"},
     {UI_MAP_VIEW, "UI_MAP_VIEW"},
@@ -90,6 +91,12 @@ static const struct {
     {UI_COVER_FLOW_2, "UI_COVER_FLOW_2"},
     {UI_SPHERE_VIEW, "UI_SPHERE_VIEW"},
     {UI_PARTICLE_VIEW, "UI_PARTICLE_VIEW"},
+    {UI_OPTION_BOX, "UI_OPTION_BOX"},
+    {UI_CARD_CONTAINER, "UI_CARD_CONTAINER"},
+    {UI_VIDEO, "UI_VIDEO"},
+    {UI_LOTT_VIEW, "UI_LOTT_VIEW"},
+    {UI_FLOAT_BOX_VIEW, "UI_FLOAT_BOX_VIEW"},
+    {UI_TRANSFORM_BUTTON, "UI_TRANSFORM_BUTTON"},
     {UI_NUMBER_MAX, "UI_NUMBER_MAX"},
 };
 
index 3565fc5..2a11afe 100644 (file)
 #include "dfx/dfx_frame_trace.h"
 
 namespace OHOS {
-static struct {
-    FrameTraceType type;
-    std::string str;
-} g_type2string[] = {
-    {FrameTraceType::SW_DRAW_TRANSFORM, "sw_tran"},
-    {FrameTraceType::SW_DRAW_IMGBLIT, "sw_blit"},
-    {FrameTraceType::HW_DRAW_IMGBLIT, "hw_blit"},
-    {FrameTraceType::HW_DRAW_PATH, "hw_path"},
-    {FrameTraceType::HW_CLIP_IMGBYPATH, "hw_clip"},
-    {FrameTraceType::SW_DRAW_CUBICBEZIER, "sw_bezier"},
-    {FrameTraceType::SW_DRAW_RECT, "sw_rect"},
-    {FrameTraceType::HW_DRAW_RECT, "hw_rect"},
-    {FrameTraceType::HW_DRAW_BLUR, "hw_blur"},
-    {FrameTraceType::SW_DRAW_LETTER, "sw_letter"},
-    {FrameTraceType::SW_DRAW_ARC, "sw_arc"},
-    {FrameTraceType::SW_DRAW_LINE, "sw_line"},
-    {FrameTraceType::HW_DRAW_SUBMIT, "hw_submit"},
-    {FrameTraceType::HW_DRAW_FLUSH, "hw_flush"},
-    {FrameTraceType::HW_DRAW_WAIT, "hw_wait"},
-    {FrameTraceType::HW_DRAW_ARC_RECT, "hw_arc_rect"},
-    {FrameTraceType::HW_DRAW_LINE, "hw_line"},
-    {FrameTraceType::HW_DRAW_ARC, "hw_arc"},
-    {FrameTraceType::HW_DRAW_CUBICBEZIER, "hw_bezier"},
-    {FrameTraceType::HW_DRAW_ELLIPSE, "hw_ellipse"},
-};
-
 int DfxFrameTrace::evtCnt_ = 0;
 int DfxFrameTrace::tskCnt_ = 0;
 int DfxFrameTrace::frmCnt_ = 0;
 
+const char *DfxFrameTrace::DrawTypeToString(FrameTraceType type) const
+{
+    switch (type) {
+        case FrameTraceType::SW_DRAW_TRANSFORM: return "sw_tran";
+        case FrameTraceType::SW_DRAW_IMGBLIT: return "sw_blit";
+        case FrameTraceType::HW_DRAW_IMGBLIT: return "hw_blit";
+        case FrameTraceType::HW_DRAW_PATH: return "hw_path";
+        case FrameTraceType::HW_CLIP_IMGBYPATH: return "hw_clip";
+        case FrameTraceType::SW_DRAW_CUBICBEZIER: return "sw_bezier";
+        case FrameTraceType::SW_DRAW_RECT: return "sw_rect";
+        case FrameTraceType::HW_DRAW_RECT: return "hw_rect";
+        case FrameTraceType::HW_DRAW_BLUR: return "hw_blur";
+        case FrameTraceType::SW_DRAW_LETTER: return "sw_letter";
+        case FrameTraceType::SW_DRAW_ARC: return "sw_arc";
+        case FrameTraceType::SW_DRAW_LINE: return "sw_line";
+        case FrameTraceType::HW_DRAW_SUBMIT: return "hw_submit";
+        case FrameTraceType::HW_DRAW_FLUSH: return "hw_flush";
+        case FrameTraceType::HW_DRAW_WAIT: return "hw_wait";
+        case FrameTraceType::HW_DRAW_ARC_RECT: return "hw_arc_rect";
+        case FrameTraceType::HW_DRAW_LINE: return "hw_line";
+        case FrameTraceType::HW_DRAW_ARC: return "hw_arc";
+        case FrameTraceType::HW_DRAW_CUBICBEZIER: return "hw_bezier";
+        case FrameTraceType::HW_DRAW_ELLIPSE: return "hw_ellipse";
+        default: break;
+    }
+    return "hw_unknown";
+}
+
+const char *DfxFrameTrace::PathAttrToString(FrameTracePathAttr attr) const
+{
+    switch (attr) {
+        case FrameTracePathAttr::NONE: return "";
+        case FrameTracePathAttr::FILL: return "fill";
+        case FrameTracePathAttr::STROKE: return "stroke";
+        case FrameTracePathAttr::BOTH: return "both";
+        default: break;
+    }
+    return "unknown";
+}
+
 uint64_t DfxFrameTrace::GetDuration(uint64_t start, uint64_t end) const
 {
     uint64_t dur = end >= start ? end - start : UINT64_MAX - start + end + 1;
@@ -59,13 +73,16 @@ DfxFrameTrace& DfxFrameTrace::GetInstance()
     return dfx;
 }
 
-void DfxFrameTrace::SetPathType(FrameTraceType type)
+void DfxFrameTrace::SetPathType(FrameTraceType type, FrameTracePathAttr attr)
 {
     pathType_ = type;
+    pathAttr_ = attr;
+    TRACEUI_LOG("PathType:%s %s", DrawTypeToString(type), PathAttrToString(attr));
 }
 
 void DfxFrameTrace::FrameTraceStart(FrameTraceType type)
 {
+    TRACEUI_BEGIN(DrawTypeToString(type));
     if (!CanTrace()) {
         return;
     }
@@ -80,6 +97,7 @@ void DfxFrameTrace::FrameTraceStart(FrameTraceType type)
 
 void DfxFrameTrace::FrameTraceEnd(FrameTraceType type, const Rect *rect)
 {
+    TRACEUI_END();
     if (!CanTrace()) {
         return;
     }
@@ -91,6 +109,7 @@ void DfxFrameTrace::FrameTraceEnd(FrameTraceType type, const Rect *rect)
     if (type == FrameTraceType::HW_DRAW_PATH) {
         type = pathType_;
         pathType_ = FrameTraceType::HW_DRAW_PATH;
+        pathAttr_ = FrameTracePathAttr::NONE;
     }
     RecordEnd(type, rect);
 }
@@ -100,7 +119,11 @@ void DfxFrameTrace::RecordStart(FrameTraceType type)
     startTime_ = uapi_tcxo_get_us();
     uint64_t preTime = 0;
     if (drawCount_ == 0) {
-        preTime = 0;
+        if (tailEvt_ != nullptr && tailEvt_->tailTsk != nullptr) {
+            preTime = GetDuration(tailEvt_->tailTsk->startTime, startTime_);
+        } else {
+            preTime = 0;
+        }
         firstDrawTime_ = startTime_;
     } else {
         preTime = GetDuration(endTime_, startTime_);
@@ -109,14 +132,18 @@ void DfxFrameTrace::RecordStart(FrameTraceType type)
     if (type == FrameTraceType::HW_DRAW_PATH) {
         if (pathIndex_ == -1) {
             pathIndex_ = drawCount_;
+            trace_[pathIndex_].cmd = type;
+            trace_[pathIndex_].preTime = 0;
+            trace_[pathIndex_].costTime = 0;
             ++drawCount_;
         }
-        trace_[pathIndex_].cmd = type;
         trace_[pathIndex_].preTime += preTime;
+        pathAttrs_[pathIndex_] = FrameTracePathAttr::NONE;
         return;
     }
     trace_[drawCount_].cmd = type;
     trace_[drawCount_].preTime = preTime;
+    pathAttrs_[drawCount_] = pathAttr_;
 }
 
 void DfxFrameTrace::RecordEnd(FrameTraceType type, const Rect *rect)
@@ -143,7 +170,7 @@ void DfxFrameTrace::ShowFrameTrace()
         return;
     }
 
-    if (events_ == nullptr || !eventRecording_ || !taskRecording_) {
+    if (events_ == nullptr || !eventRecording_ || !taskRecording_ || drawCount_ <= 0) {
         return;
     }
     EventRecord &curEvt = *tailEvt_;
@@ -162,7 +189,6 @@ void DfxFrameTrace::ShowFrameTrace()
 
 void DfxFrameTrace::ClearState()
 {
-    memset_s(trace_, sizeof(trace_), 0, sizeof(trace_));
     drawRect_ = Rect();
     drawCount_ = 0;
     drawStack_ = 0;
@@ -174,17 +200,9 @@ void DfxFrameTrace::ClearState()
     pathIndex_ = -1;
     freq_ = 0;
     isNativeRunning_ = 0;
-}
-
-std::string DfxFrameTrace::ToString(FrameTraceType type) const
-{
-    constexpr int size = sizeof(g_type2string) / sizeof(g_type2string[0]);
-    for (int i = 0; i < size; ++i) {
-        if (g_type2string[i].type == type) {
-            return g_type2string[i].str;
-        }
-    }
-    return "";
+    pathType_ = FrameTraceType::HW_DRAW_PATH;
+    pathAttr_ = FrameTracePathAttr::NONE;
+    isSram_ = true;
 }
 
 void DfxFrameTrace::WriteFrameRecord(FrameRecord *frame) const
@@ -198,18 +216,21 @@ void DfxFrameTrace::WriteFrameRecord(FrameRecord *frame) const
     frame->freq = freq_;
     frame->pathCnt = pathCnt_;
     frame->drawRect = drawRect_;
+    frame->isSram = isSram_;
     if (drawCount_ <= 0) {
         return;
     }
     frame->drawCount = drawCount_;
     frame->trace = new (std::nothrow) FrameTrace[drawCount_];
     frame->rect = new (std::nothrow) Rect[drawCount_];
-    if (frame->trace == nullptr || frame->rect == nullptr) {
+    frame->attr = new (std::nothrow) FrameTracePathAttr[drawCount_];
+    if (frame->trace == nullptr || frame->rect == nullptr || frame->attr == nullptr) {
         return;
     }
     for (int i = 0; i < drawCount_; ++i) {
         frame->trace[i] = trace_[i];
         frame->rect[i] = rect_[i];
+        frame->attr[i] = pathAttrs_[i];
     }
 }
 
@@ -227,25 +248,39 @@ void DfxFrameTrace::ShowFrameRecord(FrameRecord *frame) const
     }
     for (int32_t i = 0; i < drawCnt; ++i) {
         if (frame->trace[i].cmd == FrameTraceType::HW_DRAW_PATH) {
-            printf("  %d. %s: %llu, %llu, %d\n",
-                i, ToString(frame->trace[i].cmd).c_str(),
+            printf("  %d. %s: %llu, %llu, %d",
+                i, DrawTypeToString(frame->trace[i].cmd),
                 frame->trace[i].preTime, frame->trace[i].costTime, frame->pathCnt);
-            continue;
-        }
-        if (frame->trace[i].cmd == FrameTraceType::HW_DRAW_SUBMIT) {
-            printf("  %d. %s: %llu, %llu, %d\n",
-                i, ToString(frame->trace[i].cmd).c_str(),
+        } else if (frame->trace[i].cmd == FrameTraceType::HW_DRAW_SUBMIT) {
+            printf("  %d. %s: %llu, %llu, %d",
+                i, DrawTypeToString(frame->trace[i].cmd),
                 frame->trace[i].preTime, frame->trace[i].costTime, frame->trace[i].isNeedWait);
-            continue;
-        }
-        if (!frame->rect[i].IsValid()) {
-            printf("  %d. %s: %llu, %llu\n", i, ToString(frame->trace[i].cmd).c_str(),
+        } else if (frame->trace[i].cmd == FrameTraceType::HW_DRAW_IMGBLIT) {
+            printf("  %d. %s: %llu, %llu, %d", i, DrawTypeToString(frame->trace[i].cmd),
+                frame->trace[i].preTime, frame->trace[i].costTime, frame->rect[i].GetLeft());
+        } else if (!frame->rect[i].IsValid()) {
+            printf("  %d. %s: %llu, %llu", i, DrawTypeToString(frame->trace[i].cmd),
                 frame->trace[i].preTime, frame->trace[i].costTime);
-            continue;
+        } else {
+            printf("  %d. %s: %llu, %llu, {%d, %d, %d, %d}",
+                i, DrawTypeToString(frame->trace[i].cmd), frame->trace[i].preTime, frame->trace[i].costTime,
+                frame->rect[i].GetLeft(),
+                frame->rect[i].GetTop(), frame->rect[i].GetRight(), frame->rect[i].GetBottom());
+        }
+
+        if (frame->trace[i].cmd == FrameTraceType::HW_DRAW_FLUSH) {
+            if (frame->isSram) {
+                printf(", s");
+            } else {
+                printf(", p");
+            }
+        }
+
+        if (frame->attr[i] == FrameTracePathAttr::NONE) {
+            printf("\n");
+        } else {
+            printf(", %s\n", PathAttrToString(frame->attr[i]));
         }
-        printf("  %d. %s: %llu, %llu, {%d, %d, %d, %d}\n",
-            i, ToString(frame->trace[i].cmd).c_str(), frame->trace[i].preTime, frame->trace[i].costTime,
-            frame->rect[i].GetLeft(), frame->rect[i].GetTop(), frame->rect[i].GetRight(), frame->rect[i].GetBottom());
     }
 }
 
@@ -297,6 +332,7 @@ void DfxFrameTrace::ClearEvents()
 
 void DfxFrameTrace::EventTraceStart()
 {
+    TRACEUI_BEGIN("GraphicEvent");
     if (traceCount_ <= 0) {
         return;
     }
@@ -316,6 +352,7 @@ void DfxFrameTrace::EventTraceStart()
 
 void DfxFrameTrace::EventTraceEnd()
 {
+    TRACEUI_END();
     if (events_ == nullptr || !eventRecording_) {
         return;
     }
@@ -330,6 +367,7 @@ void DfxFrameTrace::EventTraceEnd()
 
 void DfxFrameTrace::TaskTraceStart()
 {
+    TRACEUI_BEGIN("TaskExecute");
     if (events_ == nullptr || !eventRecording_) {
         return;
     }
@@ -350,6 +388,7 @@ void DfxFrameTrace::TaskTraceStart()
 
 void DfxFrameTrace::TaskTraceEnd()
 {
+    TRACEUI_END();
     if (events_ == nullptr || !eventRecording_ || !taskRecording_) {
         return;
     }
index b91c590..83dc8b5 100644 (file)
@@ -35,6 +35,13 @@ static constexpr uint32_t PRINT_TIME_PERIOD = 1000; // in ms
 static constexpr uint32_t SHOW_TIME_PERIOD = 1000; // in ms
 static constexpr uint32_t MILLESECOND_PER_SECOND = 1000; // in ms
 
+FPSTask::FPSTask()
+{
+    uint32_t minPeriod = MATH_MIN(PRINT_TIME_PERIOD, SHOW_TIME_PERIOD);
+    SetPeriod(minPeriod);
+    Init();
+}
+
 void FPSTask::Callback()
 {
     static uint16_t lastFps = 0;
@@ -44,7 +51,7 @@ void FPSTask::Callback()
             return;
         }
         // always ensure that fpsLabel is on the top
-        if (RootView::GetInstance()->GetChildrenTail() != fpsLabel_) {
+        if (fpsLabel_ != RootView::GetInstance()->GetAppView()->GetChildrenTail()) {
             if (isAdded_) {
                 RootView::GetInstance()->Remove(fpsLabel_);
             }
index 901a155..3c497c1 100644 (file)
@@ -28,7 +28,6 @@ public:
     static FPSTask *GetInstance()
     {
         static FPSTask instance;
-        instance.Init();
         return &instance;
     }
 
@@ -38,6 +37,8 @@ public:
     void PrintFPS(uint16_t duration = 0);
 
 private:
+    FPSTask();
+    ~FPSTask() {}
     UILabel *fpsLabel_ = nullptr;
     bool isFirstShow_ = true;
     bool isAdded_ = false;
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_buf.c b/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_buf.c
new file mode 100644 (file)
index 0000000..98ac160
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: traceui buffer manager implementation
+ * Author: Hisi Graphic Team
+ * Created: 2025-9
+ */
+
+#include "los_typedef.h"
+#include "los_memory.h"
+#include "los_spinlock.h"
+#include "traceui_buf.h"
+
+static uint8_t *g_traceBuf = NULL;
+static uint32_t g_traceBufPos = 0;
+static uint32_t g_traceBufSize = 0;
+
+LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_traceuiSpin);
+
+void TraceuiBufInit(uint8_t *buf, uint32_t size)
+{
+    uint32_t irqState;
+
+    LOS_SpinLockSave(&g_traceuiSpin, &irqState);
+    g_traceBuf = buf;
+    g_traceBufPos = 0;
+    g_traceBufSize = size;
+    LOS_SpinUnlockRestore(&g_traceuiSpin, irqState);
+}
+
+uint8_t *TraceuiGetBuf(uint32_t len)
+{
+    uint32_t irqState;
+    uint8_t *retBuf = NULL;
+
+    LOS_SpinLockSave(&g_traceuiSpin, &irqState);
+    if (g_traceBufPos + len <= g_traceBufSize) {
+        retBuf = &g_traceBuf[g_traceBufPos];
+        g_traceBufPos += len;
+    }
+    LOS_SpinUnlockRestore(&g_traceuiSpin, irqState);
+    return retBuf;
+}
+
+uint32_t TraceuiGetBufUsedSize(void)
+{
+    return g_traceBufPos;
+}
+
+void TraceuiBufDeinit(void)
+{
+    uint32_t irqState;
+
+    LOS_SpinLockSave(&g_traceuiSpin, &irqState);
+    g_traceBuf = NULL;
+    g_traceBufPos = 0;
+    g_traceBufSize = 0;
+    LOS_SpinUnlockRestore(&g_traceuiSpin, irqState);
+}
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_buf.h b/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_buf.h
new file mode 100644 (file)
index 0000000..ccde642
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: traceui buffer manager interface
+ * Author: Hisi Graphic Team
+ * Created: 2025-9
+ */
+
+#ifndef TRACEUI_BUF_H
+#define TRACEUI_BUF_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void TraceuiBufInit(uint8_t *buf, uint32_t size);
+void TraceuiBufDeinit(void);
+
+uint8_t *TraceuiGetBuf(uint32_t len);
+uint32_t TraceuiGetBufUsedSize(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_convert_perfetto_proto.c b/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_convert_perfetto_proto.c
new file mode 100644 (file)
index 0000000..ac1abc1
--- /dev/null
@@ -0,0 +1,923 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: traceui frame convert to perfetto protobuf trace implementation
+ * Author: Hisi Graphic Team
+ * Created: 2025-9
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "securec.h"
+#include "traceui_os.h"
+#include "traceui_core.h"
+
+/*
+ * Perfetto UI use PID 0 for idle task, but liteos not.
+ * So need convert liteos all pid = pid + PERFETTO_PID_INC,
+ * and liteos idle task id force convert to 0
+ */
+#define PERFETTO_PID_INC      10000
+#define PACKET_LEN_SIZE       2 // define protobuf max packet len use 2 * (8 - 1) = 14bit
+#define MAX_ENC_BUF_SIZE      (TRACEUI_FRAME_LEN_MAX * 2) // alloc buffer size for encode trace
+
+// protobuf wire type, reference: https://protobuf.dev/programming-guides/encoding/#structure
+typedef enum {
+    WIRE_VARINT = 0, // int32, int64, uint32, uint64, sint32, sint64, bool, enum
+    WIRE_I64    = 1, // fixed64, sfixed64, double
+    WIRE_LEN    = 2, // string, bytes, embedded messages, packed repeated fields
+    WIRE_SGROUP = 3, // group start (deprecated)
+    WIRE_EGROUP = 4, // group end (deprecated)
+    WIRE_I32    = 5, // fixed32, sfixed32, float
+} WireType;
+
+// reference: external/perfetto/src/trace_processor/types/task_state.h
+typedef enum {
+    TASK_STATE_RUNNABLE = 0,
+    TASK_STATE_INTERRUPTIBLE_SLEEP = 1,
+    TASK_STATE_UNINTERRUPTIBLE_SLEEP = 2,
+    TASK_STATE_STOPED = 4,
+    TASK_STATE_TRACED = 8,
+    TASK_STATE_EXIT_DEAD = 16,
+    TASK_STATE_EXIT_ZOMBIE = 32,
+    TASK_STATE_TASK_DEAD = 64,
+    TASK_STATE_WAKE_KILL = 128,
+    TASK_STATE_WAKING = 256,
+    TASK_STATE_PARKED = 512,
+    TASK_STATE_NO_LOAD = 1024,
+    TASK_STATE_TASK_NEW = 2048,
+    TASK_STATE_RUN_PLUS = 4096, // guess
+    TASK_STATE_VALID = 0x8000,
+} TaskStateId;
+
+// perfetto proto struct. reference android code: external/perfetto/protos/perfetto/trace/perfetto_trace.proto
+typedef enum {
+    FTRACE_EVENT_PRINT_BUF  = 2,
+} PrintFtraceEventId;
+
+typedef struct {
+    const char *buf; // FTRACE_EVENT_PRINT_BUF
+} PrintFtraceEvent;
+
+typedef enum {
+    SCHED_SWITCH_PREV_COMM  = 1, // string
+    SCHED_SWITCH_PREV_PID   = 2, // int32
+    SCHED_SWITCH_PREV_PRIO  = 3, // int32
+    SCHED_SWITCH_PREV_STATE = 4, // int64
+    SCHED_SWITCH_NEXT_COMM  = 5, // string
+    SCHED_SWITCH_NEXT_PID   = 6, // int32
+    SCHED_SWITCH_NEXT_PRIO  = 7, // int32
+} SchedSwitchFtraceEventId;
+
+typedef struct {
+    const char *prevComm;
+    int32_t prevPid;
+    int32_t prevPrio;
+    int64_t prevState;
+    const char *nextComm;
+    int32_t nextPid;
+    int32_t nextPrio;
+} SchedSwitchFtraceEvent;
+
+typedef enum {
+    SCHED_WAKING_COMM       = 1,
+    SCHED_WAKING_PID        = 2,
+    SCHED_WAKING_PRIO       = 3,
+    SCHED_WAKING_SUCCESS    = 4,
+    SCHED_WAKING_TARGET_CPU = 5,
+} SchedWakingFtraceEventId;
+
+typedef struct {
+    const char *comm;
+    int32_t pid;
+    int32_t prio;
+    int32_t success;
+    int32_t targetCpu;
+} SchedWakingFtraceEvent;
+
+typedef enum {
+    IRQ_HANDLER_ENTRY_IRQ   = 1,
+    IRQ_HANDLER_ENTRY_NAME  = 2,
+} IrqHandlerEntryFtraceEventId;
+
+typedef struct {
+    int32_t irq; // IRQ_HANDLER_ENTRY_IRQ
+    const char *name; // IRQ_HANDLER_ENTRY_NAME
+} IrqHandlerEntryFtraceEvent;
+
+typedef enum {
+    IRQ_HANDLER_EXIT_IRQ     = 1,
+    IRQ_HANDLER_EXIT_RET     = 2,
+} IrqHandlerExitFtraceEventId;
+
+typedef struct {
+    int32_t irq; // IRQ_HANDLER_EXIT_IRQ
+    int32_t ret; // IRQ_HANDLER_EXIT_RET
+} IrqHandlerExitFtraceEvent;
+
+typedef enum {
+    FTRACE_EVENT_TIMESTAMP         = 1,
+    FTRACE_EVENT_PID               = 2,
+    FTRACE_EVENT_PRINT             = 3,
+    FTRACE_EVENT_SCHED_SWITCH      = 4,
+    FTRACE_EVENT_SCHED_WAKING      = 20,
+    FTRACE_EVENT_IRQ_HANDLER_ENTRY = 36,
+    FTRACE_EVENT_IRQ_HANDLER_EXIT  = 37,
+} FtraceEventId;
+
+typedef struct {
+    uint64_t timestamp; // FTRACE_EVENT_TIMESTAMP
+    uint32_t pid; // FTRACE_EVENT_PID
+    FtraceEventId eventType;
+    union {
+        PrintFtraceEvent print; // FTRACE_EVENT_PRINT
+        SchedSwitchFtraceEvent schedSwitch; // FTRACE_EVENT_SCHED_SWITCH
+        SchedWakingFtraceEvent schedWaking; // FTRACE_EVENT_SCHED_WAKING
+        IrqHandlerEntryFtraceEvent irqEntry; // FTRACE_EVENT_IRQ_HANDLER_ENTRY
+        IrqHandlerExitFtraceEvent irqExit; // FTRACE_EVENT_IRQ_HANDLER_EXIT
+    };
+} FtraceEvent;
+
+typedef enum {
+    FTRACE_EVENT_BUNDLE_CPU   = 1,
+    FTRACE_EVENT              = 2,
+} FtraceEventBundleId;
+
+typedef struct {
+    uint32_t cpu; // FTRACE_EVENT_BUNDLE_CPU
+    FtraceEvent event; // FTRACE_EVENT
+} FtraceEventBundle;
+
+typedef enum {
+    CLOCK_SNAPSHOT_CLOCK_ID        = 1,
+    CLOCK_SNAPSHOT_CLOCK_TIMESTAMP = 2,
+} ClockSnapshotClockId;
+
+typedef struct {
+    uint32_t clockId; // CLOCK_SNAPSHOT_CLOCK_ID
+    uint64_t timestamp; // CLOCK_SNAPSHOT_CLOCK_TIMESTAMP
+} ClockSnapshotClock; // message Clock
+
+typedef enum {
+    BUILTIN_CLOCK_REALTIME         = 1,
+    BUILTIN_CLOCK_REALTIME_COARSE  = 2,
+    BUILTIN_CLOCK_MONOTONIC        = 3,
+    BUILTIN_CLOCK_MONOTONIC_COARSE = 4,
+    BUILTIN_CLOCK_MONOTONIC_RAW    = 5,
+    BUILTIN_CLOCK_BOOT_TIME        = 6,
+    BUILTIN_CLOCK_MAX
+} BuiltinClockId;
+
+typedef enum {
+    CLOCK_SNAPSHOT_CLOCK          = 1,
+    CLOCK_SNAPSHOT_BUILTIN_CLOCK  = 2,
+} ClockSnapshotId;
+
+typedef struct {
+    uint32_t clockNum;
+    ClockSnapshotClock *clock; // CLOCK_SNAPSHOT_CLOCK
+    BuiltinClockId primaryTraceClock ; // CLOCK_SNAPSHOT_BUILTIN_CLOCK
+} ClockSnapshot;
+
+typedef enum {
+    LID_DEFAULT  = 0,
+    LID_RADIO    = 1,
+    LID_EVENTS   = 2,
+    LID_SYSTEM   = 3,
+    LID_CRASH    = 4,
+    LID_STATS    = 5,
+    LID_SECURITY = 6,
+    LID_KERNEL   = 7,
+} ALogId;
+
+typedef enum {
+    PRIO_UNSPECIFIED = 0,
+    PRIO_UNUSED = 1,
+    PRIO_VERBOSE = 2,
+    PRIO_DEBUG = 3,
+    PRIO_INFO = 4,
+    PRIO_WARN = 5,
+    PRIO_ERROR = 6,
+    PRIO_FATAL = 7,
+} ALogPriority;
+
+typedef enum {
+    ALOG_EVENT_LOG_ID        = 1,
+    ALOG_EVENT_PID           = 2,
+    ALOG_EVENT_TID           = 3,
+    ALOG_EVENT_UID           = 4,
+    ALOG_EVENT_TIMESTAMP     = 5,
+    ALOG_EVENT_TAG           = 6,
+    ALOG_EVENT_PRIORITY      = 7,
+    ALOG_EVENT_EVENT_MESSAGE = 8,
+} ALogEventId; // perfetto_trace.proto: message LogEvent
+
+typedef struct {
+    ALogId logId; // ALOG_EVENT_LOG_ID
+    int32_t pid; // ALOG_EVENT_PID
+    int32_t tid; // ALOG_EVENT_TID
+    int32_t uid; // ALOG_EVENT_UID
+    uint64_t timestamp; // ALOG_EVENT_TIMESTAMP
+    const char *tag; // ALOG_EVENT_TAG
+    ALogPriority prio; // ALOG_EVENT_PRIORITY
+    const char *message; // ALOG_EVENT_EVENT_MESSAGE
+} ALogEvent;
+
+typedef enum {
+    ALOG_STATS_NUM_TOTAL   = 1,
+    ALOG_STATS_NUM_FAILED  = 2,
+    ALOG_STATS_NUM_SKIPPED = 3,
+} ALogStatsId;
+
+typedef struct {
+    uint64_t numTotal;
+    uint64_t numFailed;
+    uint64_t numSkipped;
+} ALogStats;
+
+typedef enum {
+    ALOG_EVENT       = 1,
+    ALOG_STATS       = 2,
+} ALogPacketId;
+
+typedef struct {
+    ALogPacketId type;
+    union {
+        ALogEvent events; // ALOG_EVENT
+        ALogStats stats; // ALOG_STATS
+    };
+} ALogPacket;
+
+typedef enum {
+    FTRACE_EVENT_BUNDLE          = 1,
+    CLOCK_SNAPSHOT               = 6,
+    ALOG_PACKET                  = 39,
+} TracePacketId;
+
+typedef struct {
+    TracePacketId packetType;
+    union {
+        FtraceEventBundle ftraceEvents; // FTRACE_EVENT_BUNDLE
+        ClockSnapshot clockSnapshot; // CLOCK_SNAPSHOT
+        ALogPacket log; // ALOG_PACKET
+    };
+} TracePacket;
+
+typedef enum {
+    TRACE_PACKET = 1,
+} TraceId;
+
+typedef struct {
+    TracePacket packet; // TRACE_PACKET
+} Trace;
+
+typedef struct {
+    uint8_t *buf;
+    uint32_t len; // unused buffer len, 0 <= len <= size
+    uint32_t size; // buffer size
+} Buffer;
+
+static uint32_t g_logCount; // all successed log count of TRACEUI_EVENT_LOG
+static uint32_t g_traceTimeOffset = 0;
+static bool g_isEncodeError;
+static Buffer g_encTmpBuf; // avoid exceed the stack size
+
+#ifndef UNUSED
+#define UNUSED(x) (void)(x)
+#endif
+
+// return used buf size
+static uint32_t EncodeVarint(uint64_t value, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    uint64_t tmp = value;
+    while (tmp > 0x7F && i + 1 < bufSize) {
+        buf[i] = (uint8_t)((tmp & 0x7F) | 0x80);
+        tmp >>= 7; // 7: varint only use low 7 bit for value
+        i++;
+    }
+    if (tmp > 0x7F || i + 1 >= bufSize) {
+        TRACEUI_ERR("buf too small!\n");
+        g_isEncodeError = true;
+        return 0;
+    }
+    buf[i] = (uint8_t)(tmp & 0x7F);
+    i++;
+    return i;
+}
+
+// return used buf size
+static uint32_t EncodeVarintFixedSize(uint64_t value, uint8_t *buf, uint32_t bufSize, uint32_t typeSize)
+{
+    uint32_t i = 0;
+    uint64_t tmp = value;
+
+    if (typeSize > bufSize) {
+        TRACEUI_ERR("buf too small!\n");
+        g_isEncodeError = true;
+        return 0;
+    }
+    while (i + 1 < typeSize) {
+        buf[i] = (uint8_t)((tmp & 0x7F) | 0x80);
+        i++;
+        tmp >>= 7; // 7: varint only use low 7 bit for value
+    }
+    if (tmp > 0x7F) {
+        TRACEUI_ERR("varint error! value %llu > fixed size: %u\n", (unsigned long long)tmp, typeSize);
+        g_isEncodeError = true;
+        return 0;
+    }
+    buf[i] = (uint8_t)(tmp & 0x7F);
+    i++;
+    return i;
+}
+
+// proto use TLV(Tag-Length-Value) format
+static inline uint32_t EncodeTag(uint32_t field, WireType wireType, uint8_t *buf, uint32_t size)
+{
+    return EncodeVarint((field << 3) | wireType, buf, size); // 3: std message structure defined
+}
+
+/*
+ * reference: https://protobuf.dev/programming-guides/proto2/#scalar
+ * ProtoType  WireType
+ * double     WIRE_I64
+ * float      WIRE_I32
+ * int32      WIRE_VARINT
+ * int64      WIRE_VARINT
+ * uint32     WIRE_VARINT
+ * uint64     WIRE_VARINT
+ * sint32     WIRE_VARINT + ZigZag
+ * sint64     WIRE_VARINT + ZigZag
+ * fixed32    WIRE_I32
+ * fixed64    WIRE_I64
+ * sfixed32   WIRE_I32
+ * sfixed64   WIRE_I64
+ * bool       WIRE_VARINT
+ * string     WIRE_LEN
+ * bytes      WIRE_LEN
+ */
+static inline uint32_t EncodeTagUint(uint32_t field, uint64_t value, uint8_t *buf, uint32_t size)
+{
+    uint32_t i = 0;
+    i += EncodeTag(field, WIRE_VARINT, &buf[i], size - i);
+    i += EncodeVarint(value, &buf[i], size - i);
+    return g_isEncodeError ? 0 : i;
+}
+
+static inline uint32_t EncodeTagString(uint32_t field, const char *str, uint8_t *buf, uint32_t size)
+{
+    uint32_t strLen;
+    uint32_t i = 0;
+
+    i += EncodeTag(field, WIRE_LEN, &buf[i], size - i);
+    strLen = strlen(str);
+    i += EncodeVarint(strLen, &buf[i], size - i);
+    if (memcpy_s(&buf[i], size - i, str, strLen) != EOK) {
+        g_isEncodeError = true;
+    }
+    i += strLen;
+    return g_isEncodeError ? 0 : i;
+}
+
+typedef uint32_t (*EncodeFn)(uintptr_t msg, uint8_t *buf, uint32_t bufSize);
+static inline uint32_t EncodeTagMessage(uint32_t field, EncodeFn fn, uintptr_t msg, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    uint32_t lenOffset;
+    uint32_t len;
+
+    i += EncodeTag(field, WIRE_LEN, &buf[i], bufSize - i);
+
+    // set len for place holder
+    lenOffset = i;
+    i += EncodeVarintFixedSize(0, &buf[lenOffset], bufSize - lenOffset, PACKET_LEN_SIZE);
+
+    // call message process function
+    len = fn(msg, &buf[i], bufSize - i);
+    i += len;
+
+    // reset len
+    EncodeVarintFixedSize(len, &buf[lenOffset], bufSize - lenOffset, PACKET_LEN_SIZE);
+    return g_isEncodeError ? 0 : i;
+}
+
+static uint32_t EncodePrintFtraceEvent(const PrintFtraceEvent *t, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    i += EncodeTagString(FTRACE_EVENT_PRINT_BUF, t->buf, &buf[i], bufSize - i);
+    return i;
+}
+
+static uint32_t EncodeSchedSwitchFtraceEvent(const SchedSwitchFtraceEvent *t, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    i += EncodeTagString(SCHED_SWITCH_PREV_COMM, t->prevComm, &buf[i], bufSize - i);
+    i += EncodeTagUint(SCHED_SWITCH_PREV_PID, t->prevPid, &buf[i], bufSize - i);
+    i += EncodeTagUint(SCHED_SWITCH_PREV_PRIO, t->prevPrio, &buf[i], bufSize - i);
+    i += EncodeTagUint(SCHED_SWITCH_PREV_STATE, t->prevState, &buf[i], bufSize - i);
+    i += EncodeTagString(SCHED_SWITCH_NEXT_COMM, t->nextComm, &buf[i], bufSize - i);
+    i += EncodeTagUint(SCHED_SWITCH_NEXT_PID, t->nextPid, &buf[i], bufSize - i);
+    i += EncodeTagUint(SCHED_SWITCH_NEXT_PRIO, t->nextPrio, &buf[i], bufSize - i);
+    return i;
+}
+
+static uint32_t EncodeSchedWakingFtraceEvent(const SchedWakingFtraceEvent *t, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    i += EncodeTagString(SCHED_WAKING_COMM, t->comm, &buf[i], bufSize - i);
+    i += EncodeTagUint(SCHED_WAKING_PID, t->pid, &buf[i], bufSize - i);
+    i += EncodeTagUint(SCHED_WAKING_PRIO, t->prio, &buf[i], bufSize - i);
+    i += EncodeTagUint(SCHED_WAKING_SUCCESS, t->success, &buf[i], bufSize - i);
+    i += EncodeTagUint(SCHED_WAKING_TARGET_CPU, t->targetCpu, &buf[i], bufSize - i);
+    return i;
+}
+
+static uint32_t EncodeIrqEntryFtraceEvent(const IrqHandlerEntryFtraceEvent *t, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    i += EncodeTagUint(IRQ_HANDLER_ENTRY_IRQ, t->irq, &buf[i], bufSize - i);
+    i += EncodeTagString(IRQ_HANDLER_ENTRY_NAME, t->name, &buf[i], bufSize - i);
+    return i;
+}
+
+static uint32_t EncodeIrqExitFtraceEvent(const IrqHandlerExitFtraceEvent *t, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    i += EncodeTagUint(IRQ_HANDLER_EXIT_IRQ, t->irq, &buf[i], bufSize - i);
+    i += EncodeTagUint(IRQ_HANDLER_EXIT_RET, t->ret, &buf[i], bufSize - i);
+    return i;
+}
+
+static uint32_t EncodeFtraceEvent(const FtraceEvent *t, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    i += EncodeTagUint(FTRACE_EVENT_TIMESTAMP, t->timestamp, &buf[i], bufSize - i);
+    i += EncodeTagUint(FTRACE_EVENT_PID, t->pid, &buf[i], bufSize - i);
+    if (t->eventType == FTRACE_EVENT_PRINT) {
+        i += EncodeTagMessage(t->eventType, (EncodeFn)EncodePrintFtraceEvent, (uintptr_t)&t->print,
+                              &buf[i], bufSize - i);
+    } else if (t->eventType == FTRACE_EVENT_SCHED_SWITCH) {
+        i += EncodeTagMessage(t->eventType, (EncodeFn)EncodeSchedSwitchFtraceEvent, (uintptr_t)&t->schedSwitch,
+                              &buf[i], bufSize - i);
+    } else if (t->eventType == FTRACE_EVENT_SCHED_WAKING) {
+        i += EncodeTagMessage(t->eventType, (EncodeFn)EncodeSchedWakingFtraceEvent, (uintptr_t)&t->schedWaking,
+                              &buf[i], bufSize - i);
+    } else if (t->eventType == FTRACE_EVENT_IRQ_HANDLER_ENTRY) {
+        i += EncodeTagMessage(t->eventType, (EncodeFn)EncodeIrqEntryFtraceEvent, (uintptr_t)&t->irqEntry,
+                              &buf[i], bufSize - i);
+    } else if (t->eventType == FTRACE_EVENT_IRQ_HANDLER_EXIT) {
+        i += EncodeTagMessage(t->eventType, (EncodeFn)EncodeIrqExitFtraceEvent, (uintptr_t)&t->irqExit,
+                              &buf[i], bufSize - i);
+    } else {
+        TRACEUI_ERR("unsupport ftrace type: %d\n", t->eventType);
+        g_isEncodeError = true;
+        return 0;
+    }
+    return i;
+}
+
+static uint32_t EncodeFtraceEventBundle(const FtraceEventBundle *t, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    i += EncodeTagUint(FTRACE_EVENT_BUNDLE_CPU, t->cpu, &buf[i], bufSize - i);
+    i += EncodeTagMessage(FTRACE_EVENT, (EncodeFn)EncodeFtraceEvent, (uintptr_t)&t->event, &buf[i], bufSize - i);
+    return i;
+}
+
+static uint32_t EncodeClockSnapshotClock(const ClockSnapshotClock *t, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    i += EncodeTagUint(CLOCK_SNAPSHOT_CLOCK_ID, t->clockId, &buf[i], bufSize - i);
+    i += EncodeTagUint(CLOCK_SNAPSHOT_CLOCK_TIMESTAMP, t->timestamp, &buf[i], bufSize - i);
+    return i;
+}
+
+static uint32_t EncodeClockSnapshot(const ClockSnapshot *t, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    i += EncodeTagUint(CLOCK_SNAPSHOT_BUILTIN_CLOCK, t->primaryTraceClock, &buf[i], bufSize - i);
+    for (uint32_t j = 0; j < t->clockNum; j++) {
+        i += EncodeTagMessage(CLOCK_SNAPSHOT_CLOCK, (EncodeFn)EncodeClockSnapshotClock, (uintptr_t)&t->clock[j],
+            &buf[i], bufSize - i);
+    }
+    return i;
+}
+
+static uint32_t EncodeALogEvent(const ALogEvent *t, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    i += EncodeTagUint(ALOG_EVENT_LOG_ID, t->logId, &buf[i], bufSize - i);
+    i += EncodeTagUint(ALOG_EVENT_PID, t->pid, &buf[i], bufSize - i);
+    i += EncodeTagUint(ALOG_EVENT_TID, t->tid, &buf[i], bufSize - i);
+    i += EncodeTagUint(ALOG_EVENT_UID, t->uid, &buf[i], bufSize - i);
+    i += EncodeTagUint(ALOG_EVENT_TIMESTAMP, t->timestamp, &buf[i], bufSize - i);
+    i += EncodeTagString(ALOG_EVENT_TAG, t->tag, &buf[i], bufSize - i);
+    i += EncodeTagUint(ALOG_EVENT_PRIORITY, t->prio, &buf[i], bufSize - i);
+    i += EncodeTagString(ALOG_EVENT_EVENT_MESSAGE, t->message, &buf[i], bufSize - i);
+    return i;
+}
+
+static uint32_t EncodeALogStats(const ALogStats *t, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    i += EncodeTagUint(ALOG_STATS_NUM_TOTAL, t->numTotal, &buf[i], bufSize - i);
+    i += EncodeTagUint(ALOG_STATS_NUM_FAILED, t->numFailed, &buf[i], bufSize - i);
+    i += EncodeTagUint(ALOG_STATS_NUM_SKIPPED, t->numSkipped, &buf[i], bufSize - i);
+    return i;
+}
+
+static uint32_t EncodeALogPacket(const ALogPacket *t, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    if (t->type == ALOG_EVENT) {
+        i += EncodeTagMessage(t->type, (EncodeFn)EncodeALogEvent, (uintptr_t)&t->events, &buf[i], bufSize - i);
+    } else if (t->type == ALOG_STATS) {
+        i += EncodeTagMessage(t->type, (EncodeFn)EncodeALogStats, (uintptr_t)&t->stats, &buf[i], bufSize - i);
+    } else {
+        TRACEUI_ERR("unsupport alog type: %d\n", t->type);
+        g_isEncodeError = true;
+        return 0;
+    }
+    return i;
+}
+
+static uint32_t EncodeTracePacket(const TracePacket *t, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    if (t->packetType == FTRACE_EVENT_BUNDLE) {
+        i += EncodeTagMessage(t->packetType, (EncodeFn)EncodeFtraceEventBundle, (uintptr_t)&t->ftraceEvents,
+            &buf[i], bufSize - i);
+    } else if (t->packetType == CLOCK_SNAPSHOT) {
+        i += EncodeTagMessage(t->packetType, (EncodeFn)EncodeClockSnapshot, (uintptr_t)&t->clockSnapshot,
+            &buf[i], bufSize - i);
+    } else if (t->packetType == ALOG_PACKET) {
+        i += EncodeTagMessage(t->packetType, (EncodeFn)EncodeALogPacket, (uintptr_t)&t->log, &buf[i], bufSize - i);
+    } else {
+        TRACEUI_ERR("unsupport packetType: %d\n", t->packetType);
+        g_isEncodeError = true;
+        return 0;
+    }
+    return i;
+}
+
+static uint32_t EncodeTrace(const Trace *t, uint8_t *buf, uint32_t bufSize)
+{
+    uint32_t i = 0;
+    g_isEncodeError = false;
+    i += EncodeTagMessage(TRACE_PACKET, (EncodeFn)EncodeTracePacket, (uintptr_t)&t->packet, &buf[i], bufSize - i);
+    return g_isEncodeError ? 0 : i;
+}
+
+static uint64_t CycleToNs(uint32_t cycle)
+{
+    return TraceuiCycleToNs(cycle - g_traceTimeOffset);
+}
+
+static uint32_t GetProtoPid(uint8_t taskId)
+{
+    if (TraceuiIsIdleTask(taskId)) {
+        return 0;
+    }
+    return PERFETTO_PID_INC + taskId;
+}
+
+static bool BufInit(Buffer *b, uint32_t size)
+{
+    b->buf = malloc(size);
+    if (b->buf == NULL) {
+        TRACEUI_ERR("malloc error!\n");
+        return false;
+    }
+    b->len = 0;
+    b->size = size;
+    return true;
+}
+
+static void BufDeinit(Buffer *b)
+{
+    if (b->buf != NULL) {
+        free(b->buf);
+        b->buf = NULL;
+    }
+    b->len = 0;
+    b->size = 0;
+}
+
+
+static void BufReset(Buffer *b)
+{
+    b->len = 0;
+}
+
+static char *BufGet(Buffer *b, uint32_t size)
+{
+    char *buf;
+    if (b->len + size > b->size) {
+        TRACEUI_ERR("buf full!\n");
+        g_isEncodeError = true;
+        return NULL;
+    }
+
+    buf = (char *)&b->buf[b->len];
+    b->len += size;
+    return buf;
+}
+
+static char *BufCopyStr(Buffer *b, const char *str)
+{
+    uint32_t size = strlen(str) + 1;
+    char *buf = BufGet(b, size);
+    if (buf == NULL) {
+        g_isEncodeError = true;
+        return NULL;
+    }
+
+    if (strcpy_s(buf, size, str) != EOK) {
+        TRACEUI_ERR("strcpy error!\n");
+        g_isEncodeError = true;
+        return NULL;
+    }
+    return buf;
+}
+
+static uint32_t GetProtoTaskStatus(TraceuiTaskStat stat)
+{
+    if (stat == TRACEUI_TASK_RUNNING) {
+        return (uint32_t)(TASK_STATE_RUNNABLE | TASK_STATE_RUN_PLUS | TASK_STATE_VALID);
+    }
+    return (uint32_t)(TASK_STATE_INTERRUPTIBLE_SLEEP | TASK_STATE_VALID);
+}
+
+static void FillFtraceHeader(const TraceuiFrameHeader *frame, Trace *t, FtraceEventId eventId)
+{
+    t->packet.packetType = FTRACE_EVENT_BUNDLE;
+    t->packet.ftraceEvents.cpu = frame->cpuid;
+    t->packet.ftraceEvents.event.timestamp = CycleToNs(frame->startTime);
+    t->packet.ftraceEvents.event.pid = GetProtoPid(frame->taskid);
+    t->packet.ftraceEvents.event.eventType = eventId;
+}
+
+static bool TraceFrameToTrace(const TraceuiFrameHeader *frame, Trace *t)
+{
+    int ret = -1;
+    uint32_t bufSize = TRACEUI_FRAME_LEN_MAX;
+    char *buf = BufGet(&g_encTmpBuf, TRACEUI_FRAME_LEN_MAX);
+    if (buf == NULL) {
+        return false;
+    }
+
+    FillFtraceHeader(frame, t, FTRACE_EVENT_PRINT);
+    if (frame->eventType == TRACEUI_EVENT_TRACE_BEGIN) {
+        TraceuiFrameTraceBegin *f = (TraceuiFrameTraceBegin *)frame;
+        ret = sprintf_s(buf, bufSize, "B|%d|%s", GetProtoPid(f->header.taskid), (const char *)f->name);
+    } else if (frame->eventType == TRACEUI_EVENT_TRACE_BEGIN_FORMAT) {
+        TraceuiFrameTraceBeginFormat *f = (TraceuiFrameTraceBeginFormat *)frame;
+        ret = sprintf_s(buf, bufSize, "B|%d|%s%s", GetProtoPid(f->header.taskid), (const char *)f->name, f->str);
+    } else if (frame->eventType == TRACEUI_EVENT_TRACE_END) {
+        ret = sprintf_s(buf, bufSize, "E|%d", GetProtoPid(frame->taskid));
+    } else if (frame->eventType == TRACEUI_EVENT_TRACE_ASYNC_BEGIN) {
+        TraceuiFrameTraceAsync *f = (TraceuiFrameTraceAsync *)frame;
+        ret = sprintf_s(buf, bufSize, "S|%d|%s|%d", GetProtoPid(f->header.taskid), (const char *)f->name, f->cookie);
+    } else if (frame->eventType == TRACEUI_EVENT_TRACE_ASYNC_END) {
+        TraceuiFrameTraceAsync *f = (TraceuiFrameTraceAsync *)frame;
+        ret = sprintf_s(buf, bufSize, "F|%d|%s|%d", GetProtoPid(f->header.taskid), (const char *)f->name, f->cookie);
+    } else if (frame->eventType == TRACEUI_EVENT_TRACE_INT) {
+        TraceuiFrameTraceInt *f = (TraceuiFrameTraceInt *)frame;
+        ret = sprintf_s(buf, bufSize, "C|%d|%s|%d", GetProtoPid(f->header.taskid), (const char *)f->name, f->value);
+    }
+    if (ret <= 0) {
+        TRACEUI_ERR("frame to trace error! type: %u\n", frame->eventType);
+        return false;
+    }
+    t->packet.ftraceEvents.event.print.buf = buf;
+    return g_isEncodeError ? false : true;
+}
+
+static bool TaskSwitchFrameToTrace(const TraceuiFrameTaskSwitch *f, Trace *t)
+{
+    SchedSwitchFtraceEvent *event = &t->packet.ftraceEvents.event.schedSwitch;
+
+    FillFtraceHeader(&f->header, t, FTRACE_EVENT_SCHED_SWITCH);
+    event->prevComm = BufCopyStr(&g_encTmpBuf, TraceuiGetTaskName(f->header.taskid));
+    event->prevPid = GetProtoPid(f->header.taskid);
+    event->prevPrio = f->prePrio;
+    event->prevState = GetProtoTaskStatus(f->preState);
+    event->nextComm = BufCopyStr(&g_encTmpBuf, TraceuiGetTaskName(f->nextTaskId));
+    event->nextPid = GetProtoPid(f->nextTaskId);
+    event->nextPrio = f->nextPrio;
+    return g_isEncodeError ? false : true;
+}
+
+static bool TaskWakeupFrameToTrace(TraceuiFrameTaskWakeup *f, Trace *t)
+{
+    SchedWakingFtraceEvent *event = &t->packet.ftraceEvents.event.schedWaking;
+
+    FillFtraceHeader(&f->header, t, FTRACE_EVENT_SCHED_WAKING);
+    event->comm = BufCopyStr(&g_encTmpBuf, TraceuiGetTaskName(f->wakeTaskId));
+    event->pid = GetProtoPid(f->wakeTaskId);
+    event->prio = f->wakePrio;
+    event->success = 0;
+    event->targetCpu = 0;
+    return g_isEncodeError ? false : true;
+}
+
+static bool HwiEnterFrameToTrace(TraceuiFrameHwiEnter *f, Trace *t)
+{
+    IrqHandlerEntryFtraceEvent *event = &t->packet.ftraceEvents.event.irqEntry;
+
+    FillFtraceHeader(&f->header, t, FTRACE_EVENT_IRQ_HANDLER_ENTRY);
+    event->irq = f->hwiNum;
+    event->name = BufCopyStr(&g_encTmpBuf, TraceuiGetIrqName(f->hwiNum));
+    return g_isEncodeError ? false : true;
+}
+
+static bool HwiExitFrameToTrace(TraceuiFrameHwiExit *f, Trace *t)
+{
+    IrqHandlerExitFtraceEvent *event = &t->packet.ftraceEvents.event.irqExit;
+
+    FillFtraceHeader(&f->header, t, FTRACE_EVENT_IRQ_HANDLER_EXIT);
+    event->irq = f->hwiNum;
+    event->ret = 0;
+    return g_isEncodeError ? false : true;
+}
+
+static bool LogFrameToTrace(TraceuiFrameLog *f, Trace *t)
+{
+    t->packet.packetType = ALOG_PACKET;
+    t->packet.log.type = ALOG_EVENT;
+    t->packet.log.events.logId = LID_DEFAULT;
+    t->packet.log.events.pid = GetProtoPid(f->header.taskid);
+    t->packet.log.events.tid = GetProtoPid(f->header.taskid);
+    t->packet.log.events.uid = 0;
+    t->packet.log.events.timestamp = CycleToNs(f->header.startTime);
+    t->packet.log.events.tag = BufCopyStr(&g_encTmpBuf, TraceuiGetTaskName(f->header.taskid));
+    t->packet.log.events.prio = PRIO_INFO;
+    t->packet.log.events.message = f->str;
+    g_logCount++;
+    return g_isEncodeError ? false : true;
+}
+
+static bool FrameToTrace(const TraceuiFrameHeader *frame, Trace *t)
+{
+    g_isEncodeError = false;
+    switch (frame->eventType) {
+        case TRACEUI_EVENT_TASK_SWITCH:
+            return TaskSwitchFrameToTrace((TraceuiFrameTaskSwitch *)frame, t);
+        case TRACEUI_EVENT_TASK_WAKEUP:
+            return TaskWakeupFrameToTrace((TraceuiFrameTaskWakeup *)frame, t);
+        case TRACEUI_EVENT_HWI_ENTER:
+            return HwiEnterFrameToTrace((TraceuiFrameHwiEnter *)frame, t);
+        case TRACEUI_EVENT_HWI_EXIT:
+            return HwiExitFrameToTrace((TraceuiFrameHwiExit *)frame, t);
+        case TRACEUI_EVENT_TRACE_BEGIN:
+        case TRACEUI_EVENT_TRACE_BEGIN_FORMAT:
+        case TRACEUI_EVENT_TRACE_END:
+        case TRACEUI_EVENT_TRACE_ASYNC_BEGIN:
+        case TRACEUI_EVENT_TRACE_ASYNC_END:
+        case TRACEUI_EVENT_TRACE_INT:
+            return TraceFrameToTrace(frame, t);
+        case TRACEUI_EVENT_LOG:
+            return LogFrameToTrace((TraceuiFrameLog *)frame, t);
+        default:
+            break;
+    }
+    TRACEUI_ERR("unsupport frame type: %d\n", frame->eventType);
+    return false;
+}
+
+static uint32_t EncodeFrameContent(const TraceuiFrameHeader *frame, uint8_t *buf, uint32_t bufSize)
+{
+    Trace *t;
+
+    BufReset(&g_encTmpBuf);
+    t = (Trace *)BufGet(&g_encTmpBuf, sizeof(Trace));
+    if (t == NULL) {
+        return 0;
+    }
+
+    (void)memset_s(t, sizeof(Trace), 0, sizeof(Trace));
+    if (!FrameToTrace(frame, t)) {
+        return 0;
+    }
+    return EncodeTrace(t, buf, bufSize);
+}
+
+
+static uint32_t EncodeFullClockSnapshot(uint8_t *buf, uint32_t bufSize)
+{
+    Trace *t;
+    ClockSnapshotClock *clocks;
+    uint32_t count = 0;
+
+    BufReset(&g_encTmpBuf);
+    t = (Trace *)BufGet(&g_encTmpBuf, sizeof(Trace));
+    clocks = (ClockSnapshotClock *)BufGet(&g_encTmpBuf, sizeof(ClockSnapshotClock) * BUILTIN_CLOCK_MAX);
+    if (t == NULL || clocks == NULL) {
+        return 0;
+    }
+
+    (void)memset_s(t, sizeof(Trace), 0, sizeof(Trace));
+    for (BuiltinClockId i = BUILTIN_CLOCK_REALTIME; i <= BUILTIN_CLOCK_BOOT_TIME; i++) {
+        clocks[count].clockId = (uint32_t)i;
+        clocks[count].timestamp = 0;
+        count++;
+    }
+    t->packet.packetType = CLOCK_SNAPSHOT;
+    t->packet.clockSnapshot.clockNum = count;
+    t->packet.clockSnapshot.clock = clocks;
+    t->packet.clockSnapshot.primaryTraceClock = BUILTIN_CLOCK_BOOT_TIME;
+    return EncodeTrace(t, buf, bufSize);
+}
+
+static uint32_t EncodeLogEventStatus(uint8_t *buf, uint32_t bufSize)
+{
+    Trace *t;
+
+    BufReset(&g_encTmpBuf);
+    t = (Trace *)BufGet(&g_encTmpBuf, sizeof(Trace));
+    if (t == NULL) {
+        return 0;
+    }
+
+    (void)memset_s(t, sizeof(Trace), 0, sizeof(Trace));
+    t->packet.packetType = ALOG_PACKET;
+    t->packet.log.type = ALOG_STATS;
+    t->packet.log.stats.numTotal = g_logCount;
+    t->packet.log.stats.numFailed = 0;
+    t->packet.log.stats.numSkipped = 0;
+    return EncodeTrace(t, buf, bufSize);
+}
+
+static bool StartConvert(const uint8_t *buf, uint32_t bufSize, FILE *fp)
+{
+    uint32_t walkIndex = 0;
+    Buffer dstBuf;
+    const TraceuiFrameHeader *frame = (const TraceuiFrameHeader *)buf;
+    bool ret = false;
+
+    if (!BufInit(&dstBuf, MAX_ENC_BUF_SIZE) || !BufInit(&g_encTmpBuf, MAX_ENC_BUF_SIZE)) {
+        goto out;
+    }
+
+    // write prefix
+    g_logCount = 0;
+    g_traceTimeOffset = frame->startTime;
+    dstBuf.len = EncodeFullClockSnapshot(dstBuf.buf, dstBuf.size);
+    if (fwrite(dstBuf.buf, dstBuf.len, 1, fp) <= 0) {
+        TRACEUI_ERR("fwrite failed!\n");
+        goto out;
+    }
+
+    // write main trace
+    while ((frame = TraceuiWalkBuf(buf, bufSize, &walkIndex)) != NULL) {
+        dstBuf.len = EncodeFrameContent(frame, dstBuf.buf, dstBuf.size);
+        if (dstBuf.len <= 0) {
+            continue;
+        }
+        if (fwrite(dstBuf.buf, dstBuf.len, 1, fp) <= 0) {
+            TRACEUI_ERR("fwrite failed!\n");
+            goto out;
+        }
+    }
+
+    // write tail
+    dstBuf.len = EncodeLogEventStatus(dstBuf.buf, dstBuf.size);
+    if (fwrite(dstBuf.buf, dstBuf.len, 1, fp) <= 0) {
+        TRACEUI_ERR("fwrite failed!\n");
+        goto out;
+    }
+    ret = true;
+
+out:
+    BufDeinit(&g_encTmpBuf);
+    BufDeinit(&dstBuf);
+    return ret;
+}
+
+bool TraceuiConvertToPerfettoProto(const uint8_t *buf, uint32_t bufSize, const char *outPath)
+{
+    FILE *fp = NULL;
+    bool success = false;
+
+    if (buf == NULL || outPath == NULL) {
+        TRACEUI_ERR("parameter error! null!\n");
+        goto out;
+    }
+
+    fp = fopen(outPath, "w");
+    if (fp == NULL) {
+        TRACEUI_ERR("open %s failed!\n", outPath);
+        goto out;
+    }
+    success = StartConvert(buf, bufSize, fp);
+    if (!success) {
+        TRACEUI_ERR("convert %s failed!\n", outPath);
+        goto out;
+    }
+
+out:
+    if (fp != NULL) {
+        fclose(fp);
+    }
+    return success;
+}
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_core.c b/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_core.c
new file mode 100644 (file)
index 0000000..35145b4
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: traceui core implementation
+ * Author: Hisi Graphic Team
+ * Created: 2025-9
+ */
+
+#include <stdio.h>
+#include "asm/interrupt_config.h"
+#include "traceui_buf.h"
+#include "traceui_os.h"
+#include "traceui_core.h"
+
+static uint32_t g_eventMask = 0;
+static bool g_trace_record = false;
+static bool g_record_full = false;
+
+#ifdef LOSCFG_BASE_CORE_TSK_MONITOR
+static void TaskSwitchHook(uint32_t oldTaskId, uint32_t newTaskId)
+{
+    UNUSED(oldTaskId);
+    TraceuiEventTaskSwitch(newTaskId);
+}
+#endif
+
+#ifdef LOSCFG_HWI_PRE_POST_PROCESS
+static void HwiProcPreHook(HWI_HANDLE_T hwiNum)
+{
+    TraceuiEventHwiEnter(hwiNum);
+}
+
+static void HwiProcPostHook(HWI_HANDLE_T hwiNum)
+{
+    TraceuiEventHwiExit(hwiNum);
+}
+#endif
+
+bool TraceuiRecordStart(uint32_t events, uint8_t *buf, uint32_t bufSize)
+{
+    g_eventMask = events;
+    g_record_full = false;
+    TraceuiBufInit(buf, bufSize);
+
+#ifdef LOSCFG_BASE_CORE_TSK_MONITOR
+    LOS_TaskSwitchHookReg(TaskSwitchHook);
+#else
+    TRACEUI_ERR("Warn: no task switch, need LOSCFG_BASE_CORE_TSK_MONITOR=y\n");
+#endif
+#ifdef LOSCFG_HWI_PRE_POST_PROCESS
+    LOS_HwiPreHookReg(HwiProcPreHook);
+    LOS_HwiPostHookReg(HwiProcPostHook);
+#else
+    TRACEUI_ERR("Warn: no interrupt, need LOSCFG_HWI_PRE_POST_PROCESS=y\n");
+#endif
+
+    g_trace_record = TRUE;
+    return true;
+}
+
+uint32_t TraceuiRecordStop(void)
+{
+    g_trace_record = false;
+    uint32_t ret = TraceuiGetBufUsedSize();
+    TraceuiBufDeinit();
+#ifdef LOSCFG_BASE_CORE_TSK_MONITOR
+    LOS_TaskSwitchHookReg(NULL);
+#endif
+#ifdef LOSCFG_HWI_PRE_POST_PROCESS
+    LOS_HwiPreHookReg(NULL);
+    LOS_HwiPostHookReg(NULL);
+#endif
+    return ret;
+}
+
+static uint32_t GetEventTypeSize(TraceuiEventType type)
+{
+    switch (type) {
+        case TRACEUI_EVENT_TASK_SWITCH:
+            return sizeof(TraceuiFrameTaskSwitch);
+        case TRACEUI_EVENT_TASK_WAKEUP:
+            return sizeof(TraceuiFrameTaskWakeup);
+        case TRACEUI_EVENT_TRACE_BEGIN:
+            return sizeof(TraceuiFrameTraceBegin);
+        case TRACEUI_EVENT_TRACE_BEGIN_FORMAT:
+            return sizeof(TraceuiFrameTraceBeginFormat);
+        case TRACEUI_EVENT_TRACE_END:
+            return sizeof(TraceuiFrameTraceEnd);
+        case TRACEUI_EVENT_TRACE_ASYNC_BEGIN:
+        case TRACEUI_EVENT_TRACE_ASYNC_END:
+            return sizeof(TraceuiFrameTraceAsync);
+        case TRACEUI_EVENT_TRACE_INT:
+            return sizeof(TraceuiFrameTraceInt);
+        case TRACEUI_EVENT_HWI_ENTER:
+            return sizeof(TraceuiFrameHwiEnter);
+        case TRACEUI_EVENT_HWI_EXIT:
+            return sizeof(TraceuiFrameHwiExit);
+        case TRACEUI_EVENT_LOG:
+            return sizeof(TraceuiFrameLog);
+        default:
+            break;
+    }
+    return 0;
+}
+
+const TraceuiFrameHeader* TraceuiWalkBuf(const uint8_t *buf, uint32_t bufSize, uint32_t *pos)
+{
+    uint32_t size;
+    const TraceuiFrameHeader *header;
+
+    if (buf == NULL || pos == NULL) {
+        return NULL;
+    }
+    if (*pos + sizeof(TraceuiFrameHeader) > bufSize) {
+        return NULL;
+    }
+
+    header = (const TraceuiFrameHeader *)&buf[*pos];
+    size = header->frameLen;
+    if (size == 0 || *pos + size > bufSize) {
+        TRACEUI_ERR("Error size: event type: 0x%x\n", header->eventType);
+        return NULL;
+    }
+    *pos += size;
+    return header;
+}
+
+static TraceuiTaskStat ConvertTaskStatus(uint16_t taskStatus)
+{
+    if (taskStatus & OS_TASK_STATUS_READY) {
+        return TRACEUI_TASK_RUNNING;
+    } else if (taskStatus & OS_TASK_STATUS_DELAY) {
+        return TRACEUI_TASK_DELAY;
+    }
+    return TRACEUI_TASK_PENDING;
+}
+
+static inline uint8_t ConvertTaskId(uint32_t taskId)
+{
+    if ((taskId & 0xFFFFFF00) != 0) {
+        TRACEUI_ERR("Error! taskId too large: 0x%x\n", taskId);
+    }
+    return (uint8_t)(taskId & 0xFF);
+}
+
+static inline uint8_t ConvertPriority(uint16_t prio)
+{
+    if ((prio & 0xFFFFFF00) != 0) {
+        TRACEUI_ERR("Error! priority too large: 0x%x\n", prio);
+    }
+    return (uint8_t)(prio & 0xFF);
+}
+
+static TraceuiFrameHeader *GenFrame(TraceuiEventType event, uint32_t addLen)
+{
+    if ((g_eventMask & TRACEUI_EVENT_MASK(event)) == 0 || g_record_full) {
+        return NULL;
+    }
+
+    uint32_t len = GetEventTypeSize(event) + addLen;
+    if (len <= addLen) {
+        TRACEUI_ERR("unsupport event type: %d\n", (int)event);
+        return NULL;
+    }
+    len = (len + TRACEUI_FRAME_LEN_ALIGN - 1) / TRACEUI_FRAME_LEN_ALIGN * TRACEUI_FRAME_LEN_ALIGN;
+    if (len > TRACEUI_FRAME_LEN_MAX) {
+        TRACEUI_ERR("Error! frame len too long, event: %d\n", event);
+        return NULL;
+    }
+    TraceuiFrameHeader *header = (TraceuiFrameHeader *)TraceuiGetBuf(len);
+    if (header == NULL) {
+        g_record_full = true;
+        TRACEUI_PRINT("record full!\n");
+        return NULL;
+    }
+
+    const LosTaskCB *curTask = OsCurrTaskGet();
+    if (curTask == NULL) {
+        return NULL;
+    }
+
+    header->startTime = TraceuiGetTimeCycle();
+    header->eventType = event;
+    header->taskid = ConvertTaskId(curTask->taskId);
+    header->cpuid = TraceuiGetCpuId();
+    header->frameLen = (uint8_t)len;
+    return header;
+}
+
+void TraceuiEventTaskSwitch(uint32_t newTaskId)
+{
+    TraceuiFrameTaskSwitch *frame = (TraceuiFrameTaskSwitch *)GenFrame(TRACEUI_EVENT_TASK_SWITCH, 0);
+    if (frame == NULL) {
+        return;
+    }
+
+    const LosTaskCB *curTask = OsCurrTaskGet();
+    const LosTaskCB *newTask = OS_TCB_FROM_TID(newTaskId);
+    if (curTask == NULL || newTask == NULL) {
+        return;
+    }
+
+    frame->prePrio = ConvertPriority(curTask->priority);
+    frame->preState = ConvertTaskStatus(curTask->taskStatus);
+    frame->nextTaskId = ConvertTaskId(newTask->taskId);
+    frame->nextPrio = ConvertPriority(newTask->priority);
+}
+
+void TraceuiEventTaskWakeup(uint32_t wakeTaskId)
+{
+    TraceuiFrameTaskWakeup *frame = (TraceuiFrameTaskWakeup *)GenFrame(TRACEUI_EVENT_TASK_WAKEUP, 0);
+    if (frame == NULL) {
+        return;
+    }
+
+    const LosTaskCB *wakeTask = OS_TCB_FROM_TID(wakeTaskId);
+    if (wakeTask == NULL) {
+        return;
+    }
+
+    frame->wakePrio = ConvertPriority(wakeTask->priority);
+    frame->wakeTaskId = ConvertTaskId(wakeTask->taskId);
+}
+
+void TraceuiEventTraceBegin(const char *name)
+{
+    TraceuiFrameTraceBegin *frame = (TraceuiFrameTraceBegin *)GenFrame(TRACEUI_EVENT_TRACE_BEGIN, 0);
+    if (frame == NULL) {
+        return;
+    }
+    frame->name = (uintptr_t)name;
+}
+
+void TraceuiEventTraceBeginFormat(const char *name, const char *fmt, ...)
+{
+    char buf[TRACEUI_FRAME_LEN_MAX - sizeof(TraceuiFrameTraceBeginFormat)];
+    va_list ap;
+    va_start(ap, fmt);
+    int fmtStrLen = vsprintf_s(buf, sizeof(buf), fmt, ap);
+    va_end(ap);
+    if (fmtStrLen <= 0) {
+        TRACEUI_ERR("format error!\n");
+        return;
+    }
+    fmtStrLen++; // add '\0' len
+
+    TraceuiFrameTraceBeginFormat *frame;
+    frame = (TraceuiFrameTraceBeginFormat *)GenFrame(TRACEUI_EVENT_TRACE_BEGIN_FORMAT, fmtStrLen);
+    if (frame == NULL) {
+        return;
+    }
+    frame->name = (uintptr_t)name;
+    (void)memcpy_s(frame->str, fmtStrLen, buf, fmtStrLen);
+}
+
+void TraceuiEventTraceEnd(void)
+{
+    TraceuiFrameTraceEnd *frame = (TraceuiFrameTraceEnd *)GenFrame(TRACEUI_EVENT_TRACE_END, 0);
+    if (frame == NULL) {
+        return;
+    }
+}
+
+void TraceuiEventTraceAsyncBegin(const char *name, int cookie)
+{
+    TraceuiFrameTraceAsync *frame = (TraceuiFrameTraceAsync *)GenFrame(TRACEUI_EVENT_TRACE_ASYNC_BEGIN, 0);
+    if (frame == NULL) {
+        return;
+    }
+    frame->name = (uintptr_t)name;
+    frame->cookie = cookie;
+}
+
+void TraceuiEventTraceAsyncEnd(const char *name, int cookie)
+{
+    TraceuiFrameTraceAsync *frame = (TraceuiFrameTraceAsync *)GenFrame(TRACEUI_EVENT_TRACE_ASYNC_END, 0);
+    if (frame == NULL) {
+        return;
+    }
+    frame->name = (uintptr_t)name;
+    frame->cookie = cookie;
+}
+
+void TraceuiEventTraceInt(const char *name, int value)
+{
+    TraceuiFrameTraceInt *frame = (TraceuiFrameTraceInt *)GenFrame(TRACEUI_EVENT_TRACE_INT, 0);
+    if (frame == NULL) {
+        return;
+    }
+    frame->name = (uintptr_t)name;
+    frame->value = value;
+}
+
+void TraceuiEventHwiEnter(uint32_t hwiNum)
+{
+    // skip timer irq: It happens too frequently, and takes little time.
+    if (hwiNum == NUM_HAL_INTERRUPT_TIMER) {
+        return;
+    }
+
+    TraceuiFrameHwiEnter *frame = (TraceuiFrameHwiEnter *)GenFrame(TRACEUI_EVENT_HWI_ENTER, 0);
+    if (frame == NULL) {
+        return;
+    }
+
+    frame->hwiNum = hwiNum;
+}
+
+void TraceuiEventHwiExit(uint32_t hwiNum)
+{
+    // skip timer irq: It happens too frequently, and takes little time.
+    if (hwiNum == NUM_HAL_INTERRUPT_TIMER) {
+        return;
+    }
+
+    TraceuiFrameHwiExit *frame = (TraceuiFrameHwiExit *)GenFrame(TRACEUI_EVENT_HWI_EXIT, 0);
+    if (frame == NULL) {
+        return;
+    }
+
+    frame->hwiNum = hwiNum;
+}
+
+void TraceuiEventLog(const char *fmt, ...)
+{
+    char buf[TRACEUI_FRAME_LEN_MAX - sizeof(TraceuiFrameLog)];
+    va_list ap;
+    va_start(ap, fmt);
+    int fmtStrLen = vsprintf_s(buf, sizeof(buf), fmt, ap);
+    va_end(ap);
+    if (fmtStrLen < 0) {
+        TRACEUI_ERR("format error!\n");
+        return;
+    }
+    fmtStrLen++; // add '\0' len
+
+    TraceuiFrameLog *frame = (TraceuiFrameLog *)GenFrame(TRACEUI_EVENT_LOG, fmtStrLen);
+    if (frame == NULL) {
+        return;
+    }
+    (void)memcpy_s(frame->str, fmtStrLen, buf, fmtStrLen);
+}
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_core.h b/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_core.h
new file mode 100644 (file)
index 0000000..9b27f3f
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: traceui core interface
+ * Author: Hisi Graphic Team
+ * Created: 2025-9
+ */
+
+#ifndef _LOS_TRACEUI_H
+#define _LOS_TRACEUI_H
+
+#include "dfx/dfx_traceui.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define TRACEUI_FRAME_LEN_MAX 0xFF
+#define TRACEUI_FRAME_LEN_ALIGN sizeof(uintptr_t)
+
+typedef enum {
+    TRACEUI_TASK_RUNNING = 1,
+    TRACEUI_TASK_DELAY   = 2,
+    TRACEUI_TASK_PENDING = 3,
+} TraceuiTaskStat;
+
+typedef struct {
+    uint32_t startTime; // unit: cycle
+    uint8_t taskid; // current or pre sched switch task id
+    uint8_t cpuid; // which cpu core
+    uint8_t eventType; // TraceuiEventType
+    uint8_t frameLen; // include frame header
+} TraceuiFrameHeader;
+
+typedef struct {
+    TraceuiFrameHeader header;
+    uint8_t prePrio; // task priority before task switch
+    uint8_t preState; // TraceuiTaskStat
+    uint8_t nextTaskId; // taskid after task switch
+    uint8_t nextPrio; // task priority after task switch
+} TraceuiFrameTaskSwitch;
+
+typedef struct {
+    TraceuiFrameHeader header;
+    uint8_t wakePrio;
+    uint8_t wakeTaskId;
+} TraceuiFrameTaskWakeup;
+
+typedef struct {
+    TraceuiFrameHeader header;
+    uintptr_t name; // string pointer
+} TraceuiFrameTraceBegin;
+
+typedef struct {
+    TraceuiFrameHeader header;
+    uintptr_t name; // string pointer
+    char str[0];
+} TraceuiFrameTraceBeginFormat;
+
+typedef struct {
+    TraceuiFrameHeader header;
+} TraceuiFrameTraceEnd;
+
+typedef struct {
+    TraceuiFrameHeader header;
+    uintptr_t name; // string pointer
+    int cookie;
+} TraceuiFrameTraceAsync;
+
+typedef struct {
+    TraceuiFrameHeader header;
+    uintptr_t name; // string pointer
+    int value;
+} TraceuiFrameTraceInt;
+
+typedef struct {
+    TraceuiFrameHeader header;
+    uint8_t hwiNum;
+} TraceuiFrameHwiEnter;
+
+typedef struct {
+    TraceuiFrameHeader header;
+    uint8_t hwiNum;
+} TraceuiFrameHwiExit;
+
+typedef struct {
+    TraceuiFrameHeader header;
+    char str[0];
+} TraceuiFrameLog;
+
+void TraceuiEventTaskSwitch(uint32_t newTaskId);
+void TraceuiEventTaskWakeup(uint32_t wakeTaskId);
+void TraceuiEventHwiEnter(uint32_t hwiNum);
+void TraceuiEventHwiExit(uint32_t hwiNum);
+
+// useage: uint32_t pos = 0; while ((frame = TraceuiWalkBuf(buf, bufSize, &pos)) != NULL) {}
+const TraceuiFrameHeader* TraceuiWalkBuf(const uint8_t *buf, uint32_t bufSize, uint32_t *pos);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_os.h b/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/dfx/traceui/traceui_os.h
new file mode 100644 (file)
index 0000000..d9c501a
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: traceui operating system interface
+ * Author: Hisi Graphic Team
+ * Created: 2025-9
+ */
+
+#ifndef TRACEUI_OS_H
+#define TRACEUI_OS_H
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <securec.h>
+#include "los_tick.h"
+#include "los_hwi.h"
+#include "los_hwi_pri.h"
+#include "los_task.h"
+#include "los_task_pri.h"
+
+#define TRACEUI_ERR(fmt, ...) printf("ERR: " fmt, ##__VA_ARGS__)
+#define TRACEUI_DBG(fmt, ...) printf("DBG: " fmt, ##__VA_ARGS__)
+#define TRACEUI_PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
+
+#ifndef UNUSED
+#define UNUSED(x) ((void)(x))
+#endif
+
+// get current timestamp in cycle
+static inline uint32_t TraceuiGetTimeCycle(void)
+{
+    return (uint32_t)HalClockGetCycles();
+}
+
+// convert cycle to nanosecond
+static inline uint64_t TraceuiCycleToNs(uint32_t cycle)
+{
+    return (uint64_t)cycle * OS_SYS_NS_PER_SECOND / g_sysClock;
+}
+
+// get current cpu core id
+static inline uint8_t TraceuiGetCpuId(void)
+{
+    return ArchCurrCpuid();
+}
+
+// get hardware interrupt name
+static inline const char *TraceuiGetIrqName(uint32_t irqNum)
+{
+    static char name[16];
+    const HwiHandleInfo *form = OsGetHwiForm(irqNum);
+    if (form != NULL && (void *)form->registerInfo != NULL && ((HWI_IRQ_PARAM_S *)form->registerInfo)->pName != NULL) {
+        if (sprintf_s(name, sizeof(name), "IRQ-%s", ((HWI_IRQ_PARAM_S *)form->registerInfo)->pName) > 0) {
+            return name;
+        }
+    }
+    (void)sprintf_s(name, sizeof(name), "IRQ-%u", irqNum);
+    return name;
+}
+
+// get task name
+static inline const char *TraceuiGetTaskName(uint32_t taskId)
+{
+    static char name[16];
+    LosTaskCB *task = OS_TCB_FROM_TID(taskId);
+    if (task == NULL || task->taskName == NULL) {
+        (void)sprintf_s(name, sizeof(name), "task-%u", taskId);
+        return name;
+    }
+    return task->taskName;
+}
+
+static inline bool TraceuiIsIdleTask(uint32_t taskId)
+{
+    Percpu *perCpu;
+    for (int32_t i = 0; i < LOSCFG_KERNEL_CORE_NUM; i++) {
+        perCpu = OsPercpuGetByID(i);
+        if (perCpu != NULL && taskId == perCpu->idleTaskId) {
+            return true;
+        }
+    }
+    return false;
+}
+
+#endif
index 485dd31..16a9a22 100644 (file)
@@ -52,12 +52,24 @@ ImageInfo ClipImg::ClipImgByCircle(ImageInfo& srcInfo, Point center, int16_t rad
         return dstInfo;
     }
 
-    if (!AllocImageInfo(dstInfo, 2 * radius, 2 * radius, mode)) { // 2: the diameter of the circle
+    float scale = 1.0;
+    if (srcInfo.userData != nullptr) {
+        scale = *(static_cast<float*>(srcInfo.userData));
+    }
+    if (!AllocImageInfo(dstInfo, 2 * radius * scale, 2 * radius * scale, mode)) { // 2: the diameter of the circle
         HWDrawUtils::GetInstance()->FreeBufferForPath(&path);
         return dstInfo;
     }
 
-    ClipImgByPath(dstInfo, srcInfo, &path, nullptr, nullptr, nullptr);
+    Matrix4<float> pathMat;
+    Matrix4<float> imgMat;
+    if (!FloatEqual(scale, 1.0)) {
+        pathMat[0][0] = scale;
+        pathMat[1][1] = scale;
+        imgMat[0][0] = scale;
+        imgMat[1][1] = scale;
+    }
+    ClipImgByPath(dstInfo, srcInfo, &path, nullptr, &pathMat, &imgMat);
     if (immediatelySync) {
         LiteMGfxEngine::GetInstance()->SyncHwDraw();
     }
@@ -95,4 +107,39 @@ ImageInfo ClipImg::ClipImgByRect(ImageInfo& srcInfo, Rect* srcImgArea, Rect clip
     HWDrawUtils::GetInstance()->FreeBufferForPath(&path);
     return dstInfo;
 }
+
+ImageInfo ClipImg::ClipImgByRoundRect(ImageInfo& srcInfo, Rect clipArea, uint16_t radius,
+    ColorMode mode, bool immediatelySync)
+{
+    ImageInfo dstInfo = {{0}};
+    Path path = {0};
+
+    if (!HWDrawUtils::GetInstance()->ObtainRectPathWithRadius(clipArea, path, radius)) { // 5: cmd and data num
+        return dstInfo;
+    }
+
+    float scale = 1.0;
+    if (srcInfo.userData != nullptr) {
+        scale = *(static_cast<float*>(srcInfo.userData));
+    }
+    if (!AllocImageInfo(dstInfo, clipArea.GetWidth() * scale, clipArea.GetHeight() * scale, mode)) {
+        HWDrawUtils::GetInstance()->FreeBufferForPath(&path);
+        return dstInfo;
+    }
+
+    Matrix4<float> pathMat;
+    Matrix4<float> imgMat;
+    if (!FloatEqual(scale, 1.0)) {
+        pathMat[0][0] = scale;
+        pathMat[1][1] = scale;
+        imgMat[0][0] = scale;
+        imgMat[1][1] = scale;
+    }
+    ClipImgByPath(dstInfo, srcInfo, &path, nullptr, &pathMat, &imgMat);
+    if (immediatelySync) {
+        LiteMGfxEngine::GetInstance()->SyncHwDraw();
+    }
+    HWDrawUtils::GetInstance()->FreeBufferForPath(&path);
+    return dstInfo;
+}
 }
index 5d55adf..43e90d4 100644 (file)
@@ -23,6 +23,8 @@ public:
     static ImageInfo ClipImgByCircle(ImageInfo& srcInfo, Point center, int16_t radius,
         ColorMode mode = RGB888, bool immediatelySync = false);
     static ImageInfo ClipImgByRect(ImageInfo& srcInfo, Rect* srcImgArea, Rect clipArea, ColorMode mode = RGB888);
+    static ImageInfo ClipImgByRoundRect(ImageInfo& srcInfo, Rect clipArea, uint16_t radius,
+        ColorMode mode = RGB888, bool immediatelySync = false);
 };
 } // namespace OHOS
 #endif // GRAPHIC_LITE_DRAW_LABEL_H
index d44c2fd..2f14744 100644 (file)
@@ -19,6 +19,8 @@
 #include "gfx_utils/graphic_math.h"
 #include "gfx_utils/graphic_log.h"
 #include "hals/gralloc_engines.h"
+#include "imgdecode/image_load.h"
+#include "hals/display_dev.h"
 
 #if ENABLE_VGU_ENGINE
 namespace OHOS {
@@ -107,14 +109,13 @@ static float ConvertArcDegree(ArcInfo& arc, uint32_t& quaNum, uint32_t& bezNum)
         bezNum = 4; // 4: num of quaerter in circle
         return 0.0f;
     }
-    int neg = (arc.startAngle < arc.endAngle) ? 1 : -1;
     uint32_t deltaAngleInt = static_cast<uint32_t>(deltaAngle);
     if (FloatEqual(deltaAngle - deltaAngleInt, 1.0f, PRECISION_ANGLE)) {
         deltaAngleInt += 1;
     }
     quaNum = deltaAngleInt / QUARTER_IN_DEGREE;
     float remain = deltaAngle - quaNum * QUARTER_IN_DEGREE;
-    bezNum = FloatMore(remain, 0.0f, PRECISION_ANGLE) ? quaNum + 1:  quaNum;
+    bezNum = FloatMore(remain, 0.0f, PRECISION_ANGLE) ? quaNum + 1: quaNum;
     return remain;
 }
 
@@ -186,7 +187,7 @@ bool HWDrawUtils::ObtainArcPath(ArcInfo arc, uint32_t& cmdNum, uint8_t*& cmds, u
 
     GetArcData(data, arc, quaNum, remain);
     cmds[0] = CMD_MOVE_TO;
-    for (int i = 1; i < cmdNum; i++) {
+    for (uint32_t i = 1; i < cmdNum; i++) {
         cmds[i] = CMD_CUBIC_TO;
     }
     return true;
@@ -215,7 +216,7 @@ bool HWDrawUtils::ObtainSectorPath(ArcInfo arc, uint32_t& cmdNum, uint8_t*& cmds
     cmds[0] = CMD_MOVE_TO;
     cmds[1] = CMD_LINE_TO;
     cmds[cmdNum - 1] = CMD_CLOSE;
-    for (int i = 2; i < cmdNum - 1; i++) {
+    for (uint32_t i = 2; i < cmdNum - 1; i++) {
         cmds[i] = CMD_CUBIC_TO;
     }
     return true;
@@ -274,7 +275,7 @@ bool HWDrawUtils::ObtainCirclePath(const ArcInfo& arc, uint32_t& cmdNum,
     return true;
 }
 
-bool HWDrawUtils::ObtainRectPathWithRadius(const Rect& rect, Path& path, int16_t radius)
+bool HWDrawUtils::ObtainRectPathWithRadius(const Rect& rect, Path& path, int16_t topRadius, int16_t bottomRadius)
 {
     uint32_t cmdNum = 10; // 10: Circle path command number is 10
     if (path.cmdNum < cmdNum) {
@@ -309,52 +310,63 @@ bool HWDrawUtils::ObtainRectPathWithRadius(const Rect& rect, Path& path, int16_t
     }
     path.dataNum = dataNum;
 
-    GetFilledRoundRectData(path.data, radius, rect);
+    GetFilledRoundRectData(path.data, topRadius, bottomRadius, rect);
     return true;
 }
 
+bool HWDrawUtils::ObtainRectPathWithRadius(const Rect& rect, Path& path, int16_t radius)
+{
+    return ObtainRectPathWithRadius(rect, path, radius, radius);
+}
+
 void HWDrawUtils::GetFilledRoundRectData(float* data, uint16_t radius, const Rect& rect)
 {
-    float r = radius;
+    GetFilledRoundRectData(data, radius, radius, rect);
+}
+
+void HWDrawUtils::GetFilledRoundRectData(float* data, uint16_t topRadius, uint16_t bottomRadius, const Rect& rect)
+{
+    float tr = topRadius;
+    float br = bottomRadius;
     int16_t x1 = rect.GetLeft();
     int16_t y1 = rect.GetTop();
     int16_t x2 = rect.GetRight();
     int16_t y2 = rect.GetBottom();
 
     data[0] = x1;
-    data[1] = y1 + r;
+    data[1] = y1 + tr;
     data[2] = x1; // 2: index
-    data[3] = y2 - r; // 3: index
+    data[3] = y2 - br; // 3: index
 
     // 1 arc end point
-    data[8] = x1 + r; // 8: index
+    data[8] = x1 + br; // 8: index
     data[9] = y2 + 1; // 9: index
-    data[10] = x2 - r; // 10: index
+    data[10] = x2 - br; // 10: index
     data[11] = y2 + 1; // 11: index
 
     // 2 arc end point
     data[16] = x2 + 1; // 16: index
-    data[17] = y2 - r; // 17: index
+    data[17] = y2 - br; // 17: index
     data[18] = x2 + 1; // 18: index
-    data[19] = y1 + r; // 19: index
+    data[19] = y1 + tr; // 19: index
 
     // 3 arc end point
-    data[24] = x2 - r; // 24: index
+    data[24] = x2 - tr; // 24: index
     data[25] = y1; // 25: index
-    data[26] = x1 + r; // 26: index
+    data[26] = x1 + tr; // 26: index
     data[27] = y1; // 27: index
 
     // 4 arc end point
     data[32] = x1; // 32: index
-    data[33] = y1 + r; // 33: index
+    data[33] = y1 + tr; // 33: index
 
-    GetArcControlPoint(&data[2], x1 + r, y2 - r, ARC_TO_BEZIER_90_DEG, -1); // 2: index
+    GetArcControlPoint(&data[2], x1 + br, y2 - br, ARC_TO_BEZIER_90_DEG, -1); // 2: index
 
-    GetArcControlPoint(&data[10], x2 - r, y2 - r, ARC_TO_BEZIER_90_DEG, -1); // 10: index
+    GetArcControlPoint(&data[10], x2 - br, y2 - br, ARC_TO_BEZIER_90_DEG, -1); // 10: index
 
-    GetArcControlPoint(&data[18], x2 - r, y1 + r, ARC_TO_BEZIER_90_DEG, -1); // 18: index
+    GetArcControlPoint(&data[18], x2 - tr, y1 + tr, ARC_TO_BEZIER_90_DEG, -1); // 18: index
 
-    GetArcControlPoint(&data[26], x1 + r, y1 + r, ARC_TO_BEZIER_90_DEG, -1); // 26: index
+    GetArcControlPoint(&data[26], x1 + tr, y1 + tr, ARC_TO_BEZIER_90_DEG, -1); // 26: index
 }
 
 static void GetEllipsePathData(const Point& center, uint16_t rx, uint16_t ry, Path& path)
@@ -468,5 +480,66 @@ void HWDrawUtils::Matrix4ToVguMatrix3(const Matrix4<float>& matrix, VGUMatrix3&
     vguMat.m[1][2] = data[13]; // 2, 13: index
     vguMat.m[2][2] = data[15]; // 2, 15: index
 }
+
+ColorMode HWDrawUtils::ConvertPixelFmt2ColorMode(PixelFormat fmt)
+{
+    switch (fmt) {
+        case PIXEL_FMT_RGBA_8888:
+            return ARGB8888;
+        case PIXEL_FMT_RGB_888:
+            return RGB888;
+        case PIXEL_FMT_RGB_565:
+            return RGB565;
+        case PIXEL_FMT_A8:
+            return A8;
+        case PIXEL_FMT_A1:
+            return A1;
+        default:
+            return UNKNOW;
+    }
+}
+
+PixelFormat HWDrawUtils::ConvertColorMode2PixelFmt(ColorMode mode)
+{
+    switch (mode) {
+        case ARGB8888:
+            return PIXEL_FMT_RGBA_8888;
+        case RGB888:
+            return PIXEL_FMT_RGB_888;
+        case RGB565:
+            return PIXEL_FMT_RGB_565;
+        case A8:
+            return PIXEL_FMT_A8;
+        case A1:
+            return PIXEL_FMT_A1;
+        default:
+            return PIXEL_FMT_BUTT;
+    }
+}
+
+void HWDrawUtils::ImageInfo2BufferInfo(const ImageInfo &imageInfo, BufferInfo &bufferInfo)
+{
+    bufferInfo.color = 0;
+    bufferInfo.rect = {0, 0, imageInfo.header.width - 1, imageInfo.header.height - 1};
+    bufferInfo.width = imageInfo.header.width;
+    bufferInfo.height = imageInfo.header.height;
+    bufferInfo.compressMode = imageInfo.header.compressMode;
+    bufferInfo.mode = static_cast<ColorMode>(imageInfo.header.colorMode);
+    bufferInfo.stride = static_cast<int32_t>(DisplayDev::GetInstance()->CalcStride(bufferInfo.width,
+        ConvertColorMode2PixelFmt(bufferInfo.mode), bufferInfo.compressMode));
+    bufferInfo.virAddr = static_cast<void*>(const_cast<uint8_t*>(imageInfo.data));
+    bufferInfo.phyAddr = bufferInfo.virAddr;
+}
+
+void HWDrawUtils::BufferInfo2ImageInfo(const BufferInfo &bufferInfo, ImageInfo &imageInfo)
+{
+    memset_s(&imageInfo, sizeof(imageInfo), 0, sizeof(imageInfo));
+    imageInfo.header.width = bufferInfo.width;
+    imageInfo.header.height = bufferInfo.height;
+    imageInfo.header.colorMode = bufferInfo.mode;
+    imageInfo.header.compressMode = bufferInfo.compressMode;
+    imageInfo.dataSize = bufferInfo.stride * bufferInfo.height;
+    imageInfo.data = static_cast<uint8_t*>(bufferInfo.virAddr);
+}
 }
 #endif
index 2280c0d..1050c42 100644 (file)
@@ -21,6 +21,8 @@
 #include "engines/gfx/gfx_engine_manager.h"
 #include "common/graphic_hardware_types.h"
 #include "display_vgu.h"
+#include "display_type.h"
+#include "gfx_utils/graphic_types.h"
 
 namespace OHOS {
 class HWDrawUtils : public HeapBase {
@@ -38,10 +40,15 @@ public:
     bool AllocBufferForPath(Path* path, uint16_t cmdNum, uint16_t dataNum);
     void FreeBufferForPath(Path* path);
     void Obtain30DegSectorPath(const ArcInfo& arc, float x, float y, uint8_t* cmd, float* data);
+    bool ObtainRectPathWithRadius(const Rect& rect, Path& path, int16_t topRadius, int16_t bottomRadius);
     bool ObtainRectPathWithRadius(const Rect& rect, Path& path, int16_t radius);
     bool ObtainEllipsePath(const Point& center, uint16_t rx, uint16_t ry, Path& path);
     void Matrix3ToVguMatrix3(const Matrix3<float>& matrix, VGUMatrix3& vguMat);
     void Matrix4ToVguMatrix3(const Matrix4<float>& matrix, VGUMatrix3& vguMat);
+    void ImageInfo2BufferInfo(const ImageInfo &imageInfo, BufferInfo &bufferInfo);
+    void BufferInfo2ImageInfo(const BufferInfo &bufferInfo, ImageInfo &imageInfo);
+    static ColorMode ConvertPixelFmt2ColorMode(PixelFormat fmt);
+    static PixelFormat ConvertColorMode2PixelFmt(ColorMode mode);
 
 private:
     HWDrawUtils() {}
@@ -49,6 +56,7 @@ private:
     void GetArcData(float* arcData, const ArcInfo& arc, uint32_t quaNum, float bezMore);
     void GetArcControlPoint(float* arcData, float centerX, float centerY, float mangicNum, int8_t neg);
     void GetFilledRoundRectData(float* data, uint16_t radius, const Rect& rect);
+    void GetFilledRoundRectData(float* data, uint16_t topRadius, uint16_t bottomRadius, const Rect& rect);
 };
 }
 #endif
index 3d066c5..2e0b483 100644 (file)
@@ -91,6 +91,13 @@ public:
         const Style& style,
         OpacityType opacity) override;
 
+    void DrawRect(BufferInfo& dst,
+        const Rect& rect,
+        const Rect& dirtyRect,
+        const Style& style,
+        OpacityType opacity,
+        TransformMap* transMap);
+
     void DrawTransform(BufferInfo& dst,
         const Rect& mask,
         const Point& position,
@@ -167,6 +174,7 @@ public:
     }
 
 #endif
+
 private:
     LiteMGfxEngine() {}
     virtual ~LiteMGfxEngine()
@@ -186,9 +194,9 @@ private:
     bool RotateBufferIfNecessary();
 #endif
     void DrawRectWithRound(BufferInfo& dst, const Rect& rect, const Style& style, const Rect& dirtyRect,
-        OpacityType opacity);
+        OpacityType opacity, VGUMatrix3* matrix = nullptr);
     void DrawRectWithoutRound(BufferInfo& dst, const Rect& rect, const Style& style, const Rect& dirtyRect,
-        OpacityType opacity);
+        OpacityType opacity, VGUMatrix3* matrix = nullptr);
     bool HandleImageSrc(const Image* imgSrc, VGUImage& image, const Style& style);
     void ReleasePath();
     void DrawArcInner(BufferInfo& dst, const ArcInfo& arcInfo, const Rect& mask,
@@ -205,7 +213,7 @@ private:
 #if ENABLE_VGU_ENGINE
     VGUFuncs* vguFuncs_ = nullptr;
     uint8_t blitNum_ = 0;
-    VGUImage images_[BLIT_COUNT_MAX] = {{PIXEL_FMT_BUTT}};
+    VGUImage images_[BLIT_COUNT_MAX] = {{{PIXEL_FMT_BUTT}}};
     VGUSurface surface_ = {{PIXEL_FMT_BUTT}};
     bool isHwDrawPending_ = false;
     uint16_t hwDrawPendingCnt_ = 0;
index 108e4da..1ad18e7 100644 (file)
@@ -109,7 +109,7 @@ RetCode HWJpegDecoder::DecodeJPEG(ImgResDsc& dsc)
     dst.uv_offset = dinfo_.output.size[0];
     dst.size = dinfo_.output.size[0] + dinfo_.output.size[1];
 
-    ImageInfo temp = {0};
+    ImageInfo temp = {{0}};
     temp.dataSize = dst.size;
     dst.phy_buf = reinterpret_cast<uint32_t>(ImageCacheMalloc(temp));
     dst.vir_buf = reinterpret_cast<char*>(dst.phy_buf);
@@ -143,20 +143,15 @@ static uint8_t Clamp(int16_t value, int16_t min, int16_t max)
 RetCode HWJpegDecoder::ConvertYUVToRGB(ImgResDsc& dsc, jpeg_dst_struct* dst)
 {
     uint8_t* yStart = reinterpret_cast<uint8_t*>(dst->vir_buf);
-    uint32_t yLength = dst->uv_offset;
     uint8_t* uvStart = reinterpret_cast<uint8_t*>(dst->vir_buf) + dst->uv_offset;
-    uint32_t uvLength = dinfo_.output.size[1];
 
     uint16_t imgWidth = dinfo_.output_width;
     uint16_t imgHeight = dinfo_.output_height;
     uint16_t alignedImgWidth = ALIGN_BYTE(imgWidth, BYTE_ALIGNMENT);
     uint32_t rgbSize = alignedImgWidth * imgHeight * 3; // 3: bpp of RGB888
-    ImageInfo tempImgInfo = {0};
+    ImageInfo tempImgInfo = {{0}};
     tempImgInfo.dataSize = rgbSize;
     uint8_t* rgbAddr = reinterpret_cast<uint8_t*>(ImageCacheMalloc(tempImgInfo));
-    uint32_t yIndex = 0;
-    uint32_t uvIndex = 0;
-    uint32_t pxIndex = 0;
     for (uint16_t i = 0; i < imgHeight; i++) {
         uint8_t* rowStart = rgbAddr + i * alignedImgWidth * 3; // 3: bpp of RGB888
         for (uint16_t j = 0; j < imgWidth; j++) {
index 6c392bd..18eb552 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 #include "imgdecode/jpeg_img_decoder.h"
-#if (ENABLE_JPEG_AND_PNG && CACHE_JPEG_AND_PNG)
+#if (ENABLE_JPEG_AND_PNG && CACHE_JPEG_AND_PNG && !CAPABILITY_HW_JPEG_DECODE)
 #include "gfx_utils/file.h"
 #include "gfx_utils/graphic_log.h"
 #include "gfx_utils/mem_api.h"
index faeb175..e1b723f 100644 (file)
@@ -17,7 +17,7 @@
 #define GRAPHIC_LITE_JPEG_IMG_DECODER_H
 
 #include "file_img_decoder.h"
-#if (ENABLE_JPEG_AND_PNG && CACHE_JPEG_AND_PNG)
+#if (ENABLE_JPEG_AND_PNG && CACHE_JPEG_AND_PNG && !CAPABILITY_HW_JPEG_DECODE)
 #include "draw/draw_image.h"
 #include "draw/draw_utils.h"
 #include "jpeglib.h"
index cb3a34d..5ed5b96 100644 (file)
 namespace OHOS {
 class CardFlipEffect : public CardSwipe {
 public:
-    CardFlipEffect(void) {}
+    CardFlipEffect(void)
+    {
+        isNeedClip_ = true;
+    }
     ~CardFlipEffect() override {}
     void CardSwipeAlg(UICardPage* leftCard, UICardPage* rightCard, int16_t xOffset) override;
     void CardSwipeAlg(UIImageView* leftCard, UIImageView* rightCard, int16_t xOffset) override;
index 067d5e8..a028b83 100644 (file)
@@ -134,6 +134,8 @@ void CubeEffect::CommonAlg(UIView* leftCard, UIView* rightCard, int16_t xOffset)
     if (leftCard != preLeftCard && rightCard != preRightCard) {\r
         leftImg_.SetPosition(0, 0, width, height);\r
         if (leftCard->GetViewType() == UI_IMAGE_VIEW) {\r
+            leftImg_.SetAutoEnable(false);\r
+            leftImg_.SetResizeMode(UIImageView::FILL);\r
             leftImg_.SetSrc(static_cast<UIImageView *>(leftCard)->GetImageInfo());\r
         }\r
         preLeftCard = leftCard;\r
@@ -141,6 +143,8 @@ void CubeEffect::CommonAlg(UIView* leftCard, UIView* rightCard, int16_t xOffset)
         preLeftCard->SetCameraDistance(CAMERA_DISTANCE);\r
         rightImg_.SetPosition(0, 0, width, height);\r
         if (rightCard->GetViewType() == UI_IMAGE_VIEW) {\r
+            rightImg_.SetAutoEnable(false);\r
+            rightImg_.SetResizeMode(UIImageView::FILL);\r
             rightImg_.SetSrc(static_cast<UIImageView *>(rightCard)->GetImageInfo());\r
         }\r
         preRightCard = rightCard;\r
index 7e2c8b4..0ff8dde 100644 (file)
 namespace OHOS {\r
 class CubeEffect : public CardSwipe {\r
 public:\r
-    CubeEffect(void) {}\r
+    CubeEffect(void)\r
+    {\r
+        isNeedClip_ = true;\r
+    }\r
     ~CubeEffect() override {}\r
     void CardSwipeAlg(UICardPage* leftCard, UICardPage* rightCard, int16_t xOffset) override;\r
     void CardSwipeAlg(UIImageView* leftCard, UIImageView* rightCard, int16_t xOffset) override;\r
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/push_press_effect.cpp b/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/push_press_effect.cpp
new file mode 100644 (file)
index 0000000..6e32ea0
--- /dev/null
@@ -0,0 +1,171 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.\r
+ * Description: PushPressEffect\r
+ * Create: 2025-04\r
+ */\r
+\r
+#include "securec.h"\r
+#include "common/screen.h"\r
+#include "push_press_effect.h"\r
+\r
+namespace OHOS {\r
+static constexpr int16_t CAMERA_DISTANCE = 600;\r
+static constexpr int16_t EASE_RANGE = 100;\r
+static constexpr float PERCENT = 100.f;\r
+static constexpr float SCALE_RANGE = 0.2f;\r
+static constexpr float SCALE_MAX = 1.0f;\r
+static constexpr int16_t NUM_2 = 2;\r
+\r
+void PushPressEffect::ResetPreviousCards(void)\r
+{\r
+    if (preLeftCard_ != nullptr) {\r
+        preLeftCard_->SetVisible(true);\r
+        preRightCard_->SetVisible(true);\r
+        preLeftCard_ = nullptr;\r
+        preRightCard_ = nullptr;\r
+        FreeInfo();\r
+    }\r
+}\r
+\r
+void PushPressEffect::StopEffect()\r
+{\r
+    ResetPreviousCards();\r
+    if (added_) {\r
+        container_->UIViewGroup::Remove(&leftImg_);\r
+        container_->UIViewGroup::Remove(&rightImg_);\r
+        added_ = false;\r
+    }\r
+    CardSwipe::StopEffect();\r
+}\r
+\r
+bool PushPressEffect::UpdateCardVisibility(UIView* leftCard, UIView* rightCard)\r
+{\r
+    if (preLeftCard_ == leftCard || preRightCard_ == rightCard) {\r
+        return true;\r
+    }\r
+\r
+    ResetPreviousCards();\r
+\r
+    if (leftCard->GetViewType() == UI_IMAGE_VIEW) {\r
+        lInfo_ = *(static_cast<UIImageView *>(leftCard)->GetImageInfo());\r
+        rInfo_ = *(static_cast<UIImageView *>(rightCard)->GetImageInfo());\r
+    } else {\r
+        FreeInfo();\r
+        if (!AllocInfo(leftCard, rightCard)) {\r
+            GRAPHIC_LOGE("get bitmap failed!");\r
+            return false;\r
+        }\r
+        lInfo_ = *leftInfo_;\r
+        rInfo_ = *rightInfo_;\r
+    }\r
+    leftCard->SetVisible(false);\r
+    rightCard->SetVisible(false);\r
+    preLeftCard_ = leftCard;\r
+    preRightCard_ = rightCard;\r
+    return true;\r
+}\r
+\r
+void PushPressEffect::ResetAndAddImages(void)\r
+{\r
+    if (!added_) {\r
+        leftImg_.SetAutoEnable(false);\r
+        leftImg_.SetResizeMode(UIImageView::ImageResizeMode::FILL);\r
+        leftImg_.SetCameraDistance(CAMERA_DISTANCE);\r
+        container_->Add(&leftImg_);\r
+\r
+        rightImg_.SetAutoEnable(false);\r
+        rightImg_.SetResizeMode(UIImageView::ImageResizeMode::FILL);\r
+        rightImg_.SetCameraDistance(CAMERA_DISTANCE);\r
+        container_->Add(&rightImg_);\r
+        added_ = true;\r
+    }\r
+    leftImg_.SetSrc(&lInfo_);\r
+    rightImg_.SetSrc(&rInfo_);\r
+}\r
+\r
+void PushPressEffect::FreeInfo(void)\r
+{\r
+    if (leftInfo_ != nullptr) {\r
+        ImageCacheFree(*leftInfo_);\r
+        delete leftInfo_;\r
+        leftInfo_ = nullptr;\r
+    }\r
+    if (rightInfo_ != nullptr) {\r
+        ImageCacheFree(*rightInfo_);\r
+        delete rightInfo_;\r
+        rightInfo_ = nullptr;\r
+    }\r
+}\r
+\r
+bool PushPressEffect::AllocInfo(UIView* leftCard, UIView* rightCard)\r
+{\r
+    if (leftCard == nullptr || rightCard == nullptr) {\r
+        return false;\r
+    }\r
+    leftInfo_ = new ImageInfo;\r
+    rightInfo_ = new ImageInfo;\r
+    if (leftInfo_ == nullptr || rightInfo_ == nullptr) {\r
+        delete leftInfo_;\r
+        delete rightInfo_;\r
+        return false;\r
+    }\r
+    memset_s(leftInfo_, sizeof(ImageInfo), 0, sizeof(ImageInfo));\r
+    memset_s(rightInfo_, sizeof(ImageInfo), 0, sizeof(ImageInfo));\r
+    leftCard->GetBitmap(*leftInfo_);\r
+    rightCard->GetBitmap(*rightInfo_);\r
+    return true;\r
+}\r
+\r
+void PushPressEffect::CommonAlg(UIView* leftCard, UIView* rightCard, int16_t xOffset)\r
+{\r
+    if (xOffset == 0) {\r
+        return;\r
+    }\r
+    static const int16_t middleHeight = height_ / NUM_2;\r
+    if (preLeftCard_ != leftCard && preRightCard_ != rightCard) {\r
+        if (!UpdateCardVisibility(leftCard, rightCard)) {\r
+            return;\r
+        }\r
+        ResetAndAddImages();\r
+    }\r
+\r
+    const float scaleFactor = EasingEquation::LinearEaseNone(0, EASE_RANGE, abs(xOffset), width_) / PERCENT;\r
+    const float outScale = SCALE_MAX - SCALE_RANGE * scaleFactor;\r
+    const float intScale = SCALE_MAX - SCALE_RANGE * (SCALE_MAX - scaleFactor);\r
+\r
+    int16_t cardWidth = 0;\r
+    float leftScale = 0;\r
+    float rightScale = 0;\r
+    if (xOffset > 0) {\r
+        cardWidth = xOffset;\r
+        leftScale = intScale;\r
+        rightScale = outScale;\r
+    } else {\r
+        cardWidth = width_ + xOffset;\r
+        leftScale = outScale;\r
+        rightScale = intScale;\r
+    }\r
+\r
+    Vector2<float> leftScaleCenter = {cardWidth / NUM_2, middleHeight};\r
+    Vector2<float> rightScaleCenter = {(width_ - cardWidth) / NUM_2, middleHeight};\r
+\r
+    leftImg_.SetPosition(0, 0, cardWidth, height_);\r
+    leftImg_.Scale(Vector2<float>(SCALE_MAX, leftScale), leftScaleCenter);\r
+    rightImg_.SetPosition(cardWidth, 0, width_ - cardWidth, height_);\r
+    rightImg_.Scale(Vector2<float>(SCALE_MAX, rightScale), rightScaleCenter);\r
+    return;\r
+}\r
+\r
+void PushPressEffect::CardSwipeAlg(UICardPage* leftCard, UICardPage* rightCard, int16_t xOffset)\r
+{\r
+    CardSwipe::CardSwipeAlg(leftCard, rightCard, xOffset);\r
+    CommonAlg(leftCard, rightCard, xOffset);\r
+}\r
+\r
+void PushPressEffect::CardSwipeAlg(UIImageView* leftCard, UIImageView* rightCard, int16_t xOffset)\r
+{\r
+    CardSwipe::CardSwipeAlg(leftCard, rightCard, xOffset);\r
+    CommonAlg(leftCard, rightCard, xOffset);\r
+}\r
+\r
+}\r
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/push_press_effect.h b/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/push_press_effect.h
new file mode 100644 (file)
index 0000000..a664ce0
--- /dev/null
@@ -0,0 +1,50 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.\r
+ * Description: PushPressEffect\r
+ * Create: 2025-04\r
+ */\r
+\r
+#ifndef PUSH_PRESS_EFFECT_H\r
+#define PUSH_PRESS_EFFECT_H\r
+#include "common/screen.h"\r
+#include "components/ui_cross_view.h"\r
+\r
+namespace OHOS {\r
+class PushPressEffect : public CardSwipe {\r
+public:\r
+    PushPressEffect(void)\r
+    {\r
+        isNeedClip_ = true;\r
+        width_ = Screen::GetInstance().GetWidth();\r
+        height_ = Screen::GetInstance().GetHeight();\r
+    }\r
+    ~PushPressEffect() override\r
+    {\r
+        FreeInfo();\r
+    }\r
+    void CardSwipeAlg(UICardPage* leftCard, UICardPage* rightCard, int16_t xOffset) override;\r
+    void CardSwipeAlg(UIImageView* leftCard, UIImageView* rightCard, int16_t xOffset) override;\r
+    void StopEffect() override;\r
+\r
+private:\r
+    int16_t width_;\r
+    int16_t height_;\r
+    UIImageView leftImg_;\r
+    UIImageView rightImg_;\r
+    bool added_ = false;\r
+    UIView* preLeftCard_ = nullptr;\r
+    UIView* preRightCard_ = nullptr;\r
+    ImageInfo* leftInfo_ = nullptr;\r
+    ImageInfo* rightInfo_ = nullptr;\r
+    ImageInfo lInfo_ = {0};\r
+    ImageInfo rInfo_ = {0};\r
+\r
+    void CommonAlg(UIView* leftCard, UIView* rightCard, int16_t xOffset);\r
+    void ResetAndAddImages(void);\r
+    void ResetPreviousCards(void);\r
+    bool UpdateCardVisibility(UIView* leftCard, UIView* rightCard);\r
+    void FreeInfo(void);\r
+    bool AllocInfo(UIView* leftCard, UIView* rightCard);\r
+};\r
+}\r
+#endif\r
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/windmill_effect.cpp b/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/windmill_effect.cpp
new file mode 100644 (file)
index 0000000..ad30cc9
--- /dev/null
@@ -0,0 +1,75 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.\r
+ * Description: WindmillEffect\r
+ * Create: 2025-04\r
+ */\r
+\r
+#include "common/screen.h"\r
+#include "engines/gfx/lite_m_gfx_engine.h"\r
+#include "windmill_effect.h"\r
+\r
+namespace OHOS {\r
+static constexpr int16_t EASE_RANGE = 30;\r
+static constexpr int16_t NUM_2 = 2;\r
+\r
+void WindmillEffect::StopEffect()\r
+{\r
+    if (preLeftCard_ != nullptr) {\r
+        preLeftCard_->ResetTransParameter();\r
+        preLeftCard_ = nullptr;\r
+    }\r
+\r
+    if (preRightCard_ != nullptr) {\r
+        preRightCard_->ResetTransParameter();\r
+        preRightCard_ = nullptr;\r
+    }\r
+\r
+    CardSwipe::StopEffect();\r
+}\r
+\r
+void WindmillEffect::CommonAlg(UIView* leftCard, UIView* rightCard, int16_t xOffset)\r
+{\r
+    if (xOffset == 0) {\r
+        leftCard->ResetTransParameter();\r
+        return;\r
+    }\r
+\r
+    if (preLeftCard_ != leftCard && preRightCard_ != rightCard) {\r
+        if (preLeftCard_ != nullptr) {\r
+            preLeftCard_->ResetTransParameter();\r
+        }\r
+        if (preRightCard_ != nullptr) {\r
+            preRightCard_->ResetTransParameter();\r
+        }\r
+        preLeftCard_ = leftCard;\r
+        preRightCard_ = rightCard;\r
+    }\r
+\r
+    Vector2<float> scaleCenter;\r
+    scaleCenter.x_ = width_ / NUM_2;\r
+    scaleCenter.y_ = height_;\r
+\r
+    float factor = 0;\r
+    factor = EasingEquation::LinearEaseNone(0, EASE_RANGE, abs(xOffset), width_);\r
+    if (xOffset > 0) {\r
+        leftCard->Rotate(-EASE_RANGE + factor, scaleCenter);\r
+        rightCard->Rotate(factor, scaleCenter);\r
+    } else {\r
+        leftCard->Rotate(-factor, scaleCenter);\r
+        rightCard->Rotate(EASE_RANGE - factor, scaleCenter);\r
+    }\r
+    return;\r
+}\r
+\r
+void WindmillEffect::CardSwipeAlg(UICardPage* leftCard, UICardPage* rightCard, int16_t xOffset)\r
+{\r
+    CardSwipe::CardSwipeAlg(leftCard, rightCard, xOffset);\r
+    CommonAlg(leftCard, rightCard, xOffset);\r
+}\r
+\r
+void WindmillEffect::CardSwipeAlg(UIImageView* leftCard, UIImageView* rightCard, int16_t xOffset)\r
+{\r
+    CardSwipe::CardSwipeAlg(leftCard, rightCard, xOffset);\r
+    CommonAlg(leftCard, rightCard, xOffset);\r
+}\r
+}\r
diff --git a/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/windmill_effect.h b/code/sdk/middleware/services/gui/uikit/proprietary/src/ui/frameworks/swipe_effect/windmill_effect.h
new file mode 100644 (file)
index 0000000..3c855d5
--- /dev/null
@@ -0,0 +1,35 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.\r
+ * Description: WindmillEffect\r
+ * Create: 2025-04\r
+ */\r
+\r
+#ifndef WINDMILL_EFFECT_H\r
+#define WINDMILL_EFFECT_H\r
+#include "components/ui_cross_view.h"\r
+\r
+namespace OHOS {\r
+class WindmillEffect : public CardSwipe {\r
+public:\r
+    WindmillEffect(void)\r
+    {\r
+        isNeedClip_ = true;\r
+        width_ = Screen::GetInstance().GetWidth();\r
+        height_ = Screen::GetInstance().GetHeight();\r
+    }\r
+    ~WindmillEffect() override {}\r
+    void CardSwipeAlg(UICardPage* leftCard, UICardPage* rightCard, int16_t xOffset) override;\r
+    void CardSwipeAlg(UIImageView* leftCard, UIImageView* rightCard, int16_t xOffset) override;\r
+    void StopEffect() override;\r
+\r
+private:\r
+    int16_t width_;\r
+    int16_t height_;\r
+    UIView* preLeftCard_ = nullptr;\r
+    UIView* preRightCard_ = nullptr;\r
+\r
+    void CommonAlg(UIView* leftCard, UIView* rightCard, int16_t xOffset);\r
+};\r
+\r
+}\r
+#endif\r
index 64d414a..1a4e576 100644 (file)
 namespace OHOS {
 class ZoomEffect : public CardSwipe {
 public:
-    ZoomEffect(void) {}
+    ZoomEffect(void)
+    {
+        isNeedClip_ = true;
+    }
     ~ZoomEffect() override {}
     void CardSwipeAlg(UICardPage* leftCard, UICardPage* rightCard, int16_t xOffset) override;
     void CardSwipeAlg(UIImageView* leftCard, UIImageView* rightCard, int16_t xOffset) override;
index 288a85e..5ad101a 100644 (file)
@@ -36,6 +36,11 @@ public:
         return selectedIndex_;\r
     }\r
 \r
+    UIViewType GetViewType() const override\r
+    {\r
+        return UI_OPTION_BOX;\r
+    }\r
+\r
     class OptionDragListener : public UIView::OnDragListener {\r
     public:\r
         explicit OptionDragListener(UIOptionBox* optBox) : box_(optBox) {}\r
index 4f06c90..7f186a1 100644 (file)
@@ -24,6 +24,7 @@
 #include "dfx/dfx_frame_trace.h"
 #include "imgdecode/image_load.h"
 #include "engines/gfx/lite_m_gfx_engine.h"
+#include "draw/hw_draw_utils.h"
 
 #ifndef _WIN32
 #include "tcxo.h"
@@ -64,6 +65,10 @@ void DisplayDev::LcdFlush(uint8_t layerId)
                 GRAPHIC_LOGE("flush failed.");
             }
             exitUlps_ = false;
+            if (pendingSurface_ != nullptr) {
+                pendingSurface_->ClearBuffers();
+                pendingSurface_ = nullptr;
+            }
             return;
         }
         uint8_t currentBufferIndex = currentBufferId_[layerId];
@@ -73,6 +78,8 @@ void DisplayDev::LcdFlush(uint8_t layerId)
         } else {
             buffer = &layer_[layerId].buffer[currentBufferIndex];
         }
+        SET_TRACE_FLUSH_TYPE(!((buffer->data.phyAddr >= PSRAM_BASE_ADDR) &&
+                               (buffer->data.phyAddr < PSRAM_BASE_ADDR + PSRAM_LENTH)));
         if (layerFuncs_->Flush(devId_, layer_[layerId].layerHdl, buffer) !=
             DISPLAY_SUCCESS) {
             GRAPHIC_LOGE("flush failed.");
@@ -231,6 +238,11 @@ bool DisplayDev::SwapBuffer(uint8_t layerId)
     return true;
 }
 
+void DisplayDev::SetPendingReleaseSurface(std::shared_ptr<LiteSurface> surface)
+{
+    pendingSurface_ = surface;
+}
+
 static uint32_t GetAlignedStride(uint32_t width, PixelFormat fmt, uint8_t cmpMode)
 {
     uint32_t bpp;
@@ -322,7 +334,6 @@ uint32_t DisplayDev::CalcSize(uint32_t stride, uint32_t height, uint8_t cmpMode)
         default:
             GRAPHIC_LOGE("unsupported compress mode: %d, just return 0.", cmpMode);
             return 0;
-            break;
     }
 
     return size;
@@ -749,21 +760,6 @@ void DisplayDev::DisplayDevClose()
 }
 
 #if defined(HW_ROTATE_ANGLE)
-static void ConvertPixelFormat2ColorMode(ColorMode& mode, PixelFormat fmt)
-{
-    switch (fmt) {
-        case PIXEL_FMT_RGBA_8888:
-            mode = ARGB8888;
-            break;
-        case PIXEL_FMT_RGB_888:
-            mode = RGB888;
-            break;
-        default:
-            mode = UNKNOW;
-            break;
-    }
-}
-
 bool LiteMGfxEngine::RotateBufferIfNecessary()
 {
     LayerRotateType rotateType = DisplayDev::GetInstance()->GetLayerRotateType(LAYER_0);
@@ -777,15 +773,12 @@ bool LiteMGfxEngine::RotateBufferIfNecessary()
         return false;
     }
 
-    int32_t rotateBufferWidth = rotateBuffer->width;
-    int32_t rotateBufferHeight = rotateBuffer->height;
-
     BufferInfo src;
     src.rect = {0, 0, static_cast<int16_t>(rotateBuffer->width - 1), static_cast<int16_t>(rotateBuffer->height - 1)};
     src.virAddr = rotateBuffer->data.virAddr;
     src.phyAddr = src.virAddr;
     src.stride = rotateBuffer->pitch;
-    ConvertPixelFormat2ColorMode(src.mode, rotateBuffer->pixFormat);
+    src.mode = HWDrawUtils::ConvertPixelFmt2ColorMode(rotateBuffer->pixFormat);
     src.color = 0;
     src.width = rotateBuffer->width;
     src.height = rotateBuffer->height;
@@ -796,7 +789,7 @@ bool LiteMGfxEngine::RotateBufferIfNecessary()
     dst.virAddr = buffer->data.virAddr;
     dst.phyAddr = dst.virAddr;
     dst.stride = buffer->pitch;
-    ConvertPixelFormat2ColorMode(dst.mode, buffer->pixFormat);
+    dst.mode = HWDrawUtils::ConvertPixelFmt2ColorMode(buffer->pixFormat);
     dst.color = 0;
     dst.width = buffer->width;
     dst.height = buffer->height;
index 26518b3..19ef476 100644 (file)
@@ -22,6 +22,7 @@
 #include "gfx_utils/heap_base.h"
 #include "gfx_utils/rect.h"
 #include "gfx_utils/pixel_format_utils.h"
+#include "common/lite_surface.h"
 
 namespace OHOS {
 enum class LayerRotateType {
@@ -158,6 +159,8 @@ public:
      */
     bool SwapBuffer(uint8_t layerId);
 
+    void SetPendingReleaseSurface(std::shared_ptr<LiteSurface> surface);
+
     struct Layer {
         uint32_t layerHdl;
         LayerInfo layerInfo;
@@ -192,6 +195,7 @@ private:
     const uint8_t layerBpp_ = 24;
     const PixelFormat layerPixFmt_ = PIXEL_FMT_RGB_888;
 #endif
+    std::shared_ptr<LiteSurface> pendingSurface_;
 };
 } // namespace OHOS
 #endif // GRAPHIC_LITE_DISPLAY_DEV_H
index 07e2291..86d2e23 100644 (file)
@@ -7,6 +7,10 @@ set(UIKIT_ROOT_DIR ${PROJECT_ROOT_DIR}/uikit)
 set(COMPONENT_NAME "uikit_test")
 
 file(GLOB_RECURSE src_file ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
+if(NOT "JS_ENABLE" IN_LIST DEFINES)
+    file(GLOB files_to_remove "${CMAKE_CURRENT_SOURCE_DIR}/uitest/components/ui_test_transition/*.cpp")
+    list(REMOVE_ITEM src_file ${files_to_remove})
+endif()
 list(REMOVE_ITEM src_file ${CMAKE_CURRENT_SOURCE_DIR}/components/test_bitmap_font.cpp)
 list(REMOVE_ITEM src_file ${CMAKE_CURRENT_SOURCE_DIR}/uitest/components/ui_test_bitmap_font/ui_test_bitmap_font.cpp)
 list(REMOVE_ITEM src_file ${CMAKE_CURRENT_SOURCE_DIR}/uitest/components/ui_test_font/ui_test_font_global.cpp)
@@ -48,6 +52,13 @@ set(PRIVATE_HEADER
     ${ROOTDIR}/open_source/openharmony/foundation/multimedia/utils/include
 )
 
+if("JS_ENABLE" IN_LIST DEFINES)
+set(PRIVATE_HEADER
+    ${PRIVATE_HEADER}
+    ${ROOTDIR}/application/wearable/nativeabilityfwk/include
+)
+endif()
+
 set(PRIVATE_DEFINES
     ${CCDEFINES}
 )
index 112a3d4..dfa83c4 100644 (file)
  */
 
 #include "sample_ui.h"
+#include "debug_print.h"
+#include "ui_test.h"
 #include "ui_test_app.h"
+#include "ui_test_group.h"
+#include "test_case_list_adapter.h"
 #include "common/screen.h"
 #include "components/root_view.h"
 #include "graphic_config.h"
 #include "graphic_service.h"
 #include "common/graphic_startup.h"
+#include "gfx_utils/mem_check.h"
 
 int SampleUi()
 {
@@ -30,3 +35,74 @@ int SampleUi()
     });
     return 0;
 }
+
+class BackButton : public OHOS::UIButton {
+public:
+    static BackButton* GetInstance()
+    {
+        static BackButton instance;
+        return &instance;
+    }
+
+    bool OnClickEvent(const OHOS::ClickEvent &event) override
+    {
+        OHOS::RootView::GetInstance()->RemoveAll();
+        OHOS::UITest* uiTest = OHOS::UITestGroup::GetInstance()->GetTestCase(caseId.c_str());
+        if (uiTest != nullptr) {
+            uiTest->TearDown();
+            PRINT("[Memory Info After TearDown]\n");
+            OHOS::MemCheck::GetInstance()->DumpMemInfo();
+        }
+        OHOS::UITestApp::GetInstance()->Init();
+        return true;
+    }
+    
+    void SetCaseId(const char* s)
+    {
+        caseId = s;
+    }
+
+private:
+    BackButton() : OHOS::UIButton()
+    {
+        opaScale_ = 0;
+    }
+
+    std::string caseId;
+};
+
+int StartCaseUi(const char* testCaseId)
+{
+    BackButton::GetInstance()->SetPosition(0,
+        (OHOS::Screen::GetInstance().GetHeight() - 50) / 2, 50, 50); // 2 : half ;  50 : offset
+    
+    GraphicService::GetInstance()->PostGraphicEvent([testCaseId] {
+        OHOS::UIViewGroup* rootView = OHOS::RootView::GetInstance();
+
+        OHOS::UITest* uiTest = OHOS::UITestGroup::GetInstance()->GetTestCase(testCaseId);
+        if (uiTest == nullptr) {
+            PRINT("[Auto Test]: test case [%s] not find \n", testCaseId);
+            return;
+        }
+        PRINT("[Memory Info Before Setup]\n");
+        OHOS::MemCheck::GetInstance()->DumpMemInfo();
+        uiTest->SetUp();
+        OHOS::UIView* tempView = const_cast<OHOS::UIView*>(uiTest->GetTestView());
+        if (tempView != nullptr) {
+            rootView->RemoveAll();
+            tempView->SetTouchable(true);
+            tempView->SetViewId(testCaseId);
+            tempView->SetPosition(tempView->GetX(), tempView->GetY());
+            rootView->Add(tempView);
+            BackButton::GetInstance()->SetCaseId(testCaseId);
+            rootView->Add(BackButton::GetInstance());
+            rootView->Invalidate();
+            PRINT("[Auto Test]: test case view [%s] started \n", testCaseId);
+        } else {
+            PRINT("[Auto Test]: error, case view is null \n", testCaseId);
+            return;
+        }
+        return;
+    });
+    return 0;
+}
index f4d5cb4..1a63174 100644 (file)
@@ -1,16 +1,8 @@
 /*
- * Copyright (c) 2022 CompanyNameMagicTag.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: sample utils
+ * Author: Hisi Graphic Team
+ * Created: 2025-7
  */
 
 #ifndef SAMPLE_UI_H
@@ -22,6 +14,12 @@ extern "C" {
 
 int SampleUi(void);
 
+/*
+  ¹¦ÄÜÃèÊö     :  Æô¶¯Ö¸¶¨ÓÃÀý
+  ²ÎÊýÄÚÈÝ     :  ²ÎÊýΪÓÃÀýÃû³Æ
+*/
+int StartCaseUi(const char* testCaseId);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/code/sdk/middleware/services/gui/uikit/sample/sample_util.cpp b/code/sdk/middleware/services/gui/uikit/sample/sample_util.cpp
new file mode 100644 (file)
index 0000000..58c251e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: sample utils
+ * Author: Hisi Graphic Team
+ * Created: 2025-7
+ */
+#include "debug_print.h"
+#include "common/screen.h"
+#include "components/root_view.h"
+#include "gfx_utils/image_info.h"
+#include "gfx_utils/rect.h"
+#include "mbedtls/sha256.h"
+#include "graphic_service.h"
+#include "hals/display_dev.h"
+#include "imgdecode/image_load.h"
+#include "draw/draw_utils.h"
+#include "gfx_utils/graphic_types.h"
+#include "sample_util.h"
+
+int CalcSampleUiHash(const char* viewId)
+{
+    GraphicService::GetInstance()->PostGraphicEvent([] {
+        OHOS::RootView::GetInstance()->Invalidate();
+    });
+
+    GraphicService::GetInstance()->PostGraphicEvent([viewId] {
+        OHOS::ImageInfo info = {0};
+        OHOS::Screen::GetInstance().GetScreenBitmapByRect(info, nullptr, 1.0, true); // 1.0: scale factor
+        
+        // mbedtls_sha256 方法要求32位
+        unsigned char* hash = new unsigned char[32];
+        mbedtls_sha256(info.data, info.dataSize, hash, 0);
+        ImageCacheFree(info);
+
+        // 65: 32*2+1,32位hash数组每位按照16进制输出长度为2,再加上一个结束符
+        char* output =  new char[65];
+        for (int i = 0; i < 32; i++) { // 32: 长度
+            sprintf_s(output + (i * 2), 3, "%02x", hash[i]); // 2:位; 3:多一个结束符
+        }
+        PRINT("screen hash value of %s=[%s] \n", viewId, output);
+        
+        delete[] hash;
+        delete[] output;
+    });
+   
+    return 0;
+}
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/sample_util.h b/code/sdk/middleware/services/gui/uikit/sample/sample_util.h
new file mode 100644 (file)
index 0000000..f447f2b
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: sample utils
+ * Author: Hisi Graphic Team
+ * Created: 2025-7
+ */
+
+#ifndef SAMPLE_UTIL_H
+#define SAMPLE_UTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+  功能描述 :  计算当前画面截图后文件的hash值,并打印出来。
+  参数内容 :  参数包含一个参数(key),打印在时一同输出。用于关联定位。
+*/
+int CalcSampleUiHash(const char* viewId);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_analog_clock/test_resource_config.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_analog_clock/test_resource_config.h
new file mode 100644 (file)
index 0000000..f899a88
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+ 
+#ifndef TEST_RESOURCE_CONFIG_H
+#define TEST_RESOURCE_CONFIG_H
+ 
+namespace OHOS {
+#if defined QT_COMPILER
+#define IMAGE_DIR "..\\..\\simulator\\config\\images\\"
+#define FACE_DIR "..\\..\\simulator\\config\\faces\\default\\"
+#elif defined _WIN32
+#define IMAGE_DIR "..\\config\\images\\"
+#define FACE_DIR "..\\config\\faces\\default\\"
+#else
+#define IMAGE_DIR RES_PATH
+#define FACE_DIR RES_PATH
+#endif
+ 
+#define BLUE_RGB888_IMAGE_PATH (IMAGE_DIR "blue_rgb888.bin")
+#define BLUE_ARGB8888_IMAGE_PATH (IMAGE_DIR "blue_argb8888.bin")
+#define BLUE_RGB565_IMAGE_PATH (IMAGE_DIR "blue_rgb565.bin")
+#define BLUE_IMAGE_PATH (IMAGE_DIR "blue.png")
+#define RED_IMAGE_PATH (IMAGE_DIR "red.png")
+#define GREEN_IMAGE_PATH (IMAGE_DIR "green.png")
+#define YELLOW_IMAGE_PATH (IMAGE_DIR "yellow.png")
+#define IMAGE_ANIMATOR_0_PATH (IMAGE_DIR "image_animator_0.bin")
+#define IMAGE_ANIMATOR_1_PATH (IMAGE_DIR "image_animator_1.bin")
+#define IMAGE_ANIMATOR_2_PATH (IMAGE_DIR "image_animator_2.bin")
+#define IMAGE_ANIMATOR_3_PATH (IMAGE_DIR "image_animator_3.bin")
+#define B024_002_IMAGE_PATH (FACE_DIR "B024_002.bin")
+#define B024_009_IMAGE_PATH (FACE_DIR "B024_009.bin")
+#define B024_010_IMAGE_PATH (FACE_DIR "B024_010.bin")
+#define B024_011_IMAGE_PATH (FACE_DIR "B024_011.bin")
+#define SLIDER_BACKGROUND_IMAGE_PATH (IMAGE_DIR "sliderBackground.bin")
+#define SLIDER_INDICATOR_IMAGE_PATH (IMAGE_DIR "sliderIndicator.bin")
+#define SLIDER_KNOB_IMAGE_PATH (IMAGE_DIR "sliderKnob.bin")
+#define JPEG_IMAGE_PATH (IMAGE_DIR "jpeg.jpg")
+#define PNG_1_PALETTE_IMAGE_PATH (IMAGE_DIR "png_1_palette.png")
+#define PNG_2_PALETTE_IMAGE_PATH (IMAGE_DIR "png_2_palette.png")
+#define PNG_4_PALETTE_IMAGE_PATH (IMAGE_DIR "png_4_palette.png")
+#define PNG_8_PALETTE_IMAGE_PATH (IMAGE_DIR "png_8_palette.png")
+#define PNG_8_GRAY_IMAGE_PATH (IMAGE_DIR "png_8_gray.png")
+#define PNG_16_GRAY_IMAGE_PATH (IMAGE_DIR "png_16_gray.png")
+#define PNG_24_RGB_IMAGE_PATH (IMAGE_DIR "png_24_rgb.png")
+#define PNG_32_RGB_ALPHA_IMAGE_PATH (IMAGE_DIR "png_32_rgba.png")
+#ifndef VERSION_LITE
+#define GIF_IMAGE_PATH1 (IMAGE_DIR "gif_image1.gif")
+#define GIF_IMAGE_PATH2 (IMAGE_DIR "gif_image2.gif")
+#define GIF_IMAGE_PATH_ERROR (IMAGE_DIR "gif_error.gif")
+#define TIF_IMAGE_PATH (IMAGE_DIR "tif_image.tif")
+#endif
+#define VIDEO_SOURCE_DIRECTORY (IMAGE_DIR "video.mp4")
+#define TEST_RIGHT_ARROW (IMAGE_DIR "ic_arrow_right.png")
+#define TEST_BACK_LEFT_ARROW (IMAGE_DIR "ic_back.png")
+#define TEST_CIRCLE_FORE_IMAGE (FACE_DIR "fore.png")
+} // namespace OHOS
+#endif // TEST_RESOURCE_CONFIG_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_analog_clock/ui_test_analog_clock.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_analog_clock/ui_test_analog_clock.cpp
new file mode 100644 (file)
index 0000000..003451d
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_analog_clock.h"
+#include "common/screen.h"
+#include "components/ui_analog_clock.h"
+#include "components/ui_image_view.h"
+#include "components/ui_label.h"
+#include "test_resource_config.h"
+
+namespace OHOS {
+namespace {
+const uint8_t BUTTON_TEXT_SIZE = 16;
+const uint8_t BUTTON_WIDTH = 120;
+const uint8_t BUTTON_HEIGHT = 40;
+const uint16_t offsetX = 102;
+const uint16_t offsetY = 10;
+const uint16_t offHeight = 30;
+const uint16_t clock_positionx_ = 150;
+const uint16_t clock_positiony_ = 70;
+const uint16_t offset_ = 50;
+const uint16_t offset2_ = 100;
+const uint16_t offset3_ = 150;
+const uint16_t offset4_ = 200;
+const uint16_t diff_ = 100;
+const uint16_t width_ = 58;
+const uint16_t move_ = 100;
+const uint16_t width1_ = 48;
+} // namespace
+
+void UITestAnalogClock::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+    }
+}
+
+void UITestAnalogClock::TearDown()
+{
+    if (animator_ != nullptr) {
+        delete animator_;
+        delete callback_;
+        animator_ = nullptr;
+        callback_ = nullptr;
+    }
+
+    if (animator2_ != nullptr) {
+        delete animator2_;
+        delete callback2_;
+        animator2_ = nullptr;
+        callback2_ = nullptr;
+    }
+    if (changeModeListener_ != nullptr) {
+        delete changeModeListener_;
+        changeModeListener_ = nullptr;
+    }
+    if (clickMoveLeftListener_ != nullptr) {
+        delete clickMoveLeftListener_;
+        clickMoveLeftListener_ = nullptr;
+    }
+    if (clickMoveRightListener_ != nullptr) {
+        delete clickMoveRightListener_;
+        clickMoveRightListener_ = nullptr;
+    }
+    if (clickMoveTopListener_ != nullptr) {
+        delete clickMoveTopListener_;
+        clickMoveTopListener_ = nullptr;
+    }
+    if (clickMoveBottomListener_ != nullptr) {
+        delete clickMoveBottomListener_;
+        clickMoveBottomListener_ = nullptr;
+    }
+    if (changeModeListener1_ != nullptr) {
+        delete changeModeListener1_;
+        changeModeListener1_ = nullptr;
+    }
+    if (clickMoveLeftListener1_ != nullptr) {
+        delete clickMoveLeftListener1_;
+        clickMoveLeftListener1_ = nullptr;
+    }
+    if (clickMoveRightListener1_ != nullptr) {
+        delete clickMoveRightListener1_;
+        clickMoveRightListener1_ = nullptr;
+    }
+    if (clickMoveTopListener1_ != nullptr) {
+        delete clickMoveTopListener1_;
+        clickMoveTopListener1_ = nullptr;
+    }
+    if (clickMoveBottomListener1_ != nullptr) {
+        delete clickMoveBottomListener1_;
+        clickMoveBottomListener1_ = nullptr;
+    }
+    DeleteChildren(container_);
+    container_ = nullptr;
+}
+
+const UIView* UITestAnalogClock::GetTestView()
+{
+    UIKitTestLineHandAnalogClock001();
+    UIKitTestImageHandAnalogClock002();
+    return container_;
+}
+
+class TestBtnOnClickChangeModeListener : public UIView::OnClickListener {
+public:
+    TestBtnOnClickChangeModeListener(UIView* uiView, UIAnalogClock* clock) : uiView_(uiView), clock_(clock) {}
+    ~TestBtnOnClickChangeModeListener() {}
+    bool OnClick(UIView& view, const ClickEvent& event) override
+    {
+        if (clock_->GetWorkMode() == UIAbstractClock::ALWAYS_ON) {
+            clock_->SetWorkMode(UIAbstractClock::NORMAL);
+        } else {
+            clock_->SetWorkMode(UIAbstractClock::ALWAYS_ON);
+        }
+        return true;
+    }
+
+    UIView* uiView_;
+    UIAnalogClock* clock_;
+};
+
+class TestBtnOnClickMovePositionListener : public UIView::OnClickListener {
+public:
+    enum class MoveType {
+        MOVE_LEFT,
+        MOVE_RIGHT,
+        MOVE_TOP,
+        MOVE_BOTTOM,
+    };
+    TestBtnOnClickMovePositionListener(UIView* uiView, UIAnalogClock* clock, MoveType type, uint16_t grid)
+        : uiView_(uiView), clock_(clock), type_(type), grid_(grid)
+    {
+    }
+    ~TestBtnOnClickMovePositionListener() {}
+    bool OnClick(UIView& view, const ClickEvent& event) override
+    {
+        int16_t xPos = clock_->GetX();
+        int16_t yPos = clock_->GetY();
+        clock_->Invalidate();
+        if (type_ == MoveType::MOVE_LEFT) {
+            xPos -= grid_;
+        } else if (type_ == MoveType::MOVE_RIGHT) {
+            xPos += grid_;
+        } else if (type_ == MoveType::MOVE_TOP) {
+            yPos -= grid_;
+        } else if (type_ == MoveType::MOVE_BOTTOM) {
+            yPos += grid_;
+        }
+        clock_->SetPosition(xPos, yPos);
+        return true;
+    }
+
+    UIView* uiView_;
+    UIAnalogClock* clock_;
+    MoveType type_;
+    uint16_t grid_;
+};
+
+void UITestAnalogClock::UIKitTestLineHandAnalogClock001()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group1 = new UIViewGroup();
+        group1->SetPosition(0, 0);
+        group1->SetWidth(Screen::GetInstance().GetWidth());
+        group1->SetHeight(Screen::GetInstance().GetHeight() + diff_); // 100: height bigger value
+        container_->Add(group1);
+
+        UILabel* label = new UILabel();
+        group1->Add(label);
+        // 30: height
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE + offsetX, TEXT_DISTANCE_TO_TOP_SIDE + offsetY,
+            Screen::GetInstance().GetWidth(), offHeight);
+        label->SetText("直线指针效果");
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+
+        UIAnalogClock* clock1 = new UIAnalogClock();
+        group1->Add(clock1);
+        clock1->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE2, VIEW_DISTANCE_TO_TOP_SIDE,
+                            Screen::GetInstance().GetWidth() / 2, // 2: half of screen width
+                            Screen::GetInstance().GetHeight());
+
+        UIImageView* curFace = new UIImageView();
+        curFace->SetSrc(B024_002_IMAGE_PATH);
+        clock1->Add(curFace);
+        curFace->SetPosition(0, 0);
+        // 214: position x 3:position y 14:center x 223:center y 1: width 223:height 255: opacity
+        clock1->SetHandLine(UIAnalogClock::HandType::SECOND_HAND, {214, 3}, {14, 223}, Color::White(), 1, 223, 255);
+        // 202: position x 25:position y 25:center x 201:center y 3: width 201:height 255: opacity
+        clock1->SetHandLine(UIAnalogClock::HandType::MINUTE_HAND, {202, 25}, {25, 201}, Color::Green(), 3, 201, 255);
+        // 202: position x 95:position y 25:center x 132:center y 5: width 132: height 255: opacity
+        clock1->SetHandLine(UIAnalogClock::HandType::HOUR_HAND, {202, 95}, {25, 132}, Color::Red(), 5, 132, 255);
+        clock1->SetInitTime24Hour(0, 0, 0);
+        clock1->SetWorkMode(UIAnalogClock::WorkMode::NORMAL);
+        clock1->SetTime24Hour(10, 3, 20); // 10: hour; 3: minute: 20: second
+        CreateButtons001(group1, curFace, clock1);
+        callback_ = new ClockAnimatorCallback(clock1);
+        animator_ = new Animator(callback_, clock1, 0, true);
+        animator_->Start();
+    }
+}
+
+void UITestAnalogClock::CreateButtons001(UIViewGroup* group, UIImageView* curFace, UIAnalogClock* clock)
+{
+    if ((group == nullptr) || (curFace == nullptr) || (clock == nullptr)) {
+        return;
+    }
+    UILabelButton* button1 = SetUpButton("切换模式");
+    group->Add(button1);
+    // 58: increase x-position; 48: y-position
+    button1->SetPosition(curFace->GetWidth() + width_, clock_positiony_, BUTTON_WIDTH, BUTTON_HEIGHT);
+    if (changeModeListener_ == nullptr) {
+        changeModeListener_ = static_cast<UIView::OnClickListener*>(
+            new TestBtnOnClickChangeModeListener(static_cast<UIView*>(button1), clock));
+    }
+    button1->SetOnClickListener(changeModeListener_);
+
+    UILabelButton* button2 = SetUpButton("左移");
+    group->Add(button2);
+    // 58: increase x-position; 58: increase y-position
+    button2->SetPosition(curFace->GetWidth() + width_, clock_positiony_ + offset_, BUTTON_WIDTH, BUTTON_HEIGHT);
+    if (clickMoveLeftListener_ == nullptr) {
+        clickMoveLeftListener_ = static_cast<UIView::OnClickListener*>(
+            new TestBtnOnClickMovePositionListener(
+            static_cast<UIView*>(button2), clock,
+            TestBtnOnClickMovePositionListener::MoveType::MOVE_LEFT, 10)); // 10: grid
+    }
+    button2->SetOnClickListener(clickMoveLeftListener_);
+
+    UILabelButton* button3 = SetUpButton("右移");
+    group->Add(button3);
+    // 58: increase x-position; 148: y-position
+    button3->SetPosition(curFace->GetWidth() + width_, clock_positiony_ + offset2_, BUTTON_WIDTH, BUTTON_HEIGHT);
+    if (clickMoveRightListener_ == nullptr) {
+        clickMoveRightListener_ = static_cast<UIView::OnClickListener*>(
+            new TestBtnOnClickMovePositionListener(
+            static_cast<UIView*>(button3), clock,
+            TestBtnOnClickMovePositionListener::MoveType::MOVE_RIGHT, 10)); // 10: grid
+    }
+    button3->SetOnClickListener(clickMoveRightListener_);
+
+    UILabelButton* button4 = SetUpButton("上移");
+    group->Add(button4);
+    // 58: increase x-position; 198: y-position
+    button4->SetPosition(curFace->GetWidth() + width_, clock_positiony_ + offset3_, BUTTON_WIDTH, BUTTON_HEIGHT);
+    if (clickMoveTopListener_ == nullptr) {
+        clickMoveTopListener_ = static_cast<UIView::OnClickListener*>(
+            new TestBtnOnClickMovePositionListener(
+            static_cast<UIView*>(button4), clock,
+            TestBtnOnClickMovePositionListener::MoveType::MOVE_TOP, 10)); // 10: move value
+    }
+    button4->SetOnClickListener(clickMoveTopListener_);
+
+    UILabelButton* button5 = SetUpButton("下移");
+    group->Add(button5);
+    // 58: increase x-position; 248: y-position
+    button5->SetPosition(curFace->GetWidth() + width_, clock_positiony_ + offset4_, BUTTON_WIDTH, BUTTON_HEIGHT);
+    if (clickMoveBottomListener_ == nullptr) {
+        clickMoveBottomListener_ = static_cast<UIView::OnClickListener*>(
+            new TestBtnOnClickMovePositionListener(
+            static_cast<UIView*>(button5), clock,
+            TestBtnOnClickMovePositionListener::MoveType::MOVE_BOTTOM, 10)); // 10: move value
+    }
+    button5->SetOnClickListener(clickMoveBottomListener_);
+}
+
+void UITestAnalogClock::UIKitTestImageHandAnalogClock002()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group2 = new UIViewGroup();
+        group2->SetPosition(0, Screen::GetInstance().GetHeight() - diff_); // 50: increase y-coordinate
+        group2->SetWidth(Screen::GetInstance().GetWidth());
+        group2->SetHeight(Screen::GetInstance().GetHeight() + diff_); // 100: increase y-coordinate
+        container_->Add(group2);
+
+        UILabel* label = new UILabel();
+        group2->Add(label);
+        label->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE + offsetX, 0, Screen::GetInstance().GetWidth(), offHeight);
+        label->SetText("图片指针效果");
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+
+        UIImageView* image1 = new UIImageView();
+        image1->SetSrc(B024_010_IMAGE_PATH);
+        UIImageView* image2 = new UIImageView();
+        image2->SetSrc(B024_011_IMAGE_PATH);
+        UIImageView* image3 = new UIImageView();
+        image3->SetSrc(B024_009_IMAGE_PATH);
+
+        UIAnalogClock* clock2 = new UIAnalogClock();
+        group2->Add(clock2);
+        clock2->SetDragParentInstead(true);
+        clock2->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE2, VIEW_DISTANCE_TO_TOP_SIDE,
+                            Screen::GetInstance().GetWidth() / 2, // 2: half of screen width
+                            Screen::GetInstance().GetHeight());
+
+        UIImageView* curFace = new UIImageView();
+        curFace->SetSrc(B024_002_IMAGE_PATH);
+        clock2->Add(curFace);
+        curFace->SetPosition(0, 0);
+        // {214, 3}: position x, y {14, 223}: center x, y
+        clock2->SetHandImage(UIAnalogClock::HandType::SECOND_HAND, *image1, {214, 3}, {14, 223});
+        // {202, 15}: position x, y {25, 211}: center x, y
+        clock2->SetHandImage(UIAnalogClock::HandType::MINUTE_HAND, *image2, {202, 15}, {25, 211});
+        // {202, 15}: position x, y {25, 211}: center x, y
+        clock2->SetHandImage(UIAnalogClock::HandType::HOUR_HAND, *image3, {202, 15}, {25, 211});
+
+        clock2->SetInitTime24Hour(0, 0, 0);
+        clock2->SetWorkMode(UIAnalogClock::WorkMode::NORMAL);
+        clock2->SetTime24Hour(3, 3, 15); // 3: hour; 3: minute: 15: second
+        CreateButtons002(group2, curFace, clock2);
+        callback2_ = new ClockAnimatorCallback(clock2);
+        animator2_ = new Animator(callback2_, clock2, 0, true);
+        animator2_->Start();
+    }
+}
+
+void UITestAnalogClock::CreateButtons002(UIViewGroup* group, UIImageView* curFace, UIAnalogClock* clock)
+{
+    if ((group == nullptr) || (curFace == nullptr) || (clock == nullptr)) {
+        return;
+    }
+    UILabelButton* button1 = SetUpButton("切换模式");
+    group->Add(button1);
+    // 58: increase x-coordinate; 48: y-coordinate
+    button1->SetPosition(curFace->GetWidth() + width_, width1_, BUTTON_WIDTH, BUTTON_HEIGHT);
+    if (changeModeListener1_ == nullptr) {
+        changeModeListener1_ = static_cast<UIView::OnClickListener*>(
+            new TestBtnOnClickChangeModeListener(static_cast<UIView*>(button1), clock));
+    }
+    button1->SetOnClickListener(changeModeListener1_);
+
+    UILabelButton* button2 = SetUpButton("左移");
+    group->Add(button2);
+    // 58: increase x-coordinate; 98: y-coordinate
+    button2->SetPosition(curFace->GetWidth() + width_, width1_ + offset_, BUTTON_WIDTH, BUTTON_HEIGHT);
+    if (clickMoveLeftListener1_ == nullptr) {
+        clickMoveLeftListener1_ = static_cast<UIView::OnClickListener*>(
+            new TestBtnOnClickMovePositionListener(
+            static_cast<UIView*>(button2), clock,
+            TestBtnOnClickMovePositionListener::MoveType::MOVE_LEFT, move_)); // 10: grid
+    }
+    button2->SetOnClickListener(clickMoveLeftListener1_);
+
+    UILabelButton* button3 = SetUpButton("右移");
+    group->Add(button3);
+    // 58: increase x-coordinate; 148: y-coordinate
+    button3->SetPosition(curFace->GetWidth() + width_, width1_ + offset2_, BUTTON_WIDTH, BUTTON_HEIGHT);
+    if (clickMoveRightListener1_ == nullptr) {
+        clickMoveRightListener1_ = static_cast<UIView::OnClickListener*>(
+            new TestBtnOnClickMovePositionListener(
+            static_cast<UIView*>(button3), clock,
+            TestBtnOnClickMovePositionListener::MoveType::MOVE_RIGHT, move_)); // 10: move value
+    }
+    button3->SetOnClickListener(clickMoveRightListener1_);
+
+    UILabelButton* button4 = SetUpButton("上移");
+    group->Add(button4);
+    // 58: increase x-coordinate; 198: y-coordinate
+    button4->SetPosition(curFace->GetWidth() + width_, width1_ + offset3_, BUTTON_WIDTH, BUTTON_HEIGHT);
+    if (clickMoveTopListener1_ == nullptr) {
+        clickMoveTopListener1_ = static_cast<UIView::OnClickListener*>(
+            new TestBtnOnClickMovePositionListener(
+            static_cast<UIView*>(button4), clock,
+            TestBtnOnClickMovePositionListener::MoveType::MOVE_TOP, move_)); // 10: move value
+    }
+    button4->SetOnClickListener(clickMoveTopListener1_);
+    UILabelButton* button5 = SetUpButton("下移");
+    group->Add(button5);
+    // 58: increase x-coordinate; 248: y-coordinate
+    button5->SetPosition(curFace->GetWidth() + width_, width1_ + offset4_, BUTTON_WIDTH, BUTTON_HEIGHT);
+    /* Move bottom */
+    if (clickMoveBottomListener1_ == nullptr) {
+        clickMoveBottomListener1_ = static_cast<UIView::OnClickListener*>(
+            new TestBtnOnClickMovePositionListener(
+            static_cast<UIView*>(button5), clock,
+            TestBtnOnClickMovePositionListener::MoveType::MOVE_BOTTOM, move_)); // 10: move value
+    }
+    button5->SetOnClickListener(clickMoveBottomListener1_);
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_analog_clock/ui_test_analog_clock.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_analog_clock/ui_test_analog_clock.h
new file mode 100644 (file)
index 0000000..1421630
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_ANALOG_CLOCK1_H
+#define UI_TEST_ANALOG_CLOCK1_H
+
+#include "ui_test.h"
+
+#include "components/ui_analog_clock.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+
+namespace OHOS {
+class ClockAnimatorCallback : public AnimatorCallback {
+public:
+    explicit ClockAnimatorCallback(UIAnalogClock* clock) : clock_(clock) {}
+    ~ClockAnimatorCallback() {};
+    virtual void Callback(UIView* view)
+    {
+        count_++;
+        if ((count_ == 30) && (clock_ != nullptr)) { // 30: run every tick (~30ms)
+            clock_->IncOneSecond();
+            count_ = 0;
+        }
+    }
+private:
+    UIAnalogClock* clock_;
+    int16_t count_ = 0;
+};
+
+class UITestAnalogClock : public UITest {
+public:
+    UITestAnalogClock() {}
+    ~UITestAnalogClock() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    void CreateButtons001(UIViewGroup* group, UIImageView* curFace, UIAnalogClock* clock);
+    void CreateButtons002(UIViewGroup* group, UIImageView* curFace, UIAnalogClock* clock);
+
+    void UIKitTestLineHandAnalogClock001();
+    void UIKitTestImageHandAnalogClock002();
+
+private:
+    UIScrollView* container_ = nullptr;
+    ClockAnimatorCallback* callback_ = nullptr;
+    Animator* animator_ = nullptr;
+    ClockAnimatorCallback* callback2_ = nullptr;
+    Animator* animator2_ = nullptr;
+    UIView::OnClickListener* changeModeListener_ = nullptr;
+    UIView::OnClickListener* clickMoveLeftListener_ = nullptr;
+    UIView::OnClickListener* clickMoveRightListener_ = nullptr;
+    UIView::OnClickListener* clickMoveTopListener_ = nullptr;
+    UIView::OnClickListener* clickMoveBottomListener_ = nullptr;
+    UIView::OnClickListener* changeModeListener1_ = nullptr;
+    UIView::OnClickListener* clickMoveLeftListener1_ = nullptr;
+    UIView::OnClickListener* clickMoveRightListener1_ = nullptr;
+    UIView::OnClickListener* clickMoveTopListener1_ = nullptr;
+    UIView::OnClickListener* clickMoveBottomListener1_ = nullptr;
+    UILabelButton* SetUpButton(const char* title)
+    {
+        UILabelButton* btn = new UILabelButton();
+        btn->Resize(BUTTON_WIDHT2, BUTTON_HEIGHT2);
+        btn->SetText(title);
+        btn->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
+        btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+        btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+        btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+        btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+        btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+        btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+        return btn;
+    }
+};
+}
+#endif // UI_TEST_ANALOG_CLOCK1_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_animator/ui_test_animator.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_animator/ui_test_animator.cpp
new file mode 100644 (file)
index 0000000..d4acd27
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_animator.h"
+#include "common/screen.h"
+#include "components/ui_label.h"
+
+namespace OHOS {
+namespace {
+const int16_t LABEL_HEIGHT = 29;
+const int16_t BUTTON_WIDTH = 140;
+const int16_t BUTTON_HEIGHT = BUTTON_HEIGHT3;
+const int16_t DELTA_X_COORDINATE = 5;
+const int16_t DELTA_Y_COORDINATE = 12;
+} // namespace
+
+void UITestAnimator::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        uiViewGroupFrame_ = new UIViewGroup();
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_COLOR, Color::White().full);
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_OPA, HALF_OPA_OPAQUE);
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_WIDTH, VIEW_STYLE_BORDER_WIDTH);
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_RADIUS, VIEW_STYLE_BORDER_RADIUS);
+        uiViewGroupFrame_->SetStyle(STYLE_BACKGROUND_OPA, 0);
+        uiViewGroupFrame_->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE2, VIEW_DISTANCE_TO_TOP_SIDE);
+        container_->Add(uiViewGroupFrame_);
+        UILabel* label = new UILabel();
+        container_->Add(label);
+        // 264: label width; 48: label height
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, TEXT_DISTANCE_TO_TOP_SIDE, 264, 48);
+        label->SetText("动画效果");
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        image_ = new UIImageView();
+        image_->SetSrc(RES_PATH"/tiger_path.bin");
+        image_->SetPosition(0, 5);                                 // 5:y-coordinate
+        callback_ = new ImageEaseAnimatorCallback(image_, 0, 338); // 338:endPos
+        animator_ = callback_->GetAnimator();
+        uiViewGroupFrame_->Add(image_);
+        uiViewGroupFrame_->Resize(Screen::GetInstance().GetWidth() - VIEW_DISTANCE_TO_LEFT_SIDE,
+                                  image_->GetHeight() + 10); // 10: increase y-coordinate
+    }
+    if (scroll_ == nullptr) {
+        scroll_ = new UIScrollView();
+        // 20: increase y-coordinate
+        uint16_t y = uiViewGroupFrame_->GetY() + uiViewGroupFrame_->GetHeight() + 20;
+        scroll_->SetPosition(0, y, Screen::GetInstance().GetWidth(),
+                             Screen::GetInstance().GetHeight() - y - 64); // 64: decrease y-coordinate
+        container_->Add(scroll_);
+        positionX_ = 0;
+    }
+}
+
+void UITestAnimator::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+    image_ = nullptr;
+    scroll_ = nullptr;
+    delete callback_;
+    callback_ = nullptr;
+    uiViewGroupFrame_ = nullptr;
+}
+
+const UIView* UITestAnimator::GetTestView()
+{
+    UIKitAnimatorTestBackEasing001();
+    UIKitAnimatorTestCircEasing002();
+    UIKitAnimatorTestCubicEasing003();
+    UIKitAnimatorTestSineEasing004();
+    UIKitAnimatorTestQuadEasing005();
+    UIKitAnimatorTestQuintEasing006();
+    UIKitAnimatorTestLinearEasing007();
+    UIKitAnimatorTestFPS008();
+    return container_;
+}
+
+void UITestAnimator::SetUpLabel(const char* title, int16_t x, int16_t y)
+{
+    UILabel* label = GetTitleLabel(title);
+    scroll_->Add(label);
+    label->SetPosition(x, y, 288, LABEL_HEIGHT); // 288: label width
+}
+
+void UITestAnimator::SetUpButton(UILabelButton* btn, const char* title, int16_t x, int16_t y)
+{
+    if (btn == nullptr) {
+        return;
+    }
+    scroll_->Add(btn);
+    btn->SetPosition(x, y, BUTTON_WIDHT3, BUTTON_HEIGHT3);
+    btn->SetText(title);
+    btn->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
+    btn->SetOnClickListener(this);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+    scroll_->Invalidate();
+}
+
+void UITestAnimator::UIKitAnimatorTestBackEasing001()
+{
+    backOvershootBtn_ = new UILabelButton();
+    backEaseInBtn_ = new UILabelButton();
+    backEaseOutBtn_ = new UILabelButton();
+    backEaseInOutBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_LEFT_SIDE;
+    positionY_ = 0;
+    SetUpLabel("back动画效果: ", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(backOvershootBtn_, "overshoot+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(backEaseInBtn_, "BackEaseIn", positionX_, positionY_);
+    positionX_ = TEXT_DISTANCE_TO_LEFT_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE;
+    SetUpButton(backEaseOutBtn_, "BackEaseOut", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(backEaseInOutBtn_, "BackEaseInOut", positionX_, positionY_);
+}
+
+void UITestAnimator::UIKitAnimatorTestCircEasing002()
+{
+    circEaseInBtn_ = new UILabelButton();
+    circEaseOutBtn_ = new UILabelButton();
+    circEaseInOutBtn_ = new UILabelButton();
+    // 2: count of btn
+    positionX_ = BUTTON_WIDTH * 2 + DELTA_Y_COORDINATE * 2 + TEXT_DISTANCE_TO_LEFT_SIDE;
+    positionY_ = 0;
+    SetUpLabel("circ动画效果: ", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(circEaseInBtn_, "CircEaseIn", positionX_, positionY_);
+    positionX_ +=  BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(circEaseOutBtn_, "CircEaseOut", positionX_, positionY_);
+    // 2: count of btn
+    positionX_ = BUTTON_WIDTH * 2 + DELTA_Y_COORDINATE * 2 + TEXT_DISTANCE_TO_LEFT_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE;
+    SetUpButton(circEaseInOutBtn_, "CircEaseInOut", positionX_, positionY_);
+}
+
+void UITestAnimator::UIKitAnimatorTestCubicEasing003()
+{
+    cubicEaseInBtn_ = new UILabelButton();
+    cubicEaseOutBtn_ = new UILabelButton();
+    cubicEaseInOutBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_LEFT_SIDE;
+    positionY_ = 148; // 148: y-coordinate
+    SetUpLabel("cubic动画效果: ", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(cubicEaseInBtn_, "CubicEaseIn", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(cubicEaseOutBtn_, "CubicEaseOut", positionX_, positionY_);
+    positionX_ = TEXT_DISTANCE_TO_LEFT_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE;
+    SetUpButton(cubicEaseInOutBtn_, "CubicEaseInOut", positionX_, positionY_);
+}
+
+void UITestAnimator::UIKitAnimatorTestSineEasing004()
+{
+    sineEaseInBtn_ = new UILabelButton();
+    sineEaseOutBtn_ = new UILabelButton();
+    sineEaseInOutBtn_ = new UILabelButton();
+     // 2: count of btn
+    positionX_ = BUTTON_WIDTH * 2 + DELTA_Y_COORDINATE * 2 + TEXT_DISTANCE_TO_LEFT_SIDE;
+    positionY_ = 148; // 148: y-coordinate
+    SetUpLabel("sine动画效果: ", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(sineEaseInBtn_, "SineEaseIn", positionX_, positionY_);
+    positionX_ +=  BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(sineEaseOutBtn_, "SineEaseOut", positionX_, positionY_);
+    // 2: count of btn
+    positionX_ = BUTTON_WIDTH * 2 + DELTA_Y_COORDINATE * 2 + TEXT_DISTANCE_TO_LEFT_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE;
+    SetUpButton(sineEaseInOutBtn_, "SineEaseInOut", positionX_, positionY_);
+}
+
+void UITestAnimator::UIKitAnimatorTestQuadEasing005()
+{
+    quadEaseInBtn_ = new UILabelButton();
+    quadEaseOutBtn_ = new UILabelButton();
+    quadEaseInOutBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_LEFT_SIDE;
+    positionY_ = 296; // 296: y-coordinate
+    SetUpLabel("quad动画效果: ", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(quadEaseInBtn_, "QuadEaseIn", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(quadEaseOutBtn_, "QuadEaseOut", positionX_, positionY_);
+    positionX_ = TEXT_DISTANCE_TO_LEFT_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE;
+    SetUpButton(quadEaseInOutBtn_, "QuadEaseInOut", positionX_, positionY_);
+}
+
+void UITestAnimator::UIKitAnimatorTestQuintEasing006()
+{
+    quintEaseInBtn_ = new UILabelButton();
+    quintEaseOutBtn_ = new UILabelButton();
+    quintEaseInOutBtn_ = new UILabelButton();
+    // 2: count of btn
+    positionX_ = BUTTON_WIDTH * 2 + DELTA_Y_COORDINATE * 2 + TEXT_DISTANCE_TO_LEFT_SIDE;
+    positionY_ = 296; // 296: y-coordinate
+    SetUpLabel("quint动画效果: ", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(quintEaseInBtn_, "QuintEaseIn", positionX_, positionY_);
+    positionX_ +=  BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(quintEaseOutBtn_, "QuintEaseOut", positionX_, positionY_);
+    // 2: count of btn
+    positionX_ = BUTTON_WIDTH * 2 + DELTA_Y_COORDINATE * 2 + TEXT_DISTANCE_TO_LEFT_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE;
+    SetUpButton(quintEaseInOutBtn_, "QuintEaseInOut", positionX_, positionY_);
+}
+
+void UITestAnimator::UIKitAnimatorTestLinearEasing007()
+{
+    linearEaseNoneBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_LEFT_SIDE;
+    positionY_ = 444; // 444: y-coordinate
+    SetUpLabel("linear动画效果: ", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(linearEaseNoneBtn_, "LinearEaseNone", positionX_, positionY_);
+}
+
+void UITestAnimator::UIKitAnimatorTestFPS008()
+{
+    fpsLabel_ = new UILabel();
+    // 90:x-coordinate, 0:y-coordinate, 90:new width, 20:new height
+    fpsLabel_->SetPosition(Screen::GetInstance().GetWidth() - 90, TEXT_DISTANCE_TO_TOP_SIDE, 90,
+                           TITLE_LABEL_DEFAULT_HEIGHT);
+    fpsLabel_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    fpsLabel_->SetText("FPS");
+    OnFPSChangedListener::SetFPSCalculateType(SysInfo::FPS_CT_PRECISE_SAMPLING);
+    container_->Add(fpsLabel_);
+    fpsLabel_->Invalidate();
+}
+
+void UITestAnimator::SetSineEaseEvent(UIView& view)
+{
+    if (&view == sineEaseInBtn_) {
+        callback_->SetEasingFunc(EasingEquation::SineEaseIn);
+    } else if (&view == sineEaseOutBtn_) {
+        callback_->SetEasingFunc(EasingEquation::SineEaseOut);
+    } else if (&view == sineEaseInOutBtn_) {
+        callback_->SetEasingFunc(EasingEquation::SineEaseInOut);
+    }
+}
+
+bool UITestAnimator::OnClick(UIView& view, const ClickEvent& event)
+{
+    static double overshoot = 1.7;
+    if (&view == backOvershootBtn_) {
+        overshoot += 1;
+        EasingEquation::SetBackOvershoot(overshoot);
+    } else if (&view == backEaseInBtn_) {
+        callback_->SetEasingFunc(EasingEquation::BackEaseIn);
+    } else if (&view == backEaseOutBtn_) {
+        callback_->SetEasingFunc(EasingEquation::BackEaseOut);
+    } else if (&view == backEaseInOutBtn_) {
+        callback_->SetEasingFunc(EasingEquation::BackEaseInOut);
+    } else if (&view == circEaseInBtn_) {
+        callback_->SetEasingFunc(EasingEquation::CircEaseIn);
+    } else if (&view == circEaseOutBtn_) {
+        callback_->SetEasingFunc(EasingEquation::CircEaseOut);
+    } else if (&view == circEaseInOutBtn_) {
+        callback_->SetEasingFunc(EasingEquation::CircEaseInOut);
+    } else if (&view == cubicEaseInBtn_) {
+        callback_->SetEasingFunc(EasingEquation::CubicEaseIn);
+    } else if (&view == cubicEaseOutBtn_) {
+        callback_->SetEasingFunc(EasingEquation::CubicEaseOut);
+    } else if (&view == cubicEaseInOutBtn_) {
+        callback_->SetEasingFunc(EasingEquation::CubicEaseInOut);
+    } else if (&view == linearEaseNoneBtn_) {
+        callback_->SetEasingFunc(EasingEquation::LinearEaseNone);
+    } else if (&view == quadEaseInBtn_) {
+        callback_->SetEasingFunc(EasingEquation::QuadEaseIn);
+    } else if (&view == quadEaseOutBtn_) {
+        callback_->SetEasingFunc(EasingEquation::QuadEaseOut);
+    } else if (&view == quadEaseInOutBtn_) {
+        callback_->SetEasingFunc(EasingEquation::QuadEaseInOut);
+    } else if (&view == quintEaseInBtn_) {
+        callback_->SetEasingFunc(EasingEquation::QuintEaseIn);
+    } else if (&view == quintEaseOutBtn_) {
+        callback_->SetEasingFunc(EasingEquation::QuintEaseOut);
+    } else if (&view == quintEaseInOutBtn_) {
+        callback_->SetEasingFunc(EasingEquation::QuintEaseInOut);
+    } else {
+        SetSineEaseEvent(view);
+    }
+    animator_->Start();
+    container_->Invalidate();
+    return true;
+}
+
+void UITestAnimator::OnFPSChanged(float newFPS)
+{
+    fpsLabel_->SetText("FPS");
+    fpsLabel_->Invalidate();
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_animator/ui_test_animator.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_animator/ui_test_animator.h
new file mode 100644 (file)
index 0000000..ec51b5e
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_ANIMATOR_H
+#define UI_TEST_ANIMATOR_H
+
+#include "animator/easing_equation.h"
+#include "components/ui_image_view.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "gfx_utils/sys_info.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class ImageEaseAnimatorCallback : public AnimatorCallback {
+public:
+    ImageEaseAnimatorCallback(UIView* uiView, int16_t startPos, int16_t endPos)
+        : startPos_(startPos),
+          endPos_(endPos),
+          easingFunc_(EasingEquation::LinearEaseNone),
+          animator_(new Animator(this, uiView, 1000, true)) // 1000:duration of animator_, in milliseconds.
+    {
+    }
+
+    virtual ~ImageEaseAnimatorCallback()
+    {
+        delete animator_;
+    }
+
+    Animator* GetAnimator() const
+    {
+        return animator_;
+    }
+
+    void SetEasingFunc(EasingFunc easingFunc)
+    {
+        easingFunc_ = easingFunc;
+    }
+
+    virtual void Callback(UIView* view)
+    {
+        if (view == nullptr) {
+            return;
+        }
+        int16_t pos = easingFunc_(startPos_, endPos_, animator_->GetRunTime(), animator_->GetTime());
+        Rect invalidatedArea = view->GetRect();
+        view->SetPosition(pos, view->GetY());
+        invalidatedArea.Join(invalidatedArea, view->GetRect());
+        view->InvalidateRect(invalidatedArea);
+    }
+
+protected:
+    int16_t startPos_;
+    int16_t endPos_;
+    EasingFunc easingFunc_;
+    Animator* animator_;
+};
+
+class UITestAnimator : public UITest, public UIView::OnClickListener, public SysInfo::OnFPSChangedListener {
+public:
+    UITestAnimator() {}
+    ~UITestAnimator(){};
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    void SetUpButton(UILabelButton* btn, const char* title, int16_t x, int16_t y);
+    void SetUpLabel(const char* title, int16_t x, int16_t y);
+    void SetSineEaseEvent(UIView& view);
+    bool OnClick(UIView& view, const ClickEvent& event) override;
+    void OnFPSChanged(float newFPS) override;
+
+    void UIKitAnimatorTestBackEasing001();
+    void UIKitAnimatorTestCircEasing002();
+    void UIKitAnimatorTestCubicEasing003();
+    void UIKitAnimatorTestSineEasing004();
+    void UIKitAnimatorTestQuadEasing005();
+    void UIKitAnimatorTestQuintEasing006();
+    void UIKitAnimatorTestLinearEasing007();
+    void UIKitAnimatorTestFPS008();
+
+private:
+    UIScrollView* container_ = nullptr;
+    UIScrollView* scroll_ = nullptr;
+    UIImageView* image_ = nullptr;
+    ImageEaseAnimatorCallback* callback_ = nullptr;
+    Animator* animator_ = nullptr;
+    UIViewGroup* uiViewGroupFrame_ = nullptr;
+
+    UILabelButton* backOvershootBtn_ = nullptr;
+    UILabelButton* backEaseInBtn_ = nullptr;
+    UILabelButton* backEaseOutBtn_ = nullptr;
+    UILabelButton* backEaseInOutBtn_ = nullptr;
+    UILabelButton* circEaseInBtn_ = nullptr;
+    UILabelButton* circEaseOutBtn_ = nullptr;
+    UILabelButton* circEaseInOutBtn_ = nullptr;
+    UILabelButton* cubicEaseInBtn_ = nullptr;
+    UILabelButton* cubicEaseOutBtn_ = nullptr;
+    UILabelButton* cubicEaseInOutBtn_ = nullptr;
+    UILabelButton* linearEaseNoneBtn_ = nullptr;
+    UILabelButton* quadEaseInBtn_ = nullptr;
+    UILabelButton* quadEaseOutBtn_ = nullptr;
+    UILabelButton* quadEaseInOutBtn_ = nullptr;
+    UILabelButton* quintEaseInBtn_ = nullptr;
+    UILabelButton* quintEaseOutBtn_ = nullptr;
+    UILabelButton* quintEaseInOutBtn_ = nullptr;
+    UILabelButton* sineEaseInBtn_ = nullptr;
+    UILabelButton* sineEaseOutBtn_ = nullptr;
+    UILabelButton* sineEaseInOutBtn_ = nullptr;
+    UILabel* fpsLabel_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_ANIMATOR_H
index 5e6b141..44a80aa 100644 (file)
@@ -1,16 +1,8 @@
 /*
- * Copyright (c) 2022 CompanyNameMagicTag.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
  */
 
 #include "ui_test_bitmap_font.h"
index 5886df3..71a7bef 100644 (file)
@@ -1,16 +1,8 @@
 /*
- * Copyright (c) 2022 CompanyNameMagicTag.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
  */
 
 #ifndef UI_TEST_BITMAP_FONT_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_border_margin_padding/ui_test_border_listener.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_border_margin_padding/ui_test_border_listener.h
new file mode 100644 (file)
index 0000000..04ad369
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_BORDER_LISTENER_H
+#define UI_TEST_BORDER_LISTENER_H
+
+namespace OHOS {
+
+class BorderListener;
+class MarginListener;
+class PaddingListener;
+
+}
+
+#endif // UI_TEST_BORDER_LISTENER_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_border_margin_padding/ui_test_border_margin_padding.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_border_margin_padding/ui_test_border_margin_padding.cpp
new file mode 100644 (file)
index 0000000..643cd28
--- /dev/null
@@ -0,0 +1,678 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_border_margin_padding.h"
+#include "common/screen.h"
+#include "components/text_adapter.h"
+#include "components/ui_arc_label.h"
+#include "components/ui_box_progress.h"
+#include "components/ui_canvas.h"
+#include "components/ui_circle_progress.h"
+#include "components/ui_image_animator.h"
+#include "components/ui_label_button.h"
+#include "components/ui_list.h"
+#include "components/ui_qrcode.h"
+#include "components/ui_radio_button.h"
+#include "components/ui_slider.h"
+#include "components/ui_swipe_view.h"
+
+namespace OHOS {
+static ImageAnimatorInfo g_imageAnimatorInfo[4] = {
+    {RES_PATH"image_animator_0.bin", {84, 108}, 116, 116, IMG_SRC_FILE_PATH},
+    {RES_PATH"image_animator_1.bin", {84, 108}, 116, 116, IMG_SRC_FILE_PATH},
+    {RES_PATH"image_animator_2.bin", {84, 108}, 116, 116, IMG_SRC_FILE_PATH},
+    {RES_PATH"image_animator_3.bin", {84, 108}, 116, 116, IMG_SRC_FILE_PATH},
+};
+
+
+class MarginListener : public UICheckBox::OnChangeListener {
+public:
+    explicit MarginListener(UITestBorderMarginPadding* view)
+    {
+        view_ = view;
+    }
+
+    virtual ~MarginListener() {}
+
+    bool OnChange(UICheckBox::UICheckBoxState state) override
+    {
+        if (state == UICheckBox::SELECTED) {
+            view_->style_.SetStyle(STYLE_MARGIN_LEFT, MARGIN_SIZE);
+            view_->style_.SetStyle(STYLE_MARGIN_TOP, MARGIN_SIZE);
+            view_->style_.SetStyle(STYLE_MARGIN_RIGHT, MARGIN_SIZE);
+            view_->style_.SetStyle(STYLE_MARGIN_BOTTOM, MARGIN_SIZE);
+        } else {
+            view_->style_.SetStyle(STYLE_MARGIN_LEFT, 0);
+            view_->style_.SetStyle(STYLE_MARGIN_TOP, 0);
+            view_->style_.SetStyle(STYLE_MARGIN_RIGHT, 0);
+            view_->style_.SetStyle(STYLE_MARGIN_BOTTOM, 0);
+        }
+        view_->ReloadTest();
+        return true;
+    }
+
+private:
+    static constexpr int16_t MARGIN_SIZE = 30;
+    UITestBorderMarginPadding* view_ = nullptr;
+};
+
+class BorderListener : public UICheckBox::OnChangeListener {
+public:
+    explicit BorderListener(UITestBorderMarginPadding* view)
+    {
+        view_ = view;
+    }
+
+    virtual ~BorderListener() {}
+
+    bool OnChange(UICheckBox::UICheckBoxState state) override
+    {
+        if (state == UICheckBox::SELECTED) {
+            view_->style_.SetStyle(STYLE_BORDER_WIDTH, 20); // 20: border width
+            view_->style_.SetStyle(STYLE_BORDER_OPA, OPA_OPAQUE);
+            view_->style_.SetStyle(STYLE_BORDER_COLOR, Color::Blue().full);
+        } else {
+            view_->style_.SetStyle(STYLE_BORDER_WIDTH, 0);
+        }
+        view_->ReloadTest();
+        return true;
+    }
+
+private:
+    UITestBorderMarginPadding* view_ = nullptr;
+};
+
+class PaddingListener : public UICheckBox::OnChangeListener {
+public:
+    explicit PaddingListener(UITestBorderMarginPadding* view)
+    {
+        view_ = view;
+    }
+
+    virtual ~PaddingListener() {}
+
+    bool OnChange(UICheckBox::UICheckBoxState state) override
+    {
+        if (state == UICheckBox::SELECTED) {
+            view_->style_.SetStyle(STYLE_PADDING_LEFT, PADDING_SIZE);
+            view_->style_.SetStyle(STYLE_PADDING_TOP, PADDING_SIZE);
+            view_->style_.SetStyle(STYLE_PADDING_RIGHT, PADDING_SIZE);
+            view_->style_.SetStyle(STYLE_PADDING_BOTTOM, PADDING_SIZE);
+        } else {
+            view_->style_.SetStyle(STYLE_PADDING_LEFT, 0);
+            view_->style_.SetStyle(STYLE_PADDING_TOP, 0);
+            view_->style_.SetStyle(STYLE_PADDING_RIGHT, 0);
+            view_->style_.SetStyle(STYLE_PADDING_BOTTOM, 0);
+        }
+        view_->ReloadTest();
+        return true;
+    }
+
+private:
+    static constexpr int16_t PADDING_SIZE = 30;
+    UITestBorderMarginPadding* view_ = nullptr;
+};
+
+void UITestBorderMarginPadding::InitUIToggleButton()
+{
+    UIToggleButton* marginBtn = new UIToggleButton();
+    UIToggleButton* borderBtn = new UIToggleButton();
+    UIToggleButton* paddingBtn = new UIToggleButton();
+    UILabel* labelMargin = new UILabel();
+    UILabel* labelBorder = new UILabel();
+    UILabel* labelPadding = new UILabel();
+    // 20 : offset
+    layoutButton_->SetPosition(Screen::GetInstance().GetWidth() - BUTTON_GROUP_WIDTH + 20, 0, BUTTON_GROUP_WIDTH,
+                               Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+    layoutButton_->SetRows(8);  // 8 : ro
+    layoutButton_->SetCols(1);
+
+    container_->Add(layoutButton_);
+
+    marginBtn->Resize(64, 64);  // 64 : button size
+    borderBtn->Resize(64, 64);  // 64 : button size
+    paddingBtn->Resize(64, 64); // 64 : button size
+
+    labelMargin->SetLineBreakMode(UILabel::LINE_BREAK_ADAPT);
+    labelMargin->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 15); // 15: font size
+    labelMargin->SetText("margin ON/OFF");
+    labelMargin->ReMeasure();
+
+    labelBorder->SetLineBreakMode(UILabel::LINE_BREAK_ADAPT);
+    labelBorder->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 15); // 15: font size
+    labelBorder->SetText("border ON/OFF");
+    labelBorder->ReMeasure();
+
+    labelPadding->SetLineBreakMode(UILabel::LINE_BREAK_ADAPT);
+    labelPadding->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 15); // 15: font size
+    labelPadding->SetText("padding ON/OFF");
+    labelPadding->ReMeasure();
+
+    layoutButton_->Add(new UILabel());
+    layoutButton_->Add(new UILabel());
+    layoutButton_->Add(labelMargin);
+    layoutButton_->Add(marginBtn);
+    layoutButton_->Add(labelBorder);
+    layoutButton_->Add(borderBtn);
+    layoutButton_->Add(labelPadding);
+    layoutButton_->Add(paddingBtn);
+    layoutButton_->LayoutChildren();
+
+    if (borderListener_ == nullptr) {
+        borderListener_ = new BorderListener(this);
+    }
+    borderBtn->SetOnChangeListener(borderListener_);
+    if (marginListener_ == nullptr) {
+        marginListener_ = new MarginListener(this);
+    }
+    marginBtn->SetOnChangeListener(marginListener_);
+    if (paddingListener_ == nullptr) {
+        paddingListener_ = new PaddingListener(this);
+    }
+    paddingBtn->SetOnChangeListener(paddingListener_);
+}
+
+void UITestBorderMarginPadding::InitAdapterData()
+{
+    if (adapterData_ == nullptr) {
+        adapterData_ = new List<const char*>();
+        adapterData_->PushBack("000");
+        adapterData_->PushBack("111");
+        adapterData_->PushBack("222");
+        adapterData_->PushBack("333");
+        adapterData_->PushBack("444");
+        adapterData_->PushBack("555");
+        adapterData_->PushBack("666");
+        adapterData_->PushBack("777");
+        adapterData_->PushBack("888");
+        adapterData_->PushBack("999");
+        adapterData_->PushBack("AAA");
+        adapterData_->PushBack("BBB");
+        adapterData_->PushBack("CCC");
+    }
+}
+
+void UITestBorderMarginPadding::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIViewGroup();
+    }
+    if (scroll_ == nullptr) {
+        scroll_ = new UIScrollView();
+    }
+    if (layoutButton_ == nullptr) {
+        layoutButton_ = new GridLayout();
+    }
+    if (listScroll_ == nullptr) {
+        listScroll_ = new ListLayout();
+    }
+
+    container_->SetPosition(0, 0, Screen::GetInstance().GetWidth(),
+                            Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+    // 40: x
+    scroll_->SetPosition(40, 0, Screen::GetInstance().GetWidth() - BUTTON_GROUP_WIDTH,
+                         Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+    scroll_->SetThrowDrag(true);
+    scroll_->SetHorizontalScrollState(false);
+    scroll_->SetScrollBlankSize(100); // 100 : blank size
+    
+    listScroll_ = new ListLayout(ListLayout::VERTICAL);
+    listScroll_->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    listScroll_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Olive().full);
+    listScroll_->SetPosition(0, 0, Screen::GetInstance().GetWidth() - BUTTON_GROUP_WIDTH,
+                             Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+    scroll_->Add(listScroll_);
+    container_->Add(scroll_);
+
+    InitUIToggleButton();
+    InitAdapterData();
+}
+
+void UITestBorderMarginPadding::TearDown()
+{
+    if (borderListener_ != nullptr) {
+        delete borderListener_;
+        borderListener_ = nullptr;
+    }
+    if (marginListener_ != nullptr) {
+        delete marginListener_;
+        marginListener_ = nullptr;
+    }
+    if (paddingListener_ != nullptr) {
+        delete paddingListener_;
+        paddingListener_ = nullptr;
+    }
+    if (adapterData_ != nullptr) {
+        adapterData_->Clear();
+        delete adapterData_;
+        adapterData_ = nullptr;
+    }
+    if (picker_ != nullptr) {
+        listScroll_->Remove(picker_);
+        delete picker_;
+        picker_ = nullptr;
+    }
+    if (chart_ != nullptr) {
+        listScroll_->Remove(chart_);
+        chart_->ClearDataSerial();
+        delete dataSerial_;
+        dataSerial_ = nullptr;
+        delete chart_;
+        chart_ = nullptr;
+    }
+    DeleteChildren(container_);
+    container_ = nullptr;
+    scroll_ = nullptr;
+    layoutButton_ = nullptr;
+    listScroll_ = nullptr;
+}
+
+void UITestBorderMarginPadding::ReloadTest()
+{
+    int16_t heightBefor = listScroll_->GetHeight();
+    int16_t yBefor = listScroll_->GetY();
+
+    scroll_->RemoveAll();
+    if (chart_ != nullptr) {
+        listScroll_->Remove(chart_);
+        chart_->ClearDataSerial();
+        delete dataSerial_;
+        dataSerial_ = nullptr;
+        delete chart_;
+        chart_ = nullptr;
+    }
+
+    if (picker_ != nullptr) {
+        listScroll_->Remove(picker_);
+        delete picker_;
+        picker_ = nullptr;
+    }
+
+    DeleteChildren(listScroll_);
+    listScroll_ = new ListLayout(ListLayout::VERTICAL);
+    listScroll_->SetPosition(0, 0, Screen::GetInstance().GetWidth() - BUTTON_GROUP_WIDTH,
+                             Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+    listScroll_->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    listScroll_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Olive().full);
+    scroll_->Add(listScroll_);
+    GetTestView();
+
+    int16_t yAfter = listScroll_->GetHeight() * yBefor / heightBefor;
+    scroll_->ScrollBy(0, yAfter);
+    container_->Invalidate();
+}
+
+const UIView* UITestBorderMarginPadding::GetTestView()
+{
+    UIKitUITestBorderMarginPaddingTest001();
+    UIKitUITestBorderMarginPaddingTest002();
+    UIKitUITestBorderMarginPaddingTest003();
+    UIKitUITestBorderMarginPaddingTest004();
+    UIKitUITestBorderMarginPaddingTest005();
+    UIKitUITestBorderMarginPaddingTest006();
+    UIKitUITestBorderMarginPaddingTest007();
+    UIKitUITestBorderMarginPaddingTest008();
+    UIKitUITestBorderMarginPaddingTest009();
+    UIKitUITestBorderMarginPaddingTest011();
+    UIKitUITestBorderMarginPaddingTest012();
+    UIKitUITestBorderMarginPaddingTest013();
+    UIKitUITestBorderMarginPaddingTest014();
+    UIKitUITestBorderMarginPaddingTest016();
+    UIKitUITestBorderMarginPaddingTest017();
+    UIKitUITestBorderMarginPaddingTest018();
+    return container_;
+}
+
+void UITestBorderMarginPadding::AddTitle(const char* text)
+{
+    UILabel* titleLabel = new UILabel();
+    titleLabel->SetLineBreakMode(UILabel::LINE_BREAK_ADAPT);
+    titleLabel->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    titleLabel->SetText(text);
+    listScroll_->Add(titleLabel);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest001()
+{
+    AddTitle("UIView");
+    UIView* view = new UIView();
+    view->SetStyle(style_);
+    view->Resize(200, 100); // 200:size 100: size
+    listScroll_->Add(view);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest002()
+{
+    AddTitle("UILabel");
+    UILabel* view = new UILabel();
+    view->SetStyle(style_);
+    view->SetLineBreakMode(UILabel::LINE_BREAK_CLIP);
+    view->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+    view->Resize(200, 100); // 200:size 100: size
+    view->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    view->SetText("TEST UILABEL");
+    listScroll_->Add(view);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest003()
+{
+    AddTitle("ArcLabel");
+    UIArcLabel* view = new UIArcLabel();
+    view->SetStyle(style_);
+    view->SetArcTextCenter(180, 180);                // 180: text center
+    view->SetArcTextRadius(150);                     // 150: text radius
+    view->SetArcTextAngle(0, 270);                   // 0: start angle 270: end angle
+    view->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 30); // 30: font size
+    view->SetText("012345678ABCDEF0123456789ABCDE");
+    listScroll_->Add(view);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest004()
+{
+    AddTitle("BoxProgress");
+    UIBoxProgress* boxProgress = new UIBoxProgress();
+    boxProgress->SetStyle(style_);
+    boxProgress->SetPosition(10, 10, 100, 10); // 10: x 10: y 100: width 10: height
+    boxProgress->SetValue(20);                 // 20: value
+    boxProgress->SetBackgroundStyle(STYLE_BACKGROUND_COLOR, Color::Yellow().full);
+    boxProgress->SetForegroundStyle(STYLE_BACKGROUND_COLOR, Color::Green().full);
+    listScroll_->Add(boxProgress);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest005()
+{
+    AddTitle("UIViewGroup");
+    UIViewGroup* group = new UIViewGroup();
+    group->SetStyle(style_);
+    group->Resize(200, 100); // 200: size 100: size
+    listScroll_->Add(group);
+
+    UIButton* button = new UIButton();
+    button->SetPosition(0, 0, 100, 50); // 100: size 50: size
+    group->Add(button);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest006()
+{
+    AddTitle("UICanvas");
+    UICanvas* canvas = new UICanvas();
+    canvas->SetStyle(style_);
+    canvas->Resize(400, 400); // 400: size
+    Paint paint;
+    paint.SetStrokeWidth(10); // 10: line width
+    // {10, 10}: Start point coordinates x, y; {300, 10}: end point coordinates x, y
+    canvas->DrawLine({10, 10}, {300, 10}, paint);
+
+    paint.SetStrokeColor(Color::Yellow());
+    canvas->DrawCurve({100, 50}, {150, 50}, {150, 50}, {150, 100}, paint);
+
+    paint.SetStyle(Paint::PaintStyle::FILL_STYLE);
+    paint.SetFillColor(Color::Yellow());
+    paint.SetStrokeWidth(30); // 30: line width
+    // {10, 200}: left corner coordinates point, 50: width, 50: rectangle style
+    canvas->DrawRect({10, 200}, 50, 50, paint);
+
+    paint.SetStyle(Paint::PaintStyle::STROKE_FILL_STYLE);
+    paint.SetFillColor(Color::Yellow());
+    paint.SetStrokeColor(Color::Blue());
+    paint.SetStrokeWidth(10); // 10: line width
+    paint.SetOpacity(127);    // 127: opacity
+    // {300, 100}: circle center coordinates, 30: circle radius
+    canvas->DrawCircle({300, 100}, 30, paint);
+    listScroll_->Add(canvas);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest007()
+{
+    AddTitle("UIChart");
+    chart_ = new UIChartPolyline();
+    chart_->SetStyle(style_);
+    chart_->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, VIEW_DISTANCE_TO_TOP_SIDE);
+    chart_->SetWidth(454);  // 454: width
+    chart_->SetHeight(250); // 250: height
+
+    dataSerial_ = new UIChartDataSerial();
+    dataSerial_->SetMaxDataCount(5); // 5: number of data points
+    Point pointArray[5] = {{0, 2478}, {1, 2600}, {2, 3000}, {3, 3200}, {4, 3500}};
+    dataSerial_->AddPoints(pointArray, 5); // 5: number of data points
+    dataSerial_->SetLineColor(Color::Red());
+    dataSerial_->SetFillColor(Color::Red());
+    dataSerial_->EnableGradient(true);
+
+    UIXAxis& xAxis = chart_->GetXAxis();
+    UIYAxis& yAxis = chart_->GetYAxis();
+    xAxis.SetMarkNum(5);         // 5: number of scales
+    xAxis.SetDataRange(0, 5);    // 0: minimum value, 5: maximum value
+    yAxis.SetDataRange(0, 5000); // 0: minimum value, 5000: maximum value
+
+    chart_->SetGradientOpacity(25, 127); // 25: min opacity, 127: max opacity
+    chart_->AddDataSerial(dataSerial_);
+
+    listScroll_->Add(chart_);
+}
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest008()
+{
+    AddTitle("Button");
+    UIViewGroup* group = new UIViewGroup();
+    group->Resize(Screen::GetInstance().GetWidth() - BUTTON_GROUP_WIDTH, 200); // 200: button UIViewGroup height
+
+    UIButton* button = new UIButton();
+    button->SetStyleForState(STYLE_MARGIN_LEFT, style_.marginLeft_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_MARGIN_LEFT, style_.marginLeft_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_MARGIN_TOP, style_.marginTop_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_MARGIN_TOP, style_.marginTop_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_MARGIN_RIGHT, style_.marginRight_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_MARGIN_RIGHT, style_.marginRight_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_MARGIN_BOTTOM, style_.marginBottom_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_MARGIN_BOTTOM, style_.marginBottom_, UIButton::PRESSED);
+
+    button->SetStyleForState(STYLE_BORDER_WIDTH, style_.borderWidth_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_BORDER_WIDTH, style_.borderWidth_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_BORDER_OPA, style_.borderOpa_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_BORDER_OPA, style_.borderOpa_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_BORDER_COLOR, style_.borderColor_.full, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_BORDER_COLOR, style_.borderColor_.full, UIButton::PRESSED);
+
+    button->SetStyleForState(STYLE_PADDING_LEFT, style_.paddingLeft_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_PADDING_LEFT, style_.paddingLeft_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_PADDING_TOP, style_.paddingTop_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_PADDING_TOP, style_.paddingTop_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_PADDING_RIGHT, style_.paddingRight_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_PADDING_RIGHT, style_.paddingRight_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_PADDING_BOTTOM, style_.paddingBottom_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_PADDING_BOTTOM, style_.paddingBottom_, UIButton::PRESSED);
+
+    button->SetPosition(50, 30, 70, 50); // 50: x 30: y 70: width 50: height
+    group->Add(button);
+
+    UICheckBox* checkbox = new UICheckBox();
+    checkbox->SetStyle(style_);
+    checkbox->SetPosition(200, 30, 50, 50); // 200: x-coordinate, 30: y-coordinate, 50: size
+    group->Add(checkbox);
+
+    UIRadioButton* radioButton = new UIRadioButton();
+    radioButton->SetStyle(style_);
+    radioButton->SetPosition(350, 30, 50, 50); // 350: x-coordinate, 30: y-coordinate, 50: size
+    group->Add(radioButton);
+
+    UIToggleButton* toggleButton = new UIToggleButton();
+    toggleButton->SetStyle(style_);
+    toggleButton->SetPosition(500, 30, 50, 50); // 500: x-coordinate, 30: y-coordinate, 50: size
+    group->Add(toggleButton);
+
+    listScroll_->Add(group);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest009()
+{
+    AddTitle("UICircleProgress");
+    UICircleProgress* circleProgress = new UICircleProgress();
+    circleProgress->SetStyle(style_);
+    circleProgress->Resize(150, 150);          // 150: width 150: height
+    circleProgress->SetCenterPosition(75, 75); // 75: position x 75: position y
+    circleProgress->SetRadius(50);             // 50: radius
+    circleProgress->SetValue(20);              // 20: value
+    listScroll_->Add(circleProgress);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest010()
+{
+    AddTitle("UIImageAnimatorView");
+    UIImageAnimatorView* imageAnimator = new UIImageAnimatorView();
+    imageAnimator->SetStyle(style_);
+    imageAnimator->SetPosition(50, 50, 200, 200);                    // 50 : offset 50 : offset 200 : offset 200: offset
+    imageAnimator->SetImageAnimatorSrc(g_imageAnimatorInfo, 4, 100); // 4: the number of images, 100: updating time
+    imageAnimator->Start();
+    listScroll_->Add(imageAnimator);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest011()
+{
+    AddTitle("UIImageView");
+    UIImageView* imageView = new UIImageView();
+    imageView->SetStyle(style_);
+    imageView->SetWidth(50);  // 50 : size
+    imageView->SetHeight(50); // 50 : size
+    imageView->SetSrc(RES_PATH"blue_rgb888.bin");
+    listScroll_->Add(imageView);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest012()
+{
+    AddTitle("UILabelButton");
+    UILabelButton* button = new UILabelButton();
+    button->SetStyleForState(STYLE_MARGIN_LEFT, style_.marginLeft_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_MARGIN_LEFT, style_.marginLeft_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_MARGIN_TOP, style_.marginTop_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_MARGIN_TOP, style_.marginTop_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_MARGIN_RIGHT, style_.marginRight_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_MARGIN_RIGHT, style_.marginRight_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_MARGIN_BOTTOM, style_.marginBottom_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_MARGIN_BOTTOM, style_.marginBottom_, UIButton::PRESSED);
+
+    button->SetStyleForState(STYLE_BORDER_WIDTH, style_.borderWidth_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_BORDER_WIDTH, style_.borderWidth_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_BORDER_OPA, style_.borderOpa_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_BORDER_OPA, style_.borderOpa_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_BORDER_COLOR, style_.borderColor_.full, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_BORDER_COLOR, style_.borderColor_.full, UIButton::PRESSED);
+
+    button->SetStyleForState(STYLE_PADDING_LEFT, style_.paddingLeft_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_PADDING_LEFT, style_.paddingLeft_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_PADDING_TOP, style_.paddingTop_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_PADDING_TOP, style_.paddingTop_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_PADDING_RIGHT, style_.paddingRight_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_PADDING_RIGHT, style_.paddingRight_, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_PADDING_BOTTOM, style_.paddingBottom_, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_PADDING_BOTTOM, style_.paddingBottom_, UIButton::PRESSED);
+    button->SetWidth(200); // 200 : size
+    button->SetHeight(50); // 50 : size
+    button->SetText("Test UILabelButton");
+    listScroll_->Add(button);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest013()
+{
+    AddTitle("UIList");
+    if (adapter_ == nullptr) {
+        adapter_ = new TextAdapter();
+    }
+    adapter_->SetData(adapterData_);
+    adapter_->GetStyle() = style_;
+
+    UIList* list = new UIList(UIList::VERTICAL);
+    list->SetIntercept(true);
+    list->SetStyle(style_);
+    list->Resize(300, 400); // 300 : size, 400 : size
+    list->SetAdapter(adapter_);
+    listScroll_->Add(list);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest014()
+{
+    AddTitle("UIPicker");
+    picker_ = new UIPicker();
+    picker_->SetIntercept(true);
+    picker_->SetStyle(style_);
+    picker_->SetFontId(16, 18); // 16:back font id 18:high light font id
+    picker_->SetItemHeight(50); // 50: height
+    picker_->SetTextColor(Color::White(), Color::Red());
+    picker_->SetValues(-5, 20); // -5: start 20:end
+    picker_->Resize(300, 400);  // 300: picker size 400: picker size
+    listScroll_->Add(picker_);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest015()
+{
+    AddTitle("UIQrcode");
+    UIQrcode* qrcode = new UIQrcode();
+    qrcode->SetStyle(style_);
+    qrcode->Resize(60, 60); // 60: height
+    qrcode->SetQrcodeInfo("Hello\n HarmonyOS Lite GUI");
+    listScroll_->Add(qrcode);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest016()
+{
+    AddTitle("UIScroll");
+    UIScrollView* scroll = new UIScrollView();
+    scroll->SetIntercept(true);
+    scroll->SetStyle(style_);
+    scroll->Resize(200, 200); // 200: size
+
+    UILabelButton* button = new UILabelButton();
+    button->SetPosition(0, 0, 300, 300); // 300: size
+    button->SetText("button1");
+    scroll->Add(button);
+    listScroll_->Add(scroll);
+}
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest017()
+{
+    AddTitle("UISlider");
+    UISlider* slider = new UISlider();
+    slider->SetIntercept(true);
+    slider->SetStyle(style_);
+    slider->Resize(50, 300);     // 50: width; 300: height
+    slider->SetValidHeight(250); // 250: valid height;
+    slider->SetValue(20);        // 20:  progress bar current value
+    slider->SetDirection(UISlider::Direction::DIR_BOTTOM_TO_TOP);
+    listScroll_->Add(slider);
+}
+
+void UITestBorderMarginPadding::UIKitUITestBorderMarginPaddingTest018()
+{
+    AddTitle("UISwipe");
+    UISwipeView* swipe = new UISwipeView(UISwipeView::HORIZONTAL);
+    swipe->SetIntercept(true);
+    swipe->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    swipe->Resize(200, 200);  // 200: size
+    swipe->SetBlankSize(100); // 100: is blank size
+    UILabel* view1 = new UILabel();
+    view1->SetStyle(style_);
+    view1->SetLineBreakMode(UILabel::LINE_BREAK_CLIP);
+    view1->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+    view1->SetPosition(0, 0, 150, 150); // 150: size
+    view1->SetText("label1");
+    swipe->Add(view1);
+    UILabel* view2 = new UILabel();
+    view2->SetStyle(style_);
+    view2->SetLineBreakMode(UILabel::LINE_BREAK_CLIP);
+    view2->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+    view2->SetPosition(0, 0, 150, 150); // 150: size
+    view2->SetText("label2");
+    swipe->Add(view2);
+    UILabel* view3 = new UILabel();
+    view3->SetStyle(style_);
+    view3->SetLineBreakMode(UILabel::LINE_BREAK_CLIP);
+    view3->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+    view3->SetPosition(0, 0, 150, 150); // 150: size
+    view3->SetText("label3");
+    swipe->Add(view3);
+
+    listScroll_->Add(swipe);
+}
+} // namespace OHOS
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_border_margin_padding/ui_test_border_margin_padding.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_border_margin_padding/ui_test_border_margin_padding.h
new file mode 100644 (file)
index 0000000..8dbf2de
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+#ifndef UI_TEST_BORDER_MARGIN_PADDING_H
+#define UI_TEST_BORDER_MARGIN_PADDING_H
+
+#include "ui_test_border_listener.h"
+#include "components/text_adapter.h"
+#include "components/ui_chart.h"
+#include "components/ui_label.h"
+#include "components/ui_picker.h"
+#include "components/ui_scroll_view.h"
+#include "components/ui_toggle_button.h"
+#include "layout/grid_layout.h"
+#include "layout/list_layout.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestBorderMarginPadding : public UITest {
+public:
+    UITestBorderMarginPadding()
+    {
+        style_ = StyleDefault::GetDefaultStyle();
+        style_.bgOpa_ = OPA_OPAQUE;
+        style_.bgColor_ = Color::Gray();
+    }
+    virtual ~UITestBorderMarginPadding() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    void ReloadTest();
+    void InitUIToggleButton();
+    void InitAdapterData();
+    void UIKitUITestBorderMarginPaddingTest001();
+    void UIKitUITestBorderMarginPaddingTest002();
+    void UIKitUITestBorderMarginPaddingTest003();
+    void UIKitUITestBorderMarginPaddingTest004();
+    void UIKitUITestBorderMarginPaddingTest005();
+    void UIKitUITestBorderMarginPaddingTest006();
+    void UIKitUITestBorderMarginPaddingTest007();
+    void UIKitUITestBorderMarginPaddingTest008();
+    void UIKitUITestBorderMarginPaddingTest009();
+    void UIKitUITestBorderMarginPaddingTest010();
+    void UIKitUITestBorderMarginPaddingTest011();
+    void UIKitUITestBorderMarginPaddingTest012();
+    void UIKitUITestBorderMarginPaddingTest013();
+    void UIKitUITestBorderMarginPaddingTest014();
+    void UIKitUITestBorderMarginPaddingTest015();
+    void UIKitUITestBorderMarginPaddingTest016();
+    void UIKitUITestBorderMarginPaddingTest017();
+    void UIKitUITestBorderMarginPaddingTest018();
+    Style style_;
+
+private:
+    const int16_t BUTTON_GROUP_WIDTH = 200;
+    UIScrollView* scroll_ = nullptr;
+    GridLayout* layoutButton_ = nullptr;
+    ListLayout* listScroll_ = nullptr;
+    UIViewGroup* container_ = nullptr;
+    MarginListener* marginListener_ = nullptr;
+    BorderListener* borderListener_ = nullptr;
+    PaddingListener* paddingListener_ = nullptr;
+    UIChartPolyline* chart_ = nullptr;
+    UIChartDataSerial* dataSerial_ = nullptr;
+    TextAdapter* adapter_ = nullptr;
+    List<const char*>* adapterData_ = nullptr;
+    UIPicker* picker_ = nullptr;
+
+    void AddTitle(const char* text);
+};
+} // namespace OHOS
+#endif // UI_TEST_BORDER_MARGIN_PADDING_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_button/ui_test_button.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_button/ui_test_button.cpp
new file mode 100644 (file)
index 0000000..86f3fdf
--- /dev/null
@@ -0,0 +1,628 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+#include "ui_test_button.h"
+
+#include "common/screen.h"
+#include "components/root_view.h"
+#include "components/ui_digital_clock.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_radio_button.h"
+#include "components/ui_toggle_button.h"
+#include "font/ui_font.h"
+
+namespace OHOS {
+void UITestButton::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        container_->SetHorizontalScrollState(false);
+    }
+}
+
+void UITestButton::SubTearDown()
+{
+    if (checkBoxChangeListener_ != nullptr) {
+        delete checkBoxChangeListener_;
+        checkBoxChangeListener_ = nullptr;
+    }
+    if (checkBoxChangeListener1_ != nullptr) {
+        delete checkBoxChangeListener1_;
+        checkBoxChangeListener1_ = nullptr;
+    }
+    if (radioChangeListener_ != nullptr) {
+        delete radioChangeListener_;
+        radioChangeListener_ = nullptr;
+    }
+    if (radioChangeListener1_ != nullptr) {
+        delete radioChangeListener1_;
+        radioChangeListener1_ = nullptr;
+    }
+
+    if (toggleChangeListener_ != nullptr) {
+        delete toggleChangeListener_;
+        toggleChangeListener_ = nullptr;
+    }
+    if (toggleChangeListener1_ != nullptr) {
+        delete toggleChangeListener1_;
+        toggleChangeListener1_ = nullptr;
+    }
+    if (clickBigListener_ != nullptr) {
+        delete clickBigListener_;
+        clickBigListener_ = nullptr;
+    }
+    if (clickLeftListener_ != nullptr) {
+        delete clickLeftListener_;
+        clickLeftListener_ = nullptr;
+    }
+    if (clickRightListener_ != nullptr) {
+        delete clickRightListener_;
+        clickRightListener_ = nullptr;
+    }
+    if (clickUpListener_ != nullptr) {
+        delete clickUpListener_;
+        clickUpListener_ = nullptr;
+    }
+    if (clickDownListener_ != nullptr) {
+        delete clickDownListener_;
+        clickDownListener_ = nullptr;
+    }
+    if (clickSmallListener_ != nullptr) {
+        delete clickSmallListener_;
+        clickSmallListener_ = nullptr;
+    }
+}
+
+void UITestButton::TearDown()
+{
+    SubTearDown();
+    DeleteChildren(container_);
+    container_ = nullptr;
+}
+
+class TestBtnOnStateChangeListener : public OHOS::UICheckBox::OnChangeListener {
+public:
+    explicit TestBtnOnStateChangeListener(UILabel *uiLabel) : uiLabel_(uiLabel)
+    {}
+
+    ~TestBtnOnStateChangeListener()
+    {}
+
+    bool OnChange(UICheckBox::UICheckBoxState state) override
+    {
+        if (state == UICheckBox::UICheckBoxState::SELECTED) {
+            uiLabel_->SetText("ON");
+        } else {
+            uiLabel_->SetText("OFF");
+        }
+        uiLabel_->Invalidate();
+        return true;
+    }
+
+private:
+    UILabel *uiLabel_;
+};
+
+const UIView *UITestButton::GetTestView()
+{
+    if (container_ != nullptr) {
+        UILabel *empty = new UILabel();
+        container_->Add(empty);
+        empty->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, 0, Screen::GetInstance().GetWidth(), 100);  // 100 : height
+    }
+    UIKitCheckBoxTest001();
+    UIKitRadioButtonTest001();
+    UIKitToggleButtonTest001();
+    UIKitCheckBoxTest002();
+    UIKitRadioButtonTest002();
+    UIKitToggleButtonTest002();
+    UIKitButtonTest001();
+    return container_;
+}
+
+UIViewGroup *UITestButton::CreateButtonGroup(
+    int16_t posX, int16_t posY, UICheckBox::OnChangeListener **listener, UIViewType type, const char *name)
+{
+    UIViewGroup *group = new UIViewGroup();
+    group->SetPosition(posX, posY, 300, 150);  // 300: width, 150: height
+    UILabel *label = new UILabel();
+    group->Add(label);
+    label->SetPosition(10, 30, 80, 20);  // 10: posX 30 posY 80 width 20 height
+    label->SetText("State: ");
+
+    UILabel *label1 = new UILabel();
+    group->Add(label1);
+    label1->SetPosition(70, 30, 40, 20);  // 70: posX 30 posY 40 width 20 height
+    *listener = static_cast<UICheckBox::OnChangeListener *>(new TestBtnOnStateChangeListener(label1));
+
+    UICheckBox *checkBox = nullptr;
+    if (type == UIViewType::UI_TOGGLE_BUTTON) {
+        checkBox = static_cast<UICheckBox *>(new UIToggleButton());
+    } else if (type == UIViewType::UI_RADIO_BUTTON) {
+        checkBox = static_cast<UICheckBox *>(new UIRadioButton(name));
+    } else {
+        checkBox = new UICheckBox();
+        checkBox->SetImages("", "");
+    }
+    group->Add(checkBox);
+    checkBox->SetOnChangeListener(*listener);
+    checkBox->SetPosition(100, 0, 100, 100);  // 100: posX 0: posY; 100: width,height
+    if (checkBox->GetState() == UICheckBox::SELECTED) {
+        label1->SetText("ON");
+    } else {
+        label1->SetText("OFF");
+    }
+    return group;
+}
+
+void UITestButton::UIKitCheckBoxTest001()
+{
+    if (container_ != nullptr) {
+        UILabel *empty = new UILabel();
+        container_->Add(empty);
+        empty->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, 0, Screen::GetInstance().GetWidth(), 100);  // 100: height
+
+        UILabel *label = new UILabel();
+        container_->Add(label);
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE,
+            100,  // 100: y-coordinate
+            Screen::GetInstance().GetWidth(),
+            TITLE_LABEL_DEFAULT_HEIGHT);
+        label->SetText("checkbox功能");
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        // 40: posX 35 posY 100 width 100 height
+        UIViewGroup *group = CreateButtonGroup(40, 135, &checkBoxChangeListener_);
+        // 250: posX 35 posY 100 width 100 height
+        UIViewGroup *group1 = CreateButtonGroup(250, 135, &checkBoxChangeListener1_);
+        container_->Add(group);
+        container_->Add(group1);
+    }
+}
+
+void UITestButton::UIKitRadioButtonTest001()
+{
+    if (container_ != nullptr) {
+        UILabel *label = new UILabel();
+        container_->Add(label);
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, 230,     // 230:y-coordinate
+            Screen::GetInstance().GetWidth(), TITLE_LABEL_DEFAULT_HEIGHT);
+        label->SetText("radiobutton功能");
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        // 40: posX 260 posY 100 width 100 height
+        UIViewGroup *group = CreateButtonGroup(40, 260, &radioChangeListener_, UIViewType::UI_RADIO_BUTTON, "bb");
+        // 250: posX 260 posY 100 width 100 height
+        UIViewGroup *group1 = CreateButtonGroup(250, 260, &radioChangeListener1_, UIViewType::UI_RADIO_BUTTON, "bb");
+        container_->Add(group);
+        container_->Add(group1);
+    }
+}
+
+void UITestButton::UIKitToggleButtonTest001()
+{
+    if (container_ != nullptr) {
+        UILabel *label = new UILabel();
+        container_->Add(label);
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, 370, // 370:y-coordinate
+            Screen::GetInstance().GetWidth(), TITLE_LABEL_DEFAULT_HEIGHT);
+        label->SetText("togglebutton功能");
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+
+        // 40: posX 300 posY 100 width 100 height
+        UIViewGroup *group = CreateButtonGroup(40, 400, &toggleChangeListener_, UIViewType::UI_TOGGLE_BUTTON);
+        // 250: posX 300 posY 100 width 100 height
+        UIViewGroup *group1 = CreateButtonGroup(250, 400, &toggleChangeListener1_, UIViewType::UI_TOGGLE_BUTTON);
+        container_->Add(group);
+        container_->Add(group1);
+    }
+}
+void UITestButton::UIKitCheckBoxTest002() const
+{
+    if (container_ != nullptr) {
+        UILabel *label = new UILabel();
+        container_->Add(label);
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, 566, // 566:y-coordinate
+            Screen::GetInstance().GetWidth(), TITLE_LABEL_DEFAULT_HEIGHT);
+        label->SetText("checkbox SetImage功能");
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+
+        UICheckBox *checkbox1 = new UICheckBox();
+        checkbox1->SetPosition(50, 620);  // 50: x-coordinate, 620: y-coordinate
+        UICheckBox *checkbox2 = new UICheckBox();
+        checkbox2->SetPosition(100, 620);  // 100: x-coordinate, 620: y-coordinate
+        checkbox2->SetWidth(130);          // 130: width
+        checkbox2->SetHeight(130);         // 130: height
+        checkbox2->SetImages(RES_PATH"blue.png", RES_PATH"yellow.png");
+
+        UICheckBox *checkbox3 = new UICheckBox();
+        checkbox3->SetPosition(150, 620);  // 150: x-coordinate, 620: y-coordinate
+        checkbox3->SetWidth(130);          // 130: width
+        checkbox3->SetHeight(130);         // 130: height
+        checkbox3->SetImages(RES_PATH"green.png", RES_PATH"red.png");
+
+        container_->Add(checkbox1);
+        container_->Add(checkbox2);
+        container_->Add(checkbox3);
+    }
+}
+
+void UITestButton::UIKitRadioButtonTest002() const
+{
+    if (container_ != nullptr) {
+        UILabel *label = new UILabel();
+        container_->Add(label);
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, 670, // 670:y-coordinate
+            Screen::GetInstance().GetWidth(), TITLE_LABEL_DEFAULT_HEIGHT);
+        label->SetText("radiobutton SetImage功能");
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+
+        UIRadioButton *radioButton = new UIRadioButton("aaa");
+        radioButton->SetPosition(30, 10);  // 30: x-coordinate, 10: y-coordinate
+        radioButton->SetWidth(130);        // 130: width
+        radioButton->SetHeight(130);       // 130: height
+        radioButton->SetImages(RES_PATH"blue.png", RES_PATH"yellow.png");
+
+        UIRadioButton *radioButton2 = new UIRadioButton("aaa");
+        radioButton2->SetPosition(200, 10);  // 200: x-coordinate, 10: y-coordinate
+        radioButton2->SetWidth(130);         // 130: width
+        radioButton2->SetHeight(130);        // 130: height
+        radioButton2->SetImages(RES_PATH"green.png", RES_PATH"red.png");
+
+        OHOS::UIViewGroup *viewGroup = new UIViewGroup();
+        viewGroup->SetPosition(0, 700);                               // 0: x-coordinate, 700: y-coordinate
+        viewGroup->SetWidth(Screen::GetInstance().GetWidth());        // 2: half width
+        viewGroup->SetHeight(Screen::GetInstance().GetHeight() / 2);  // 2: half height
+
+        viewGroup->Add(radioButton);
+        viewGroup->Add(radioButton2);
+        viewGroup->SetStyle(STYLE_BACKGROUND_OPA, 0);
+
+        container_->Add(viewGroup);
+    }
+}
+
+void UITestButton::UIKitToggleButtonTest002()
+{
+    if (container_ != nullptr) {
+        UILabel *label = new UILabel();
+        container_->Add(label);
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, 840, // 840: y-coordinate
+            Screen::GetInstance().GetWidth(), TITLE_LABEL_DEFAULT_HEIGHT);
+        label->SetText("togglebutton SetImage功能");
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+
+        UIToggleButton *togglebutton = new UIToggleButton();
+        togglebutton->SetPosition(30, 870);               // 30: x-coordinate, 870: y-coordinate
+        togglebutton->SetStyle(STYLE_BACKGROUND_OPA, 0);  // 0: opacity
+        togglebutton->SetState(true);
+        togglebutton->SetWidth(130);   // 130: width
+        togglebutton->SetHeight(130);  // 130: height
+        togglebutton->SetImages(RES_PATH"blue.png", RES_PATH"yellow.png");
+
+        UIToggleButton *togglebutton2 = new UIToggleButton();
+        togglebutton2->SetPosition(200, 870);              // 200: x-coordinate, 870: y-coordinate
+        togglebutton2->SetStyle(STYLE_BACKGROUND_OPA, 0);  // 0: opacity
+        togglebutton2->SetState(false);
+        togglebutton2->SetWidth(130);   // 130: width
+        togglebutton2->SetHeight(130);  // 130: height
+        togglebutton2->SetImages(RES_PATH"green.png", RES_PATH"red.png");
+
+        container_->Add(togglebutton);
+        container_->Add(togglebutton2);
+    }
+}
+
+class TestBtnOnClickShapeChangeListener : public UIView::OnClickListener {
+public:
+    TestBtnOnClickShapeChangeListener(UIView *uiView, int16_t grid) : uiView_(uiView), changeGrid_(grid)
+    {}
+
+    ~TestBtnOnClickShapeChangeListener()
+    {}
+
+    bool OnClick(UIView &view, const ClickEvent &event) override
+    {
+        int16_t width = uiView_->GetWidth() + changeGrid_;
+        int16_t height = uiView_->GetHeight() + changeGrid_;
+        if (changeGrid_ < 0) {
+            uiView_->Invalidate();
+        }
+        uiView_->Resize(width, height);
+        uiView_->Invalidate();
+        return true;
+    }
+
+private:
+    UIView *uiView_;
+    int16_t changeGrid_;
+};
+
+class TestBtnOnClickPositionChangeListener : public OHOS::UIView::OnClickListener {
+public:
+    enum class MoveType {
+        MOVE_LEFT,
+        MOVE_RIGHT,
+        MOVE_TOP,
+        MOVE_BOTTOM,
+    };
+    TestBtnOnClickPositionChangeListener(UIView *uiView, MoveType moveType, uint16_t grid)
+        : uiView_(uiView), moveType_(moveType), grid_(grid)
+    {}
+
+    ~TestBtnOnClickPositionChangeListener()
+    {}
+
+    bool OnClick(UIView &view, const ClickEvent &event) override
+    {
+        int16_t xPos = uiView_->GetX();
+        int16_t yPos = uiView_->GetY();
+        uiView_->Invalidate();
+        if (moveType_ == MoveType::MOVE_LEFT) {
+            xPos = xPos - grid_;
+        } else if (moveType_ == MoveType::MOVE_RIGHT) {
+            xPos = xPos + grid_;
+        } else if (moveType_ == MoveType::MOVE_TOP) {
+            yPos = yPos - grid_;
+        } else if (moveType_ == MoveType::MOVE_BOTTOM) {
+            yPos = yPos + grid_;
+        }
+        uiView_->SetX(xPos);
+        uiView_->SetY(yPos);
+        uiView_->Invalidate();
+        return true;
+    }
+
+private:
+    UIView *uiView_;
+    MoveType moveType_;
+    uint16_t grid_;
+};
+
+class TestBtnOnClickVisableListener : public OHOS::UIView::OnClickListener {
+public:
+    TestBtnOnClickVisableListener(UIView *uiView, bool visible) : uiView_(uiView), visible_(visible)
+    {}
+
+    ~TestBtnOnClickVisableListener()
+    {}
+
+    bool OnClick(UIView &view, const ClickEvent &event) override
+    {
+        uiView_->SetVisible(visible_);
+        uiView_->Invalidate();
+        return true;
+    }
+
+private:
+    UIView *uiView_;
+    bool visible_;
+};
+
+class TestBtnOnClickTouchableListener : public UIView::OnClickListener {
+public:
+    TestBtnOnClickTouchableListener(UIView *uiView, bool touchable) : uiView_(uiView), touchable_(touchable)
+    {}
+
+    ~TestBtnOnClickTouchableListener()
+    {}
+
+    bool OnClick(UIView &view, const ClickEvent &event) override
+    {
+        uiView_->SetTouchable(touchable_);
+        uiView_->Invalidate();
+        return true;
+    }
+
+private:
+    UIView *uiView_;
+    bool touchable_;
+};
+
+class TestBtnOnClickChangeColorListener : public OHOS::UIView::OnClickListener {
+public:
+    TestBtnOnClickChangeColorListener(UIView *uiView, uint16_t red, uint16_t green, uint16_t blue)
+        : uiView_(uiView), red_(red), green_(green), blue_(blue)
+    {}
+
+    ~TestBtnOnClickChangeColorListener()
+    {}
+
+    bool OnClick(UIView &view, const ClickEvent &event) override
+    {
+        ColorType color;
+        color.full = uiView_->GetStyle(STYLE_BACKGROUND_COLOR);
+        color.red = red_;
+        color.green = green_;
+        color.blue = blue_;
+        uiView_->SetStyle(STYLE_BACKGROUND_COLOR, color.full);
+        uiView_->Invalidate();
+        return true;
+    }
+
+private:
+    UIView *uiView_;
+    uint16_t red_;
+    uint16_t green_;
+    uint16_t blue_;
+};
+
+class TestBtnOnClickRevertColorListener : public UIView::OnClickListener {
+public:
+    explicit TestBtnOnClickRevertColorListener(UIView *uiView) : uiView_(uiView), originColor_(0)
+    {
+        if (uiView != nullptr) {
+            originColor_ = uiView->GetStyle(STYLE_BACKGROUND_COLOR);
+        }
+    }
+
+    ~TestBtnOnClickRevertColorListener()
+    {}
+
+    bool OnClick(UIView &view, const ClickEvent &event) override
+    {
+        uiView_->SetStyle(STYLE_BACKGROUND_COLOR, originColor_);
+        uiView_->Invalidate();
+        return true;
+    }
+
+private:
+    UIView *uiView_;
+    uint32_t originColor_;
+};
+
+class TestBtnOnClickRevertToOriginStateListener : public UIView::OnClickListener {
+public:
+    explicit TestBtnOnClickRevertToOriginStateListener(UIView *uiView)
+        : uiView_(uiView), originColor_(0), width_(0), height_(0), visible_(false), touchable_(false)
+    {
+        if (uiView != nullptr) {
+            originColor_ = uiView->GetStyle(STYLE_BACKGROUND_COLOR);
+            width_ = uiView->GetWidth();
+            height_ = uiView->GetHeight();
+            visible_ = uiView->IsVisible();
+            touchable_ = uiView->IsTouchable();
+        }
+    }
+
+    ~TestBtnOnClickRevertToOriginStateListener()
+    {}
+
+    bool OnClick(UIView &view, const ClickEvent &event) override
+    {
+        uiView_->Invalidate();
+        uiView_->SetStyle(STYLE_BACKGROUND_COLOR, originColor_);
+        uiView_->SetWidth(width_);
+        uiView_->SetHeight(height_);
+        uiView_->SetVisible(visible_);
+        uiView_->SetTouchable(touchable_);
+        ((UIButton *)uiView_)->Invalidate();
+        return true;
+    }
+
+private:
+    UIView *uiView_;
+    uint32_t originColor_;
+    uint32_t width_;
+    uint32_t height_;
+    bool visible_;
+    bool touchable_;
+};
+
+#if DEFAULT_ANIMATION
+class TestBtnAnimationListener : public UIView::OnClickListener {
+public:
+    TestBtnAnimationListener(UIView *uiView, bool enableAnimation) : uiView_(uiView), enableAnimation_(enableAnimation)
+    {}
+
+    ~TestBtnAnimationListener()
+    {}
+
+    bool OnClick(UIView &view, const ClickEvent &event) override
+    {
+        static_cast<UIButton *>(uiView_)->EnableButtonAnimation(enableAnimation_);
+        return true;
+    }
+
+private:
+    UIView *uiView_;
+    bool enableAnimation_;
+};
+#endif
+
+UILabel *GetTestUILabel(const char *titlename)
+{
+    if (titlename == nullptr) {
+        return nullptr;
+    }
+
+    UILabel *label = new UILabel();
+    // 900:y-coordinate
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, 900, Screen::GetInstance().GetWidth(), TITLE_LABEL_DEFAULT_HEIGHT);
+    label->SetText(titlename);
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    return label;
+}
+
+UILabelButton *GetTestUIButton(const char *buttonText, int16_t x, int16_t y, UIButton *button)
+{
+    if (buttonText == nullptr) {
+        return nullptr;
+    }
+
+    UILabelButton *labelButton = new UILabelButton();
+    // 150: x-coordinate, 440: y-coordinate
+    labelButton->SetPosition(x, y);
+    labelButton->Resize(BUTTON_WIDHT1, BUTTON_HEIGHT1);
+    labelButton->SetText(buttonText);
+    labelButton->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    labelButton->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+    labelButton->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+    labelButton->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+    labelButton->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+    labelButton->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+    return labelButton;
+}
+
+void InitButton(
+    UILabelButton *labelButton, UIView::OnClickListener *&listener, UIView::OnClickListener *&targetListener)
+{
+    if (listener == nullptr) {
+        listener = targetListener;
+    }
+    labelButton->SetOnClickListener(listener);
+}
+
+void UITestButton::UIKitButtonTest001()
+{
+    if (container_ != nullptr) {
+        UILabel *label = GetTestUILabel("普通button功能效果");
+        container_->Add(label);
+
+        UIButton *button = new UIButton();
+        button->SetPosition(10, 1035);  // 10: x-coordinate, 1035: y-coordinate
+        button->SetWidth(80);           // 80: width
+        button->SetHeight(60);          // 60: height
+        button->SetImageSrc(RES_PATH"blue.png", RES_PATH"yellow.png");
+
+        UILabelButton *button2 = GetTestUIButton("放大", 160, 940, button);  // 160: x-coordinate, 940: y-coordinate
+        UIView::OnClickListener *l2 = new TestBtnOnClickShapeChangeListener(button, CHANGE_SIZE);
+        InitButton(button2, clickBigListener_, l2);
+
+        UILabelButton *button3 = GetTestUIButton("缩小", 160, 990, button);  // 160: x-coordinate, 990: y-coordinate
+        UIView::OnClickListener *l3 = new TestBtnOnClickShapeChangeListener(button, -CHANGE_SIZE);
+        InitButton(button3, clickSmallListener_, l3);
+
+        UILabelButton *button4 = GetTestUIButton("左移", 250, 940, button);  // 250: x-coordinate, 940: y-coordinate
+        UIView::OnClickListener *l4 = new TestBtnOnClickPositionChangeListener(
+            (UIView *)button, TestBtnOnClickPositionChangeListener::MoveType::MOVE_LEFT, CHANGE_SIZE);
+        InitButton(button4, clickLeftListener_, l4);
+
+        UILabelButton *button5 = GetTestUIButton("右移", 250, 990, button);  // 250: x-coordinate, 990: y-coordinate
+        UIView::OnClickListener *l5 = new TestBtnOnClickPositionChangeListener(
+            (UIView *)button, TestBtnOnClickPositionChangeListener::MoveType::MOVE_RIGHT, CHANGE_SIZE);
+        InitButton(button5, clickRightListener_, l5);
+
+        UILabelButton *button6 = GetTestUIButton("上移", 340, 940, button);  // 340: x-coordinate, 940: y-coordinate
+        UIView::OnClickListener *l6 = new TestBtnOnClickPositionChangeListener(
+            (UIView *)button, TestBtnOnClickPositionChangeListener::MoveType::MOVE_TOP, CHANGE_SIZE);
+        InitButton(button6, clickUpListener_, l6);
+
+        UILabelButton *button7 = GetTestUIButton("下移", 340, 990, button);  // 340: x-coordinate, 990: y-coordinate
+        UIView::OnClickListener *l7 = new TestBtnOnClickPositionChangeListener(
+            (UIView *)button, TestBtnOnClickPositionChangeListener::MoveType::MOVE_BOTTOM, CHANGE_SIZE);
+        InitButton(button7, clickDownListener_, l7);
+
+        container_->Add(button);
+        container_->Add(button2);
+        container_->Add(button3);
+        container_->Add(button4);
+        container_->Add(button5);
+        container_->Add(button6);
+        container_->Add(button7);
+    }
+}
+}  // namespace OHOS
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_button/ui_test_button.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_button/ui_test_button.h
new file mode 100644 (file)
index 0000000..0f91286
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+#ifndef UI_TEST_BUTTON_H
+#define UI_TEST_BUTTON_H
+
+#include "components/ui_button.h"
+#include "components/ui_checkbox.h"
+#include "components/ui_scroll_view.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestButton : public UITest {
+public:
+    UITestButton() {}
+    ~UITestButton() {}
+    void SetUp() override;
+    void TearDown() override;
+    void SubTearDown();
+
+    const UIView* GetTestView() override;
+
+    /**
+     * @brief Test Checkbox Function
+     */
+    void UIKitCheckBoxTest001();
+
+    /**
+     * @brief Test Checkbox's SetImage Function
+     */
+    void UIKitCheckBoxTest002() const;
+
+    /**
+     * @brief Test Radiobutton Function
+     */
+    void UIKitRadioButtonTest001();
+
+    /**
+     * @brief Test Radiobutton's SetImage Function
+     */
+    void UIKitRadioButtonTest002() const;
+
+    /**
+     * @brief Test Togglebutton Function
+     */
+    void UIKitToggleButtonTest001();
+
+    /**
+     * @brief Test Togglebutton's SetImage Function
+     */
+    void UIKitToggleButtonTest002();
+
+    /**
+     * @brief Test button Function
+     */
+    void UIKitButtonTest001();
+
+private:
+    void UIKit_Button_Test_002(UIScrollView* container, UIButton* button);
+    UIViewGroup* CreateButtonGroup(int16_t posX, int16_t posY,
+                                    UICheckBox::OnChangeListener** listener,
+                                    UIViewType type = UI_CHECK_BOX,
+                                    const char* name = "aa");
+    static constexpr int16_t CHANGE_SIZE = 10;
+    UIScrollView* container_ = nullptr;
+
+    UICheckBox::OnChangeListener* checkBoxChangeListener_ = nullptr;
+    UICheckBox::OnChangeListener* checkBoxChangeListener1_ = nullptr;
+    UICheckBox::OnChangeListener* radioChangeListener_ = nullptr;
+    UICheckBox::OnChangeListener* radioChangeListener1_ = nullptr;
+    UICheckBox::OnChangeListener* toggleChangeListener_ = nullptr;
+    UICheckBox::OnChangeListener* toggleChangeListener1_ = nullptr;
+
+    UIView::OnClickListener* clickBigListener_ = nullptr;
+    UIView::OnClickListener* clickLeftListener_ = nullptr;
+    UIView::OnClickListener* clickRightListener_ = nullptr;
+    UIView::OnClickListener* clickUpListener_ = nullptr;
+    UIView::OnClickListener* clickDownListener_ = nullptr;
+    UIView::OnClickListener* clickSmallListener_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_BUTTON_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_canvas/ui_test_canvas.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_canvas/ui_test_canvas.cpp
new file mode 100644 (file)
index 0000000..95b18c7
--- /dev/null
@@ -0,0 +1,810 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_canvas.h"
+#include "common/screen.h"
+#include "components/ui_label.h"
+
+namespace OHOS {
+void UITestCanvas::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        container_->SetHorizontalScrollState(false);
+        container_->SetThrowDrag(true);
+    }
+    positionY_ = 0;
+}
+
+void UITestCanvas::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+}
+
+const UIView* UITestCanvas::GetTestView()
+{
+    UIKitCanvasTestDrawLine001();
+    UIKitCanvasTestDrawLine002();
+    UIKitCanvasTestDrawCurve001();
+    UIKitCanvasTestDrawCurve002();
+    UIKitCanvasTestDrawRect001();
+    UIKitCanvasTestDrawRect002();
+    UIKitCanvasTestDrawRect003();
+    UIKitCanvasTestDrawCircle001();
+    UIKitCanvasTestDrawCircle002();
+    UIKitCanvasTestDrawCircle003();
+    UIKitCanvasTestDrawArc001();
+    UIKitCanvasTestDrawImage001();
+    UIKitCanvasTestDrawLabel001();
+    UIKitCanvasTestDrawSector001();
+    UIKitCanvasTestDrawPath003();
+    UIKitCanvasTestDrawPath004();
+    UIKitCanvasTestDrawPath006();
+    UIKitCanvasTestDrawPath007();
+    UIKitCanvasTestDrawPath008();
+    UIKitCanvasTestDrawPath009();
+    UIKitCanvasTestDrawPath010();
+    UIKitCanvasTestDrawPath011();
+    UIKitCanvasTestDrawPath012();
+    UIKitCanvasTestDrawPath013();
+    UIKitCanvasTestDrawPath014();
+    UIKitCanvasTestDrawPath015();
+    UIKitCanvasTestDrawPath016();
+    UIKitCanvasTestDrawPath017();
+    UIKitCanvasTestDrawPath018();
+    UIKitCanvasTestDrawPath019();
+    UIKitCanvasTestDrawPath020();
+    UIKitCanvasTestDrawPath023();
+    UIKitCanvasTestDrawPath025();
+    UIKitCanvasTestDrawPath026();
+    UIKitCanvasTestDrawPath027();
+    UIKitCanvasTestDrawPath028();
+    UIKitCanvasTestDrawPath029();
+    UIKitCanvasTestDrawPath030();
+    UIKitCanvasTestDrawPath031();
+    UIKitCanvasTestDrawPath032();
+    UIKitCanvasTestDrawPath033();
+    UIKitCanvasTestDrawPath034();
+
+    return container_;
+}
+
+void UITestCanvas::CreateTitleLabel(const char* title)
+{
+    UILabel* titleLabel = new UILabel();
+    titleLabel->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, positionY_, Screen::GetInstance().GetWidth(), TITLE_HEIGHT);
+    titleLabel->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    titleLabel->SetText(title);
+    container_->Add(titleLabel);
+    positionY_ += TITLE_HEIGHT + 8; // 8: gap
+}
+
+UICanvas* UITestCanvas::CreateCanvas()
+{
+    UICanvas* canvas = new UICanvas();
+    canvas->SetHeight(CANVAS_HEIGHT);
+    canvas->SetWidth(CANVAS_WIDTH);
+    canvas->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, positionY_);
+    canvas->SetStyle(STYLE_BACKGROUND_COLOR, Color::Gray().full);
+    container_->Add(canvas);
+    positionY_ += CANVAS_HEIGHT + GAP;
+    return canvas;
+}
+
+void UITestCanvas::UIKitCanvasTestDrawLine001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("绘制直线");
+    UICanvas* canvas = CreateCanvas();
+    Paint paint;
+    // {0, 10}: Start point coordinates x, y; {50, 10}: end point coordinates x, y
+    canvas->DrawLine({0, 10}, {50, 10}, paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawLine002()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("绘制直线");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    paint.SetStrokeWidth(5); // 5: line width
+    canvas->SetStartPosition({ 50, 10 }); // {50, 10}: Start point coordinates x, y;
+    canvas->DrawLine({ 100, 50 }, paint); // {100, 50}: end point coordinates x, y
+}
+
+void UITestCanvas::UIKitCanvasTestDrawCurve001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("绘制曲线");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    paint.SetStrokeColor(Color::Red());
+    canvas->DrawCurve({ 100, 50 }, { 150, 50 }, { 150, 50 }, { 150, 100 }, paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawCurve002()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("绘制曲线");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    paint.SetStrokeColor(Color::Red());
+    canvas->DrawCurve({ 100, 50 }, { 150, 50 }, { 150, 100 }, paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawRect001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("矩形填充");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    paint.SetStyle(Paint::PaintStyle::FILL_STYLE);
+    paint.SetFillColor(Color::Yellow());
+    paint.SetStrokeWidth(30); // 30: line width
+    // {100, 10}: left corner coordinates point, 50: width, 50: rectangle style
+    canvas->DrawRect({ 100, 10 }, 50, 50, paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawRect002()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("矩形描边");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    paint.SetStyle(Paint::PaintStyle::STROKE_STYLE);
+    paint.SetStrokeColor(Color::Blue());
+    // {200, 10}: left corner coordinates point, 50: width, 50: rectangle style
+    canvas->DrawRect({ 200, 10 }, 50, 50, paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawRect003()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("矩形填充 + 描边");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    paint.SetStyle(Paint::PaintStyle::STROKE_FILL_STYLE);
+    paint.SetFillColor(Color::Yellow());
+    paint.SetStrokeColor(Color::Blue());
+    // {300, 10}: left corner coordinates point, 50: width, 50: rectangle style
+    canvas->DrawRect({ 300, 10 }, 50, 50, paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawCircle001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("圆形填充");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    paint.SetStyle(Paint::PaintStyle::FILL_STYLE);
+    paint.SetStrokeColor(Color::Yellow());
+    paint.SetFillColor(Color::Yellow());
+    paint.SetStrokeWidth(10); // 10: line width
+    paint.SetOpacity(127);    // 127: opacity
+    // {100, 100}: circle center coordinates, 30: circle radius
+    canvas->DrawCircle({ 100, 100 }, 30, paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawCircle002()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("圆形描边");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    paint.SetStyle(Paint::PaintStyle::STROKE_STYLE);
+    paint.SetStrokeColor(Color::Blue());
+    paint.SetStrokeWidth(10); // 10: line width
+    paint.SetOpacity(127);    // 127: opacity
+    // {200, 100}: circle center coordinates, 30: circle radius
+    canvas->DrawCircle({ 200, 100 }, 30, paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawCircle003()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("圆形填充 + 描边");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    paint.SetStyle(Paint::PaintStyle::STROKE_FILL_STYLE);
+    paint.SetFillColor(Color::Yellow());
+    paint.SetStrokeColor(Color::Blue());
+    paint.SetStrokeWidth(10); // 10: line width
+    paint.SetOpacity(127);    // 127: opacity
+    // {300, 100}: circle center coordinates, 30: circle radius
+    canvas->DrawCircle({ 300, 100 }, 30, paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawArc001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("绘制弧线");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    paint.SetStyle(Paint::PaintStyle::STROKE_STYLE);
+    paint.SetStrokeColor(Color::Red());
+    paint.SetStrokeWidth(10); // 10: line width
+    // {100, 150}: arc's center coordinates, 50: arc radius, 135: start angle, 270: end angle
+    canvas->DrawArc({ 100, 150 }, 50, 135, 270, paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawImage001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("绘制图片");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    paint.SetOpacity(127); // 127: opacity
+    // {200, 50}: start point coordinates
+    canvas->DrawImage({ 200, 50 }, RES_PATH"green.png", paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawLabel001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("绘制文字");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    paint.SetFillColor(Color::Blue());
+    UICanvas::FontStyle fontStyle;
+    fontStyle.align = TEXT_ALIGNMENT_RIGHT;
+    fontStyle.direct = TEXT_DIRECT_RTL;
+    fontStyle.fontName = DEFAULT_VECTOR_FONT_FILENAME;
+    fontStyle.fontSize = 30;    // 30: font size
+    fontStyle.letterSpace = 10; // 10 letter space
+    // {50, 50}: start point coordinates, 100: max width
+    canvas->DrawLabel({ 50, 50 }, "canvas绘制字体", 100, fontStyle, paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawSector001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("扇形填充");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    paint.SetStyle(Paint::PaintStyle::FILL_STYLE);
+    paint.SetFillColor(Color::Yellow());
+    // {350, 150}: sector's center coordinates, 100: sector radius, 0: start angle, 30: end angle
+    canvas->DrawSector({ 350, 150 }, 100, 0, 30, paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath003()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("arc");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->ArcTo({ CENTER_X, CENTER_Y }, RADIUS, START_ANGLE, END_ANGLE);
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath004()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("rect");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->AddRect({ RECT_X, RECT_Y }, RECT_HEIGHT, RECT_WIDTH);
+    canvas->DrawPath(paint);
+}
+
+
+void UITestCanvas::UIKitCanvasTestDrawPath006()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("moveTo + lineTo");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->LineTo({ LINE1_X, LINE1_Y });
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath007()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("moveTo + arc");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->ArcTo({ CENTER_X, CENTER_Y }, RADIUS, START_ANGLE, END_ANGLE);
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath008()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("moveTo + rect");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->AddRect({ RECT_X, RECT_Y }, RECT_HEIGHT, RECT_WIDTH);
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath009()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("moveTo + closePath");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->LineTo({ LINE1_X, LINE1_Y });
+    canvas->LineTo({ LINE2_X, LINE2_Y });
+    canvas->ClosePath();
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath010()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("闭合路径调用closePath");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->LineTo({ LINE1_X, LINE1_Y });
+    canvas->LineTo({ LINE2_X, LINE2_Y });
+    canvas->LineTo({ START1_X, START1_Y });
+    canvas->ClosePath();
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath011()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("moveTo + lineTo + moveTo + lineTo");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->LineTo({ LINE1_X, LINE1_Y });
+    canvas->MoveTo({ START2_X, START2_Y });
+    canvas->LineTo({ LINE2_X, LINE2_Y });
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath012()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("moveTo + lineTo + arc");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->LineTo({ LINE1_X, LINE1_Y });
+    canvas->ArcTo({ CENTER_X, CENTER_Y }, RADIUS, START_ANGLE, END_ANGLE);
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath013()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("moveTo + lineTo + arc + closePath");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->LineTo({ LINE1_X, LINE1_Y });
+    canvas->ArcTo({ CENTER_X, CENTER_Y }, RADIUS, START_ANGLE, END_ANGLE);
+    canvas->ClosePath();
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath014()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("moveTo + lineTo + rect");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->LineTo({ LINE1_X, LINE1_Y });
+    canvas->AddRect({ RECT_X, RECT_Y }, RECT_HEIGHT, RECT_WIDTH);
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath015()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("moveTo + lineTo + rect + closePath");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->LineTo({ LINE1_X, LINE1_Y });
+    canvas->AddRect({ RECT_X, RECT_Y }, RECT_HEIGHT, RECT_WIDTH);
+    canvas->ClosePath();
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath016()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("rect + lineTo");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->AddRect({ RECT_X, RECT_Y }, RECT_HEIGHT, RECT_WIDTH);
+    canvas->LineTo({ LINE1_X, LINE1_Y });
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath017()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("rect + moveTo + lineTo");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->AddRect({ RECT_X, RECT_Y }, RECT_HEIGHT, RECT_WIDTH);
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->LineTo({ LINE1_X, LINE1_Y });
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath018()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("rect + arc");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->AddRect({ RECT_X, RECT_Y }, RECT_HEIGHT, RECT_WIDTH);
+    canvas->ArcTo({ CENTER_X, CENTER_Y }, RADIUS, START_ANGLE, END_ANGLE);
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath019()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("arc + rect");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->ArcTo({ CENTER_X, CENTER_Y }, RADIUS, START_ANGLE, END_ANGLE);
+    canvas->AddRect({ RECT_X, RECT_Y }, RECT_HEIGHT, RECT_WIDTH);
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath020()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("moveTo + arc + closePath + lineTo");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->ArcTo({ CENTER_X, CENTER_Y }, RADIUS, START_ANGLE, END_ANGLE);
+    canvas->ClosePath();
+    canvas->LineTo({ LINE1_X, LINE1_Y });
+    canvas->DrawPath(paint);
+}
+
+
+void UITestCanvas::UIKitCanvasTestDrawPath023()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("moveTo + lineTo + closePath");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->LineTo({ LINE1_X, LINE1_Y });
+    canvas->ClosePath();
+    canvas->DrawPath(paint);
+}
+
+
+void UITestCanvas::UIKitCanvasTestDrawPath025()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("多次drawPath");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->LineTo({ LINE1_X, LINE1_Y });
+    canvas->DrawPath(paint);
+    paint.SetStrokeColor(Color::Blue());
+    paint.SetStrokeWidth(1);
+    canvas->LineTo({ LINE2_X, LINE2_Y });
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath026()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("arc起止角度互换");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->ArcTo({ CENTER_X, CENTER_Y }, RADIUS, START_ANGLE, END_ANGLE);
+
+    canvas->MoveTo({ START2_X, START2_Y });
+    canvas->ArcTo({ CENTER_X + CENTER_X, CENTER_Y }, RADIUS, END_ANGLE, START_ANGLE);
+
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath027()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("arc扫描范围超过360度 ");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->ArcTo({ CENTER_X, CENTER_Y }, RADIUS, START_ANGLE, START_ANGLE + CIRCLE_IN_DEGREE + QUARTER_IN_DEGREE);
+    canvas->ArcTo({ CENTER_X + CENTER_X, CENTER_Y }, RADIUS, END_ANGLE, START_ANGLE + CIRCLE_IN_DEGREE);
+
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath028()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("创建两条路径,只绘制后一条 ");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->ArcTo({ CENTER_X, CENTER_Y }, RADIUS, START_ANGLE, START_ANGLE + CIRCLE_IN_DEGREE);
+
+    canvas->BeginPath();
+    canvas->MoveTo({ START2_X, START2_Y });
+    canvas->ArcTo({ CENTER_X + CENTER_X, CENTER_Y }, RADIUS, END_ANGLE, START_ANGLE + CIRCLE_IN_DEGREE);
+
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath029()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("绘制两条不同样式的路径 ");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->ArcTo({ CENTER_X, CENTER_Y }, RADIUS, START_ANGLE, START_ANGLE + CIRCLE_IN_DEGREE);
+    canvas->DrawPath(paint);
+
+    canvas->BeginPath();
+    canvas->MoveTo({ START2_X, START2_Y });
+    canvas->ArcTo({ CENTER_X + CENTER_X, CENTER_Y }, RADIUS, END_ANGLE, START_ANGLE + CIRCLE_IN_DEGREE);
+    paint.SetStrokeColor(Color::Blue());
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath030()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("同一条路径绘制100遍 ");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->LineTo({ LINE1_X, LINE1_Y });
+    canvas->ArcTo({ CENTER_X, CENTER_Y }, RADIUS, START_ANGLE, START_ANGLE + CIRCLE_IN_DEGREE);
+    canvas->AddRect({ RECT_X, RECT_Y }, RECT_HEIGHT, RECT_WIDTH);
+    for (uint8_t i = 0; i < 100; i++) { // 100: number of times for drawing loops
+        canvas->DrawPath(paint);
+    }
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath031()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("绘制直线超出canvas范围");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ START1_X, START1_Y });
+    canvas->LineTo({ LINE1_X + HORIZONTAL_RESOLUTION, LINE1_Y });
+    canvas->LineTo({ LINE2_X, LINE2_Y });
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath032()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    CreateTitleLabel("绘制直线传入临界值 ");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->MoveTo({ INT16_MAX, INT16_MAX });
+    canvas->LineTo({ 0, 0 });
+
+    canvas->MoveTo({ 0, 0 });
+    canvas->LineTo({ INT16_MAX, INT16_MAX });
+
+    canvas->MoveTo({ INT16_MIN, INT16_MIN });
+    canvas->LineTo({ 0, 0 });
+
+    canvas->MoveTo({ 0, 0 });
+    canvas->LineTo({ INT16_MIN, INT16_MIN });
+    canvas->DrawPath(paint);
+}
+
+
+void UITestCanvas::UIKitCanvasTestDrawPath033()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    CreateTitleLabel("绘制arc传入临界值 ");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->ArcTo({ INT16_MAX, INT16_MAX }, RADIUS, START_ANGLE, END_ANGLE);
+    canvas->DrawPath(paint);
+
+    canvas->BeginPath();
+    canvas->ArcTo({ INT16_MIN, INT16_MIN }, RADIUS, START_ANGLE, END_ANGLE);
+    paint.SetStrokeColor(Color::Red());
+    canvas->DrawPath(paint);
+
+    canvas->BeginPath();
+    canvas->ArcTo({ CENTER_X, CENTER_Y }, UINT16_MAX, START_ANGLE, END_ANGLE);
+    paint.SetStrokeColor(Color::Yellow());
+    canvas->DrawPath(paint);
+
+    canvas->BeginPath();
+    canvas->ArcTo({ CENTER_X + CENTER_X, CENTER_Y }, RADIUS, INT16_MIN, INT16_MAX);
+    paint.SetStrokeColor(Color::Blue());
+    canvas->DrawPath(paint);
+}
+
+void UITestCanvas::UIKitCanvasTestDrawPath034()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    CreateTitleLabel("绘制rect传入临界值 ");
+    UICanvas* canvas = CreateCanvas();
+
+    Paint paint;
+    canvas->BeginPath();
+    canvas->AddRect({ INT16_MAX, INT16_MAX }, RECT_HEIGHT, RECT_WIDTH);
+    canvas->DrawPath(paint);
+
+    canvas->BeginPath();
+    canvas->AddRect({ RECT_X, RECT_Y }, INT16_MAX, INT16_MAX);
+    paint.SetStrokeColor(Color::Red());
+    canvas->DrawPath(paint);
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_canvas/ui_test_canvas.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_canvas/ui_test_canvas.h
new file mode 100644 (file)
index 0000000..0575d57
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_CANVAS_H
+#define UI_TEST_CANVAS_H
+
+#include "components/ui_canvas.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "layout/grid_layout.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestCanvas : public UITest {
+public:
+    UITestCanvas() {}
+    ~UITestCanvas() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    void UIKitCanvasTestDrawLine001();
+    void UIKitCanvasTestDrawLine002();
+    void UIKitCanvasTestDrawCurve001();
+    void UIKitCanvasTestDrawCurve002();
+    void UIKitCanvasTestDrawRect001();
+    void UIKitCanvasTestDrawRect002();
+    void UIKitCanvasTestDrawRect003();
+    void UIKitCanvasTestDrawCircle001();
+    void UIKitCanvasTestDrawCircle002();
+    void UIKitCanvasTestDrawCircle003();
+    void UIKitCanvasTestDrawArc001();
+    void UIKitCanvasTestDrawImage001();
+    void UIKitCanvasTestDrawLabel001();
+    void UIKitCanvasTestDrawSector001();
+    void UIKitCanvasTestClear001();
+    void UIKitCanvasTestDrawPath001();
+    void UIKitCanvasTestDrawPath002();
+    void UIKitCanvasTestDrawPath003();
+    void UIKitCanvasTestDrawPath004();
+    void UIKitCanvasTestDrawPath005();
+    void UIKitCanvasTestDrawPath006();
+    void UIKitCanvasTestDrawPath007();
+    void UIKitCanvasTestDrawPath008();
+    void UIKitCanvasTestDrawPath009();
+    void UIKitCanvasTestDrawPath010();
+    void UIKitCanvasTestDrawPath011();
+    void UIKitCanvasTestDrawPath012();
+    void UIKitCanvasTestDrawPath013();
+    void UIKitCanvasTestDrawPath014();
+    void UIKitCanvasTestDrawPath015();
+    void UIKitCanvasTestDrawPath016();
+    void UIKitCanvasTestDrawPath017();
+    void UIKitCanvasTestDrawPath018();
+    void UIKitCanvasTestDrawPath019();
+    void UIKitCanvasTestDrawPath020();
+    void UIKitCanvasTestDrawPath021();
+    void UIKitCanvasTestDrawPath022();
+    void UIKitCanvasTestDrawPath023();
+    void UIKitCanvasTestDrawPath024();
+    void UIKitCanvasTestDrawPath025();
+    void UIKitCanvasTestDrawPath026();
+    void UIKitCanvasTestDrawPath027();
+    void UIKitCanvasTestDrawPath028();
+    void UIKitCanvasTestDrawPath029();
+    void UIKitCanvasTestDrawPath030();
+    void UIKitCanvasTestDrawPath031();
+    void UIKitCanvasTestDrawPath032();
+    void UIKitCanvasTestDrawPath033();
+    void UIKitCanvasTestDrawPath034();
+
+private:
+    const static int16_t GAP = 10;
+    const static int16_t TITLE_HEIGHT = 29;
+    const static uint16_t CANVAS_WIDTH = 360;
+    const static uint16_t CANVAS_HEIGHT = 200;
+
+    static constexpr int16_t START1_X = 10;
+    static constexpr int16_t START1_Y = 10;
+    static constexpr int16_t START2_X = 80;
+    static constexpr int16_t START2_Y = 10;
+    static constexpr int16_t LINE1_X = 40;
+    static constexpr int16_t LINE1_Y = 100;
+    static constexpr int16_t LINE2_X = 100;
+    static constexpr int16_t LINE2_Y = 120;
+    static constexpr int16_t CENTER_X = 150;
+    static constexpr int16_t CENTER_Y = 150;
+    static constexpr int16_t RADIUS = 50;
+    static constexpr int16_t START_ANGLE = 30;
+    static constexpr int16_t END_ANGLE = 250;
+    static constexpr int16_t RECT_X = 250;
+    static constexpr int16_t RECT_Y = 50;
+    static constexpr int16_t RECT_WIDTH = 100;
+    static constexpr int16_t RECT_HEIGHT = 50;
+    void CreateTitleLabel(const char* title);
+    UICanvas* CreateCanvas();
+
+    UIScrollView* container_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_CANVAS_H
index 43a043d..5361562 100644 (file)
@@ -31,19 +31,19 @@ void UITestChartPillar::SetUp()
 
     dataSerial_[0] = new UIChartDataSerial();
     dataSerial_[0]->SetMaxDataCount(5); // 5: number of data points
-    Point pointArray[5] = {{0, 150}, {1, 250}, {2, 170}, {3, 220}, {4, 140}};
+    Point pointArray[5] = {{0, 5}, {1, 5}, {2, 5}, {3, 90}, {4, 100}};
     dataSerial_[0]->AddPoints(pointArray, 5); // 5: number of data points
     dataSerial_[0]->SetFillColor(Color::Cyan());
 
     dataSerial_[1] = new UIChartDataSerial();
     dataSerial_[1]->SetMaxDataCount(5); // 5: number of data points
-    Point pointArray1[5] = {{0, 200}, {1, 190}, {2, 220}, {3, 180}, {4, 170}};
+    Point pointArray1[5] = {{0, 100}, {1, 5}, {2, 5}, {3, 20}, {4, 60}};
     dataSerial_[1]->AddPoints(pointArray1, 5); // 5: number of data points
     dataSerial_[1]->SetFillColor(Color::Gray());
 
     dataSerial_[2] = new UIChartDataSerial(); // 2 array index
     dataSerial_[2]->SetMaxDataCount(5); // 2 array index, 5: number of data points
-    Point pointArray2[5] = {{0, 140}, {1, 150}, {2, 160}, {3, 180}, {4, 200}};
+    Point pointArray2[5] = {{0, 5}, {1, 50}, {2, 5}, {3, 50}, {4, 20}};
     dataSerial_[2]->AddPoints(pointArray2, 5); // 2 array index, 5: number of data points
     dataSerial_[2]->SetFillColor(Color::White()); // 2 array index
     curDataIndex_ = 0;
@@ -91,19 +91,21 @@ const UIView* UITestChartPillar::GetTestView()
     UiKitChartPillarTestEnableReverse002();
     UiKitChartPillarTestSetAxisLineColor003();
     UiKitChartPillarTestSetAxisLineVisible004();
+    UiKitChartPillarTestSwitchCap005();
+    UiKitChartPillarTestSwitchPillarType006();
     return container_;
 }
 
 void UITestChartPillar::UiKitChartPillarTestAddDataSerial001()
 {
-    UILabel* label = GetTitleLabel("UIChartPillar效果 ");
+    UILabel* label = GetTitleLabel("UIChartPillarExt效果 ");
     if (label == nullptr) {
         return;
     }
     label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, TEXT_DISTANCE_TO_TOP_SIDE);
     container_->Add(label);
 
-    chart_ = new UIChartPillar();
+    chart_ = new UIChartPillarExt();
     chart_->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, VIEW_DISTANCE_TO_TOP_SIDE);
     chart_->SetWidth(350); // 350: width
     chart_->SetHeight(200); // 200: height
@@ -158,6 +160,21 @@ void UITestChartPillar::UiKitChartPillarTestSetAxisLineVisible004()
     SetUpButton(setAxisVisibleBtn_, "坐标轴不可见");
 }
 
+void UITestChartPillar::UiKitChartPillarTestSwitchCap005()
+{
+    switchCapBtn_ = new UILabelButton();
+    positionX_ = 48; // 48: x-coordinate
+    SetUpButton(switchCapBtn_, "Cap切换");
+}
+
+void UITestChartPillar::UiKitChartPillarTestSwitchPillarType006()
+{
+    switchPillarTypeBtn_ = new UILabelButton();
+    positionX_ = switchCapBtn_->GetX() + switchCapBtn_->GetWidth() + g_blank;
+    positionY_ = switchCapBtn_->GetY();
+    SetUpButton(switchPillarTypeBtn_, "模式切换");
+}
+
 bool UITestChartPillar::OnClick(UIView& view, const ClickEvent& event)
 {
     if (&view == addDataSerialBtn_) {
@@ -179,19 +196,30 @@ bool UITestChartPillar::OnClick(UIView& view, const ClickEvent& event)
         curDataIndex_ = 0;
         chart_->Invalidate();
     } else if (&view == reverseBtn_) {
-        chart_->EnableReverse(true);
+        reverseState_ = !reverseState_;
+        chart_->EnableReverse(reverseState_);
         chart_->Invalidate();
     } else if (&view == setAxisColorBtn_) {
-        UIXAxis& xAxis = chart_->GetXAxis();
-        UIYAxis& yAxis = chart_->GetYAxis();
-        xAxis.SetLineColor(Color::Orange());
-        yAxis.SetLineColor(Color::Green());
+        chart_->GetXAxis().SetLineColor(Color::Orange());
+        chart_->GetYAxis().SetLineColor(Color::Green());
         chart_->Invalidate();
     } else if (&view == setAxisVisibleBtn_) {
-        UIXAxis& xAxis = chart_->GetXAxis();
-        UIYAxis& yAxis = chart_->GetYAxis();
-        xAxis.SetVisible(false);
-        yAxis.SetVisible(false);
+        chart_->GetXAxis().SetVisible(false);
+        chart_->GetYAxis().SetVisible(false);
+        chart_->Invalidate();
+    } else if (&view == switchCapBtn_) {
+        if (chart_->GetStyle(STYLE_LINE_CAP) == CapType::CAP_ROUND) {
+            chart_->SetStyle(STYLE_LINE_CAP, CapType::CAP_NONE);
+        } else {
+            chart_->SetStyle(STYLE_LINE_CAP, CapType::CAP_ROUND);
+        }
+        chart_->Invalidate();
+    } else if (&view == switchPillarTypeBtn_) {
+        if (chart_->GetPillarType() == UIChartPillarExt::PillarType::PILLAR_NORMAL) {
+            chart_->SetPillarType(UIChartPillarExt::PillarType::PILLAR_STACKED);
+        } else {
+            chart_->SetPillarType(UIChartPillarExt::PillarType::PILLAR_NORMAL);
+        }
         chart_->Invalidate();
     }
     return true;
index 31daa17..bf4ef50 100644 (file)
@@ -16,7 +16,7 @@
 #ifndef UI_TEST_CHART_PILLAR_H
 #define UI_TEST_CHART_PILLAR_H
 
-#include "components/ui_chart.h"
+#include "components/ui_chart_pillar_ext.h"
 #include "components/ui_label.h"
 #include "components/ui_label_button.h"
 #include "components/ui_scroll_view.h"
@@ -39,6 +39,8 @@ public:
     void UiKitChartPillarTestEnableReverse002();
     void UiKitChartPillarTestSetAxisLineColor003();
     void UiKitChartPillarTestSetAxisLineVisible004();
+    void UiKitChartPillarTestSwitchCap005();
+    void UiKitChartPillarTestSwitchPillarType006();
 
 private:
     void SetLastPos(UIView* view);
@@ -46,15 +48,18 @@ private:
     static constexpr uint8_t DATA_NUM = 3;
     UIChartDataSerial *dataSerial_[DATA_NUM];
     uint8_t curDataIndex_ = 0;
+    bool reverseState_ = false;
 
     UIScrollView* container_ = nullptr;
-    UIChartPillar* chart_ = nullptr;
+    UIChartPillarExt* chart_ = nullptr;
     UILabelButton* addDataSerialBtn_ = nullptr;
     UILabelButton* deleteDataSerialBtn_ = nullptr;
     UILabelButton* clearDataSerialBtn_ = nullptr;
     UILabelButton* reverseBtn_ = nullptr;
     UILabelButton* setAxisColorBtn_ = nullptr;
     UILabelButton* setAxisVisibleBtn_ = nullptr;
+    UILabelButton* switchCapBtn_ = nullptr;
+    UILabelButton* switchPillarTypeBtn_ = nullptr;
 
     int16_t lastX_ = 0;
     int16_t lastY_ = 0;
index 98bd4f7..c48f391 100644 (file)
@@ -106,7 +106,7 @@ const UIView* UITestChartPolyline::GetTestView()
 void UITestChartPolyline::TestAddDataSerial()\r
 {\r
     chart_ = new UIChartPolyline();\r
-    chart_->SetPosition(50, 30); // 50: x, 30: y\r
+    chart_->SetPosition(100, 100); // 100: x, 100: y\r
     chart_->SetWidth(300);       // 300: width\r
     chart_->SetHeight(150);      // 150: height\r
 \r
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_chart/ui_test_scatter_plot.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_chart/ui_test_scatter_plot.cpp
new file mode 100644 (file)
index 0000000..ebab09d
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: UITestScatterPlot
+ * Author: Hisi Graphic Team
+ * Created: 2025-9
+ */
+
+#include "ui_test_scatter_plot.h"
+
+namespace OHOS {
+namespace {
+static int16_t g_blank = 20;
+} // namespace
+
+void UITestScatterPlot::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight());
+        container_->SetHorizontalScrollState(false);
+        container_->SetThrowDrag(true);
+    }
+
+    for (uint8_t i = 0; i < DATA_NUM; i++) {
+        dataSerial_[i] = new UIScatterPlotDataSerial();
+        dataSerial_[i]->SetMaxDataCount(10); // 10: max data count
+    }
+
+    UIChartDataSerial::PointStyle pointStyle;
+    pointStyle.radius = 5; // 5: inner radius
+    pointStyle.strokeWidth = 0; // 0: stroke width
+
+    // 5: cnt; {1, 2600}, {2, 3000}, {3, 3200}, {4, 2700}, {5, 2100} : point array [index, value]
+    Point pointArray[5] = {{1, 2600}, {2, 3000}, {3, 3200}, {4, 2700}, {5, 2100}};
+    dataSerial_[0]->AddPoints(pointArray, 5); // 5: number of data points
+
+    pointStyle.fillColor = Color::Silver();
+    dataSerial_[0]->SetPointStyle(pointStyle);
+
+    // 5: cnt; {1, 900}, {2, 1200}, {3, 700}, {4, 300}, {5, 1700} : point array [index, value]
+    Point pointArray1[5] = {{1, 900}, {2, 1200}, {3, 700}, {4, 300}, {5, 1700}};
+    dataSerial_[1]->AddPoints(pointArray1, 5); // 5: number of data points
+
+    pointStyle.fillColor = Color::Yellow();
+    dataSerial_[1]->SetPointStyle(pointStyle);
+
+    // 5: cnt; {1, 500}, {2, 700}, {3, 400}, {4, 1100}, {5, 1500} : point array [index, value]
+    Point pointArray2[5] = {{1, 1500}, {2, 1800}, {3, 1400}, {4, 1100}, {5, 800}};
+    dataSerial_[2]->AddPoints(pointArray2, 5);   // 2: array index, 5: number of data points
+
+    pointStyle.fillColor = Color::Magenta();
+    dataSerial_[2]->SetPointStyle(pointStyle); // 2: array index
+
+    curDataIndex_ = 0;
+}
+
+void UITestScatterPlot::InnerDeleteChildren(UIView* view) const
+{
+    if (view == nullptr) {
+        return;
+    }
+    while (view != nullptr) {
+        UIView* tempView = view;
+        view = view->GetNextSibling();
+        if (tempView->IsViewGroup()) {
+            InnerDeleteChildren(static_cast<UIViewGroup*>(tempView)->GetChildrenHead());
+        }
+        if (tempView->GetViewType() == UI_AXIS) {
+            continue;
+        }
+        if (tempView->GetParent() != nullptr) {
+            static_cast<UIViewGroup*>(tempView->GetParent())->Remove(tempView);
+        }
+        delete tempView;
+        tempView = nullptr;
+    }
+}
+
+void UITestScatterPlot::TearDown()
+{
+    chart_->ClearDataSerial();
+    for (uint8_t i = 0; i < DATA_NUM; i++) {
+        delete dataSerial_[i];
+        dataSerial_[i] = nullptr;
+    }
+    InnerDeleteChildren(container_);
+    container_ = nullptr;
+
+    lastX_ = 0;
+    lastY_ = 0;
+    positionX_ = 0;
+    positionY_ = 0;
+}
+
+const UIView* UITestScatterPlot::GetTestView()
+{
+    TestAddDataSerial();
+    TestReverse();
+    TestAddPoints();
+    return container_;
+}
+
+void UITestScatterPlot::TestAddDataSerial()
+{
+    chart_ = new UIScatterPlot();
+    chart_->SetPosition(100, 100); // 100: x, 100: y
+    chart_->SetWidth(300);       // 300: width
+    chart_->SetHeight(150);      // 150: height
+
+    UIXAxis& xAxis = chart_->GetXAxis();
+    UIYAxis& yAxis = chart_->GetYAxis();
+    xAxis.SetMarkNum(5);         // 5: number of scales
+    xAxis.SetDataRange(0, 10);    // 0: minimum value, 10: maximum value
+    yAxis.SetDataRange(0, 3500); // 0: minimum value, 3500: maximum value
+
+    chart_->AddDataSerial(dataSerial_[0]);
+    curDataIndex_++;
+    container_->Add(chart_);
+    SetLastPos(chart_);
+
+    addDataSerialBtn_ = new UILabelButton();
+    deleteDataSerialBtn_ = new UILabelButton();
+    clearDataSerialBtn_ = new UILabelButton();
+    topPointBtn_ = new UILabelButton();
+    bottomPointBtn_ = new UILabelButton();
+    headPointBtn_ = new UILabelButton();
+
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE;
+    positionY_ = lastY_ + 10; // 10: increase y-coordinate
+    SetUpButton(addDataSerialBtn_, "add data serial");
+    positionX_ = addDataSerialBtn_->GetX() + addDataSerialBtn_->GetWidth() + g_blank;
+    positionY_ = addDataSerialBtn_->GetY();
+    SetUpButton(deleteDataSerialBtn_, "delete");
+    positionX_ = deleteDataSerialBtn_->GetX() + deleteDataSerialBtn_->GetWidth() + g_blank;
+    positionY_ = deleteDataSerialBtn_->GetY();
+    SetUpButton(clearDataSerialBtn_, "clear");
+
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE;
+    SetUpButton(topPointBtn_, "max");
+    positionX_ = topPointBtn_->GetX() + topPointBtn_->GetWidth() + g_blank;
+    positionY_ = topPointBtn_->GetY();
+    SetUpButton(bottomPointBtn_, "min");
+    positionX_ = bottomPointBtn_->GetX() + bottomPointBtn_->GetWidth() + g_blank;
+    positionY_ = bottomPointBtn_->GetY();
+    SetUpButton(headPointBtn_, "head");
+}
+
+void UITestScatterPlot::TestReverse()
+{
+    reverseBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE;
+    SetUpButton(reverseBtn_, "reverse");
+    SetLastPos(reverseBtn_);
+}
+
+void UITestScatterPlot::TestAddPoints()
+{
+    addPointsBtn_ = new UILabelButton();
+    positionX_ = reverseBtn_->GetX() + reverseBtn_->GetWidth() + g_blank;
+    positionY_ = reverseBtn_->GetY();
+    SetUpButton(addPointsBtn_, "add points");
+    SetLastPos(addPointsBtn_);
+}
+
+bool UITestScatterPlot::OnClick(UIView& view, const ClickEvent& event)
+{
+    UIChartDataSerial::PointStyle pointStyle;
+    pointStyle.fillColor = Color::Silver();
+    pointStyle.radius = 5; // 5: Inner radius
+    pointStyle.strokeWidth = 2; // 2: stroke width
+
+    if (&view == addDataSerialBtn_) {
+        if (curDataIndex_ >= DATA_NUM) {
+            return true;
+        }
+        chart_->AddDataSerial(dataSerial_[curDataIndex_]);
+        curDataIndex_++;
+    } else if (&view == deleteDataSerialBtn_) {
+        if (curDataIndex_ <= 0) {
+            return true;
+        }
+        chart_->DeleteDataSerial(dataSerial_[curDataIndex_ - 1]);
+        curDataIndex_--;
+    } else if (&view == clearDataSerialBtn_) {
+        chart_->ClearDataSerial();
+        curDataIndex_ = 0;
+    } else if (&view == topPointBtn_) {
+        dataSerial_[0]->EnableTopPoint(true);
+        pointStyle.strokeColor = Color::Green();
+        dataSerial_[0]->SetTopPointStyle(pointStyle);
+        printf("EnableTopPoint!\n");
+    } else if (&view == bottomPointBtn_) {
+        dataSerial_[0]->EnableBottomPoint(true);
+        pointStyle.strokeColor = Color::Red();
+        dataSerial_[0]->SetBottomPointStyle(pointStyle);
+        printf("EnableBottomPoint!\n");
+    } else if (&view == headPointBtn_) {
+        dataSerial_[0]->EnableHeadPoint(true);
+        pointStyle.strokeColor = Color::Purple();
+        dataSerial_[0]->SetHeadPointStyle(pointStyle);
+        printf("EnableHeadPoint!\n");
+    } else if (&view == reverseBtn_) {
+        chart_->EnableReverse(true);
+        printf("EnableReverse!\n");
+    } else if (&view == addPointsBtn_) {
+        Point pointArray[2] = {{6, 2800}, {7, 2100}}; // 2: count; 6, 2800: index, height; 7, 2100: index, height
+        dataSerial_[0]->AddPoints(pointArray, 2); // 2: number of data points
+    }
+    chart_->Invalidate();
+    return true;
+}
+
+void UITestScatterPlot::SetUpButton(UILabelButton* btn, const char* title)
+{
+    if (btn == nullptr) {
+        return;
+    }
+    container_->Add(btn);
+    btn->SetPosition(positionX_, positionY_, 100, 50); // 100: button width, 50: height
+    positionY_ += btn->GetHeight() + 5; // 5: increase height
+    btn->SetText(title);
+    btn->SetOnClickListener(this);
+    container_->Invalidate();
+}
+
+void UITestScatterPlot::SetLastPos(UIView* view)
+{
+    if (view == nullptr) {
+        return;
+    }
+    lastX_ = view->GetX();
+    lastY_ = view->GetY() + view->GetHeight();
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_chart/ui_test_scatter_plot.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_chart/ui_test_scatter_plot.h
new file mode 100644 (file)
index 0000000..ead55d1
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: UITestScatterPlot
+ * Author: Hisi Graphic Team
+ * Created: 2025-9
+ */
+
+#ifndef UI_TEST_SCATTER_PLOT_H
+#define UI_TEST_SCATTER_PLOT_H
+
+#include "components/ui_chart.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "components/ui_scatter_plot.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestScatterPlot : public UITest, public UIView::OnClickListener {
+public:
+    UITestScatterPlot() {}
+    ~UITestScatterPlot() override {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    void SetUpButton(UILabelButton* btn, const char* title);
+    bool OnClick(UIView& view, const ClickEvent& event) override;
+
+    void TestAddDataSerial();
+    void TestReverse();
+    void TestGradientBottom();
+    void TestAddPoints();
+
+private:
+    void InnerDeleteChildren(UIView* view) const;
+    void SetLastPos(UIView* view);
+    static constexpr uint8_t DATA_NUM = 3;
+    UIScrollView* container_ = nullptr;
+    UIScatterPlot* chart_ = nullptr;
+    UIScatterPlotDataSerial *dataSerial_[DATA_NUM] = {0};
+    uint8_t curDataIndex_ = 0;
+
+    UILabelButton* addDataSerialBtn_ = nullptr;
+    UILabelButton* deleteDataSerialBtn_ = nullptr;
+    UILabelButton* clearDataSerialBtn_ = nullptr;
+    UILabelButton* reverseBtn_ = nullptr;
+    UILabelButton* topPointBtn_ = nullptr;
+    UILabelButton* bottomPointBtn_ = nullptr;
+    UILabelButton* headPointBtn_ = nullptr;
+    UILabelButton* addPointsBtn_ = nullptr;
+
+    int16_t lastX_ = 0;
+    int16_t lastY_ = 0;
+};
+} // namespace OHOS
+#endif // UI_TEST_SCATTER_PLOT_H
\ No newline at end of file
index c0c5c9b..fb15d0c 100644 (file)
@@ -332,22 +332,6 @@ namespace OHOS {
     constexpr const char *PNG_MAIN_DROP_DOWN_ALARM_B = RES_PATH"/DROPDOWN_ALARM_B.bin";
     constexpr const char *PNG_MAIN_DROP_DOWN_SETTING_B = RES_PATH"/DROPDOWN_SETTING_B.bin";
     constexpr const char *PNG_MAIN_DROP_DOWN_BLUETOOTH_B = RES_PATH"/DROPDOWN_BLUETOOTH_B.bin";
-
-    // 室内步行
-    constexpr const char *PNG_APPLIST_WALK_IMAGE = RES_PATH"/APPLIST_WALK.bin"; // Applist图标
-    constexpr const char *PNG_WALK_BACK_GROUND = RES_PATH"/WALK_BACK_GROUND.bin";
-    constexpr const char *PNG_WALK_IMAGE = RES_PATH"/INDOORWALK.bin";
-    constexpr const char *PNG_AEROBIC_IMAGE = RES_PATH"/AEROBIC.bin";
-    constexpr const char *PNG_ANAEROBIC_IMAGE = RES_PATH"/ANAEROBIC.bin";
-    constexpr const char *PNG_OPTIONS_BOX1_IMAGE = RES_PATH"/OPTIONS_BOX1.bin";
-    constexpr const char *PNG_OPTIONS_BOX2_IMAGE = RES_PATH"/OPTIONS_BOX2.bin";
-    constexpr const char *PNG_OPTIONS_BOX3_IMAGE = RES_PATH"/OPTIONS_BOX3.bin";
-    constexpr const char *PNG_OPTIONS_BOX4_IMAGE = RES_PATH"/OPTIONS_BOX4.bin";
-    constexpr const char *PNG_WALK_TIME_IMAGE = RES_PATH"/TIME_IMAGE.bin";
-    constexpr const char *PNG_WALK_DISTANCES_IMAGE = RES_PATH"/DISTANCES_IMAGE.bin";
-    constexpr const char *PNG_WALK_HEART_IMAGE = RES_PATH"/HEART_IMAGE.bin";
-    constexpr const char *PNG_WALK_SPEED_IMAGE = RES_PATH"/SPEED_IMAGE.bin";
-    constexpr const char *PNG_WALK_STEPS_IMAGE = RES_PATH"/STEPS_IMAGE.bin";
 }
 
 #endif // UI_CONFIG_H
index 14f2bc7..8d8406b 100644 (file)
@@ -16,7 +16,7 @@
 #include "ui_test_clock_dial.h"
 
 namespace OHOS {
-static UITestClockDial *g_pMainView = nullptr;
+static UITestClockDial* g_pMainView = nullptr;
 static constexpr uint16_t MESLABLE_X_TMP = 177;
 static constexpr uint16_t MESLABLE_Y_TMP = 212;
 static constexpr uint16_t MESLABLE_WIDTH_TMP = 100;
@@ -26,9 +26,11 @@ static constexpr uint8_t PULL_MIDDLE_VIEW_OPA = 0;
 
 struct MainViewMapper {
     CardId id;
-    AppGroupView *(UITestClockDial::*func)(void);
+    AppGroupView* (UITestClockDial::*func)(void);
 };
 
+static uint8_t g_modelIndex = 0;
+
 static const MainViewMapper PAGE_MAPPER[] = {
     {CardId::WATCH_FACE, &UITestClockDial::InitWatchFacePage},
     {CardId::ACTIVITY, &UITestClockDial::InitActivityPage},
@@ -36,6 +38,13 @@ static const MainViewMapper PAGE_MAPPER[] = {
     {CardId::COMPASS, &UITestClockDial::InitCompassPage},
 };
 
+static const char* g_transitionMapper[] = {
+    "1.推拉",
+    "2.翻页",
+    "3.立方体",
+    "4.卡片",
+};
+
 void SwipeListener::OnSwipe(UISwipeView& view)
 {
     UNUSED(view);
@@ -50,7 +59,7 @@ UITestClockDial::UITestClockDial()
     g_pMainView = this;
 }
 
-UITestClockDial *UITestClockDial::GetInstance(void)
+UITestClockDial* UITestClockDial::GetInstance(void)
 {
     return g_pMainView;
 }
@@ -65,7 +74,7 @@ void UITestClockDial::SetUp()
     }
 
     if (callback == nullptr) {
-        callback = new ZoomEffect();
+        SwitchFlipTypeMode(g_modelIndex);
         if (callback == nullptr) {
             delete mainSwipeGroup;
             mainSwipeGroup = nullptr;
@@ -80,13 +89,41 @@ void UITestClockDial::SetUp()
     VerticalViewInit();
     VertViewLoad();
     mainSwipeGroup->SetPosition(0, 0, Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight());
-    mainSwipeGroup->SetAnimatorTime(50); // 50: animator drag time(ms);
+    mainSwipeGroup->SetAnimatorTime(50);  // 50: animator drag time(ms);
     mainSwipeGroup->SetLoopState(true);
     mainSwipeGroup->EnableScreenCap(true);
     mainSwipeGroup->RegisterSwipeCallback(callback);
     mainSwipeGroup->SetHorCurrentPage(mainClockView->GetViewIndex());
 }
 
+void UITestClockDial::SwitchFlipTypeMode(uint8_t tmIndex)
+{
+    EffectType tm = static_cast<EffectType>(tmIndex);
+    if (callback != nullptr) {
+        delete callback;
+        callback = nullptr;
+    }
+    switch (tm) {
+        case EffectType::ZOOM:
+            callback = new ZoomEffect();
+            break;
+        case EffectType::TURN_PAGE:
+            callback = new TurnPageEffect();
+            break;
+        case EffectType::CUBE:
+            callback = new CubeEffect();
+            break;
+        case EffectType::CARD_FLIP:
+            callback = new CardFlipEffect();
+            break;
+        default:
+            callback = new ZoomEffect();
+    }
+    if (callback == nullptr) {
+        GRAPHIC_LOGE("callback new fail");
+    }
+}
+
 void UITestClockDial::TearDown()
 {
     dropDownView->ClearBackgroundBlur();
@@ -148,6 +185,11 @@ void UITestClockDial::TearDown()
         delete callback;
         callback = nullptr;
     }
+
+    if (controlButton != nullptr) {
+        delete controlButton;
+        controlButton = nullptr;
+    }
 }
 
 const UIView* UITestClockDial::GetTestView()
@@ -171,11 +213,11 @@ bool UITestClockDial::HorizontalViewInit(void)
     }
     recordCard[0]->InitView();
     pageStatus[0] = true;
-    if (maxPage >= 2) { // 2 is right card
+    if (maxPage >= 2) {  // 2 is right card
         recordCard[1]->InitView();
         pageStatus[1] = true;
     }
-    if (maxPage >= 3) { // 3 is left card
+    if (maxPage >= 3) {  // 3 is left card
         recordCard[maxPage - 1]->InitView();
         pageStatus[maxPage - 1] = true;
     }
@@ -224,6 +266,28 @@ void UITestClockDial::VerticalViewInit(void)
     messageLabel->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_SIZE_TMP);
     messageLabel->SetStyle(STYLE_BACKGROUND_COLOR, OPA_TRANSPARENT);
     messageView->Add(messageLabel);
+
+    controlButton = new UILabelButton();
+    controlButton->SetPosition(177, 350, 100, 50);  // 177, 350, 100, 50: left, right, width, height
+    controlButton->SetText(g_transitionMapper[g_modelIndex]);
+    controlButton->SetDragParentInstead(false);
+    controlButton->SetOnClickListener(this);
+    messageView->Add(controlButton);
+}
+
+bool UITestClockDial::OnClick(UIView& view, const ClickEvent& event)
+{
+    int length = sizeof(g_transitionMapper) / sizeof(g_transitionMapper[0]);
+    g_modelIndex = (g_modelIndex + 1) % length;  // 按钮循环显示文本
+    controlButton->SetText(g_transitionMapper[g_modelIndex]);
+    SwitchFlipTypeMode(g_modelIndex);
+    if (callback == nullptr) {
+        GRAPHIC_LOGE("callback new fail\n");
+        return false;
+    }
+    callback->SetContainer(mainSwipeGroup);
+    mainSwipeGroup->RegisterSwipeCallback(callback);
+    return true;
 }
 
 void UITestClockDial::VertViewLoad(void)
@@ -233,7 +297,7 @@ void UITestClockDial::VertViewLoad(void)
     GRAPHIC_LOGD("UITestClockDial::PullViewLoad::Pull View Load complete\n");
 }
 
-AppGroupView *UITestClockDial::InitWatchFacePage(void)
+AppGroupView* UITestClockDial::InitWatchFacePage(void)
 {
     mainClockView = new MainClockView();
     if (mainClockView == nullptr) {
@@ -243,7 +307,7 @@ AppGroupView *UITestClockDial::InitWatchFacePage(void)
     return mainClockView;
 }
 
-AppGroupView *UITestClockDial::InitHeartRatePage(void)
+AppGroupView* UITestClockDial::InitHeartRatePage(void)
 {
     heartRateView = new HeartRateView();
     if (heartRateView == nullptr) {
@@ -253,7 +317,7 @@ AppGroupView *UITestClockDial::InitHeartRatePage(void)
     return heartRateView;
 }
 
-AppGroupView *UITestClockDial::InitActivityPage(void)
+AppGroupView* UITestClockDial::InitActivityPage(void)
 {
     activityWeekView = new ActivityWeekView();
     if (activityWeekView == nullptr) {
@@ -263,7 +327,7 @@ AppGroupView *UITestClockDial::InitActivityPage(void)
     return activityWeekView;
 }
 
-AppGroupView *UITestClockDial::InitCompassPage(void)
+AppGroupView* UITestClockDial::InitCompassPage(void)
 {
     compassControlView = new CompassControlView();
     if (compassControlView == nullptr) {
@@ -273,10 +337,10 @@ AppGroupView *UITestClockDial::InitCompassPage(void)
     return compassControlView;
 }
 
-AppGroupView *UITestClockDial::GreatePage(int32_t streamId)
+AppGroupView* UITestClockDial::GreatePage(int32_t streamId)
 {
     uint16_t i;
-    AppGroupView *view = nullptr;
+    AppGroupView* view = nullptr;
     int32_t cardId = ScreenModel::GetInstance()->GetCardPage(streamId);
     GRAPHIC_LOGD("GreatePage cardId:%d\n", cardId);
     for (i = 0; i < sizeof(PAGE_MAPPER) / sizeof(PAGE_MAPPER[0]); i++) {
@@ -335,4 +399,4 @@ void UITestClockDial::AnimatorStop(void)
         heartRateView->HeartbeatImageAnimatorStop();
     }
 }
-}
+}  // namespace OHOS
index 5ff88ff..52dbc30 100644 (file)
@@ -22,6 +22,9 @@
 #include "components/ui_swipe_view.h"
 #include "components/ui_scroll_view.h"
 #include "swipe_effect/zoom_effect.h"
+#include "swipe_effect/cube_effect.h"
+#include "swipe_effect/card_flip_effect.h"
+#include "swipe_effect/turn_page_effect.h"
 #include "font/ui_font_bitmap.h"
 #include "font/ui_font.h"
 #include "graphic_config.h"
@@ -42,7 +45,14 @@ public:
     void OnSwipe(UISwipeView& view) override;
 };
 
-class UITestClockDial : public UITest {
+enum class EffectType {
+    ZOOM = 0,
+    TURN_PAGE,
+    CUBE,
+    CARD_FLIP,
+    ENUM_COUNT,
+};
+class UITestClockDial : public UITest, public UIView::OnClickListener {
 public:
     UITestClockDial();
     ~UITestClockDial() override {}
@@ -55,6 +65,7 @@ public:
     AppGroupView *InitWatchFacePage(void);
     AppGroupView *InitHeartRatePage(void);
     AppGroupView *InitActivityPage(void);
+    bool OnClick(UIView& view, const ClickEvent& event) override;   // Çл»ÌØÐÔ
     AppGroupView *InitCompassPage(void);
     void AnimatorStart(int pageIndex);
     void AnimatorStop(void);
@@ -81,12 +92,13 @@ private:
     bool pageStatus[static_cast<uint32_t>(CardId::MAX_CARD)]{false};
     UICrossView *mainSwipeGroup{nullptr};
     SwipeListener *listener{nullptr};
-    ZoomEffect* callback{nullptr};
-
+    CardSwipe* callback{nullptr};
+    UILabelButton* controlButton {nullptr}; // Çл»°´Å¥
     bool HorizontalViewInit(void);
     void VerticalViewInit(void);
     void VertViewLoad(void);
     void HorViewLoad(void);
+    void SwitchFlipTypeMode(uint8_t mode);
     AppGroupView *GreatePage(int32_t streamId);
 };
 }
index 604bf64..137756c 100644 (file)
@@ -49,7 +49,7 @@ static void ScreenStatusNotify(ScreenStatus status)
     } else if (status == SCREEN_STATUS_ON) {
         if (g_videoPlay->isPause_) {
             g_videoPlay->ResumeVideoPlay();
-        } else if (!g_video->isPlayed_) {
+        } else if (!g_videoPlay->isPlayed_) {
             g_videoPlay->StartVideoPlay();
         }
     }
@@ -165,7 +165,7 @@ void UITestCross::VideoPage::PageInit()
     std::string uri("/user/video/demo_pure_video_loop.mp4");
     videoPlay_ = new MediaVideoPlay(surface, nullptr, uri, true);
 #ifdef SUPPORT_OHOSFWK
-    g_videoPlay = videoPlayer_;
+    g_videoPlay = videoPlay_;
     registerNotifyScreenStatus(ScreenStatusNotify);
 #endif
 }
@@ -366,6 +366,7 @@ bool UITestCross::OnClick(UIView& view, const ClickEvent& event)
         if (pageIndex > 1) {
             pageIndex = 0;
         }
+#ifndef _WIN32
     } else if (&view == video_) {
         static uint16_t pageIndexFromCenter = 0;
         container_->SetVerCurrentPage(pageIndexFromCenter);
@@ -375,6 +376,7 @@ bool UITestCross::OnClick(UIView& view, const ClickEvent& event)
         } else {
             pageIndexFromCenter = 0;
         }
+#endif
     }
     return true;
 }
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_digital_clock/ui_test_digital_clock.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_digital_clock/ui_test_digital_clock.cpp
new file mode 100644 (file)
index 0000000..523619d
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_digital_clock.h"
+#include "common/screen.h"
+#include "components/ui_digital_clock.h"
+#include "components/ui_label.h"
+#include "font/ui_font.h"
+
+namespace OHOS {
+namespace {
+const int16_t GAP = 10;
+const int16_t TITLE_HEIGHT = 30;
+const uint16_t DIGITAL_CLOCK_WIDTH = 350;
+const uint16_t DIGITAL_CLOCK_HEIGHT = 50;
+} // namespace
+
+void UITestDigitalClock::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->SetThrowDrag(true);
+        container_->SetHorizontalScrollState(false);
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        positionX_ = 50;    // 50 : x
+        positionY_ = 10;    // 10 : y
+    }
+}
+
+void UITestDigitalClock::TearDown()
+{
+    UIView* view = static_cast<UIViewGroup*>(container_)->GetChildrenHead();
+    while (view != nullptr) {
+        UIView* tempView = view;
+        view = view->GetNextSibling();
+        if (tempView->GetParent()) {
+            static_cast<UIViewGroup*>(tempView->GetParent())->Remove(tempView);
+        }
+        delete tempView;
+    }
+    delete container_;
+    container_ = nullptr;
+}
+
+void UITestDigitalClock::InnerTestTitle(const char* title)
+{
+    UILabel* titleLabel = new UILabel();
+    titleLabel->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, positionY_, Screen::GetInstance().GetWidth(),
+                            TITLE_LABEL_DEFAULT_HEIGHT);
+    titleLabel->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    titleLabel->SetText(title);
+    container_->Add(titleLabel);
+    positionY_ += TITLE_HEIGHT + GAP;
+}
+
+const UIView* UITestDigitalClock::GetTestView()
+{
+    UIKitUIDigitalClockTestDisplay001();
+    UIKitUIDigitalClockTestDisplay002();
+    UIKitUIDigitalClockTestSetColor();
+    UIKitUIDigitalClockTestDisplayMode001();
+    UIKitUIDigitalClockTestDisplayMode002();
+    UIKitUIDigitalClockTestDisplayMode003();
+    UIKitUIDigitalClockTestDisplayMode004();
+    UIKitUIDigitalClockTestDisplayLeadingZero();
+    UIKitUIDigitalClockTestSetOpacity();
+    return container_;
+}
+
+void UITestDigitalClock::UIKitUIDigitalClockTestDisplay001()
+{
+    if (container_ != nullptr) {
+        UILabel* empty = new UILabel();
+        empty->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, positionY_, 10, 80); // 10 : weight; 80 : height
+        container_->Add(empty);
+        positionY_ += 80;   // 80 : y
+        InnerTestTitle("UIDigitalClock效果");
+        UIDigitalClock* dClock = new UIDigitalClock();
+        dClock->SetPosition(positionX_, positionY_);
+        dClock->Resize(DIGITAL_CLOCK_WIDTH, DIGITAL_CLOCK_HEIGHT);
+        dClock->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 30); // 30: font size
+        dClock->SetTime24Hour(7, 25, 50);                  // 7: hour, 25: minute, 50: second
+        container_->Add(dClock);
+        positionY_ += DIGITAL_CLOCK_HEIGHT + GAP;
+    }
+}
+
+void UITestDigitalClock::UIKitUIDigitalClockTestDisplay002()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("UIDigitalClock效果");
+        UIDigitalClock* dClock = new UIDigitalClock();
+        dClock->SetPosition(positionX_, positionY_);
+        dClock->Resize(DIGITAL_CLOCK_WIDTH, DIGITAL_CLOCK_HEIGHT);
+        dClock->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 30); // 30: font size
+        dClock->SetTime24Hour(7, 25, 50);                  // 7:hour, 25:minute, 50:second
+        container_->Add(dClock);
+        positionY_ += DIGITAL_CLOCK_HEIGHT + GAP;
+    }
+}
+
+void UITestDigitalClock::UIKitUIDigitalClockTestSetColor()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("设置Digital Clock颜色");
+        UIDigitalClock* dClock = new UIDigitalClock();
+        dClock->SetPosition(positionX_, positionY_);
+        dClock->Resize(DIGITAL_CLOCK_WIDTH, DIGITAL_CLOCK_HEIGHT);
+        dClock->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 30); // 30: font size
+        dClock->SetTime24Hour(7, 25, 50);                  // 7:hour, 25:minute, 50:second
+        dClock->SetColor(Color::Red());
+        container_->Add(dClock);
+        positionY_ += DIGITAL_CLOCK_HEIGHT + GAP;
+    }
+}
+
+void UITestDigitalClock::UIKitUIDigitalClockTestDisplayMode001()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("设置Digital Clock仅显示小时、分钟 ");
+        UIDigitalClock* dClock = new UIDigitalClock();
+        dClock->SetPosition(positionX_, positionY_);
+        dClock->Resize(DIGITAL_CLOCK_WIDTH, DIGITAL_CLOCK_HEIGHT);
+        dClock->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 30); // 30: font size
+        dClock->SetTime24Hour(17, 25, 50);                 // 17:hour, 25:minute, 50:second
+        dClock->SetDisplayMode(UIDigitalClock::DISPLAY_12_HOUR_NO_SECONDS);
+        container_->Add(dClock);
+        positionY_ += DIGITAL_CLOCK_HEIGHT + GAP;
+    }
+}
+
+void UITestDigitalClock::UIKitUIDigitalClockTestDisplayMode002()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("设置Digital Clock 24小时制仅显示小时、分钟 ");
+        UIDigitalClock* dClock = new UIDigitalClock();
+        dClock->SetPosition(positionX_, positionY_);
+        dClock->Resize(DIGITAL_CLOCK_WIDTH, DIGITAL_CLOCK_HEIGHT);
+        dClock->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 30); // 30: font size
+        dClock->SetTime24Hour(17, 25, 50);                 // 17:hour, 25:minute, 50:second
+        dClock->SetDisplayMode(UIDigitalClock::DISPLAY_24_HOUR_NO_SECONDS);
+        container_->Add(dClock);
+        positionY_ += DIGITAL_CLOCK_HEIGHT + GAP;
+    }
+}
+
+void UITestDigitalClock::UIKitUIDigitalClockTestDisplayMode003()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("设置Digital Clock 12小时制 ");
+        UIDigitalClock* dClock = new UIDigitalClock();
+        dClock->SetPosition(positionX_, positionY_);
+        dClock->Resize(DIGITAL_CLOCK_WIDTH, DIGITAL_CLOCK_HEIGHT);
+        dClock->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 30); // 30: font size
+        dClock->SetTime24Hour(17, 25, 50);                 // 17:hour, 25:minute, 50:second
+        dClock->SetDisplayMode(UIDigitalClock::DISPLAY_12_HOUR);
+        container_->Add(dClock);
+        positionY_ += DIGITAL_CLOCK_HEIGHT + GAP;
+    }
+}
+
+void UITestDigitalClock::UIKitUIDigitalClockTestDisplayMode004()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("设置Digital Clock 24小时制 ");
+        UIDigitalClock* dClock = new UIDigitalClock();
+        dClock->SetPosition(positionX_, positionY_);
+        dClock->Resize(DIGITAL_CLOCK_WIDTH, DIGITAL_CLOCK_HEIGHT);
+        dClock->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 30); // 30: font size
+        dClock->SetTime24Hour(17, 25, 50);                 // 17:hour, 25:minute, 50:second
+        dClock->SetDisplayMode(UIDigitalClock::DISPLAY_24_HOUR);
+        container_->Add(dClock);
+        positionY_ += DIGITAL_CLOCK_HEIGHT + GAP;
+    }
+}
+
+void UITestDigitalClock::UIKitUIDigitalClockTestDisplayLeadingZero()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("设置Digital Clock不显示首位的0 ");
+        UIDigitalClock* dClock = new UIDigitalClock();
+        dClock->SetPosition(positionX_, positionY_);
+        dClock->Resize(DIGITAL_CLOCK_WIDTH, DIGITAL_CLOCK_HEIGHT);
+        dClock->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 30); // 30: font size
+        dClock->SetTime24Hour(7, 5, 9);                    // 7:hour, 5:minute, 9:second
+        dClock->DisplayLeadingZero(false);
+        container_->Add(dClock);
+        positionY_ += DIGITAL_CLOCK_HEIGHT + GAP;
+    }
+}
+
+void UITestDigitalClock::UIKitUIDigitalClockTestSetOpacity()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("设置Digital Clock透明度 ");
+        UIDigitalClock* dClock = new UIDigitalClock();
+        dClock->SetPosition(positionX_, positionY_);
+        dClock->Resize(DIGITAL_CLOCK_WIDTH, DIGITAL_CLOCK_HEIGHT);
+        dClock->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 30); // 30: font size
+        dClock->SetTime24Hour(7, 5, 9);                    // 7:hour, 5:minute, 9:second
+        dClock->SetOpacity(178);                           // 178: num of opacity
+        container_->Add(dClock);
+        positionY_ += DIGITAL_CLOCK_HEIGHT + GAP;
+    }
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_digital_clock/ui_test_digital_clock.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_digital_clock/ui_test_digital_clock.h
new file mode 100644 (file)
index 0000000..d0a11ac
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_DIGITAL_CLOCK_H
+#define UI_TEST_DIGITAL_CLOCK_H
+
+#include "components/ui_scroll_view.h"
+#include "font/ui_font.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestDigitalClock : public UITest {
+public:
+    UITestDigitalClock() {}
+    ~UITestDigitalClock() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    void UIKitUIDigitalClockTestDisplay001();
+    void UIKitUIDigitalClockTestDisplay002();
+    void UIKitUIDigitalClockTestSetColor();
+    void UIKitUIDigitalClockTestDisplayMode001();
+    void UIKitUIDigitalClockTestDisplayMode002();
+    void UIKitUIDigitalClockTestDisplayMode003();
+    void UIKitUIDigitalClockTestDisplayMode004();
+    void UIKitUIDigitalClockTestDisplayLeadingZero();
+    void UIKitUIDigitalClockTestSetOpacity();
+
+private:
+    UIScrollView* container_ = nullptr;
+    void InnerTestTitle(const char* title);
+};
+} // namespace OHOS
+#endif // UI_TEST_DIGITAL_CLOCK_H
index 1249ec6..0ebae71 100644 (file)
@@ -75,6 +75,7 @@ void UITestCanvasExt::SetUp()
     SetUpBtn(scaleBtn_, "Scale 0.5", X_300, 240); // 240: Y coordinate
     SetUpBtn(rotateBtn_, "Rotate 90", X_300, 300); // 300: Y coordinate
     SetUpBtn(matrixBtn_, "Matrix", X_300, 360); // 360: Y coordinate
+    SetUpBtn(paddingBtn_, "padding", X_300, 420); // 420: Y coordinate
     sectorCallBack_ = new SectorAnimatorCallback();
     if (sectorCallBack_ == nullptr) {
         GRAPHIC_LOGE("CallBack new fail");
@@ -125,6 +126,7 @@ void UITestCanvasExt::TearDown()
     scaleBtn_ = nullptr;
     rotateBtn_ = nullptr;
     matrixBtn_ = nullptr;
+    paddingBtn_ = nullptr;
     matrixIndex_ = -1;
     img_ = nullptr;
     ImageCacheManager::GetInstance().UnloadSingleRes(RES_PATH"haha.bin");
@@ -178,11 +180,19 @@ bool UITestCanvasExt::OnClick(UIView& view, const ClickEvent& event)
         canvas_->Rotate(90, {200, 200}); // 90: rotate angle, 200, 200: rotate pivot
     } else if (&view == matrixBtn_) {
         if (matrixIndex_ != -1) {
-            Matrix3<float> mat(1, 0, 0, 0, 1, 0, 0, 50, 1); // 50: Y trans by 50
+            static int para = 1;
+            Matrix3<float> mat(1 + 0.5 * para, 0, 0, 0, 1, 0, 0, para * 50, 1); // 0.5: scale, 50: Y trans by 50
             canvas_->SetMatrix(mat, matrixIndex_);
+            para = (para + 1) % 2; // 2: num
         }
     } else if (&view == addSectorBtn_) {
         DrawSector(canvas_);
+    } else if (&view == paddingBtn_) {
+        static int para = 1;
+        canvas_->SetStyle(STYLE_PADDING_LEFT, para * 50); // 50: padding left
+        canvas_->SetStyle(STYLE_PADDING_TOP, para * 50); // 50: padding top
+        container_->Invalidate();
+        para = (para + 1) % 2; // 2: num
     }
     return true;
 }
index 85cf839..40b2b63 100644 (file)
@@ -70,6 +70,7 @@ private:
     UILabelButton* scaleBtn_ = nullptr;
     UILabelButton* rotateBtn_ = nullptr;
     UILabelButton* matrixBtn_ = nullptr;
+    UILabelButton* paddingBtn_ = nullptr;
     UIScrollView* container_ = nullptr;
     SectorAnimatorCallback *sectorCallBack_ = nullptr;
     Animator *sectorAnimator_ = nullptr;
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_draw_line/ui_test_draw_line.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_draw_line/ui_test_draw_line.cpp
new file mode 100644 (file)
index 0000000..6865e3e
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_draw_line.h"
+#include "common/screen.h"
+#include "components/ui_canvas.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+
+namespace OHOS {
+namespace {
+const uint16_t DELTA_X = 24;
+}
+
+void UITestDrawLine::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        container_->SetHorizontalScrollState(false);
+    }
+}
+void UITestDrawLine::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+}
+
+const UIView* UITestDrawLine::GetTestView()
+{
+    UIKitDrawLineTestLine001();
+    UIKitDrawLineTestLine002();
+    UIKitDrawLineTestLine003();
+    UIKitDrawLineTestLine004();
+    UIKitDrawLineTestLine005();
+    UIKitDrawLineTestLine006();
+    UIKitDrawLineTestLine007();
+    UIKitDrawLineTestLine008();
+    UIKitDrawLineTestLine009();
+    UIKitDrawLineTestLine010();
+    UIKitDrawLineTestLine011();
+    UIKitDrawLineTestLine012();
+    return container_;
+}
+
+UIViewGroup* UITestDrawLine::CreateTestCaseGroup() const
+{
+    UIViewGroup* group = new UIViewGroup();
+    // 288: group width; 250: group height
+    group->Resize(288, 250);
+    return group;
+}
+
+UILabel* UITestDrawLine::CreateTitleLabel() const
+{
+    UILabel* label = new UILabel();
+    // 2: half of screen width;
+    label->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, TEXT_DISTANCE_TO_TOP_SIDE, Screen::GetInstance().GetWidth() / 2,
+                       TITLE_LABEL_DEFAULT_HEIGHT);
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    return label;
+}
+
+UICanvas* UITestDrawLine::CreateCanvas() const
+{
+    UICanvas* canvas = new UICanvas();
+    canvas->SetHeight(200); // 200 : height size
+    canvas->SetWidth(200);  // 200 : width size
+    canvas->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, VIEW_DISTANCE_TO_TOP_SIDE);
+    canvas->SetStyle(STYLE_BACKGROUND_COLOR, Color::Gray().full);
+    return canvas;
+}
+
+void UITestDrawLine::UIKitDrawLineTestLine001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKitDrawLineTestLine001");
+    group->SetPosition(0, 0);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    label->SetText("水平直线绘制 ");
+
+    UICanvas* canvas = CreateCanvas();
+    Paint paint;
+    canvas->DrawLine({50, 50}, {150, 50}, paint); // 50 : start x 50 : start y 150 : end x 50 : end y
+    group->Add(canvas);
+    group->LayoutLeftOfParent(50);  // 50 : offset
+    container_->Add(group);
+}
+
+void UITestDrawLine::UIKitDrawLineTestLine002()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKitDrawLineTestLine002");
+    group->SetPosition(0, 0);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    label->SetText("垂直直线绘制 ");
+
+    UICanvas* canvas = CreateCanvas();
+    Paint paint;
+    canvas->DrawLine({100, 50}, {100, 150}, paint); // 100 : start x 50 : start y 100 : end x 150 : end y
+    group->Add(canvas);
+
+    container_->Add(group);
+    group->LayoutLeftOfParent(50);  // 50 : offset
+    group->LayoutBottomToSibling("UIKitDrawLineTestLine001", DELTA_X);
+}
+
+void UITestDrawLine::UIKitDrawLineTestLine003()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKitDrawLineTestLine003");
+    group->SetPosition(0, 0);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    label->SetText("左下-右上方向直线绘制 ");
+
+    UICanvas* canvas = CreateCanvas();
+    Paint paint;
+    canvas->DrawLine({20, 180}, {160, 20}, paint); // 20 : start x 180 : start y 160 : end x 20 : end y
+    canvas->DrawLine({20, 180}, {180, 20}, paint); // 20 : start x 180 : start y 180 : end x 20 : end y
+    canvas->DrawLine({20, 180}, {180, 40}, paint); // 20 : start x 180 : start y 180 : end x 40 : end y
+    group->Add(canvas);
+
+    container_->Add(group);
+    group->LayoutLeftOfParent(50);  // 50 : offset
+    group->LayoutBottomToSibling("UIKitDrawLineTestLine002", DELTA_X);
+}
+
+void UITestDrawLine::UIKitDrawLineTestLine004()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKitDrawLineTestLine004");
+    group->SetPosition(0, 0);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    label->SetText("左上-右下方向直线绘制 ");
+
+    UICanvas* canvas = CreateCanvas();
+    Paint paint;
+    canvas->DrawLine({20, 20}, {160, 180}, paint); // 20 : start x 20 : start y 160 : end x 180 : end y
+    canvas->DrawLine({20, 20}, {180, 180}, paint); // 20 : start x 20 : start y 180 : end x 180 : end y
+    canvas->DrawLine({20, 20}, {180, 160}, paint); // 20 : start x 20 : start y 180 : end x 160 : end y
+    group->Add(canvas);
+
+    container_->Add(group);
+    group->LayoutLeftOfParent(50);  // 50 : offset
+    group->LayoutBottomToSibling("UIKitDrawLineTestLine003", 10); // 10 : offset size
+}
+
+void UITestDrawLine::UIKitDrawLineTestLine005()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKitDrawLineTestLine005");
+    group->SetPosition(0, 0);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    label->SetText("右上-左下方向直线绘制 ");
+
+    UICanvas* canvas = CreateCanvas();
+    Paint paint;
+    canvas->DrawLine({180, 20}, {20, 160}, paint); // 180 : start x 20 : start y 20 : end x 160 : end y
+    canvas->DrawLine({180, 20}, {20, 180}, paint); // 180 : start x 20 : start y 20 : end x 180 : end y
+    canvas->DrawLine({180, 20}, {40, 180}, paint); // 180 : start x 20 : start y 40 : end x 180 : end y
+    group->Add(canvas);
+
+    container_->Add(group);
+    group->LayoutLeftOfParent(50);  // 50 : offset
+    group->LayoutBottomToSibling("UIKitDrawLineTestLine004", 10); // 10: offset
+}
+
+void UITestDrawLine::UIKitDrawLineTestLine006()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKitDrawLineTestLine006");
+    group->SetPosition(0, 0);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    label->SetText("左上-右下方向直线绘制 ");
+
+    UICanvas* canvas = CreateCanvas();
+    Paint paint;
+    canvas->DrawLine({180, 180}, {20, 40}, paint); // 180 : start x 180 : start y 20 : end x 40 : end y
+    canvas->DrawLine({180, 180}, {20, 20}, paint); // 180 : start x 180 : start y 20 : end x 20 : end y
+    canvas->DrawLine({180, 180}, {40, 20}, paint); // 180 : start x 180 : start y 40 : end x 20 : end y
+    group->Add(canvas);
+
+    container_->Add(group);
+    group->LayoutLeftOfParent(50);  // 50 : offset
+    group->LayoutBottomToSibling("UIKitDrawLineTestLine005", 10); // 10: offset
+}
+
+void UITestDrawLine::UIKitDrawLineTestLine007()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKitDrawLineTestLine007");
+    group->SetPosition(0, 0);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    label->SetText("宽度为零直线绘制 ");
+
+    UICanvas* canvas = CreateCanvas();
+    Paint paint;
+    paint.SetStrokeWidth(0);                       // 0 : stroke width
+    canvas->DrawLine({10, 190}, {190, 10}, paint); // 10 : start x 190 : start y 190 : end x 10 : end y
+    group->Add(canvas);
+
+    container_->Add(group);
+    group->LayoutLeftOfParent(50);  // 50 : offset
+    group->LayoutBottomToSibling("UIKitDrawLineTestLine006", 10); // 10 : offset size
+}
+
+void UITestDrawLine::UIKitDrawLineTestLine008()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKitDrawLineTestLine008");
+    group->SetPosition(0, 0);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    label->SetText("不同宽度的直线绘制 ");
+
+    UICanvas* canvas = CreateCanvas();
+    Paint paint;
+    paint.SetStrokeWidth(2);                       // 2 : stroke width
+    canvas->DrawLine({10, 190}, {190, 10}, paint); // 10 : start x 190 : start y 190 : end x 10 : end y
+    Paint paint2;
+    paint2.SetStrokeWidth(4);                       // 4 : stroke width
+    canvas->DrawLine({30, 190}, {190, 30}, paint2); // 30 : start x 190 : start y 190 : end x 30 : end y
+    Paint paint3;
+    paint3.SetStrokeWidth(5);                       // 5 : stroke width
+    canvas->DrawLine({50, 190}, {190, 50}, paint3); // 50 : start x 190 : start y 190 : end x 50 : end y
+    Paint paint4;
+    paint4.SetStrokeWidth(90);                    // 90 : stroke width
+    canvas->DrawLine({40, 90}, {90, 40}, paint4); // 40 : start x 90 : start y 90 : end x 40 : end y
+    group->Add(canvas);
+    container_->Add(group);
+    group->LayoutLeftOfParent(50);  // 50 : offset
+    group->LayoutBottomToSibling("UIKitDrawLineTestLine007", 10); // 10: offset
+}
+
+void UITestDrawLine::UIKitDrawLineTestLine009()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKitDrawLineTestLine009");
+    group->SetPosition(0, 0);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    label->SetText("全透明的直线绘制 ");
+
+    UICanvas* canvas = CreateCanvas();
+    Paint paint;
+    paint.SetOpacity(OPA_TRANSPARENT);
+    canvas->DrawLine({10, 190}, {190, 10}, paint); // 10 : start x 190 : start y 190 : end x 10 : end y
+    group->Add(canvas);
+    container_->Add(group);
+    group->LayoutLeftOfParent(50);  // 50 : offset
+    group->LayoutBottomToSibling("UIKitDrawLineTestLine008", 10); // 10: offset
+}
+
+void UITestDrawLine::UIKitDrawLineTestLine010()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKitDrawLineTestLine010");
+    group->SetPosition(0, 0);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    label->SetText("不透明的直线绘制 ");
+
+    UICanvas* canvas = CreateCanvas();
+    Paint paint;
+    paint.SetOpacity(OPA_OPAQUE);
+    canvas->DrawLine({10, 190}, {190, 10}, paint); // 10 : start x 190 : start y 190 : end x 10 : end y
+    group->Add(canvas);
+
+    container_->Add(group);
+    group->LayoutLeftOfParent(50);  // 50 : offset
+    group->LayoutBottomToSibling("UIKitDrawLineTestLine009", 10); // 10 : offset size
+}
+
+void UITestDrawLine::UIKitDrawLineTestLine011()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKitDrawLineTestLine011");
+    group->SetPosition(0, 0);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    label->SetText("不同透明度的直线绘制 ");
+
+    UICanvas* canvas = CreateCanvas();
+    Paint paint;
+    paint.SetOpacity(51);                          // 51 : opacity size
+    canvas->DrawLine({10, 190}, {190, 10}, paint); // 10 : start x 190 : start y 190 : end x 10 : end y
+    Paint paint2;
+    paint2.SetOpacity(127);                         // 127 : opacity size
+    canvas->DrawLine({30, 190}, {190, 30}, paint2); // 30 : start x 190 : start y 190 : end x 30 : end y
+    Paint paint3;
+    paint3.SetOpacity(178);                         // 178 : opacity size
+    canvas->DrawLine({50, 190}, {190, 50}, paint3); // 50 : start x 190 : start y 190 : end x 50 : end y
+    group->Add(canvas);
+    container_->Add(group);
+    group->LayoutLeftOfParent(50);  // 50 : offset
+    group->LayoutBottomToSibling("UIKitDrawLineTestLine010", 10); // 10 : offset size
+}
+
+void UITestDrawLine::UIKitDrawLineTestLine012()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKitDrawLineTestLine012");
+    group->SetPosition(0, 0);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    label->SetText("不同颜色的直线绘制 ");
+
+    UICanvas* canvas = CreateCanvas();
+    Paint paint;
+    paint.SetStrokeColor(Color::Red());
+    canvas->DrawLine({10, 190}, {190, 10}, paint); // 10 : start x 190 : start y 190 : end x 10 : end y
+    Paint paint2;
+    paint2.SetStrokeColor(Color::Yellow());
+    canvas->DrawLine({30, 190}, {190, 30}, paint2); // 30 : start x 190 : start y 190 : end x 30 : end y
+    Paint paint3;
+    paint3.SetStrokeColor(Color::Green());
+    canvas->DrawLine({50, 190}, {190, 50}, paint3); // 50 : start x 190 : start y 190 : end x 50 : end y
+    group->Add(canvas);
+    container_->Add(group);
+    group->LayoutLeftOfParent(50);  // 50 : offset
+    group->LayoutBottomToSibling("UIKitDrawLineTestLine011", 10); // 10 : offset size
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_draw_line/ui_test_draw_line.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_draw_line/ui_test_draw_line.h
new file mode 100644 (file)
index 0000000..deee624
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_DRAW_LINE_H
+#define UI_TEST_DRAW_LINE_H
+
+#include "components/ui_canvas.h"
+#include "components/ui_label.h"
+#include "components/ui_scroll_view.h"
+#include "components/ui_view_group.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestDrawLine : public UITest {
+public:
+    UITestDrawLine() {}
+    ~UITestDrawLine() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    /**
+     * @brief Test draw line Function
+     */
+    void UIKitDrawLineTestLine001();
+    void UIKitDrawLineTestLine002();
+    void UIKitDrawLineTestLine003();
+    void UIKitDrawLineTestLine004();
+    void UIKitDrawLineTestLine005();
+    void UIKitDrawLineTestLine006();
+    void UIKitDrawLineTestLine007();
+    void UIKitDrawLineTestLine008();
+    void UIKitDrawLineTestLine009();
+    void UIKitDrawLineTestLine010();
+    void UIKitDrawLineTestLine011();
+    void UIKitDrawLineTestLine012();
+
+private:
+    UIViewGroup* CreateTestCaseGroup() const;
+    UILabel* CreateTitleLabel() const;
+    UICanvas* CreateCanvas() const;
+    UIScrollView* container_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_DRAW_LINE_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_dump_dom_tree/cJSON.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_dump_dom_tree/cJSON.h
new file mode 100644 (file)
index 0000000..51355ab
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef cJSON__h
+#define cJSON__h
+
+#include <stddef.h>
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
+#define __WINDOWS__
+#endif
+
+#ifdef __WINDOWS__
+
+#define CJSON_CDECL __cdecl
+#define CJSON_STDCALL __stdcall
+
+/* export symbols by default, this is necessary for copy pasting the C and header file */
+#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
+#define CJSON_EXPORT_SYMBOLS
+#endif
+
+#if defined(CJSON_HIDE_SYMBOLS)
+#elif defined(CJSON_EXPORT_SYMBOLS)
+#endif
+#else /* !__WINDOWS__ */
+#define CJSON_CDECL
+#define CJSON_STDCALL
+
+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
+#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
+#else
+#define CJSON_PUBLIC(type) type
+#endif
+#endif
+
+/* project version */
+#define CJSON_VERSION_MAJOR 1
+#define CJSON_VERSION_MINOR 7
+#define CJSON_VERSION_PATCH 15
+
+/* cJSON Types: */
+#define cJSON_Invalid (0)
+#define cJSON_False  (1 << 0)
+#define cJSON_True   (1 << 1)
+#define cJSON_NULL   (1 << 2)
+#define cJSON_Number (1 << 3)
+#define cJSON_String (1 << 4)
+#define cJSON_Array  (1 << 5)
+#define cJSON_Object (1 << 6)
+#define cJSON_Raw    (1 << 7) /* raw json */
+
+#define cJSON_IsReference 256
+#define cJSON_StringIsConst 512
+
+/* The cJSON structure: */
+typedef struct cJSON {
+    struct cJSON *next;
+    struct cJSON *prev;
+    struct cJSON *child;
+    int type;
+
+    std::string *valuestring;
+    int valueint;
+    double valuedouble;
+    std::string *string;
+} cJSON;
+
+typedef struct cJSON_Hooks {
+    void *(CJSON_CDECL *malloc_fn)(size_t sz);
+    void (CJSON_CDECL *free_fn)(void *ptr);
+} cJSON_Hooks;
+
+#ifndef CJSON_NESTING_LIMIT
+#define CJSON_NESTING_LIMIT 1000
+#endif
+
+/* returns the version of cJSON as a string */
+CJSON_PUBLIC(const char*) cJSON_Version(void);
+
+/* Supply malloc, realloc and free functions to cJSON */
+CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
+CJSON_PUBLIC(cJSON *) cJSON_Parse(const std::string *value);
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const std::string *value, size_t buffer_length);
+
+/* Render a cJSON entity to text for transfer/storage. */
+CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
+/* Render a cJSON entity to text for transfer/storage without any formatting. */
+CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
+CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, int fmt);
+CJSON_PUBLIC(int) cJSON_PrintPreallocated(cJSON *item, std::string *buffer, const int length, const int format);
+/* Delete a cJSON entity and all subentities. */
+CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
+
+/* Returns the number of items in an array (or object). */
+CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
+/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
+/* Get item "string" from object. Case insensitive. */
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
+CJSON_PUBLIC(int) cJSON_HasObjectItem(const cJSON *object, const char *string);
+CJSON_PUBLIC(const std::string *) cJSON_GetErrorPtr(void);
+
+/* Check item type and return its value */
+CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
+CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
+
+/* These functions check the type of an item */
+CJSON_PUBLIC(int) cJSON_IsInvalid(const cJSON * const item);
+CJSON_PUBLIC(int) cJSON_IsFalse(const cJSON * const item);
+CJSON_PUBLIC(int) cJSON_IsTrue(const cJSON * const item);
+CJSON_PUBLIC(int) cJSON_IsBool(const cJSON * const item);
+CJSON_PUBLIC(int) cJSON_IsNull(const cJSON * const item);
+CJSON_PUBLIC(int) cJSON_IsNumber(const cJSON * const item);
+CJSON_PUBLIC(int) cJSON_IsString(const cJSON * const item);
+CJSON_PUBLIC(int) cJSON_IsArray(const cJSON * const item);
+CJSON_PUBLIC(int) cJSON_IsObject(const cJSON * const item);
+CJSON_PUBLIC(int) cJSON_IsRaw(const cJSON * const item);
+
+/* These calls create a cJSON item of the appropriate type. */
+CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(int boolean);
+CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
+CJSON_PUBLIC(cJSON *) cJSON_CreateString(const std::string *string);
+/* raw json */
+CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const std::string *raw);
+CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
+
+/* Create a string where valuestring references a string so
+ * it will not be freed by cJSON_Delete */
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const std::string *string);
+/* Create an object/array that only references it's elements so
+ * they will not be freed by cJSON_Delete */
+CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
+CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const std::string *const *strings, int count);
+
+/* Append item to the specified array/object. */
+CJSON_PUBLIC(int) cJSON_AddItemToArray(cJSON *array, cJSON *item);
+CJSON_PUBLIC(int) cJSON_AddItemToObject(cJSON *object, const std::string *string, cJSON *item);
+CJSON_PUBLIC(int) cJSON_AddItemToObjectCS(cJSON *object, const std::string *string, cJSON *item);
+CJSON_PUBLIC(int) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+CJSON_PUBLIC(int) cJSON_AddItemReferenceToObject(cJSON *object, const std::string *string, cJSON *item);
+
+/* Remove/Detach items from Arrays/Objects. */
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
+
+/* Update array items. */
+CJSON_PUBLIC(int) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem);
+CJSON_PUBLIC(int) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
+CJSON_PUBLIC(int) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem);
+CJSON_PUBLIC(int) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem);
+
+CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, int recurse);
+CJSON_PUBLIC(int) cJSON_Compare(const cJSON * const a, const cJSON * const b, const int case_sensitive);
+
+CJSON_PUBLIC(void) cJSON_Minify(std::string *json);
+CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const int boolean);
+CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
+CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
+CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
+CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
+CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
+CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
+CJSON_PUBLIC(void) cJSON_free(void *object);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_dump_dom_tree/test_resource_config.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_dump_dom_tree/test_resource_config.h
new file mode 100644 (file)
index 0000000..f899a88
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+ 
+#ifndef TEST_RESOURCE_CONFIG_H
+#define TEST_RESOURCE_CONFIG_H
+ 
+namespace OHOS {
+#if defined QT_COMPILER
+#define IMAGE_DIR "..\\..\\simulator\\config\\images\\"
+#define FACE_DIR "..\\..\\simulator\\config\\faces\\default\\"
+#elif defined _WIN32
+#define IMAGE_DIR "..\\config\\images\\"
+#define FACE_DIR "..\\config\\faces\\default\\"
+#else
+#define IMAGE_DIR RES_PATH
+#define FACE_DIR RES_PATH
+#endif
+ 
+#define BLUE_RGB888_IMAGE_PATH (IMAGE_DIR "blue_rgb888.bin")
+#define BLUE_ARGB8888_IMAGE_PATH (IMAGE_DIR "blue_argb8888.bin")
+#define BLUE_RGB565_IMAGE_PATH (IMAGE_DIR "blue_rgb565.bin")
+#define BLUE_IMAGE_PATH (IMAGE_DIR "blue.png")
+#define RED_IMAGE_PATH (IMAGE_DIR "red.png")
+#define GREEN_IMAGE_PATH (IMAGE_DIR "green.png")
+#define YELLOW_IMAGE_PATH (IMAGE_DIR "yellow.png")
+#define IMAGE_ANIMATOR_0_PATH (IMAGE_DIR "image_animator_0.bin")
+#define IMAGE_ANIMATOR_1_PATH (IMAGE_DIR "image_animator_1.bin")
+#define IMAGE_ANIMATOR_2_PATH (IMAGE_DIR "image_animator_2.bin")
+#define IMAGE_ANIMATOR_3_PATH (IMAGE_DIR "image_animator_3.bin")
+#define B024_002_IMAGE_PATH (FACE_DIR "B024_002.bin")
+#define B024_009_IMAGE_PATH (FACE_DIR "B024_009.bin")
+#define B024_010_IMAGE_PATH (FACE_DIR "B024_010.bin")
+#define B024_011_IMAGE_PATH (FACE_DIR "B024_011.bin")
+#define SLIDER_BACKGROUND_IMAGE_PATH (IMAGE_DIR "sliderBackground.bin")
+#define SLIDER_INDICATOR_IMAGE_PATH (IMAGE_DIR "sliderIndicator.bin")
+#define SLIDER_KNOB_IMAGE_PATH (IMAGE_DIR "sliderKnob.bin")
+#define JPEG_IMAGE_PATH (IMAGE_DIR "jpeg.jpg")
+#define PNG_1_PALETTE_IMAGE_PATH (IMAGE_DIR "png_1_palette.png")
+#define PNG_2_PALETTE_IMAGE_PATH (IMAGE_DIR "png_2_palette.png")
+#define PNG_4_PALETTE_IMAGE_PATH (IMAGE_DIR "png_4_palette.png")
+#define PNG_8_PALETTE_IMAGE_PATH (IMAGE_DIR "png_8_palette.png")
+#define PNG_8_GRAY_IMAGE_PATH (IMAGE_DIR "png_8_gray.png")
+#define PNG_16_GRAY_IMAGE_PATH (IMAGE_DIR "png_16_gray.png")
+#define PNG_24_RGB_IMAGE_PATH (IMAGE_DIR "png_24_rgb.png")
+#define PNG_32_RGB_ALPHA_IMAGE_PATH (IMAGE_DIR "png_32_rgba.png")
+#ifndef VERSION_LITE
+#define GIF_IMAGE_PATH1 (IMAGE_DIR "gif_image1.gif")
+#define GIF_IMAGE_PATH2 (IMAGE_DIR "gif_image2.gif")
+#define GIF_IMAGE_PATH_ERROR (IMAGE_DIR "gif_error.gif")
+#define TIF_IMAGE_PATH (IMAGE_DIR "tif_image.tif")
+#endif
+#define VIDEO_SOURCE_DIRECTORY (IMAGE_DIR "video.mp4")
+#define TEST_RIGHT_ARROW (IMAGE_DIR "ic_arrow_right.png")
+#define TEST_BACK_LEFT_ARROW (IMAGE_DIR "ic_back.png")
+#define TEST_CIRCLE_FORE_IMAGE (FACE_DIR "fore.png")
+} // namespace OHOS
+#endif // TEST_RESOURCE_CONFIG_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_dump_dom_tree/ui_dump_dom_tree.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_dump_dom_tree/ui_dump_dom_tree.h
new file mode 100644 (file)
index 0000000..70296a0
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+ 
+/**
+ * @addtogroup UI_DFX
+ * @{
+ *
+ * @brief Provides test and analysis capabilities, such as stimulating input events and viewing information about a
+ *        Document Object Model (DOM) tree.
+ *
+ * @since 1.0
+ * @version 1.0
+ */
+
+/**
+ * @file ui_dump_dom_tree.h
+ *
+ * @brief Declares a function for exporting information about a Document Object Model (DOM) tree or DOM node.
+ *
+ * @since 1.0
+ * @version 1.0
+ */
+#ifndef GRAPHIC_LITE_UI_DUMP_DOM_TREE_H
+#define GRAPHIC_LITE_UI_DUMP_DOM_TREE_H
+
+#include "graphic_config.h"
+#include "gfx_utils/heap_base.h"
+#if ENABLE_DEBUG
+#include "cJSON.h"
+#include "components/ui_view.h"
+#endif // ENABLE_DEBUG
+namespace OHOS {
+#if ENABLE_DEBUG
+/**
+ * @brief Enumerates export modes.
+ */
+enum DumpMode {
+    /** DOM tree */
+    DUMP_TREE,
+    /** DOM node */
+    DUMP_NODE
+};
+#endif // ENABLE_DEBUG
+
+/**
+ * @brief Provides functions for exporting information about a specified DOM node or information about the DOM tree
+ * starting from a specified DOM node.
+ *
+ * @since 1.0
+ * @version 1.0
+ */
+class UIDumpDomTree : public HeapBase {
+public:
+    /**
+     * @brief Obtains an instance in singleton pattern.
+     *
+     * @return Returns the function instance for exporting DOM information.
+     * @since 1.0
+     * @version 1.0
+     */
+    static UIDumpDomTree* GetInstance();
+
+    /**
+     * @brief Exports information about a DOM tree starting from a specified DOM node and saves the information to
+     * a specified path.
+     *
+     * @param id Indicates the pointer to the DOM node ID.
+     * @param path Indicates the pointer to the specified path.
+     * @return Returns <b>true</b> if the operation is successful; returns <b>false</b> otherwise.
+     * @since 1.0
+     * @version 1.0
+     */
+    bool DumpDomTree(const char* id, const char* path);
+
+    /**
+     * @brief Exports information about a DOM tree starting from a specified DOM node and saves the information to
+     * the default path.
+     * The default path is {@link DEFAULT_DUMP_DOM_TREE_PATH}.
+     *
+     * @param id Indicates the pointer to the DOM node ID.
+     * @return Returns <b>true</b> if the operation is successful; returns <b>false</b> otherwise.
+     * @since 1.0
+     * @version 1.0
+     */
+    bool DumpDomTree(const char* id)
+    {
+        return DumpDomTree(id, nullptr);
+    }
+
+    /**
+     * @brief Exports information about a specified DOM node.
+     *
+     * @param id Indicates the pointer to the DOM node ID.
+     * @return Returns a character string about the DOM node information. The character string memory is released by
+     * invoking <b>cJSON_free()</b>.
+     * @since 1.0
+     * @version 1.0
+     */
+    char* DumpDomNode(const char* id);
+
+private:
+#if ENABLE_DEBUG
+    bool searchFlag_;     // Search flag, set when find the view with right id.
+    bool allocErrorFlag_; // Alloc error flag, set when cJSON fails to allocate memory.
+    char* pJson_;         // Pointer for returning cJSON string.
+    cJSON* rootJson_;     // Root pointer of cJSON structure.
+    const char* path_;
+
+    void DumpJsonById(UIView* view, const char* id, DumpMode mode);
+
+    void AddNameField(UIViewType type, cJSON* usr) const;
+    void AddCommonField(UIView* view, cJSON* usr) const;
+    void AddImageViewSpecialField(const UIView* view, cJSON* usr) const;
+    void AddLabelField(const UIView* view, cJSON* usr) const;
+    void AddLabelButtonField(const UIView* view, cJSON* usr) const;
+    void AddCheckboxField(const UIView* view, cJSON* usr) const;
+    void AddToggleButtonField(const UIView* view, cJSON* usr) const;
+    void AddProgressField(const UIView* view, cJSON* usr) const;
+    void AddScrollViewField(const UIView* view, cJSON* usr) const;
+    void AddListField(const UIView* view, cJSON* usr) const;
+    void AddClockField(const UIView* view, cJSON* usr) const;
+    void AddPickerField(const UIView* view, cJSON* usr) const;
+    void AddSwipeViewField(const UIView* view, cJSON* usr) const;
+    void AddTimePickerField(const UIView* view, cJSON* usr) const;
+    void AddSpecialField(const UIView* view, cJSON* usr) const;
+    void OutputDomNode(UIView* view);
+    void OutputDomTree(UIView* view, cJSON* usr);
+    bool WriteDumpFile() const;
+
+    UIDumpDomTree()
+        : searchFlag_(false),
+          allocErrorFlag_(false),
+          pJson_(nullptr),
+          rootJson_(nullptr),
+          path_(DEFAULT_DUMP_DOM_TREE_PATH)
+    {
+    }
+#else
+    UIDumpDomTree() {}
+#endif // ENABLE_DEBUG
+    virtual ~UIDumpDomTree() {}
+
+    UIDumpDomTree(const UIDumpDomTree&) = delete;
+    UIDumpDomTree& operator=(const UIDumpDomTree&) = delete;
+    UIDumpDomTree(UIDumpDomTree&&) = delete;
+    UIDumpDomTree& operator=(UIDumpDomTree&&) = delete;
+};
+} // namespace OHOS
+#endif // GRAPHIC_LITE_UI_DUMP_DOM_TREE_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_dump_dom_tree/ui_test_dump_dom.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_dump_dom_tree/ui_test_dump_dom.cpp
new file mode 100644 (file)
index 0000000..b6e6d13
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "graphic_config.h"
+
+#if ENABLE_DEBUG
+#include "ui_test_dump_dom.h"
+
+#include "common/screen.h"
+#include "components/ui_arc_label.h"
+#include "components/ui_box_progress.h"
+#include "components/ui_checkbox.h"
+#include "components/ui_circle_progress.h"
+#include "components/ui_image_view.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_radio_button.h"
+#include "components/ui_slider.h"
+#include "components/ui_toggle_button.h"
+#include "ui_dump_dom_tree.h"
+#include "imgdecode/cache_manager.h"
+#include "test_resource_config.h"
+#include "gfx_utils/graphic_log.h"
+
+const uint16_t offsetx_ = 10;
+const uint16_t offsety_ = 160;
+const uint16_t offsetX = 20;
+const uint16_t offsetY = 100;
+const uint16_t x_coordinate1 = 230;
+const uint16_t y_coordinate1 = 68;
+const uint16_t y_coordinate2 = 108;
+const uint16_t y_coordinate3 = 310;
+const uint16_t x_coordinate = 105;
+const uint16_t y_coordinate = 73;
+const uint16_t g_height_ = 200;
+const uint16_t g_height2_ = 200;
+const uint16_t g_height3_ = 200;
+const uint16_t g_height4_ = 500;
+const uint16_t x_position = 90;
+const uint16_t y_position = 300;
+const uint16_t radius = 90;
+const uint16_t angle_end = 270;
+const uint16_t letter_space = 30;
+const uint16_t dumph_ = 29;
+namespace OHOS {
+void UITestDumpDomTree::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        container_->SetViewId("dump_scroll_view");
+    }
+}
+
+void UITestDumpDomTree::TearDown()
+{
+    if (clickDumpDomListener1_ != nullptr) {
+        delete clickDumpDomListener1_;
+        clickDumpDomListener1_ = nullptr;
+    }
+    if (clickDumpDomListener2_ != nullptr) {
+        delete clickDumpDomListener2_;
+        clickDumpDomListener2_ = nullptr;
+    }
+    if (clickDumpDomListener3_ != nullptr) {
+        delete clickDumpDomListener3_;
+        clickDumpDomListener3_ = nullptr;
+    }
+    if (clickDumpDomListener4_ != nullptr) {
+        delete clickDumpDomListener4_;
+        clickDumpDomListener4_ = nullptr;
+    }
+    if (clickDumpDomListener5_ != nullptr) {
+        delete clickDumpDomListener5_;
+        clickDumpDomListener5_ = nullptr;
+    }
+    if (clickDumpDomListener6_ != nullptr) {
+        delete clickDumpDomListener6_;
+        clickDumpDomListener6_ = nullptr;
+    }
+    if (clickDumpDomListener7_ != nullptr) {
+        delete clickDumpDomListener7_;
+        clickDumpDomListener7_ = nullptr;
+    }
+    if (clickDumpDomListener8_ != nullptr) {
+        delete clickDumpDomListener8_;
+        clickDumpDomListener8_ = nullptr;
+    }
+    if (clickDumpDomListener9_ != nullptr) {
+        delete clickDumpDomListener9_;
+        clickDumpDomListener9_ = nullptr;
+    }
+    if (clickDumpDomListener10_ != nullptr) {
+        delete clickDumpDomListener10_;
+        clickDumpDomListener10_ = nullptr;
+    }
+    if (clickDumpDomListener11_ != nullptr) {
+        delete clickDumpDomListener11_;
+        clickDumpDomListener11_ = nullptr;
+    }
+    if (clickDumpDomListener12_ != nullptr) {
+        delete clickDumpDomListener12_;
+        clickDumpDomListener12_ = nullptr;
+    }
+    positionY_ = 0;
+    DeleteChildren(container_);
+    container_ = nullptr;
+}
+
+const UIView* UITestDumpDomTree::GetTestView()
+{
+    positionY_ = 0;
+    UIKit_TestDumpDom_001();
+    UIKit_TestDumpDom_002();
+    UIKit_TestDumpDom_003();
+    UIKit_TestDumpDom_004();
+    UIKit_TestDumpDom_005();
+    UIKit_TestDumpDom_006();
+    return container_;
+}
+
+class TestBtnOnClickDumpDomListener : public UIView::OnClickListener {
+public:
+    TestBtnOnClickDumpDomListener(UIView* uiView, const char* id) : uiView_(uiView), id_(id) {}
+    ~TestBtnOnClickDumpDomListener() {}
+    bool OnClick(UIView& view, const ClickEvent& event) override
+    {
+        char* tmpPtr = UIDumpDomTree::GetInstance()->DumpDomNode(id_);
+        if (tmpPtr != nullptr) {
+            cJSON_free(tmpPtr);
+        }
+        uiView_->Invalidate();
+        return true;
+    }
+
+private:
+    UIView* uiView_;
+    const char* id_;
+};
+
+class TestBtnOnClickDumpDomTreeListener : public UIView::OnClickListener {
+public:
+    TestBtnOnClickDumpDomTreeListener(UIView* uiView, const char* id) : uiView_(uiView), id_(id) {}
+    ~TestBtnOnClickDumpDomTreeListener() {}
+    bool OnClick(UIView& view, const ClickEvent& event) override
+    {
+        if (UIDumpDomTree::GetInstance()->DumpDomTree(id_)) {
+            if (id_ == nullptr) {
+                GRAPHIC_LOGI("dump tree from rootView success\n");
+            } else {
+                GRAPHIC_LOGI("dump tree from id success\n");
+            }
+        } else {
+            GRAPHIC_LOGI("dump tree failed\n");
+        }
+        uiView_->Invalidate();
+        return true;
+    }
+
+private:
+    UIView* uiView_;
+    const char* id_;
+};
+
+void UITestDumpDomTree::UIKit_TestDumpDom_001()
+{
+    if (container_ != nullptr) {
+        UILabel* label = GetTitleLabel("dump checkbox");
+        container_->Add(label);
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE + offsetX, TEXT_DISTANCE_TO_TOP_SIDE + offsetY);
+        positionY_ += label->GetHeight();
+
+        GridLayout* layout = new GridLayout();
+        layout->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE + offsetX, VIEW_DISTANCE_TO_TOP_SIDE + offsetY,
+        // 2: half of screen width; 88: decrease screen width; 180: height
+            Screen::GetInstance().GetWidth() / 2 - 88, 180);
+        layout->SetViewId("dump_group");
+        container_->Add(layout);
+        positionY_ += layout->GetHeight();
+        layout->SetRows(3); // 3: row
+        layout->SetCols(3); // 3: col
+        CreateButtons(layout);
+        layout->LayoutChildren();
+    }
+}
+
+void UITestDumpDomTree::CreateButtons(GridLayout* layout)
+{
+    if (layout == nullptr) {
+        return;
+    }
+    UICheckBox* checkBox = new UICheckBox();
+    layout->Add(checkBox);
+    checkBox->SetState(UICheckBox::SELECTED);
+    checkBox->SetViewId("dump_checkbox");
+
+    UIRadioButton* radioButton = new UIRadioButton("aaa");
+    layout->Add(radioButton);
+    radioButton->SetState(UICheckBox::UNSELECTED);
+    radioButton->SetViewId("dump_radiobutton");
+
+    UIToggleButton* toggleButton = new UIToggleButton();
+    layout->Add(toggleButton);
+    toggleButton->SetStyle(STYLE_BACKGROUND_OPA, 0);
+    toggleButton->SetViewId("dump_togglebutton");
+
+    UILabelButton* dumpButton1 = GetLabelButton("dump");
+    layout->Add(dumpButton1);
+    /* dump node here */
+    if (clickDumpDomListener1_ == nullptr) {
+        clickDumpDomListener1_ = static_cast<UIView::OnClickListener*>(
+            new TestBtnOnClickDumpDomListener(static_cast<UIView*>(dumpButton1), "dump_checkbox"));
+    }
+    dumpButton1->SetOnClickListener(clickDumpDomListener1_);
+
+    UILabelButton* dumpButton2 = GetLabelButton("dump");
+    layout->Add(dumpButton2);
+    /* dump node here */
+    if (clickDumpDomListener2_ == nullptr) {
+        clickDumpDomListener2_ = static_cast<UIView::OnClickListener*>(
+            new TestBtnOnClickDumpDomListener(static_cast<UIView*>(dumpButton2), "dump_radiobutton"));
+    }
+    dumpButton2->SetOnClickListener(clickDumpDomListener2_);
+
+    UILabelButton* dumpButton3 = GetLabelButton("dump");
+    layout->Add(dumpButton3);
+    /* dump node here */
+    if (clickDumpDomListener3_ == nullptr) {
+        clickDumpDomListener3_ = static_cast<UIView::OnClickListener*>(
+            new TestBtnOnClickDumpDomListener(static_cast<UIView*>(dumpButton3), "dump_togglebutton"));
+    }
+    dumpButton3->SetOnClickListener(clickDumpDomListener3_);
+
+    UILabelButton* dumpButton4 = GetLabelButton("dump_all ");
+    layout->Add(dumpButton4);
+
+    if (clickDumpDomListener4_ == nullptr) {
+        clickDumpDomListener4_ = static_cast<UIView::OnClickListener*>(
+            new TestBtnOnClickDumpDomTreeListener(static_cast<UIView*>(dumpButton4), nullptr));
+    }
+    dumpButton4->SetOnClickListener(clickDumpDomListener4_);
+
+    UILabelButton* dumpButton5 = GetLabelButton("dump_group");
+    layout->Add(dumpButton5);
+    if (clickDumpDomListener5_ == nullptr) {
+        clickDumpDomListener5_ = static_cast<UIView::OnClickListener*>(
+            new TestBtnOnClickDumpDomTreeListener(static_cast<UIView*>(dumpButton5), "dump_group"));
+    }
+    dumpButton5->SetOnClickListener(clickDumpDomListener5_);
+}
+
+void UITestDumpDomTree::UIKit_TestDumpDom_002()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group2 = new UIViewGroup();
+        group2->SetPosition(Screen::GetInstance().GetWidth() / 2, 0); // 2: half of screen width
+        group2->SetWidth(Screen::GetInstance().GetWidth() / 2); // 2: half of screen width
+        group2->SetHeight(g_height_); // 200: height
+        group2->SetViewId("dump_group2");
+        container_->Add(group2);
+        positionY_ += group2->GetHeight();
+
+        UILabel* label = GetTitleLabel("dump image");
+        group2->Add(label);
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, TEXT_DISTANCE_TO_TOP_SIDE + offsetY);
+
+        UIImageView* imageView = new UIImageView();
+        imageView->SetPosition(VIEW_DISTANCE_TO_TOP_SIDE, TEXT_DISTANCE_TO_LEFT_SIDE + offsetY);
+        imageView->SetWidth(50); // 50: width
+        imageView->SetHeight(50); // 50: height
+        imageView->SetSrc(BLUE_RGB888_IMAGE_PATH);
+        imageView->SetViewId("dump_image");
+        group2->Add(imageView);
+
+        UILabelButton* dumpButton1 = GetLabelButton("dump");
+        dumpButton1->SetPosition(VIEW_DISTANCE_TO_TOP_SIDE, VIEW_DISTANCE_TO_TOP_SIDE + offsetY);
+        group2->Add(dumpButton1);
+        dumpButton1->SetText("dump");
+        /* dump node here */
+        if (clickDumpDomListener6_ == nullptr) {
+            clickDumpDomListener6_ = static_cast<UIView::OnClickListener*>(
+                new TestBtnOnClickDumpDomListener(static_cast<UIView*>(dumpButton1), "dump_image"));
+        }
+        dumpButton1->SetOnClickListener(clickDumpDomListener6_);
+    }
+}
+
+void UITestDumpDomTree::UIKit_TestDumpDom_003()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group5 = new UIViewGroup();
+        group5->SetPosition(0, 260); // 260: y-coordinate
+        group5->SetWidth(Screen::GetInstance().GetWidth() / 2); // 2: half of screen width
+        group5->SetHeight(g_height_); // 200: height
+        group5->SetViewId("dump_group5");
+        container_->Add(group5);
+        positionY_ += group5->GetHeight();
+
+        UILabel* label = GetTitleLabel("dump slider progress");
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, TEXT_DISTANCE_TO_TOP_SIDE);
+        group5->Add(label);
+
+        UISlider* slider = new UISlider();
+        // 50: new width, 100: new height
+        slider->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, VIEW_DISTANCE_TO_TOP_SIDE, BACK_BUTTON_HEIGHT,
+            BACK_BUTTON_HEIGHT + BACK_BUTTON_HEIGHT);
+        slider->SetValidHeight(250); // 250: valid height
+        slider->SetDirection(UISlider::Direction::DIR_BOTTOM_TO_TOP);
+        slider->SetRange(100, 0); // 100: max
+        slider->SetValue(BACK_BUTTON_HEIGHT);     // 50: value of progress bar
+        slider->SetStep(0);
+        slider->SetBackgroundStyle(STYLE_BACKGROUND_COLOR, Color::GetColorFromRGB(0, 182, 191).full); // 182, 191: color
+        slider->SetForegroundStyle(STYLE_BACKGROUND_COLOR, Color::GetColorFromRGB(255, 152, 0).full); // 255, 152: color
+        slider->SetKnobWidth(BACK_BUTTON_HEIGHT); // 50: knob width
+        slider->SetKnobStyle(StyleDefault::GetSliderKnobStyle());
+        slider->SetImage(static_cast<ImageInfo*>(nullptr), static_cast<ImageInfo*>(nullptr));
+        slider->EnableBackground(true);
+        slider->SetViewId("dump_slider");
+        group5->Add(slider);
+
+        UILabelButton* dumpButton = GetLabelButton("dump");
+        dumpButton->SetPosition(x_coordinate, y_coordinate); // 120: x-coordinate, 73: y-coordinate
+        /* dump node here */
+        if (clickDumpDomListener7_ == nullptr) {
+            clickDumpDomListener7_ = static_cast<UIView::OnClickListener*>(
+                new TestBtnOnClickDumpDomListener(static_cast<UIView*>(dumpButton), "dump_slider"));
+        }
+        dumpButton->SetOnClickListener(clickDumpDomListener7_);
+        group5->Add(dumpButton);
+    }
+}
+
+void UITestDumpDomTree::UIKit_TestDumpDom_004()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group4 = new UIViewGroup();
+        group4->SetPosition(Screen::GetInstance().GetWidth() / 2, 260); // 2: half of screen width; 260: y-coordinate
+        group4->SetWidth(Screen::GetInstance().GetWidth() / 2); // 2: half of screen width
+        group4->SetHeight(g_height_); // 100: height
+        group4->SetViewId("dump_group4");
+        container_->Add(group4);
+        positionY_ += group4->GetHeight();
+
+        UILabel* label = GetTitleLabel("dump box progress");
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, TEXT_DISTANCE_TO_TOP_SIDE);
+        group4->Add(label);
+
+        UIBoxProgress* boxProgress = new UIBoxProgress();
+        // y_coordinate2: x-coordinate, 68: y-coordinate, 90: new width, 10: new height
+        boxProgress->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, y_coordinate1, 90, 10);
+        boxProgress->SetDirection(UIBoxProgress::Direction::DIR_LEFT_TO_RIGHT);
+        boxProgress->SetValidHeight(10); // 10: valid height
+        boxProgress->SetValidWidth(100); // 100: valid width
+        boxProgress->SetRange(100, 0); // 100: max
+        boxProgress->SetValue(20); // 20 : value of progress bar
+        boxProgress->SetStep(0);
+        // 182, 191: color
+        boxProgress->SetBackgroundStyle(STYLE_BACKGROUND_COLOR, Color::GetColorFromRGB(0, 182, 191).full);
+        // 255, 152: color
+        boxProgress->SetForegroundStyle(STYLE_BACKGROUND_COLOR, Color::GetColorFromRGB(255, 152, 0).full);
+        boxProgress->SetImage(static_cast<char*>(nullptr));
+        boxProgress->EnableBackground(true);
+        boxProgress->SetViewId("dump_boxprogress");
+        group4->Add(boxProgress);
+        UILabelButton* dumpButton = GetLabelButton("dump");
+        dumpButton->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, TEXT_DISTANCE_TO_TOP_SIDE + offsetY);
+        /* dump node here */
+        if (clickDumpDomListener8_ == nullptr) {
+            clickDumpDomListener8_ = static_cast<UIView::OnClickListener*>(
+                new TestBtnOnClickDumpDomListener(static_cast<UIView*>(dumpButton), "dump_boxprogress"));
+        }
+        dumpButton->SetOnClickListener(clickDumpDomListener8_);
+        group4->Add(dumpButton);
+    }
+}
+
+void UITestDumpDomTree::UIKit_TestDumpDom_005()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group3 = new UIViewGroup();
+        group3->SetPosition(0, 450); // 450: y-coordinate
+        group3->SetWidth(Screen::GetInstance().GetWidth() / 2 - VIEW_DISTANCE_TO_LEFT_SIDE); // 2: half of screen width
+        group3->SetHeight(g_height4_); // 500: height
+        group3->SetViewId("dump_group3");
+        container_->Add(group3);
+
+        UILabel* label = GetTitleLabel("dump label");
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE + offsetX, TEXT_DISTANCE_TO_TOP_SIDE);
+        group3->Add(label);
+
+        UILabel* label2 = GetTitleLabel("UILabel");
+        label2->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
+        label2->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE + offsetX, VIEW_DISTANCE_TO_TOP_SIDE + offsetx_,
+            BUTTON_WIDHT1 + offsetx_, dumph_);
+        label2->SetViewId("dump_label");
+        group3->Add(label2);
+
+        UILabelButton* labelButton = GetLabelButton("LabelButton");
+        labelButton->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, y_coordinate2); // 48: x position, 108: y position
+        labelButton->SetViewId("dump_label_button");
+        group3->Add(labelButton);
+
+        UIArcLabel* label3 = new UIArcLabel();
+        label3->SetArcTextCenter(x_position, y_position); // 70: x position, 330: y position
+        label3->SetArcTextRadius(radius);     // 150: radius
+        label3->SetArcTextAngle(0, angle_end);   // 0: start angle, 270: end angle
+        label3->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        label3->SetText("012345678ABCDEF");
+        label3->SetStyle(STYLE_LETTER_SPACE, letter_space); // 30: letter space
+        label3->SetViewId("dump_arc_label");
+        group3->Add(label3);
+
+        UILabelButton* dumpButton1 = GetLabelButton("dump");
+        dumpButton1->SetPosition(x_coordinate1, 48); // 230: x-coordinate, 48: y-coordinate
+        /* dump node here */
+        if (clickDumpDomListener9_ == nullptr) {
+            clickDumpDomListener9_ = static_cast<UIView::OnClickListener*>(
+                new TestBtnOnClickDumpDomListener(static_cast<UIView*>(dumpButton1), "dump_label"));
+        }
+        dumpButton1->SetOnClickListener(clickDumpDomListener9_);
+        group3->Add(dumpButton1);
+
+        UILabelButton* dumpButton2 = GetLabelButton("dump");
+        dumpButton2->SetPosition(x_coordinate1, y_coordinate2); // 230: x-coordinate, 108: y-coordinate
+        /* dump node here */
+        if (clickDumpDomListener10_ == nullptr) {
+            clickDumpDomListener10_ = static_cast<UIView::OnClickListener*>(
+                new TestBtnOnClickDumpDomListener(static_cast<UIView*>(dumpButton2), "dump_label_button"));
+        }
+        dumpButton2->SetOnClickListener(clickDumpDomListener10_);
+        group3->Add(dumpButton2);
+
+        UILabelButton* dumpButton3 = GetLabelButton("dump");
+        dumpButton3->SetPosition(x_coordinate1, y_coordinate3); // 230: x position, 310: y position
+        /* dump node here */
+        if (clickDumpDomListener11_ == nullptr) {
+            clickDumpDomListener11_ = static_cast<UIView::OnClickListener*>(
+                new TestBtnOnClickDumpDomListener(static_cast<UIView*>(dumpButton3), "dump_arc_label"));
+        }
+        dumpButton3->SetOnClickListener(clickDumpDomListener11_);
+        group3->Add(dumpButton3);
+    }
+}
+
+void UITestDumpDomTree::UIKit_TestDumpDom_006()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group6 = new UIViewGroup();
+        // 2: half of screen width; 450: screen height
+        group6->SetPosition(Screen::GetInstance().GetWidth() / 2, 450);
+        group6->SetWidth(Screen::GetInstance().GetWidth() / 2); // 2: half of screen width
+        group6->SetHeight(250); // 250: height
+        group6->SetViewId("dump_group6");
+        container_->Add(group6);
+        positionY_ += group6->GetHeight();
+
+        UILabel* label = GetTitleLabel("dump circle progress");
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE - offsetX, TEXT_DISTANCE_TO_TOP_SIDE);
+        group6->Add(label);
+
+        UICircleProgress* circleProgress = new UICircleProgress();
+        // 40: y-coordinate, 48: y-coordinate, 150: new width, 150: new height
+        circleProgress->SetPosition(BUTTON_HEIGHT1, VIEW_DISTANCE_TO_LEFT_SIDE, 150, 150);
+        circleProgress->SetCenterPosition(BACK_BUTTON_HEIGHT, BACK_BUTTON_HEIGHT); // 50: x-coordinate, 50: y-coordinate
+        circleProgress->SetRadius(BACK_BUTTON_HEIGHT); // 50: radius
+        circleProgress->SetValue(20); // 20: value of progress bar
+        circleProgress->SetStyle(STYLE_PADDING_LEFT, 10); // 10: padding left
+        circleProgress->SetStyle(STYLE_PADDING_TOP, 5); // 5: padding top
+        circleProgress->SetRange(100, 0); // 100: max
+        circleProgress->SetValue(BACK_BUTTON_HEIGHT); // 50: value of progress bar
+        circleProgress->SetStartAngle(0);
+        circleProgress->SetEndAngle(360); // 360: end angle
+        circleProgress->SetStep(0);
+        circleProgress->SetBackgroundStyle(StyleDefault::GetProgressBackgroundStyle());
+        circleProgress->SetForegroundStyle(StyleDefault::GetProgressForegroundStyle());
+        circleProgress->SetLineColor(Color::White());
+        circleProgress->EnableBackground(true);
+        circleProgress->SetViewId("dump_circle_progress");
+        group6->Add(circleProgress);
+
+        UILabelButton* dumpButton = GetLabelButton("dump");
+        dumpButton->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE - offsetx_, TEXT_DISTANCE_TO_TOP_SIDE + offsety_);
+        /* dump node here */
+        if (clickDumpDomListener12_ == nullptr) {
+            clickDumpDomListener12_ = static_cast<UIView::OnClickListener*>(
+                new TestBtnOnClickDumpDomListener(static_cast<UIView*>(dumpButton), "dump_circle_progress"));
+        }
+        dumpButton->SetOnClickListener(clickDumpDomListener12_);
+        group6->Add(dumpButton);
+    }
+}
+
+UILabelButton* UITestDumpDomTree::GetLabelButton(const char* buttonname)
+{
+    const int16_t labelButtonWidth = BUTTON_WIDHT2;
+    const int16_t labelButtonHeight = BUTTON_HEIGHT1;
+    if (buttonname == nullptr) {
+        return nullptr;
+    }
+    UILabelButton* labelButton = new UILabelButton();
+    if (labelButton == nullptr) {
+        return nullptr;
+    }
+    labelButton->SetPosition(0, 0);
+    labelButton->Resize(labelButtonWidth, labelButtonHeight);
+    labelButton->SetText(buttonname);
+    labelButton->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
+    labelButton->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+    labelButton->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+    labelButton->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+    labelButton->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+    labelButton->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+    labelButton->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+    return labelButton;
+}
+} // namespace OHOS
+#endif // ENABLE_DEBUG
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_dump_dom_tree/ui_test_dump_dom.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_dump_dom_tree/ui_test_dump_dom.h
new file mode 100644 (file)
index 0000000..d3e802a
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+#ifndef GRAPHIC_LITE_UI_TEST_DUMP_DOM_H
+#define GRAPHIC_LITE_UI_TEST_DUMP_DOM_H
+
+#include "graphic_config.h"
+
+#if ENABLE_DEBUG
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "layout/grid_layout.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestDumpDomTree : public UITest {
+public:
+    UITestDumpDomTree() {}
+    ~UITestDumpDomTree() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    void CreateButtons(GridLayout* layout);
+
+    void UIKit_TestDumpDom_001();
+    void UIKit_TestDumpDom_002();
+    void UIKit_TestDumpDom_003();
+    void UIKit_TestDumpDom_004();
+    void UIKit_TestDumpDom_005();
+    void UIKit_TestDumpDom_006();
+    UILabelButton* GetLabelButton(const char* buttonname);
+
+private:
+    UIScrollView* container_ = nullptr;
+    UIView::OnClickListener* clickDumpDomListener1_ = nullptr;
+    UIView::OnClickListener* clickDumpDomListener2_ = nullptr;
+    UIView::OnClickListener* clickDumpDomListener3_ = nullptr;
+    UIView::OnClickListener* clickDumpDomListener4_ = nullptr;
+    UIView::OnClickListener* clickDumpDomListener5_ = nullptr;
+    UIView::OnClickListener* clickDumpDomListener6_ = nullptr;
+    UIView::OnClickListener* clickDumpDomListener7_ = nullptr;
+    UIView::OnClickListener* clickDumpDomListener8_ = nullptr;
+    UIView::OnClickListener* clickDumpDomListener9_ = nullptr;
+    UIView::OnClickListener* clickDumpDomListener10_ = nullptr;
+    UIView::OnClickListener* clickDumpDomListener11_ = nullptr;
+    UIView::OnClickListener* clickDumpDomListener12_ = nullptr;
+};
+}
+#endif // ENABLE_DEBUG
+#endif // GRAPHIC_LITE_UI_TEST_DUMP_DOM_H
+
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_event_injector/ui_test_event_injector.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_event_injector/ui_test_event_injector.h
new file mode 100644 (file)
index 0000000..6ef5106
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_EVENT_INJECTOR_H
+#define UI_TEST_EVENT_INJECTOR_H
+
+#include "graphic_config.h"
+
+#include "components/root_view.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "dock/input_device.h"
+#include "ui_test.h"
+#include "layout/grid_layout.h"
+#include "ui_test_event_injector_view.h"
+
+namespace OHOS {
+class UITestEventInjector : public UITest, public UIView::OnClickListener {
+public:
+    UITestEventInjector() {}
+    ~UITestEventInjector() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    void ActionEvent(const UIView& view);
+    bool OnClick(UIView& view, const ClickEvent& event) override;
+
+    void UIKitEventInjectorClickEvent001();
+    void UIKitEventInjectorDragEvent002();
+    void UIKitEventInjectorLongPressEvent003();
+    void UIKitEventInjectorKeyEvent004();
+    void UIKitEventInjectorUptodown005();
+    void UIKitEventInjectorDowntoUp006();
+    void UIKitEventInjectorLefttoRight007();
+    void UIKitEventInjectorRighttoLeft008();
+    void UIKitEventInjectorULefttoLRight009();
+    void UIKitEventInjectorLRighttoULeft010();
+
+private:
+    UIScrollView* container_ = nullptr;
+    GridLayout* layout_ = nullptr;
+    UILabelButton* clickBtn_ = nullptr;
+    UILabelButton* dragBtn_ = nullptr;
+    UILabelButton* longPressBtn_ = nullptr;
+    UILabelButton* keyBtn_ = nullptr;
+    UILabelButton* upToDownBtn_ = nullptr;
+    UILabelButton* downToUpBtn_ = nullptr;
+    UILabelButton* leftToRightBtn_ = nullptr;
+    UILabelButton* rightToLeftBtn_ = nullptr;
+    UILabelButton* uLeftTolRightBtn_ = nullptr;
+    UILabelButton* lRightTouLeftBtn_ = nullptr;
+    UILabelButton* increaseDragTimeBtn_ = nullptr;
+    UILabelButton* decreaseDragTimeBtn_ = nullptr;
+    UILabelButton* DragTimeDisplayBtn_ = nullptr;
+    UITestEventInjectorView* clickTestView_ = nullptr;
+    UITestEventInjectorView* dragTestView_ = nullptr;
+    UITestEventInjectorView* longPressTestView_ = nullptr;
+    UITestEventInjectorView* KeyEventTestView_ = nullptr;
+    UIScrollView* scrollTestView_ = nullptr;
+
+    int16_t lastX_ = 0;
+    int16_t lastY_ = 0;
+    uint16_t dragTime_ = 100; // 100: 100ms
+
+    void InnerTest(std::string title, bool touchable, bool draggable, bool dragParent,
+        std::string btnTitle, UILabelButton* btn, UITestEventInjectorView*& testView);
+    void SetLastPos(UIView* view);
+    void SetUpButton(UILabelButton* btn, std::string title);
+    void SetUpScrollView();
+    void IncreaseDragTime();
+    void DecreaseDragTime();
+    void DragTimeDisplay();
+    void SetDragTimeDisplay(uint16_t dragTime);
+};
+} // namespace OHOS
+#endif // UI_TEST_EVENT_INJECTOR_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_event_injector/ui_test_event_injector_view.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_event_injector/ui_test_event_injector_view.cpp
new file mode 100644 (file)
index 0000000..9e684e4
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "graphic_config.h"
+
+#if ENABLE_DEBUG
+#include "components/root_view.h"
+#include "dfx/event_injector.h"
+#include "engines/gfx/gfx_engine_manager.h"
+#include "ui_test_event_injector.h"
+#include <string>
+#if ENABLE_WINDOW
+#include "window/window.h"
+#endif
+
+#define POINT_YHX static_cast<int16_t>(scrollPoint.y + SCROLL_HEIGHT / RATIO_X)
+#define POINT_YHY static_cast<int16_t>(scrollPoint.y + SCROLL_HEIGHT / RATIO_Y)
+#define POINT_XWX static_cast<int16_t>(scrollPoint.x + SCROLL_WIDTH / RATIO_X)
+#define POINT_XWY static_cast<int16_t>(scrollPoint.x + SCROLL_WIDTH / RATIO_Y)
+namespace OHOS {
+namespace {
+const int16_t ITEM_H = 50;
+const int16_t TEXT_H = 29;
+const int16_t TEXT_W = 250;
+const int16_t TEST_VIEW_H = 50;
+const int16_t TEST_VIEW_W = 50;
+const int16_t GAP = 5;
+const int16_t TEST_VIEW_GAP = 80;
+const int16_t TEST_BUTTON_W = 100;
+const int16_t TEST_BUTTON_H = 30;
+const int16_t LAYOUT_HEIGHT = 250;
+const int16_t LAYOUT_WIDTH = 320;
+const int16_t BLANK = 20;
+const int16_t SCROLL_WIDTH = 250;
+const int16_t SCROLL_HEIGHT = 250;
+const int16_t SCROLL_BUTTON_W = 740;
+const int16_t SCROLL_BUTTON_H = 360;
+const int16_t DRAG_TIME_OFFSET = 20;
+const int16_t RATIO_X = 3;
+const int16_t RATIO_Y = 10;
+const int16_t POINT_OFFSET = 4;
+} // namespace
+
+bool UITestEventInjectorView::OnLongPressEvent(const LongPressEvent& event)
+{
+    if (label_ != nullptr) {
+        label_->SetText("long press!");
+        label_->Invalidate();
+    }
+    return UIView::OnLongPressEvent(event);
+}
+
+bool UITestEventInjectorView::OnDragEvent(const DragEvent& event)
+{
+    if (label_ != nullptr) {
+        label_->SetText("drag!");
+        label_->Invalidate();
+    }
+    return UIView::OnDragEvent(event);
+}
+
+bool UITestEventInjectorView::OnClickEvent(const ClickEvent& event)
+{
+    if (label_ != nullptr) {
+        label_->SetText(sentence_.c_str());
+        label_->Invalidate();
+    }
+    return UIView::OnClickEvent(event);
+}
+
+bool UITestEventInjectorView::OnPressEvent(const PressEvent& event)
+{
+    if (label_ != nullptr) {
+        label_->SetText("press!");
+        label_->Invalidate();
+    }
+    return UIView::OnPressEvent(event);
+}
+
+bool UITestEventInjectorView::OnReleaseEvent(const ReleaseEvent& event)
+{
+    if (label_ != nullptr) {
+        label_->SetText("release!");
+        label_->Invalidate();
+    }
+    return UIView::OnReleaseEvent(event);
+}
+
+bool UITestEventInjectorView::OnCancelEvent(const CancelEvent& event)
+{
+    if (label_ != nullptr) {
+        label_->SetText("cancel!");
+        label_->Invalidate();
+    }
+    return UIView::OnCancelEvent(event);
+}
+
+
+bool UITestEventInjectorView::OnKeyAct(UIView& view, const KeyEvent& event)
+{
+    if (label_ == nullptr) {
+        return false;
+    }
+    label_->SetText("key!");
+    label_->Invalidate();
+    return true;
+}
+
+void UITestEventInjector::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        container_->SetHorizontalScrollState(false);
+        container_->SetThrowDrag(true);
+    }
+    EventInjector::GetInstance()->RegisterEventInjector(EventDataType::POINT_TYPE);
+    EventInjector::GetInstance()->RegisterEventInjector(EventDataType::KEY_TYPE);
+
+    positionX_ = 20; // 20 : start x
+    positionY_ = 20; // 20 : start y
+
+#if ENABLE_WINDOW
+    Window* window = RootView::GetInstance()->GetBoundWindow();
+    if (window != nullptr) {
+        EventInjector::GetInstance()->SetWindowId(window->GetWindowId());
+    }
+#endif
+}
+
+void UITestEventInjector::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+    layout_ = nullptr;
+
+    if (EventInjector::GetInstance()->IsEventInjectorRegistered(EventDataType::POINT_TYPE)) {
+        EventInjector::GetInstance()->UnregisterEventInjector(EventDataType::POINT_TYPE);
+    }
+    if (EventInjector::GetInstance()->IsEventInjectorRegistered(EventDataType::KEY_TYPE)) {
+        EventInjector::GetInstance()->UnregisterEventInjector(EventDataType::KEY_TYPE);
+    }
+}
+
+const UIView* UITestEventInjector::GetTestView()
+{
+    UIKitEventInjectorClickEvent001();
+    UIKitEventInjectorDragEvent002();
+    UIKitEventInjectorLongPressEvent003();
+    UIKitEventInjectorKeyEvent004();
+
+    SetUpScrollView();
+    UIKitEventInjectorUptodown005();
+    UIKitEventInjectorDowntoUp006();
+    UIKitEventInjectorLefttoRight007();
+    UIKitEventInjectorRighttoLeft008();
+    UIKitEventInjectorULefttoLRight009();
+    UIKitEventInjectorLRighttoULeft010();
+    IncreaseDragTime();
+    DecreaseDragTime();
+    DragTimeDisplay();
+
+    layout_->LayoutChildren();
+    return container_;
+}
+
+void UITestEventInjector::UIKitEventInjectorClickEvent001()
+{
+    clickBtn_ = new UILabelButton();
+    InnerTest("模拟点击事件 ", true, false, false, "click", clickBtn_, clickTestView_);
+}
+
+void UITestEventInjector::UIKitEventInjectorDragEvent002()
+{
+    dragBtn_ = new UILabelButton();
+    InnerTest("模拟滑动事件 ", true, true, false, "drag", dragBtn_, dragTestView_);
+}
+
+void UITestEventInjector::UIKitEventInjectorLongPressEvent003()
+{
+    longPressBtn_ = new UILabelButton();
+    InnerTest("模拟长按事件 ", true, true, true, "long press", longPressBtn_, longPressTestView_);
+}
+
+void UITestEventInjector::UIKitEventInjectorKeyEvent004()
+{
+    keyBtn_ = new UILabelButton();
+    InnerTest("模拟按键输入 ", true, false, false, "key event", keyBtn_, KeyEventTestView_);
+}
+
+void UITestEventInjector::UIKitEventInjectorUptodown005()
+{
+    upToDownBtn_ = new UILabelButton();
+    SetUpButton(upToDownBtn_, "up to down");
+}
+
+void UITestEventInjector::UIKitEventInjectorDowntoUp006()
+{
+    downToUpBtn_ = new UILabelButton();
+    SetUpButton(downToUpBtn_, "down to up");
+}
+
+void UITestEventInjector::UIKitEventInjectorLefttoRight007()
+{
+    leftToRightBtn_ = new UILabelButton();
+    SetUpButton(leftToRightBtn_, "left to right");
+}
+
+void UITestEventInjector::UIKitEventInjectorRighttoLeft008()
+{
+    rightToLeftBtn_ = new UILabelButton();
+    SetUpButton(rightToLeftBtn_, "right to left");
+}
+
+void UITestEventInjector::UIKitEventInjectorULefttoLRight009()
+{
+    uLeftTolRightBtn_ = new UILabelButton();
+    SetUpButton(uLeftTolRightBtn_, "uLeft to lRight");
+}
+
+void UITestEventInjector::UIKitEventInjectorLRighttoULeft010()
+{
+    lRightTouLeftBtn_ = new UILabelButton();
+    SetUpButton(lRightTouLeftBtn_, "lRight to uleft");
+}
+
+void UITestEventInjector::IncreaseDragTime()
+{
+    increaseDragTimeBtn_ = new UILabelButton();
+    SetUpButton(increaseDragTimeBtn_, "increase drag time");
+}
+
+void UITestEventInjector::DecreaseDragTime()
+{
+    decreaseDragTimeBtn_ = new UILabelButton();
+    SetUpButton(decreaseDragTimeBtn_, "decrease drag time");
+}
+
+void UITestEventInjector::DragTimeDisplay()
+{
+    DragTimeDisplayBtn_ = new UILabelButton();
+    std::string dragTimestr = "dragTime:" + std::to_string(dragTime_);
+    SetUpButton(DragTimeDisplayBtn_, dragTimestr.c_str());
+}
+
+void UITestEventInjector::InnerTest(std::string title,
+                                    bool touchable,
+                                    bool draggable,
+                                    bool dragParent,
+                                    std::string btnTitle,
+                                    UILabelButton* btn,
+                                    UITestEventInjectorView*& testView)
+{
+    if ((container_ != nullptr) && (btn != nullptr)) {
+        UILabel* label = new UILabel();
+        container_->Add(label);
+        label->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, positionY_, Screen::GetInstance().GetWidth(),
+                           TITLE_LABEL_DEFAULT_HEIGHT);
+        label->SetText(title.c_str());
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        positionY_ += (TEXT_H + GAP);
+        testView = new UITestEventInjectorView();
+        testView->InitListener();
+        container_->Add(testView);
+        testView->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, positionY_, TEST_VIEW_W, TEST_VIEW_H);
+        testView->SetStyle(STYLE_BACKGROUND_COLOR, Color::Blue().full);
+        testView->SetTouchable(touchable);
+        testView->SetDraggable(draggable);
+        testView->SetDragParentInstead(dragParent);
+        UILabel* label1 = new UILabel();
+        container_->Add(label1);
+        label1->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE + TEST_VIEW_GAP,
+            positionY_ + 2 * GAP, TEXT_W, TEXT_H); // 2 : ratio
+        label1->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        testView->SetLabel(label1);
+
+        container_->Add(btn);
+        btn->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE + 3 * TEST_VIEW_GAP, positionY_ + GAP, // 3 : ratio
+                         BUTTON_WIDHT2, BUTTON_HEIGHT2);
+        btn->SetText(btnTitle.c_str());
+        btn->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
+        btn->SetOnClickListener(this);
+        btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+        btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+        btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+        btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+        btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+        btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+
+        positionY_ += ITEM_H;
+    }
+}
+
+void UITestEventInjector::SetUpScrollView()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("模拟Drag事件测试");
+    container_->Add(label);
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, positionY_);
+    SetLastPos(label);
+
+    scrollTestView_ = new UIScrollView();
+    scrollTestView_->SetIntercept(true);
+    scrollTestView_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    scrollTestView_->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, positionY_, SCROLL_WIDTH, SCROLL_HEIGHT);
+    if (Screen::GetInstance().GetScreenShape() == ScreenShape::RECTANGLE) {
+        scrollTestView_->SetXScrollBarVisible(true);
+    }
+    scrollTestView_->SetYScrollBarVisible(true);
+    scrollTestView_->SetThrowDrag(true);
+    container_->Add(scrollTestView_);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetText("button1");
+    button1->SetPosition(0, 0, SCROLL_BUTTON_W, SCROLL_BUTTON_H);
+    UILabelButton* button2 = new UILabelButton();
+    button2->SetText("button2");
+    button2->SetPosition(0, SCROLL_BUTTON_H, SCROLL_BUTTON_W, SCROLL_BUTTON_H);
+    scrollTestView_->Add(button1);
+    scrollTestView_->Add(button2);
+
+    if (layout_ == nullptr) {
+        layout_ = new GridLayout();
+        // 40 : offset
+        layout_->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE + 40, positionY_ + SCROLL_HEIGHT, LAYOUT_WIDTH, LAYOUT_HEIGHT);
+        container_->Add(layout_);
+        layout_->SetLayoutDirection(LAYOUT_VER);
+        layout_->SetRows(5); // 5 : rows
+        layout_->SetCols(2); // 2 : columns
+    }
+}
+
+void UITestEventInjector::SetLastPos(UIView* view)
+{
+    if (view == nullptr) {
+        return;
+    }
+    lastX_ = view->GetX();
+    lastY_ = view->GetY() + view->GetHeight();
+    positionY_ = lastY_ + 8 * GAP; /* 8:ratio */
+}
+
+void UITestEventInjector::SetUpButton(UILabelButton* btn, std::string title)
+{
+    if (btn == nullptr) {
+        return;
+    }
+    layout_->Add(btn);
+    btn->Resize(BUTTON_WIDHT3, BUTTON_HEIGHT3);
+    btn->SetText(title.c_str());
+    btn->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    btn->SetOnClickListener(this);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+}
+
+void UITestEventInjector::SetDragTimeDisplay(uint16_t dragTime)
+{
+    std::string dragTimestr = "dragTime:" + std::to_string(dragTime);
+    DragTimeDisplayBtn_->SetText(dragTimestr.c_str());
+    DragTimeDisplayBtn_->Invalidate();
+}
+
+void UITestEventInjector::ActionEvent(const UIView& view)
+{
+    Point point;
+    Point scrollPoint;
+    if (&view == clickBtn_) {
+        point = {static_cast<int16_t>(clickTestView_->GetRect().GetX() + TEST_VIEW_W / POINT_OFFSET),
+                 clickBtn_->GetRect().GetBottom()};
+        EventInjector::GetInstance()->SetClickEvent(point);
+    } else if (&view == dragBtn_) {
+        point = {static_cast<int16_t>(dragTestView_->GetRect().GetX() + TEST_VIEW_W / POINT_OFFSET),
+                 dragBtn_->GetRect().GetBottom()};
+        Point endPoint = {static_cast<int16_t>(point.x + (RATIO_X * TEST_VIEW_W) / POINT_OFFSET), point.y};
+        // 80:ms
+        EventInjector::GetInstance()->SetDragEvent(point, endPoint, 80);
+    } else if (&view == longPressBtn_) {
+        point = {static_cast<int16_t>(longPressTestView_->GetRect().GetX() + TEST_VIEW_W / POINT_OFFSET),
+                 longPressBtn_->GetRect().GetBottom()};
+        EventInjector::GetInstance()->SetLongPressEvent(point);
+    } else if (&view == keyBtn_) {
+        // 26:key id
+        uint16_t keyId = 26;
+        EventInjector::GetInstance()->SetKeyEvent(keyId, InputDevice::STATE_PRESS);
+    } else if (&view == upToDownBtn_) {
+        scrollPoint = {scrollTestView_->GetRect().GetX(), scrollTestView_->GetRect().GetY()};
+        Point startPoint = {POINT_XWX, POINT_YHY};
+        Point endPoint = {POINT_XWX, POINT_YHX};
+        EventInjector::GetInstance()->SetDragEvent(startPoint, endPoint, dragTime_);
+    } else if (&view == downToUpBtn_) {
+        scrollPoint = {scrollTestView_->GetRect().GetX(), scrollTestView_->GetRect().GetY()};
+        Point startPoint = {POINT_XWX, POINT_YHX};
+        Point endPoint = {POINT_XWX, POINT_YHY};
+        EventInjector::GetInstance()->SetDragEvent(startPoint, endPoint, dragTime_);
+    }
+}
+
+/* drag range:0 < x < 300, 62 < y < 362, click range:20 < x < 60, 392 < y < 432 */
+bool UITestEventInjector::OnClick(UIView& view, const ClickEvent& event)
+{
+    Point point;
+    Point scrollPoint;
+    if (&view == leftToRightBtn_) {
+        scrollPoint = {scrollTestView_->GetRect().GetX(), scrollTestView_->GetRect().GetY()};
+        Point startPoint = {POINT_XWY, POINT_YHX};
+        Point endPoint = {POINT_XWX,  POINT_YHX};
+        EventInjector::GetInstance()->SetDragEvent(startPoint, endPoint, dragTime_);
+    } else if (&view == rightToLeftBtn_) {
+        scrollPoint = {scrollTestView_->GetRect().GetX(), scrollTestView_->GetRect().GetY()};
+        Point startPoint = {POINT_XWX,  POINT_YHX};
+        Point endPoint = {POINT_XWY, POINT_YHX};
+        EventInjector::GetInstance()->SetDragEvent(startPoint, endPoint, dragTime_);
+    } else if (&view == uLeftTolRightBtn_) {
+        scrollPoint = {scrollTestView_->GetRect().GetX(), scrollTestView_->GetRect().GetY()};
+        Point startPoint = {POINT_XWY, POINT_YHY};
+        Point endPoint = {POINT_XWX, POINT_YHX};
+        EventInjector::GetInstance()->SetDragEvent(startPoint, endPoint, dragTime_);
+    } else if (&view == lRightTouLeftBtn_) {
+        scrollPoint = {scrollTestView_->GetRect().GetX(), scrollTestView_->GetRect().GetY()};
+        Point startPoint = {POINT_XWX, POINT_YHX};
+        Point endPoint = {POINT_XWY, POINT_YHY};
+        EventInjector::GetInstance()->SetDragEvent(startPoint, endPoint, dragTime_);
+    } else if (&view == increaseDragTimeBtn_) {
+        dragTime_ += DRAG_TIME_OFFSET;
+        SetDragTimeDisplay(dragTime_);
+    } else if (&view == decreaseDragTimeBtn_) {
+        dragTime_ -= DRAG_TIME_OFFSET;
+        SetDragTimeDisplay(dragTime_);
+    }
+    ActionEvent(view);
+    return true;
+}
+} // namespace OHOS
+#endif // ENABLE_DEBUG
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_event_injector/ui_test_event_injector_view.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_event_injector/ui_test_event_injector_view.h
new file mode 100644 (file)
index 0000000..f74b00f
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Navtive Test Case
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+#ifndef UI_TEST_EVENT_INJECTOR_VIEW_H
+#define UI_TEST_EVENT_INJECTOR_VIEW_H
+
+#include "graphic_config.h"
+#include "components/root_view.h"
+
+namespace OHOS {
+
+class UITestEventInjectorView : public UIView, public RootView::OnKeyActListener {
+public:
+    UITestEventInjectorView() : label_(nullptr) {}
+    virtual ~UITestEventInjectorView() {RootView::GetInstance()->ClearOnKeyActListener();}
+    void InitListener() { RootView::GetInstance()->SetOnKeyActListener(this);}
+    bool OnLongPressEvent(const LongPressEvent& event) override;
+    bool OnDragEvent(const DragEvent& event) override;
+    void SetSentence(std::string sentence) {sentence_ = sentence;}
+    void SetLabel(UILabel* label) {label_ = label;}
+    bool OnClickEvent(const ClickEvent& event) override;
+    bool OnPressEvent(const PressEvent& event) override;
+    bool OnReleaseEvent(const ReleaseEvent& event) override;
+    bool OnCancelEvent(const CancelEvent& event) override;
+    bool OnKeyAct(UIView& view, const KeyEvent& event) override;
+
+private:
+    UILabel* label_;
+    std::string sentence_ = "click";
+};
+}
+
+#endif // UI_TEST_EVENT_INJECTOR_VIEW_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_float_box/ui_test_float_box.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_float_box/ui_test_float_box.cpp
new file mode 100644 (file)
index 0000000..8db53bb
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: UITestFloatBoxView
+ * Author: Hisi Graphic Team
+ * Created: 2025-8
+ */
+
+#include "ui_test_float_box.h"
+#include "common/screen.h"
+#include "font/ui_font.h"
+#include "components/ui_float_box_view.h"
+#include "common/image_cache_manager.h"
+
+namespace OHOS {
+namespace {
+const int16_t BTN_W = 80;
+const int16_t BTN_H = 50;
+
+static constexpr uint8_t MAX_ITEM_CNT = 3;
+static FloatItem g_floatItems[MAX_ITEM_CNT] = {
+    {"SPORT", nullptr},
+    {"SETTING", nullptr},
+    {"SLEEP", nullptr},
+};
+
+static const char* g_floatItemsPath[MAX_ITEM_CNT] = {
+    RES_PATH"SPORT_ICON.bin",
+    RES_PATH"SETTING_ICON.bin",
+    RES_PATH"SLEEP_ICON.bin",
+};
+} // namespace
+
+void UITestFloatBox::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->SetThrowDrag(true);
+        container_->SetHorizontalScrollState(false);
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight());
+
+        UIView* view = new UIView();
+        view->SetPosition(0, 0, Screen::GetInstance().GetWidth(), 800); // 800: height
+        view->SetStyle(STYLE_BACKGROUND_COLOR, Color::White().full);
+        container_->Add(view);
+    }
+
+    UIScrollView* group = new UIScrollView();
+    // 50: x, y; 100: screen width and height - 100
+    group->SetPosition(50, 50, Screen::GetInstance().GetWidth() - 100, Screen::GetInstance().GetHeight() - 100);
+    group->SetStyle(STYLE_BACKGROUND_COLOR, Color::Gray().full);
+    group->SetIntercept(true);
+    container_->Add(group);
+
+    UIView* view = new UIView();
+    view->SetPosition(0, 0, 800, 800); // 800: width and height
+    group->Add(view);
+
+    if (floatBox_ == nullptr) {
+        floatBox_ = new UIFloatBoxView();
+    }
+    // 200: x, y; 150: screen width and height - 150
+    floatBox_->SetPosition(200, 200, Screen::GetInstance().GetWidth() - 150, Screen::GetInstance().GetHeight() - 150);
+#if ENABLE_ROTATE_INPUT
+    floatBox_->RequestFocus();
+#endif
+    LoadItemImgs();
+    floatBox_->AddItems(g_floatItems, 2); // 2: item cnt
+    floatBox_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Yellow().full);
+    floatBox_->SetItemSize(60); // 60: item size
+    floatBox_->SetItemSpacing(10); // 10: item spacing
+    floatBox_->SetDraggable(true);
+    floatBox_->SetTouchable(true);
+    floatBox_->SetIntercept(true);
+    floatBox_->SetDragFactor(1.5f);
+    floatBox_->SetAccFactor(6.0f);
+    floatBox_->SetRotateFactor(5.0f);
+    floatBox_->SetAlignAvgSpeed(2.0f);
+    floatBox_->SetOnItemClickListener(this);
+    group->Add(floatBox_);
+
+    if (switchBtn_ == nullptr) {
+        switchBtn_ = new UILabelButton();
+    }
+    switchBtn_->SetPosition((Screen::GetInstance().GetWidth() - BTN_W) / 2, // 2: divider
+        Screen::GetInstance().GetHeight() - BTN_H, BTN_W, BTN_H); // 2: divider
+    switchBtn_->SetOnClickListener(this);
+    switchBtn_->SetText("Switch");
+    container_->Add(switchBtn_);
+}
+
+void UITestFloatBox::LoadItemImgs()
+{
+    for (uint8_t i = 0; i < MAX_ITEM_CNT; i++) {
+        if (g_floatItems[i].imgInfo == nullptr) {
+            g_floatItems[i].imgInfo = ImageCacheManager::GetInstance().LoadSingleRes(g_floatItemsPath[i]);
+        }
+    }
+}
+
+bool UITestFloatBox::OnClick(UIView& view, const ClickEvent& event)
+{
+    if (&view == switchBtn_) {
+        if (floatBox_ == nullptr) {
+            return false;
+        }
+        uint16_t itemCnt = floatBox_->GetItemCnt();
+        if (itemCnt == 2) { // 2: item cnt
+            floatBox_->AddItems(g_floatItems, 3); // 3: item Cnt
+            printf("Add 3 items\n");
+        } else {
+            floatBox_->AddItems(g_floatItems, 2); // 2: item Cnt
+            printf("Add 2 items\n");
+        }
+    }
+    return true;
+}
+
+void UITestFloatBox::TearDown()
+{
+#if ENABLE_ROTATE_INPUT
+    floatBox_->ClearFocus();
+#endif
+    DeleteChildren(container_);
+    container_ = nullptr;
+    floatBox_ = nullptr;
+    switchBtn_ = nullptr;
+
+    for (uint8_t i = 0; i < MAX_ITEM_CNT; i++) {
+        if (g_floatItems[i].imgInfo != nullptr) {
+            ImageCacheManager::GetInstance().UnloadSingleRes(g_floatItemsPath[i]);
+            g_floatItems[i].imgInfo = nullptr;
+        }
+    }
+}
+
+const UIView* UITestFloatBox::GetTestView()
+{
+    return container_;
+}
+
+void UITestFloatBox::OnItemClick(const std::string& name)
+{
+    printf("Click Item: %s\n", name.c_str());
+}
+}
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_float_box/ui_test_float_box.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_float_box/ui_test_float_box.h
new file mode 100644 (file)
index 0000000..dba22cf
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: UITestFloatBoxView
+ * Author: Hisi Graphic Team
+ * Created: 2025-8
+ */
+
+#ifndef UI_TEST_FLOAT_BOX_H
+#define UI_TEST_FLOAT_BOX_H
+
+#include "ui_test.h"
+#include "components/ui_float_box_view.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "components/ui_view_group.h"
+
+namespace OHOS {
+class UITestFloatBox : public UITest, public UIView::OnClickListener, public UIFloatBoxView::OnItemClickListener {
+public:
+    UITestFloatBox() {}
+    ~UITestFloatBox() override {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    void OnItemClick(const std::string& name) override;
+    bool OnClick(UIView& view, const ClickEvent& event) override;
+
+private:
+    void LoadItemImgs();
+    UIScrollView* container_ = nullptr;
+    UIFloatBoxView* floatBox_ = nullptr;
+    UILabelButton* switchBtn_ = nullptr;
+};
+}
+#endif
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_focus_manager/ui_test_focus_manager.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_focus_manager/ui_test_focus_manager.cpp
new file mode 100644 (file)
index 0000000..1e8b895
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_focus_manager.h"
+
+#if ENABLE_FOCUS_MANAGER
+namespace OHOS {
+namespace {
+const uint16_t LABEL_BUTTON_DEFAULT_FONT_SIZE = 15;
+const uint16_t LABEL_BUTTON_DEFAULT_WIDTH = 60;
+const uint16_t LABEL_BUTTON_DEFAULT_HEIGHT = 40;
+} // namespace
+
+class TestOnFocusListener : public UIView::OnFocusListener {
+public:
+    TestOnFocusListener() {}
+
+    ~TestOnFocusListener() {}
+
+    bool OnFocus(UIView& view) override
+    {
+        if (view.IsViewGroup()) {
+            view.SetStyle(STYLE_BORDER_COLOR, Color::Red().full);
+        } else {
+            view.SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+        }
+        view.Invalidate();
+        return true;
+    }
+
+    bool OnBlur(UIView& view) override
+    {
+        if (view.IsViewGroup()) {
+            view.SetStyle(STYLE_BORDER_COLOR, Color::White().full);
+        } else {
+            /* 0: red, 125: green, 255: blue */
+            view.SetStyle(STYLE_BACKGROUND_COLOR, Color::GetColorFromRGB(0, 125, 255).full);
+        }
+        view.Invalidate();
+        return true;
+    }
+};
+
+class RequestFocusByDirectionOnClickListener : public UIView::OnClickListener {
+public:
+    explicit RequestFocusByDirectionOnClickListener(uint8_t direction) : direction_(direction) {}
+
+    ~RequestFocusByDirectionOnClickListener() {}
+
+    bool OnClick(UIView& view, const ClickEvent& event)
+    {
+        FocusManager::GetInstance()->RequestFocusByDirection(direction_);
+        return true;
+    }
+private:
+    uint8_t direction_ = 0;
+};
+
+class ResetFocusOnClickListener : public UIView::OnClickListener {
+public:
+    explicit ResetFocusOnClickListener(UIView* focus) : focus_(focus) {}
+
+    ~ResetFocusOnClickListener() {}
+
+    bool OnClick(UIView& view, const ClickEvent& event)
+    {
+        FocusManager::GetInstance()->RequestFocus(focus_);
+        return true;
+    }
+
+private:
+    UIView* focus_ = nullptr;
+};
+
+class SetGroupInterceptOnClickListener : public UIView::OnClickListener {
+public:
+    SetGroupInterceptOnClickListener(UIViewGroup* viewGroup, bool intercept)
+        : viewGroup_(viewGroup), intercept_(intercept) {}
+
+    ~SetGroupInterceptOnClickListener() {}
+
+    bool OnClick(UIView& view, const ClickEvent& event)
+    {
+        if (viewGroup_ != nullptr) {
+            viewGroup_->SetInterceptFocus(intercept_);
+            return true;
+        }
+        return false;
+    }
+private:
+    UIViewGroup* viewGroup_ = nullptr;
+    bool intercept_;
+};
+
+class SetGroupInterceptFalseOnClickListener : public UIView::OnClickListener {
+public:
+    explicit SetGroupInterceptFalseOnClickListener(UIViewGroup* viewGroup) : viewGroup_(viewGroup) {}
+
+    ~SetGroupInterceptFalseOnClickListener() {}
+
+    bool OnClick(UIView& view, const ClickEvent& event)
+    {
+        viewGroup_->SetInterceptFocus(false);
+        return true;
+    }
+private:
+    UIViewGroup* viewGroup_ = nullptr;
+};
+
+class SetFocusableOnClickListener : public UIView::OnClickListener {
+public:
+    SetFocusableOnClickListener(UIView* view, bool enable) : view_(view), enable_(enable) {}
+
+    ~SetFocusableOnClickListener() {}
+
+    bool OnClick(UIView& view, const ClickEvent& event)
+    {
+        view_->SetFocusable(enable_);
+        return true;
+    }
+private:
+    UIView* view_ = nullptr;
+    bool enable_ = false;
+};
+
+class RequestFocusOnClickListener : public UIView::OnClickListener {
+public:
+    explicit RequestFocusOnClickListener(UIView* view) : view_(view) {}
+
+    ~RequestFocusOnClickListener() {}
+
+    bool OnClick(UIView& view, const ClickEvent& event)
+    {
+        FocusManager::GetInstance()->RequestFocus(view_);
+        return true;
+    }
+private:
+    UIView* view_ = nullptr;
+};
+
+class ClearFocusOnClickListener : public UIView::OnClickListener {
+public:
+    ClearFocusOnClickListener() {}
+
+    ~ClearFocusOnClickListener() {}
+
+    bool OnClick(UIView& view, const ClickEvent& event)
+    {
+        FocusManager::GetInstance()->ClearFocus();
+        return true;
+    }
+};
+
+void UITestFocusManager::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        container_->SetHorizontalScrollState(false);
+    }
+}
+
+void UITestFocusManager::TearDown()
+{
+    FocusManager::GetInstance()->ClearFocus();
+    if (testOnFocusListener_ != nullptr) {
+        delete testOnFocusListener_;
+        testOnFocusListener_ = nullptr;
+    }
+    if (requestFocusByDirectionLeftListener_ != nullptr) {
+        delete requestFocusByDirectionLeftListener_;
+        requestFocusByDirectionLeftListener_ = nullptr;
+    }
+    if (requestFocusByDirectionRightListener_ != nullptr) {
+        delete requestFocusByDirectionRightListener_;
+        requestFocusByDirectionRightListener_ = nullptr;
+    }
+    if (requestFocusByDirectionUpListener_ != nullptr) {
+        delete requestFocusByDirectionUpListener_;
+        requestFocusByDirectionUpListener_ = nullptr;
+    }
+    if (requestFocusByDirectionLeftListener_ != nullptr) {
+        delete requestFocusByDirectionLeftListener_;
+        requestFocusByDirectionLeftListener_ = nullptr;
+    }
+    if (requestFocusByDirectionDownListener_ != nullptr) {
+        delete requestFocusByDirectionDownListener_;
+        requestFocusByDirectionDownListener_ = nullptr;
+    }
+    if (setFocusableViewListener_ != nullptr) {
+        delete setFocusableViewListener_;
+        setFocusableViewListener_ = nullptr;
+    }
+    if (setFocusableViewListener1_ != nullptr) {
+        delete setFocusableViewListener1_;
+        setFocusableViewListener1_ = nullptr;
+    }
+    if (setGroupInterceptListener_ != nullptr) {
+        delete setGroupInterceptListener_;
+        setGroupInterceptListener_ = nullptr;
+    }
+    if (setGroupInterceptListener1_ != nullptr) {
+        delete setGroupInterceptListener1_;
+        setGroupInterceptListener1_ = nullptr;
+    }
+    if (resetFocusListener_ != nullptr) {
+        delete resetFocusListener_;
+        resetFocusListener_ = nullptr;
+    }
+    if (clearFocusListener_ != nullptr) {
+        delete clearFocusListener_;
+        clearFocusListener_ = nullptr;
+    }
+    DeleteChildren(container_);
+    container_ = nullptr;
+}
+
+const UIView* UITestFocusManager::GetTestView()
+{
+    UIKit_Focus_Manager_Test_001();
+    return container_;
+}
+
+UIView* UITestFocusManager::CreateTestUILabel(UIViewGroup* parent, int16_t x, int16_t y,
+    const char* text, bool focusable)
+{
+    UILabel* label = new UILabel();
+    parent->Add(label);
+    label->SetPosition(x, y, LABEL_BUTTON_DEFAULT_WIDTH, LABEL_BUTTON_DEFAULT_HEIGHT);
+    label->SetText(text);
+    label->SetViewId(text);
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, LABEL_BUTTON_DEFAULT_FONT_SIZE);
+    label->SetFocusable(focusable);
+    /* 0: red, 125: green, 255: blue */
+    label->SetStyle(STYLE_BACKGROUND_COLOR, Color::GetColorFromRGB(0, 125, 255).full);
+    label->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    label->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+    if (testOnFocusListener_ == nullptr) {
+        testOnFocusListener_ = static_cast<UIView::OnFocusListener*>(new TestOnFocusListener());
+    }
+    label->SetOnFocusListener(testOnFocusListener_);
+    return label;
+}
+
+UIViewGroup* UITestFocusManager::CreateTestUIViewGroup(UIViewGroup* parent, bool focusable, bool interceptFocus)
+{
+    UIViewGroup* viewGroup = new UIViewGroup();
+    parent->Add(viewGroup);
+    viewGroup->SetFocusable(focusable);
+    viewGroup->SetInterceptFocus(interceptFocus);
+    viewGroup->SetStyle(STYLE_BORDER_COLOR, Color::White().full);
+    viewGroup->SetStyle(STYLE_BORDER_OPA, HALF_OPA_OPAQUE);
+    viewGroup->SetStyle(STYLE_BORDER_WIDTH, 1);
+    viewGroup->SetStyle(STYLE_BORDER_RADIUS, VIEW_STYLE_BORDER_RADIUS);
+    if (testOnFocusListener_ == nullptr) {
+        testOnFocusListener_ = static_cast<UIView::OnFocusListener*>(new TestOnFocusListener());
+    }
+    viewGroup->SetOnFocusListener(testOnFocusListener_);
+    return viewGroup;
+}
+
+void UITestFocusManager::InitListener(UIViewGroup* group)
+{
+    UIView* view2 = CreateTestUILabel(group, 195, 5, "2", true); /* 195: x, 5: y */
+    if (clearFocusListener_ == nullptr) {
+        clearFocusListener_ = static_cast<UIView::OnClickListener*>(new ClearFocusOnClickListener());
+    }
+    if (setFocusableViewListener_ == nullptr) {
+        setFocusableViewListener_ = static_cast<UIView::OnClickListener*>(
+            new SetFocusableOnClickListener(view2, true));
+    }
+    if (setFocusableViewListener1_ == nullptr) {
+        setFocusableViewListener1_ = static_cast<UIView::OnClickListener*>(
+            new SetFocusableOnClickListener(view2, false));
+    }
+    UIViewGroup* btnViewGroup = new UIViewGroup();
+    /* 50: x, 300: width, 400: height */
+    btnViewGroup->SetPosition(50, 400, 300, 400);
+    container_->Add(btnViewGroup);
+    UIKit_Focus_Manager_Test_002(btnViewGroup);
+}
+
+void UITestFocusManager::UIKit_Focus_Manager_Test_001()
+{
+    UILabel* label = new UILabel();
+    container_->Add(label);
+    /* 150: x ; 288: width */
+    label->SetPosition(150, TEXT_DISTANCE_TO_TOP_SIDE, 288, TITLE_LABEL_DEFAULT_HEIGHT);
+    label->SetText("焦点管理效果 ");
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    UIViewGroup* viewGroup = CreateTestUIViewGroup(container_, true, false);
+    /* 500: width, 350: height */
+    viewGroup->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE2, VIEW_DISTANCE_TO_TOP_SIDE, 500, 350);
+
+    UIViewGroup* viewGroup1 = CreateTestUIViewGroup(viewGroup, true, false);
+    UIViewGroup* viewGroup2 = CreateTestUIViewGroup(viewGroup1, true, false);
+    UIViewGroup* viewGroup3 = CreateTestUIViewGroup(viewGroup, true, false);
+    UIViewGroup* viewGroup4 = CreateTestUIViewGroup(viewGroup3, true, false);
+    UIViewGroup* viewGroup5 = CreateTestUIViewGroup(viewGroup4, true, false);
+    UIViewGroup* viewGroup6 = CreateTestUIViewGroup(viewGroup, true, false);
+
+    viewGroup1->SetPosition(5, 5, 270, 60);      /* 5: x,   5: y;   270: width, 60: height */
+    viewGroup2->SetPosition(100, 5, 80, 50);     /* 100: x, 5: y;   80: width,  50: height */
+    viewGroup3->SetPosition(290, 5, 280, 115);   /* 290: x, 5: y;   280: width, 115: height */
+    viewGroup4->SetPosition(5, 5, 260, 60);      /* 5: x,   5: y;   260: width, 60: height */
+    viewGroup5->SetPosition(5, 5, 250, 50);      /* 5: x,   5: y;   250: width, 50: height */
+    viewGroup6->SetPosition(100, 160, 400, 160); /* 100: x, 160: y; 400: width, 160: height */
+
+    CreateTestUILabel(viewGroup1, 0, 5, "1", true);                   /* 0: x,   5: y */
+    CreateTestUILabel(viewGroup2, 5, 5, "3", true);                   /* 5: x,   5: y */
+    CreateTestUILabel(viewGroup5, 5, 5, "4", true);                   /* 5: x,   5: y */
+    CreateTestUILabel(viewGroup5, 35, 5, "5", true);                 /* 35: x, 5: y */
+    CreateTestUILabel(viewGroup3, 50, 70, "6", true);                /* 50: x, 70: y */
+
+    CreateTestUILabel(viewGroup, 80, 100, "7", true);                 /* 80: x,  100: y */
+    CreateTestUILabel(viewGroup6, 5, 5, "8", true);                   /* 5: x,   5: y */
+    CreateTestUILabel(viewGroup6, 100, 80, "9", true);                /* 100: x, 80: y */
+    CreateTestUILabel(viewGroup6, 200, 5, "10", true);                /* 200: x, 5: y */
+    
+    if (setGroupInterceptListener_ == nullptr) {
+        setGroupInterceptListener_ = static_cast<UIView::OnClickListener*>(
+            new SetGroupInterceptOnClickListener(viewGroup5, true));
+    }
+    if (setGroupInterceptListener1_ == nullptr) {
+        setGroupInterceptListener1_ = static_cast<UIView::OnClickListener*>(
+            new SetGroupInterceptOnClickListener(viewGroup5, false));
+    }
+    if (resetFocusListener_ == nullptr) {
+        resetFocusListener_ = static_cast<UIView::OnClickListener*>(
+            new ResetFocusOnClickListener(viewGroup1->GetChildById("1")));
+    }
+    InitListener(viewGroup1);
+    FocusManager::GetInstance()->RequestFocus(viewGroup1->GetChildById("1"));
+}
+
+void UITestFocusManager::UIKit_Focus_Manager_Test_002(UIViewGroup* btnViewGroup)
+{
+    if (requestFocusByDirectionLeftListener_ == nullptr) {
+        requestFocusByDirectionLeftListener_ = static_cast<UIView::OnClickListener*>(
+            new RequestFocusByDirectionOnClickListener(FOCUS_DIRECTION_LEFT));
+    }
+    if (requestFocusByDirectionRightListener_ == nullptr) {
+        requestFocusByDirectionRightListener_ = static_cast<UIView::OnClickListener*>(
+            new RequestFocusByDirectionOnClickListener(FOCUS_DIRECTION_RIGHT));
+    }
+    if (requestFocusByDirectionUpListener_ == nullptr) {
+        requestFocusByDirectionUpListener_ = static_cast<UIView::OnClickListener*>(
+            new RequestFocusByDirectionOnClickListener(FOCUS_DIRECTION_UP));
+    }
+    if (requestFocusByDirectionDownListener_ == nullptr) {
+        requestFocusByDirectionDownListener_ = static_cast<UIView::OnClickListener*>(
+            new RequestFocusByDirectionOnClickListener(FOCUS_DIRECTION_DOWN));
+    }
+     /* 10: x, 10: y */
+    SetUpButton("向左 ", 10, 10, btnViewGroup, requestFocusByDirectionLeftListener_);
+    /* 150: x, 10: y */
+    SetUpButton("向右 ", 150, 10, btnViewGroup, requestFocusByDirectionRightListener_);
+    /* 10: x, 60: y */
+    SetUpButton("向上 ", 10, 60, btnViewGroup, requestFocusByDirectionUpListener_);
+    /* 150: x, 60: y */
+    SetUpButton("向下 ", 150, 60, btnViewGroup, requestFocusByDirectionDownListener_);
+    /* 10: x, 110: y */
+    SetUpButton("2可获焦 ", 10, 110, btnViewGroup, setFocusableViewListener_);
+    /* 150: x, 110: y */
+    SetUpButton("2不可获焦 ", 150, 110, btnViewGroup, setFocusableViewListener1_);
+    /* 10: x, 160: y */
+    SetUpButton("设置4容器拦截 ", 10, 160, btnViewGroup, setGroupInterceptListener_);
+    /* 150: x, 160: y */
+    SetUpButton("取消4容器拦截 ", 150, 160, btnViewGroup, setGroupInterceptListener1_);
+    /* 10: x, 210: y */
+    SetUpButton("重置焦点 ", 10, 210, btnViewGroup, resetFocusListener_);
+    /* 150: x, 210: y */
+    SetUpButton("清除焦点 ", 150, 210, btnViewGroup, clearFocusListener_);
+}
+
+UILabelButton* UITestFocusManager::SetUpButton(std::string title, int16_t x, int16_t y, UIViewGroup* viewGroup,
+    UIView::OnClickListener* listener)
+{
+    UILabelButton* btn = new UILabelButton();
+    btn->SetPosition(x, y, BUTTON_WIDHT2, BUTTON_HEIGHT1);
+    btn->SetText(title.c_str());
+    btn->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
+    btn->SetOnClickListener(listener);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+    viewGroup->Add(btn);
+    return btn;
+}
+} // namespace OHOS
+#endif
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_focus_manager/ui_test_focus_manager.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_focus_manager/ui_test_focus_manager.h
new file mode 100644 (file)
index 0000000..6b05825
--- /dev/null
@@ -0,0 +1,53 @@
+
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_FOCUS_MANAGER_H
+#define UI_TEST_FOCUS_MANAGER_H
+
+#include "graphic_config.h"
+#if ENABLE_FOCUS_MANAGER
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "dock/focus_manager.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestFocusManager : public UITest {
+public:
+    UITestFocusManager() {}
+    ~UITestFocusManager() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    void InitListener(UIViewGroup* group);
+
+    void UIKit_Focus_Manager_Test_001();
+    void UIKit_Focus_Manager_Test_002(UIViewGroup* btnViewGroup);
+
+private:
+    UIView* CreateTestUILabel(UIViewGroup* parent, int16_t x, int16_t y,
+        const char* text, bool focusable);
+    UIViewGroup* CreateTestUIViewGroup(UIViewGroup* parent, bool focusable, bool interceptFocus);
+    UILabelButton* SetUpButton(std::string title, int16_t x, int16_t y, UIViewGroup* viewGroup,
+        UIView::OnClickListener* listener);
+    UIScrollView* container_ = nullptr;
+    UIView::OnFocusListener* testOnFocusListener_ = nullptr;
+    UIView::OnClickListener* requestFocusByDirectionLeftListener_ = nullptr;
+    UIView::OnClickListener* requestFocusByDirectionRightListener_ = nullptr;
+    UIView::OnClickListener* requestFocusByDirectionUpListener_ = nullptr;
+    UIView::OnClickListener* requestFocusByDirectionDownListener_ = nullptr;
+    UIView::OnClickListener* setFocusableViewListener_ = nullptr;
+    UIView::OnClickListener* setFocusableViewListener1_ = nullptr;
+    UIView::OnClickListener* setGroupInterceptListener_ = nullptr;
+    UIView::OnClickListener* setGroupInterceptListener1_ = nullptr;
+    UIView::OnClickListener* resetFocusListener_ = nullptr;
+    UIView::OnClickListener* clearFocusListener_ = nullptr;
+};
+} // namespace OHOS
+#endif
+#endif // UI_TEST_FOCUS_MANAGER_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_foldable/ui_test_foldable.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_foldable/ui_test_foldable.cpp
new file mode 100644 (file)
index 0000000..9fb3f77
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) CompanyNameMagicTag 2025. All rights reserved.
+ * Description: UITestFoldable
+ * Author:
+ * Create: 2025-09
+ */
+
+#include "ui_test_foldable.h"
+#include "components/ui_transform_group.h"
+#include "common/screen.h"
+#include "font/ui_font.h"
+#include "common/image_cache_manager.h"
+
+namespace OHOS {
+namespace {
+struct FaceInfo {
+    const char* name;
+    const char* path;
+} ;
+
+static constexpr uint8_t FOLDABLE_MAX_PAGE_NUM = 7;
+UIViewGroup* foldPages_[FOLDABLE_MAX_PAGE_NUM];
+static FaceInfo g_faceInfo[FOLDABLE_MAX_PAGE_NUM] = {
+    {"0 foldpage0", RES_PATH"/foldpage6_CS6.bin"},
+    {"1 foldpage1", RES_PATH"/foldpage1_CS6.bin"},
+    {"2 foldpage2", RES_PATH"/foldpage2_CS6.bin"},
+    {"3 foldpage3", RES_PATH"/foldpage3_CS6.bin"},
+    {"4 foldpage4", RES_PATH"/foldpage4_CS6.bin"},
+    {"5 foldpage5", RES_PATH"/foldpage5_CS6.bin"},
+    {"6 foldpage6", RES_PATH"/foldpage6_CS6.bin"}
+};
+static constexpr const char* DESKTOP_IMAGE_PATH = RES_PATH"/Desktop_CS6.bin";
+
+static constexpr int16_t LABEL_FONT_SIZE = 30;
+static constexpr uint8_t DIVISOR_TWO = 2;
+static constexpr uint16_t PAGE_WIDTH = 360;
+static constexpr uint16_t PAGE_HEIGHT = 150;
+static constexpr uint16_t EDIT_PAGE_WIDTH = 270;
+static constexpr uint16_t EDIT_PAGE_HEIGHT = 60;
+static constexpr uint16_t EDIT_LABEL_WIDTH = 300;
+static constexpr uint16_t EDIT_LABEL_HEIGHT = 100;
+static constexpr uint16_t FOLD_DEFAULT_BG_OPA = 160;
+static constexpr uint8_t BOTTOM_SLID_OUT_THRE = 50;
+static constexpr uint8_t TOP_OVER_SCROLL_UP_LIMIT = 50;
+static constexpr uint16_t MAX_SCROLL_DIS = 500;
+} // namespace
+
+void UITestFoldable::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIViewGroup();
+        container_->SetDraggable(true);
+        container_->SetOnDragListener(this);
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight());
+        dragYoffset_ = Screen::GetInstance().GetHeight();
+    }
+}
+
+void UITestFoldable::TearDown()
+{
+    if (container_ != nullptr) {
+        if (desktop_) {
+            ImageCacheManager::GetInstance().UnloadSingleRes(std::string(DESKTOP_IMAGE_PATH));
+        }
+        if (foldableView_) {
+            if (lastFocusView_) {
+                lastFocusView_->Remove(focusLabel_);
+                delete focusLabel_;
+                focusLabel_ = nullptr;
+                lastFocusView_ = nullptr;
+            }
+            for (uint8_t i = 0; i < FOLDABLE_MAX_PAGE_NUM; i++) {
+                ImageCacheManager::GetInstance().UnloadSingleRes(std::string(g_faceInfo[i].path));
+            }
+        }
+
+        DeleteChildren(container_);
+        container_ = nullptr;
+        desktop_ = nullptr;
+        editLabel_ = nullptr;
+        applistLabel_ = nullptr;
+        foldableView_ = nullptr;
+        focusLabel_ = nullptr;
+        titleLabel_ = nullptr;
+    }
+}
+
+const UIView* UITestFoldable::GetTestView()
+{
+    UITestFoldableView();
+    return container_;
+}
+
+void UITestFoldable::InitDesktopPage()
+{
+    if (desktop_ == nullptr) {
+        desktop_ = new UIImageView();
+        ImageInfo* src = ImageCacheManager::GetInstance().LoadSingleRes(std::string(DESKTOP_IMAGE_PATH));
+        desktop_->SetViewId("Desktop");
+        desktop_->SetSrc(src);
+        desktop_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight());
+        desktop_->SetPosition(0, 0);
+        desktop_->SetResizeMode(UIImageView::ImageResizeMode::FILL);
+        desktop_->SetAutoEnable(false);
+        desktop_->SetDragParentInstead(true);
+        container_->Add(desktop_);
+    }
+}
+
+void UITestFoldable::InitEditPage()
+{
+    if (editLabel_ == nullptr) {
+        editLabel_ = new UILabelButton();
+        editLabel_->SetPosition(Screen::GetInstance().GetWidth() / DIVISOR_TWO - EDIT_LABEL_WIDTH / DIVISOR_TWO,
+            Screen::GetInstance().GetHeight() / DIVISOR_TWO - EDIT_LABEL_HEIGHT / DIVISOR_TWO,
+            EDIT_LABEL_WIDTH, EDIT_LABEL_HEIGHT);
+        editLabel_->SetTextColor(Color::Yellow());
+        editLabel_->SetAlign(TEXT_ALIGNMENT_CENTER);
+        editLabel_->SetText("编辑卡片页面\n长按返回");
+        editLabel_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, LABEL_FONT_SIZE);
+        editLabel_->SetVisible(false);
+        editLabel_->SetOnLongPressListener(this);
+        container_->Add(editLabel_);
+    }
+}
+
+void UITestFoldable::InitApplistPage()
+{
+    if (applistLabel_ == nullptr) {
+        applistLabel_ = new UILabel();
+        applistLabel_->SetPosition(0, 0, Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight());
+        applistLabel_->SetTextColor(Color::Blue());
+        applistLabel_->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        applistLabel_->SetText("应用列表页面\n下滑返回");
+        applistLabel_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, LABEL_FONT_SIZE);
+        applistLabel_->SetVisible(false);
+        container_->Add(applistLabel_);
+    }
+}
+
+void UITestFoldable::InitFlodableViewCards()
+{
+    for (uint8_t i = 0; i < FOLDABLE_MAX_PAGE_NUM; i++) {
+        UIImageView* image = new UIImageView();
+        ImageInfo* src = ImageCacheManager::GetInstance().LoadSingleRes(std::string(g_faceInfo[i].path));
+        image->SetViewId(g_faceInfo[i].name);
+        image->SetSrc(src);
+        image->SetResizeMode(UIImageView::ImageResizeMode::FILL);
+        image->SetAutoEnable(false);
+        UITransformGroup* group = new UITransformGroup();
+        group->SetViewId(g_faceInfo[i].name);
+        group->SetStyle(STYLE_BACKGROUND_OPA, 0);
+        group->SetDragParentInstead(true);
+        group->SetTouchable(true);
+        group->SetOnClickListener(this);
+        group->Add(image);
+
+        if (i == 0) {
+            image->Resize(EDIT_PAGE_WIDTH, EDIT_PAGE_HEIGHT);
+            group->SetPosition(0, 0, EDIT_PAGE_WIDTH, EDIT_PAGE_HEIGHT);
+            UILabel *lable = new UILabel();
+            lable->Resize(EDIT_PAGE_WIDTH, EDIT_PAGE_HEIGHT);
+            lable->SetTextColor(Color::Blue());
+            lable->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+            lable->SetText("应用列表");
+            lable->SetFont(DEFAULT_VECTOR_FONT_FILENAME, LABEL_FONT_SIZE);
+            group->Add(lable);
+            image->LayoutCenterOfParent();
+            lable->LayoutCenterOfParent();
+        } else {
+            image->Resize(PAGE_WIDTH, PAGE_HEIGHT);
+            group->SetPosition(0, 0, PAGE_WIDTH, PAGE_HEIGHT);
+            image->LayoutCenterOfParent();
+        }
+        foldableView_->Add(group);
+        foldPages_[i] = group;
+    }
+}
+
+void UITestFoldable::InitFlodableView()
+{
+    if (foldableView_ == nullptr) {
+        foldableView_ = new UIFoldableView();
+        foldableView_->SetPosition(0, 0, Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight());
+        foldableView_->SetIntercept(true);
+        foldableView_->SetThrowDrag(true);
+        foldableView_->SetMaxPageNum(10); // 10: max page num
+        foldableView_->SetPageSize(PAGE_WIDTH, PAGE_HEIGHT);
+        foldableView_->SetFoldableScrollListener(this);
+        foldableView_->SetOnLongPressListener(this);
+        foldableView_->SetDragParentInstead(true);
+        foldableView_->SetVisible(false);
+        foldableView_->SetFoldScaleGradient(0.2); // 0.2 scale gradient
+        foldableView_->SetFoldOpacityChange(OPA_OPAQUE, 155, 10); // 155 min fold page opacity, 10 opacity gradient
+        foldableView_->SetMarginBetweenExpandPages(15); // 15 default blank space between expand pages
+        foldableView_->SetMaxScrollDistance(MAX_SCROLL_DIS);
+        foldableView_->SetDragYoffset(Screen::GetInstance().GetHeight());
+        foldableView_->SetStyle(STYLE_BACKGROUND_OPA, FOLD_DEFAULT_BG_OPA);
+        foldableView_->SetOverScrollUpLimit(TOP_OVER_SCROLL_UP_LIMIT);
+        InitFlodableViewCards();
+        container_->Add(foldableView_);
+
+        if (focusLabel_ == nullptr) {
+            focusLabel_ = new UILabel();
+            focusLabel_->SetPosition(0, 0, PAGE_WIDTH, PAGE_HEIGHT);
+            focusLabel_->SetTextColor(Color::Green());
+            focusLabel_->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_TOP);
+            focusLabel_->SetText("focus");
+            focusLabel_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, LABEL_FONT_SIZE);
+        }
+        if (titleLabel_ == nullptr) {
+            titleLabel_ = new UILabel();
+            titleLabel_->SetPosition(127, 50, 200, 50); // 127 50 200 50: label position
+            titleLabel_->SetTextColor(Color::White());
+            titleLabel_->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+            titleLabel_->SetText("foldable sample");
+            titleLabel_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, LABEL_FONT_SIZE);
+            titleLabel_->SetVisible(false);
+            container_->Add(titleLabel_);
+        }
+    }
+}
+
+void UITestFoldable::UITestFoldableView()
+{
+    if (container_ != nullptr) {
+        InitDesktopPage();
+        InitEditPage();
+        InitApplistPage();
+        InitFlodableView();
+    }
+}
+
+void UITestFoldable::OnScroll(int16_t dragYoffset)
+{
+    titleLabel_->SetY(50 + dragYoffset); // 50: label position
+    dragYoffset_ = dragYoffset;
+}
+
+void UITestFoldable::OnOverScrollUp(int16_t dragYoffset, int16_t overDistance)
+{
+    OnScroll(dragYoffset);
+    if (overDistance >= TOP_OVER_SCROLL_UP_LIMIT && !(topSlidingOut_ || topSlidingIn_)) {
+        topSlidingOut_ = true;
+        foldableView_->StartTopSlidOutAnimator();
+    }
+}
+
+void UITestFoldable::OnOverScrollDown(int16_t dragYoffset, int16_t overDistance)
+{
+    OnScroll(dragYoffset);
+    if (overDistance <= Screen::GetInstance().GetHeight()) {
+        float coefficient = overDistance * 1.0 / Screen::GetInstance().GetHeight();
+        foldableView_->SetOpaScale((uint8_t)(OPA_OPAQUE - OPA_OPAQUE * coefficient));
+        foldableView_->SetStyle(STYLE_BACKGROUND_OPA, FOLD_DEFAULT_BG_OPA - FOLD_DEFAULT_BG_OPA * coefficient);
+        titleLabel_->SetOpaScale((uint8_t)(OPA_OPAQUE - OPA_OPAQUE * coefficient));
+    }
+}
+
+void UITestFoldable::OnTopSlidOutAnimatorStop()
+{
+    titleLabel_->SetVisible(false);
+    foldableView_->SetVisible(false);
+    applistLabel_->SetVisible(true);
+    topSlidingOut_ = false;
+    dragYoffset_ = -Screen::GetInstance().GetHeight();
+}
+
+void UITestFoldable::OnTopSlidInAnimatorStop()
+{
+    topSlidingIn_ = false;
+}
+
+void UITestFoldable::OnBottomSlidOutAnimatorStop()
+{
+    titleLabel_->SetVisible(false);
+    foldableView_->SetVisible(false);
+    dragYoffset_ = Screen::GetInstance().GetHeight();
+}
+
+void UITestFoldable::OnBottomSlidInAnimatorStop()
+{
+    foldableView_->SetOpaScale((uint8_t)(OPA_OPAQUE));
+    foldableView_->SetStyle(STYLE_BACKGROUND_OPA, FOLD_DEFAULT_BG_OPA);
+    titleLabel_->SetOpaScale((uint8_t)(OPA_OPAQUE));
+}
+
+bool UITestFoldable::OnDragStart(UIView& view, const DragEvent& event)
+{
+    if (MATH_ABS(event.GetDeltaX()) < MATH_ABS(event.GetDeltaY())) {
+        direction_ = VERTICAL;
+    } else {
+        direction_ = HORIZONTAL;
+        GRAPHIC_LOGW("drag on horizontal is not support.\n");
+    }
+    if (&view != container_ || direction_ != VERTICAL) {
+        return false;
+    }
+
+    if (event.GetDeltaY() > 0) {
+        startDragDirection_ = DragEvent::DIRECTION_TOP_TO_BOTTOM;
+    } else {
+        startDragDirection_ = DragEvent::DIRECTION_BOTTOM_TO_TOP;
+    }
+    startDragYoffset_ = foldableView_->GetDragYoffset();
+    if (startDragYoffset_ == foldableView_->GetFullyExpandDragYoffset() - Screen::GetInstance().GetHeight() &&
+        event.GetDeltaY() > 0) {
+        applistLabel_->SetVisible(false);
+        titleLabel_->SetVisible(true);
+        foldableView_->SetVisible(true);
+        topSlidingIn_ = true;
+        foldableView_->StartTopSlidInAnimator(false);
+    } else if (startDragYoffset_ == Screen::GetInstance().GetHeight() && event.GetDeltaY() < 0) {
+        titleLabel_->SetVisible(true);
+        foldableView_->SetVisible(true);
+    }
+    return foldableView_->OnDragStartEvent(event);
+}
+
+bool UITestFoldable::OnDrag(UIView& view, const DragEvent& event)
+{
+    if (&view != container_ || direction_ != VERTICAL) {
+        return false;
+    }
+
+    return foldableView_->OnDragEvent(event);
+}
+
+bool UITestFoldable::OnDragEnd(UIView& view, const DragEvent& event)
+{
+    if (&view != container_ || direction_ != VERTICAL) {
+        return false;
+    }
+
+    if (startDragYoffset_ == 0 && startDragDirection_ == DragEvent::DIRECTION_TOP_TO_BOTTOM) {
+        int16_t dragDistanceY =
+            foldableView_->CalculateDragThrowYDistance(event.GetCurrentPos(), event.GetPreLastPoint());
+        if (dragYoffset_ + dragDistanceY < BOTTOM_SLID_OUT_THRE) {
+            foldableView_->StartBottomSlidInAnimator(true);
+        } else {
+            foldableView_->StartBottomSlidOutAnimator();
+        }
+    } else if (startDragYoffset_ > 0) {
+        int16_t dragDistanceY =
+            foldableView_->CalculateDragThrowYDistance(event.GetCurrentPos(), event.GetPreLastPoint());
+        if (dragYoffset_ + dragDistanceY < startDragYoffset_) {
+            foldableView_->StartBottomSlidInAnimator(true);
+        } else {
+            foldableView_->StartBottomSlidOutAnimator();
+        }
+    }
+
+    return foldableView_->OnDragEndEvent(event);
+}
+
+bool UITestFoldable::OnClick(UIView& view, const ClickEvent& event)
+{
+    for (int i = 0; i < FOLDABLE_MAX_PAGE_NUM; i++) {
+        if (&view == foldPages_[i]) {
+            if (i == 0) {
+                topSlidingOut_ = true;
+                foldableView_->StartTopSlidOutAnimator();
+                break;
+            }
+            if (lastFocusView_) {
+                lastFocusView_->Remove(focusLabel_);
+            }
+            if (lastFocusView_ != foldPages_[i]) {
+                foldPages_[i]->Add(focusLabel_);
+                lastFocusView_ = foldPages_[i];
+            } else {
+                lastFocusView_ = NULL;
+            }
+        }
+    }
+
+    foldableView_->Invalidate();
+    return true;
+}
+
+bool UITestFoldable::OnLongPress(UIView& view, const LongPressEvent& event)
+{
+    if (&view == foldableView_) {
+        if (lastFocusView_ != nullptr) {
+            foldableView_->PinOnTop(lastFocusView_);
+        } else {
+            editLabel_->SetVisible(!editLabel_->IsVisible());
+            foldableView_->SetVisible(!foldableView_->IsVisible());
+        }
+    } else if (&view == editLabel_) {
+        editLabel_->SetVisible(!editLabel_->IsVisible());
+        foldableView_->SetVisible(!foldableView_->IsVisible());
+    }
+    foldableView_->SetStyle(STYLE_BACKGROUND_OPA, foldableView_->IsVisible() ? FOLD_DEFAULT_BG_OPA : OPA_TRANSPARENT);
+    return true;
+}
+} // namespace OHOS
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_foldable/ui_test_foldable.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_foldable/ui_test_foldable.h
new file mode 100644 (file)
index 0000000..7d1165f
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) CompanyNameMagicTag 2025. All rights reserved.
+ * Description: UITestFoldable
+ * Author:
+ * Create: 2025-09
+ */
+
+#ifndef UI_TEST_FOLDABLE_H
+#define UI_TEST_FOLDABLE_H
+
+#include "components/ui_foldable_view.h"
+#include "components/ui_image_view.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestFoldable : public UITest,
+    public UIFoldableView::OnFoldableViewEventListener, public UIView::OnDragListener,
+    public UIView::OnClickListener, public UIView::OnLongPressListener {
+public:
+    UITestFoldable() {}
+    ~UITestFoldable() override {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    /**
+     * @brief Test display UIFoldable
+     */
+    void UITestFoldableView();
+
+    void OnScroll(int16_t dragYoffset) override;
+    void OnOverScrollUp(int16_t dragYoffset, int16_t overDistance) override;
+    void OnOverScrollDown(int16_t dragYoffset, int16_t overDistance) override;
+    void OnTopSlidOutAnimatorStop() override;
+    void OnTopSlidInAnimatorStop() override;
+    void OnBottomSlidOutAnimatorStop() override;
+    void OnBottomSlidInAnimatorStop() override;
+
+    bool OnDragStart(UIView& view, const DragEvent& event) override;
+    bool OnDrag(UIView& view, const DragEvent& event) override;
+    bool OnDragEnd(UIView& view, const DragEvent& event) override;
+    bool OnClick(UIView& view, const ClickEvent& event) override;
+    bool OnLongPress(UIView& view, const LongPressEvent& event) override;
+private:
+    void InitDesktopPage();
+    void InitEditPage();
+    void InitApplistPage();
+    void InitFlodableView();
+    void InitFlodableViewCards();
+
+    static constexpr uint8_t HORIZONTAL = 0;
+    static constexpr uint8_t VERTICAL = 1;
+
+    UIViewGroup* container_ = nullptr;
+    UIImageView* desktop_ = nullptr;
+    UIFoldableView* foldableView_ = nullptr;
+    UIViewGroup* lastFocusView_ = nullptr;
+    UILabel* focusLabel_ = nullptr;
+    UILabelButton* editLabel_ = nullptr;
+    UILabel* applistLabel_ = nullptr;
+    UILabel* titleLabel_ = nullptr;
+    int16_t dragYoffset_ = 0;
+    uint8_t direction_ = VERTICAL;
+    int8_t startDragDirection_ = 0;
+    int16_t startDragYoffset_ = 0;
+    bool topSlidingOut_ = false;
+    bool topSlidingIn_ = false;
+};
+} // namespace OHOS
+#endif // UI_TEST_FOLDABLE_H
index 468cf74..8157cda 100644 (file)
@@ -26,6 +26,7 @@ const int16_t TITLE_HEIGHT = 20;
 const uint16_t LABEL_WIDTH = 400;
 const uint16_t LABEL_HEIGHT = 50;
 const uint16_t TEXT_BUF_SIZE = 200;
+const uint16_t CONTAINER_Y = 100;
 } // namespace
 
 void UITestFont::SetUp()
@@ -34,7 +35,9 @@ void UITestFont::SetUp()
         container_ = new UIScrollView();
         container_->SetThrowDrag(true);
         container_->SetHorizontalScrollState(false);
-        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - LABEL_HEIGHT);
+        container_->SetPosition(0, CONTAINER_Y);
+        container_->Resize(Screen::GetInstance().GetWidth(),
+                           Screen::GetInstance().GetHeight() - LABEL_HEIGHT - CONTAINER_Y);
         positionX_ = 50; // 50: init position x
         positionY_ = 5;  // 5: init position y
     }
index a284d17..b6b4891 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 CompanyNameMagicTag.
+ * Copyright (c) 2025-2025 Huawei Device Co., Ltd.
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_image/ui_test_png.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_image/ui_test_png.cpp
new file mode 100644 (file)
index 0000000..c960787
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Png Test
+ * Author: Hisi Graphic Team
+ * Created: 2025-9
+ */
+
+#include "ui_test_png.h"
+#if ENABLE_JPEG_AND_PNG
+namespace OHOS {
+const static int16_t START_X = 100;
+const static int16_t START_Y = 0;
+const static int16_t GAP = 10;
+const static int16_t IMG_WIDTH = 62;
+const static int16_t IMG_HEIGHT = 62;
+const static int16_t HEIGHT_100 = 100;
+const static int16_t WIDTH_50 = 50;
+const static int16_t HEIGHT_50 = 50;
+static int16_t g_xCoord = START_X;
+static int16_t g_yCoord = START_Y;
+
+void UITestPNG::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->SetThrowDrag(true);
+        container_->SetHorizontalScrollState(false);
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight());
+        positionX_ = 0;
+        positionY_ = 0;
+    }
+}
+
+void UITestPNG::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+    g_xCoord = START_X;
+    g_yCoord = START_Y;
+}
+
+const UIView* UITestPNG::GetTestView()
+{
+    SetBackgroundColor();
+    TestPNG();
+    TestFillPNG();
+    TestContainPNG();
+    return container_;
+}
+
+void UITestPNG::SetBackgroundColor()
+{
+    container_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Orange().full);
+    container_->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+}
+
+void UITestPNG::CreateLabel(const char* text)
+{
+    UILabel* label = new UILabel();
+    label->SetText(text);
+    label->SetPosition(g_xCoord, g_yCoord, TEST_LABEL_WIDTH, TEST_LABEL_HEIGHT);
+    container_->Add(label);
+    g_yCoord += TEST_LABEL_HEIGHT + GAP;
+}
+
+void UITestPNG::TestPNG()
+{
+    CreateLabel("PNG full image");
+
+    UIImageView* img = new UIImageView();
+    img->SetAutoEnable(true);
+    img->SetPosition(g_xCoord, g_yCoord, WIDTH_50, HEIGHT_50);
+    img->SetSrc(RES_PATH"haha.png");
+    img->SetStyle(STYLE_IMAGE_OPA, OPA_OPAQUE);
+    container_->Add(img);
+    g_yCoord += IMG_HEIGHT + GAP;
+}
+
+void UITestPNG::TestFillPNG()
+{
+    CreateLabel("PNG FILL 50x100");
+
+    UIImageView* img = new UIImageView();
+    img->SetAutoEnable(false);
+    img->SetSrc(RES_PATH"haha.png");
+    img->SetPosition(g_xCoord, g_yCoord, WIDTH_50, HEIGHT_100);
+    img->SetResizeMode(UIImageView::FILL);
+    img->SetStyle(STYLE_IMAGE_OPA, OPA_OPAQUE);
+    container_->Add(img);
+    g_yCoord += HEIGHT_100 + GAP;
+}
+
+void UITestPNG::TestContainPNG()
+{
+    CreateLabel("PNG CONTAIN 50x100");
+
+    UIImageView* img = new UIImageView();
+    img->SetAutoEnable(false);
+    img->SetSrc(RES_PATH"haha.png");
+    img->SetPosition(g_xCoord, g_yCoord, WIDTH_50, HEIGHT_100);
+    img->SetResizeMode(UIImageView::CONTAIN);
+    img->SetStyle(STYLE_IMAGE_OPA, OPA_OPAQUE);
+    container_->Add(img);
+    g_yCoord += HEIGHT_100 + GAP;
+}
+}
+#endif // ENABLE_JPEG_AND_PNG
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_image/ui_test_png.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_image/ui_test_png.h
new file mode 100644 (file)
index 0000000..8d163d4
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Png Test
+ * Author: Hisi Graphic Team
+ * Created: 2025-9
+ */
+
+#ifndef UI_TEST_PNG_H
+#define UI_TEST_PNG_H
+
+#include "ui_test.h"
+#include "common/screen.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "core/render_manager.h"
+#include "components/ui_image_view.h"
+#include "components/ui_scroll_view.h"
+#include "graphic_config.h"
+
+#if ENABLE_JPEG_AND_PNG
+namespace OHOS {
+class UITestPNG : public UITest {
+public:
+    UITestPNG() {}
+    ~UITestPNG() override {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+private:
+    void SetBackgroundColor();
+    void TestPNG();
+    void TestFillPNG();
+    void TestContainPNG();
+    void CreateLabel(const char* text);
+    UIScrollView* container_ = nullptr;
+};
+}
+#endif // ENABLE_JPEG_AND_PNG
+#endif // UI_TEST_PNG_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_image_animator/ui_test_image_animator.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_image_animator/ui_test_image_animator.cpp
new file mode 100644 (file)
index 0000000..1fbf449
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+
+#include "ui_test_image_animator.h"
+#include "common/screen.h"
+
+namespace OHOS {
+namespace {
+static ImageAnimatorInfo g_imageAnimatorInfo[4] = {
+    {RES_PATH"image_animator_1.bin", {84, 108}, 116, 116, IMG_SRC_FILE_PATH},
+    {RES_PATH"image_animator_2.bin", {84, 108}, 116, 116, IMG_SRC_FILE_PATH},
+    {RES_PATH"image_animator_3.bin", {84, 108}, 116, 116, IMG_SRC_FILE_PATH},
+    {RES_PATH"image_animator_4.bin", {84, 108}, 116, 116, IMG_SRC_FILE_PATH},
+};
+
+static ImageAnimatorInfo g_imageAnimatorInfo2[4] = {
+    {RES_PATH"blue.png", {84, 108}, 94, 94, IMG_SRC_FILE_PATH},
+    {RES_PATH"red.png", {84, 108}, 94, 94, IMG_SRC_FILE_PATH},
+    {RES_PATH"green.png", {84, 108}, 94, 94, IMG_SRC_FILE_PATH},
+    {RES_PATH"yellow.png", {84, 108}, 94, 94, IMG_SRC_FILE_PATH},
+};
+} // namespace
+
+void UITestImageAnimator::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+
+        UIViewGroup* uiViewGroup = new UIViewGroup();
+        // 270: width; 360: height
+        uiViewGroup->SetPosition(0, 0, 270, 360);
+        container_->Add(uiViewGroup);
+        UILabel* label = new UILabel();
+        uiViewGroup->Add(label);
+        // 260: width; 48: height
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, TEXT_DISTANCE_TO_TOP_SIDE, 260, 48);
+        label->SetText("   UIImageAnimator效果");
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        UIViewGroup* uiViewGroupFrame_ = new UIViewGroup();
+        uiViewGroup->Add(uiViewGroupFrame_);
+        // 250: width; 306: height
+        uiViewGroupFrame_->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE2, VIEW_DISTANCE_TO_TOP_SIDE, 250, 306);
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_COLOR, Color::White().full);
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_OPA, HALF_OPA_OPAQUE);
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_WIDTH, VIEW_STYLE_BORDER_WIDTH);
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_RADIUS, VIEW_STYLE_BORDER_RADIUS);
+        uiViewGroupFrame_->SetStyle(STYLE_BACKGROUND_OPA, 0);
+
+        imageAnimator_ = new UIImageAnimatorView();
+        imageAnimator_->SetPosition(25, 50, 200, 200); // 25 : offset 50 : offset ;200 : offset 200: offset
+        imageAnimator_->SetImageAnimatorSrc(g_imageAnimatorInfo, 4, 100); // 4: the number of images, 100: updating time
+        imageAnimator_->Start();
+        listener_ = new TestAnimatorStopListener(container_);
+        listener_->Init();
+        uiViewGroupFrame_->Add(imageAnimator_);
+        imageAnimator_->LayoutCenterOfParent();
+    }
+
+    if (layout_ == nullptr) {
+        layout_ = new GridLayout();
+        uint16_t height = Screen::GetInstance().GetHeight();
+        layout_->SetPosition(270, 0, 250, height); // 270: x 0 : y, 250: width,
+        container_->Add(layout_);
+        layout_->LayoutTopOfParent(60); // 60: offset
+        layout_->SetLayoutDirection(LAYOUT_VER);
+        layout_->SetRows(10); // 10 : rows
+        layout_->SetCols(2); // 2 : columns
+    }
+
+    InitImageInfo();
+}
+
+void UITestImageAnimator::InitImageInfo()
+{
+    const uint16_t pixelByteSize = 4; // 4: bytes per pixel
+    const uint16_t width = 100;       // 100: image's width
+    const uint16_t height = 100;      // 100: image's height
+    uint32_t dataSize = width * height * pixelByteSize;
+
+    InitImageInfo1();
+    InitImageInfo2();
+    InitImageInfo3();
+}
+
+void UITestImageAnimator::InitImageInfo1()
+{
+    const uint16_t pixelByteSize = 4; // 4: bytes per pixel
+    const uint16_t width = 100;       // 100: image's width
+    const uint16_t height = 100;      // 100: image's height
+    uint32_t dataSize = width * height * pixelByteSize;
+
+    uint8_t* srcData1 = static_cast<uint8_t*>(UIMalloc(dataSize));
+    if (srcData1 == nullptr) {
+        return;
+    }
+
+    for (uint32_t i = 0; i < dataSize; i += pixelByteSize) {
+        srcData1[i] = 255;            // 255: pixel value
+        srcData1[i + 1] = 0;          // 1: set green channel
+        srcData1[i + 2] = 0;          // 2: set red channel
+        srcData1[i + 3] = OPA_OPAQUE; // 3: set alpha channel
+    }
+    imageInfo1_ = static_cast<ImageInfo*>(UIMalloc(sizeof(ImageInfo)));
+    if (imageInfo1_ == nullptr) {
+        UIFree(srcData1);
+        return;
+    }
+
+    imageInfo1_->header.width = width;
+    imageInfo1_->header.height = height;
+    imageInfo1_->header.colorMode = ColorMode::ARGB8888;
+    imageInfo1_->dataSize = dataSize;
+    imageInfo1_->data = srcData1;
+}
+
+void UITestImageAnimator::InitImageInfo2()
+{
+    const uint16_t pixelByteSize = 4; // 4: bytes per pixel
+    const uint16_t width = 100;       // 100: image's width
+    const uint16_t height = 100;      // 100: image's height
+    uint32_t dataSize = width * height * pixelByteSize;
+    uint8_t* srcData2 = static_cast<uint8_t*>(UIMalloc(dataSize));
+
+    if (srcData2 == nullptr) {
+        UIFree(imageInfo1_);
+        return;
+    }
+    for (uint32_t i = 0; i < dataSize; i += pixelByteSize) {
+        srcData2[i] = 0;              // set blue channel
+        srcData2[i + 1] = 255;        // 1: set green channel 255: pixel value
+        srcData2[i + 2] = 0;          // 2: set red channel
+        srcData2[i + 3] = OPA_OPAQUE; // 3: set alpha channel
+    }
+
+    imageInfo2_ = static_cast<ImageInfo*>(UIMalloc(sizeof(ImageInfo)));
+    if (imageInfo2_ == nullptr) {
+        UIFree(srcData2);
+        UIFree(imageInfo1_);
+        return;
+    }
+    imageInfo2_->header.width = width;
+    imageInfo2_->header.height = height;
+    imageInfo2_->header.colorMode = ARGB8888;
+    imageInfo2_->dataSize = dataSize;
+    imageInfo2_->data = srcData2;
+}
+
+void UITestImageAnimator::InitImageInfo3()
+{
+    const uint16_t pixelByteSize = 4; // 4: bytes per pixel
+    const uint16_t width = 100;       // 100: image's width
+    const uint16_t height = 100;      // 100: image's height
+    uint32_t dataSize = width * height * pixelByteSize;
+
+    uint8_t* srcData3 = static_cast<uint8_t*>(UIMalloc(dataSize));
+    if (srcData3 == nullptr) {
+        UIFree(imageInfo2_);
+        UIFree(imageInfo1_);
+        return;
+    }
+    for (uint32_t i = 0; i < dataSize; i += pixelByteSize) {
+        srcData3[i] = 0;              // set blue channel
+        srcData3[i + 1] = 0;          // 1: set green channel
+        srcData3[i + 2] = 255;        // 2: set red channel 255: pixel value
+        srcData3[i + 3] = OPA_OPAQUE; // 3: set alpha channel
+    }
+
+    imageInfo3_ = static_cast<ImageInfo*>(UIMalloc(sizeof(ImageInfo)));
+    if (imageInfo3_ == nullptr) {
+        UIFree(srcData3);
+        UIFree(imageInfo2_);
+        UIFree(imageInfo1_);
+        return;
+    }
+    imageInfo3_->header.width = width;
+    imageInfo3_->header.height = height;
+    imageInfo3_->header.colorMode = ARGB8888;
+    imageInfo3_->dataSize = dataSize;
+    imageInfo3_->data = srcData3;
+
+    imageAnimatorImageInfo_[0].imageInfo = imageInfo1_;
+    imageAnimatorImageInfo_[0].pos = {84, 108};
+    imageAnimatorImageInfo_[0].width = 100;  // 100: width value
+    imageAnimatorImageInfo_[0].height = 100; // 100: height value
+    imageAnimatorImageInfo_[0].imageType = IMG_SRC_IMAGE_INFO;
+
+    imageAnimatorImageInfo_[1].imageInfo = imageInfo2_;
+    imageAnimatorImageInfo_[1].pos = {84, 108};
+    imageAnimatorImageInfo_[1].width = 100;  // 100: width value
+    imageAnimatorImageInfo_[1].height = 100; // 100: height value
+    imageAnimatorImageInfo_[1].imageType = IMG_SRC_IMAGE_INFO;
+
+    imageAnimatorImageInfo_[2].imageInfo = imageInfo3_;        // 2: image index
+    imageAnimatorImageInfo_[2].pos = {84, 108};                // 2: image index
+    imageAnimatorImageInfo_[2].width = 100;                    // 2: image index, 100: width value
+    imageAnimatorImageInfo_[2].height = 100;                   // 2: image index, 100: height value
+    imageAnimatorImageInfo_[2].imageType = IMG_SRC_IMAGE_INFO; // 2: image index
+}
+
+void UITestImageAnimator::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+    imageAnimator_ = nullptr;
+    layout_ = nullptr;
+    delete listener_;
+    listener_ = nullptr;
+
+    UIFree(reinterpret_cast<void*>(const_cast<uint8_t*>(imageInfo1_->data)));
+    imageInfo1_->data = nullptr;
+    UIFree(reinterpret_cast<void*>(const_cast<uint8_t*>(imageInfo2_->data)));
+    imageInfo2_->data = nullptr;
+    UIFree(reinterpret_cast<void*>(const_cast<uint8_t*>(imageInfo3_->data)));
+    imageInfo3_->data = nullptr;
+    UIFree(reinterpret_cast<void*>(const_cast<ImageInfo*>(imageInfo1_)));
+    imageInfo1_ = nullptr;
+    UIFree(reinterpret_cast<void*>(const_cast<ImageInfo*>(imageInfo2_)));
+    imageInfo2_ = nullptr;
+    UIFree(reinterpret_cast<void*>(const_cast<ImageInfo*>(imageInfo3_)));
+    imageInfo3_ = nullptr;
+}
+
+const UIView* UITestImageAnimator::GetTestView()
+{
+    UIKitImageAnimatorTestStart001();
+    UIKitImageAnimatorTestStop002();
+    UIKitImageAnimatorTestPause003();
+    UIKitImageAnimatorTestResume004();
+    UIKitImageAnimatorTestSetImageAnimatorSrc005();
+    UIKitImageAnimatorTestSetTickOfUpdate006();
+    UIKitImageAnimatorTestSetSizeFixed007();
+    UIKitImageAnimatorTestSetRepeat008();
+    UIKitImageAnimatorTestSetReverse009();
+    UIKitImageAnimatorTestSetAnimatorStopListener010();
+    UIKitImageAnimatorTestSetRepeatTimes011();
+    UIKitImageAnimatorTestSetFillModeTrueForward012();
+    UIKitImageAnimatorTestSetFillModeTrueBackward013();
+    UIKitImageAnimatorTestSetFillModeFalseForward014();
+    UIKitImageAnimatorTestSetFillModeFalseBackward015();
+    UIKitImageAnimatorTestSetImageInfo016();
+
+    layout_->LayoutChildren();
+    return container_;
+}
+
+void UITestImageAnimator::SetUpButton(UILabelButton* btn, const char* title)
+{
+    if (btn == nullptr) {
+        return;
+    }
+    layout_->Add(btn);
+    btn->Resize(BUTTON_WIDHT2, BUTTON_HEIGHT2);
+    btn->SetText(title);
+    btn->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
+    btn->SetOnClickListener(this);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestStart001()
+{
+    startBtn_ = new UILabelButton();
+    SetUpButton(startBtn_, "Start");
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestStop002()
+{
+    stopBtn_ = new UILabelButton();
+    SetUpButton(stopBtn_, "Stop");
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestPause003()
+{
+    pauseBtn_ = new UILabelButton();
+    SetUpButton(pauseBtn_, "Pause");
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestResume004()
+{
+    resumeBtn_ = new UILabelButton();
+    SetUpButton(resumeBtn_, "Resume");
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestSetImageAnimatorSrc005()
+{
+    setImageBtn_ = new UILabelButton();
+    SetUpButton(setImageBtn_, "设置图片");
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestSetTickOfUpdate006()
+{
+    setSpeedBtn_ = new UILabelButton();
+    SetUpButton(setSpeedBtn_, "设置速度");
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestSetSizeFixed007()
+{
+    fixedBtn_ = new UILabelButton();
+    SetUpButton(fixedBtn_, "图片大小固定");
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestSetRepeat008()
+{
+    repeatBtn_ = new UILabelButton();
+    noRepeatBtn_ = new UILabelButton();
+    SetUpButton(repeatBtn_, "循环播放");
+    SetUpButton(noRepeatBtn_, "播放一次 ");
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestSetReverse009()
+{
+    reverseOrderBtn_ = new UILabelButton();
+    positiveOrderBtn_ = new UILabelButton();
+    SetUpButton(reverseOrderBtn_, "逆序播放");
+    SetUpButton(positiveOrderBtn_, "正序播放");
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestSetAnimatorStopListener010()
+{
+    listenerBtn_ = new UILabelButton();
+    SetUpButton(listenerBtn_, "播放结束监听");
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestSetRepeatTimes011()
+{
+    repeatTimesBtn_ = new UILabelButton();
+    SetUpButton(repeatTimesBtn_, "播放次数+");
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestSetFillModeTrueForward012()
+{
+    fillModeTrueForwardBtn_ = new UILabelButton();
+    SetUpButton(fillModeTrueForwardBtn_, "fillMode true 正播");
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestSetFillModeTrueBackward013()
+{
+    fillModeTrueBackwardBtn_ = new UILabelButton();
+    SetUpButton(fillModeTrueBackwardBtn_, "fillMode true 逆播");
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestSetFillModeFalseForward014()
+{
+    fillModeFalseForwardBtn_ = new UILabelButton();
+    SetUpButton(fillModeFalseForwardBtn_, "fillMode false 正播");
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestSetFillModeFalseBackward015()
+{
+    fillModeFalseBackwardBtn_ = new UILabelButton();
+    SetUpButton(fillModeFalseBackwardBtn_, "fillMode false 逆播");
+}
+
+void UITestImageAnimator::UIKitImageAnimatorTestSetImageInfo016()
+{
+    setImageInfoBtn_ = new UILabelButton();
+    SetUpButton(setImageInfoBtn_, "设置ImageInfo");
+}
+void UITestImageAnimator::SubEvent(const UIView& view)
+{
+    if (&view == startBtn_) {
+        imageAnimator_->Start();
+    } else if (&view == stopBtn_) {
+        imageAnimator_->Stop();
+    } else if (&view == pauseBtn_) {
+        imageAnimator_->Pause();
+    } else if (&view == resumeBtn_) {
+        imageAnimator_->Resume();
+    } else if (&view == setImageBtn_) {
+        imageAnimator_->Stop();
+        imageAnimator_->SetImageAnimatorSrc(g_imageAnimatorInfo2, 4); // 4: the number of images
+        imageAnimator_->Start();
+    } else if (&view == setSpeedBtn_) {
+        imageAnimator_->Stop();
+        imageAnimator_->SetTimeOfUpdate(10); // 10: set time of update
+        imageAnimator_->Start();
+    } else if (&view == fixedBtn_) {
+        imageAnimator_->SetSizeFixed(true);
+        imageAnimator_->SetPosition(50, 50, 200, 200); // 50 : offset 50 : offset 200 : offset 200 :offset
+    } else if (&view == repeatBtn_) {
+        imageAnimator_->Stop();
+        imageAnimator_->SetRepeat(true);
+        imageAnimator_->Start();
+    } else if (&view == noRepeatBtn_) {
+        imageAnimator_->Stop();
+        imageAnimator_->SetRepeat(false);
+        imageAnimator_->Start();
+    } else if (&view == reverseOrderBtn_) {
+        imageAnimator_->Stop();
+        imageAnimator_->SetReverse(true);
+        imageAnimator_->Start();
+    } else if (&view == positiveOrderBtn_) {
+        imageAnimator_->Stop();
+        imageAnimator_->SetReverse(false);
+        imageAnimator_->Start();
+    } else if (&view == listenerBtn_) {
+        imageAnimator_->SetAnimatorStopListener(listener_);
+    } else if (&view == repeatTimesBtn_) {
+        imageAnimator_->Stop();
+        imageAnimator_->SetRepeatTimes(imageAnimator_->GetRepeatTimes() + 1);
+        imageAnimator_->Start();
+    }
+}
+
+bool UITestImageAnimator::OnClick(UIView& view, const ClickEvent& event)
+{
+    SubEvent(view);
+    if (&view == fillModeTrueForwardBtn_) {
+        imageAnimator_->Stop();
+        imageAnimator_->SetFillMode(true);
+        imageAnimator_->SetRepeat(false);
+        imageAnimator_->SetReverse(false);
+        imageAnimator_->Start();
+    } else if (&view == fillModeTrueBackwardBtn_) {
+        imageAnimator_->Stop();
+        imageAnimator_->SetFillMode(true);
+        imageAnimator_->SetRepeat(false);
+        imageAnimator_->SetReverse(true);
+        imageAnimator_->Start();
+    } else if (&view == fillModeFalseForwardBtn_) {
+        imageAnimator_->Stop();
+        imageAnimator_->SetFillMode(false);
+        imageAnimator_->SetRepeat(false);
+        imageAnimator_->SetReverse(false);
+        imageAnimator_->Start();
+    } else if (&view == fillModeFalseBackwardBtn_) {
+        imageAnimator_->Stop();
+        imageAnimator_->SetFillMode(false);
+        imageAnimator_->SetRepeat(false);
+        imageAnimator_->SetReverse(true);
+        imageAnimator_->Start();
+    } else if (&view == setImageInfoBtn_) {
+        imageAnimator_->Stop();
+        imageAnimator_->SetImageAnimatorSrc(imageAnimatorImageInfo_, 3); // 3: the number of images
+        imageAnimator_->Start();
+    }
+    return true;
+}
+} // namespace OHOS
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_image_animator/ui_test_image_animator.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_image_animator/ui_test_image_animator.h
new file mode 100644 (file)
index 0000000..3674bb3
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_IMAGE_ANIMATOR_H
+#define UI_TEST_IMAGE_ANIMATOR_H
+
+#include "components/ui_image_animator.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "layout/grid_layout.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class TestAnimatorStopListener : public UIImageAnimatorView::AnimatorStopListener {
+public:
+    explicit TestAnimatorStopListener(UIViewGroup* viewGroup) : viewGroup_(viewGroup)
+    {
+        viewGroup_ = viewGroup;
+    }
+    ~TestAnimatorStopListener() {}
+
+    void Init()
+    {
+        label_ = new UILabel();
+        viewGroup_->Add(label_);
+        label_->SetPosition(24, 50, 200, 29); // 24: position x 50: position y 200: width 29: height
+        label_->SetText("OnAnimatorStop");
+        label_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        label_->SetStyle(STYLE_TEXT_COLOR, Color::Black().full);
+        label_->SetStyle(STYLE_BACKGROUND_COLOR, Color::White().full);
+        label_->SetStyle(STYLE_BACKGROUND_OPA, 255); // 255: value
+        label_->SetVisible(false);
+    }
+
+    void OnAnimatorStop(UIView& view) override
+    {
+        label_->SetVisible(true);
+        label_->Invalidate();
+    }
+private:
+    UILabel* label_ = nullptr;
+    UIViewGroup* viewGroup_ = nullptr;
+};
+
+class UITestImageAnimator : public UITest, public UIView::OnClickListener {
+public:
+    UITestImageAnimator() {}
+    ~UITestImageAnimator() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    void SetUpButton(UILabelButton* btn, const char* title);
+    void SubEvent(const UIView& view);
+
+    bool OnClick(UIView& view, const ClickEvent& event) override;
+
+    void UIKitImageAnimatorTestStart001();
+    void UIKitImageAnimatorTestStop002();
+    void UIKitImageAnimatorTestPause003();
+    void UIKitImageAnimatorTestResume004();
+    void UIKitImageAnimatorTestSetImageAnimatorSrc005();
+    void UIKitImageAnimatorTestSetTickOfUpdate006();
+    void UIKitImageAnimatorTestSetSizeFixed007();
+    void UIKitImageAnimatorTestSetRepeat008();
+    void UIKitImageAnimatorTestSetReverse009();
+    void UIKitImageAnimatorTestSetAnimatorStopListener010();
+    void UIKitImageAnimatorTestSetRepeatTimes011();
+    void UIKitImageAnimatorTestSetFillModeTrueForward012();
+    void UIKitImageAnimatorTestSetFillModeTrueBackward013();
+    void UIKitImageAnimatorTestSetFillModeFalseForward014();
+    void UIKitImageAnimatorTestSetFillModeFalseBackward015();
+    void UIKitImageAnimatorTestSetImageInfo016();
+
+private:
+    void InitImageInfo();
+    void InitImageInfo1();
+    void InitImageInfo2();
+    void InitImageInfo3();
+    UIScrollView* container_ = nullptr;
+    GridLayout* layout_ = nullptr;
+    UIImageAnimatorView* imageAnimator_ = nullptr;
+    TestAnimatorStopListener* listener_ = nullptr;
+
+    UILabelButton* startBtn_ = nullptr;
+    UILabelButton* stopBtn_ = nullptr;
+    UILabelButton* pauseBtn_ = nullptr;
+    UILabelButton* resumeBtn_ = nullptr;
+    UILabelButton* setImageBtn_ = nullptr;
+    UILabelButton* setSpeedBtn_ = nullptr;
+    UILabelButton* fixedBtn_ = nullptr;
+    UILabelButton* repeatBtn_ = nullptr;
+    UILabelButton* noRepeatBtn_ = nullptr;
+    UILabelButton* reverseOrderBtn_ = nullptr;
+    UILabelButton* positiveOrderBtn_ = nullptr;
+    UILabelButton* listenerBtn_ = nullptr;
+    UILabelButton* repeatTimesBtn_ = nullptr;
+    UILabelButton* fillModeTrueForwardBtn_ = nullptr;
+    UILabelButton* fillModeTrueBackwardBtn_ = nullptr;
+    UILabelButton* fillModeFalseForwardBtn_ = nullptr;
+    UILabelButton* fillModeFalseBackwardBtn_ = nullptr;
+    UILabelButton* setImageInfoBtn_ = nullptr;
+
+    ImageInfo* imageInfo1_ = nullptr;
+    ImageInfo* imageInfo2_ = nullptr;
+    ImageInfo* imageInfo3_ = nullptr;
+    ImageAnimatorInfo imageAnimatorImageInfo_[3] = { 0 };
+};
+} // namespace OHOS
+#endif // UI_TEST_IMAGE_ANIMATOR_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_input_event/ui_test_input_event.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_input_event/ui_test_input_event.cpp
new file mode 100644 (file)
index 0000000..c7e7fb1
--- /dev/null
@@ -0,0 +1,630 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_input_event.h"
+
+#include "common/screen.h"
+#include "components/root_view.h"
+
+namespace OHOS {
+namespace {
+const int16_t INIT_H = 90;
+const int16_t ITEM_H = 50;
+const int16_t TEXT_H = 29;
+const int16_t TEXT_W = 250;
+const int16_t TEST_VIEW_H = 40;
+const int16_t TEST_VIEW_W = 40;
+const int16_t GAP = 5;
+const int16_t TEST_VIEW_GAP = 80;
+} // namespace
+
+class TestView : public UIView {
+public:
+    TestView() {}
+    virtual ~TestView() {}
+    bool OnLongPressEvent(const LongPressEvent& event) override
+    {
+        if (label_ != nullptr) {
+            label_->SetText("long press!");
+            label_->Invalidate();
+        }
+        return UIView::OnLongPressEvent(event);
+    }
+
+    bool OnDragEvent(const DragEvent& event) override
+    {
+        if (label_ != nullptr) {
+            label_->SetText("drag!");
+            label_->Invalidate();
+        }
+        return UIView::OnDragEvent(event);
+    }
+
+    void SetSentence(const char* sentence)
+    {
+        sentence_ = sentence;
+    }
+
+    bool OnClickEvent(const ClickEvent& event) override
+    {
+        if (label_ != nullptr) {
+            label_->SetText(sentence_);
+            label_->Invalidate();
+        }
+        return UIView::OnClickEvent(event);
+    }
+
+    bool OnPressEvent(const PressEvent& event) override
+    {
+        if (label_ != nullptr) {
+            label_->SetText("press!");
+            label_->Invalidate();
+        }
+        return UIView::OnPressEvent(event);
+    }
+
+    bool OnReleaseEvent(const ReleaseEvent& event) override
+    {
+        if (label_ != nullptr) {
+            label_->SetText("release!");
+            label_->Invalidate();
+        }
+        return UIView::OnReleaseEvent(event);
+    }
+
+    bool OnCancelEvent(const CancelEvent& event) override
+    {
+        if (label_ != nullptr) {
+            label_->SetText("cancel!");
+            label_->Invalidate();
+        }
+        return UIView::OnCancelEvent(event);
+    }
+
+    void SetLabel(UILabel* label)
+    {
+        label_ = label;
+    }
+
+    void SetLabel2(UILabel* label)
+    {
+        label2_ = label;
+    }
+
+private:
+    UILabel* label_ = nullptr;
+    UILabel* label2_ = nullptr;
+    const char* sentence_ = "click";
+};
+
+class TestUIScrollView : public UIScrollView {
+public:
+    TestUIScrollView() {}
+    virtual ~TestUIScrollView() {}
+    bool OnLongPressEvent(const LongPressEvent& event) override
+    {
+        if (label_ != nullptr) {
+            label_->SetText("long press!");
+            label_->Invalidate();
+        }
+        return UIView::OnLongPressEvent(event);
+    }
+
+    bool OnDragEvent(const DragEvent& event) override
+    {
+        if (label_ != nullptr) {
+            label_->SetText("drag!");
+            label_->Invalidate();
+        }
+        return UIScrollView::OnDragEvent(event);
+    }
+
+    bool OnDragStartEvent(const DragEvent& event) override
+    {
+        if (label_ != nullptr) {
+            label_->SetText("drag start!");
+            label_->Invalidate();
+        }
+        return UIScrollView::OnDragStartEvent(event);
+    }
+
+    bool OnDragEndEvent(const DragEvent& event) override
+    {
+        if (label_ != nullptr) {
+            label_->SetText("drag end!");
+            label_->Invalidate();
+        }
+        return UIScrollView::OnDragEndEvent(event);
+    }
+
+    void SetSentence(const char* sentence)
+    {
+        sentence_ = sentence;
+    }
+
+    bool OnClickEvent(const ClickEvent& event) override
+    {
+        if (label_ != nullptr) {
+            label_->SetText(sentence_);
+            label_->Invalidate();
+        }
+        return UIView::OnClickEvent(event);
+    }
+
+    bool OnPressEvent(const PressEvent& event) override
+    {
+        if (label_ != nullptr) {
+            label_->SetText("press!");
+            label_->Invalidate();
+        }
+        return UIView::OnPressEvent(event);
+    }
+
+    bool OnReleaseEvent(const ReleaseEvent& event) override
+    {
+        if (label_ != nullptr) {
+            label_->SetText("release!");
+            label_->Invalidate();
+        }
+        return UIView::OnReleaseEvent(event);
+    }
+
+    bool OnCancelEvent(const CancelEvent& event) override
+    {
+        if (label_ != nullptr) {
+            label_->SetText("cancel!");
+            label_->Invalidate();
+        }
+        return UIView::OnCancelEvent(event);
+    }
+
+    void SetLabel(UILabel* label)
+    {
+        label_ = label;
+    }
+
+private:
+    UILabel* label_ = nullptr;
+    const char* sentence_ = "click";
+};
+
+void UITestInputEvent::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        container_->SetHorizontalScrollState(false);
+    }
+    positionX_ = 48; // 48: position x
+    positionY_ = 0;
+}
+
+void DeleteChildrenAndListener(UIView* view)
+{
+    if (view == nullptr) {
+        return;
+    }
+    while (view != nullptr) {
+        UIView* tempView = view;
+        view = view->GetNextSibling();
+        if (tempView->IsViewGroup()) {
+            DeleteChildrenAndListener(static_cast<UIViewGroup*>(tempView)->GetChildrenHead());
+        }
+        if (tempView->GetParent()) {
+            static_cast<UIViewGroup*>(tempView->GetParent())->Remove(tempView);
+        }
+
+        if (tempView->GetOnClickListener()) {
+            delete tempView->GetOnClickListener();
+        }
+        if (tempView->GetOnDragListener()) {
+            delete tempView->GetOnDragListener();
+        }
+        if (tempView->GetOnLongPressListener()) {
+            delete tempView->GetOnLongPressListener();
+        }
+        if (tempView->GetTouchListener()) {
+            delete tempView->GetTouchListener();
+        }
+
+        delete tempView;
+    }
+}
+
+void UITestInputEvent::TearDown()
+{
+    DeleteChildrenAndListener(container_);
+    container_ = nullptr;
+    RootView::GetInstance()->ClearOnKeyActListener();
+    if (keyListener_ != nullptr) {
+        delete keyListener_;
+        keyListener_ = nullptr;
+    }
+}
+
+const UIView* UITestInputEvent::GetTestView()
+{
+    UIKitPointerInputTestDispatchSimpleEvent001();
+    UIKitPointerInputTestDispatchSimpleEvent002();
+    UIKitPointerInputTestDispatchDragEven001();
+    UIKitPointerInputTestDispatchDragEven002();
+    UIKitPointerInputTestDispatchDragEven003();
+    UIKitPointerInputTestDispatchKeyEvent001();
+    UIKitPointerInputTestDispatchInVisibleEvent001();
+    UIKitPointerInputTestDispatchBubble001();
+    UIKitPointerInputTestDispatchBubble002();
+    UIKitPointerInputTestDispatchBubble003();
+    UIKitPointerInputTestDispatchBubble004();
+    UIKitPointerInputTestDispatchBubble005();
+    UIKitPointerInputTestDispatchBubble006();
+    UIKitPointerInputTestDispatchBubble007();
+    UIKitPointerInputTestDispatchBubble008();
+    UIKitPointerInputTestDispatchBubble009();
+    UIKitPointerInputTestDispatchBubble010();
+    return container_;
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchSimpleEvent001()
+{
+    UILabel* label = new UILabel();
+    container_->Add(label);
+    // 2: half Screen width
+    label->SetPosition(positionX_, positionY_, Screen::GetInstance().GetWidth() / 2, INIT_H);
+    label->SetText("");
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    positionY_ += (INIT_H + GAP);
+
+    InnerTest("可点击对象事件测试 ", true, false, false);
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchSimpleEvent002()
+{
+    InnerTest("不可点击对象事件测试 ", false, false, false);
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchDragEven001()
+{
+    InnerTest("可点击可拖拽dragparent测试 ", true, true, true);
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchDragEven002()
+{
+    InnerTest("可点击可拖拽非dragparent测试 ", true, true, false);
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchDragEven003()
+{
+    InnerTest("不可点击可拖拽测试 ", false, true, false);
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchBubble001()
+{
+    positionY_ = 0;
+    UILabel* label = new UILabel();
+    container_->Add(label);
+    // 2: half Screen width
+    label->SetPosition(positionX_, positionY_, Screen::GetInstance().GetWidth() / 2, INIT_H);
+    label->SetText("");
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    positionY_ += (INIT_H + GAP);
+    InnerBubbleTest("可点击有监听事件不消费冒泡测试 ", true, true, true, false);
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchBubble002()
+{
+    InnerBubbleTest("可点击有监听事件消费冒泡测试 ", true, true, true, true);
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchBubble003()
+{
+    InnerBubbleTest("可点击无监听事件不消费冒泡测试 ", true, true, false, false);
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchBubble004()
+{
+    InnerBubbleTest("不可点击有监听事件消费冒泡测试 ", false, false, true, true);
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchBubble005()
+{
+    InnerBubbleDragTest("子父可拖拽有监听事件不消费冒泡测试 ", true, true, true, false);
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchBubble006()
+{
+    InnerBubbleDragTest("子父可拖拽有监听事件消费冒泡测试 ", true, true, true, true);
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchBubble007()
+{
+    InnerBubbleDragTest("子父可拖拽无监听事件消费冒泡测试 ", true, true, false, true);
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchBubble008()
+{
+    InnerBubbleDragTest("子父不可拖拽有监听事件消费冒泡测试 ", false, false, true, true);
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchBubble009()
+{
+    InnerBubbleDragTest("子不可拖拽父可拖拽有监听事件消费冒泡测试 ", false, true, true, true);
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchBubble010()
+{
+    InnerBubbleDragTest("子不可拖拽父可拖拽有监听事件不消费冒泡测试 ", false, true, true, false);
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchKeyEvent001()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* uiViewGroup = new UIViewGroup();
+        // 2: half of screen width;
+        uiViewGroup->SetPosition(
+            TEXT_DISTANCE_TO_LEFT_SIDE, positionY_,
+            (Screen::GetInstance().GetWidth() / 2 - TEXT_DISTANCE_TO_LEFT_SIDE), // 2: half of screen width;
+            128);                                                                // 128: height
+        container_->Add(uiViewGroup);
+
+        UILabel* label = new UILabel();
+        uiViewGroup->Add(label);
+        // 2: half of screen width;
+        label->SetPosition(0, 0, Screen::GetInstance().GetWidth() / 2, TEXT_H);
+        label->SetText("物理按键事件测试 ");
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        positionY_ += (TEXT_H + GAP);
+        UILabel* label1 = new UILabel();
+        uiViewGroup->Add(label1);
+        label1->SetPosition(0, TEXT_H + GAP, TEXT_W, TEXT_H);
+        label1->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        if (keyListener_ == nullptr) {
+            keyListener_ = new TestKeyInputListener2(label1);
+        }
+        RootView::GetInstance()->SetOnKeyActListener(keyListener_);
+        positionY_ += ITEM_H;
+    }
+}
+
+void UITestInputEvent::UIKitPointerInputTestDispatchInVisibleEvent001()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* uiViewGroup = new UIViewGroup();
+        // 2: half of screen width; 36: decrease x-coordinate; 90: y-coordinate
+        uiViewGroup->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, positionY_, 480, 128); // 480: width; 128: height
+        container_->Add(uiViewGroup);
+        UILabel* label = new UILabel();
+        uiViewGroup->Add(label);
+        // 2: half of screen width;
+        label->SetPosition(0, 0, Screen::GetInstance().GetWidth() / 2, TEXT_H);
+        label->SetText("不可见对象事件传递测试 ");
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        positionY_ = 0;
+        positionY_ += (TEXT_H + GAP * 2); // 2: double GAP
+        UIViewGroup* group1 = new UIViewGroup();
+        uiViewGroup->Add(group1);
+        // 20: increase width 20: increase  height
+        group1->SetPosition(positionX_, positionY_, TEST_VIEW_W + 20, TEST_VIEW_H + 20);
+        group1->SetStyle(STYLE_BACKGROUND_COLOR, Color::White().full);
+        group1->SetVisible(false);
+        TestView* testView = new TestView();
+        group1->Add(testView);
+        testView->SetPosition(5, 5, TEST_VIEW_W, TEST_VIEW_H); // 5: position x 5:position y
+        testView->SetStyle(STYLE_BACKGROUND_COLOR, Color::Blue().full);
+        testView->SetTouchable(true);
+        testView->SetSentence("Click From test 0!");
+        UIViewGroup* group2 = new UIViewGroup();
+        uiViewGroup->Add(group2);
+        // 20: increase width 20: increase  height
+        group2->SetPosition(0, positionY_, TEST_VIEW_W + 20, TEST_VIEW_H + 20);
+        group2->SetStyle(STYLE_BACKGROUND_COLOR, Color::White().full);
+        TestView* testView1 = new TestView();
+        group2->Add(testView1);
+        testView1->SetPosition(5, 5, TEST_VIEW_W, TEST_VIEW_H); // 5: position x 5:position y
+        testView1->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+        testView1->SetTouchable(true);
+        testView1->SetSentence("Click From test 1!");
+        UILabel* label1 = new UILabel();
+        uiViewGroup->Add(label1);
+        // 50: increase width; 2:double GAP
+        label1->SetPosition(positionX_ + 50, positionY_ + 2 * GAP, TEXT_W, TEXT_H);
+        label1->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        testView->SetLabel(label1);
+        testView1->SetLabel(label1);
+        positionY_ += ITEM_H;
+    }
+}
+
+void UITestInputEvent::InnerTest(const char* title, bool touchable, bool draggable, bool dragParent)
+{
+    if (container_ != nullptr) {
+        UILabel* label = new UILabel();
+        container_->Add(label);
+        // 2: half Screen width
+        label->SetPosition(positionX_, positionY_, Screen::GetInstance().GetWidth() / 2, TEXT_H);
+        label->SetText(title);
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        positionY_ += (TEXT_H + GAP);
+        auto testView = new TestView();
+        container_->Add(testView);
+        testView->SetPosition(positionX_, positionY_, TEST_VIEW_W, TEST_VIEW_H);
+        testView->SetStyle(STYLE_BACKGROUND_COLOR, Color::Blue().full);
+        testView->SetTouchable(touchable);
+        testView->SetDraggable(draggable);
+        testView->SetDragParentInstead(dragParent);
+        UILabel* label1 = new UILabel();
+        container_->Add(label1);
+        label1->SetPosition(positionX_ + TEST_VIEW_GAP, positionY_ + 2 * GAP, TEXT_W, TEXT_H); // 2: double GAP
+        label1->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        testView->SetLabel(label1);
+        positionY_ += ITEM_H;
+    }
+}
+
+void UITestInputEvent::InnerBubbleTest(const char* title,
+                                       bool touchable,
+                                       bool draggable,
+                                       bool hasListener,
+                                       bool isBubble)
+{
+    if (container_ != nullptr) {
+        UILabel* label = new UILabel();
+        container_->Add(label);
+        label->SetPosition((Screen::GetInstance().GetWidth() / 2 + TEXT_DISTANCE_TO_LEFT_SIDE), // 2: half screen width
+                           positionY_,
+                           (Screen::GetInstance().GetWidth() / 2 - TEXT_DISTANCE_TO_LEFT_SIDE), // 2: half screen width
+                           TEXT_H);
+        label->SetText(title);
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        positionY_ += (TEXT_H + GAP);
+
+        OHOS::UIScrollView* parentContainer = new UIScrollView();
+        // 2: half screen width
+        parentContainer->SetPosition(Screen::GetInstance().GetWidth() / 2 + TEXT_DISTANCE_TO_LEFT_SIDE, positionY_,
+                                     Screen::GetInstance().GetWidth() - TEXT_DISTANCE_TO_LEFT_SIDE, ITEM_H);
+        container_->Add(parentContainer);
+        TestView* testView = new TestView();
+        parentContainer->Add(testView);
+        testView->SetPosition(0, 0, TEST_VIEW_W, TEST_VIEW_H);
+        testView->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+        testView->SetTouchable(touchable);
+        testView->SetDraggable(draggable);
+        testView->SetDragParentInstead(true);
+        UILabel* label1 = new UILabel();
+        parentContainer->Add(label1);
+        label1->SetPosition(positionX_ + TEST_VIEW_GAP, 2 * GAP, TEXT_W, TEXT_H); // 2: tow gap
+        label1->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        testView->SetLabel(label1);
+
+        UILabel* label2 = new UILabel();
+        parentContainer->Add(label2);
+        label2->SetPosition(positionX_ + 2 * TEST_VIEW_GAP, 2 * GAP, TEXT_W, TEXT_H); // 2: tow gap
+        label2->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        testView->SetLabel2(label2);
+
+        if (hasListener) {
+            UIView::OnClickListener* clickListenerParent =
+                new TestOnClickListener(label2, "l-parent click", isBubble);
+            UIView::OnClickListener* clickListenerChild =
+                new TestOnClickListener(label1, "l-click", isBubble);
+            testView->SetOnClickListener(clickListenerChild);
+            parentContainer->SetOnClickListener(clickListenerParent);
+
+            UIView::OnLongPressListener* longTouchListenerParent =
+                new TestOnLongPressListener(label2, "l-parent long press", isBubble);
+            UIView::OnLongPressListener* longTouchListenerChild =
+                new TestOnLongPressListener(label1, "l-long press", isBubble);
+            testView->SetOnLongPressListener(longTouchListenerChild);
+            parentContainer->SetOnLongPressListener(longTouchListenerParent);
+
+            UIView::OnTouchListener* touchListenerParent = new TestOnTouchListener(
+                label2, "l-parent press", "l-parent release",
+                "l-parent cancel", isBubble);
+            UIView::OnTouchListener* touchListenerChild =
+                new TestOnTouchListener(label1, "l-press", "l-release", "l-cancel", isBubble);
+            testView->SetOnTouchListener(touchListenerChild);
+            parentContainer->SetOnTouchListener(touchListenerParent);
+        }
+
+        positionY_ += ITEM_H;
+    }
+}
+void UITestInputEvent::InitScrollView(UIScrollView* parentScroll, const char* title, bool parentDraggable)
+{
+    int itemH1 = ITEM_H * 2; // 2 times of ITEM_H
+    int itemH2 = itemH1 + ITEM_H;
+    int itemH3 = itemH2 + ITEM_H;
+    int halfScreenWith = Screen::GetInstance().GetWidth() / 2; // 2: half screen width
+    UILabel* label = new UILabel();
+    container_->Add(label);
+    // 2: half screen width
+    label->SetPosition(halfScreenWith + TEXT_DISTANCE_TO_LEFT_SIDE, positionY_,
+        halfScreenWith - TEXT_DISTANCE_TO_LEFT_SIDE, TEXT_H);
+    label->SetText(title);
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    positionY_ += (TEXT_H + GAP);
+    parentScroll->SetStyle(STYLE_BACKGROUND_COLOR, Color::Blue().full);
+    parentScroll->SetPosition(halfScreenWith + TEXT_DISTANCE_TO_LEFT_SIDE, positionY_, itemH1, itemH1);
+    parentScroll->SetThrowDrag(parentDraggable);
+    parentScroll->SetDraggable(parentDraggable);
+    container_->Add(parentScroll);
+}
+
+void UITestInputEvent::InnerBubbleDragTest(const char* title,
+                                           bool childDraggable,
+                                           bool parentDraggable,
+                                           bool hasListener,
+                                           bool isBubble)
+{
+    int itemH1 = ITEM_H * 2; // 2 times of ITEM_H
+    int itemH2 = itemH1 + ITEM_H;
+    int itemH3 = itemH2 + ITEM_H;
+    int halfScreenWith = Screen::GetInstance().GetWidth() / 2; // 2: half screen width
+    int offset = 30;                                           // 40 pixel offset
+
+    if (container_ != nullptr) {
+        OHOS::TestUIScrollView* parentScroll = new TestUIScrollView();
+        InitScrollView(parentScroll, title, parentDraggable);
+        
+        OHOS::TestUIScrollView* childScroll = new TestUIScrollView();
+        childScroll->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+        childScroll->SetPosition(offset, offset, itemH2, itemH2);
+        childScroll->SetThrowDrag(childDraggable);
+        childScroll->SetDraggable(childDraggable);
+        parentScroll->Add(childScroll);
+
+        UILabelButton* button1 = new UILabelButton();
+        button1->SetStyle(STYLE_BACKGROUND_COLOR, Color::Yellow().full);
+        button1->SetText("button1");
+        button1->SetPosition(offset, offset, itemH3 * 2, itemH3); // 2: tow width
+        childScroll->Add(button1);
+
+        UILabel* label1 = new UILabel();
+        container_->Add(label1);
+        label1->SetPosition(itemH3 + offset + halfScreenWith, positionY_ + 2 * GAP, TEXT_W, TEXT_H); // 2: tow gap
+        label1->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        childScroll->SetLabel(label1);
+
+        UILabel* label2 = new UILabel();
+        container_->Add(label2);
+        label2->SetPosition(itemH3 + offset + halfScreenWith, positionY_ + 6 * GAP, TEXT_W, TEXT_H); // 6: tow gap
+        label2->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        parentScroll->SetLabel(label2);
+
+        if (hasListener) {
+            UIView::OnClickListener* clickListenerParent =
+                new TestOnClickListener(label2, "l-parent click", isBubble);
+            UIView::OnClickListener* clickListenerChild =
+                new TestOnClickListener(label1, "l-click", isBubble);
+            childScroll->SetOnClickListener(clickListenerChild);
+            parentScroll->SetOnClickListener(clickListenerParent);
+
+            UIView::OnLongPressListener* longTouchListenerParent =
+                new TestOnLongPressListener(label2, "l-parent long press", isBubble);
+            UIView::OnLongPressListener* longTouchListenerChild =
+                new TestOnLongPressListener(label1, "l-long press", isBubble);
+            childScroll->SetOnLongPressListener(longTouchListenerChild);
+            parentScroll->SetOnLongPressListener(longTouchListenerParent);
+
+            UIView::OnTouchListener* touchListenerParent = new TestOnTouchListener(
+                label2, "l-parent press", "l-parent release",
+                "l-parent cancel", isBubble);
+            UIView::OnTouchListener* touchListenerChild =
+                new TestOnTouchListener(label1, "l-press", "l-release", "l-cancel", isBubble);
+            childScroll->SetOnTouchListener(touchListenerChild);
+            parentScroll->SetOnTouchListener(touchListenerParent);
+
+            UIView::OnDragListener* dragListenerParent = new TestOnDragListener(
+                label2, "l-dragStart parent", "l-drag parent", "l-dragEnd parent", isBubble);
+            UIView::OnDragListener* dragListenerChild =
+                new TestOnDragListener(label1, "l-dragStart", "l-drag", "l-dragEnd", isBubble);
+            childScroll->SetOnDragListener(dragListenerChild);
+            parentScroll->SetOnDragListener(dragListenerParent);
+        }
+        positionY_ += itemH1;
+    }
+}
+} // namespace OHOS
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_input_event/ui_test_input_event.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_input_event/ui_test_input_event.h
new file mode 100644 (file)
index 0000000..7c894da
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_INPUT_EVENT_H
+#define UI_TEST_INPUT_EVENT_H
+
+#include "components/root_view.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "dock/input_device.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class TestKeyInputListener2 : public RootView::OnKeyActListener {
+public:
+    explicit TestKeyInputListener2(UILabel* label) : label_(label) {}
+    virtual ~TestKeyInputListener2() {}
+    bool OnKeyAct(UIView& view, const KeyEvent& event) override
+    {
+        if (label_ == nullptr) {
+            return true;
+        }
+        switch (event.GetState()) {
+            case InputDevice::STATE_PRESS:
+                label_->SetText("key pressed!");
+                break;
+            case InputDevice::STATE_RELEASE:
+                label_->SetText("key released!");
+                break;
+            default:
+                label_->SetText("");
+                break;
+        }
+        label_->Invalidate();
+        return true;
+    }
+
+private:
+    UILabel* label_;
+};
+
+class TestOnClickListener : public UIView::OnClickListener {
+public:
+    explicit TestOnClickListener(UILabel* label, std::string sentence, bool isConsume)
+        : label_(label), sentence_(sentence), isConsume_(isConsume)
+    {
+    }
+    virtual ~TestOnClickListener() {}
+    virtual bool OnClick(UIView& view, const ClickEvent& event)
+    {
+        if (label_ != nullptr) {
+            label_->SetText(sentence_.c_str());
+            label_->Invalidate();
+        }
+        return isConsume_;
+    }
+
+private:
+    UILabel* label_;
+    std::string sentence_;
+    bool isConsume_;
+};
+
+class TestOnLongPressListener : public UIView::OnLongPressListener {
+public:
+    explicit TestOnLongPressListener(UILabel* label, std::string sentence, bool isConsume)
+        : label_(label), sentence_(sentence), isConsume_(isConsume)
+    {
+    }
+    virtual ~TestOnLongPressListener() {}
+    virtual bool OnLongPress(UIView& view, const LongPressEvent& event)
+    {
+        if (label_ != nullptr) {
+            label_->SetText(sentence_.c_str());
+            label_->Invalidate();
+        }
+        return isConsume_;
+    }
+
+private:
+    UILabel* label_;
+    std::string sentence_;
+    bool isConsume_;
+};
+
+class TestOnTouchListener : public UIView::OnTouchListener {
+public:
+    explicit TestOnTouchListener(UILabel* label, std::string strPress,
+        std::string strRelease, std::string strCancel, bool isConsume)
+        : label_(label), strPress_(strPress), strRelease_(strRelease), strCancel_(strCancel), isConsume_(isConsume)
+    {
+    }
+    virtual ~TestOnTouchListener() {}
+    virtual bool OnPress(UIView& view, const PressEvent& event)
+    {
+        if (label_ != nullptr) {
+            label_->SetText(strPress_.c_str());
+            label_->Invalidate();
+        }
+        return isConsume_;
+    }
+
+    virtual bool OnRelease(UIView& view, const ReleaseEvent& event)
+    {
+        if (label_ != nullptr) {
+            label_->SetText(strRelease_.c_str());
+            label_->Invalidate();
+        }
+        return isConsume_;
+    }
+
+    virtual bool OnCancel(UIView& view, const CancelEvent& event)
+    {
+        if (label_ != nullptr) {
+            label_->SetText(strCancel_.c_str());
+            label_->Invalidate();
+        }
+        return isConsume_;
+    }
+
+private:
+    UILabel* label_;
+    std::string strPress_;
+    std::string strRelease_;
+    std::string strCancel_;
+    bool isConsume_;
+};
+
+class TestOnDragListener : public UIView::OnDragListener {
+public:
+    explicit TestOnDragListener(UILabel* label, std::string strDragStart,
+        std::string strDrag, std::string strDragEnd, bool isConsume)
+        : label_(label), strDragStart_(strDragStart), strDrag_(strDrag), strDragEnd_(strDragEnd), isConsume_(isConsume)
+    {
+    }
+    virtual ~TestOnDragListener() {}
+    virtual bool OnDragStart(UIView& view, const DragEvent& event)
+    {
+        if (label_ != nullptr) {
+            label_->SetText(strDragStart_.c_str());
+            label_->Invalidate();
+        }
+        return isConsume_;
+    }
+
+    virtual bool OnDrag(UIView& view, const DragEvent& event)
+    {
+        if (label_ != nullptr) {
+            label_->SetText(strDrag_.c_str());
+            label_->Invalidate();
+        }
+        return isConsume_;
+    }
+
+    virtual bool OnDragEnd(UIView& view, const DragEvent& event)
+    {
+        if (label_ != nullptr) {
+            label_->SetText(strDragEnd_.c_str());
+            label_->Invalidate();
+        }
+        return isConsume_;
+    }
+
+private:
+    UILabel* label_;
+    std::string strDragStart_;
+    std::string strDrag_;
+    std::string strDragEnd_;
+    bool isConsume_;
+};
+
+class UITestInputEvent : public UITest {
+public:
+    UITestInputEvent() {}
+    ~UITestInputEvent() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    /**
+     * @brief Test if dispatch press\release\longpress\cancel event act normal when target is touchable
+     */
+    void UIKitPointerInputTestDispatchSimpleEvent001();
+    /**
+     * @brief Test if dispatch press\release\longpress\cancel\drag event act normal when target is untouchable
+     */
+    void UIKitPointerInputTestDispatchSimpleEvent002();
+    /**
+     * @brief Test if dispatch drag event act normal when target is touchable and draggable and drag parent instead.
+     */
+    void UIKitPointerInputTestDispatchDragEven001();
+    /**
+     * @brief Test if dispatch drag event act normal when target is touchable and draggable and not drag parent instead.
+     */
+    void UIKitPointerInputTestDispatchDragEven002();
+    /**
+     * @brief Test if dispatch drag event act normal when target is untouchable but draggable.
+     */
+    void UIKitPointerInputTestDispatchDragEven003();
+    /**
+     * @brief Test if dispatch drag event act normal when target is untouchable but draggable.
+     */
+    void UIKitPointerInputTestDispatchKeyEvent001();
+    /**
+     * @brief Test if dispatch drag event act normal when target is untouchable but draggable.
+     */
+    void UIKitPointerInputTestDispatchInVisibleEvent001();
+    /**
+     * @brief Test click, release or longClick event bubble act normal when both of parent and child is triggered.
+     */
+    void UIKitPointerInputTestDispatchBubble001();
+    /**
+     * @brief Test click, release or longClick event bubble act normal when child is triggered but and parent not.
+     */
+    void UIKitPointerInputTestDispatchBubble002();
+    /**
+     * @brief Test click, release or longClick event bubble act normal when child is triggered but and parent not.
+     */
+    void UIKitPointerInputTestDispatchBubble003();
+    /**
+     * @brief Test click, release or longClick event bubble act normal when parent is triggered but and child not.
+     */
+    void UIKitPointerInputTestDispatchBubble004();
+    /**
+     * @brief Test drag event bubble act normal when both of parent and child is triggered.
+     */
+    void UIKitPointerInputTestDispatchBubble005();
+    /**
+     * @brief Test drag event bubble act normal when child is triggered but and parent not.
+     */
+    void UIKitPointerInputTestDispatchBubble006();
+    /**
+     * @brief Test drag event bubble act normal when child is triggered but and parent not.
+     */
+    void UIKitPointerInputTestDispatchBubble007();
+    /**
+     * @brief Test drag event bubble act normal when both of parent and child is not triggered.
+     */
+    void UIKitPointerInputTestDispatchBubble008();
+    /**
+     * @brief Test drag event bubble act normal when parent is triggered but and child not.
+     */
+    void UIKitPointerInputTestDispatchBubble009();
+    /**
+     * @brief Test drag event bubble act normal when parent is triggered but and child not.
+     */
+    void UIKitPointerInputTestDispatchBubble010();
+
+private:
+    UIScrollView* container_ = nullptr;
+    TestKeyInputListener2* keyListener_ = nullptr;
+    void InnerTest(const char* title, bool touchable, bool draggable, bool dragParent);
+    void InnerBubbleTest(const char* title, bool touchable, bool draggable, bool hasListener, bool isBubble);
+    void InnerBubbleDragTest(const char* title,
+                             bool childDraggable,
+                             bool parentDraggable,
+                             bool hasListener,
+                             bool isBubble);
+    void InitScrollView(UIScrollView* parentScroll, const char* title, bool parentDraggable);
+};
+} // namespace OHOS
+#endif // UI_TEST_INPUT_EVENT_H
index f820733..3022866 100644 (file)
@@ -25,27 +25,35 @@ void UITestKaleidoscope::SetUp()
     container_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);
 
     imgInfo_ = ImageCacheManager::GetInstance().LoadSingleRes(RES_PATH"rabbit454.bin");
+    if (imgInfo_ == nullptr) {
+        delete container_;
+        container_ = nullptr;
+        return;
+    }
 
-    if ((Screen::GetInstance().GetWidth() == imgInfo_->header.width) &&
-        (Screen::GetInstance().GetHeight() == imgInfo_->header.height)) {
-        kaleidoscope_ = new UIKaleidoscopeView();
-        if (kaleidoscope_->SetSrc(imgInfo_) == false) {
-            return;
-        }
+    InitKaleidoscopeView();
 
-        container_->Add(kaleidoscope_);
-        kaleidoscope_->RequestFocus();
-        kaleidoscope_->SetRotateEventFactor(0.2f); // 0.2: rotate event factor
-        kaleidoscope_->SetRotateAnimatorValue(0.02f); // 0.02: rotate animator value
-        kaleidoscope_->StartRotateAnimator();
-        return;
+    if (switchBtn_ == nullptr) {
+        switchBtn_ = new UILabelButton();
     }
+    switchBtn_->Resize(100, 100); // 100: size
+    container_->Add(switchBtn_);
+    switchBtn_->LayoutCenterOfParent();
+    switchBtn_->SetOpaScale(OPA_TRANSPARENT);
+    switchBtn_->SetOnClickListener(this);
+}
 
-    kaleidoscopeUtils_ = new KaleidoscopeUtils();
+void UITestKaleidoscope::InitKaleidoscopeImg()
+{
+    if (kaleidoscopeUtils_ == nullptr) {
+        kaleidoscopeUtils_ = new KaleidoscopeUtils();
+    }
     kaleidoscopeUtils_->Init(imgInfo_, nullptr);
     ImageInfoExt* infoExt = kaleidoscopeUtils_->GetKaleidoscopeInfo();
 
-    img_ = new UIImageView();
+    if (img_ == nullptr) {
+        img_ = new UIImageView();
+    }
     img_->SetPosition(0, 0, Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight());
     img_->SetAutoEnable(false);
     img_->SetResizeMode(UIImageView::ImageResizeMode::FILL);
@@ -54,8 +62,25 @@ void UITestKaleidoscope::SetUp()
 
     if (utilsAnimator_ == nullptr) {
         utilsAnimator_ = new KaleidoscopeAnimator(kaleidoscopeUtils_, img_);
-        utilsAnimator_->Start();
     }
+    utilsAnimator_->Start();
+}
+
+void UITestKaleidoscope::InitKaleidoscopeView()
+{
+    if (kaleidoscope_ == nullptr) {
+        kaleidoscope_ = new UIKaleidoscopeView();
+    }
+
+    if (kaleidoscope_->SetSrc(imgInfo_) == false) {
+        return;
+    }
+
+    container_->Add(kaleidoscope_);
+    kaleidoscope_->RequestFocus();
+    kaleidoscope_->SetRotateEventFactor(0.2f); // 0.2: rotate event factor
+    kaleidoscope_->SetRotateAnimatorValue(0.02f); // 0.02: rotate animator value
+    kaleidoscope_->StartRotateAnimator();
 }
 
 void UITestKaleidoscope::TearDown()
@@ -76,6 +101,7 @@ void UITestKaleidoscope::TearDown()
     container_ = nullptr;
     imgInfo_ = nullptr;
     img_ = nullptr;
+    switchBtn_ = nullptr;
 
     if (kaleidoscopeUtils_ != nullptr) {
         delete kaleidoscopeUtils_;
@@ -84,6 +110,33 @@ void UITestKaleidoscope::TearDown()
     ImageCacheManager::GetInstance().UnloadSingleRes(RES_PATH"rabbit454.bin");
 }
 
+bool UITestKaleidoscope::OnClick(UIView& view, const ClickEvent& event)
+{
+    if (&view == switchBtn_) {
+        if (kaleidoscope_ != nullptr) {
+            container_->Remove(kaleidoscope_);
+            delete kaleidoscope_;
+            kaleidoscope_ = nullptr;
+
+            InitKaleidoscopeImg();
+            printf("Switch to Kaleidoscope View!");
+        } else {
+            utilsAnimator_->Stop();
+            container_->Remove(img_);
+            delete kaleidoscopeUtils_;
+            delete img_;
+            delete utilsAnimator_;
+            kaleidoscopeUtils_ = nullptr;
+            img_ = nullptr;
+            utilsAnimator_ = nullptr;
+
+            InitKaleidoscopeView();
+            printf("Switch to Kaleidoscope Img!");
+        }
+    }
+    return true;
+}
+
 const UIView* UITestKaleidoscope::GetTestView()
 {
     return container_;
index 15c3d93..903a2f1 100644 (file)
@@ -5,20 +5,22 @@
 #ifndef UI_TEST_KALEIDOSCOPE_H
 #define UI_TEST_KALEIDOSCOPE_H
 
-#include "ui_test.h"
-#include "components/ui_kaleidoscope_view.h"
-#include "components/kaleidoscope_utils.h"
 #include "animator/animator.h"
+#include "components/kaleidoscope_utils.h"
 #include "components/ui_image_view.h"
+#include "components/ui_kaleidoscope_view.h"
+#include "components/ui_label_button.h"
+#include "ui_test.h"
 
 namespace OHOS {
-class UITestKaleidoscope : public UITest {
+class UITestKaleidoscope : public UITest, public UIView::OnClickListener {
 public:
     UITestKaleidoscope() {}
     ~UITestKaleidoscope() override {}
     void SetUp() override;
     void TearDown() override;
     const UIView* GetTestView() override;
+    bool OnClick(UIView& view, const ClickEvent& event) override;
 
 private:
     class KaleidoscopeAnimator : public Animator, public AnimatorCallback {
@@ -32,8 +34,12 @@ private:
         KaleidoscopeUtils* kaleidoscopeUtils_;
     };
 
+    void InitKaleidoscopeView();
+    void InitKaleidoscopeImg();
+
     UIViewGroup* container_ = nullptr;
     ImageInfo* imgInfo_ = nullptr;
+    UILabelButton* switchBtn_ = nullptr;
 
     UIKaleidoscopeView* kaleidoscope_ = nullptr;
 
index 40b832a..9dc409e 100644 (file)
 #include "image_text_adapter.h"
 #include "components/ui_label_button.h"
 #include "components/ui_image_view.h"
+#include "components/ui_transform_button.h"
 #include "common/image_cache_manager.h"
 #include "securec.h"
 #include "graphic_config.h"
 #include "ui_list_fps_res.h"
 
 namespace OHOS {
-class ImageTextContainer : public UIViewGroup {
+class ImageTextContainer : public UITransformButton {
 public:
     ImageTextContainer() : image_(nullptr), label_(nullptr) {}
     ~ImageTextContainer() override
@@ -206,6 +207,9 @@ UIView* ImageTextAdapter::GetView(UIView* inView, int16_t index)
             return nullptr;
         }
         newView->Resize(width_, height_);
+        newView->SetStateForStyle(UITransformButton::TransformButtonState::PRESSED);
+        newView->SetStyle(STYLE_BACKGROUND_OPA, OPA_TRANSPARENT);
+        newView->SetStateForStyle(UITransformButton::TransformButtonState::RELEASED);
         newView->SetStyle(STYLE_BACKGROUND_OPA, OPA_TRANSPARENT);
         UIImageView* image = newView->GetImageView();
         image->SetAutoEnable(false);
index 6d0d7f1..e56bded 100644 (file)
@@ -44,16 +44,28 @@ void UITestLottie::SetUp()
     container_->Add(lottieView_);\r
 \r
     startBtn_ = new UILabelButton();\r
-    startBtn_->SetPosition(167, 400, 60, 50); // 167, 400, 60, 50: coordinate\r
+    startBtn_->SetPosition(87, 380, 70, 50); // 87, 380, 70, 50: coordinate\r
     startBtn_->SetOnClickListener(this);\r
     startBtn_->SetText("Start");\r
     container_->Add(startBtn_);\r
 \r
     switchBtn_ = new UILabelButton();\r
-    switchBtn_->SetPosition(237, 400, 60, 50); // 237, 400, 60, 50: coordinate\r
+    switchBtn_->SetPosition(157, 380, 70, 50); // 157, 380, 70, 50: coordinate\r
     switchBtn_->SetOnClickListener(this);\r
     switchBtn_->SetText("Switch");\r
     container_->Add(switchBtn_);\r
+\r
+    repeatBtn_ = new UILabelButton();\r
+    repeatBtn_->SetPosition(227, 380, 70, 50); // 227, 380, 70, 50: coordinate\r
+    repeatBtn_->SetOnClickListener(this);\r
+    repeatBtn_->SetText("Repeat");\r
+    container_->Add(repeatBtn_);\r
+\r
+    transformBtn_ = new UILabelButton();\r
+    transformBtn_->SetPosition(297, 380, 80, 50); // 297, 380, 80, 50: coordinate\r
+    transformBtn_->SetOnClickListener(this);\r
+    transformBtn_->SetText("Transform");\r
+    container_->Add(transformBtn_);\r
 }\r
 \r
 void UITestLottie::TearDown()\r
@@ -62,24 +74,40 @@ void UITestLottie::TearDown()
     lottieView_ = nullptr;\r
     startBtn_ = nullptr;\r
     switchBtn_ = nullptr;\r
+    repeatBtn_ = nullptr;\r
+    transformBtn_ = nullptr;\r
     container_ = nullptr;\r
 }\r
 \r
 bool UITestLottie::OnClick(UIView& view, const ClickEvent& event)\r
 {\r
+    if (lottieView_ == nullptr) {\r
+        return false;\r
+    }\r
     if (&view == startBtn_) {\r
-        if (lottieView_ != nullptr) {\r
-            lottieView_->Start();\r
+        lottieView_->Start();\r
+    } else if (&view == switchBtn_) {\r
+        lottieView_->SetSrc(g_filePath[fileIndex_]);\r
+        fileIndex_++;\r
+        if (fileIndex_ == FILE_MAX) {\r
+            fileIndex_ = 0;\r
         }\r
-    }\r
-    if (&view == switchBtn_) {\r
-        if (lottieView_ != nullptr) {\r
-            lottieView_->SetSrc(g_filePath[fileIndex_]);\r
-            fileIndex_++;\r
-            if (fileIndex_ == FILE_MAX) {\r
-                fileIndex_ = 0;\r
-            }\r
-            lottieView_->Start();\r
+        lottieView_->Start();\r
+    } else if (&view == repeatBtn_) {\r
+        bool repeat = !lottieView_->IsRepeat();\r
+        lottieView_->SetRepeat(repeat);\r
+        printf("SetRepeat to %d", repeat);\r
+    } else if (&view == transformBtn_) {\r
+        if (lottieView_->IsTransInvalid()) {\r
+            Vector2<float> pivot = {lottieView_->GetWidth() / 2.0f, lottieView_->GetHeight() / 2.0f}; // 2: divider\r
+            lottieView_->Rotate(90.0f, pivot);\r
+            lottieView_->Scale(Vector2<float>{0.5f, 0.5f}, pivot);\r
+            printf("Rotate 90 degree and scale by [0.5, 0.5]\n");\r
+        } else {\r
+            Matrix4<float> identity;\r
+            lottieView_->GetTransformMap().SetMatrix(identity);\r
+            lottieView_->Invalidate();\r
+            printf("Reset transformation!\n");\r
         }\r
     }\r
     return true;\r
index 97b1aa2..476cf2e 100644 (file)
@@ -27,6 +27,8 @@ private:
     UILottView* lottieView_ = nullptr;\r
     UILabelButton* startBtn_ = nullptr;\r
     UILabelButton* switchBtn_ = nullptr;\r
+    UILabelButton* repeatBtn_ = nullptr;\r
+    UILabelButton* transformBtn_ = nullptr;\r
     uint8_t fileIndex_ = 0;\r
 };\r
 }\r
index 3b84dad..0c64c19 100644 (file)
@@ -17,7 +17,7 @@
 #include "animator/easing_equation.h"\r
 \r
 namespace OHOS {\r
-const int8_t TEXT_ARRAY_LEN = 8;\r
+const int8_t TEXT_ARRAY_LEN = 24;\r
 const float MIN_BLUR_VALUE = 0.0f;\r
 const float MAX_BLUR_VALUE = 32.0f;\r
 const float BLUR_MODIFY_STEP = 0.4f;\r
@@ -33,9 +33,24 @@ void UITestMessage::SetUp()
     img->SetStyle(STYLE_IMAGE_OPA, OPA_OPAQUE);\r
     container_->Add(img);\r
 \r
+    under_ = new UILabel;\r
+    under_->SetPosition(158, 101, 140, 34); // 158: x, 101: y, 140: w, 34: h\r
+    under_->SetText("under");\r
+    under_->SetStyle(STYLE_BACKGROUND_COLOR, fgColors_[0]);\r
+    under_->SetStyle(STYLE_TEXT_COLOR, Color::Red().full);\r
+    under_->SetStyle(STYLE_TOP_BORDER_RADIUS, 20); // 20: top radius\r
+    under_->SetStyle(STYLE_BOTTOM_BORDER_RADIUS, 50); // 50: bottom radius\r
+    under_->SetStyle(STYLE_BACKGROUND_OPA, 200); // 200: Opacity for background.\r
+    under_->SetStyle(STYLE_BORDER_WIDTH, 10); // 10: border width\r
+    under_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 35); // 35: Font size.\r
+    under_->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);\r
+    container_->Add(under_);\r
+\r
     msgLabel_ = new UILabel();\r
-    msgLabel_->SetPosition(100, 80, 250, 70); // 100, 80, 250, 70: Left, right, width, height.\r
-    msgLabel_->SetText("Message: comes...");\r
+    msgLabel_->SetPosition(23, 80, 405, 201); // 23, 80, 405, 201: Left, right, width, height.\r
+    msgLabel_->SetText("Message: comes, please wait.................");\r
+    msgLabel_->SetMarqueeBlankNum(blankSapce_);\r
+    msgLabel_->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE);\r
     msgLabel_->SetStyle(STYLE_BACKGROUND_COLOR, 0xff505050);\r
     msgLabel_->SetStyle(STYLE_TEXT_COLOR, Color::White().full);\r
     msgLabel_->SetStyle(STYLE_BORDER_RADIUS, 20); // 20: Radius for label boarder.\r
@@ -44,27 +59,18 @@ void UITestMessage::SetUp()
     msgLabel_->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);\r
     container_->Add(msgLabel_);\r
 \r
-    add_ = new UILabelButton();\r
-    add_->SetPosition(70, 300, 100, 40); // 70: x, 300: y, 100: width, 40: height\r
-    add_->SetText("Add blur");\r
-    add_->SetOnClickListener(this);\r
-    container_->Add(add_);\r
-\r
-    reduce_ = new UILabelButton();\r
-    reduce_->SetPosition(194, 300, 100, 40); // 194: x, 300: y, 100: width, 40: height\r
-    reduce_->SetText("Reduce blur");\r
-    reduce_->SetOnClickListener(this);\r
-    container_->Add(reduce_);\r
-\r
-    clear_ = new UILabelButton();\r
-    clear_->SetPosition(318, 300, 100, 40); // 318: x, 300: y, 100: width, 40: height\r
-    clear_->SetText("Clear blur");\r
-    clear_->SetOnClickListener(this);\r
-    container_->Add(clear_);\r
+    SetupBtn(70, 35, "fg color", fgColor_); // 70: x, 35: y\r
+    SetupBtn(170, 35, "add blank", addBlank_); // 170: x, 35: y\r
+    SetupBtn(270, 35, "switch mode", labelMode_); // 270: x, 35: y\r
+    SetupBtn(70, 360, "cache", cacheEnable_); // 70: x, 360: y\r
+    SetupBtn(70, 300, "Add blur", add_); // 70: x, 300: y\r
+    SetupBtn(194, 300, "Reduce blur", reduce_); // 194: x, 300: y\r
+    SetupBtn(318, 300, "Clear blur", clear_); // 318: x, 300: y\r
 \r
     valueLabel_ = new UILabel();\r
     valueLabel_->SetPosition(194, 360, 100, 40); // 194, 360, 100, 40: Left, right, width, height.\r
-    valueLabel_->SetText("0.00");\r
+    valueLabel_->SetText("BLUR: 0.00");\r
+    valueLabel_->SetLineBreakMode(UILabel::LINE_BREAK_STRETCH);\r
     valueLabel_->SetStyle(STYLE_TEXT_COLOR, Color::Red().full);\r
     valueLabel_->SetStyle(STYLE_BORDER_OPA, 0); // 20: Radius for label boarder.\r
     valueLabel_->SetStyle(STYLE_BACKGROUND_OPA, 0); // 150: Opacity for background.\r
@@ -82,6 +88,11 @@ void UITestMessage::TearDown()
     reduce_ = nullptr;\r
     clear_ = nullptr;\r
     valueLabel_ = nullptr;\r
+    fgColor_ = nullptr;\r
+    cacheEnable_ = nullptr;\r
+    under_ = nullptr;\r
+    addBlank_ = nullptr;\r
+    labelMode_ = nullptr;\r
 }\r
 \r
 const UIView* UITestMessage::GetTestView()\r
@@ -97,6 +108,24 @@ bool UITestMessage::OnClick(UIView& view, const ClickEvent& event)
         blurVaule_ -= BLUR_MODIFY_STEP;\r
     } else if (&view == clear_) {\r
         blurVaule_ = MIN_BLUR_VALUE;\r
+    } else if (&view == fgColor_) {\r
+        uint32_t color = fgColors_[fgIndex_];\r
+        under_->SetStyle(STYLE_BACKGROUND_COLOR, color);\r
+        under_->SetWidth(140 + fgIndex_ * 30); // 140: w, 30: width variation value\r
+        fgIndex_ = (fgIndex_ + 1) % 2; // 2: num\r
+        under_->Invalidate();\r
+        return true;\r
+    } else if (&view == cacheEnable_) {\r
+        msgLabel_->EnableGaussianBlurCache(!msgLabel_->IsGaussianBlurCacheEnable());\r
+    } else if (&view == addBlank_) {\r
+        blankSapce_ += 10;  // 10: blankspace num\r
+        msgLabel_->SetMarqueeBlankNum(blankSapce_);\r
+    } else if (&view == labelMode_) {\r
+        if (msgLabel_->GetLineBreakMode() == UILabel::LINE_BREAK_MARQUEE) {\r
+            msgLabel_->SetLineBreakMode(UILabel::LINE_BREAK_TRUNCATE);\r
+        } else {\r
+            msgLabel_->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE);\r
+        }\r
     }\r
     if (FloatMore(blurVaule_, MAX_BLUR_VALUE)) {\r
         blurVaule_ = MAX_BLUR_VALUE;\r
@@ -105,8 +134,21 @@ bool UITestMessage::OnClick(UIView& view, const ClickEvent& event)
     }\r
     msgLabel_->SetBackgroundBlur(blurVaule_);\r
     char blurText[TEXT_ARRAY_LEN] = {0};\r
-    snprintf_s(blurText, TEXT_ARRAY_LEN, 4, "%4.1f", blurVaule_); // 4, size of format string\r
+    std::string enable = msgLabel_->IsGaussianBlurCacheEnable() ? "CACHE" : "BLUR";\r
+    if (snprintf_s(blurText, TEXT_ARRAY_LEN, TEXT_ARRAY_LEN, "%s: %4.1f", enable.c_str(), blurVaule_) == -1) {\r
+        GRAPHIC_LOGE("sprintf error");\r
+        return false;\r
+    }\r
     valueLabel_->SetText(blurText);\r
     return true;\r
 }\r
+\r
+void UITestMessage::SetupBtn(int16_t x, int16_t y, const std::string &title, UILabelButton *&btn)\r
+{\r
+    btn = new UILabelButton();\r
+    btn->SetPosition(x, y, 100, 40); // 100: w, 40: h\r
+    btn->SetText(title.c_str());\r
+    btn->SetOnClickListener(this);\r
+    container_->Add(btn);\r
+}\r
 }
\ No newline at end of file
index 0bf3180..c6da239 100644 (file)
@@ -34,13 +34,22 @@ public:
     bool OnClick(UIView& view, const ClickEvent& event) override;\r
 \r
 private:\r
+    void SetupBtn(int16_t x, int16_t y, const std::string &title, UILabelButton *&btn);\r
     UIViewGroup* container_ = nullptr;\r
     UILabel* msgLabel_ = nullptr;\r
+    UILabel* under_ = nullptr;\r
+    UILabelButton* fgColor_ = nullptr;\r
+    UILabelButton* addBlank_ = nullptr;\r
+    UILabelButton* labelMode_ = nullptr;\r
+    UILabelButton* cacheEnable_ = nullptr;\r
     UILabelButton* add_ = nullptr;\r
     UILabelButton* reduce_ = nullptr;\r
     UILabelButton* clear_ = nullptr;\r
     UILabel* valueLabel_ = nullptr;\r
     float blurVaule_ = 0.0f;\r
+    uint32_t fgColors_[2] = {Color::Green().full, Color::Yellow().full}; // 2: num\r
+    uint8_t fgIndex_ = 0;\r
+    uint8_t blankSapce_ = 10;\r
 };\r
 }\r
 #endif
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_opacity/ui_test_opacity.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_opacity/ui_test_opacity.cpp
new file mode 100644 (file)
index 0000000..07d2507
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_opacity.h"
+#include "common/screen.h"
+#include "components/ui_swipe_view.h"
+#include "font/ui_font.h"
+
+namespace OHOS {
+namespace {
+const int16_t TITLE_HEIGHT = 20;
+const uint16_t LABEL_WIDTH = 200;
+const uint16_t LABEL_HEIGHT = 50;
+const uint16_t BUTTON_WIDTH = 150;
+const uint16_t BUTTON_HEIGHT = 160;
+const uint16_t CENTER_X = 130;
+const uint16_t CENTER_Y = 100;
+const uint16_t RADIUS = 80;
+static ImageAnimatorInfo g_imageAnimatorInfo[4] = {
+    {RES_PATH"green.png", {50, 50}, 94, 94, IMG_SRC_FILE_PATH},
+    {RES_PATH"yellow.png", {50, 50}, 94, 94, IMG_SRC_FILE_PATH},
+    {RES_PATH"blue.png", {50, 50}, 94, 94, IMG_SRC_FILE_PATH},
+    {RES_PATH"red.png", {50, 50}, 94, 94, IMG_SRC_FILE_PATH},
+};
+static ImageAnimatorInfo g_imageAnimatorInfo2[4] = {
+    {RES_PATH"green.png", {200, 50}, 94, 94, IMG_SRC_FILE_PATH},
+    {RES_PATH"yellow.png", {200, 50}, 94, 94, IMG_SRC_FILE_PATH},
+    {RES_PATH"blue.png", {200, 50}, 94, 94, IMG_SRC_FILE_PATH},
+    {RES_PATH"red.png", {200, 50}, 94, 94, IMG_SRC_FILE_PATH},
+};
+} // namespace
+
+void UITestOpacity::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->SetThrowDrag(true);
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+    }
+}
+
+void UITestOpacity::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+}
+
+UIViewGroup* UITestOpacity::CreateTestCaseGroup(std::string title) const
+{
+    UIViewGroup* group = new UIViewGroup();
+    group->SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);
+    group->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    group->SetPosition(0, 0);
+    UILabel* titleLabel = new UILabel();
+    titleLabel->SetPosition(0, 0, Screen::GetInstance().GetWidth(), TITLE_LABEL_DEFAULT_HEIGHT);
+    titleLabel->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    titleLabel->SetText(title.c_str());
+    group->Add(titleLabel);
+    return group;
+}
+
+const UIView* UITestOpacity::GetTestView()
+{
+    UIKitOpacityTestUILabel001();
+    UIKitOpacityTestUILabel002();
+    UIKitOpacityTestUIButton001();
+    UIKitOpacityTestUIButton002();
+    UIKitOpacityTestUILabelButton001();
+    UIKitOpacityTestUIArcLabel001();
+    UIKitOpacityTestUIImageView001();
+    UIKitOpacityTestUIImageAnimator001();
+    UIKitOpacityTestUIView001();
+    UIKitOpacityTestUIViewGroup001();
+    UIKitOpacityTestUIList001();
+    UIKitOpacityTestUIScrollView001();
+    UIKitOpacityTestUISwipeView001();
+    return container_;
+}
+
+UILabel* UITestOpacity::CreateTestCaseUILabel(std::string title, uint8_t opaScale) const
+{
+    UILabel* label = new UILabel();
+    label->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    label->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    label->SetPosition(10, 30); // 10 width 30: height
+    label->Resize(LABEL_WIDTH, LABEL_HEIGHT);
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 20); // 20:font size
+    label->SetText(title.c_str());
+    label->SetOpaScale(opaScale); // 200: opacity
+    return label;
+}
+
+void UITestOpacity::UIKitOpacityTestUILabel001()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group = CreateTestCaseGroup(" display dynamic text with opacity 200 and 100");
+        group->Resize(Screen::GetInstance().GetWidth(), LABEL_HEIGHT + 50); // 50 : height
+        group->SetViewId("UIKitOpacityTestUILabel001");
+        UILabel* empty = new UILabel();
+        empty->SetPosition(10, 100); // 10 width 100: height
+        group->Add(empty);
+        UILabel* label = CreateTestCaseUILabel("轻量级GUI-200", 200);  // 200: opacity
+        UILabel* label2 = CreateTestCaseUILabel("轻量级GUI-100", 100); // 100: opacity
+        label2->SetX(220);                                             // 220: width
+        group->Add(label);
+        group->Add(label2);
+        container_->Add(group);
+    }
+}
+
+void UITestOpacity::UIKitOpacityTestUILabel002()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group = CreateTestCaseGroup(" display dynamic text with opacity 256  and -1, uint8_t");
+        group->Resize(Screen::GetInstance().GetWidth(), LABEL_HEIGHT + 50); // 50 : height
+        group->SetViewId("UIKitOpacityTestUILabel002");
+        UILabel* label = CreateTestCaseUILabel("轻量级GUI-255", 255); // 255: opacity
+        UILabel* label2 = CreateTestCaseUILabel("轻量级GUI-(-1)", -1); // -1: opacity
+        label2->SetX(220);                                            // 220: width
+        group->Add(label);
+        group->Add(label2);
+        container_->Add(group);
+        group->LayoutBottomToSibling("UIKitOpacityTestUILabel001", 10); // 10: height
+    }
+}
+
+void UITestOpacity::UIKitOpacityTestUIButton001()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group = CreateTestCaseGroup(" display UIButton with opacity 200 and 100");
+        group->Resize(Screen::GetInstance().GetWidth(), BUTTON_HEIGHT);
+        group->SetViewId("UIKitOpacityTestUIButton001");
+
+        UIButton* button = new UIButton();
+        button->SetPosition(60, 30, BUTTON_WIDTH, BUTTON_HEIGHT >> 1); // 60: width 30  :height
+        button->SetOpaScale(200);                                      // 200: opacity
+        UIButton* button2 = new UIButton();
+        button2->SetPosition(250, 30, BUTTON_WIDTH, BUTTON_HEIGHT >> 1); // 250: width 30 : height
+        button2->SetOpaScale(100);                                       // 100: opacity
+
+        group->Add(button);
+        group->Add(button2);
+        container_->Add(group);
+        group->LayoutBottomToSibling("UIKitOpacityTestUILabel002", 10); // 10: height
+    }
+}
+
+UIButton* UITestOpacity::CreateTestCaseUIButton(uint8_t opaScale) const
+{
+    UIButton* button = new UIButton();
+    button->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    button->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    button->SetPosition(60, 30, BUTTON_WIDTH, BUTTON_HEIGHT); // 60 30 x y
+    button->SetImageSrc(RES_PATH"blue.png", RES_PATH"yellow.png");
+    button->SetOpaScale(opaScale); // 200: opacity
+    return button;
+}
+
+void UITestOpacity::UIKitOpacityTestUIButton002()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group = CreateTestCaseGroup(" display UIButton Image with opacity 200 and 100");
+        group->Resize(Screen::GetInstance().GetWidth(), BUTTON_HEIGHT + 50); // 50 : height
+        group->SetViewId("UIKitOpacityTestUIButton002");
+
+        UIButton* button = CreateTestCaseUIButton(200); // 200: opacity
+        group->Add(button);
+        UIButton* button2 = CreateTestCaseUIButton(100); // 100: opacity
+        button2->SetPosition(250, 30);                   // 250: width 30 y
+        group->Add(button2);
+        container_->Add(group);
+        group->LayoutBottomToSibling("UIKitOpacityTestUIButton001", 10); // 10: height
+    }
+}
+
+UILabelButton* UITestOpacity::CreateTestCaseUILabelButton(std::string title, uint8_t opaScale) const
+{
+    UILabelButton* labelButton = new UILabelButton();
+    labelButton->SetPosition(60, 30, BUTTON_WIDTH, BUTTON_HEIGHT >> 1); // 60 x 30 : y
+    labelButton->SetText(title.c_str());
+    labelButton->SetOpaScale(opaScale);
+    return labelButton;
+}
+
+void UITestOpacity::UIKitOpacityTestUILabelButton001()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group = CreateTestCaseGroup(" display UILabelButton with opacity 200 and 100");
+        group->Resize(Screen::GetInstance().GetWidth(), BUTTON_HEIGHT);
+        group->SetViewId("UIKitOpacityTestUILabelButton001");
+        UILabelButton* labelButton = CreateTestCaseUILabelButton("200", 200); // 200 : opacity
+        group->Add(labelButton);
+        UILabelButton* labelButton2 = CreateTestCaseUILabelButton("100", 100); // 100: opacity
+        labelButton2->SetX(250);                                               // 250: width
+        group->Add(labelButton2);
+        container_->Add(group);
+        group->LayoutBottomToSibling("UIKitOpacityTestUIButton002", 10); // 10: height
+    }
+}
+
+UIArcLabel* UITestOpacity::CreateTestCaseUIArcLabel(std::string title, uint8_t opaScale) const
+{
+    UIArcLabel* label = new UIArcLabel();
+    label->SetArcTextCenter(CENTER_X, CENTER_Y + 20); // 20 : height
+    label->SetArcTextRadius(RADIUS);
+    label->SetArcTextAngle(270, 0);                   // 270: start angle, 0: end angle
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 30); // 30: font size
+    label->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    label->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    label->SetText(title.c_str());
+    label->SetStyle(STYLE_LETTER_SPACE, 30); // 30: space
+    label->SetOpaScale(opaScale);            // 200: opacity
+    return label;
+}
+void UITestOpacity::UIKitOpacityTestUIArcLabel001()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group = CreateTestCaseGroup(" display UIArcLabel with opacity 200 and 100");
+        group->Resize(Screen::GetInstance().GetWidth(), BUTTON_HEIGHT + 50); // 50 : height
+        group->SetViewId("UIKitOpacityTestUIArcLabel001");
+        UIArcLabel* label = CreateTestCaseUIArcLabel("01234567", 200); // 200: opacity
+        group->Add(label);
+        UIArcLabel* label2 = CreateTestCaseUIArcLabel("01234567", 100); // 100: opacity
+        if (label2 == nullptr) {
+            return;
+        }
+        label2->SetArcTextCenter(CENTER_X + 200, CENTER_Y + 20);        // 200: width 20 : height
+        group->Add(label2);
+        container_->Add(group);
+        group->LayoutBottomToSibling("UIKitOpacityTestUILabelButton001", 10); // 10 : height
+    }
+}
+
+UIImageView* UITestOpacity::CreateTestCaseUIImageView(std::string path, uint8_t opaScale) const
+{
+    UIImageView* imageView = new UIImageView();
+    imageView->SetPosition(60, 30, 130, 130); // 60 x 30: y 130 : size
+    imageView->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    imageView->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    imageView->SetSrc(path.c_str());
+    imageView->SetOpaScale(opaScale); // 200: opacity
+    return imageView;
+}
+
+void UITestOpacity::UIKitOpacityTestUIImageView001()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group = CreateTestCaseGroup(" display UIImageView with opacity 200 and 100");
+        group->Resize(Screen::GetInstance().GetWidth(), BUTTON_HEIGHT + 50); // 50 : height
+        group->SetViewId("UIKitOpacityTestUIImageView001");
+        UIImageView* imageView = CreateTestCaseUIImageView(RES_PATH"blue.png", 200); // 200: opacity
+        group->Add(imageView);
+        UIImageView* imageView2 = CreateTestCaseUIImageView(RES_PATH"blue_argb8888.bin", 100); // 100: opacity
+        imageView2->SetX(250);  // 250: width
+        group->Add(imageView2);
+        container_->Add(group);
+        group->LayoutBottomToSibling("UIKitOpacityTestUIArcLabel001", 10); // 10 : height
+    }
+}
+
+UIImageAnimatorView* UITestOpacity::CreateTestCaseUIImageAnimator(const ImageAnimatorInfo imageAnimatorInfo[],
+                                                                  uint8_t opaScale) const
+{
+    UIImageAnimatorView* imageAnimator = new UIImageAnimatorView();
+    imageAnimator->SetPosition(60, 30, 200, 200); // 60 : offset 30 : offset 200 : offset 200: offset
+    imageAnimator->SetOpaScale(opaScale);
+    imageAnimator->SetImageAnimatorSrc(imageAnimatorInfo, 4, 10); // 4: image number, 10: updating time
+    imageAnimator->Start();
+    return imageAnimator;
+}
+
+void UITestOpacity::UIKitOpacityTestUIImageAnimator001()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group = CreateTestCaseGroup(" display UIImageAnimator with opacity 200 and 100");
+        group->Resize(Screen::GetInstance().GetWidth(), BUTTON_HEIGHT + 50); // 50: height
+        group->SetViewId("UIKitOpacityTestUIImageAnimator001");
+        UIImageAnimatorView* imageAnimator = CreateTestCaseUIImageAnimator(g_imageAnimatorInfo, 200); // 200: opacity
+        group->Add(imageAnimator);
+        UIImageAnimatorView* imageAnimator2 = CreateTestCaseUIImageAnimator(g_imageAnimatorInfo2, 100); // 100: opacity
+        imageAnimator2->SetPosition(230, 30); // 230: width 30: height
+        group->Add(imageAnimator2);
+        container_->Add(group);
+        group->LayoutBottomToSibling("UIKitOpacityTestUIImageView001", 10); // 10: height
+    }
+}
+UIView* UITestOpacity::CreateTestCaseUIView(uint8_t opaScale) const
+{
+    UIView* view = new UIView();
+    view->SetPosition(60, 30, BUTTON_WIDTH, BUTTON_HEIGHT); // 60: x 30: y
+    view->SetStyle(STYLE_BACKGROUND_COLOR, (Color::White()).full);
+    view->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    view->SetOpaScale(opaScale);
+    return view;
+}
+
+void UITestOpacity::UIKitOpacityTestUIView001()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group = CreateTestCaseGroup(" display UIView with opacity 200 and 100");
+        group->Resize(Screen::GetInstance().GetWidth(), BUTTON_HEIGHT + 50); // 50 : height
+        group->SetViewId("UIKitOpacityTestUIView001");
+
+        UIView* view = CreateTestCaseUIView(200); // 200 : opacity
+        group->Add(view);
+        UIView* view2 = CreateTestCaseUIView(100); // 100 : opacity
+        view2->SetX(250);                          // 250: wdith
+        group->Add(view2);
+
+        container_->Add(group);
+        group->LayoutBottomToSibling("UIKitOpacityTestUIImageAnimator001", 10); // 10 : height
+    }
+}
+
+void UITestOpacity::UIKitOpacityTestUIViewGroup001()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group = CreateTestCaseGroup(" display UIViewGroup with opacity 200 and 100");
+        group->Resize(Screen::GetInstance().GetWidth(), (BUTTON_HEIGHT << 1) + 100); // 100: height
+        group->SetViewId("UIKitOpacityTestUIViewGroup001");
+
+        UIViewGroup* group1 = new UIViewGroup();
+        group1->SetPosition(10, 30, (BUTTON_WIDTH << 1) + 50, (BUTTON_HEIGHT << 1) + 100); // 30 y 50: width 100: height
+        group1->SetStyle(STYLE_BACKGROUND_COLOR, (Color::Red()).full);
+        UIViewGroup* group2 = new UIViewGroup();
+        group2->SetPosition(170, 250, 150, 150); // 170: x 250: y 150: width 150: height
+        group2->SetStyle(STYLE_BACKGROUND_COLOR, (Color::White()).full);
+
+        UILabelButton* labelButton = new UILabelButton();
+        labelButton->SetPosition(10, 10, 60, 30); // 10: x y 60 wdith 30 height
+        labelButton->SetText("Test1");
+        UILabelButton* labelButton2 = new UILabelButton();
+        labelButton2->SetPosition(170, 10, 60, 30); // 170: x 10: y 60 wdith 30 height
+        labelButton2->SetText("Test2");
+        labelButton2->SetOpaScale(100); // 100: opacity
+        UIButton* button = new UIButton();
+        button->SetPosition(10, 60, BUTTON_WIDTH, BUTTON_HEIGHT); // 10: x 60: y
+        UIButton* button2 = new UIButton();
+        button2->SetPosition(170, 60, BUTTON_WIDTH, BUTTON_HEIGHT); // 170: x 60: y
+        button2->SetImageSrc(RES_PATH"blue.png", RES_PATH"yellow.png");
+        button2->SetOpaScale(100); // 100: opacity
+        UIImageView* imageView = new UIImageView();
+        imageView->SetPosition(10, 250, 50, 50); // 10: x 250: y 50 : size
+        imageView->SetSrc(RES_PATH"blue.png");
+        imageView->SetOpaScale(100); // 100: opacity
+        UIImageView* imageView2 = new UIImageView();
+        imageView2->SetPosition(10, 10, 50, 50); // 10: x y 50 : size
+        imageView2->SetSrc(RES_PATH"yellow.png");
+
+        group2->Add(imageView2);
+        group1->Add(labelButton);
+        group1->Add(labelButton2);
+        group1->Add(button);
+        group1->Add(button2);
+        group1->Add(imageView);
+        group1->Add(group2);
+        group2->SetOpaScale(100); // 100: opacity
+        group1->SetOpaScale(200); // 200: opacity
+        group->Add(group1);
+        container_->Add(group);
+        group1->LayoutLeftOfParent(40); // 40 : height
+        group->LayoutBottomToSibling("UIKitOpacityTestUIView001", 10); // 10 : height
+    }
+}
+
+UIList* UITestOpacity::CreateTestCaseUIList(uint8_t opaScale) const
+{
+    List<const char*>* adapterData = new List<const char*>();
+    adapterData->PushBack("000");
+    adapterData->PushBack("111");
+    adapterData->PushBack("222");
+    adapterData->PushBack("333");
+    adapterData->PushBack("444");
+    adapterData->PushBack("555");
+    adapterData->PushBack("666");
+    adapterData->PushBack("777");
+    adapterData->PushBack("888");
+    adapterData->PushBack("999");
+
+    TextAdapter* adapter = new TextAdapter();
+    adapter->SetData(adapterData);
+    UIList* list = new UIList(UIList::VERTICAL);
+    list->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    list->SetPosition(60, 30, BUTTON_WIDTH, BUTTON_HEIGHT); // 60 x 30 y
+    list->SetAdapter(adapter);
+    list->SetOpaScale(opaScale); // 200: opacity
+    return list;
+}
+
+void UITestOpacity::UIKitOpacityTestUIList001()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group = CreateTestCaseGroup(" display UIList with opacity 200 and 100");
+        group->Resize(Screen::GetInstance().GetWidth(), BUTTON_HEIGHT + 100); // 100: height
+        group->SetViewId("UIKitOpacityTestUIList001");
+        UIList* list = CreateTestCaseUIList(200); // 200 : opacity
+        group->Add(list);
+        UIList* list2 = CreateTestCaseUIList(100); // 100 : opacity
+        list2->SetX(260);                          // 260: width
+        group->Add(list2);
+        container_->Add(group);
+        group->LayoutBottomToSibling("UIKitOpacityTestUIViewGroup001", 10); // 10 : height
+    }
+}
+
+void UITestOpacity::UIKitOpacityTestUIScrollView001()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group = CreateTestCaseGroup(" display UIScrollView with opacity 200 and 100");
+        group->Resize(Screen::GetInstance().GetWidth(), BUTTON_HEIGHT << 1);
+        group->SetViewId("UIKitOpacityTestUIScrollView001");
+
+        UIScrollView* group1 = new UIScrollView();
+        group1->SetPosition(10, 30, (BUTTON_WIDTH << 1) + 50, (BUTTON_HEIGHT) + 100); // 10 x 30 y 50: width 100: height
+        group1->SetStyle(STYLE_BACKGROUND_COLOR, (Color::Red()).full);
+        UIScrollView* group2 = new UIScrollView();
+        group2->SetPosition(170, 80, 150, 150); // 170: x 80: y 150: width 150: height
+        group2->SetStyle(STYLE_BACKGROUND_COLOR, (Color::White()).full);
+        UILabelButton* labelButton = new UILabelButton();
+        labelButton->SetPosition(10, 10, 80, 40); // 10 x y 80: width 40: height
+        labelButton->SetText("test1");
+        UILabelButton* labelButton2 = new UILabelButton();
+        labelButton2->SetPosition(170, 10, 80, 40); // 170: x 10: y 80: width 40: height
+        labelButton2->SetText("test2");
+        labelButton2->SetOpaScale(100); // 100: opacity
+        UIImageView* imageView = new UIImageView();
+        imageView->SetPosition(10, 80, 50, 50); // 10: x 80: y 50 : size
+        imageView->SetSrc(RES_PATH"blue.png");
+        imageView->SetOpaScale(100); // 100: opacity
+        UIImageView* imageView2 = new UIImageView();
+        imageView2->SetPosition(10, 10, 50, 50); // 10: x y 50 : size
+        imageView2->SetSrc(RES_PATH"yellow.png");
+
+        group2->Add(imageView2);
+        group1->Add(labelButton);
+        group1->Add(labelButton2);
+        group1->Add(imageView);
+        group1->Add(group2);
+        group2->SetOpaScale(100); // 100: opacity
+        group1->SetOpaScale(200); // 200: opacity
+        group->Add(group1);
+        container_->Add(group);
+        group1->LayoutLeftOfParent(40);  // 40 : offset
+        group->LayoutBottomToSibling("UIKitOpacityTestUIList001", 60); // 60 : height
+    }
+}
+
+void UITestOpacity::UIKitOpacityTestUISwipeView001()
+{
+    if (container_ != nullptr) {
+        UIViewGroup* group = CreateTestCaseGroup(" display UISwipeView with opacity 200 and 100");
+        group->Resize(Screen::GetInstance().GetWidth(), BUTTON_HEIGHT);
+        group->SetViewId("UIKitOpacityTestUISwipeView001");
+
+        UISwipeView* swipe = new UISwipeView(UISwipeView::HORIZONTAL);
+        swipe->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+        swipe->SetPosition(60, 30, BUTTON_WIDTH << 1, BUTTON_HEIGHT); // 60 30 size
+        swipe->SetBlankSize(50);                                      // 50: is blank size
+        group->Add(swipe);
+
+        UILabelButton* button1 = new UILabelButton();
+        button1->SetPosition(0, 0, BUTTON_WIDTH, BUTTON_HEIGHT >> 1);
+        button1->SetText("button1");
+        swipe->Add(button1);
+
+        UILabelButton* button2 = new UILabelButton();
+        button2->SetPosition(0, 0, BUTTON_WIDTH, BUTTON_HEIGHT >> 1);
+        button2->SetText("button2");
+        button2->SetOpaScale(200); // 200: opacity
+        swipe->Add(button2);
+
+        UILabelButton* button3 = new UILabelButton();
+        button3->SetPosition(0, 0, BUTTON_WIDTH, BUTTON_HEIGHT >> 1);
+        button3->SetText("button3");
+        button3->SetOpaScale(100); // 100: opacity
+        swipe->Add(button3);
+
+        swipe->SetOpaScale(200); // 200: opacity
+        container_->Add(group);
+        group->LayoutBottomToSibling("UIKitOpacityTestUIScrollView001", 60); // 60 : height
+    }
+}
+} // namespace OHOS
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_opacity/ui_test_opacity.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_opacity/ui_test_opacity.h
new file mode 100644 (file)
index 0000000..4f8946a
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_OPACITY_H
+#define UI_TEST_OPACITY_H
+
+#include "components/root_view.h"
+#include "components/text_adapter.h"
+#include "components/ui_arc_label.h"
+#include "components/ui_button.h"
+#include "components/ui_image_animator.h"
+#include "components/ui_image_view.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_list.h"
+#include "components/ui_scroll_view.h"
+#include "ui_test.h"
+namespace OHOS {
+class UITestOpacity : public UITest {
+public:
+    UITestOpacity() {}
+    ~UITestOpacity() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    /**
+     * @brief Test UILabel
+     */
+    void UIKitOpacityTestUILabel001();
+
+    /**
+     * @brief Test UILabel exception value
+     */
+    void UIKitOpacityTestUILabel002();
+
+    /**
+     * @brief Test UIButton
+     */
+    void UIKitOpacityTestUIButton001();
+
+    /**
+     * @brief Test UIButton image
+     */
+    void UIKitOpacityTestUIButton002();
+
+    /**
+     * @brief Test UILabelButton
+     */
+    void UIKitOpacityTestUILabelButton001();
+
+    /**
+     * @brief Test UIArcLabel
+     */
+    void UIKitOpacityTestUIArcLabel001();
+
+    /**
+     * @brief Test UIImageView
+     */
+    void UIKitOpacityTestUIImageView001();
+
+    /**
+     * @brief Test UIImageAnimator
+     */
+    void UIKitOpacityTestUIImageAnimator001();
+
+    /**
+     * @brief Test UIView
+     */
+    void UIKitOpacityTestUIView001();
+
+    /**
+     * @brief Test UIViewGroup
+     */
+    void UIKitOpacityTestUIViewGroup001();
+
+    /**
+     * @brief Test UIList
+     */
+    void UIKitOpacityTestUIList001();
+
+    /**
+     * @brief Test UIScrollView
+     */
+    void UIKitOpacityTestUIScrollView001();
+
+    /**
+     * @brief Test UISwipeView
+     */
+    void UIKitOpacityTestUISwipeView001();
+
+private:
+    UIViewGroup* CreateTestCaseGroup(std::string title) const;
+    UILabel* CreateTestCaseUILabel(std::string title, uint8_t opaScale) const;
+    UIButton* CreateTestCaseUIButton(uint8_t opaScale) const;
+    UILabelButton* CreateTestCaseUILabelButton(std::string title, uint8_t opaScale) const;
+    UIArcLabel* CreateTestCaseUIArcLabel(std::string title, uint8_t opaScale) const;
+    UIImageView* CreateTestCaseUIImageView(std::string path, uint8_t opaScale) const;
+    UIImageAnimatorView* CreateTestCaseUIImageAnimator(const ImageAnimatorInfo imageAnimatorInfo[],
+                                                       uint8_t opaScale) const;
+    UIView* CreateTestCaseUIView(uint8_t opaScale) const;
+    UIList* CreateTestCaseUIList(uint8_t opaScale) const;
+
+    UIScrollView* container_ = nullptr;
+};
+}
+#endif // UI_TEST_OPACITY_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_picker/ui_test_ui_picker.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_picker/ui_test_ui_picker.cpp
new file mode 100644 (file)
index 0000000..2f849b2
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_ui_picker.h"
+#include "common/screen.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+
+#include <string>
+
+namespace OHOS {
+namespace {
+static int16_t g_blank = 38;
+static int16_t g_listW = 200;
+static int16_t g_listH = 300;
+static const char* g_pickerRange[] = {"A0", "B1", "C2", "D3", "E4", "F5", "G6", "H7", "I8", "J9", "K10", "L11"};
+} // namespace
+
+void UITestUIPicker::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        container_->SetThrowDrag(true);
+        container_->SetHorizontalScrollState(false);
+    }
+}
+
+void UITestUIPicker::TearDown()
+{
+    container_->Remove(setLoopBtn_);
+    container_->Remove(setLoopOffBtn_);
+    container_->Remove(setSelectBtn_);
+    container_->Remove(setLeftToRightBtn_);
+    container_->Remove(setRightToLeftBtn_);
+    container_->Remove(selectIndex_);
+    container_->Remove(selectTime_);
+    container_->Remove(picker1_);
+    container_->Remove(picker2_);
+    container_->Remove(picker3_);
+    DeleteChildren(container_);
+    setLoopBtn_ = nullptr;
+    setLoopOffBtn_ = nullptr;
+    setSelectBtn_ = nullptr;
+    setLeftToRightBtn_ = nullptr;
+    setRightToLeftBtn_ = nullptr;
+    selectIndex_ = nullptr;
+    selectTime_ = nullptr;
+    container_ = nullptr;
+    picker1_ = nullptr;
+    picker2_ = nullptr;
+    picker3_ = nullptr;
+
+    lastX_ = 0;
+    lastY_ = 0;
+}
+
+const UIView* UITestUIPicker::GetTestView()
+{
+    UIKitPickerTestBase001();
+    UIKitPickerTestBase002();
+    UIKitPickerTestTimePicker001();
+    return container_;
+}
+
+void UITestUIPicker::OnPickerStoped(UIPicker& picker)
+{
+    uint16_t index = picker.GetSelected();
+    selectIndex_->SetText(std::to_string(index).c_str());
+    selectIndex_->Invalidate();
+}
+
+void UITestUIPicker::OnTimePickerStoped(UITimePicker& picker)
+{
+    selectTime_->SetText(picker.GetSelectValue());
+    selectTime_->Invalidate();
+}
+
+void UITestUIPicker::UIKitPickerTestBase001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE;
+    UILabel* label = GetTitleLabel("UIPicker动态字体  ");
+    container_->Add(label);
+    label->SetPosition(positionX_ * 3, 30); // 3 : 3 times of label , 30 : init height
+    if (picker1_ == nullptr) {
+        picker1_ = new UIPicker();
+    }
+    picker1_->SetPosition(positionX_ + 20, label->GetY() + g_blank, g_listW, g_listH); // 20 : adjust postion
+    picker1_->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    picker1_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Green().full);
+    picker1_->SetFontId(16, 18); // 16:back font id 18:high light font id
+    picker1_->SetItemHeight(50); // 50: height
+    picker1_->SetTextColor(Color::Gray(), Color::Red());
+    picker1_->SetDirect(UITextLanguageDirect::TEXT_DIRECT_RTL);
+    picker1_->SetValues(g_pickerRange, sizeof(g_pickerRange) / sizeof(g_pickerRange[0]));
+    picker1_->RegisterSelectedListener(this);
+
+    positionX_ = picker1_->GetWidth() + picker1_->GetX();
+    positionY_ = picker1_->GetY();
+    CreatButtons();
+    if (selectIndex_ == nullptr) {
+        selectIndex_ = new UILabel();
+    }
+    selectIndex_ = GetTitleLabel("NULL");
+    selectIndex_->SetPosition(positionX_ + 40, label->GetY() + g_blank); // 40: increase x-coordinate
+    positionY_ += label->GetY() + 10;   // 10 Gap of item
+    container_->Add(selectIndex_);
+    SetUpButton(setLoopBtn_, "开启循环 ");
+    SetUpButton(setLoopOffBtn_, "关闭循环 ");
+    SetUpButton(setSelectBtn_, "定位到第5个 ");
+    SetUpButton(setLeftToRightBtn_, "从左往右 ");
+    SetUpButton(setRightToLeftBtn_, "从右往左 ");
+    container_->Add(picker1_);
+    SetLastPos(picker1_);
+}
+
+void UITestUIPicker::CreatButtons()
+{
+    if (setLoopBtn_ == nullptr) {
+        setLoopBtn_ = new UILabelButton();
+    }
+    if (setLoopOffBtn_ == nullptr) {
+        setLoopOffBtn_ = new UILabelButton();
+    }
+    if (setSelectBtn_ == nullptr) {
+        setSelectBtn_ = new UILabelButton();
+    }
+    if (setLeftToRightBtn_ == nullptr) {
+        setLeftToRightBtn_ = new UILabelButton();
+    }
+    if (setRightToLeftBtn_ == nullptr) {
+        setRightToLeftBtn_ = new UILabelButton();
+    }
+}
+
+void UITestUIPicker::UIKitPickerTestBase002()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("UIPicker区间数字  ");
+    container_->Add(label);
+    label->SetPosition(390, 0); // 390 x-coordinate
+    if (picker3_ == nullptr) {
+        picker3_ = new UIPicker();
+    }
+    picker3_->SetPosition(390, g_blank, g_listW, g_listH); // 390: x-coordinate
+    picker3_->SetFontId(16, 18);                           // 16:back font id 18:high light font id
+    picker3_->SetItemHeight(50);                           // 50: height
+    picker3_->SetTextColor(Color::Gray(), Color::Red());
+    picker3_->SetValues(-5, 20); // -5: start 20:end
+    picker3_->SetTextFormatter(new TextFormatter());
+
+    positionX_ = picker3_->GetWidth();
+    positionY_ = picker3_->GetY();
+
+    container_->Add(picker3_);
+    SetLastPos(picker3_);
+}
+
+void UITestUIPicker::UIKitPickerTestTimePicker001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("Time Picker");
+    container_->Add(label);
+    label->SetPosition(672, 0); // 672: x-coordinate
+    label->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    if (picker2_ == nullptr) {
+        picker2_ = new UITimePicker();
+    }
+    picker2_->EnableSecond(true);
+    picker2_->SetPosition(652, label->GetY() + g_blank, g_listW, g_listH); // 652: x-coordinate
+    picker2_->SetItemHeight(50);                                           // 50 height
+    picker2_->RegisterSelectedListener(this);
+    positionX_ = picker2_->GetWidth();
+    positionY_ = picker2_->GetY();
+
+    if (selectTime_ == nullptr) {
+        selectTime_ = new UILabel();
+    }
+    selectTime_ = GetTitleLabel("NULL");
+    picker2_->RegisterSelectedListener(this);
+    selectTime_->SetPosition(662 + picker2_->GetWidth(), label->GetY() + g_blank); // 662: increase x-coordinate
+    container_->Add(selectTime_);
+    container_->Add(picker2_);
+    SetLastPos(picker2_);
+}
+
+bool UITestUIPicker::OnClick(UIView& view, const ClickEvent& event)
+{
+    if (&view == setLoopBtn_) {
+        picker1_->SetLoopState(true);
+    } else if (&view == setLoopOffBtn_) {
+        picker1_->SetLoopState(false);
+    } else if (&view == setSelectBtn_) {
+        picker1_->SetSelected(5); // 5: index
+    } else if (&view == setLeftToRightBtn_) {
+        picker1_->SetDirect(UITextLanguageDirect::TEXT_DIRECT_LTR);
+    } else if (&view == setRightToLeftBtn_) {
+        picker1_->SetDirect(UITextLanguageDirect::TEXT_DIRECT_RTL);
+    }
+    return true;
+}
+
+void UITestUIPicker::SetUpButton(UILabelButton* btn, const char* title)
+{
+    if (btn == nullptr) {
+        return;
+    }
+    container_->Add(btn);
+    btn->SetPosition(positionX_ + 30, positionY_, BUTTON_WIDHT2, BUTTON_HEIGHT2); // 30: increase x-coordinate;
+    positionY_ += btn->GetHeight() + 12;                                          // 12: increase y-coordinate
+    btn->SetText(title);
+    btn->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
+    btn->SetOnClickListener(this);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+    container_->Invalidate();
+}
+
+void UITestUIPicker::SetLastPos(UIView* view)
+{
+    lastX_ = view->GetX();
+    lastY_ = view->GetY() + view->GetHeight();
+}
+} // namespace OHOS
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_picker/ui_test_ui_picker.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_picker/ui_test_ui_picker.h
new file mode 100644 (file)
index 0000000..dc3fa28
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_UI_PICKER_H
+#define UI_TEST_UI_PICKER_H
+
+#include "components/text_adapter.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_picker.h"
+#include "components/ui_scroll_view.h"
+#include "components/ui_time_picker.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestUIPicker : public UITest, UIView::OnClickListener, UIPicker::SelectedListener,
+    UITimePicker::SelectedListener {
+public:
+    UITestUIPicker() {}
+    ~UITestUIPicker() {}
+    void SetUp() override;
+    void TearDown() override;
+    bool OnClick(UIView& view, const ClickEvent& event) override;
+    const UIView* GetTestView() override;
+    void OnPickerStoped(UIPicker& picker) override;
+    void OnTimePickerStoped(UITimePicker& picker) override;
+    void CreatButtons();
+    void UIKitPickerTestBase001();
+    void UIKitPickerTestBase002();
+    void UIKitPickerTestTimePicker001();
+
+private:
+    void SetLastPos(UIView* view);
+    void SetUpButton(UILabelButton* btn, const char* title);
+    UILabelButton* setLoopBtn_ = nullptr;
+    UILabelButton* setLoopOffBtn_ = nullptr;
+    UILabelButton* setSelectBtn_ = nullptr;
+    UILabelButton* setLeftToRightBtn_ = nullptr;
+    UILabelButton* setRightToLeftBtn_ = nullptr;
+    UILabel* selectIndex_ = nullptr;
+    UILabel* selectTime_ = nullptr;
+    UIScrollView* container_ = nullptr;
+    UIPicker* picker1_ = nullptr;
+    UIPicker* picker3_ = nullptr;
+    UITimePicker* picker2_ = nullptr;
+    int16_t lastX_ = 0;
+    int16_t lastY_ = 0;
+};
+} // namespace OHOS
+#endif // UI_TEST_UI_PICKER_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_progress_bar/ui_test_box_progress.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_progress_bar/ui_test_box_progress.cpp
new file mode 100644 (file)
index 0000000..94e4adc
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_box_progress.h"
+#include "common/screen.h"
+#include "components/ui_label.h"
+
+namespace OHOS {
+namespace {
+const int16_t LABEL_HEIGHT = 29;
+const int16_t BUTTON_WIDTH = 120;
+const int16_t BUTTON_HEIGHT = 40;
+const int16_t DELTA_X_COORDINATE = 8;
+const int16_t DELTA_X_COORDINATE_2 = 336;
+const int16_t DELTA_Y_COORDINATE = 12;
+const int16_t DELTA_Y_COORDINATE_2 = 19;
+} // namespace
+
+void UITestBoxProgress::SetUp()
+{
+    if (container_ == nullptr) {
+        positionX_ = 0;
+        positionY_ = 0;
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        UIViewGroup* uiViewGroup = new UIViewGroup();
+        uiViewGroup->SetPosition(positionX_, positionY_ + 20, 240, 360); // 20: offset; 240: width; 360: height
+        container_->Add(uiViewGroup);
+        UILabel* label = new UILabel();
+        uiViewGroup->Add(label);
+        container_->Add(uiViewGroup);
+        // 50: offset; 200: width; 48: height
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, TEXT_DISTANCE_TO_TOP_SIDE + 50, 200, 48);
+        label->SetText("BoxProgress");
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        uiViewGroupFrame_ = new UIViewGroup();
+        uiViewGroup->Add(uiViewGroupFrame_);
+        // 50: offset; 200: width; 210: height
+        uiViewGroupFrame_->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE2, TEXT_DISTANCE_TO_LEFT_SIDE + 50, 200, 210);
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_COLOR, Color::White().full);
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_OPA, HALF_OPA_OPAQUE);
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_WIDTH, VIEW_STYLE_BORDER_WIDTH);
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_RADIUS, VIEW_STYLE_BORDER_RADIUS);
+        uiViewGroupFrame_->SetStyle(STYLE_BACKGROUND_OPA, 0);
+
+        boxProgress_ = new UIBoxProgress();
+        // 10: offset; 100: width; 10: height
+        boxProgress_->SetPosition(10, 10, 100, 10);
+        boxProgress_->SetValue(20); // 20 : value
+        boxProgress_->SetBackgroundStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+        boxProgress_->SetForegroundStyle(STYLE_BACKGROUND_COLOR, Color::Green().full);
+        boxProgress_->SetStyle(STYLE_BORDER_COLOR, Color::Yellow().full);
+        uiViewGroupFrame_->Add(boxProgress_);
+        boxProgress_->LayoutCenterOfParent();
+    }
+
+    if (scroll_ == nullptr) {
+        scroll_ = new UIScrollView();
+        // 250: x-pos; 11: y-pos
+        scroll_->SetPosition(250, 11);
+        // 300: width; 100: Adjust the visible height of scroll
+        scroll_->Resize(300, Screen::GetInstance().GetHeight() - 100);
+        container_->Add(scroll_);
+        positionY_ = 0;
+    }
+}
+
+void UITestBoxProgress::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+    boxProgress_ = nullptr;
+    scroll_ = nullptr;
+    uiViewGroupFrame_ = nullptr;
+}
+
+const UIView* UITestBoxProgress::GetTestView()
+{
+    UIKitBoxProgressTestUIBoxProgress001();
+    UIKitBoxProgressTestSetRange002();
+    UIKitBoxProgressTestSetValue003();
+    UIKitBoxProgressTestSetImage004();
+    UIKitBoxProgressTestSetStyle005();
+    UIKitBoxProgressTestGetStyle006();
+    UIKitBoxProgressTestSetCapType007();
+    UIKitBoxProgressTestSetDirection008();
+    UIKitBoxProgressTestEnableBackground009();
+    UIKitBoxProgressTestSetStep010();
+    UIKitBoxProgressTestSetValidSize011();
+    UIKitBoxProgressTestSetBorderAndPadding012();
+
+    return container_;
+}
+
+void UITestBoxProgress::SetUpLabel(const char* title, int16_t x, int16_t y) const
+{
+    UILabel* label = new UILabel();
+    scroll_->Add(label);
+    label->SetPosition(x, y, 288, 30); // 288: width; 30: height
+    label->SetText(title);
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+}
+void UITestBoxProgress::SetUpButton(UILabelButton* btn, const char* title, int16_t x, int16_t y)
+{
+    if (btn == nullptr) {
+        return;
+    }
+    scroll_->Add(btn);
+    btn->SetPosition(x, y, BUTTON_WIDHT2, BUTTON_HEIGHT2);
+    btn->SetText(title);
+    btn->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
+    btn->SetOnClickListener(this);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+    scroll_->Invalidate();
+}
+
+void UITestBoxProgress::UIKitBoxProgressTestUIBoxProgress001()
+{
+    resetBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ = 0;
+    SetUpLabel("创建条形进度条:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(resetBtn_, "重置", positionX_, positionY_);
+}
+
+void UITestBoxProgress::UIKitBoxProgressTestSetRange002()
+{
+    incMinProgressBtn_ = new UILabelButton();
+    decMinProgressBtn_ = new UILabelButton();
+    incMaxProgressBtn_ = new UILabelButton();
+    decMaxProgressBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置条形进度条范围:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(incMinProgressBtn_, "下限+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(decMinProgressBtn_, "下限-", positionX_, positionY_);
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE;
+    SetUpButton(incMaxProgressBtn_, "上限+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(decMaxProgressBtn_, "上限-", positionX_, positionY_);
+}
+
+void UITestBoxProgress::UIKitBoxProgressTestSetValue003()
+{
+    incProgressBtn_ = new UILabelButton();
+    decProgressBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置条形进度条当前值:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(incProgressBtn_, "进度+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(decProgressBtn_, "进度-", positionX_, positionY_);
+}
+
+void UITestBoxProgress::UIKitBoxProgressTestSetImage004()
+{
+    imageBtn_ = new UILabelButton();
+    noImageBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置条形进度条图片:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(imageBtn_, "设置图片", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(noImageBtn_, "取消图片", positionX_, positionY_);
+}
+
+void UITestBoxProgress::UIKitBoxProgressTestSetStyle005()
+{
+    setStyleBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置条形进度条样式:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(setStyleBtn_, "设置样式", positionX_, positionY_);
+}
+
+void UITestBoxProgress::UIKitBoxProgressTestGetStyle006()
+{
+    getStyleBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置条形进度条样式:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(getStyleBtn_, "设置样式", positionX_, positionY_);
+}
+
+void UITestBoxProgress::UIKitBoxProgressTestSetCapType007()
+{
+    roundCapBtn_ = new UILabelButton();
+    noneCapBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置条形进度条端点:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(roundCapBtn_, "圆形端点", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(noneCapBtn_, "方形端点", positionX_, positionY_);
+}
+
+void UITestBoxProgress::UIKitBoxProgressTestSetDirection008()
+{
+    dirL2RBtn_ = new UILabelButton();
+    dirR2LBtn_ = new UILabelButton();
+    dirT2BBtn_ = new UILabelButton();
+    dirB2TBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置条形进度条方向:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(dirL2RBtn_, "从左到右", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(dirR2LBtn_, "从右到左", positionX_, positionY_);
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE;
+    SetUpButton(dirT2BBtn_, "从上到下", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(dirB2TBtn_, "从下到上", positionX_, positionY_);
+}
+
+void UITestBoxProgress::UIKitBoxProgressTestEnableBackground009()
+{
+    enableBgBtn_ = new UILabelButton();
+    disableBgBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置条形进度条背景:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(enableBgBtn_, "设置背景", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(disableBgBtn_, "隐藏背景", positionX_, positionY_);
+}
+
+void UITestBoxProgress::UIKitBoxProgressTestSetStep010()
+{
+    stepBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置条形进度条步长:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(stepBtn_, "步长+", positionX_, positionY_);
+}
+
+void UITestBoxProgress::UIKitBoxProgressTestSetValidSize011()
+{
+    incWidthBtn_ = new UILabelButton();
+    incHeightBtn_ = new UILabelButton();
+    decWidthBtn_ = new UILabelButton();
+    decHeightBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置条形进度条有效区域宽高:", positionX_, positionY_);
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += LABEL_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpButton(incHeightBtn_, "box高度+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE_2;
+    SetUpButton(incWidthBtn_, "box宽度+", positionX_, positionY_);
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += LABEL_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpButton(decHeightBtn_, "box高度-", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE_2;
+    SetUpButton(decWidthBtn_, "box宽度-", positionX_, positionY_);
+}
+
+void UITestBoxProgress::UIKitBoxProgressTestSetBorderAndPadding012()
+{
+    borderIncBtn_ = new UILabelButton();
+    borderDecBtn_ = new UILabelButton();
+    paddingLeftIncBtn_ = new UILabelButton();
+    paddingRightIncBtn_ = new UILabelButton();
+    paddingTopIncBtn_ = new UILabelButton();
+    paddingBottomIncBtn_ = new UILabelButton();
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置边宽和内边距:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(borderIncBtn_, "边宽+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE_2;
+    SetUpButton(borderDecBtn_, "边宽-", positionX_, positionY_);
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpButton(paddingLeftIncBtn_, "左内边距+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE_2;
+    SetUpButton(paddingRightIncBtn_, "右内边距+", positionX_, positionY_);
+    positionX_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpButton(paddingTopIncBtn_, "上内边距+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE_2;
+    SetUpButton(paddingBottomIncBtn_, "下内边距+", positionX_, positionY_);
+}
+
+
+void UITestBoxProgress::SetMoveBtnEvent(UIView& view)
+{
+    static uint16_t progress = 20; // 20: progress
+    static uint16_t step = 0;
+    static uint16_t width = 100; // 100: width
+    static uint16_t height = 10; // 10: height
+    static int16_t min = 0;
+    static int16_t max = 100; // 100: max value
+    if (&view == resetBtn_) {
+        boxProgress_->SetPosition(10, 10, 100, 10); // 10: x 10: y 100: width 15: height
+        progress = 20;                              // 20: progress
+        step = 0;
+        width = 100; // 100: width
+        height = 10; // 10: height
+        min = 0;
+        max = 100; // 100: max value
+        boxProgress_->SetDirection(UIBoxProgress::Direction::DIR_LEFT_TO_RIGHT);
+        boxProgress_->SetValidHeight(height);
+        boxProgress_->SetValidWidth(width);
+        boxProgress_->SetRange(max, min);
+        boxProgress_->SetValue(progress);
+        boxProgress_->SetStep(step);
+        // 182, 191: color
+        boxProgress_->SetBackgroundStyle(STYLE_BACKGROUND_COLOR, Color::GetColorFromRGB(0, 182, 191).full);
+        // 255, 152: color
+        boxProgress_->SetForegroundStyle(STYLE_BACKGROUND_COLOR, Color::GetColorFromRGB(255, 152, 0).full);
+        boxProgress_->SetImage(static_cast<ImageInfo*>(nullptr));
+        boxProgress_->EnableBackground(true);
+        boxProgress_->LayoutCenterOfParent();
+    } else if (&view == incProgressBtn_) {
+        progress++;
+        boxProgress_->SetValue(progress);
+    } else if (&view == decProgressBtn_) {
+        progress--;
+        boxProgress_->SetValue(progress);
+    } else if (&view == stepBtn_) {
+        step++;
+        boxProgress_->SetStep(step);
+    } else if (&view == incWidthBtn_) {
+        width++;
+        boxProgress_->SetValidWidth(width);
+    } else if (&view == incHeightBtn_) {
+        height++;
+        boxProgress_->SetValidHeight(height);
+    } else if (&view == decWidthBtn_) {
+        width--;
+        boxProgress_->SetValidWidth(width);
+    } else if (&view == decHeightBtn_) {
+        height--;
+        boxProgress_->SetValidHeight(height);
+    } else if (&view == incMinProgressBtn_) {
+        min++;
+        boxProgress_->SetRange(boxProgress_->GetRangeMax(), min);
+    } else if (&view == decMinProgressBtn_) {
+        min--;
+        boxProgress_->SetRange(boxProgress_->GetRangeMax(), min);
+    } else if (&view == incMaxProgressBtn_) {
+        max++;
+        boxProgress_->SetRange(max, boxProgress_->GetRangeMin());
+    } else if (&view == decMaxProgressBtn_) {
+        max--;
+        boxProgress_->SetRange(max, boxProgress_->GetRangeMin());
+    } else if (&view == dirL2RBtn_) {
+        width = 100; // 100: width
+        height = 10; // 10: height
+        boxProgress_->Resize(width, height);
+        boxProgress_->SetDirection(UIBoxProgress::Direction::DIR_LEFT_TO_RIGHT);
+        boxProgress_->SetValidHeight(height);
+        boxProgress_->SetValidWidth(width);
+        boxProgress_->LayoutCenterOfParent();
+    } else if (&view == dirR2LBtn_) {
+        width = 100; // 100: width
+        height = 10; // 10: height
+        boxProgress_->Resize(width, height);
+        boxProgress_->SetDirection(UIBoxProgress::Direction::DIR_RIGHT_TO_LEFT);
+        boxProgress_->SetValidHeight(height);
+        boxProgress_->SetValidWidth(width);
+        boxProgress_->LayoutCenterOfParent();
+    } else if (&view == dirT2BBtn_) {
+        width = 10;   // 10: width
+        height = 100; // 100: height
+        boxProgress_->Resize(width, height);
+        boxProgress_->SetDirection(UIBoxProgress::Direction::DIR_TOP_TO_BOTTOM);
+        boxProgress_->SetValidHeight(height);
+        boxProgress_->SetValidWidth(width);
+        boxProgress_->LayoutCenterOfParent();
+    } else if (&view == dirB2TBtn_) {
+        width = 10;   // 10: width
+        height = 100; // 100: height
+        boxProgress_->Resize(width, height);
+        boxProgress_->SetDirection(UIBoxProgress::Direction::DIR_BOTTOM_TO_TOP);
+        boxProgress_->SetValidHeight(height);
+        boxProgress_->SetValidWidth(width);
+        boxProgress_->LayoutCenterOfParent();
+    } else if (&view == imageBtn_) {
+        boxProgress_->SetImage(RES_PATH"red.png", RES_PATH"blue.png");
+    } else if (&view == noImageBtn_) {
+        boxProgress_->SetImage(static_cast<ImageInfo*>(nullptr));
+    }
+}
+
+void UITestBoxProgress::SetStyleBtnEvent(UIView& view)
+{
+    static uint16_t progress = 20; // 20: progress
+    static uint16_t step = 0;
+    static uint16_t width = 100; // 100: width
+    static uint16_t height = 10; // 10: height
+    static int16_t min = 0;
+    static int16_t max = 100; // 100: max value
+    if (&view == setStyleBtn_) {
+        Style style = StyleDefault::GetDefaultStyle();
+        style.bgColor_ = Color::White();
+        boxProgress_->SetBackgroundStyle(style);
+        style.bgColor_ = Color::Blue();
+        boxProgress_->SetForegroundStyle(style);
+    } else if (&view == getStyleBtn_) {
+        boxProgress_->SetBackgroundStyle(STYLE_BACKGROUND_COLOR, Color::White().full);
+        boxProgress_->SetBackgroundStyle(STYLE_BACKGROUND_OPA, 128); // 128: opa
+        boxProgress_->SetForegroundStyle(STYLE_BACKGROUND_COLOR, Color::Blue().full);
+    } else if (&view == roundCapBtn_) {
+        boxProgress_->SetCapType(CapType::CAP_ROUND);
+    } else if (&view == noneCapBtn_) {
+        boxProgress_->SetCapType(CapType::CAP_NONE);
+    } else if (&view == enableBgBtn_) {
+        boxProgress_->EnableBackground(true);
+    } else if (&view == disableBgBtn_) {
+        boxProgress_->EnableBackground(false);
+    } else if (&view == borderIncBtn_) {
+        int64_t bodrderWidth = boxProgress_->GetStyle(STYLE_BORDER_WIDTH);
+        // 20: max width; 5: step
+        bodrderWidth = (bodrderWidth + 5 > 20) ? 20 : (bodrderWidth + 5);
+        boxProgress_->SetStyle(STYLE_BORDER_WIDTH, bodrderWidth);
+    } else if (&view == borderDecBtn_) {
+        int64_t bodrderWidth = boxProgress_->GetStyle(STYLE_BORDER_WIDTH);
+        // 0: min width; 5: step
+        bodrderWidth = (bodrderWidth - 5 < 0) ? 0 : (bodrderWidth - 5);
+        boxProgress_->SetStyle(STYLE_BORDER_WIDTH, bodrderWidth);
+    } else if (&view == paddingLeftIncBtn_) {
+        int64_t paddingWidth = boxProgress_->GetStyle(STYLE_PADDING_LEFT);
+        // 20: max width; 5: step
+        paddingWidth = (paddingWidth + 5 > 20) ? 20 : (paddingWidth + 5);
+        boxProgress_->SetStyle(STYLE_PADDING_LEFT, paddingWidth);
+    } else if (&view == paddingRightIncBtn_) {
+        int64_t paddingWidth = boxProgress_->GetStyle(STYLE_PADDING_RIGHT);
+        // 20: max width; 5: step
+        paddingWidth = (paddingWidth + 5 > 20) ? 20 : (paddingWidth + 5);
+        boxProgress_->SetStyle(STYLE_PADDING_RIGHT, paddingWidth);
+    } else if (&view == paddingTopIncBtn_) {
+        int64_t paddingWidth = boxProgress_->GetStyle(STYLE_PADDING_TOP);
+        // 20: max width; 5: step
+        paddingWidth = (paddingWidth + 5 > 20) ? 20 : (paddingWidth + 5);
+        boxProgress_->SetStyle(STYLE_PADDING_TOP, paddingWidth);
+    } else if (&view == paddingBottomIncBtn_) {
+        int64_t paddingWidth = boxProgress_->GetStyle(STYLE_PADDING_BOTTOM);
+        // 20: max width; 5: step
+        paddingWidth = (paddingWidth + 5 > 20) ? 20 : (paddingWidth + 5);
+        boxProgress_->SetStyle(STYLE_PADDING_BOTTOM, paddingWidth);
+    }
+}
+
+bool UITestBoxProgress::OnClick(UIView& view, const ClickEvent& event)
+{
+    SetMoveBtnEvent(view);
+    SetStyleBtnEvent(view);
+    container_->Invalidate();
+    return true;
+}
+
+} // namespace OHOS
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_progress_bar/ui_test_box_progress.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_progress_bar/ui_test_box_progress.h
new file mode 100644 (file)
index 0000000..c87910e
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_BOX_PROGRESS_H
+#define UI_TEST_BOX_PROGRESS_H
+
+#include "components/ui_box_progress.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestBoxProgress : public UITest, public UIView::OnClickListener {
+public:
+    UITestBoxProgress() {}
+    ~UITestBoxProgress() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    void SetUpButton(UILabelButton* btn, const char* title, int16_t x, int16_t y);
+    void SetUpLabel(const char* title, int16_t x, int16_t y) const;
+    void SetStyleBtnEvent(UIView& view);
+    void SetMoveBtnEvent(UIView& view);
+
+    bool OnClick(UIView& view, const ClickEvent& event) override;
+
+    void UIKitBoxProgressTestUIBoxProgress001();
+    void UIKitBoxProgressTestSetRange002();
+    void UIKitBoxProgressTestSetValue003();
+    void UIKitBoxProgressTestSetImage004();
+    void UIKitBoxProgressTestSetStyle005();
+    void UIKitBoxProgressTestGetStyle006();
+    void UIKitBoxProgressTestSetCapType007();
+    void UIKitBoxProgressTestSetDirection008();
+    void UIKitBoxProgressTestEnableBackground009();
+    void UIKitBoxProgressTestSetStep010();
+    void UIKitBoxProgressTestSetValidSize011();
+    void UIKitBoxProgressTestSetBorderAndPadding012();
+
+private:
+    UIScrollView* container_ = nullptr;
+    UIScrollView* scroll_ = nullptr;
+    UIBoxProgress* boxProgress_ = nullptr;
+    UIViewGroup* uiViewGroupFrame_ = nullptr;
+
+    UILabelButton* resetBtn_ = nullptr;
+    UILabelButton* incWidthBtn_ = nullptr;
+    UILabelButton* incHeightBtn_ = nullptr;
+    UILabelButton* decWidthBtn_ = nullptr;
+    UILabelButton* decHeightBtn_ = nullptr;
+    UILabelButton* incProgressBtn_ = nullptr;
+    UILabelButton* decProgressBtn_ = nullptr;
+    UILabelButton* incMinProgressBtn_ = nullptr;
+    UILabelButton* decMinProgressBtn_ = nullptr;
+    UILabelButton* incMaxProgressBtn_ = nullptr;
+    UILabelButton* decMaxProgressBtn_ = nullptr;
+    UILabelButton* stepBtn_ = nullptr;
+    UILabelButton* dirL2RBtn_ = nullptr;
+    UILabelButton* dirR2LBtn_ = nullptr;
+    UILabelButton* dirT2BBtn_ = nullptr;
+    UILabelButton* dirB2TBtn_ = nullptr;
+    UILabelButton* imageBtn_ = nullptr;
+    UILabelButton* noImageBtn_ = nullptr;
+    UILabelButton* setStyleBtn_ = nullptr;
+    UILabelButton* getStyleBtn_ = nullptr;
+    UILabelButton* roundCapBtn_ = nullptr;
+    UILabelButton* noneCapBtn_ = nullptr;
+    UILabelButton* enableBgBtn_ = nullptr;
+    UILabelButton* disableBgBtn_ = nullptr;
+    UILabelButton* borderIncBtn_ = nullptr;
+    UILabelButton* borderDecBtn_ = nullptr;
+    UILabelButton* paddingLeftIncBtn_ = nullptr;
+    UILabelButton* paddingRightIncBtn_ = nullptr;
+    UILabelButton* paddingTopIncBtn_ = nullptr;
+    UILabelButton* paddingBottomIncBtn_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_BOX_PROGRESS_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_progress_bar/ui_test_circle_progress.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_progress_bar/ui_test_circle_progress.cpp
new file mode 100644 (file)
index 0000000..cc9a39a
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_circle_progress.h"
+#include "common/screen.h"
+#include "components/ui_label.h"
+
+namespace OHOS {
+namespace {
+const int16_t LABEL_HEIGHT = 29;
+const int16_t BUTTON_WIDTH = 120;
+const int16_t BUTTON_HEIGHT = 40;
+const int16_t DELTA_X_COORDINATE = 8;
+const int16_t DELTA_X_COORDINATE_2 = 336;
+const int16_t DELTA_Y_COORDINATE = 12;
+const int16_t DELTA_Y_COORDINATE_2 = 19;
+const int16_t GROUP_WIDTH = 230;
+const int16_t GROUP_HEIGHT = 300;
+const int16_t MARGIN_TOP = 50;
+} // namespace
+
+void UITestCircleProgress::SetUp()
+{
+    if (container_ == nullptr) {
+        positionX_ = 0;
+        positionY_ = 0;
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        UIViewGroup* uiViewGroup = new UIViewGroup();
+        uiViewGroup->SetPosition(positionX_, positionY_ + 20, GROUP_WIDTH, GROUP_HEIGHT); // 20: gap
+        container_->Add(uiViewGroup);
+        UILabel* label = new UILabel();
+        uiViewGroup->Add(label);
+        label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE,
+            TEXT_DISTANCE_TO_TOP_SIDE + MARGIN_TOP, 200, MARGIN_TOP); // 200:width
+        label->SetText("CircleProgress");
+        label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+        uiViewGroupFrame_ = new UIViewGroup();
+        uiViewGroup->Add(uiViewGroupFrame_);
+        uiViewGroupFrame_->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE2,
+            VIEW_DISTANCE_TO_TOP_SIDE + MARGIN_TOP, 180, 190); // 180:width 190: height
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_COLOR, Color::White().full);
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_OPA, HALF_OPA_OPAQUE);
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_WIDTH, VIEW_STYLE_BORDER_WIDTH);
+        uiViewGroupFrame_->SetStyle(STYLE_BORDER_RADIUS, VIEW_STYLE_BORDER_RADIUS);
+        uiViewGroupFrame_->SetStyle(STYLE_BACKGROUND_OPA, 0);
+
+        circleProgress_ = new UICircleProgress();
+        circleProgress_->SetPosition(0, 0, 150, 150);    // 150:width 150: height
+        circleProgress_->SetCenterPosition(75, 75);        // 75: position x 75: position y
+        circleProgress_->SetRadius(50);                    // 50: radius
+        circleProgress_->SetValue(20);                     // 20: value
+        circleProgress_->SetStyle(STYLE_PADDING_LEFT, 10); // 10: value
+        circleProgress_->SetStyle(STYLE_PADDING_TOP, 5);   // 5: value
+        uiViewGroupFrame_->Add(circleProgress_);
+        circleProgress_->LayoutCenterOfParent();
+    }
+
+    if (scroll_ == nullptr) {
+        scroll_ = new UIScrollView();
+        scroll_->SetPosition(210, 11);                      // 210: x-coordinate; 11: y-coordinate
+        scroll_->Resize(305, container_->GetHeight() - 11); // 305: width; // 11: decrease height
+        container_->Add(scroll_);
+        positionY_ = 0;
+    }
+}
+
+void UITestCircleProgress::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+    circleProgress_ = nullptr;
+    scroll_ = nullptr;
+}
+
+const UIView* UITestCircleProgress::GetTestView()
+{
+    UIKitCircleProgressTestUICircleProgress001();
+    UIKitCircleProgressTestSetValue002();
+    UIKitCircleProgressTestSetImage003();
+    UIKitCircleProgressTestSetStyle004();
+    UIKitCircleProgressTestGetStyle005();
+    UIKitCircleProgressTestSetCapType006();
+    UIKitCircleProgressTestSetStep007();
+    UIKitCircleProgressTestSetRange008();
+    UIKitCircleProgressTestEnableBackground009();
+    UIKitCircleProgressTestSetCenter010();
+    UIKitCircleProgressTestSetRadius011();
+    UIKitCircleProgressTestSetLineWidth012();
+    UIKitCircleProgressTestSetImagePosition013();
+    UIKitCircleProgressTestSetLineColor014();
+    UIKitCircleProgressTestSetAngle015();
+
+    return container_;
+}
+
+void UITestCircleProgress::SetUpLabel(const char* title, int16_t x, int16_t y) const
+{
+    UILabel* label = new UILabel();
+    scroll_->Add(label);
+    label->SetPosition(x, y, 288, 30); // 288: width; 30: height
+    label->SetText(title);
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+}
+void UITestCircleProgress::SetUpButton(UILabelButton* btn, const char* title, int16_t x, int16_t y)
+{
+    if (btn == nullptr) {
+        return;
+    }
+    scroll_->Add(btn);
+    btn->SetPosition(x, y, BUTTON_WIDHT2, BUTTON_HEIGHT2);
+    btn->SetText(title);
+    btn->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
+    btn->SetOnClickListener(this);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+    scroll_->Invalidate();
+}
+
+void UITestCircleProgress::UIKitCircleProgressTestUICircleProgress001()
+{
+    resetBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ = 0;
+    SetUpLabel("创建环形进度条:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(resetBtn_, "重置", positionX_, positionY_);
+}
+
+void UITestCircleProgress::UIKitCircleProgressTestSetValue002()
+{
+    incProgressBtn_ = new UILabelButton();
+    decProgressBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置环形进度条当前值:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(incProgressBtn_, "进度+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(decProgressBtn_, "进度-", positionX_, positionY_);
+}
+
+void UITestCircleProgress::UIKitCircleProgressTestSetImage003()
+{
+    imageBtn_ = new UILabelButton();
+    noImageBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置环形进度条图片:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(imageBtn_, "设置图片", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(noImageBtn_, "取消图片", positionX_, positionY_);
+}
+
+void UITestCircleProgress::UIKitCircleProgressTestSetStyle004()
+{
+    setStyleBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置环形进度条样式:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(setStyleBtn_, "设置样式", positionX_, positionY_);
+}
+
+void UITestCircleProgress::UIKitCircleProgressTestGetStyle005()
+{
+    getStyleBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置环形进度条样式:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(getStyleBtn_, "设置样式", positionX_, positionY_);
+}
+
+void UITestCircleProgress::UIKitCircleProgressTestSetCapType006()
+{
+    roundCapBtn_ = new UILabelButton();
+    noneCapBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置环形进度条端点:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(roundCapBtn_, "圆形端点", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(noneCapBtn_, "方形端点", positionX_, positionY_);
+}
+
+void UITestCircleProgress::UIKitCircleProgressTestSetStep007()
+{
+    stepBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置环形进度条步长:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(stepBtn_, "步长+", positionX_, positionY_);
+}
+
+void UITestCircleProgress::UIKitCircleProgressTestSetRange008()
+{
+    incMinProgressBtn_ = new UILabelButton();
+    decMinProgressBtn_ = new UILabelButton();
+    incMaxProgressBtn_ = new UILabelButton();
+    decMaxProgressBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置环形进度条范围:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(incMinProgressBtn_, "下限+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(decMinProgressBtn_, "下限-", positionX_, positionY_);
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE;
+    SetUpButton(incMaxProgressBtn_, "上限+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(decMaxProgressBtn_, "上限-", positionX_, positionY_);
+}
+
+void UITestCircleProgress::UIKitCircleProgressTestEnableBackground009()
+{
+    enableBgBtn_ = new UILabelButton();
+    disableBgBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("环形进度条隐藏背景:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(enableBgBtn_, "设置背景", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(disableBgBtn_, "隐藏背景", positionX_, positionY_);
+}
+
+void UITestCircleProgress::UIKitCircleProgressTestSetCenter010()
+{
+    centerXBtn_ = new UILabelButton();
+    centerYBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置环形进度条圆心:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(centerXBtn_, "圆心X+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(centerYBtn_, "圆心Y+", positionX_, positionY_);
+}
+
+void UITestCircleProgress::UIKitCircleProgressTestSetRadius011()
+{
+    incRadiusBtn_ = new UILabelButton();
+    decRadiusBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置环形进度条半径:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(incRadiusBtn_, "半径+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(decRadiusBtn_, "半径-", positionX_, positionY_);
+}
+
+void UITestCircleProgress::UIKitCircleProgressTestSetLineWidth012()
+{
+    incWidthBtn_ = new UILabelButton();
+    decWidthBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置环形进度条线宽:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(incWidthBtn_, "线宽+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(decWidthBtn_, "线宽-", positionX_, positionY_);
+}
+
+void UITestCircleProgress::UIKitCircleProgressTestSetImagePosition013()
+{
+    imgPosXBtn_ = new UILabelButton();
+    imgPosYBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置环形进度条图片位置:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(imgPosXBtn_, "图片X+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(imgPosYBtn_, "图片Y+", positionX_, positionY_);
+}
+
+void UITestCircleProgress::UIKitCircleProgressTestSetLineColor014()
+{
+    lineColorBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置环形进度条前景线条颜色: ", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(lineColorBtn_, "前景绿色", positionX_, positionY_);
+}
+
+void UITestCircleProgress::UIKitCircleProgressTestSetAngle015()
+{
+    incStartAngleBtn_ = new UILabelButton();
+    decStartAngleBtn_ = new UILabelButton();
+    incEndAngleBtn_ = new UILabelButton();
+    decEndAngleBtn_ = new UILabelButton();
+    swapAngleBtn_ = new UILabelButton();
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE_2;
+    SetUpLabel("设置环形进度条角度:", positionX_, positionY_);
+    positionY_ += LABEL_HEIGHT + DELTA_X_COORDINATE;
+    SetUpButton(incStartAngleBtn_, "起始角度+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + VIEW_DISTANCE_TO_LEFT_SIDE2;
+    SetUpButton(decStartAngleBtn_, "起始角度-", positionX_, positionY_);
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE;
+    SetUpButton(incEndAngleBtn_, "结束角度+", positionX_, positionY_);
+    positionX_ += BUTTON_WIDTH + DELTA_Y_COORDINATE;
+    SetUpButton(decEndAngleBtn_, "结束角度-", positionX_, positionY_);
+    positionX_ = VIEW_DISTANCE_TO_LEFT_SIDE2;
+    positionY_ += BUTTON_HEIGHT + DELTA_Y_COORDINATE;
+    SetUpButton(swapAngleBtn_, "转换方向", positionX_, positionY_);
+}
+
+void UITestCircleProgress::SetBtnEvent1(const UIView& view,
+    uint16_t& progress,
+    uint16_t& step,
+    int16_t& min,
+    int16_t& max)
+{
+    if (&view == incProgressBtn_) {
+        progress++;
+        circleProgress_->SetValue(progress);
+    } else if (&view == decProgressBtn_) {
+        progress--;
+        circleProgress_->SetValue(progress);
+    } else if (&view == stepBtn_) {
+        step++;
+        circleProgress_->SetStep(step);
+    } else if (&view == incMinProgressBtn_) {
+        min++;
+        circleProgress_->SetRange(circleProgress_->GetRangeMax(), min);
+    } else if (&view == decMinProgressBtn_) {
+        min--;
+        circleProgress_->SetRange(circleProgress_->GetRangeMax(), min);
+    } else if (&view == incMaxProgressBtn_) {
+        max++;
+        circleProgress_->SetRange(max, circleProgress_->GetRangeMin());
+    } else if (&view == decMaxProgressBtn_) {
+        max--;
+        circleProgress_->SetRange(max, circleProgress_->GetRangeMin());
+    }
+}
+
+void UITestCircleProgress::SetBtnEvent2(const UIView& view,
+    Point& center,
+    Point& imgPos,
+    int16_t& startAngle,
+    int16_t& endAngle)
+{
+    if (&view == incStartAngleBtn_) {
+        startAngle++;
+        circleProgress_->SetStartAngle(startAngle);
+    } else if (&view == decStartAngleBtn_) {
+        startAngle--;
+        circleProgress_->SetStartAngle(startAngle);
+    } else if (&view == incEndAngleBtn_) {
+        endAngle++;
+        circleProgress_->SetEndAngle(endAngle);
+    } else if (&view == decEndAngleBtn_) {
+        endAngle--;
+        circleProgress_->SetEndAngle(endAngle);
+    } else if (&view == swapAngleBtn_) {
+        int16_t angle = startAngle;
+        startAngle = endAngle;
+        endAngle = angle;
+        circleProgress_->SetStartAngle(startAngle);
+        circleProgress_->SetEndAngle(endAngle);
+    } else if (&view == centerXBtn_) {
+        center.x++;
+        circleProgress_->SetCenterPosition(center.x, circleProgress_->GetCenterPosition().y);
+    } else if (&view == centerYBtn_) {
+        center.y++;
+        circleProgress_->SetCenterPosition(circleProgress_->GetCenterPosition().x, center.y);
+    } else if (&view == imgPosXBtn_) {
+        imgPos.x++;
+        circleProgress_->SetBackgroundImagePosition(imgPos.x, imgPos.y);
+        circleProgress_->SetProgressImagePosition(imgPos.x, imgPos.y);
+    } else if (&view == imgPosXBtn_) {
+        imgPos.y++;
+        circleProgress_->SetBackgroundImagePosition(imgPos.x, imgPos.y);
+        circleProgress_->SetProgressImagePosition(imgPos.x, imgPos.y);
+    }
+}
+
+void UITestCircleProgress::SetBtnEvent3(const UIView& view, int16_t& radius)
+{
+    if (&view == imageBtn_) {
+        circleProgress_->SetImage(RES_PATH"red.png", RES_PATH"blue.png");
+    } else if (&view == noImageBtn_) {
+        circleProgress_->SetImage(static_cast<ImageInfo*>(nullptr));
+    } else if (&view == setStyleBtn_) {
+        Style style = StyleDefault::GetDefaultStyle();
+        style.lineColor_ = Color::White();
+        circleProgress_->SetBackgroundStyle(style);
+        style.lineColor_ = Color::Blue();
+        circleProgress_->SetForegroundStyle(style);
+    } else if (&view == getStyleBtn_) {
+        circleProgress_->SetBackgroundStyle(STYLE_LINE_COLOR, Color::Red().full);
+        circleProgress_->SetForegroundStyle(STYLE_LINE_COLOR, Color::Yellow().full);
+    } else if (&view == roundCapBtn_) {
+        circleProgress_->SetCapType(CapType::CAP_ROUND);
+    } else if (&view == noneCapBtn_) {
+        circleProgress_->SetCapType(CapType::CAP_NONE);
+    } else if (&view == lineColorBtn_) {
+        circleProgress_->SetLineColor(Color::Green());
+    } else if (&view == incWidthBtn_) {
+        circleProgress_->SetBackgroundStyle(STYLE_LINE_WIDTH,
+                                            circleProgress_->GetBackgroundStyle(STYLE_LINE_WIDTH) + 1);
+        circleProgress_->SetForegroundStyle(STYLE_LINE_WIDTH,
+                                            circleProgress_->GetForegroundStyle(STYLE_LINE_WIDTH) + 1);
+    } else if (&view == decWidthBtn_) {
+        circleProgress_->SetBackgroundStyle(STYLE_LINE_WIDTH,
+                                            circleProgress_->GetBackgroundStyle(STYLE_LINE_WIDTH) - 1);
+        circleProgress_->SetForegroundStyle(STYLE_LINE_WIDTH,
+                                            circleProgress_->GetForegroundStyle(STYLE_LINE_WIDTH) - 1);
+    } else if (&view == enableBgBtn_) {
+        circleProgress_->EnableBackground(true);
+    } else if (&view == disableBgBtn_) {
+        circleProgress_->EnableBackground(false);
+    } else if (&view == incRadiusBtn_) {
+        radius++;
+        circleProgress_->SetRadius(radius);
+    } else if (&view == decRadiusBtn_) {
+        radius--;
+        circleProgress_->SetRadius(radius);
+    }
+}
+
+bool UITestCircleProgress::OnClick(UIView& view, const ClickEvent& event)
+{
+    static uint16_t progress = 20; // 20: progress
+    static uint16_t step = 0;
+    static uint16_t width = 150;  // 150: width
+    static uint16_t height = 150; // 150: height
+    static int16_t min = 0;
+    static int16_t max = 100;       // 100: max value
+    static Point center = {75, 75}; // 75: position x 75: position y
+    static Point imgPos = {0, 0};
+    static int16_t startAngle = 0;
+    static int16_t endAngle = 360; // 360: end angle
+    static int16_t radius = 50;    // 50: radius
+
+    if (&view == resetBtn_) {
+        circleProgress_->SetPosition(10, 10, 150, 150); // 10: x 10: y 150: width 150: height
+        progress = 100;                                 // 100 progress
+        step = 0;
+        width = 150;  // 150: width
+        height = 150; // 150: height
+        min = 0;
+        max = 100;         // 100: max value
+        center = {75, 75}; // 75: position x 75: position y
+        startAngle = 0;
+        endAngle = 360; // 360: end angle
+        radius = 50;    // 50: radius
+        imgPos = {0, 0};
+
+        circleProgress_->SetRange(max, min);
+        circleProgress_->SetValue(progress);
+        circleProgress_->SetCenterPosition(center.x, center.y);
+        circleProgress_->SetRadius(radius);
+        circleProgress_->SetStartAngle(startAngle);
+        circleProgress_->SetEndAngle(endAngle);
+        circleProgress_->SetStep(step);
+        circleProgress_->SetBackgroundStyle(StyleDefault::GetProgressBackgroundStyle());
+        circleProgress_->SetForegroundStyle(StyleDefault::GetProgressForegroundStyle());
+        circleProgress_->SetLineColor(Color::Red());
+        circleProgress_->SetForegroundStyle(STYLE_LINE_WIDTH, 40); // 40: value
+        circleProgress_->SetForegroundStyle(STYLE_LINE_OPA, 127);  // 127: value
+        circleProgress_->SetBackgroundImagePosition(imgPos.x, imgPos.y);
+        circleProgress_->SetProgressImagePosition(imgPos.x, imgPos.y);
+        circleProgress_->SetImage(static_cast<ImageInfo*>(nullptr));
+        circleProgress_->EnableBackground(false);
+        circleProgress_->LayoutCenterOfParent();
+    }
+    SetBtnEvent1(view, progress, step, min, max);
+    SetBtnEvent2(view, center, imgPos, startAngle, endAngle);
+    SetBtnEvent3(view, radius);
+    container_->Invalidate();
+    return true;
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_progress_bar/ui_test_circle_progress.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_progress_bar/ui_test_circle_progress.h
new file mode 100644 (file)
index 0000000..96b95cd
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_CIRCLE_PROGRESS_H
+#define UI_TEST_CIRCLE_PROGRESS_H
+
+#include "components/ui_circle_progress.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestCircleProgress : public UITest, public UIView::OnClickListener {
+public:
+    UITestCircleProgress() {}
+    ~UITestCircleProgress() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    void SetUpButton(UILabelButton* btn, const char* title, int16_t x, int16_t y);
+    void SetUpLabel(const char* title, int16_t x, int16_t y) const;
+    void SetBtnEvent1(const UIView& view, uint16_t& progress, uint16_t& step, int16_t& min, int16_t& max);
+    void SetBtnEvent2(const UIView& view, Point& center, Point& imgPos, int16_t& startAngle, int16_t& endAngle);
+    void SetBtnEvent3(const UIView& view, int16_t& radius);
+    void SetMoveBtnEvent(UIView& view);
+    bool OnClick(UIView& view, const ClickEvent& event) override;
+
+    void UIKitCircleProgressTestUICircleProgress001();
+    void UIKitCircleProgressTestSetValue002();
+    void UIKitCircleProgressTestSetImage003();
+    void UIKitCircleProgressTestSetStyle004();
+    void UIKitCircleProgressTestGetStyle005();
+    void UIKitCircleProgressTestSetCapType006();
+    void UIKitCircleProgressTestSetStep007();
+    void UIKitCircleProgressTestSetRange008();
+    void UIKitCircleProgressTestEnableBackground009();
+    void UIKitCircleProgressTestSetCenter010();
+    void UIKitCircleProgressTestSetRadius011();
+    void UIKitCircleProgressTestSetLineWidth012();
+    void UIKitCircleProgressTestSetImagePosition013();
+    void UIKitCircleProgressTestSetLineColor014();
+    void UIKitCircleProgressTestSetAngle015();
+
+private:
+    UIScrollView* container_ = nullptr;
+    UIScrollView* scroll_ = nullptr;
+    UICircleProgress* circleProgress_ = nullptr;
+    UIViewGroup* uiViewGroupFrame_ = nullptr;
+
+    UILabelButton* resetBtn_ = nullptr;
+    UILabelButton* incProgressBtn_ = nullptr;
+    UILabelButton* decProgressBtn_ = nullptr;
+    UILabelButton* incMinProgressBtn_ = nullptr;
+    UILabelButton* decMinProgressBtn_ = nullptr;
+    UILabelButton* incMaxProgressBtn_ = nullptr;
+    UILabelButton* decMaxProgressBtn_ = nullptr;
+    UILabelButton* centerXBtn_ = nullptr;
+    UILabelButton* centerYBtn_ = nullptr;
+    UILabelButton* incRadiusBtn_ = nullptr;
+    UILabelButton* decRadiusBtn_ = nullptr;
+    UILabelButton* incWidthBtn_ = nullptr;
+    UILabelButton* decWidthBtn_ = nullptr;
+    UILabelButton* incStartAngleBtn_ = nullptr;
+    UILabelButton* decStartAngleBtn_ = nullptr;
+    UILabelButton* incEndAngleBtn_ = nullptr;
+    UILabelButton* decEndAngleBtn_ = nullptr;
+    UILabelButton* swapAngleBtn_ = nullptr;
+    UILabelButton* stepBtn_ = nullptr;
+    UILabelButton* imageBtn_ = nullptr;
+    UILabelButton* noImageBtn_ = nullptr;
+    UILabelButton* setStyleBtn_ = nullptr;
+    UILabelButton* getStyleBtn_ = nullptr;
+    UILabelButton* roundCapBtn_ = nullptr;
+    UILabelButton* noneCapBtn_ = nullptr;
+    UILabelButton* enableBgBtn_ = nullptr;
+    UILabelButton* disableBgBtn_ = nullptr;
+    UILabelButton* imgPosXBtn_ = nullptr;
+    UILabelButton* imgPosYBtn_ = nullptr;
+    UILabelButton* lineColorBtn_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_CIRCLE_PROGRESS_H
index 17278af..3a22c30 100644 (file)
@@ -27,6 +27,7 @@ const int16_t QRCODE_HEIGHT = 250;
 const int16_t GROUP_HEIGHT_100 = 100;\r
 const int16_t GROUP_HEIGHT_300 = 300;\r
 const int16_t LAYOUT_OFFSET = 10;\r
+const int16_t CONTAINER_Y = 100;\r
 } // namespace\r
 \r
 void UITestQrcode::SetUp()\r
@@ -35,7 +36,8 @@ void UITestQrcode::SetUp()
         container_ = new UIScrollView();\r
         container_->SetThrowDrag(true);\r
         container_->SetHorizontalScrollState(false);\r
-        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight());\r
+        container_->SetPosition(0, CONTAINER_Y);\r
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - CONTAINER_Y);\r
     }\r
 }\r
 \r
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_render/ui_test_render.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_render/ui_test_render.cpp
new file mode 100644 (file)
index 0000000..09bac6e
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_render.h"
+
+#include "common/screen.h"
+
+namespace OHOS {
+    namespace {
+    const uint16_t LABEL_HEIGHT = 60;
+    const uint16_t DEFAULT_WIDITH = 200;
+    const uint16_t DEFAULT_WIDITH1 = 550;
+    const uint16_t DEFAULT_HEIGHT = 40;
+    const uint16_t offsetX = 50;
+    const uint16_t offsetY = 50;
+    const uint16_t x_position1 = 20;
+    const uint16_t x_position = 50;
+    const uint16_t y_position = 80;
+    const uint16_t w_position = 100;
+    const uint16_t h_position = 50;
+    const uint16_t fontSize = 15;
+}
+void UITestRender::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+    }
+}
+
+void UITestRender::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+}
+
+const UIView* UITestRender::GetTestView()
+{
+    UIKitRenderTestRender001();
+    UIKitRenderTestRenderMeasure001();
+    return container_;
+}
+
+class TestRenderClickListener : public UIView::OnClickListener {
+public:
+    bool OnClick(UIView& view, const ClickEvent& event) override
+    {
+        static uint8_t r = 20;
+        static uint8_t g = 120;
+        static uint8_t b = 50;
+        view.SetStyle(STYLE_BACKGROUND_COLOR, Color::GetColorFromRGB(r, g, b).full);
+        view.Invalidate();
+
+        r = r + 30; // 30: red add
+        g = g + 30; // 30: green add
+        b = b + 30; // 30: blue add
+        return true;
+    }
+};
+
+UIViewGroup* UITestRender::CreateTestCaseGroup() const
+{
+    UIViewGroup* group = new UIViewGroup();
+    group->Resize(Screen::GetInstance().GetWidth(), DEFAULT_WIDITH); // 200: height
+    return group;
+}
+
+UILabel* UITestRender::CreateTitleLabel() const
+{
+    UILabel* label = new UILabel();
+    // 216: label width
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, TEXT_DISTANCE_TO_TOP_SIDE, 216, TITLE_LABEL_DEFAULT_HEIGHT);
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    return label;
+}
+
+void UITestRender::UIKitRenderTestRender001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UILabel* label1 = CreateTitleLabel();
+    container_->Add(label1);
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKit_Render_Test_Render_001");
+    group->SetPosition(x_position1, h_position);
+    
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    label->SetText("UIKit绘制效果:");
+
+    UIView* view = new UIView();
+    view->Resize(DEFAULT_WIDITH, DEFAULT_HEIGHT);     // 200: width 50: height
+    view->SetPosition(x_position, y_position); // 50: position x 50: position y
+    view->SetStyle(STYLE_BACKGROUND_COLOR, Color::Yellow().full);
+    group->Add(view);
+    view->SetTouchable(true);
+    view->SetOnClickListener(new TestRenderClickListener());
+
+    UIView* view1 = new UIView();
+    view1->Resize(w_position, h_position);      // 100: width 50: height
+    view1->SetPosition(x_position, y_position + offsetY); // 50: position x 120: position y
+    view1->SetStyle(STYLE_BACKGROUND_COLOR, Color::Green().full);
+    view1->SetTouchable(true);
+    view1->SetOnClickListener(new TestRenderClickListener());
+    group->Add(view1);
+    container_->Add(group);
+}
+
+void UITestRender::UIKitRenderTestRenderMeasure001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKit_Render_Test_RenderMeasure_001");
+    container_->Add(group);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    // 2: half of screen width
+    label->Resize(Screen::GetInstance().GetWidth() / 2, TITLE_LABEL_DEFAULT_HEIGHT);
+    label->SetText("UIKit绘制Measure效果:");
+
+    testLabel_ = new UILabel();
+    group->Add(testLabel_);
+    testLabel_->SetPosition(x_position, offsetY);
+    testLabel_->Resize(w_position + offsetX, w_position); // 150: width 80: height
+    testLabel_->SetViewId("label_text");
+    testLabel_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    testLabel_->SetLineBreakMode(UILabel::LINE_BREAK_WRAP);
+    testLabel_->SetText("示例文字,示例文字");
+
+    labelButton_ = new UILabelButton();
+    group->Add(labelButton_);
+    labelButton_->Resize(BUTTON_WIDHT3, BUTTON_HEIGHT3);
+    labelButton_->SetText("更新label");
+    labelButton_->SetViewId(UI_TEST_RENDER_UPDATA_BUTTON_ID_01);
+    labelButton_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    labelButton_->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+    labelButton_->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+    labelButton_->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+    labelButton_->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_PRESS, UIButton::PRESSED);
+    labelButton_->SetPosition(DEFAULT_WIDITH + offsetX, DEFAULT_WIDITH1);
+    labelButton_->SetOnClickListener(this);
+    labelButton_->LayoutBottomToSibling("label_text"); // 10: offset
+    group->LayoutBottomToSibling("UIKit_Render_Test_Render_001", 10); // 10: offset
+}
+
+bool UITestRender::OnClick(UIView& view, const ClickEvent& event)
+{
+    if (&view == labelButton_) {
+        testLabel_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, fontSize); // 18: font size
+    }
+    return true;
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_render/ui_test_render.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_render/ui_test_render.h
new file mode 100644 (file)
index 0000000..9ef3c44
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_RENDER_H
+#define UI_TEST_RENDER_H
+
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "ui_test.h"
+
+namespace OHOS {
+constexpr char* UI_TEST_RENDER_ID = "Render";
+constexpr char* UI_TEST_RENDER_UPDATA_BUTTON_ID_01 = "test_render_updata_buttin_01";
+
+class UITestRender : public UITest, public UIView::OnClickListener {
+public:
+    UITestRender() : container_(nullptr) {}
+    ~UITestRender() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    bool OnClick(UIView& view, const ClickEvent& event) override;
+
+    /**
+     * @brief Test render Function
+     */
+    void UIKitRenderTestRender001();
+
+    /**
+     * @brief Test render measure Function
+     */
+    void UIKitRenderTestRenderMeasure001();
+
+private:
+    UIViewGroup* CreateTestCaseGroup() const;
+    UILabel* CreateTitleLabel() const;
+    UIScrollView* container_ = nullptr;
+    UILabel* testLabel_ = nullptr;
+    UILabelButton* labelButton_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_RENDER_H
index 3ee280d..7aff261 100644 (file)
@@ -47,15 +47,15 @@ bool UITestRollerView::ChildStateListener::StateChange(UIView* view, float angle
     UIViewGroup* group = dynamic_cast<UIViewGroup*>(view);
     UIImageView* head = dynamic_cast<UIImageView*>(group->GetChildrenHead());
     UIImageView* tail = dynamic_cast<UIImageView*>(group->GetChildrenTail());
-    if (FloatMore(angle, 90.0f) && FloatLess(angle, 270.0f)) { // 90 270: rotate range
-        head->SetStyle(STYLE_IMAGE_OPA, OPA_OPAQUE / 2); // 2: half of opa
+    if (FloatMore(angle, 90.0f) && FloatLess(angle, 270.0f)) { // 90 270:rotate range
+        head->SetStyle(STYLE_IMAGE_OPA, OPA_OPAQUE / 2); // 2: hald of opa
         if (roller_->IsShowMirrorMode()) {
-            tail->SetStyle(STYLE_IMAGE_OPA, 50); // 50: Transparency Value
+            tail->SetStyle(STYLE_IMAGE_OPA, 50); // 50: hald of opa
         }
     } else {
         head->SetStyle(STYLE_IMAGE_OPA, OPA_OPAQUE);
         if (roller_->IsShowMirrorMode()) {
-            tail->SetStyle(STYLE_IMAGE_OPA, 100); // 100: Transparency Value
+            tail->SetStyle(STYLE_IMAGE_OPA, 100); // 100: hald of opa
         }
     }
     return true;
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_rotate_input/ui_test_rotate_input.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_rotate_input/ui_test_rotate_input.cpp
new file mode 100644 (file)
index 0000000..0e2b80d
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_rotate_input.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "cstdio"
+#include "dock/focus_manager.h"
+#include "dock/vibrator_manager.h"
+#include "engines/gfx/gfx_engine_manager.h"
+
+#if ENABLE_ROTATE_INPUT
+namespace OHOS {
+static int16_t g_blank = 40;
+static int16_t g_listW = 200;
+static int16_t g_listH = 400;
+static int16_t g_scrollH = 200;
+static int16_t g_scrollW = 300;
+static int16_t g_buttonH = 500;
+static int16_t g_buttonW = 500;
+static int16_t g_smallButtonH = 60;
+static int16_t g_smallButtonW = 150;
+static int16_t g_swipeH = 200;
+static int16_t g_swipeW = 400;
+static int16_t g_sliderW = 40;
+static int16_t g_sliderH = 300;
+static int16_t g_testButtonW = 80;
+static int16_t g_testButtonH = 40;
+static int16_t g_testx = 150;
+static int16_t g_testy = 40;
+static int16_t g_offset = 200;
+static int16_t g_height = 50;
+static int16_t g_blank1 = 260;
+static int16_t g_size = 15;
+static const char* g_pickerRange[] = {"A0", "B1", "C2", "D3", "E4", "F5", "G6", "H7", "I8", "J9", "K10", "L11"};
+
+#if ENABLE_VIBRATOR
+void Print(VibratorType vibratorType)
+{
+    switch (vibratorType) {
+        case VibratorType::VIBRATOR_TYPE_ONE:
+            printf("VIBRATOR_TYPE_ONE\n");
+            break;
+        case VibratorType::VIBRATOR_TYPE_TWO:
+            printf("VIBRATOR_TYPE_TWO\n");
+            break;
+        case VibratorType::VIBRATOR_TYPE_THREE:
+            printf("VIBRATOR_TYPE_THREE\n");
+            break;
+        default:
+            break;
+    }
+}
+#endif
+
+class TestSetRotateFactorListener : public UIView::OnClickListener {
+public:
+    TestSetRotateFactorListener(UIView* view, float factor) : view_(view), factor_(factor) {}
+    ~TestSetRotateFactorListener() {}
+
+    bool OnClick(UIView& view, const ClickEvent& event) override
+    {
+        switch (view_->GetViewType()) {
+            case UI_SWIPE_VIEW:
+                static_cast<UISwipeView*>(view_)->SetRotateFactor(factor_);
+                break;
+            case UI_SCROLL_VIEW:
+                static_cast<UIScrollView*>(view_)->SetRotateFactor(factor_);
+                break;
+            default:
+                break;
+        }
+        return true;
+    }
+
+private:
+    UIView* view_ = nullptr;
+    float factor_ = 0;
+};
+
+void UITestRotateInput::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->SetOnTouchListener(this);
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight());
+        container_->SetThrowDrag(true);
+        container_->SetRotateFactor(20); // 20 : rotate factor for container
+        container_->RequestFocus();
+        container_->SetReboundSize(g_height);
+    }
+    if (adapterData_ == nullptr) {
+        adapterData_ = new List<const char*>();
+        adapterData_->PushBack("000");
+        adapterData_->PushBack("111");
+        adapterData_->PushBack("222");
+        adapterData_->PushBack("333");
+        adapterData_->PushBack("444");
+        adapterData_->PushBack("555");
+        adapterData_->PushBack("666");
+        adapterData_->PushBack("777");
+        adapterData_->PushBack("888");
+        adapterData_->PushBack("999");
+        adapterData_->PushBack("///");
+        adapterData_->PushBack("***");
+        adapterData_->PushBack("+++");
+        adapterData_->PushBack("---");
+        adapterData_->PushBack("...");
+        adapterData_->PushBack("@@@");
+        adapterData_->PushBack("000");
+        adapterData_->PushBack("111");
+        adapterData_->PushBack("222");
+        adapterData_->PushBack("333");
+        adapterData_->PushBack("444");
+        adapterData_->PushBack("555");
+        adapterData_->PushBack("666");
+        adapterData_->PushBack("777");
+        adapterData_->PushBack("888");
+        adapterData_->PushBack("999");
+        adapterData_->PushBack("///");
+        adapterData_->PushBack("***");
+        adapterData_->PushBack("+++");
+        adapterData_->PushBack("---");
+        adapterData_->PushBack("...");
+        adapterData_->PushBack("@@@");
+    }
+#if ENABLE_VIBRATOR
+    VibratorManager::GetInstance()->RegisterVibratorFunc(Print);
+#endif
+}
+
+void UITestRotateInput::TearDown()
+{
+    if (listener1_ != nullptr) {
+        delete listener1_;
+        listener1_ = nullptr;
+    }
+    if (listener2_ != nullptr) {
+        delete listener2_;
+        listener2_ = nullptr;
+    }
+    if (listener3_ != nullptr) {
+        delete listener3_;
+        listener3_ = nullptr;
+    }
+    if (listener4_ != nullptr) {
+        delete listener4_;
+        listener4_ = nullptr;
+    }
+    if (listener5_ != nullptr) {
+        delete listener5_;
+        listener5_ = nullptr;
+    }
+    container_->ClearFocus();
+    container_->Remove(timePicker_);
+    container_->Remove(picker_);
+    DeleteChildren(container_);
+    container_ = nullptr;
+    if (adapterData_ != nullptr) {
+        adapterData_->Clear();
+        delete adapterData_;
+        adapterData_ = nullptr;
+    }
+    if (adapter_ != nullptr) {
+        delete adapter_;
+        adapter_ = nullptr;
+    }
+    lastX_ = 0;
+    lastY_ = 0;
+    list_ = nullptr;
+    scroll_ = nullptr;
+    swipe_ = nullptr;
+    timePicker_ = nullptr;
+    slider_ = nullptr;
+    picker_ = nullptr;
+}
+
+const UIView* UITestRotateInput::GetTestView()
+{
+    UIKit_Rotate_Event_List_001();
+    UIKit_Rotate_Event_Scroll_View_002();
+    UIKit_Rotate_Event_Swipe_View_003();
+    UIKit_Rotate_Event_Slider_004();
+    UIKit_Rotate_Event_Time_Picker_005();
+    UIKit_Rotate_Event_Picker_006();
+    return container_;
+}
+
+void UITestRotateInput::UIKit_Rotate_Event_List_001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("UIList Test");
+    container_->Add(label);
+    label->SetPosition(g_testx, lastY_ + g_blank);
+    if (adapter_ == nullptr) {
+        adapter_ = new TextAdapter();
+    }
+    adapter_->SetData(adapterData_);
+    if (list_ == nullptr) {
+        list_ = new UIList(UIList::VERTICAL);
+    }
+    list_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);
+    list_->SetPosition(g_testx, label->GetY() + g_blank, g_listW, g_listH - g_offset); // 200: mean list reduce height
+    list_->SetStartIndex(6);                                                // 6 : list start index
+    list_->SetAdapter(adapter_);
+    list_->SetOnTouchListener(this);
+    list_->SetThrowDrag(true);
+    list_->SetRotateFactor(10); // 10 : rotate factor
+    list_->SetReboundSize(g_height);
+    container_->Add(list_);
+    SetLastPos(list_);
+}
+
+void UITestRotateInput::UIKit_Rotate_Event_Scroll_View_002()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("UIScrollView Test");
+    container_->Add(label);
+    label->SetPosition(g_testx, lastY_ + g_blank);
+    if (scroll_ == nullptr) {
+        scroll_ = new UIScrollView();
+    }
+    scroll_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);
+    scroll_->SetPosition(BUTTON_WIDHT1, label->GetY() + g_blank, g_scrollW, g_scrollH);
+    if (Screen::GetInstance().GetScreenShape() == ScreenShape::RECTANGLE) {
+        scroll_->SetXScrollBarVisible(true);
+    }
+    scroll_->SetYScrollBarVisible(true);
+    scroll_->SetRotateFactor(10); // 10 : rotateFactor
+    UIButton* btn = new UIButton();
+    btn->SetPosition(0, 0, g_buttonW, g_buttonH);
+    scroll_->Add(btn);
+    scroll_->SetThrowDrag(true);
+    scroll_->SetOnTouchListener(this);
+    scroll_->SetReboundSize(g_height);
+    container_->Add(scroll_);
+    SetTestLabelButton(label, scroll_);
+    SetLastPos(scroll_);
+}
+
+void UITestRotateInput::UIKit_Rotate_Event_Swipe_View_003()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("UISwipeView Test");
+    container_->Add(label);
+    label->SetPosition(g_testx, lastY_ + g_blank + g_offset);
+    if (swipe_ == nullptr) {
+        swipe_ = new UISwipeView(UISwipeView::HORIZONTAL);
+    }
+    swipe_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);
+    swipe_->SetPosition(0, label->GetY() + g_blank, g_swipeW, g_swipeH);
+    swipe_->SetBlankSize(100); // 100 is blank size
+    UILabelButton* btn1 = new UILabelButton();
+    UILabelButton* btn2 = new UILabelButton();
+    UILabelButton* btn3 = new UILabelButton();
+    UILabelButton* btn4 = new UILabelButton();
+    UILabelButton* btn5 = new UILabelButton();
+    UILabelButton* btn6 = new UILabelButton();
+    UILabelButton* btn7 = new UILabelButton();
+    btn1->SetPosition(0, 0, g_smallButtonW, g_smallButtonH);
+    btn2->SetPosition(0, 0, g_smallButtonW, g_smallButtonH);
+    btn3->SetPosition(0, 0, g_smallButtonW, g_smallButtonH);
+    btn4->SetPosition(0, 0, g_smallButtonW, g_smallButtonH);
+    btn5->SetPosition(0, 0, g_smallButtonW, g_smallButtonH);
+    btn6->SetPosition(0, 0, g_smallButtonW, g_smallButtonH);
+    btn7->SetPosition(0, 0, g_smallButtonW, g_smallButtonH);
+    btn1->SetText("Button 1");
+    btn2->SetText("Button 2");
+    btn3->SetText("Button 3");
+    btn4->SetText("Button 4");
+    btn5->SetText("Button 5");
+    btn6->SetText("Button 6");
+    btn7->SetText("Button 7");
+    swipe_->Add(btn1);
+    swipe_->Add(btn2);
+    swipe_->Add(btn3);
+    swipe_->Add(btn4);
+    swipe_->Add(btn5);
+    swipe_->Add(btn6);
+    swipe_->Add(btn7);
+    swipe_->SetOnTouchListener(this);
+    swipe_->SetRotateFactor(30); // 30 : rotate factor
+    container_->Add(swipe_);
+    SetTestLabelButton(label, swipe_);
+    SetLastPos(swipe_);
+}
+
+void UITestRotateInput::UIKit_Rotate_Event_Slider_004()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("UISlider Test");
+    container_->Add(label);
+    label->SetPosition(g_testx, lastY_ + g_blank + g_offset);
+    if (slider_ == nullptr) {
+        slider_ = new UISlider();
+    }
+    slider_->SetPosition(g_testx, label->GetY() + g_blank, g_sliderW, g_sliderH);
+    slider_->SetValidHeight(g_offset);
+    slider_->SetValue(g_blank);
+    slider_->SetDirection(UISlider::Direction::DIR_BOTTOM_TO_TOP);
+    slider_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Gray().full);
+    slider_->SetOnTouchListener(this);
+    container_->Add(slider_);
+    SetLastPos(slider_);
+}
+
+void UITestRotateInput::UIKit_Rotate_Event_Time_Picker_005()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("UITimePicker Test");
+    container_->Add(label);
+    label->SetPosition(g_testx, lastY_ + g_blank);
+    if (timePicker_ == nullptr) {
+        timePicker_ = new UITimePicker();
+    }
+    timePicker_->EnableSecond(true);
+    timePicker_->SetPosition(BUTTON_WIDHT1 + BACK_BUTTON_HEIGHT, label->GetY() + g_blank, g_listW, g_listH);
+    timePicker_->SetItemHeight(g_height);
+
+    UIView* hour = timePicker_->GetChildById("hour");
+    if (hour == nullptr) {
+        return;
+    }
+    static_cast<UIList*>(hour)->SetRotateFactor(5); // 5: rotate factor
+    hour->SetOnTouchListener(this);
+
+    UIView* minute = timePicker_->GetChildById("minute");
+    if (minute == nullptr) {
+        return;
+    }
+    static_cast<UIList*>(minute)->SetRotateFactor(5); // 5: rotate factor
+    minute->SetOnTouchListener(this);
+
+    UIView* second = timePicker_->GetChildById("second");
+    if (second == nullptr) {
+        return;
+    }
+    static_cast<UIList*>(second)->SetRotateFactor(5); // 5: rotate factor
+    second->SetOnTouchListener(this);
+
+    container_->Add(timePicker_);
+    SetLastPos(timePicker_);
+}
+
+void UITestRotateInput::UIKit_Rotate_Event_Picker_006()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("UIPicker Test");
+    container_->Add(label);
+    label->SetPosition(g_testx, lastY_ + g_blank);
+    if (picker_ == nullptr) {
+        picker_ = new UIPicker();
+    }
+    picker_->SetPosition(BUTTON_WIDHT2, label->GetY() + g_blank, g_listW, g_listH);
+    picker_->SetItemHeight(g_height);
+    picker_->SetValues(g_pickerRange, sizeof(g_pickerRange) / sizeof(g_pickerRange[0]));
+    picker_->SetOnTouchListener(this);
+    picker_->SetRotateFactor(5); // 5: rotate factor
+    container_->Add(picker_);
+    SetLastPos(picker_);
+}
+bool UITestRotateInput::OnPress(UIView& view, const PressEvent& event)
+{
+    if (&view == container_) {
+        container_->RequestFocus();
+        return true;
+    } else if (&view == list_) {
+        list_->RequestFocus();
+        return true;
+    } else if (&view == scroll_) {
+        scroll_->RequestFocus();
+        return true;
+    } else if (&view == swipe_) {
+        swipe_->RequestFocus();
+        return true;
+    } else if (&view == slider_) {
+        slider_->RequestFocus();
+        return true;
+    } else if (&view == timePicker_->GetChildById(UITimePicker::HOUR_LIST_NAME)) {
+        view.RequestFocus();
+        return true;
+    } else if (&view == timePicker_->GetChildById(UITimePicker::MIN_LIST_NAME)) {
+        view.RequestFocus();
+        return true;
+    } else if (&view == timePicker_->GetChildById(UITimePicker::SEC_LIST_NAME)) {
+        view.RequestFocus();
+        return true;
+    } else if (&view == picker_) {
+        picker_->RequestFocus();
+        return true;
+    }
+    return false;
+}
+void UITestRotateInput::SetLastPos(UIView* view)
+{
+    if (view == nullptr) {
+        return;
+    }
+    lastX_ = view->GetX();
+    lastY_ = view->GetY() + view->GetHeight();
+}
+
+void UITestRotateInput::CreateLabelButton(int16_t x, int16_t y, UIView::OnClickListener* listener, const char* text)
+{
+    UILabelButton* labelButton = new UILabelButton();
+    labelButton->SetPosition(x, y, g_testButtonW, g_testButtonH);
+    labelButton->SetOnClickListener(listener);
+    labelButton->SetText(text);
+    labelButton->SetFont(DEFAULT_VECTOR_FONT_FILENAME, g_size);
+    container_->Add(labelButton);
+    SetLastPos(labelButton);
+}
+
+void UITestRotateInput::SetTestLabelButton(UILabel* label, UIView* view)
+{
+    if (listener1_ == nullptr) {
+        listener1_ = static_cast<UIView::OnClickListener*>(new TestSetRotateFactorListener(view, 0));
+    }
+    CreateLabelButton(g_testx, label->GetY() + g_blank1, listener1_, "factor: 0");
+    if (listener2_ == nullptr) {
+        listener2_ = static_cast<UIView::OnClickListener*>(
+            new TestSetRotateFactorListener(view, 15)); // 15: rotate factor
+    }
+    CreateLabelButton(g_testx, lastY_ + g_blank, listener2_, "factor: 15");
+    if (listener3_ == nullptr) {
+        listener3_ = static_cast<UIView::OnClickListener*>(
+            new TestSetRotateFactorListener(view, -15)); // -15: rotate factor
+    }
+    CreateLabelButton(g_testx, lastY_ + g_blank, listener3_, "factor: -15");
+    if (listener4_ == nullptr) {
+        listener4_ = static_cast<UIView::OnClickListener*>(
+            new TestSetRotateFactorListener(view, 30)); // 30: rotate factor
+    }
+    int16_t x = lastX_ + g_testButtonW + g_blank;
+    CreateLabelButton(x, label->GetY() + g_blank1, listener4_, "factor: 30");
+    if (listener5_ == nullptr) {
+        listener5_ = static_cast<UIView::OnClickListener*>(
+            new TestSetRotateFactorListener(view, -30)); // -30: rotate factor
+    }
+    CreateLabelButton(x, lastY_ + g_blank, listener5_, "factor: -30");
+}
+} // namespace OHOS
+#endif
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_rotate_input/ui_test_rotate_input.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_rotate_input/ui_test_rotate_input.h
new file mode 100644 (file)
index 0000000..94f75c3
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_ROTATE_INPUT_H
+#define UI_TEST_ROTATE_INPUT_H
+
+#include "components/ui_list.h"
+#include "components/ui_scroll_view.h"
+#include "components/ui_slider.h"
+#include "components/ui_swipe_view.h"
+#include "components/ui_time_picker.h"
+#include "ui_test.h"
+
+#if ENABLE_ROTATE_INPUT
+namespace OHOS {
+class UITestRotateInput : public UITest, UIView::OnTouchListener {
+public:
+    UITestRotateInput() {}
+    ~UITestRotateInput() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    void UIKit_Rotate_Event_List_001();
+    void UIKit_Rotate_Event_Scroll_View_002();
+    void UIKit_Rotate_Event_Swipe_View_003();
+    void UIKit_Rotate_Event_Slider_004();
+    void UIKit_Rotate_Event_Time_Picker_005();
+    void UIKit_Rotate_Event_Picker_006();
+    bool OnPress(UIView& view, const PressEvent& event) override;
+
+private:
+    void SetLastPos(UIView* view);
+    void CreateLabelButton(int16_t x, int16_t y, UIView::OnClickListener* listener, const char* text);
+    void SetTestLabelButton(UILabel* label, UIView* view);
+    UIScrollView* container_ = nullptr;
+    UIList* list_ = nullptr;
+    UIScrollView* scroll_ = nullptr;
+    UISwipeView* swipe_ = nullptr;
+    UITimePicker* timePicker_ = nullptr;
+    UISlider* slider_ = nullptr;
+    List<const char*>* adapterData_  = nullptr;
+    TextAdapter* adapter_ = nullptr;
+    int16_t lastX_ = 0;
+    int16_t lastY_ = 0;
+    UIPicker* picker_ = nullptr;
+    UIView::OnClickListener* listener1_ = nullptr;
+    UIView::OnClickListener* listener2_ = nullptr;
+    UIView::OnClickListener* listener3_ = nullptr;
+    UIView::OnClickListener* listener4_ = nullptr;
+    UIView::OnClickListener* listener5_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_ROTATE_INPUT_H
+#endif
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_scroll_bar/ui_test_scroll_bar.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_scroll_bar/ui_test_scroll_bar.cpp
new file mode 100644 (file)
index 0000000..4d83078
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_scroll_bar.h"
+#include "components/ui_label_button.h"
+#include "engines/gfx/gfx_engine_manager.h"
+
+namespace {
+constexpr int16_t LABEL_WIDTH = 150;
+constexpr int16_t LABEL_HEIGHT = 74;
+constexpr int16_t LABEL_INTERVAL = 50;
+constexpr int16_t LABEL_LEFT_INTERVAL = 125;
+constexpr int16_t VIEW_WIDTH = 400;
+constexpr int16_t VIEW_HEIGHT = 400;
+}
+namespace OHOS {
+void UITestScrollBar::SetUp()
+{
+    BaseGfxEngine::GetInstance()->SetScreenShape(ScreenShape::CIRCLE);
+
+    if (container_ == nullptr) {
+        container_ = new UIViewGroup();
+    }
+    if (scrollView_ == nullptr) {
+        scrollView_ = new UIScrollView();
+    }
+    if (list_ == nullptr) {
+        list_ = new UIList();
+    }
+    if (foreImg1_ == nullptr) {
+        foreImg1_ = new UIImageView();
+    }
+    if (foreImg2_ == nullptr) {
+        foreImg2_ = new UIImageView();
+    }
+    if (adapter_ == nullptr) {
+        adapter_ = new TextAdapter();
+    }
+    if (adapterData_ == nullptr) {
+        adapterData_ = new List<const char*>();
+        adapterData_->PushBack("abcd0");
+        adapterData_->PushBack("abcd1");
+        adapterData_->PushBack("abcd2");
+        adapterData_->PushBack("abcd3");
+        adapterData_->PushBack("abcd4");
+        adapterData_->PushBack("abcd5");
+        adapterData_->PushBack("abcd6");
+        adapterData_->PushBack("abcd7");
+        adapterData_->PushBack("abcd8");
+        adapterData_->PushBack("abcd9");
+        adapterData_->PushBack("abcd10");
+        adapterData_->PushBack("abcd11");
+        adapterData_->PushBack("abcd12");
+        adapterData_->PushBack("abcd13");
+        adapterData_->PushBack("abcd14");
+        adapterData_->PushBack("abcd15");
+    }
+
+    container_->SetPosition(0, 0, Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight());
+
+    container_->Add(scrollView_);
+    scrollView_->SetPosition(0, 0, VIEW_WIDTH, VIEW_HEIGHT);
+    scrollView_->SetYScrollBarVisible(true);
+    scrollView_->SetHorizontalScrollState(false);
+    scrollView_->SetReboundSize(50); // 50: rebound size
+    scrollView_->SetScrollBarCenter({200, 200}); // 200: x, y of center
+
+    container_->Add(list_);
+    list_->SetPosition(450, 0, VIEW_WIDTH, VIEW_HEIGHT); // 450: x
+    list_->SetYScrollBarVisible(true);
+    list_->SetScrollBarSide(SCROLL_BAR_LEFT_SIDE);
+    list_->SetReboundSize(50); // 50: rebound size
+}
+
+void UITestScrollBar::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+    scrollView_ = nullptr;
+    list_ = nullptr;
+    foreImg1_ = nullptr;
+    foreImg2_ = nullptr;
+    if (adapterData_ != nullptr) {
+        adapterData_->Clear();
+        delete adapterData_;
+        adapterData_ = nullptr;
+    }
+    if (adapter_ != nullptr) {
+        delete adapter_;
+        adapter_ = nullptr;
+    }
+
+    BaseGfxEngine::GetInstance()->SetScreenShape(ScreenShape::RECTANGLE);
+}
+
+const UIView* UITestScrollBar::GetTestView()
+{
+    UIKitScrollBarTestScrollview001();
+    UIKitScrollBarTestList001();
+    return container_;
+}
+
+void UITestScrollBar::UIKitScrollBarTestScrollview001()
+{
+    UILabelButton* label1 = new UILabelButton();
+    scrollView_->Add(label1);
+    label1->LayoutTopOfParent(LABEL_INTERVAL);
+    label1->LayoutLeftOfParent(LABEL_LEFT_INTERVAL);
+    label1->SetWidth(LABEL_WIDTH);
+    label1->SetHeight(LABEL_HEIGHT);
+    label1->SetViewId("label1");
+    label1->SetText("label1");
+
+    UILabelButton* label2 = new UILabelButton();
+    scrollView_->Add(label2);
+    label2->LayoutBottomToSibling("label1", LABEL_INTERVAL);
+    label2->LayoutLeftOfParent(LABEL_LEFT_INTERVAL);
+    label2->SetWidth(LABEL_WIDTH);
+    label2->SetHeight(LABEL_HEIGHT);
+    label2->SetViewId("label2");
+    label2->SetText("label2");
+
+    UILabelButton* label3 = new UILabelButton();
+    scrollView_->Add(label3);
+    label3->LayoutBottomToSibling("label2", LABEL_INTERVAL);
+    label3->LayoutLeftOfParent(LABEL_LEFT_INTERVAL);
+    label3->SetWidth(LABEL_WIDTH);
+    label3->SetHeight(LABEL_HEIGHT);
+    label3->SetViewId("label3");
+    label3->SetText("label3");
+
+    UILabelButton* label4 = new UILabelButton();
+    scrollView_->Add(label4);
+    label4->LayoutBottomToSibling("label3", LABEL_INTERVAL);
+    label4->LayoutLeftOfParent(LABEL_LEFT_INTERVAL);
+    label4->SetWidth(LABEL_WIDTH);
+    label4->SetHeight(LABEL_HEIGHT);
+    label4->SetViewId("label4");
+    label4->SetText("label4");
+
+    UILabelButton* label5 = new UILabelButton();
+    scrollView_->Add(label5);
+    label5->LayoutBottomToSibling("label4", LABEL_INTERVAL);
+    label5->LayoutLeftOfParent(LABEL_LEFT_INTERVAL);
+    label5->SetWidth(LABEL_WIDTH);
+    label5->SetHeight(LABEL_HEIGHT);
+    label5->SetViewId("label5");
+    label5->SetText("label5");
+
+    foreImg1_->SetSrc(RES_PATH"fore.png");
+    container_->Add(foreImg1_);
+    foreImg1_->SetPosition(0, 0);
+}
+
+void UITestScrollBar::UIKitScrollBarTestList001()
+{
+    adapter_->SetLineBreakMode(UILabel::LINE_BREAK_CLIP);
+    adapter_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    adapter_->SetHeight(LABEL_HEIGHT);
+    adapter_->SetWidth(VIEW_WIDTH);
+    adapter_->SetData(adapterData_);
+
+    list_->SetAdapter(adapter_);
+    list_->SetIntercept(true);
+    list_->SetYScrollBarVisible(true);
+
+    foreImg2_->SetSrc(RES_PATH"fore.png");
+    container_->Add(foreImg2_);
+    foreImg2_->SetPosition(450, 0); // 450: x
+}
+} // namespace OHOS
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_scroll_bar/ui_test_scroll_bar.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_scroll_bar/ui_test_scroll_bar.h
new file mode 100644 (file)
index 0000000..aed6981
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_SCROLL_BAR_H
+#define UI_TEST_SCROLL_BAR_H
+
+#include "components/text_adapter.h"
+#include "components/ui_image_view.h"
+#include "components/ui_list.h"
+#include "components/ui_scroll_view.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestScrollBar : public UITest {
+public:
+    UITestScrollBar() {}
+    ~UITestScrollBar() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    void UIKitScrollBarTestScrollview001();
+    void UIKitScrollBarTestList001();
+
+private:
+    UIViewGroup* container_ = nullptr;
+    UIScrollView* scrollView_ = nullptr;
+    UIList* list_ = nullptr;
+    UIImageView* foreImg1_ = nullptr;
+    UIImageView* foreImg2_ = nullptr;
+    List<const char*>* adapterData_ = nullptr;
+    TextAdapter* adapter_ = nullptr;
+}; // namespace OHOS
+}
+#endif // UI_TEST_SCROLL_BAR_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_simple_list/ui_test_simple_list.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_simple_list/ui_test_simple_list.cpp
new file mode 100644 (file)
index 0000000..dd3797d
--- /dev/null
@@ -0,0 +1,122 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.\r
+ * Description: List with built-in adapter sample\r
+ * Author: Hisi Team\r
+ * Created: 2025-07\r
+ */\r
+\r
+#include "ui_test_simple_list.h"\r
+#include "common/screen.h"\r
+#include "components/ui_menu_item.h"\r
+#include "common/image_cache_manager.h"\r
+#include "graphic_config.h"\r
+#include "ui_test_list_fps/image_text_adapter.h"\r
+#include "ui_test_list_fps/ui_list_fps_res.h"\r
+\r
+namespace OHOS {\r
+static const int16_t LIST_WIDTH = 454;\r
+static const int16_t LIST_HEIGHT = 454;\r
+static const uint16_t ITEM_WIDTH = 400;\r
+static const uint16_t ITEM_HEIGHT = 100;\r
+static const uint16_t LIST_FONT_SIZE = 40;\r
+\r
+static ItemNode g_itemNode[] = {\r
+    {APPLIST_ALARM, "闹钟"},\r
+    {BLUETOOTH_TITLE, "蓝牙"},\r
+    {APPLIST_CALLER_IMAGE, "通话记录"},\r
+    {APPLIST_COMPASS_IMAGE, "指南针"},\r
+    {APPLIST_SETTING, "设置"},\r
+    {APPLIST_SPO2, "血氧饱和度"},\r
+    {APPLIST_VOCASSIST_IMAGE, "语音助手"},\r
+    {APPLIST_ALARM, "长文本滚动测试ABCD"},\r
+    {BLUETOOTH_TITLE, "蓝牙"},\r
+    {APPLIST_CALLER_IMAGE, "通话记录"},\r
+    {APPLIST_COMPASS_IMAGE, "指南针"},\r
+    {APPLIST_SETTING, "设置"},\r
+    {APPLIST_SPO2, "血氧饱和度"},\r
+    {APPLIST_VOCASSIST_IMAGE, "语音助手"}\r
+};\r
+\r
+static UIView* CreateViewCb(uint8_t type)\r
+{\r
+    UIMenuItem* item = new UIMenuItem();\r
+    if (item == nullptr) {\r
+        return nullptr;\r
+    }\r
+\r
+    item->Resize(ITEM_WIDTH, ITEM_HEIGHT);\r
+    item->SetStyle(STYLE_BACKGROUND_OPA, OPA_TRANSPARENT);\r
+    item->SetImgResizeMode(UIImageView::ImageResizeMode::CENTER);\r
+    item->SetFont(DEFAULT_VECTOR_FONT_FILENAME, LIST_FONT_SIZE);\r
+    item->SetScaleAlignMode(UIMenuItem::ScaleAlignMode::ALIGN_ITEM_CENTER);\r
+    item->SetLineBreakMode(UILabel::LineBreakMode::LINE_BREAK_MARQUEE);\r
+    return item;\r
+}\r
+\r
+static void UpdateViewCb(UIView* view, void* data, uint8_t type)\r
+{\r
+    if (view == nullptr || data == nullptr) {\r
+        return;\r
+    }\r
+    UIMenuItem* item = dynamic_cast<UIMenuItem*>(view);\r
+    ItemNode* content = static_cast<ItemNode *>(data);\r
+    if (content->imgInfo == nullptr) {\r
+        content->imgInfo = ImageCacheManager::GetInstance().LoadOneInMultiRes(content->resId, LIST_FPS);\r
+    }\r
+    item->SetImageSrc(content->imgInfo);\r
+    item->SetText(content->txt);\r
+    item->SetAlign(TEXT_ALIGNMENT_CENTER);\r
+}\r
+\r
+void UITestSimpleList::SetUp()\r
+{\r
+    if (list_ == nullptr) {\r
+        list_ = new UISimpleList();\r
+    }\r
+    list_->SetPosition(0, 0, LIST_WIDTH, LIST_HEIGHT);\r
+    list_->SetThrowDrag(true);\r
+    list_->SetStyle(STYLE_BACKGROUND_OPA, OPA_TRANSPARENT);\r
+    list_->SetScrollBlankSize(LIST_HEIGHT / 2); // 2: divisor\r
+\r
+    Contents* content = nullptr;\r
+    for (uint8_t i = 0; i < (sizeof(g_itemNode) / sizeof(ItemNode)); ++i) {\r
+        content = new Contents();\r
+        if (content == nullptr) {\r
+            continue;\r
+        }\r
+        content->createFunc = CreateViewCb;\r
+        content->updateFunc = UpdateViewCb;\r
+        content->type = 1;\r
+        content->data = reinterpret_cast<void *>(&g_itemNode[i]);\r
+        data_.PushBack(content);\r
+        list_->AddContent(*content);\r
+    }\r
+    list_->RefreshList();\r
+}\r
+\r
+void UITestSimpleList::TearDown()\r
+{\r
+    if (list_ != nullptr) {\r
+        delete list_;\r
+        list_ = nullptr;\r
+    }\r
+\r
+    while (!data_.IsEmpty()) {\r
+        Contents* element = data_.Back();\r
+        if (element != nullptr) {\r
+            delete element;\r
+        }\r
+        data_.PopBack();\r
+    }\r
+\r
+    ImageCacheManager::GetInstance().UnloadAllInMultiRes(LIST_FPS);\r
+    for (uint8_t i = 0; i < (sizeof(g_itemNode) / sizeof(ItemNode)); ++i) {\r
+        g_itemNode[i].imgInfo = nullptr;\r
+    }\r
+}\r
+\r
+UIView* UITestSimpleList::GetTestView()\r
+{\r
+    return list_;\r
+}\r
+} // namespace OHOS\r
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_simple_list/ui_test_simple_list.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_simple_list/ui_test_simple_list.h
new file mode 100644 (file)
index 0000000..2dd0d21
--- /dev/null
@@ -0,0 +1,28 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.\r
+ * Description: List with built-in adapter sample\r
+ * Author: Hisi Team\r
+ * Created: 2025-07\r
+ */\r
+#ifndef UI_TEST_SIMPLE_LIST_H\r
+#define UI_TEST_SIMPLE_LIST_H\r
+\r
+#include "components/ui_simple_list.h"\r
+#include "ui_test.h"\r
+\r
+namespace OHOS {\r
+class UITestSimpleList : public UITest, UIView::OnClickListener, ListScrollListener {\r
+public:\r
+    UITestSimpleList() : list_(nullptr) {}\r
+    ~UITestSimpleList() override {}\r
+    void SetUp() override;\r
+    void TearDown() override;\r
+    UIView* GetTestView() override;\r
+\r
+private:\r
+    UISimpleList* list_;\r
+    List<Contents*> data_;\r
+};\r
+} // namespace OHOS\r
+#endif // UI_TEST_LIST_FPS_H\r
+\r
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_simple_list/ui_test_simple_transform_list.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_simple_list/ui_test_simple_transform_list.cpp
new file mode 100644 (file)
index 0000000..2de2117
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: List with built-in adapter sample
+ * Author: Hisi Team
+ * Created: 2025-07
+ */
+
+#include "ui_test_simple_transform_list.h"
+#include "common/screen.h"
+#include "components/ui_menu_item.h"
+#include "common/image_cache_manager.h"
+#include "graphic_config.h"
+#include "ui_test_list_fps/ui_list_fps_res.h"
+
+namespace OHOS {
+static const int16_t LIST_WIDTH = 454;
+static const int16_t LIST_HEIGHT = 454;
+static const int16_t SCROLL_STEP = 10;
+static const int16_t DEFAULT_RADIUS = 10;
+static const uint16_t ITEM_WIDTH = 400;
+static const uint16_t ITEM_HEIGHT = 100;
+static const uint16_t IMAGE_WIDTH = 50;
+static const uint16_t IMAGE_HEIGHT = 50;
+static const uint16_t LABEL_WIDTH = 300;
+static const uint16_t LABEL_HEIGHT = 100;
+static const uint16_t LIST_FONT_SIZE = 40;
+static const uint16_t SCALE_FACTOR = 400;
+static const uint16_t X_POS = 50;
+static const uint16_t Y_POS = 50;
+static const uint16_t IMAGE_W = 220;
+static const uint16_t IMAGE_H = 220;
+static const uint16_t IMAGE_NUM = 3;
+
+struct ItemNode {
+    int resId;
+    const char* txt;
+    bool isEnableImgAni;
+    bool isEnableSlider;
+    ImageInfo* imgInfo;
+};
+
+// First type can't be 0
+enum class ItemType {
+    IMGANI_SLIDER = 1,
+    NULL_SLIDER,
+    IMGANI_NULL,
+    IMG_LABEL,
+};
+
+static ItemNode g_itemNode[] = {
+    {0, nullptr, true, true},
+    {APPLIST_ALARM, "闹钟", false, false},
+    {BLUETOOTH_TITLE, "蓝牙", false, false},
+    {APPLIST_CALLER_IMAGE, "通话记录", false, false},
+    {APPLIST_COMPASS_IMAGE, "指南针", false, false},
+    {APPLIST_SETTING, "设置", false, false},
+    {APPLIST_SPO2, "血氧饱和度", false, false},
+    {APPLIST_VOCASSIST_IMAGE, "语音助手", false, false},
+    {APPLIST_ALARM, "长文本滚动测试ABCD", false, false},
+    {BLUETOOTH_TITLE, "蓝牙", false, false},
+    {APPLIST_CALLER_IMAGE, "通话记录", false, false},
+    {APPLIST_COMPASS_IMAGE, "指南针", false, false},
+    {APPLIST_SETTING, "设置", false, false},
+    {APPLIST_SPO2, "血氧饱和度", false, false},
+    {APPLIST_VOCASSIST_IMAGE, "语音助手", false, false}
+};
+
+static char* g_imagePath[IMAGE_NUM] = {
+    RES_PATH"A094_051_8888.bin",
+    RES_PATH"A094_051_888.bin",
+    RES_PATH"A094_051_565.bin",
+};
+
+static ImageAnimatorInfo g_binImageAnimatorInfo[IMAGE_NUM] = {{{0}}};
+
+static bool TransformItemBaseOnPosition(UITransformList* list, UIView* item)
+{
+    if (list == nullptr || item == nullptr) {
+        return false;
+    }
+    if (item->GetViewType() != UI_TRANSFORM_GROUP) {
+        return false;
+    }
+    UITransformGroup* group = dynamic_cast<UITransformGroup*>(item);
+    if (group == nullptr) {
+        return false;
+    }
+    int16_t w = group->GetWidth();
+    int16_t h = group->GetHeight();
+    if (list->GetDirection() == UIList::VERTICAL) {
+        int16_t midY = list->GetY() + (list->GetHeight() >> 1);
+        int16_t y = group->GetY();
+        int offset = (y + (h >> 1) - midY);
+        int temp = EasingEquation::SineEaseIn(0, SCALE_FACTOR, abs(offset), SCALE_FACTOR);
+        float scale = 1.0 - (static_cast<float>(temp) / SCALE_FACTOR);
+        group->Scale(Vector2<float>(scale, scale), Vector2<float>(w >> 1,  h >> 1));
+        if ((y <= midY) && (y + group->GetHeight() >= midY)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void ItemContainer::ClearRes()
+{
+    RemoveAll();
+    if (leftImg_ != nullptr) {
+        delete leftImg_;
+        leftImg_ = nullptr;
+    }
+    if (label_ != nullptr) {
+        delete label_;
+        label_ = nullptr;
+    }
+    if (rightImg_ != nullptr) {
+        delete rightImg_;
+        rightImg_ = nullptr;
+    }
+}
+
+UIImageView* ItemContainer::CreateLeftImageView()
+{
+    if (leftImg_ == nullptr) {
+        leftImg_ = new UIImageView();
+        if (leftImg_ != nullptr) {
+            leftImg_->SetResizeMode(UIImageView::ImageResizeMode::CENTER);
+            Add(leftImg_);
+        } else {
+            GRAPHIC_LOGE("ItemContainer init UIImageView failed");
+        }
+    }
+    return leftImg_;
+}
+
+UILabelExt* ItemContainer::CreateLabelView()
+{
+    if (label_ == nullptr) {
+        label_ = new UILabelExt();
+        if (label_ != nullptr) {
+            label_->SetStyle(STYLE_BACKGROUND_OPA, OPA_TRANSPARENT);
+            label_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 40);  // 40: item font size
+            Add(label_);
+        } else {
+            GRAPHIC_LOGE("ItemContainer init UILabelExt failed");
+        }
+    }
+    return label_;
+}
+
+UIImageView* ItemContainer::CreateRightImgView()
+{
+    if (rightImg_ == nullptr) {
+        rightImg_ = new UIImageView();
+        if (rightImg_ != nullptr) {
+            rightImg_->SetResizeMode(UIImageView::ImageResizeMode::CENTER);
+            Add(rightImg_);
+        } else {
+            GRAPHIC_LOGE("ItemContainer init UIImageView failed");
+        }
+    }
+    return rightImg_;
+}
+
+UIImageAnimatorView* ItemContainer::CreateImageAniView()
+{
+    if (imgAni_ == nullptr) {
+        imgAni_ = new UIImageAnimatorView();
+        if (imgAni_ != nullptr) {
+            imgAni_->SetResizeMode(UIImageView::ImageResizeMode::CENTER);
+            Add(imgAni_);
+        } else {
+            GRAPHIC_LOGE("ItemContainer init UIImageAnimatorView failed");
+        }
+    }
+    return imgAni_;
+}
+
+UISlider* ItemContainer::CreateSlider()
+{
+    if (slider_ == nullptr) {
+        slider_ = new UISlider();
+        if (slider_ != nullptr) {
+            Add(slider_);
+        } else {
+            GRAPHIC_LOGE("ItemContainer init UIImageAnimatorView failed");
+        }
+    }
+    return slider_;
+}
+
+UIImageView* ItemContainer::GetLeftImageView()
+{
+    return leftImg_;
+}
+
+UILabelExt* ItemContainer::GetLabelView()
+{
+    return label_;
+}
+
+UIImageView* ItemContainer::GetRightImgView()
+{
+    return rightImg_;
+}
+
+UIImageAnimatorView* ItemContainer::GetImageAniView()
+{
+    return imgAni_;
+}
+
+UISlider* ItemContainer::GetSlider()
+{
+    return slider_;
+}
+
+static UIView* CreateViewCb(uint8_t type)
+{
+    ItemContainer* item = new ItemContainer();
+    if (item == nullptr) {
+        return nullptr;
+    }
+    item->Resize(ITEM_WIDTH, ITEM_HEIGHT);
+
+    if (static_cast<ItemType>(type) == ItemType::IMGANI_SLIDER ||
+        static_cast<ItemType>(type) == ItemType::IMGANI_NULL) {
+        UIImageAnimatorView* imgAni = item->CreateImageAniView();
+        if (imgAni != nullptr) {
+            imgAni->SetPosition(0, 25, IMAGE_WIDTH, IMAGE_HEIGHT); // 25:image start pos y
+        }
+    }
+
+    if (static_cast<ItemType>(type) == ItemType::IMGANI_SLIDER ||
+        static_cast<ItemType>(type) == ItemType::NULL_SLIDER) {
+        UISlider* slider = item->CreateSlider();
+        if (slider != nullptr) {
+            slider->SetPosition(IMAGE_WIDTH, 0, LABEL_WIDTH, LABEL_HEIGHT);
+        }
+    }
+
+    if (static_cast<ItemType>(type) == ItemType::IMG_LABEL) {
+        UIImageView* leftImg = item->CreateLeftImageView();
+        if (leftImg != nullptr) {
+            leftImg->SetPosition(0, 25, IMAGE_WIDTH, IMAGE_HEIGHT); // 25:image start pos y
+        }
+        UILabelExt* label = item->CreateLabelView();
+        if (label != nullptr) {
+            label->SetPosition(IMAGE_WIDTH, 0, LABEL_WIDTH, LABEL_HEIGHT);
+        }
+    }
+
+    return item;
+}
+
+static void UpdateViewCb(UIView* view, void* data, uint8_t type)
+{
+    if (view == nullptr || data == nullptr) {
+        return;
+    }
+    ItemContainer* item = dynamic_cast<ItemContainer*>(view);
+    ItemNode* content = static_cast<ItemNode *>(data);
+
+    if (static_cast<ItemType>(type) == ItemType::IMG_LABEL) {
+        UIImageView* leftImg = item->GetLeftImageView();
+        if (leftImg != nullptr) {
+            content->imgInfo = ImageCacheManager::GetInstance().LoadOneInMultiRes(content->resId, LIST_FPS);
+            leftImg->SetSrc(content->imgInfo);
+        }
+        UILabelExt* label = item->GetLabelView();
+        if (label != nullptr) {
+            label->SetText(content->txt);
+            label->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+        }
+    }
+
+    if (static_cast<ItemType>(type) == ItemType::IMGANI_SLIDER ||
+        static_cast<ItemType>(type) == ItemType::IMGANI_NULL) {
+        UIImageAnimatorView* imgAni = item->GetImageAniView();
+        if (imgAni != nullptr) {
+            imgAni->SetImageAnimatorSrc(g_binImageAnimatorInfo, IMAGE_NUM, 50); // 50: update time Interval
+            imgAni->SetSizeFixed(true);
+            imgAni->Start();
+            imgAni->Pause();
+        }
+    }
+
+    if (static_cast<ItemType>(type) == ItemType::IMGANI_SLIDER ||
+        static_cast<ItemType>(type) == ItemType::NULL_SLIDER) {
+        UISlider* slider = item->GetSlider();
+        if (slider != nullptr) {
+            slider->SetValidHeight(40);          // 40: valid height;
+            slider->SetValue(20);                 // 20:  progress bar current value
+            slider->SetDirection(UISlider::Direction::DIR_LEFT_TO_RIGHT);
+            slider->SetSliderColor(Color::Silver(), Color::Blue());
+            slider->SetKnobColor(Color::Red());
+            slider->SetSliderRadius(DEFAULT_RADIUS, DEFAULT_RADIUS);
+        }
+    }
+}
+
+void UITestSimpleTransformList::OnItemSelected(int16_t index, UIView* view)
+{
+    if (view == nullptr) {
+        GRAPHIC_LOGE("No select view!");
+        return;
+    }
+    if (lastSelectedView_ != nullptr) {
+        if (lastSelectedView_ != view) {
+            ItemContainer* selectedItem = dynamic_cast<ItemContainer *>(lastSelectedView_);
+            if (selectedItem->GetImageAniView() != nullptr) {
+                selectedItem->GetImageAniView()->Pause();
+            }
+            lastSelectedView_ = nullptr;
+        }
+    }
+    ItemContainer* item = dynamic_cast<ItemContainer *>(view);
+    if (item == nullptr) {
+        GRAPHIC_LOGE("View is not ItemContainer!");
+        return;
+    }
+    if (item->GetImageAniView() != nullptr) {
+        item->GetImageAniView()->Resume();
+        lastSelectedView_ = view;
+    }
+    return;
+}
+
+void UITestSimpleTransformList::SetUp()
+{
+    LoadImg();
+    if (list_ == nullptr) {
+        list_ = new UISimpleTransformList();
+    }
+    list_->SetPosition(0, 0, LIST_WIDTH, LIST_HEIGHT);
+    list_->SetThrowDrag(true);
+    list_->SetStyle(STYLE_BACKGROUND_OPA, OPA_TRANSPARENT);
+    list_->SetScrollBlankSize(LIST_HEIGHT / 2); // 2: divisor
+    list_->SetItemTransformFunc(&TransformItemBaseOnPosition);
+    list_->SetScrollStateListener(this);
+    list_->SetSelectPosition(227); // 227 : middle of screen
+
+    Contents* content = nullptr;
+    for (uint8_t i = 0; i < (sizeof(g_itemNode) / sizeof(ItemNode)); ++i) {
+        content = new Contents();
+        if (content == nullptr) {
+            continue;
+        }
+        content->createFunc = CreateViewCb;
+        content->updateFunc = UpdateViewCb;
+        if (g_itemNode[i].isEnableImgAni && g_itemNode[i].isEnableSlider) {
+            content->type = static_cast<uint8_t>(ItemType::IMGANI_SLIDER);
+        } else if (!g_itemNode[i].isEnableImgAni && g_itemNode[i].isEnableSlider) {
+            content->type = static_cast<uint8_t>(ItemType::NULL_SLIDER);
+        } else if (g_itemNode[i].isEnableImgAni && !g_itemNode[i].isEnableSlider) {
+            content->type = static_cast<uint8_t>(ItemType::IMGANI_NULL);
+        } else {
+            content->type = static_cast<uint8_t>(ItemType::IMG_LABEL);
+        }
+        content->data = reinterpret_cast<void *>(&g_itemNode[i]);
+        data_.PushBack(content);
+        list_->AddContent(*content);
+    }
+    list_->RefreshList();
+}
+
+void UITestSimpleTransformList::TearDown()
+{
+    ReleaseImg();
+    if (list_ != nullptr) {
+        delete list_;
+        list_ = nullptr;
+    }
+
+    while (!data_.IsEmpty()) {
+        Contents* element = data_.Back();
+        if (element != nullptr) {
+            delete element;
+        }
+        data_.PopBack();
+    }
+    if (lastSelectedView_ != nullptr) {
+        lastSelectedView_ = nullptr;
+    }
+}
+
+UIView* UITestSimpleTransformList::GetTestView()
+{
+    return list_;
+}
+
+void UITestSimpleTransformList::LoadImg()
+{
+    ImageAnimatorInfo baseinfo = {nullptr, {0, 0}, IMAGE_WIDTH, IMAGE_HEIGHT, IMG_SRC_IMAGE_INFO};
+    for (int i = 0; i < IMAGE_NUM; i++) {
+        ImageInfo* img = ImageCacheManager::GetInstance().LoadSingleRes(g_imagePath[i]);
+        if (img == nullptr) {
+            GRAPHIC_LOGE("Load image failed: %s", g_imagePath[i]);
+            ReleaseImg();
+            return;
+        }
+        g_binImageAnimatorInfo[i] = baseinfo;
+        g_binImageAnimatorInfo[i].imageInfo = img;
+    }
+}
+
+void UITestSimpleTransformList::ReleaseImg()
+{
+    for (int i = 0; i < IMAGE_NUM; i++) {
+        if (g_binImageAnimatorInfo[i].imageInfo != nullptr) {
+            ImageCacheManager::GetInstance().UnloadSingleRes(g_imagePath[i]);
+            g_binImageAnimatorInfo[i].imageInfo = nullptr;
+        }
+    }
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_simple_list/ui_test_simple_transform_list.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_simple_list/ui_test_simple_transform_list.h
new file mode 100644 (file)
index 0000000..693ac78
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: List with built-in adapter sample
+ * Author: Hisi Team
+ * Created: 2025-07
+ */
+
+#ifndef UI_TEST_SIMPLE_TRANSFORM_LIST_H
+#define UI_TEST_SIMPLE_TRANSFORM_LIST_H
+
+#include "components/ui_slider.h"
+#include "components/ui_simple_list.h"
+#include "components/ui_image_animator.h"
+#include "components/ui_label_ext.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class ItemContainer : public UITransformGroup {
+public:
+    ItemContainer() : leftImg_(nullptr), label_(nullptr), rightImg_(nullptr), imgAni_(nullptr), slider_(nullptr)
+    {
+        SetStyle(STYLE_BACKGROUND_OPA, OPA_TRANSPARENT);
+    }
+
+    ~ItemContainer()
+    {
+        ClearRes();
+    }
+
+    UIImageView* GetLeftImageView();
+    UILabelExt* GetLabelView();
+    UIImageView* GetRightImgView();
+    UIImageAnimatorView* GetImageAniView();
+    UISlider* GetSlider();
+    UIImageView* CreateLeftImageView();
+    UILabelExt* CreateLabelView();
+    UIImageView* CreateRightImgView();
+    UIImageAnimatorView* CreateImageAniView();
+    UISlider* CreateSlider();
+
+private:
+    void ClearRes();
+    UIImageView* leftImg_;
+    UILabelExt* label_;
+    UIImageView* rightImg_;
+    UIImageAnimatorView* imgAni_;
+    UISlider* slider_;
+};
+
+class UITestSimpleTransformList : public UITest, UIView::OnClickListener, ListScrollListener {
+public:
+    UITestSimpleTransformList() : list_(nullptr) {}
+    ~UITestSimpleTransformList() override {}
+    void SetUp() override;
+    void TearDown() override;
+    UIView* GetTestView() override;
+    void OnItemSelected(int16_t index, UIView* view) override;
+
+private:
+    void LoadImg();
+    void ReleaseImg();
+    UISimpleTransformList* list_;
+    List<Contents*> data_;
+    UIView* lastSelectedView_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_SIMPLE_TRANSFORM_LIST_H
+
index 836bba0..eb6ce70 100644 (file)
@@ -65,14 +65,8 @@ void UITestSlipflow::TearDown()
     label_ = nullptr;\r
     slipUpNoticelabel_ = nullptr;\r
     lastIndex_ = 0;\r
-    showBtn_ = nullptr;\r
-    isShowBtnGrp_ = false;\r
-    btnGrp_ = nullptr;\r
     loadNum_ = 0;\r
 \r
-    imgWidthAddBtn_ = nullptr;\r
-    imgWidthSubBtn_ = nullptr;\r
-\r
     imgWidth_ = 200;        // 200: default value\r
     imgPadding_ = 50;       // 50: default value\r
     mirrorOpa_ = 30;        // 30: default value\r
@@ -85,40 +79,6 @@ const UIView* UITestSlipflow::GetTestView()
     return container_;\r
 }\r
 \r
-void UITestSlipflow::CreateLabelButton(UILabelButton** btn, const char* tile, int16_t x, int16_t y)\r
-{\r
-    UILabelButton* tempBtn = nullptr;\r
-    if (tempBtn == nullptr) {\r
-        tempBtn = new UILabelButton();\r
-    }\r
-    tempBtn->SetPosition(x, y, BUTTON_WIDTH, BUTTON_HEIGHT);\r
-    tempBtn->SetText(tile);\r
-    tempBtn->SetOnClickListener(this);\r
-    btnGrp_->Add(tempBtn);\r
-    *btn = tempBtn;\r
-}\r
-\r
-void UITestSlipflow::InitButtonGroup()\r
-{\r
-    if (showBtn_ == nullptr) {\r
-        showBtn_ = new UIButton();\r
-        showBtn_->SetPosition(202, 10, BUTTON_WIDTH, BUTTON_HEIGHT);  // 202: x position 10: y position\r
-        showBtn_->SetStyleForState(STYLE_BACKGROUND_OPA, 0, UIButton::ButtonState::RELEASED);\r
-        showBtn_->SetStyleForState(STYLE_BACKGROUND_OPA, 0, UIButton::ButtonState::PRESSED);\r
-        showBtn_->SetOnClickListener(this);\r
-        container_->Add(showBtn_);\r
-    }\r
-    if (btnGrp_ == nullptr) {\r
-        btnGrp_ = new UIViewGroup();\r
-        btnGrp_->SetPosition(77, 40, BUTTON_GROUP_WIDTH, BUTTON_GROUP_HEIGHT); // 77: x position 40: y position\r
-        btnGrp_->SetStyle(STYLE_BACKGROUND_OPA, 0);\r
-        btnGrp_->SetVisible(false);\r
-        container_->Add(btnGrp_);\r
-    }\r
-    CreateLabelButton(&imgWidthAddBtn_, "wid+", 0, 0);\r
-    CreateLabelButton(&imgWidthSubBtn_, "wid-", 60, 0);    // 60: x position\r
-}\r
-\r
 void UITestSlipflow::UITestSlipflowView()\r
 {\r
     if (container_ != nullptr) {\r
@@ -128,7 +88,6 @@ void UITestSlipflow::UITestSlipflowView()
         slipflow_->SetPosition(0, 0, Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight());\r
         slipflow_->SetIntercept(true);\r
         slipflow_->SetThrowDrag(true);\r
-        slipflow_->SetPageSize(PAGE_WIDTH, PAGE_HEIGHT);\r
         slipflow_->SetOnSlipflowListener(this);\r
         UITestSlipflowViewInitFlow();\r
 \r
@@ -153,7 +112,6 @@ void UITestSlipflow::UITestSlipflowView()
         container_->Add(slipflow_);\r
         container_->Add(label_);\r
         container_->Add(slipUpNoticelabel_);\r
-        InitButtonGroup();\r
     }\r
 }\r
 \r
@@ -275,19 +233,4 @@ bool UITestSlipflow::OnRemove(UIView* view)
     group = nullptr;\r
     return true;\r
 }\r
-\r
-bool UITestSlipflow::OnClick(UIView& view, const ClickEvent& event)\r
-{\r
-    if (&view == showBtn_) {\r
-        btnGrp_->SetVisible(!btnGrp_->IsVisible());\r
-    } else if (&view == imgWidthAddBtn_) {\r
-        imgWidth_ += DEFAULT_STEP;\r
-        slipflow_->SetPageSize(imgWidth_, imgWidth_);\r
-    } else if (&view == imgWidthSubBtn_) {\r
-        imgWidth_ -= DEFAULT_STEP;\r
-        slipflow_->SetPageSize(imgWidth_, imgWidth_);\r
-    }\r
-    slipflow_->Invalidate();\r
-    return true;\r
-}\r
 } // namespace OHOS\r
index 0a219ec..ffcce7a 100644 (file)
@@ -16,7 +16,7 @@
 \r
 namespace OHOS {\r
 class UITestSlipflow : public UITest,\r
-    public UISlipflowView::OnSlipflowScrollListener, public UIView::OnClickListener {\r
+    public UISlipflowView::OnSlipflowScrollListener {\r
 public:\r
     UITestSlipflow() {}\r
     ~UITestSlipflow() override {}\r
@@ -35,8 +35,6 @@ public:
     void OnRefreshPageOpaScale(UIView* view, int16_t xOffset, int16_t yOffset) override;\r
 \r
     bool OnRemove(UIView* view) override;\r
-\r
-    bool OnClick(UIView& view, const ClickEvent& event) override;\r
 private:\r
     void InitButtonGroup();\r
     void CreateLabelButton(UILabelButton** btn, const char* tile, int16_t x, int16_t y);\r
@@ -46,12 +44,7 @@ private:
     UILabel* label_ = nullptr;\r
     UILabel* slipUpNoticelabel_ = nullptr;\r
     uint16_t lastIndex_ = 0;\r
-    UIButton* showBtn_ = nullptr;\r
-    bool isShowBtnGrp_ = false;\r
-    UIViewGroup* btnGrp_ = nullptr;\r
     uint8_t loadNum_ = 0;\r
-    UILabelButton* imgWidthAddBtn_ = nullptr;\r
-    UILabelButton* imgWidthSubBtn_ = nullptr;\r
     uint16_t imgWidth_ = 200;  // 200: default value\r
     uint16_t imgPadding_ = 50;  // 50: default value\r
     uint8_t mirrorOpa_ = 30;    // 30: default value\r
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_adapter.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_adapter.cpp
new file mode 100644 (file)
index 0000000..3b32e16
--- /dev/null
@@ -0,0 +1,70 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.\r
+ * Description: UITestTransitionAdapter\r
+ * Create: 2025-04\r
+ */\r
+\r
+#include "ui_test_transition_adapter.h"\r
+#include "ui_test_transition_itemview.h"\r
+\r
+namespace OHOS {\r
+    UITestTransitionAdapter::UITestTransitionAdapter() {}\r
+\r
+    UITestTransitionAdapter::~UITestTransitionAdapter()\r
+    {\r
+        listData_.clear();\r
+    }\r
+\r
+    uint16_t UITestTransitionAdapter::GetCount(void)\r
+    {\r
+        return listData_.size();\r
+    }\r
+\r
+    void UITestTransitionAdapter::SetData(std::list<UITestTransitionSample> &data)\r
+    {\r
+        if (!listData_.empty()) {\r
+            listData_.clear();\r
+        }\r
+        std::list<UITestTransitionSample>::iterator it;\r
+        UITestTransitionSample temp;\r
+        for (it = data.begin(); it != data.end(); it++) {\r
+            listData_.push_back(std::make_pair(*it, temp));\r
+        }\r
+    }\r
+\r
+    UIView* UITestTransitionAdapter::GetView(UIView* inView, int16_t index)\r
+    {\r
+        if (listData_.empty()) {\r
+            return nullptr;\r
+        }\r
+        if (index < 0) {\r
+            return nullptr;\r
+        }\r
+        size_t uindex = index;\r
+        if (uindex >= listData_.size()) {\r
+            return nullptr;\r
+        }\r
+\r
+        auto it = listData_.begin();\r
+        for (int i = 0; i < index; i++) {\r
+            it++;\r
+        }\r
+        UITestTransitionSample leftItemData = it->first;\r
+        UITestTransitionSample rightItemData = it->second;\r
+        UITestTransitionItemView* item = nullptr;\r
+        if (inView == nullptr) {\r
+            item = new UITestTransitionItemView();\r
+        } else {\r
+            item = static_cast<UITestTransitionItemView* >(inView);\r
+        }\r
+\r
+        item->SetItemInfo(leftItemData, rightItemData);\r
+        item->SetOnClickListener(itemClickListener_);\r
+        return item;\r
+    }\r
+\r
+    void UITestTransitionAdapter::AddListItem(const UITestTransitionSample &litem, const UITestTransitionSample &ritem)\r
+    {\r
+        listData_.push_back(std::make_pair(litem, ritem));\r
+    }\r
+} // namespace OHOS\r
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_adapter.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_adapter.h
new file mode 100644 (file)
index 0000000..e634792
--- /dev/null
@@ -0,0 +1,40 @@
+/*\r
+* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.\r
+ * Description: UITestTransitionAdapter\r
+ * Create: 2025-04\r
+ */\r
+\r
+#ifndef UI_TEST_TRAINSTION_ADAPTER_H\r
+#define UI_TEST_TRAINSTION_ADAPTER_H\r
+\r
+#include <list>\r
+#include "ohos_types.h"\r
+#include "components/ui_view_group.h"\r
+#include "components/abstract_adapter.h"\r
+#include "ui_test_transition_model.h"\r
+\r
+namespace OHOS {\r
+class UITestTransitionAdapter : public AbstractAdapter {\r
+public:\r
+    explicit UITestTransitionAdapter();\r
+    ~UITestTransitionAdapter() override;\r
+\r
+    void SetData(std::list<UITestTransitionSample> &data);\r
+\r
+    uint16_t GetCount(void) override;\r
+\r
+    UIView* GetView(UIView* inView, int16_t index) override;\r
+\r
+    void AddListItem(const UITestTransitionSample &litem, const UITestTransitionSample &ritem);\r
+\r
+    void SetItemClickListener(UIView::OnClickListener* itemclicklistener)\r
+    {\r
+        itemClickListener_ = itemclicklistener;\r
+    }\r
+private:\r
+    std::list<std::pair<UITestTransitionSample, UITestTransitionSample>> listData_;\r
+    UIView::OnClickListener* itemClickListener_{nullptr};\r
+};\r
+}\r
+\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_itemview.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_itemview.cpp
new file mode 100644 (file)
index 0000000..33932e4
--- /dev/null
@@ -0,0 +1,210 @@
+/*\r
+* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.\r
+ * Description: UiTestTransitionItemView.cpp\r
+ * Create: 2025-04\r
+ */\r
+\r
+#include "ui_test_transition_itemview.h"\r
+#include "common/image_cache_manager.h"\r
+#include "UiConfig.h"\r
+#include "gfx_utils/graphic_log.h"\r
+\r
+namespace OHOS {\r
+\r
+    static constexpr int16_t NUMS_2 = 2;\r
+    static constexpr int16_t ITEM_BUTTON_WIDTH = HORIZONTAL_RESOLUTION / NUMS_2;\r
+    static constexpr int16_t ANIMATOR_SICON_SIZE = 148;\r
+    static constexpr int16_t ANIMATOR_SICON_POINT_X = (ITEM_BUTTON_WIDTH - ANIMATOR_SICON_SIZE) / NUMS_2;\r
+    static constexpr int16_t ANIMATOR_SICON_POINT_Y = 150;\r
+    static constexpr int16_t BIND_IMAGE_DELAY = 180;\r
+    static constexpr int16_t PAUSE_TIME = 800;\r
+    static constexpr int16_t ITEM_LABEL_X = 0;\r
+    static constexpr int16_t ITEM_LABEL_Y = 320;\r
+    static constexpr int16_t ITEM_LABEL_WIDTH = ITEM_BUTTON_WIDTH;\r
+    static constexpr int16_t ITEM_LABEL_HEIGHT = 40;\r
+    static constexpr int16_t SETTING_ITEM_FONT_SIZE = 30;\r
+    static constexpr int16_t SETTING_BASE_ICON_X = ANIMATOR_SICON_POINT_X - 21;\r
+    static constexpr int16_t SETTING_BASE_ICON_Y = ANIMATOR_SICON_POINT_Y - 21;\r
+    static constexpr int16_t BACKDROP_ICON_SIZE = 190;\r
+\r
+    UITestTransitionItemView::UITestTransitionItemView()\r
+    {\r
+        SetPosition(0, 0, HORIZONTAL_RESOLUTION, VERTICAL_RESOLUTION);\r
+        SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);\r
+        SetStyle(STYLE_BACKGROUND_OPA, UN_OPACITY);\r
+        SetTouchable(true);\r
+        SetUpChild();\r
+\r
+        Add(&leftPreviewIcon_);\r
+        Add(&sAnimator_);\r
+        Add(&sLabel_);\r
+        Add(&rightPreviewIcon_);\r
+        Add(&rightAnimator_);\r
+        Add(&rightLabel_);\r
+    }\r
+\r
+    UITestTransitionItemView::~UITestTransitionItemView()\r
+    {\r
+        Remove(&sAnimator_);\r
+        Remove(&sLabel_);\r
+        Remove(&leftPreviewIcon_);\r
+        Remove(&rightPreviewIcon_);\r
+        Remove(&rightAnimator_);\r
+        Remove(&rightLabel_);\r
+    }\r
+\r
+    void UITestTransitionItemView::SetItemInfo(const UITestTransitionSample& leftItemInfo,\r
+        const UITestTransitionSample& rightItemInfo)\r
+    {\r
+        leftItemInfo_ = leftItemInfo;\r
+        rightItemInfo_ = rightItemInfo;\r
+\r
+        sLabel_.SetText(leftItemInfo_.label);\r
+        if (!LoadMultiImages(leftItemInfo_, false)) {\r
+            GRAPHIC_LOGE("leftItemInfo_ cannot open file: %s", leftItemInfo_.resourceImage);\r
+            return;\r
+        }\r
+\r
+        rightLabel_.SetText(rightItemInfo_.label);\r
+        if (!LoadMultiImages(rightItemInfo_, true)) {\r
+            GRAPHIC_LOGE("rightItemInfo_ cannot open file: %s", rightItemInfo_.resourceImage);\r
+            return;\r
+        }\r
+        SetUpChild();\r
+    }\r
+\r
+    bool UITestTransitionItemView::LoadMultiImages(UITestTransitionSample& itemInfo, bool right)\r
+    {\r
+        UIImageView* previewIcon = &leftPreviewIcon_;\r
+        UIImageAnimatorView* animator = &sAnimator_;\r
+        uint16_t animatorSiconX =  ANIMATOR_SICON_POINT_X;\r
+        if (right) {\r
+            previewIcon = &rightPreviewIcon_;\r
+            animator = &rightAnimator_;\r
+            animatorSiconX = ANIMATOR_SICON_POINT_X + ITEM_BUTTON_WIDTH;\r
+        }\r
+\r
+        if (itemInfo.viewId == 0) { // 0: UI_INVALIDE\r
+            previewIcon->SetVisible(false);\r
+            animator->SetVisible(false);\r
+            GRAPHIC_LOGE("itemInfo.viewId is  UI_INVALIDE");\r
+            return false;\r
+        }\r
+        \r
+        FILE* fp = fopen(itemInfo.resourceImage, "rb");\r
+        if (fp == nullptr) {\r
+            GRAPHIC_LOGE("cannot open file: %s", itemInfo.resourceImage);\r
+            return false;\r
+        }\r
+\r
+        previewIcon->SetSrc(ImageCacheManager::GetInstance().\r
+            LoadOneInMultiRes(itemInfo.resIds[0], itemInfo.resourceImage, fp));\r
+\r
+        uint8_t imageNum = itemInfo.resIds.size();\r
+        std::vector<ImageAnimatorInfo> searchImageInfo(imageNum);\r
+        for (uint8_t i = 0; i < imageNum; i++) {\r
+            searchImageInfo[i].imageInfo = ImageCacheManager::GetInstance().LoadOneInMultiRes(\r
+                itemInfo.resIds[i], itemInfo.resourceImage, fp);\r
+            searchImageInfo[i].imageType = IMG_SRC_IMAGE_INFO;\r
+            searchImageInfo[i].pos.x = animatorSiconX;\r
+            searchImageInfo[i].pos.y = ANIMATOR_SICON_POINT_Y;\r
+            searchImageInfo[i].width = ANIMATOR_SICON_SIZE;\r
+            searchImageInfo[i].height = ANIMATOR_SICON_SIZE;\r
+        }\r
+        animator->SetImageAnimatorSrc(searchImageInfo.data(), imageNum, BIND_IMAGE_DELAY);\r
+        fclose(fp);\r
+        return true;\r
+    }\r
+\r
+    void UITestTransitionItemView::SetUpChild()\r
+    {\r
+        sAnimator_.SetPosition(ANIMATOR_SICON_POINT_X, ANIMATOR_SICON_POINT_Y);\r
+        sAnimator_.Resize(ANIMATOR_SICON_SIZE, ANIMATOR_SICON_SIZE);\r
+        sAnimator_.SetStyle(STYLE_IMAGE_OPA, OPA_OPAQUE);\r
+        sAnimator_.SetRepeat(true);\r
+        sAnimator_.SetTimeOfPause(PAUSE_TIME);\r
+        sAnimator_.Start();\r
+\r
+        leftPreviewIcon_.SetPosition(ANIMATOR_SICON_POINT_X, ANIMATOR_SICON_POINT_Y);\r
+        leftPreviewIcon_.Resize(ANIMATOR_SICON_SIZE, ANIMATOR_SICON_SIZE);\r
+        leftPreviewIcon_.SetStyle(STYLE_IMAGE_OPA, OPA_OPAQUE);\r
+        leftPreviewIcon_.SetVisible(true);\r
+\r
+        sLabel_.SetPosition(ITEM_LABEL_X, ITEM_LABEL_Y);\r
+        sLabel_.Resize(ITEM_LABEL_WIDTH, ITEM_LABEL_HEIGHT);\r
+        sLabel_.SetFont(DEFAULT_VECTOR_FONT_FILENAME, SETTING_ITEM_FONT_SIZE);\r
+        sLabel_.SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);\r
+        sLabel_.SetStyle(STYLE_TEXT_OPA, OPA_OPAQUE);\r
+        sLabel_.SetStyle(STYLE_TEXT_COLOR, Color::White().full);\r
+        sLabel_.SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);\r
+        sLabel_.SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);\r
+\r
+        rightAnimator_.SetStyle(STYLE_IMAGE_OPA, OPA_OPAQUE);\r
+        rightAnimator_.SetRepeat(true);\r
+        rightAnimator_.SetTimeOfPause(PAUSE_TIME);\r
+        rightAnimator_.Start();\r
+\r
+        rightPreviewIcon_.SetPosition(ITEM_BUTTON_WIDTH + ANIMATOR_SICON_POINT_X, ANIMATOR_SICON_POINT_Y);\r
+        rightPreviewIcon_.Resize(ANIMATOR_SICON_SIZE, ANIMATOR_SICON_SIZE);\r
+        rightPreviewIcon_.SetStyle(STYLE_IMAGE_OPA, OPA_OPAQUE);\r
+        rightPreviewIcon_.SetVisible(true);\r
+\r
+        rightLabel_.SetPosition(ITEM_BUTTON_WIDTH + ITEM_LABEL_X, ITEM_LABEL_Y);\r
+        rightLabel_.Resize(ITEM_LABEL_WIDTH, ITEM_LABEL_HEIGHT);\r
+        rightLabel_.SetFont(DEFAULT_VECTOR_FONT_FILENAME, SETTING_ITEM_FONT_SIZE);\r
+        rightLabel_.SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);\r
+        rightLabel_.SetStyle(STYLE_TEXT_OPA, OPA_OPAQUE);\r
+        rightLabel_.SetStyle(STYLE_TEXT_COLOR, Color::White().full);\r
+        rightLabel_.SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);\r
+        rightLabel_.SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);\r
+    }\r
+\r
+    uint16_t UITestTransitionItemView::GetClickViewId(const ClickEvent& event)\r
+    {\r
+        int16_t clickY = event.GetCurrentPos().y;\r
+        int16_t minItemY = SETTING_BASE_ICON_Y;\r
+        int16_t maxItemY = SETTING_BASE_ICON_Y + BACKDROP_ICON_SIZE + ITEM_LABEL_HEIGHT;\r
+        // Check if the click position is within the valid Y-axis range\r
+        if (clickY < minItemY || clickY > maxItemY) {\r
+            // 0 indicates an invalid UI element\r
+            return 0;\r
+        }\r
+\r
+        int16_t clickX = event.GetCurrentPos().x;\r
+        int16_t leftItemX = SETTING_BASE_ICON_X;\r
+        int16_t rightItemX = ITEM_BUTTON_WIDTH + SETTING_BASE_ICON_X;\r
+        int16_t itemWidth = BACKDROP_ICON_SIZE;\r
+        // Check if the click position is within the left item's X-axis range\r
+        if (clickX > leftItemX && clickX < (leftItemX + itemWidth)) {\r
+            return leftItemInfo_.viewId;\r
+        }\r
+\r
+        // Check if the click position is within the right item's X-axis range\r
+        if (clickX > rightItemX && clickX < rightItemX + itemWidth) {\r
+            return rightItemInfo_.viewId;\r
+        }\r
+\r
+        // 0 indicates an invalid UI element\r
+        return 0;\r
+    }\r
+\r
+    void UITestTransitionItemView::SelectedChange()\r
+    {\r
+        sAnimator_.SetVisible(true);\r
+        sAnimator_.Start();\r
+        rightAnimator_.SetVisible(true);\r
+        rightAnimator_.Start();\r
+        leftPreviewIcon_.SetVisible(false);\r
+        rightPreviewIcon_.SetVisible(false);\r
+    }\r
+\r
+    void UITestTransitionItemView::Reset()\r
+    {\r
+        sAnimator_.SetVisible(false);\r
+        sAnimator_.Stop();\r
+        rightAnimator_.SetVisible(false);\r
+        rightAnimator_.Stop();\r
+        leftPreviewIcon_.SetVisible(true);\r
+        rightPreviewIcon_.SetVisible(true);\r
+    }\r
+}
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_itemview.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_itemview.h
new file mode 100644 (file)
index 0000000..f7b38e7
--- /dev/null
@@ -0,0 +1,43 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.\r
+ * Description: UITestTransitionItemView\r
+ * Create: 2025-04\r
+ */\r
+\r
+#ifndef UI_TEST_TRAINSTION_ITEM_VIEW_H_\r
+#define UI_TEST_TRAINSTION_ITEM_VIEW_H_\r
+\r
+#include "components/ui_label.h"\r
+#include "components/ui_view_group.h"\r
+#include "components/ui_image_view.h"\r
+#include "components/ui_image_animator.h"\r
+#include "ui_test_transition_sample.h"\r
+\r
+\r
+namespace OHOS {\r
+class UITestTransitionItemView : public UIViewGroup {\r
+public:\r
+    explicit UITestTransitionItemView();\r
+    ~UITestTransitionItemView() override;\r
+    virtual void SetItemInfo(const UITestTransitionSample& leftItemInfo, const UITestTransitionSample& rightItemInfo);\r
+    virtual void SetUpChild();\r
+    uint16_t GetClickViewId(const ClickEvent& event);\r
+    void SelectedChange();\r
+    void Reset();\r
+    bool LoadMultiImages(UITestTransitionSample& itemInfo, bool right);\r
+private:\r
+    UILabel sLabel_;\r
+    UILabel rightLabel_;\r
+\r
+    UIImageAnimatorView sAnimator_;\r
+    UIImageAnimatorView rightAnimator_;\r
+    \r
+    UIImageView leftPreviewIcon_;\r
+    UIImageView rightPreviewIcon_;\r
+\r
+    UITestTransitionSample leftItemInfo_;\r
+    UITestTransitionSample rightItemInfo_;\r
+};\r
+}\r
+\r
+#endif\r
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_model.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_model.cpp
new file mode 100644 (file)
index 0000000..6a7a62b
--- /dev/null
@@ -0,0 +1,159 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.\r
+ * Description: UITestTransitionModel\r
+ * Create: 2025-04\r
+ */\r
+\r
+#include <map>\r
+#include <string>\r
+#include <cstdint>\r
+#include <vector>\r
+#include "ohos_errno.h"\r
+#include "securec.h"\r
+#include "UiConfig.h"\r
+#include "wearable_log.h"\r
+#include "ui_test_transition_model.h"\r
+\r
+namespace OHOS {\r
+    static const int DIR_MASK = 0xfff00000;\r
+    static const int PNG_MASK = 0x000fffff;\r
+    static const int PNG_3D_FOLD_01 = 0x100001;\r
+    static const int PNG_3D_FOLD_02 = 0x100002;\r
+    static const int PNG_3D_FOLD_03 = 0x100003;\r
+    static const int PNG_3D_FOLD_04 = 0x100004;\r
+    static const int PNG_3D_FOLD_05 = 0x100005;\r
+    static const int PNG_3D_FOLD_06 = 0x100006;\r
+    static const int PNG_3D_FOLD_07 = 0x100007;\r
+    static const int PNG_3D_FOLD_08 = 0x100008;\r
+    static const int PNG_3D_FOLD_09 = 0x100009;\r
+    static const int PNG_3D_FOLD_10 = 0x10000a;\r
+    static const int PNG_CARD_FLIP_01 = 0x10000b;\r
+    static const int PNG_CARD_FLIP_02 = 0x10000c;\r
+    static const int PNG_CARD_FLIP_03 = 0x10000d;\r
+    static const int PNG_CARD_FLIP_04 = 0x10000e;\r
+    static const int PNG_CARD_FLIP_05 = 0x10000f;\r
+    static const int PNG_CARD_FLIP_06 = 0x100010;\r
+    static const int PNG_CARD_FLIP_07 = 0x100011;\r
+    static const int PNG_CARD_FLIP_08 = 0x100012;\r
+    static const int PNG_CARD_FLIP_09 = 0x100013;\r
+    static const int PNG_CARD_FLIP_10 = 0x100014;\r
+    static const int PNG_DESKTOP_BG = 0x100015;\r
+    static const int PNG_FADEINOUT_01 = 0x100016;\r
+    static const int PNG_FADEINOUT_02 = 0x100017;\r
+    static const int PNG_FADEINOUT_03 = 0x100018;\r
+    static const int PNG_FADEINOUT_04 = 0x100019;\r
+    static const int PNG_FADEINOUT_05 = 0x10001a;\r
+    static const int PNG_FADEINOUT_06 = 0x10001b;\r
+    static const int PNG_FADEINOUT_07 = 0x10001c;\r
+    static const int PNG_FADEINOUT_08 = 0x10001d;\r
+    static const int PNG_FADEINOUT_09 = 0x10001e;\r
+    static const int PNG_FADEINOUT_10 = 0x10001f;\r
+    static const int PNG_GAUSSIAN_01 = 0x100020;\r
+    static const int PNG_GAUSSIAN_02 = 0x100021;\r
+    static const int PNG_GAUSSIAN_03 = 0x100022;\r
+    static const int PNG_GAUSSIAN_04 = 0x100023;\r
+    static const int PNG_GAUSSIAN_05 = 0x100024;\r
+    static const int PNG_GAUSSIAN_06 = 0x100025;\r
+    static const int PNG_GAUSSIAN_07 = 0x100026;\r
+    static const int PNG_GAUSSIAN_08 = 0x100027;\r
+    static const int PNG_GAUSSIAN_09 = 0x100028;\r
+    static const int PNG_GAUSSIAN_10 = 0x100029;\r
+    static const int PNG_SLICE_ZOOM_01 = 0x10002a;\r
+    static const int PNG_SLICE_ZOOM_02 = 0x10002b;\r
+    static const int PNG_SLICE_ZOOM_03 = 0x10002c;\r
+    static const int PNG_SLICE_ZOOM_04 = 0x10002d;\r
+    static const int PNG_SLICE_ZOOM_05 = 0x10002e;\r
+    static const int PNG_SLICE_ZOOM_06 = 0x10002f;\r
+    static const int PNG_SLICE_ZOOM_07 = 0x100030;\r
+    static const int PNG_SLICE_ZOOM_08 = 0x100031;\r
+    static const int PNG_SLICE_ZOOM_09 = 0x100032;\r
+    static const int PNG_SLICE_ZOOM_10 = 0x100033;\r
+    static const int PNG_TRAINSTION_END = 0x100034;\r
+    static const int PNG_TRAINSTION_START = 0x100035;\r
+    static const int PNG_TRANSPARENTGRADIENT_01 = 0x100036;\r
+    static const int PNG_TRANSPARENTGRADIENT_02 = 0x100037;\r
+    static const int PNG_TRANSPARENTGRADIENT_03 = 0x100038;\r
+    static const int PNG_TRANSPARENTGRADIENT_04 = 0x100039;\r
+    static const int PNG_TRANSPARENTGRADIENT_05 = 0x10003a;\r
+    static const int PNG_TRANSPARENTGRADIENT_06 = 0x10003b;\r
+    static const int PNG_TRANSPARENTGRADIENT_07 = 0x10003c;\r
+    static const int PNG_TRANSPARENTGRADIENT_08 = 0x10003d;\r
+    static const int PNG_TRANSPARENTGRADIENT_09 = 0x10003e;\r
+    static const int PNG_TRANSPARENTGRADIENT_10 = 0x10003f;\r
+\r
+    static std::vector<int> PNG_FADEINOUT_RESIDS = {\r
+        PNG_TRAINSTION_START, PNG_FADEINOUT_01, PNG_FADEINOUT_02, PNG_FADEINOUT_03, PNG_FADEINOUT_04, PNG_FADEINOUT_05,\r
+        PNG_FADEINOUT_06, PNG_FADEINOUT_07, PNG_FADEINOUT_08, PNG_FADEINOUT_09, PNG_FADEINOUT_10, PNG_TRAINSTION_END,\r
+        PNG_TRAINSTION_END, PNG_FADEINOUT_10, PNG_FADEINOUT_09, PNG_FADEINOUT_08, PNG_FADEINOUT_07, PNG_FADEINOUT_06,\r
+        PNG_FADEINOUT_05, PNG_FADEINOUT_04, PNG_FADEINOUT_03, PNG_FADEINOUT_02, PNG_FADEINOUT_01, PNG_TRAINSTION_START\r
+    };\r
+\r
+    static std::vector<int> PNG_TRANSPARENTGRADIENT_RESIDS = {\r
+        PNG_TRAINSTION_START, PNG_TRANSPARENTGRADIENT_01, PNG_TRANSPARENTGRADIENT_02, PNG_TRANSPARENTGRADIENT_03,\r
+        PNG_TRANSPARENTGRADIENT_04, PNG_TRANSPARENTGRADIENT_05, PNG_TRANSPARENTGRADIENT_06, PNG_TRANSPARENTGRADIENT_07,\r
+        PNG_TRANSPARENTGRADIENT_08, PNG_TRANSPARENTGRADIENT_09, PNG_TRANSPARENTGRADIENT_10, PNG_TRAINSTION_END,\r
+        PNG_TRAINSTION_END, PNG_TRANSPARENTGRADIENT_10, PNG_TRANSPARENTGRADIENT_09, PNG_TRANSPARENTGRADIENT_08,\r
+        PNG_TRANSPARENTGRADIENT_07, PNG_TRANSPARENTGRADIENT_06, PNG_TRANSPARENTGRADIENT_05, PNG_TRANSPARENTGRADIENT_04,\r
+        PNG_TRANSPARENTGRADIENT_03, PNG_TRANSPARENTGRADIENT_02, PNG_TRANSPARENTGRADIENT_01, PNG_TRAINSTION_START\r
+    };\r
+\r
+    static std::vector<int> PNG_GAUSSIAN_RESIDS = {\r
+        PNG_TRAINSTION_START, PNG_GAUSSIAN_01, PNG_GAUSSIAN_02, PNG_GAUSSIAN_03, PNG_GAUSSIAN_04, PNG_GAUSSIAN_05,\r
+        PNG_GAUSSIAN_06, PNG_GAUSSIAN_07, PNG_GAUSSIAN_08, PNG_GAUSSIAN_09, PNG_GAUSSIAN_10, PNG_TRAINSTION_END,\r
+        PNG_TRAINSTION_END, PNG_GAUSSIAN_10, PNG_GAUSSIAN_09, PNG_GAUSSIAN_08, PNG_GAUSSIAN_07, PNG_GAUSSIAN_06,\r
+        PNG_GAUSSIAN_05, PNG_GAUSSIAN_04, PNG_GAUSSIAN_03, PNG_GAUSSIAN_02, PNG_GAUSSIAN_01, PNG_TRAINSTION_START\r
+    };\r
+\r
+    static std::vector<int> PNG_CARD_FLIP_RESIDS = {\r
+        PNG_TRAINSTION_START, PNG_CARD_FLIP_01, PNG_CARD_FLIP_02, PNG_CARD_FLIP_03, PNG_CARD_FLIP_04, PNG_CARD_FLIP_05,\r
+        PNG_CARD_FLIP_06, PNG_CARD_FLIP_07, PNG_CARD_FLIP_08, PNG_CARD_FLIP_09, PNG_CARD_FLIP_10, PNG_TRAINSTION_END,\r
+        PNG_TRAINSTION_END, PNG_CARD_FLIP_10, PNG_CARD_FLIP_09, PNG_CARD_FLIP_08, PNG_CARD_FLIP_07, PNG_CARD_FLIP_06,\r
+        PNG_CARD_FLIP_05, PNG_CARD_FLIP_04, PNG_CARD_FLIP_03, PNG_CARD_FLIP_02, PNG_CARD_FLIP_01, PNG_TRAINSTION_START,\r
+    };\r
+\r
+    static std::vector<int> PNG_SLICE_ZOOM_RESIDS = {\r
+        PNG_TRAINSTION_START, PNG_SLICE_ZOOM_01, PNG_SLICE_ZOOM_02, PNG_SLICE_ZOOM_03, PNG_SLICE_ZOOM_04,\r
+        PNG_SLICE_ZOOM_05, PNG_SLICE_ZOOM_06, PNG_SLICE_ZOOM_07, PNG_SLICE_ZOOM_08, PNG_SLICE_ZOOM_09,\r
+        PNG_SLICE_ZOOM_10, PNG_TRAINSTION_END,\r
+        PNG_TRAINSTION_END, PNG_SLICE_ZOOM_10, PNG_SLICE_ZOOM_09, PNG_SLICE_ZOOM_08, PNG_SLICE_ZOOM_07,\r
+        PNG_SLICE_ZOOM_06, PNG_SLICE_ZOOM_05, PNG_SLICE_ZOOM_04, PNG_SLICE_ZOOM_03, PNG_SLICE_ZOOM_02,\r
+        PNG_SLICE_ZOOM_01, PNG_TRAINSTION_START,\r
+    };\r
+\r
+    static std::vector<int> PNG_3D_FOLD_RESIDS = {\r
+        PNG_TRAINSTION_START, PNG_3D_FOLD_01, PNG_3D_FOLD_02, PNG_3D_FOLD_03, PNG_3D_FOLD_04, PNG_3D_FOLD_05,\r
+        PNG_3D_FOLD_06, PNG_3D_FOLD_07, PNG_3D_FOLD_08, PNG_3D_FOLD_09, PNG_3D_FOLD_10, PNG_TRAINSTION_END,\r
+        PNG_TRAINSTION_END, PNG_3D_FOLD_10, PNG_3D_FOLD_09, PNG_3D_FOLD_08, PNG_3D_FOLD_07, PNG_3D_FOLD_06,\r
+        PNG_3D_FOLD_05, PNG_3D_FOLD_04, PNG_3D_FOLD_03, PNG_3D_FOLD_02, PNG_3D_FOLD_01, PNG_TRAINSTION_START,\r
+    };\r
+\r
+    static const std::map<TransitionType, std::pair<std::string, std::vector<int>>> g_transitionsMap = {\r
+        {TransitionType::TRANSITION_FADEINOUT, std::make_pair("淡入淡出", PNG_FADEINOUT_RESIDS)},\r
+        {TransitionType::TRANSITION_TRANSPARENT_GRADIENT, std::make_pair("透明渐变", PNG_TRANSPARENTGRADIENT_RESIDS)},\r
+        {TransitionType::TRANSITION_GAUSSIAN_BLUR, std::make_pair("高斯模糊", PNG_GAUSSIAN_RESIDS)},\r
+        {TransitionType::TRANSITION_CROSS_SHAPED, std::make_pair("十字平滑", PNG_CARD_FLIP_RESIDS)},\r
+        {TransitionType::TRANSITION_ZOOM, std::make_pair("缩放", PNG_SLICE_ZOOM_RESIDS)},\r
+        {TransitionType::TRANSITION_3DFOLD, std::make_pair("3D折叠", PNG_3D_FOLD_RESIDS)},\r
+    };\r
+\r
+    UITestTransitionModel::UITestTransitionModel()\r
+    {\r
+        for (const auto& entry: g_transitionsMap) {\r
+            UITestTransitionSample info(static_cast<uint16_t>(entry.first), entry.second.second,\\r
+                                    entry.second.first.c_str(), PNG_TRANSITION_SLICE_SAMPLE);\r
+            transitionInfoList_.push_back(info);\r
+        }\r
+    }\r
+    UITestTransitionModel::~UITestTransitionModel() {}\r
+\r
+    UITestTransitionModel& UITestTransitionModel::GetInstance(void)\r
+    {\r
+        static UITestTransitionModel instance;\r
+        return instance;\r
+    }\r
+\r
+    std::list<UITestTransitionSample> UITestTransitionModel::GetTransitionListItems()\r
+    {\r
+        return transitionInfoList_;\r
+    }\r
+}
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_model.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_model.h
new file mode 100644 (file)
index 0000000..3021930
--- /dev/null
@@ -0,0 +1,31 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.\r
+ * Description: UITestTransitionModel\r
+ * Create: 2025-04\r
+ */\r
+\r
+#ifndef UI_TEST_TRANSITION_MODEL_H\r
+#define UI_TEST_TRANSITION_MODEL_H\r
+\r
+#include <list>\r
+#include <vector>\r
+#include "TransitionType.h"\r
+#include "ui_test_transition_sample.h"\r
+\r
+namespace OHOS {\r
+\r
+    class UITestTransitionModel {\r
+    public:\r
+        static UITestTransitionModel &GetInstance(void);\r
+        std::list<UITestTransitionSample> GetTransitionListItems();\r
+    private:\r
+        UITestTransitionModel();\r
+        UITestTransitionModel(const UITestTransitionModel &);\r
+        UITestTransitionModel &operator=(const UITestTransitionModel &);\r
+        virtual ~UITestTransitionModel();\r
+\r
+        std::list<UITestTransitionSample> transitionInfoList_;\r
+    };\r
+}\r
+\r
+#endif // UI_TEST_TRANSITION_MODEL_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_sample.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_sample.h
new file mode 100644 (file)
index 0000000..462ad04
--- /dev/null
@@ -0,0 +1,31 @@
+/*\r
+* Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.\r
+ * Description: UITestTransitionSample\r
+ * Create: 2025-04\r
+ */\r
+\r
+#ifndef UI_TEST_TRANSITION_SAMPLE_H\r
+#define UI_TEST_TRANSITION_SAMPLE_H\r
+\r
+#include <list>\r
+#include <vector>\r
+\r
+namespace OHOS {\r
+\r
+    struct UITestTransitionSample {\r
+        uint16_t viewId;\r
+        std::vector<int> resIds;\r
+        const char* label;\r
+        const char* resourceImage;\r
+\r
+        explicit UITestTransitionSample(uint16_t viewId = 0, std::vector<int> resIds = {},\r
+                const char* label = nullptr, const char* resourceImage = nullptr)\r
+            : viewId(viewId),\r
+            resIds(std::move(resIds)),\r
+            label(label),\r
+            resourceImage(resourceImage)\r
+            {}\r
+    };\r
+}\r
+\r
+#endif // UI_TEST_TRANSITION_SAMPLE_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_view.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_view.cpp
new file mode 100644 (file)
index 0000000..de751da
--- /dev/null
@@ -0,0 +1,177 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.\r
+ * Description: UITestTransitionView\r
+ * Create: 2025-04\r
+ */\r
+\r
+#include "AppViewIDs.h"\r
+#include "components/ui_scroll_view_nested.h"\r
+#include "components/ui_list_nested.h"\r
+#include "NativeAbility.h"\r
+#include "PageTransitionMgr.h"\r
+#include "TransitionType.h"\r
+#include "UiConfig.h"\r
+#include "ui_test_transition_itemview.h"\r
+#include "ui_test_transition_model.h"\r
+#include "ui_test_transition_view.h"\r
+\r
+\r
+namespace OHOS {\r
+    static constexpr uint8_t SETTINGS_ITEM_FONT_SIZE = 40;\r
+    static constexpr int16_t SETTINGS_RESIZE_SIZE_WIDTH = 260;\r
+    static constexpr int16_t SETTINGS_RESIZE_SIZE_HEIGHT = 60;\r
+    static constexpr int16_t SETTING_TITLE_POSITION_X = 100;\r
+    static constexpr int16_t SETTING_TITLE_POSITION_Y = 20;\r
+    static constexpr int16_t SETTING_LIST_POSITION_X = 0;\r
+    static constexpr int16_t SETTING_LIST_POSITION_Y = 0;\r
+    static constexpr int16_t SETTING_SCROLLBLANKSIZE = 100;\r
+    static constexpr int16 MAX_SCR_DIS = 1000;\r
+    static constexpr int16 SNUM_2 = 2;\r
+    static constexpr int16 SNUM_4 = 4;\r
+\r
+    template <typename T>\r
+    void SafeDelete(T*& ptr)\r
+    {\r
+        if (ptr != nullptr) {\r
+            delete ptr;\r
+            ptr = nullptr;\r
+        }\r
+    }\r
+\r
+    UITestTransitionView::~UITestTransitionView()\r
+    {\r
+        if (scrollView_ != nullptr) {\r
+            scrollView_->RemoveAll();\r
+            delete scrollView_;\r
+            scrollView_ = nullptr;\r
+        }\r
+\r
+        if (contentList_ != nullptr) {\r
+            delete contentList_;\r
+            contentList_ = nullptr;\r
+        }\r
+\r
+        if (listAdapter_ != nullptr) {\r
+            delete listAdapter_;\r
+            listAdapter_ = nullptr;\r
+        }\r
+    }\r
+\r
+    void UITestTransitionView::SetUp()\r
+    {\r
+        titleText_.SetPosition(SETTING_TITLE_POSITION_X, SETTING_TITLE_POSITION_Y);\r
+        titleText_.Resize(SETTINGS_RESIZE_SIZE_WIDTH, SETTINGS_RESIZE_SIZE_HEIGHT);\r
+        titleText_.SetText("页面动效");\r
+        titleText_.SetFont(DEFAULT_VECTOR_FONT_FILENAME, SETTINGS_ITEM_FONT_SIZE);\r
+        titleText_.SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);\r
+        titleText_.SetStyle(STYLE_TEXT_OPA, OPA_OPAQUE);\r
+        titleText_.SetStyle(STYLE_TEXT_COLOR, Color::White().full);\r
+        titleText_.SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);\r
+        titleText_.SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);\r
+\r
+        contentList_ = new UIListNested(UIList::HORIZONTAL);\r
+        if (contentList_ == nullptr) {\r
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SetTransitionView::OnStart::contentList_ is nullptr");\r
+            return;\r
+        }\r
+\r
+        contentList_->SetPosition(SETTING_LIST_POSITION_X, SETTING_LIST_POSITION_Y);\r
+        contentList_->Resize(HORIZONTAL_RESOLUTION, VERTICAL_RESOLUTION);\r
+        contentList_->SetScrollBlankSize(SETTING_SCROLLBLANKSIZE);\r
+        // middle position\r
+        contentList_->SetSelectPosition(HORIZONTAL_RESOLUTION / SNUM_2);\r
+        contentList_->SetDraggable(true);\r
+        contentList_->SetThrowDrag(true);\r
+        contentList_->SetLoopState(false);\r
+        contentList_->EnableAutoAlign(true);\r
+        contentList_->SetMaxScrollDistance(MAX_SCR_DIS);\r
+\r
+        listAdapter_ = new UITestTransitionAdapter();\r
+        const std::list<UITestTransitionSample> effectList =\r
+            UITestTransitionModel::GetInstance().GetTransitionListItems();\r
+        if (listAdapter_ == nullptr) {\r
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "new SetTransitionAdapter failed...");\r
+            return;\r
+        }\r
+        listAdapter_->SetItemClickListener(this);\r
+\r
+        auto it = effectList.begin();\r
+        while (it != effectList.end()) {\r
+            UITestTransitionSample sample;\r
+            UITestTransitionSample first = *it;\r
+            it++;\r
+            UITestTransitionSample second = (it != effectList.end()) ? *it: sample;\r
+            listAdapter_->AddListItem(first, second);\r
+            it++;\r
+        }\r
+        int16_t index = 0;\r
+        contentList_->SetAdapter(listAdapter_);\r
+        contentList_->ScrollTo(index);\r
+        contentList_->ScrollBy(SNUM_2);\r
+        contentList_->RefreshList();\r
+\r
+        // scroll view\r
+        scrollView_ = new UIScrollViewNested(UIAbstractScroll::HORIZONTAL);\r
+        if (scrollView_ == nullptr) {\r
+            WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "SetTransitionView::OnStart::scrollView_ is nullptr");\r
+            return;\r
+        }\r
+        scrollView_->SetPosition(0, 0, HORIZONTAL_RESOLUTION, VERTICAL_RESOLUTION);\r
+        scrollView_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Black().full);\r
+        scrollView_->SetStyle(STYLE_BACKGROUND_OPA, UN_OPACITY);\r
+        scrollView_->SetThrowDrag(true);\r
+\r
+        if (PageTransitionMgr::GetInstance().GetTopSlideBackImage() == nullptr) {\r
+            // support default slide back firstly\r
+            scrollView_->SetOnDragListener(this);\r
+        }\r
+        scrollView_->Add(contentList_);\r
+        scrollView_->Add(&titleText_);\r
+    }\r
+\r
+    void UITestTransitionView::TearDown()\r
+    {\r
+        if (scrollView_ != nullptr) {\r
+            scrollView_->RemoveAll();\r
+            delete scrollView_;\r
+            scrollView_ = nullptr;\r
+        }\r
+\r
+        SafeDelete(contentList_);\r
+        SafeDelete(listAdapter_);\r
+        SafeDelete(contentList_);\r
+    }\r
+\r
+    const UIView *OHOS::UITestTransitionView::GetTestView()\r
+    {\r
+        if (scrollView_ == nullptr) {\r
+            SetUp();\r
+        }\r
+        return scrollView_;\r
+    }\r
+\r
+    bool UITestTransitionView::OnClick(UIView &view, const ClickEvent &event)\r
+    {\r
+        UITestTransitionItemView *setTransitionView = static_cast<UITestTransitionItemView *>(&view);\r
+        TransitionType type = static_cast<TransitionType>(setTransitionView->GetClickViewId(event));\r
+        if (type != TransitionType::TRANSITION_INVALID) {\r
+            uint16_t priority = 4;\r
+            NativeAbility::GetInstance().ChangeSlice(VIEW_APPLIST, type, priority, true);\r
+        }\r
+        return false;\r
+    }\r
+\r
+    void UITestTransitionView::OnItemSelected(int16_t index, UIView *view)\r
+    {\r
+        UNUSED(index);\r
+        if (view != nullptr) {\r
+            itemViewSelected_ = static_cast<UITestTransitionItemView *>(view);\r
+            itemViewSelected_->SelectedChange();\r
+\r
+            if (preItemViewSelected_ != nullptr && preItemViewSelected_ != itemViewSelected_) {\r
+                itemViewSelected_->Reset();\r
+            }\r
+            preItemViewSelected_ = itemViewSelected_;\r
+        }\r
+    }\r
+}
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_view.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_transition/ui_test_transition_view.h
new file mode 100644 (file)
index 0000000..71f211f
--- /dev/null
@@ -0,0 +1,42 @@
+/*\r
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025-2025. All rights reserved.\r
+ * Description: UITestTransitionView\r
+ * Create: 2025-04\r
+ */\r
+\r
+#ifndef UI_TEST_TRANSITION_VIEW_H\r
+#define UI_TEST_TRANSITION_VIEW_H\r
+\r
+#include "common/screen.h"\r
+#include "components/ui_image_view.h"\r
+#include "components/ui_scroll_view.h"\r
+#include "components/ui_label.h"\r
+#include "components/ui_label_button.h"\r
+#include "components/ui_list.h"\r
+#include "components/ui_view.h"\r
+#include "core/render_manager.h"\r
+#include "ui_test.h"\r
+#include "ui_test_transition_adapter.h"\r
+#include "ui_test_transition_itemview.h"\r
+\r
+namespace OHOS {\r
+    class UITestTransitionView : public UITest, UIView::OnClickListener, ListScrollListener,\r
+            public UIView::OnDragListener {\r
+    public:\r
+        UITestTransitionView() {}\r
+        ~UITestTransitionView() override;\r
+        void SetUp() override;\r
+        void TearDown() override;\r
+        const UIView* GetTestView() override;\r
+        bool OnClick(UIView& view, const ClickEvent& event) override;\r
+        void OnItemSelected(int16_t index, UIView *view) override;\r
+    private:\r
+        UIScrollView *scrollView_{nullptr};\r
+        UIList *contentList_{nullptr};\r
+        UILabel titleText_;\r
+        UITestTransitionAdapter *listAdapter_{nullptr};\r
+        UITestTransitionItemView *itemViewSelected_{nullptr};\r
+        UITestTransitionItemView *preItemViewSelected_{nullptr};\r
+    };\r
+}\r
+#endif // UI_TEST_TRANSITION_VIEW_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_list/ui_test_ui_list.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_list/ui_test_ui_list.cpp
new file mode 100644 (file)
index 0000000..115cda0
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_ui_list.h"
+#include "common/screen.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "font/ui_font.h"
+
+namespace OHOS {
+namespace {
+    static int16_t g_buttonH = 80;
+    static int16_t g_buttonW = 200;
+    static int16_t g_blank = 20;
+    static int16_t g_listW = 200;
+    static int16_t g_listH = 400;
+    static int16_t g_selectPos = 150;
+    static int16_t g_blankSize = 250;
+}
+
+void UITestUIList::SetUp()
+{
+    lastX_ = 0;
+    lastY_ = 0;
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        container_->SetThrowDrag(true);
+    }
+    if (uiViewGroup1_ == nullptr) {
+        uiViewGroup1_ = new UIViewGroup();
+        uiViewGroup1_->SetPosition(0, 20, Screen::GetInstance().GetWidth(), 250); // 20: y pos; 250: height
+        container_->Add(uiViewGroup1_);
+    }
+    if (uiViewGroup2_ == nullptr) {
+        uiViewGroup2_ = new UIViewGroup();
+        uiViewGroup2_->SetPosition(0, 270, Screen::GetInstance().GetWidth(), 390); // 270: y pos; 390: height
+        container_->Add(uiViewGroup2_);
+    }
+
+    if (adapterData1_ == nullptr) {
+        adapterData1_ = new List<const char*>();
+        adapterData1_->PushBack("abcd0");
+        adapterData1_->PushBack("abcd1");
+        adapterData1_->PushBack("abcd2");
+        adapterData1_->PushBack("abcd3");
+    }
+    if (adapterData2_ == nullptr) {
+        adapterData2_ = new List<const char*>();
+        adapterData2_->PushBack("000");
+        adapterData2_->PushBack("111");
+        adapterData2_->PushBack("222");
+        adapterData2_->PushBack("333");
+        adapterData2_->PushBack("444");
+        adapterData2_->PushBack("555");
+        adapterData2_->PushBack("666");
+        adapterData2_->PushBack("777");
+        adapterData2_->PushBack("888");
+        adapterData2_->PushBack("999");
+    }
+}
+
+void UITestUIList::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+    if (adapterData1_ != nullptr) {
+        adapterData1_->Clear();
+        delete adapterData1_;
+        adapterData1_ = nullptr;
+    }
+    if (adapterData2_ != nullptr) {
+        adapterData2_->Clear();
+        delete adapterData2_;
+        adapterData2_ = nullptr;
+    }
+    if (adapter1_ != nullptr) {
+        delete adapter1_;
+        adapter1_ = nullptr;
+    }
+    if (adapter2_ != nullptr) {
+        delete adapter2_;
+        adapter2_ = nullptr;
+    }
+    if (adapter4_ != nullptr) {
+        delete adapter4_;
+        adapter4_ = nullptr;
+    }
+    setBlankBtn_ = nullptr;
+    setBlankOffBtn_ = nullptr;
+    setThrowDragBtn_ = nullptr;
+    setThrowDragOffBtn_ = nullptr;
+    scrollStateLabel_ = nullptr;
+    scrollSelectLabel_ = nullptr;
+    setRefreshBtn_ = nullptr;
+    setLoopBtn_ = nullptr;
+    setLoopOffBtn_ = nullptr;
+    setSelectBtn_ = nullptr;
+    setSelectOffBtn_ = nullptr;
+    setAutoAlignBtn_ = nullptr;
+    setAutoAlignOffBtn_ = nullptr;
+    setBackAlignBtn_ = nullptr;
+    setBackAlignOffBtn_ = nullptr;
+    setAutoAlignACCIncBtn_ = nullptr;
+    setAutoAlignACCDncBtn_ = nullptr;
+    setYScrollBarVisableBtn_ = nullptr;
+    setYScrollBarInvisableBtn_ = nullptr;
+    uiViewGroup1_ = nullptr;
+    uiViewGroup2_ = nullptr;
+    scroll_ = nullptr;
+}
+
+const UIView* UITestUIList::GetTestView()
+{
+    UIKitListInitTestFullScreen001();
+    UIKitListInitTesthalhScreen001();
+    UIKitListScrollTestBlankSet001();
+    return container_;
+}
+
+void UITestUIList::UIKitListInitTestFullScreen001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("adapter数据填满list");
+    uiViewGroup1_->Add(label);
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, TEXT_DISTANCE_TO_TOP_SIDE);
+
+    if (adapter1_ == nullptr) {
+        adapter1_ = new TextAdapter();
+    }
+    adapter1_->SetData(adapterData2_);
+
+    UIList* list = new UIList(UIList::VERTICAL);
+    list->SetIntercept(true);
+    list->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    list->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, VIEW_DISTANCE_TO_TOP_SIDE,
+        g_listW - 30, g_listH - 200);   // 200: mean list reduce height , 30 offset
+    list->SetStartIndex(5); // 5: list start index
+    list->GetStartIndex();
+    list->SetAdapter(adapter1_);
+    list->SetYScrollBarVisible(true);
+    uiViewGroup1_->Add(list);
+}
+
+void UITestUIList::UIKitListInitTesthalhScreen001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("adapter数据不填满list");
+    uiViewGroup1_->Add(label);
+    // 2: half of screen width
+    label->SetPosition(Screen::GetInstance().GetWidth() / 2 + TEXT_DISTANCE_TO_LEFT_SIDE, TEXT_DISTANCE_TO_TOP_SIDE);
+
+    if (adapter2_ == nullptr) {
+        adapter2_ = new TextAdapter();
+    }
+    adapter2_->SetData(adapterData1_);
+
+    UIList* list = new UIList(UIList::VERTICAL);
+    list->SetIntercept(true);
+    list->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    // 2: half of screen width , 30 offset
+    list->SetPosition(Screen::GetInstance().GetWidth() / 2 + VIEW_DISTANCE_TO_LEFT_SIDE - 30, VIEW_DISTANCE_TO_TOP_SIDE,
+                      g_listW - 30, g_listH - 150); // 30 offset , 150: decrease height
+    list->SetAdapter(adapter2_);
+    list->SetYScrollBarVisible(true);
+    uiViewGroup1_->Add(list);
+}
+
+void UITestUIList::SetControlButton()
+{
+    if (setBlankBtn_ == nullptr) {
+        setBlankBtn_ = new UILabelButton();
+    }
+    if (setBlankOffBtn_ == nullptr) {
+        setBlankOffBtn_ = new UILabelButton();
+    }
+    if (setThrowDragBtn_ == nullptr) {
+        setThrowDragBtn_ = new UILabelButton();
+    }
+    if (setThrowDragOffBtn_ == nullptr) {
+        setThrowDragOffBtn_ = new UILabelButton();
+    }
+    if (setRefreshBtn_ == nullptr) {
+        setRefreshBtn_ = new UILabelButton();
+    }
+    if (setLoopBtn_ == nullptr) {
+        setLoopBtn_ = new UILabelButton();
+    }
+    if (setLoopOffBtn_ == nullptr) {
+        setLoopOffBtn_ = new UILabelButton();
+    }
+    if (setSelectBtn_ == nullptr) {
+        setSelectBtn_ = new UILabelButton();
+    }
+    if (setSelectOffBtn_ == nullptr) {
+        setSelectOffBtn_ = new UILabelButton();
+    }
+    if (setAutoAlignBtn_ == nullptr) {
+        setAutoAlignBtn_ = new UILabelButton();
+    }
+    if (setAutoAlignOffBtn_ == nullptr) {
+        setAutoAlignOffBtn_ = new UILabelButton();
+    }
+    if (setBackAlignBtn_ == nullptr) {
+        setBackAlignBtn_ = new UILabelButton();
+    }
+    if (setBackAlignOffBtn_ == nullptr) {
+        setBackAlignOffBtn_ = new UILabelButton();
+    }
+    if (setAutoAlignACCIncBtn_ == nullptr) {
+        setAutoAlignACCIncBtn_ = new UILabelButton();
+    }
+    if (setAutoAlignACCDncBtn_ == nullptr) {
+        setAutoAlignACCDncBtn_ = new UILabelButton();
+    }
+    if (setYScrollBarVisableBtn_ == nullptr) {
+        setYScrollBarVisableBtn_ = new UILabelButton();
+    }
+    if (setYScrollBarInvisableBtn_ == nullptr) {
+        setYScrollBarInvisableBtn_ = new UILabelButton();
+    }
+    positionX_ += 5; // 5: increase y-coordinate
+    positionY_ = 0;
+    SetUpButton(setBlankBtn_, "开启blank");
+    SetUpButton(setBlankOffBtn_, "关闭blank");
+    SetUpButton(setThrowDragBtn_, "开启throwDrag");
+    SetUpButton(setThrowDragOffBtn_, "关闭throwDrag");
+    SetUpButton(setRefreshBtn_, "刷新list");
+    SetUpButton(setLoopBtn_, "开启loop模式");
+    SetUpButton(setLoopOffBtn_, "关闭loop模式");
+    SetUpButton(setSelectBtn_, "select 150");
+    SetUpButton(setSelectOffBtn_, "关闭select");
+    SetUpButton(setAutoAlignBtn_, "开启自动对齐 ");
+    SetUpButton(setAutoAlignOffBtn_, "关闭自动对齐 ");
+    SetUpButton(setBackAlignBtn_, "开启弹回对齐 ");
+    SetUpButton(setBackAlignOffBtn_, "关闭弹回对齐 ");
+    SetUpButton(setAutoAlignACCIncBtn_, "增加自动对齐时间 ");
+    SetUpButton(setAutoAlignACCDncBtn_, "减少自动对齐时间 ");
+    SetUpButton(setYScrollBarVisableBtn_, "显示纵向滚动条");
+    SetUpButton(setYScrollBarInvisableBtn_, "不显示纵向滚动条");
+}
+
+void UITestUIList::UIKitListScrollTestBlankSet001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("UILIst设置blank和throwDrag");
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, 10); // 10: decrease y-coordinate
+    uiViewGroup2_->Add(label);
+
+    if (adapter4_ == nullptr) {
+        adapter4_ = new TextAdapter();
+    }
+    adapter4_->SetLineBreakMode(UILabel::LINE_BREAK_CLIP);
+    adapter4_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    adapter4_->SetHeight(100);   // 100: mean adapter height
+    adapter4_->SetWidth(100);   // 100: mean adapter width
+    adapter4_->SetData(adapterData2_);
+
+    UIList* list = new UIList(UIList::VERTICAL);
+    list->SetIntercept(true);
+    list->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    list->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, 60, g_listW, g_listH); // 60:  y-coordinate
+    list->SetYScrollBarVisible(true);
+    list->SetAdapter(adapter4_);
+    list->SetScrollStateListener(this);
+    currentList_ = list;
+
+    if (scrollStateLabel_ == nullptr) {
+        scrollStateLabel_ = new UILabel();
+    }
+    if (scrollSelectLabel_ == nullptr) {
+        scrollSelectLabel_ = new UILabel();
+    }
+
+    scrollStateLabel_->SetLineBreakMode(UILabel::LINE_BREAK_ADAPT);
+    scrollSelectLabel_->SetLineBreakMode(UILabel::LINE_BREAK_ADAPT);
+    scrollStateLabel_->SetText("STOP");
+    scrollSelectLabel_->SetText("NULL");
+
+    scrollStateLabel_->SetPosition(list->GetWidth() + 53, list->GetY()); // 53: increase x-coordinate
+    // 53: increase x-coordinate
+    scrollSelectLabel_->SetPosition(list->GetWidth() + scrollStateLabel_->GetWidth() + g_blank + 53, list->GetY());
+    if (list->GetSelectView() != nullptr) {
+        scrollSelectLabel_->SetText(static_cast<UILabel*>(list->GetSelectView())->GetText());
+    }
+    positionX_ = list->GetWidth();
+    positionY_ = scrollStateLabel_->GetY() + scrollStateLabel_->GetHeight();
+
+    if (scroll_ == nullptr) {
+        scroll_ = new UIScrollView();
+        scroll_->SetPosition(g_listW + TEXT_DISTANCE_TO_LEFT_SIDE,
+            TEXT_DISTANCE_TO_TOP_SIDE + 100,    // 100 : offset
+            Screen::GetInstance().GetWidth() - g_listW - VIEW_DISTANCE_TO_LEFT_SIDE - 100,    // 100 : offset
+            Screen::GetInstance().GetHeight() - 180);    // 180 : offset,
+        // 200: width; 200: Adjust the visible height of scroll
+        scroll_->Resize(200, Screen::GetInstance().GetHeight() - 200);
+        scroll_->SetIntercept(true);
+        uiViewGroup2_->Add(scroll_);
+        SetControlButton();
+    }
+
+    UIView* selectBtnPos = new UIView();
+    selectBtnPos->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    selectBtnPos->SetStyle(STYLE_BACKGROUND_COLOR, Color::White().full);
+    selectBtnPos->SetStyle(STYLE_BORDER_WIDTH, 0);
+    selectBtnPos->SetStyle(STYLE_BORDER_RADIUS, 0);
+    selectBtnPos->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, list->GetY() + g_selectPos, 100, 1); // 100: mean view width
+
+    uiViewGroup2_->Add(list);
+    uiViewGroup2_->Add(selectBtnPos);
+    uiViewGroup2_->Add(scrollStateLabel_);
+    uiViewGroup2_->Add(scrollSelectLabel_);
+    SetLastPos(list);
+}
+
+bool UITestUIList::OnClick(UIView& view, const ClickEvent& event)
+{
+    if (currentList_ == nullptr) {
+        return true;
+    }
+    if (&view == setBlankBtn_) {
+        currentList_->SetScrollBlankSize(g_blankSize);
+    } else if (&view == setBlankOffBtn_) {
+        currentList_->SetScrollBlankSize(0);
+    } else if (&view == setThrowDragBtn_) {
+        currentList_->SetThrowDrag(true);
+    } else if (&view == setThrowDragOffBtn_) {
+        currentList_->SetThrowDrag(false);
+    } else if (&view == setRefreshBtn_) {
+        adapter4_->SetData(adapterData1_);
+        currentList_->RefreshList();
+    } else if (&view == setLoopBtn_) {
+        currentList_->SetLoopState(true);
+    } else if (&view == setLoopOffBtn_) {
+        currentList_->SetLoopState(false);
+    } else if (&view == setSelectBtn_) {
+        currentList_->SetSelectPosition(g_selectPos);
+    } else if (&view == setSelectOffBtn_) {
+        currentList_->SetSelectPosition(0);
+    } else if (&view == setAutoAlignBtn_) {
+        currentList_->EnableAutoAlign(true);
+    } else if (&view == setAutoAlignOffBtn_) {
+        currentList_->EnableAutoAlign(false);
+    } else if (&view == setBackAlignBtn_) {
+        currentList_->EnableCrossDragBack(true);
+    } else if (&view == setBackAlignOffBtn_) {
+        currentList_->EnableCrossDragBack(false);
+    } else if (&view == setAutoAlignACCIncBtn_) {
+        autoAlignTime_ += ALINE_TIME_CHANGE_VALUE;
+        currentList_->SetAutoAlignTime(autoAlignTime_);
+    } else if (&view == setAutoAlignACCDncBtn_) {
+        autoAlignTime_ -= ALINE_TIME_CHANGE_VALUE;
+        currentList_->SetAutoAlignTime(autoAlignTime_);
+    } else if (&view == setYScrollBarVisableBtn_) {
+        currentList_->SetYScrollBarVisible(true);
+    } else if (&view == setYScrollBarInvisableBtn_) {
+        currentList_->SetYScrollBarVisible(false);
+    }
+    return true;
+}
+
+void UITestUIList::OnScrollStart(int16_t index, UIView* view)
+{
+    if (GetScrollState() == SCROLL_STATE_STOP) {
+        scrollStateLabel_->SetText("STOP");
+    } else {
+        scrollStateLabel_->SetText("MOVE");
+    }
+
+    scrollStateLabel_->Invalidate();
+}
+
+void UITestUIList::OnScrollEnd(int16_t index, UIView* view)
+{
+    if (GetScrollState() == SCROLL_STATE_STOP) {
+        scrollStateLabel_->SetText("STOP");
+    } else {
+        scrollStateLabel_->SetText("MOVE");
+    }
+    scrollStateLabel_->Invalidate();
+}
+void UITestUIList::OnItemSelected(int16_t index, UIView* view)
+{
+    if (view != nullptr) {
+        scrollSelectLabel_->SetText(static_cast<UILabel*>(view)->GetText());
+        view->Invalidate();
+    } else {
+        scrollSelectLabel_->SetText("NULL");
+    }
+}
+
+void UITestUIList::SetUpButton(UILabelButton* btn, const char* title)
+{
+    if (btn == nullptr) {
+        return;
+    }
+    scroll_->Add(btn);
+    btn->SetPosition(10, positionY_, BUTTON_WIDHT3, BUTTON_HEIGHT3); // 10: button interval
+    positionY_ += btn->GetHeight() + 10;    // 10: button interval
+    btn->SetText(title);
+    btn->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
+    btn->SetOnClickListener(this);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+    scroll_->Invalidate();
+}
+
+void UITestUIList::SetLastPos(UIView* view)
+{
+    if (view == nullptr) {
+        return;
+    }
+    lastX_ = view->GetX();
+    lastY_ = view->GetY() + view->GetHeight();
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_list/ui_test_ui_list.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_list/ui_test_ui_list.h
new file mode 100644 (file)
index 0000000..ec2d51e
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_UI_LIST_H
+#define UI_TEST_UI_LIST_H
+
+#include "components/text_adapter.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_list.h"
+#include "components/ui_scroll_view.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestUIList : public UITest, UIView::OnClickListener, ListScrollListener {
+public:
+    UITestUIList() {}
+    ~UITestUIList() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    bool OnClick(UIView& view, const ClickEvent& event) override;
+    void OnScrollStart(int16_t index, UIView* view) override;
+    void OnScrollEnd(int16_t index, UIView* view) override;
+    void OnItemSelected(int16_t index, UIView* view) override;
+    void UIKitListInitTestFullScreen001();
+    void UIKitListInitTesthalhScreen001();
+    void UIKitListScrollTestBlankSet001();
+
+private:
+    static constexpr int16_t ALINE_TIME_CHANGE_VALUE = 100;
+    void SetLastPos(UIView* view);
+    void SetUpButton(UILabelButton* btn, const char* title);
+    void SetControlButton();
+    UILabelButton* setBlankBtn_ = nullptr;
+    UILabelButton* setBlankOffBtn_ = nullptr;
+    UILabelButton* setThrowDragBtn_ = nullptr;
+    UILabelButton* setThrowDragOffBtn_ = nullptr;
+    UILabelButton* setRefreshBtn_ = nullptr;
+    UILabelButton* setLoopBtn_ = nullptr;
+    UILabelButton* setLoopOffBtn_ = nullptr;
+    UILabelButton* setSelectBtn_ = nullptr;
+    UILabelButton* setSelectOffBtn_ = nullptr;
+    UILabelButton* setAutoAlignBtn_ = nullptr;
+    UILabelButton* setAutoAlignOffBtn_ = nullptr;
+    UILabelButton* setBackAlignBtn_ = nullptr;
+    UILabelButton* setBackAlignOffBtn_ = nullptr;
+    UILabelButton* setAutoAlignACCIncBtn_ = nullptr;
+    UILabelButton* setAutoAlignACCDncBtn_ = nullptr;
+    UILabelButton* setYScrollBarVisableBtn_ = nullptr;
+    UILabelButton* setYScrollBarInvisableBtn_ = nullptr;
+    UILabel* scrollStateLabel_ = nullptr;
+    UILabel* scrollSelectLabel_ = nullptr;
+    UIScrollView* container_ = nullptr;
+    UIScrollView* scroll_ = nullptr;
+    UIViewGroup* uiViewGroup1_ = nullptr;
+    UIViewGroup* uiViewGroup2_ = nullptr;
+    List<const char*>* adapterData1_ = nullptr;
+    List<const char*>* adapterData2_ = nullptr;
+    TextAdapter* adapter1_ = nullptr;
+    TextAdapter* adapter2_ = nullptr;
+    TextAdapter* adapter4_ = nullptr;
+    UIList* currentList_ = nullptr;
+    int16_t lastX_ = 0;
+    int16_t lastY_ = 0;
+    uint16_t autoAlignTime_ = 100; // 100: default list auto aling ACC
+};
+} // namespace OHOS
+#endif // UI_TEST_UI_LIST_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_list_view/ui_test_list_layout.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_list_view/ui_test_list_layout.cpp
new file mode 100644 (file)
index 0000000..f3ba4d5
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_list_layout.h"
+#include "common/screen.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "layout/list_layout.h"
+
+namespace OHOS {
+namespace {
+    static int16_t g_buttonH = 80;
+    static int16_t g_buttonW = 200;
+    static int16_t g_blank = 20;
+    static int16_t g_gap = 8;
+}
+
+void UITestListLayout::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        container_->SetThrowDrag(true);
+    }
+}
+
+void UITestListLayout::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+    positionX_ = 0;
+    positionY_ = 0;
+    listDirect_ = nullptr;
+}
+
+const UIView* UITestListLayout::GetTestView()
+{
+    ListVerticalAddTestAutoSize001();
+    ListVerticalRemoveTestAutoSize001();
+    ListVerticalRemoveTestAutoSize002();
+    ListHorAddTestAutoSize001();
+    ListHorRemoveTestAutoSize001();
+    ListHorRemoveTestAutoSize002();
+    return container_;
+}
+
+void UITestListLayout::ListVerticalAddTestAutoSize001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+   
+    /** 占位 */
+    UILabel* empty = new UILabel();
+    // 2: half of screen's width  3: 3 tiems of blank zoom
+    empty->SetPosition(0, 0, Screen::GetInstance().GetWidth() / 2, g_blank * 3);
+    container_->Add(empty);
+    
+    positionY_  = 3 * g_blank; //  3: 3 tiems of blank zoom
+    UILabel* label = GetTitleLabel("UILIst高度自适应 Add Insert");
+    container_->Add(label);
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, positionY_ + g_blank);
+
+    ListLayout* list = new ListLayout();
+    list->SetDirection(ListLayout::VERTICAL);
+    list->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    list->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, label->GetY() + TITLE_LABEL_DEFAULT_HEIGHT + g_gap);
+    list->Resize(Screen::GetInstance().GetWidth() - 100, 0); // 100: list reduce width
+    container_->Add(list);
+
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button1->SetText("button1");
+    list->Add(button1);
+    UILabelButton* button2 = new UILabelButton();
+    button2->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button2->SetText("button2");
+    list->Insert(button1, button2);
+
+    if (listDirect_ == nullptr) {
+        listDirect_ = new UILabel();
+    }
+    listDirect_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    listDirect_->SetPosition(list->GetX(), list->GetY(), 100, 100); // 100: list dir width and height
+    if (list->GetDirection() == ListLayout::VERTICAL) {
+        listDirect_->SetText("VERTICAL");
+    } else {
+        listDirect_->SetText("HROIZONTAL");
+    }
+
+    container_->Add(listDirect_);
+
+    SetLastPos(list);
+}
+
+void UITestListLayout::ListVerticalRemoveTestAutoSize001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("UILIst高度自适应 Remove");
+    container_->Add(label);
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, positionY_ + g_blank);
+
+    ListLayout* list = new ListLayout(ListLayout::VERTICAL);
+    list->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+
+    list->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, label->GetY() + TITLE_LABEL_DEFAULT_HEIGHT + g_gap,
+        Screen::GetInstance().GetWidth() - 100, 0);  // 100: list reduce width
+    container_->Add(list);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button1->SetText("button1");
+    list->Add(button1);
+    UILabelButton* button2 = new UILabelButton();
+    button2->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button2->SetText("button2");
+    list->Add(button2);
+    list->Remove(button1);
+    SetLastPos(list);
+}
+
+void UITestListLayout::ListVerticalRemoveTestAutoSize002()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("UILIst高度自适应 RemoveAll");
+    container_->Add(label);
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, positionY_ + g_blank);
+
+    ListLayout* list = new ListLayout(ListLayout::VERTICAL);
+    list->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+
+    list->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, label->GetY() + TITLE_LABEL_DEFAULT_HEIGHT + g_gap,
+        Screen::GetInstance().GetWidth() - 100, 0); // 100: list reduce width
+    container_->Add(list);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button1->SetText("button1");
+    list->Add(button1);
+    UILabelButton* button2 = new UILabelButton();
+    button2->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button2->SetText("button2");
+    list->Add(button2);
+    list->RemoveAll();
+    SetLastPos(list);
+}
+
+void UITestListLayout::ListHorAddTestAutoSize001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("UILIst宽度自适应 Add Insert");
+    container_->Add(label);
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, positionY_ + g_blank);
+
+    ListLayout* list = new ListLayout(ListLayout::HORIZONTAL);
+    list->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+
+    list->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, label->GetY() + TITLE_LABEL_DEFAULT_HEIGHT + g_gap, 0,
+                      Screen::GetInstance().GetHeight());
+    container_->Add(list);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button1->SetText("button1");
+    list->Add(button1);
+    UILabelButton* button2 = new UILabelButton();
+    button2->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button2->SetText("button2");
+    list->Insert(button1, button2);
+    SetLastPos(list);
+}
+
+void UITestListLayout::ListHorRemoveTestAutoSize001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("UILIst宽度自适应 Remove");
+    container_->Add(label);
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, positionY_ + g_blank);
+
+    ListLayout* list = new ListLayout(ListLayout::HORIZONTAL);
+    list->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+
+    list->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, label->GetY() + TITLE_LABEL_DEFAULT_HEIGHT + g_gap, 0,
+                      Screen::GetInstance().GetHeight());
+    container_->Add(list);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button1->SetText("button1");
+    list->Add(button1);
+    UILabelButton* button2 = new UILabelButton();
+    button2->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button2->SetText("button2");
+    list->Add(button2);
+    list->Remove(button1);
+    SetLastPos(list);
+}
+
+void UITestListLayout::ListHorRemoveTestAutoSize002()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("UILIst宽度自适应 RemoveAll");
+    container_->Add(label);
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, positionY_ + g_blank);
+
+    ListLayout* list = new ListLayout(ListLayout::HORIZONTAL);
+    list->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+
+    list->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, label->GetY() + TITLE_LABEL_DEFAULT_HEIGHT + g_gap, 0,
+                      Screen::GetInstance().GetHeight());
+    container_->Add(list);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button1->SetText("button1");
+    list->Add(button1);
+    UILabelButton* button2 = new UILabelButton();
+    button2->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button2->SetText("button2");
+    list->Add(button2);
+    list->RemoveAll();
+    SetLastPos(list);
+}
+
+void UITestListLayout::SetLastPos(UIView* view)
+{
+    if (view == nullptr) {
+        return;
+    }
+    positionX_ = view->GetX();
+    positionY_ = view->GetY() + view->GetHeight();
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_list_view/ui_test_list_layout.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_list_view/ui_test_list_layout.h
new file mode 100644 (file)
index 0000000..e1d90f5
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_UI_LIST_VIEW_H
+#define UI_TEST_UI_LIST_VIEW_H
+
+#include "components/ui_label.h"
+#include "components/ui_scroll_view.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestListLayout : public UITest {
+public:
+    UITestListLayout() {}
+    ~UITestListLayout() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    void ListVerticalAddTestAutoSize001();
+    void ListVerticalRemoveTestAutoSize001();
+    void ListVerticalRemoveTestAutoSize002();
+    void ListHorAddTestAutoSize001();
+    void ListHorRemoveTestAutoSize001();
+    void ListHorRemoveTestAutoSize002();
+
+private:
+    void SetLastPos(UIView* view);
+    UIScrollView* container_ = nullptr;
+    UILabel* listDirect_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_INPUT_EVENT_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_scroll_view/test_on_scroll_listener.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_scroll_view/test_on_scroll_listener.h
new file mode 100644 (file)
index 0000000..a01fbad
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: NATIVE TEST CASE
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+#ifndef TEST_ON_SCROLL_LISTENER_H
+#define TEST_ON_SCROLL_LISTENER_H
+
+#include "ui_test_ui_scroll_view.h"
+namespace OHOS {
+
+class TestOnScrollListener : public UIScrollView::OnScrollListener {
+    void OnScrollStart() override;
+
+    void OnScrollEnd() override;
+};
+}
+
+#endif // TEST_ON_SCROLL_LISTENER_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_scroll_view/ui_test_ui_scroll_view.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_scroll_view/ui_test_ui_scroll_view.cpp
new file mode 100644 (file)
index 0000000..980fa90
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+#include "ui_test_ui_scroll_view.h"
+#include "test_on_scroll_listener.h"
+#include "common/screen.h"
+#include "components/ui_label_button.h"
+
+namespace OHOS {
+namespace {
+static int16_t g_buttonH = 400;
+static int16_t g_buttonW = 400;
+static int16_t g_smallButtonH = 40;
+static int16_t g_smallButtonW = 40;
+static int16_t g_blank = 20;
+static int16_t g_scrollH = 300;
+static int16_t g_scrollW = 300;
+static UILabel* g_scrollSateLabel = nullptr;
+const int16_t DELTA_Y_COORDINATE = 19;
+const int16_t DELTA_Y_COORDINATE_2 = 37;
+static TestOnScrollListener* g_listener = nullptr;
+} // namespace
+
+void VISIBLE_XBAR(bool visible, UIScrollView* scroll)
+{
+    if (Screen::GetInstance().GetScreenShape() == ScreenShape::RECTANGLE) {
+        scroll->SetXScrollBarVisible(visible);
+    }
+}
+
+void TestOnScrollListener::OnScrollStart()
+{
+    g_scrollSateLabel->SetText("moving");
+    g_scrollSateLabel->Invalidate();
+}
+
+void TestOnScrollListener::OnScrollEnd()
+{
+    g_scrollSateLabel->SetText("stop");
+    g_scrollSateLabel->Invalidate();
+}
+
+void UITestUIScrollView::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        container_->SetThrowDrag(true);
+    }
+    if (g_scrollSateLabel == nullptr) {
+        g_scrollSateLabel = GetTitleLabel("stop");
+        g_scrollSateLabel->SetPosition(0, 0, 100, TITLE_LABEL_DEFAULT_HEIGHT); // 100: width
+        g_scrollSateLabel->SetLineBreakMode(UILabel::LINE_BREAK_ADAPT);
+    }
+
+    if (g_listener == nullptr) {
+        g_listener = new TestOnScrollListener();
+    }
+}
+
+void UITestUIScrollView::TearDown()
+{
+    container_->Remove(g_scrollSateLabel);
+    DeleteChildren(container_);
+    container_ = nullptr;
+    if (g_scrollSateLabel != nullptr) {
+        delete g_scrollSateLabel;
+        g_scrollSateLabel = nullptr;
+    }
+    if (g_listener != nullptr) {
+        delete g_listener;
+        g_listener = nullptr;
+    }
+    lastX_ = 0;
+    lastY_ = 0;
+    UITest::TearDown();
+}
+
+const UIView* UITestUIScrollView::GetTestView()
+{
+    UIKitUIScrollViewTestBar001();
+    UIKitUIScrollViewTestBar002();
+    UIKitUIScrollViewTestBar003();
+    UIKitUIScrollViewTestBar004();
+    UIKitUIScrollViewTestScrollableSet001();
+    UIKitUIScrollViewTestScrollableSet002();
+    UIKitUIScrollViewTestScrollBlankSet001();
+    UIKitUIScrollViewTestScrollListener001();
+    return container_;
+}
+
+void UITestUIScrollView::UIKitUIScrollViewTestBar001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    positionX_ = TEXT_DISTANCE_TO_LEFT_SIDE * 2;  // 2 : double gap
+    positionY_ = TEXT_DISTANCE_TO_TOP_SIDE * 2; // 2 : double gap
+    UILabel* empty = GetTitleLabel("");
+    empty->SetPosition(0, 0, positionX_, positionY_);
+    container_->Add(empty);
+    positionY_ += DELTA_Y_COORDINATE;
+    UILabel* label = GetTitleLabel("设置游标可见 ");
+    label->SetPosition(positionX_, positionY_);
+    container_->Add(label);
+    positionY_ += DELTA_Y_COORDINATE_2;
+
+    UIScrollView* scroll = new UIScrollView();
+    scroll->SetIntercept(true);
+    scroll->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    scroll->SetPosition(positionX_, positionY_, g_scrollW, g_scrollH);
+    VISIBLE_XBAR(false, scroll);
+    scroll->SetYScrollBarVisible(true);
+    scroll->SetReboundSize(50); // 50: rebound size
+    container_->Add(scroll);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button1->SetText("button1");
+    scroll->Add(button1);
+    SetLastPos(scroll);
+    positionY_ += g_scrollH;
+}
+
+void UITestUIScrollView::UIKitUIScrollViewTestBar002()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("设置游标可见 ");
+    container_->Add(label);
+    positionY_ += DELTA_Y_COORDINATE;
+    label->SetPosition(positionX_, positionY_);
+    positionY_ += DELTA_Y_COORDINATE_2;
+
+    UIScrollView* scroll = new UIScrollView();
+    scroll->SetIntercept(true);
+    scroll->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    scroll->SetPosition(positionX_, positionY_, g_scrollW, g_scrollH);
+    VISIBLE_XBAR(true, scroll);
+    scroll->SetYScrollBarVisible(true);
+    container_->Add(scroll);
+    UIButton* button1 = new UIButton();
+    button1->SetPosition(0, 0, g_smallButtonW, g_smallButtonH);
+    scroll->Add(button1);
+    SetLastPos(scroll);
+    positionY_ += g_scrollH;
+}
+
+void UITestUIScrollView::UIKitUIScrollViewTestBar003()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("游标滑动状态 ");
+    container_->Add(label);
+    positionY_ += DELTA_Y_COORDINATE;
+    label->SetPosition(positionX_, positionY_);
+    positionY_ += DELTA_Y_COORDINATE_2;
+
+    UIScrollView* scroll = new UIScrollView();
+    scroll->SetIntercept(true);
+    scroll->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    scroll->SetPosition(positionX_, positionY_, g_scrollW, g_scrollH);
+    VISIBLE_XBAR(true, scroll);
+    scroll->SetYScrollBarVisible(true);
+    container_->Add(scroll);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetText("button1");
+    button1->SetPosition(0, 0, g_buttonW, g_buttonH);
+    UILabelButton* button2 = new UILabelButton();
+    button2->SetText("button2");
+    button2->SetPosition(0, g_buttonH, g_buttonW, g_buttonH);
+    scroll->Add(button1);
+    scroll->Add(button2);
+    SetLastPos(scroll);
+    positionY_ += g_scrollH;
+}
+
+void UITestUIScrollView::UIKitUIScrollViewTestBar004()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("设置游标宽度为20");
+    container_->Add(label);
+    positionY_ += DELTA_Y_COORDINATE;
+    label->SetPosition(positionX_, positionY_);
+    positionY_ += DELTA_Y_COORDINATE_2;
+
+    UIScrollView* scroll = new UIScrollView();
+    scroll->SetIntercept(true);
+    scroll->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    scroll->SetPosition(positionX_, positionY_, g_scrollW, g_scrollH);
+    VISIBLE_XBAR(true, scroll);
+    scroll->SetYScrollBarVisible(true);
+    container_->Add(scroll);
+    UIButton* button1 = new UIButton();
+    button1->SetPosition(0, 0, g_smallButtonW, g_smallButtonH);
+    scroll->Add(button1);
+    SetLastPos(scroll);
+    positionY_ += g_scrollH;
+}
+
+void UITestUIScrollView::UIKitUIScrollViewTestScrollableSet001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    // positionX_ = Screen::GetInstance().GetWidth() / 2 + TEXT_DISTANCE_TO_LEFT_SIDE; // 2: half of screen width
+    positionY_ += DELTA_Y_COORDINATE;
+    UILabel* label = GetTitleLabel("设置仅垂直方向可滑动 ");
+    container_->Add(label);
+    label->SetPosition(positionX_, positionY_);
+    positionY_ += DELTA_Y_COORDINATE_2;
+
+    UIScrollView* scroll = new UIScrollView();
+    scroll->SetIntercept(true);
+    scroll->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    scroll->SetPosition(positionX_, positionY_, g_scrollW, g_scrollH);
+    scroll->SetScrollBlankSize(20); // 20: means scroll blank size
+    scroll->SetHorizontalScrollState(false);
+    scroll->SetVerticalScrollState(true);
+    VISIBLE_XBAR(true, scroll);
+    scroll->SetYScrollBarVisible(true);
+    container_->Add(scroll);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button1->SetText("button1");
+    scroll->Add(button1);
+    SetLastPos(scroll);
+    positionY_ += g_scrollH;
+}
+
+void UITestUIScrollView::UIKitUIScrollViewTestScrollableSet002()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("设置仅垂直方向不可滑动 ");
+    container_->Add(label);
+    positionY_ += DELTA_Y_COORDINATE;
+    label->SetPosition(positionX_, positionY_);
+    positionY_ += DELTA_Y_COORDINATE_2;
+
+    UIScrollView* scroll = new UIScrollView();
+    scroll->SetIntercept(true);
+    scroll->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    scroll->SetPosition(positionX_, positionY_, g_scrollW, g_scrollH);
+    scroll->SetHorizontalScrollState(true);
+    scroll->SetVerticalScrollState(false);
+    VISIBLE_XBAR(true, scroll);
+    scroll->SetYScrollBarVisible(true);
+    container_->Add(scroll);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button1->SetText("button1");
+    scroll->Add(button1);
+    SetLastPos(scroll);
+    positionY_ += g_scrollH;
+}
+
+void UITestUIScrollView::UIKitUIScrollViewTestScrollBlankSet001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("设置高为50的可滑动空白区域");
+    container_->Add(label);
+    positionY_ += DELTA_Y_COORDINATE;
+    label->SetPosition(positionX_, positionY_);
+    positionY_ += DELTA_Y_COORDINATE_2;
+
+    UIScrollView* scroll = new UIScrollView();
+    scroll->SetIntercept(true);
+    scroll->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    scroll->SetPosition(positionX_, positionY_, g_scrollW, g_scrollH);
+    scroll->SetScrollBlankSize(50); // (50): means scroll blank size
+    VISIBLE_XBAR(true, scroll);
+    scroll->SetYScrollBarVisible(true);
+    scroll->SetScrollBarSide(SCROLL_BAR_LEFT_SIDE);
+    container_->Add(scroll);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button1->SetText("button1");
+    scroll->Add(button1);
+    SetLastPos(scroll);
+    positionY_ += g_scrollH;
+}
+
+void UITestUIScrollView::UIKitUIScrollViewTestScrollListener001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("设置滑动状态监听 ");
+    container_->Add(label);
+    positionY_ += DELTA_Y_COORDINATE;
+    label->SetPosition(positionX_, positionY_);
+    positionY_ += DELTA_Y_COORDINATE_2;
+
+    UIScrollView* scroll = new UIScrollView();
+    scroll->SetIntercept(true);
+    scroll->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    scroll->SetPosition(positionX_, positionY_, g_scrollW, g_scrollH);
+    container_->Add(scroll);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button1->SetText("button1");
+    scroll->Add(button1);
+    scroll->RegisterScrollListener(g_listener);
+    g_scrollSateLabel->SetPosition(positionX_ + scroll->GetWidth() + 10, scroll->GetY()); // 10: increase width
+    container_->Add(g_scrollSateLabel);
+
+    SetLastPos(scroll);
+}
+
+void UITestUIScrollView::SetLastPos(UIView* view)
+{
+    if (view == nullptr) {
+        return;
+    }
+    lastX_ = view->GetX();
+    lastY_ = view->GetY() + view->GetHeight();
+}
+} // namespace OHOS
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_scroll_view/ui_test_ui_scroll_view.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_scroll_view/ui_test_ui_scroll_view.h
new file mode 100644 (file)
index 0000000..1c6b800
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_UI_SCROLL_VIEW_H
+#define UI_TEST_UI_SCROLL_VIEW_H
+
+#include "components/ui_label.h"
+#include "components/ui_scroll_view.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestUIScrollView : public UITest {
+public:
+    UITestUIScrollView() {}
+    ~UITestUIScrollView() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    void UIKitUIScrollViewTestBar001();
+    void UIKitUIScrollViewTestBar002();
+    void UIKitUIScrollViewTestBar003();
+    void UIKitUIScrollViewTestBar004();
+    void UIKitUIScrollViewTestScrollableSet001();
+    void UIKitUIScrollViewTestScrollableSet002();
+    void UIKitUIScrollViewTestScrollBlankSet001();
+    void UIKitUIScrollViewTestScrollListener001();
+
+private:
+    void SetLastPos(UIView* view);
+    UIScrollView* container_ = nullptr;
+    int16_t lastX_ = 0;
+    int16_t lastY_ = 0;
+};
+} // namespace OHOS
+#endif // UI_TEST_UI_SCROLL_VIEW_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_swipe_view/ui_test_ui_swipe_view.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_swipe_view/ui_test_ui_swipe_view.cpp
new file mode 100644 (file)
index 0000000..0d82f96
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_ui_swipe_view.h"
+
+#include <string>
+
+#include "common/screen.h"
+#include "components/ui_label.h"
+#include "components/ui_swipe_view.h"
+
+namespace OHOS {
+namespace {
+static int16_t g_buttonH = 80;
+static int16_t g_buttonW = 400;
+static int16_t g_blank = 20;
+static int16_t g_swipeH = 200;
+static int16_t g_swipeW = 400;
+static int16_t g_swipeHorH = 110;
+static int16_t g_deltaCoordinateY = 19;
+static int16_t g_deltaCoordinateY2 = 37;
+static uint16_t g_maxIndex = 3;
+} // namespace
+
+void UITestUISwipeView::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        container_->SetThrowDrag(true);
+        container_->SetHorizontalScrollState(false);
+    }
+}
+
+void UITestUISwipeView::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+    addBtnInHead_ = nullptr;
+    addBtnInTail_ = nullptr;
+    addBtnInMid_ = nullptr;
+    removeHeadBtn_ = nullptr;
+    removeMidBtn_ = nullptr;
+    removeAllBtn_ = nullptr;
+    loopBtn_ = nullptr;
+    changePageBtn_ = nullptr;
+    lastX_ = 0;
+    lastY_ = 0;
+}
+
+const UIView* UITestUISwipeView::GetTestView()
+{
+    UIKitSwipeViewTestHorizontal001();
+    UIKitSwipeViewTestHorizontal002();
+    UIKitSwipeViewTestHorizontal003();
+    UIKitSwipeViewTestAlign001(UISwipeView::ALIGN_LEFT);
+    UIKitSwipeViewTestAlign001(UISwipeView::ALIGN_CENTER);
+    UIKitSwipeViewTestAlign001(UISwipeView::ALIGN_RIGHT);
+
+    UIKitSwipeViewTestVer001();
+    UIKitSwipeViewTestVer002();
+    UIKitSwipeViewTestRemove001();
+
+    UIKitSwipeViewTestSetCurrentPage();
+
+    return container_;
+}
+
+void UITestUISwipeView::UIKitSwipeViewTestHorizontal001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* empty = GetTitleLabel("");
+    container_->Add(empty);
+    positionY_ = TEXT_DISTANCE_TO_TOP_SIDE;
+    empty->SetPosition(0, 0, Screen::GetInstance().GetWidth() / 2, positionY_);    // 2: half of screen
+
+    UILabel* label = GetTitleLabel("    两个子元素循环水平滑动");
+    container_->Add(label);
+    positionX_ = TEXT_DISTANCE_TO_LEFT_SIDE;
+    positionY_ += g_deltaCoordinateY2;
+    label->SetPosition(positionX_, positionY_);
+    positionY_ += g_deltaCoordinateY2;
+
+    UISwipeView* swipe = new UISwipeView(UISwipeView::HORIZONTAL);
+    swipe->SetIntercept(true);
+    swipe->SetLoopState(true);
+    swipe->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    swipe->SetPosition(positionX_, positionY_, g_swipeW, g_swipeHorH);
+    swipe->SetBlankSize(100); // 100: is blank size
+    container_->Add(swipe);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button1->SetText("button1");
+    swipe->Add(button1);
+    UILabelButton* button2 = new UILabelButton();
+    button2->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button2->SetText("button2");
+    swipe->Add(button2);
+    SetLastPos(swipe);
+    positionY_ += g_swipeHorH;
+}
+
+void UITestUISwipeView::UIKitSwipeViewTestHorizontal002()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("水平滑动");
+    container_->Add(label);
+    positionY_ += g_deltaCoordinateY;
+    label->SetPosition(positionX_, positionY_);
+    positionY_ += g_deltaCoordinateY2;
+
+    UISwipeView* swipe = new UISwipeView(UISwipeView::HORIZONTAL);
+    swipe->SetIntercept(true);
+    swipe->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    swipe->SetPosition(positionX_, positionY_, g_swipeW, g_swipeHorH);
+    swipe->SetAnimatorTime(100); // 100: mean animator drag time(ms)
+    container_->Add(swipe);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button1->SetText("button1");
+    swipe->Add(button1);
+    UILabelButton* button2 = new UILabelButton();
+    button2->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button2->SetText("button2");
+    swipe->Add(button2);
+    UILabelButton* button3 = new UILabelButton();
+    button3->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button3->SetText("button3");
+    swipe->Add(button3);
+    SetLastPos(swipe);
+    positionY_ += g_swipeHorH;
+}
+
+void UITestUISwipeView::UIKitSwipeViewTestHorizontal003()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("循环水平滑动");
+    container_->Add(label);
+    positionY_ += g_deltaCoordinateY;
+    label->SetPosition(positionX_, positionY_);
+    positionY_ += g_deltaCoordinateY2;
+
+    UISwipeView* swipe = new UISwipeView(UISwipeView::HORIZONTAL);
+    swipe->SetIntercept(true);
+    swipe->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    swipe->SetPosition(positionX_, positionY_, g_swipeW, g_swipeHorH);
+    swipe->SetLoopState(true);
+    swipe->SetAnimatorTime(100); // 100: mean animator drag time(ms)
+    container_->Add(swipe);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button1->SetText("button1");
+    swipe->Add(button1);
+    UILabelButton* button2 = new UILabelButton();
+    button2->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button2->SetText("button2");
+    swipe->Add(button2);
+    UILabelButton* button3 = new UILabelButton();
+    button3->SetPosition(0, 0, g_buttonW, g_buttonH);
+    button3->SetText("button3");
+    swipe->Add(button3);
+    SetLastPos(swipe);
+    positionY_ += g_swipeHorH;
+}
+
+void UITestUISwipeView::UIKitSwipeViewTestVer001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("垂直滑动");
+    container_->Add(label);
+    positionY_ += g_deltaCoordinateY;
+    label->SetPosition(positionX_, positionY_);
+    positionY_ += g_deltaCoordinateY2;
+
+    UISwipeView* swipe = new UISwipeView(UISwipeView::VERTICAL);
+    swipe->SetIntercept(true);
+    swipe->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    swipe->SetPosition(positionX_, positionY_, g_swipeH, g_swipeW);
+    container_->Add(swipe);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonH, g_buttonW);
+    button1->SetText("button1");
+    swipe->Add(button1);
+    UILabelButton* button2 = new UILabelButton();
+    button2->SetPosition(0, 0, g_buttonH, g_buttonW);
+    button2->SetText("button2");
+    swipe->Add(button2);
+    SetLastPos(swipe);
+    positionY_ += g_swipeW + g_deltaCoordinateY;
+}
+
+void UITestUISwipeView::UIKitSwipeViewTestVer002()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UILabel* label = GetTitleLabel("循环垂直滑动");
+    container_->Add(label);
+    label->SetPosition(positionX_, positionY_);
+    positionY_ += g_deltaCoordinateY2;
+
+    UISwipeView* swipe = new UISwipeView(UISwipeView::VERTICAL);
+    swipe->SetIntercept(true);
+    swipe->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    swipe->SetPosition(positionX_, positionY_, g_swipeH, g_swipeW);
+    swipe->SetLoopState(true);
+    swipe->SetAnimatorTime(100); // 100: is animator drag time(ms)
+    container_->Add(swipe);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonH, g_buttonW);
+    button1->SetText("button1");
+    swipe->Add(button1);
+    UILabelButton* button2 = new UILabelButton();
+    button2->SetPosition(0, 0, g_buttonH, g_buttonW);
+    button2->SetText("button2");
+    swipe->Add(button2);
+    UILabelButton* button3 = new UILabelButton();
+    button3->SetPosition(0, 0, g_buttonH, g_buttonW);
+    button3->SetText("button3");
+    swipe->Add(button3);
+    SetLastPos(swipe);
+    positionY_ += g_swipeW;
+}
+
+void UITestUISwipeView::UIKitSwipeViewTestRemove001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("增加和删除子节点");
+    container_->Add(label);
+    positionY_ += g_deltaCoordinateY;
+    label->SetPosition(positionX_, positionY_);
+    positionY_ += g_deltaCoordinateY2;
+
+    UISwipeView* swipe = new UISwipeView(UISwipeView::HORIZONTAL);
+    swipe->SetIntercept(true);
+    swipe->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    swipe->SetPosition(positionX_, positionY_, g_swipeH, g_swipeW);
+    swipe->SetLoopState(true);
+    swipe->SetAnimatorTime(100); // 100: mean animator drag time(ms)
+    currentSwipe_ = swipe;
+    container_->Add(swipe);
+    InitBtn();
+    positionX_ = positionX_ + swipe->GetWidth() + 20; // 20: is interval between button and swipe
+    SetUpButton(addBtnInHead_, "增加至头部 ");
+    SetUpButton(addBtnInTail_, "增加至尾部 ");
+    SetUpButton(addBtnInMid_, "增加至头部后 ");
+    SetUpButton(removeHeadBtn_, "删除头部节点 ");
+    SetUpButton(removeMidBtn_, "删除中间节点 ");
+    SetUpButton(removeAllBtn_, "删除全部节点 ");
+    SetUpButton(loopBtn_, "设置循环 关 ");
+    SetUpButton(changePageBtn_, "切换页面 ");
+    SetLastPos(swipe);
+}
+
+void UITestUISwipeView::InitBtn()
+{
+    if (addBtnInHead_ == nullptr) {
+        addBtnInHead_ = new UILabelButton();
+    }
+    if (addBtnInTail_ == nullptr) {
+        addBtnInTail_ = new UILabelButton();
+    }
+    if (addBtnInMid_ == nullptr) {
+        addBtnInMid_ = new UILabelButton();
+    }
+    if (removeHeadBtn_ == nullptr) {
+        removeHeadBtn_ = new UILabelButton();
+    }
+    if (removeMidBtn_ == nullptr) {
+        removeMidBtn_ = new UILabelButton();
+    }
+    if (removeAllBtn_ == nullptr) {
+        removeAllBtn_ = new UILabelButton();
+    }
+    if (loopBtn_ == nullptr) {
+        loopBtn_ = new UILabelButton();
+    }
+    if (changePageBtn_ == nullptr) {
+        changePageBtn_ = new UILabelButton();
+    }
+}
+
+void UITestUISwipeView::UIKitSwipeViewTestAlign001(UISwipeView::AlignMode alignMode)
+{
+    static uint8_t divNum = 4;
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UILabel* label;
+    if (alignMode == UISwipeView::ALIGN_LEFT) {
+        label = GetTitleLabel("子组件左对齐");
+    } else if (alignMode == UISwipeView::ALIGN_RIGHT) {
+        label = GetTitleLabel("子组件右对齐");
+    } else {
+        label = GetTitleLabel("子组件Center对齐");
+    }
+
+    container_->Add(label);
+    label->SetPosition(positionX_, lastY_ + g_blank);
+
+    UISwipeView* swipe = new UISwipeView(UISwipeView::HORIZONTAL);
+    swipe->SetIntercept(true);
+    swipe->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    positionY_ = label->GetY() + g_blank + g_deltaCoordinateY + g_swipeH;
+    swipe->SetPosition(positionX_, label->GetY() + g_blank + g_deltaCoordinateY,
+        g_swipeW - 100, g_swipeH);    // 100: offset
+    swipe->SetLoopState(true);
+    swipe->SetAnimatorTime(100); // 100: mean animator drag time(ms)
+    swipe->SetAlignMode(alignMode);
+    container_->Add(swipe);
+    UILabelButton* button1 = new UILabelButton();
+    button1->SetPosition(0, 0, g_buttonW / divNum, g_buttonH / 2); // 2: half
+    button1->SetText("button1");
+    swipe->Add(button1);
+    UILabelButton* button2 = new UILabelButton();
+    button2->SetPosition(0, 0, g_buttonW / divNum, g_buttonH / 2); // 2: half
+    button2->SetText("button2");
+    swipe->Add(button2);
+    UILabelButton* button3 = new UILabelButton();
+    button3->SetPosition(0, 0, g_buttonW / divNum, g_buttonH / 2); // 2: half
+    button3->SetText("button3");
+    swipe->Add(button3);
+
+    UILabel* tmpLabel = nullptr;
+    uint8_t tmpAlignMode = swipe->GetAlignMode();
+    if (tmpAlignMode == alignMode) {
+        tmpLabel = GetTitleLabel("The result of GetAlignMode is OK.");
+    } else {
+        tmpLabel = GetTitleLabel("The result of GetAlignMode is Error.");
+    }
+    tmpLabel->SetPosition(positionX_, 100, 250, 25); // 100: y, 250:width, 25:height
+    swipe->Add(tmpLabel);
+
+    SetLastPos(swipe);
+}
+
+void UITestUISwipeView::UIKitSwipeViewTestSetCurrentPage()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UILabel* label = GetTitleLabel("UISwipeView切换页面");
+    container_->Add(label);
+    positionY_ += g_deltaCoordinateY;
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, positionY_);
+    positionY_ += g_deltaCoordinateY2;
+
+    UISwipeView* swipe = new UISwipeView(UISwipeView::HORIZONTAL);
+    swipe->SetIntercept(true);
+    swipe->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    swipe->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, positionY_, g_swipeW, g_swipeH);
+    swipe->SetLoopState(loop_);
+    swipe->SetAnimatorTime(1000); // 1000: mean animator drag time(ms)
+    container_->Add(swipe);
+    UIView* view1 = new UIView();
+    view1->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    view1->Resize(g_swipeW, g_swipeH);
+    swipe->Add(view1);
+    UIView* view2 = new UIView();
+    view2->SetStyle(STYLE_BACKGROUND_COLOR, Color::White().full);
+    view2->Resize(g_swipeW, g_swipeH);
+    swipe->Add(view2);
+    UIView* view3 = new UIView();
+    view3->SetStyle(STYLE_BACKGROUND_COLOR, Color::Blue().full);
+    view3->Resize(g_swipeW, g_swipeH);
+    swipe->Add(view3);
+    UIView* view4 = new UIView();
+    view4->SetStyle(STYLE_BACKGROUND_COLOR, Color::Yellow().full);
+    view4->Resize(g_swipeW, g_swipeH);
+    swipe->Add(view4);
+}
+
+bool UITestUISwipeView::OnClick(UIView& view, const ClickEvent& event)
+{
+    if (currentSwipe_ == nullptr) {
+        return true;
+    }
+    if (&view == addBtnInHead_) {
+        UILabelButton* btn = new UILabelButton();
+        btn->SetPosition(0, 0, g_buttonH, g_buttonW);
+        btn->SetText(std::to_string(btnNum_).c_str());
+        currentSwipe_->Insert(nullptr, btn);
+    } else if (&view == addBtnInTail_) {
+        UILabelButton* btn = new UILabelButton();
+        btn->SetPosition(0, 0, g_buttonH, g_buttonW);
+        btn->SetText(std::to_string(btnNum_).c_str());
+        currentSwipe_->Add(btn);
+    } else if (&view == addBtnInMid_) {
+        UILabelButton* btn = new UILabelButton();
+        btn->SetPosition(0, 0, g_buttonH, g_buttonW);
+        btn->SetText(std::to_string(btnNum_).c_str());
+        currentSwipe_->Insert(currentSwipe_->GetChildrenHead(), btn);
+    } else if (&view == removeHeadBtn_) {
+        currentSwipe_->Remove(currentSwipe_->GetChildrenHead());
+    } else if (&view == removeMidBtn_) {
+        UIView* view = currentSwipe_->GetViewByIndex(1);
+        currentSwipe_->Remove(view);
+    } else if (&view == removeAllBtn_) {
+        currentSwipe_->RemoveAll();
+    } else if (&view == loopBtn_) {
+        loop_ = !loop_;
+        currentSwipe_->SetLoopState(loop_);
+        if (!loop_) {
+            loopBtn_->SetText("设置循环 关 ");
+        } else {
+            loopBtn_->SetText("设置循环 开 ");
+        }
+    } else if (&view == changePageBtn_) {
+        uint16_t currentIndex = currentSwipe_->GetCurrentPage();
+        if (currentIndex < g_maxIndex) {
+            currentSwipe_->SetCurrentPage(++currentIndex, true);
+        } else {
+            currentSwipe_->SetCurrentPage(0, true);
+        }
+    }
+    currentSwipe_->Invalidate();
+    btnNum_++;
+    return true;
+}
+
+void UITestUISwipeView::SetUpButton(UILabelButton* btn, const char* title)
+{
+    if (btn == nullptr) {
+        return;
+    }
+    container_->Add(btn);
+    btn->SetPosition(positionX_, positionY_, BUTTON_WIDHT2, BUTTON_HEIGHT2);
+    positionY_ += btn->GetHeight() + 10; // 10: increase y-coordinate
+    btn->SetText(title);
+    btn->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
+    btn->SetOnClickListener(this);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+    container_->Invalidate();
+}
+
+void UITestUISwipeView::SetLastPos(UIView* view)
+{
+    if (view == nullptr) {
+        return;
+    }
+    lastX_ = view->GetX();
+    lastY_ = view->GetY() + view->GetHeight();
+}
+} // namespace OHOS
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_swipe_view/ui_test_ui_swipe_view.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_ui_swipe_view/ui_test_ui_swipe_view.h
new file mode 100644 (file)
index 0000000..dbe1ef7
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_UI_SWIPE_VIEW_H
+#define UI_TEST_UI_SWIPE_VIEW_H
+
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "components/ui_swipe_view.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestUISwipeView : public UITest, UIView::OnClickListener {
+public:
+    UITestUISwipeView() {}
+    ~UITestUISwipeView() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    bool OnClick(UIView& view, const ClickEvent& event) override;
+
+    void UIKitSwipeViewTestHorizontal001();
+    void UIKitSwipeViewTestHorizontal002();
+    void UIKitSwipeViewTestHorizontal003();
+    void UIKitSwipeViewTestVer001();
+    void UIKitSwipeViewTestVer002();
+    void UIKitSwipeViewTestRemove001();
+    void UIKitSwipeViewTestAlign001(UISwipeView::AlignMode alignMode);
+    void UIKitSwipeViewTestSetCurrentPage();
+
+private:
+    void SetUpButton(UILabelButton* btn, const char* title);
+    void SetLastPos(UIView* view);
+    void InitBtn();
+    UIScrollView* container_ = nullptr;
+    UISwipeView* currentSwipe_ = nullptr;
+    UILabelButton* addBtnInHead_ = nullptr;
+    UILabelButton* addBtnInTail_ = nullptr;
+    UILabelButton* addBtnInMid_ = nullptr;
+    UILabelButton* removeHeadBtn_ = nullptr;
+    UILabelButton* removeMidBtn_ = nullptr;
+    UILabelButton* removeAllBtn_ = nullptr;
+    UILabelButton* loopBtn_ = nullptr;
+    UILabelButton* changePageBtn_ = nullptr;
+    bool loop_ = false;
+    int16_t lastX_ = 0;
+    int16_t lastY_ = 0;
+    int16_t btnNum_ = 0;
+};
+} // namespace OHOS
+#endif // UI_TEST_UI_SWIPE_VIEW_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_vector_font/ui_test_vector_font.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_vector_font/ui_test_vector_font.cpp
new file mode 100644 (file)
index 0000000..6e0e3a8
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_vector_font.h"
+#if ENABLE_VECTOR_FONT
+#include <iostream>
+
+#include "common/screen.h"
+#include "components/ui_label.h"
+#if ENABLE_MULTI_FONT
+#include "font/ui_multi_font_manager.h"
+#endif
+namespace {
+const int16_t GAP = 5;
+const int16_t TITLE_HEIGHT = 29;
+const uint16_t LABEL_WIDTH = 200;
+const uint16_t LABEL_HEIGHT = 50;
+const uint16_t BUF_SIZE = 200;
+const uint16_t LANGUAGE_FILE_ID_MAX = 9;
+const uint16_t offsetX = 100;
+const char* HYQIHEI_65S = "HYQiHei-65S.otf";
+const char* NOTONASKHARABIC_REGULAR = "NotoNaskhArabic-Regular.ttf";
+const char* ROBOTOCONDENSED_REGULAR = "RobotoCondensed-Regular.ttf";
+const char* NOTOSANSCJKJP_REGULAR = "NotoSansCJKjp-Regular.otf";
+const char* NOTOSANSTHAI_REGULAR = "NotoSansThai-Regular.ttf";
+const char* NOTOSANSHEBREW_REGULAR = "NotoSansHebrew-Regular.ttf";
+const char* NOTOSANSDEVANAGARI_REGULAR = "NotoSansDevanagari-Regular.otf";
+const char* NOTOSANSMYANMAR_CONDENSED = "NotoSansMyanmar-Condensed.ttf";
+const char* NOTOSANSBENGALI_REGULAR = "NotoSansBengali-Regular.ttf";
+} // namespace
+namespace OHOS {
+void UITestVectorFont::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->SetThrowDrag(true);
+        container_->SetHorizontalScrollState(false);
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        positionX_ = 50; // 50: init position x
+        positionY_ = 5;  // 5: init position y
+    }
+}
+
+void UITestVectorFont::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+}
+
+void UITestVectorFont::InnerTestTitle(const char* title)
+{
+    UILabel* titleLabel = new UILabel();
+    UIFont::GetInstance()->RegisterFontInfo(DEFAULT_VECTOR_FONT_FILENAME);
+    titleLabel->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE + offsetX, positionY_, Screen::GetInstance().GetWidth(),
+                            TITLE_LABEL_DEFAULT_HEIGHT);
+    titleLabel->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    titleLabel->SetText(title);
+    container_->Add(titleLabel);
+    positionY_ += TITLE_HEIGHT + GAP;
+}
+
+const UIView* UITestVectorFont::GetTestView()
+{
+    Font_FontEngine_Vector_Test_CH_Lang_001();
+    Font_FontEngine_Vector_Test_CH_Lang_002();
+    Font_FontEngine_Vector_Test_JA_Lang_001();
+    Font_FontEngine_Vector_Test_JA_Lang_002();
+    Font_FontEngine_Vector_Test_KR_Lang_001();
+    Font_FontEngine_Vector_Test_VI_Lang_001();
+#if ENABLE_MULTI_FONT
+    Font_FontEngine_MultiLanguage_Test_JA_Lang_001();
+    Font_FontEngine_MultiLanguage_Test_JA_Lang_002();
+    Font_FontEngine_MultiLanguage_Test_KR_Lang_001();
+    Font_FontEngine_MultiLanguage_Test_VI_Lang_001();
+    Font_FontEngine_MultiLanguage_Test_CS_Lang_001();
+    Font_FontEngine_MultiLanguage_Test_EL_Lang_001();
+    Font_FontEngine_MultiLanguage_Test_RO_Lang_001();
+#endif
+    return container_;
+}
+
+void UITestVectorFont::Font_FontEngine_Vector_Test_CH_Lang_001()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("");
+        InnerTestTitle("CH Language");
+        UILabel* label = new UILabel();
+        UIFont::GetInstance()->RegisterFontInfo(HYQIHEI_65S);
+        label->SetPosition(positionX_ + offsetX, positionY_);
+        label->Resize(LABEL_WIDTH, LABEL_HEIGHT);
+        label->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE);
+        label->SetFont(HYQIHEI_65S, 24); // 24 : size
+        label->SetText("测试中文");
+        container_->Add(label);
+        positionY_ += LABEL_HEIGHT + GAP;
+    }
+}
+
+void UITestVectorFont::Font_FontEngine_Vector_Test_CH_Lang_002()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("Multiline text");
+        UILabel* label = new UILabel();
+        UIFont::GetInstance()->RegisterFontInfo(HYQIHEI_65S);
+        label->SetPosition(positionX_ + offsetX, positionY_);
+        label->Resize(LABEL_WIDTH, LABEL_HEIGHT * 2); // 2:double
+        label->SetFont(HYQIHEI_65S, 24); // 24 : size
+        label->SetText("测试中英文混合:text和text text和text text和text");
+        container_->Add(label);
+        positionY_ += LABEL_HEIGHT * 2 + GAP; // 2:double
+    }
+}
+
+void UITestVectorFont::Font_FontEngine_Vector_Test_JA_Lang_001()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("JA Language");
+        UILabel* label = new UILabel();
+        UIFont::GetInstance()->RegisterFontInfo(NOTOSANSCJKJP_REGULAR);
+        label->SetPosition(positionX_ + offsetX, positionY_);
+        label->Resize(LABEL_WIDTH, LABEL_HEIGHT);
+        label->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE);
+        label->SetFont(NOTOSANSCJKJP_REGULAR, 24); // 24 : size
+        label->SetText("ランニン");
+        container_->Add(label);
+        positionY_ += LABEL_HEIGHT + GAP;
+    }
+}
+
+void UITestVectorFont::Font_FontEngine_Vector_Test_JA_Lang_002()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("JA Language");
+        UILabel* label = new UILabel();
+        UIFont::GetInstance()->RegisterFontInfo(NOTOSANSCJKJP_REGULAR);
+        label->SetPosition(positionX_ + offsetX, positionY_);
+        label->Resize(LABEL_WIDTH, LABEL_HEIGHT);
+        label->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE);
+        label->SetFont(NOTOSANSCJKJP_REGULAR, 30); // 30 : size
+        label->SetText("ランニン");
+        container_->Add(label);
+        positionY_ += LABEL_HEIGHT + GAP;
+    }
+}
+
+void UITestVectorFont::Font_FontEngine_Vector_Test_KR_Lang_001()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("KR Language");
+        UILabel* label = new UILabel();
+        label->SetPosition(positionX_ + offsetX, positionY_);
+        label->Resize(LABEL_WIDTH, LABEL_HEIGHT);
+        label->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE);
+        UIFont::GetInstance()->RegisterFontInfo(NOTOSANSCJKJP_REGULAR);
+        label->SetFont(NOTOSANSCJKJP_REGULAR, 24); // 24 : size
+        label->SetText("韩语리기");
+        container_->Add(label);
+        positionY_ += LABEL_HEIGHT + GAP;
+    }
+}
+
+void UITestVectorFont::Font_FontEngine_Vector_Test_VI_Lang_001()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("VI Language");
+        UIFont::GetInstance()->RegisterFontInfo(NOTOSANSCJKJP_REGULAR);
+        UIFont::GetInstance()->RegisterFontInfo(HYQIHEI_65S);
+        UILabel* label = new UILabel();
+        label->SetPosition(positionX_ + offsetX, positionY_);
+        label->Resize(LABEL_WIDTH, LABEL_HEIGHT);
+        label->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE);
+        label->SetFont(ROBOTOCONDENSED_REGULAR, 24); // 24 : size
+        label->SetText("Kết thúc tập luyện?");
+        container_->Add(label);
+        positionY_ += LABEL_HEIGHT + GAP;
+    }
+}
+
+#if ENABLE_MULTI_FONT
+void UITestVectorFont::Font_FontEngine_MultiLanguage_Test_JA_Lang_001()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("CH+JA Language");
+        UIFont::GetInstance()->RegisterFontInfo(NOTOSANSCJKJP_REGULAR);
+        UIFont::GetInstance()->RegisterFontInfo(HYQIHEI_65S);
+        UIFont::GetInstance()->RegisterFontInfo(ROBOTOCONDENSED_REGULAR);
+        uint8_t findPath[] = {UIFont::GetInstance()->GetFontId(HYQIHEI_65S),
+                              UIFont::GetInstance()->GetFontId(ROBOTOCONDENSED_REGULAR)};
+        UIMultiFontManager::GetInstance()->SetSearchFontList(UIFont::GetInstance()->GetFontId(HYQIHEI_65S), findPath,
+                                                             sizeof(findPath));
+        UILabel* label = new UILabel();
+        label->SetPosition(positionX_ + offsetX, positionY_);
+        label->Resize(LABEL_WIDTH, LABEL_HEIGHT);
+        label->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE);
+        label->SetFont(HYQIHEI_65S, 24); // 24 : size
+        label->SetText("日语ランニン");
+        container_->Add(label);
+        positionY_ += LABEL_HEIGHT + GAP;
+    }
+}
+
+void UITestVectorFont::Font_FontEngine_MultiLanguage_Test_JA_Lang_002()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("UnRegister JA Language");
+        UILabel* label = new UILabel();
+        label->SetPosition(positionX_ + offsetX, positionY_);
+        label->Resize(LABEL_WIDTH, LABEL_HEIGHT);
+        label->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE);
+        label->SetFont(NOTOSANSCJKJP_REGULAR, 24); // 24 : size
+        label->SetText("韩语日语리기ランニン");
+        container_->Add(label);
+        positionY_ += LABEL_HEIGHT + GAP;
+    }
+}
+
+void UITestVectorFont::Font_FontEngine_MultiLanguage_Test_KR_Lang_001()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("CH+KR Language");
+        UIFont::GetInstance()->RegisterFontInfo(NOTOSANSCJKJP_REGULAR);
+        UIFont::GetInstance()->RegisterFontInfo(HYQIHEI_65S);
+        UIFont::GetInstance()->RegisterFontInfo(ROBOTOCONDENSED_REGULAR);
+        uint8_t findPath[] = {UIFont::GetInstance()->GetFontId(HYQIHEI_65S),
+                              UIFont::GetInstance()->GetFontId(ROBOTOCONDENSED_REGULAR)};
+        UIMultiFontManager::GetInstance()->SetSearchFontList(UIFont::GetInstance()->GetFontId(NOTOSANSCJKJP_REGULAR),
+                                                             findPath, sizeof(findPath));
+        UILabel* label = new UILabel();
+        label->SetPosition(positionX_ + offsetX, positionY_);
+        label->Resize(LABEL_WIDTH, LABEL_HEIGHT);
+        label->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE);
+        label->SetFont(NOTOSANSCJKJP_REGULAR, 24); // 24 : size
+        label->SetText("韩语리기");
+        container_->Add(label);
+        positionY_ += LABEL_HEIGHT + GAP;
+    }
+}
+
+void UITestVectorFont::Font_FontEngine_MultiLanguage_Test_VI_Lang_001()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("CH+VI Language");
+        UIFont::GetInstance()->RegisterFontInfo(NOTOSANSCJKJP_REGULAR);
+        UIFont::GetInstance()->RegisterFontInfo(HYQIHEI_65S);
+        UIFont::GetInstance()->RegisterFontInfo(ROBOTOCONDENSED_REGULAR);
+        uint8_t findPath4[] = {UIFont::GetInstance()->GetFontId(HYQIHEI_65S),
+                               UIFont::GetInstance()->GetFontId(ROBOTOCONDENSED_REGULAR)};
+        UIMultiFontManager::GetInstance()->SetSearchFontList(UIFont::GetInstance()->GetFontId(NOTOSANSCJKJP_REGULAR),
+                                                             findPath4, sizeof(findPath4));
+        UILabel* label = new UILabel();
+        label->SetPosition(positionX_ + offsetX, positionY_);
+        label->Resize(LABEL_WIDTH, LABEL_HEIGHT);
+        label->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE);
+        label->SetFont(NOTOSANSCJKJP_REGULAR, 24); // 24 : size
+        label->SetText("越南语Kết thúc tập luyện?");
+        container_->Add(label);
+        positionY_ += LABEL_HEIGHT + GAP;
+    }
+}
+
+void UITestVectorFont::Font_FontEngine_MultiLanguage_Test_CS_Lang_001()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("CH+CS Language");
+        UIFont::GetInstance()->RegisterFontInfo(NOTOSANSCJKJP_REGULAR);
+        UIFont::GetInstance()->RegisterFontInfo(HYQIHEI_65S);
+        UIFont::GetInstance()->RegisterFontInfo(ROBOTOCONDENSED_REGULAR);
+        uint8_t findPath4[] = {UIFont::GetInstance()->GetFontId(HYQIHEI_65S),
+                               UIFont::GetInstance()->GetFontId(ROBOTOCONDENSED_REGULAR)};
+        UIMultiFontManager::GetInstance()->SetSearchFontList(UIFont::GetInstance()->GetFontId(NOTOSANSCJKJP_REGULAR),
+                                                             findPath4, sizeof(findPath4));
+        UILabel* label = new UILabel();
+        label->SetPosition(positionX_ + offsetX, positionY_);
+        label->Resize(LABEL_WIDTH, LABEL_HEIGHT);
+        label->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE);
+        label->SetFont(NOTOSANSCJKJP_REGULAR, 24); // 24 : size
+        label->SetText("捷克语sledování tepové frekvence");
+        container_->Add(label);
+        positionY_ += LABEL_HEIGHT + GAP;
+    }
+}
+
+void UITestVectorFont::Font_FontEngine_MultiLanguage_Test_EL_Lang_001()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("CH+EL Language");
+        UIFont::GetInstance()->RegisterFontInfo(NOTOSANSCJKJP_REGULAR);
+        UIFont::GetInstance()->RegisterFontInfo(HYQIHEI_65S);
+        UIFont::GetInstance()->RegisterFontInfo(ROBOTOCONDENSED_REGULAR);
+        uint8_t findPath4[] = {UIFont::GetInstance()->GetFontId(HYQIHEI_65S),
+                               UIFont::GetInstance()->GetFontId(ROBOTOCONDENSED_REGULAR)};
+        UIMultiFontManager::GetInstance()->SetSearchFontList(UIFont::GetInstance()->GetFontId(NOTOSANSCJKJP_REGULAR),
+                                                             findPath4, sizeof(findPath4));
+        UILabel* label = new UILabel();
+        label->SetPosition(positionX_ + offsetX, positionY_);
+        label->Resize(LABEL_WIDTH, LABEL_HEIGHT);
+        label->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE);
+        label->SetFont(NOTOSANSCJKJP_REGULAR, 24); // 24 : size
+        label->SetText("西班牙España");
+        container_->Add(label);
+        positionY_ += LABEL_HEIGHT + GAP;
+    }
+}
+
+void UITestVectorFont::Font_FontEngine_MultiLanguage_Test_RO_Lang_001()
+{
+    if (container_ != nullptr) {
+        InnerTestTitle("RO Language");
+        UIFont::GetInstance()->RegisterFontInfo(NOTOSANSCJKJP_REGULAR);
+        UIFont::GetInstance()->RegisterFontInfo(HYQIHEI_65S);
+        UIFont::GetInstance()->RegisterFontInfo(ROBOTOCONDENSED_REGULAR);
+        uint8_t findPath4[] = {UIFont::GetInstance()->GetFontId(HYQIHEI_65S),
+                               UIFont::GetInstance()->GetFontId(ROBOTOCONDENSED_REGULAR)};
+        UIMultiFontManager::GetInstance()->SetSearchFontList(UIFont::GetInstance()->GetFontId(NOTOSANSCJKJP_REGULAR),
+                                                             findPath4, sizeof(findPath4));
+        UILabel* label = new UILabel();
+        label->SetPosition(positionX_ + offsetX, positionY_);
+        label->Resize(LABEL_WIDTH, LABEL_HEIGHT);
+        label->SetLineBreakMode(UILabel::LINE_BREAK_MARQUEE);
+        label->SetFont(NOTOSANSCJKJP_REGULAR, 24); // 24 : size
+        label->SetText("罗马尼亚Română");
+        container_->Add(label);
+        positionY_ += LABEL_HEIGHT + GAP;
+    }
+}
+#endif
+} // namespace OHOS
+#endif // ENABLE_VECTOR_FONT
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_vector_font/ui_test_vector_font.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_vector_font/ui_test_vector_font.h
new file mode 100644 (file)
index 0000000..42eb77e
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+
+#ifndef UI_TEST_VECTOR_FONT_H
+#define UI_TEST_VECTOR_FONT_H
+
+#include "graphic_config.h"
+#if ENABLE_VECTOR_FONT
+#include "ui_test.h"
+#include "components/ui_scroll_view.h"
+#include "font/ui_font.h"
+#include <string>
+
+namespace OHOS {
+class UITestVectorFont : public UITest {
+public:
+    UITestVectorFont() {}
+    ~UITestVectorFont() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    void Font_FontEngine_Vector_Test_CH_Lang_001();
+    void Font_FontEngine_Vector_Test_CH_Lang_002();
+    void Font_FontEngine_Vector_Test_JA_Lang_001();
+    void Font_FontEngine_Vector_Test_JA_Lang_002();
+    void Font_FontEngine_Vector_Test_KR_Lang_001();
+    void Font_FontEngine_Vector_Test_VI_Lang_001();
+#if ENABLE_MULTI_FONT
+    /**
+     * @brief Test JA language
+     */
+    void Font_FontEngine_MultiLanguage_Test_JA_Lang_001();
+
+    /**
+     * @brief Test UnRegister JA language
+     */
+    void Font_FontEngine_MultiLanguage_Test_JA_Lang_002();
+
+    /**
+     * @brief Test KR language
+     */
+    void Font_FontEngine_MultiLanguage_Test_KR_Lang_001();
+
+    /**
+     * @brief Test VI language
+     */
+    void Font_FontEngine_MultiLanguage_Test_VI_Lang_001();
+
+    /**
+     * @brief Test CS language
+     */
+    void Font_FontEngine_MultiLanguage_Test_CS_Lang_001();
+
+    /**
+     * @brief Test EL language
+     */
+    void Font_FontEngine_MultiLanguage_Test_EL_Lang_001();
+
+    /**
+     * @brief Test RO language
+     */
+    void Font_FontEngine_MultiLanguage_Test_RO_Lang_001();
+#endif
+    UIScrollView* container_ = nullptr;
+    void InnerTestTitle(const char* title);
+};
+} // namespace OHOS
+#endif // ENABLE_VECTOR_FONT
+#endif // UI_TEST_VECTOR_FONT_H
index 73e8792..64da6e9 100644 (file)
@@ -190,6 +190,7 @@ void UITestVideoPlay::TearDown()
     }\r
 \r
     if (videoPlay_ != nullptr) {\r
+        videoPlay_->StopVideoPlay();\r
         delete videoPlay_;\r
         videoPlay_ = nullptr;\r
     }\r
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/alignment.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/alignment.h
new file mode 100644 (file)
index 0000000..a7f98c0
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+#ifndef ALIGNMENT_H
+#define ALIGNMENT_H
+
+namespace OHOS {
+enum AlignmentType : uint16_t {
+    ALIGN_DEFAULT      = 0xFF00,    // 默认值,不对齐
+    ALIGN_TOP_LEFT     = 0x0000,    // 控件左上角对齐到父容器内容区左上角
+    ALIGN_TOP_MID      = 0x0001,    // 控件顶部中点对齐到父容器内容区顶部中点
+    ALIGN_TOP_RIGHT    = 0x0002,    // 控件右上角对齐到父容器内容区右上角
+    ALIGN_MID_LEFT     = 0x0010,    // 控件右下角对齐到父容器内容区右下角
+    ALIGN_MID_MID      = 0x0011,    // 控件右边缘中点对齐到父容器内容区右边缘中点
+    ALIGN_MID_RIGHT    = 0x0012,    // 控件中心对齐到父容器内容区中心
+    ALIGN_BOTTOM_LEFT  = 0x0020,    // 控件左下角对齐到父容器内容区左下角
+    ALIGN_BOTTOM_MID   = 0x0021,    // 控件底部中点对齐到父容器内容区底部中点
+    ALIGN_BOTTOM_RIGHT = 0x0022,    // 控件右下角对齐到父容器内容区右下角
+    // 外部对齐方式
+    ALIGN_OUT_TOP_LEFT     = 0x1000,  // 控件左下角对齐到参考对象左上角
+    ALIGN_OUT_TOP_MID      = 0x1001,  // 控件底部中点对齐到参考对象顶部中点
+    ALIGN_OUT_TOP_RIGHT    = 0x1002,  // 控件右下角对齐到参考对象右上角
+    ALIGN_OUT_BOTTOM_LEFT  = 0x1010,  // 控件左上角对齐到参考对象左下角
+    ALIGN_OUT_BOTTOM_MID   = 0x1011,  // 控件顶部中点对齐到参考对象底部中点
+    ALIGN_OUT_BOTTOM_RIGHT = 0x1012,  // 控件右上角对齐到参考对象右下角
+    ALIGN_OUT_LEFT_TOP     = 0x1020,  // 控件右上角对齐到参考对象左上角
+    ALIGN_OUT_LEFT_MID     = 0x1021,  // 控件右侧中点对齐到参考对象左侧中点
+    ALIGN_OUT_LEFT_BOTTOM  = 0x1022,  // 控件右下角对齐到参考对象左下角
+    ALIGN_OUT_RIGHT_TOP    = 0x1030,  // 控件左上角对齐到参考对象右上角
+    ALIGN_OUT_RIGHT_MID    = 0x1031,  // 控件左侧中点对齐到参考对象右侧中点
+    ALIGN_OUT_RIGHT_BOTTOM = 0x1032,  // 控件左下角对齐到参考对象右下角
+};
+
+// 对齐方式编码定义
+#define ALIGN_BASE_MASK   0x00FF  // 基础对齐掩码
+#define ALIGN_OUTER_MASK  0x1000  // 外部对齐标志
+#define ALIGN_X_MASK      0x00F0  // X轴对齐掩码
+#define ALIGN_Y_MASK      0x000F  // Y轴对齐掩码
+}
+#endif // ALIGNMENT_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_dynamic.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_dynamic.cpp
new file mode 100644 (file)
index 0000000..5ca4e80
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_alignment_dynamic.h"
+
+#include "common/screen.h"
+#include "components/ui_view.h"
+#include "components/ui_swipe_view.h"
+
+
+static int16_t g_deltaY = 0;
+static int16_t g_buttonW = 150;
+static int16_t g_buttonH = 170;
+static int16_t g_rx = 20;
+static int16_t g_ry = 50;
+static int16_t g_rw = 400;
+static int16_t g_rh = 355;
+static int16_t g_ofsX = 40;
+static int16_t g_ofsY = 40;
+
+namespace OHOS {
+
+void UITestDynamicAlignment::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+    }
+    viewGroup_ = new UIViewGroup();
+    label1_ = new UILabel();
+    label2_ = new UILabel();
+    label3_ = new UILabel();
+    label4_ = new UILabel();
+    label5_ = new UILabel();
+    label6_ = new UILabel();
+    label7_ = new UILabel();
+    label8_ = new UILabel();
+    label9_ = new UILabel();
+    if (list_ == nullptr) {
+        list_ = new ListLayout(UISwipeView::VERTICAL);
+        uint16_t width = Screen::GetInstance().GetWidth();
+        uint16_t height = Screen::GetInstance().GetHeight();
+        list_->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, 0, width, height + 1);
+        container_->Add(list_);
+    }
+}
+
+void UITestDynamicAlignment::TearDown()
+{
+    animator_.Stop();
+    DeleteChildren(container_);
+    container_ = nullptr;
+    list_ = nullptr;
+    viewGroup_ = nullptr;
+    label1_ = nullptr;
+    label2_ = nullptr;
+    label3_ = nullptr;
+    label4_ = nullptr;
+    label5_ = nullptr;
+    label6_ = nullptr;
+    label7_ = nullptr;
+    label8_ = nullptr;
+    label9_ = nullptr;
+}
+
+void UITestDynamicAlignment::Callback(UIView* view)
+{
+    angleValue_++;
+
+    if (scaleValue_.x_ < 0.2f) {
+        scaleStep_ = 0.01f;
+    } else if (scaleValue_.x_ > 1.5f) {
+        scaleStep_ = -0.01f;
+    }
+    scaleValue_.x_ += scaleStep_;
+    scaleValue_.y_ += scaleStep_;
+
+    uint16_t w = viewGroup_->GetWidth();
+    uint16_t h = viewGroup_->GetHeight();
+    viewGroup_->Resize(w - 1, h - 1);
+    container_->Invalidate();
+}
+
+const UIView* UITestDynamicAlignment::GetTestView()
+{
+    UIKitAlignDynamicTest001();
+    animator_.Start();
+    return container_;
+}
+
+void UITestDynamicAlignment::UIKitAlignDynamicTop()
+{
+    label1_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label1_->SetText("TOP_LEFT:");
+    label1_->SetTouchable(true);
+    label1_->Resize(g_buttonW, g_buttonH);
+    label1_->SetStyle(STYLE_TEXT_COLOR, Color::Yellow().full);
+    label1_->AlignToReference(ALIGN_TOP_LEFT, viewGroup_, g_ofsX, g_ofsY);
+
+    label2_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label2_->SetText("TOP_MID:");
+    label2_->SetTouchable(true);
+    label2_->Resize(g_buttonW, g_buttonH);
+    label2_->AlignToReference(ALIGN_TOP_MID, viewGroup_, g_ofsX, g_ofsY);
+    label2_->SetStyle(STYLE_TEXT_COLOR, Color::Green().full);
+    
+    label3_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label3_->SetText("TOP_RIGHT:");
+    label3_->SetTouchable(true);
+    label3_->Resize(g_buttonW, g_buttonH);
+    label3_->AlignToReference(ALIGN_TOP_RIGHT, viewGroup_, g_ofsX, g_ofsY);
+    label3_->SetStyle(STYLE_TEXT_COLOR, Color::Blue().full);
+}
+
+void UITestDynamicAlignment::UIKitAlignDynamicMid()
+{
+    label4_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label4_->SetText("LEFT_MID:");
+    label4_->SetTouchable(true);
+    label4_->Resize(g_buttonW, g_buttonH);
+    label4_->SetStyle(STYLE_TEXT_COLOR, Color::Yellow().full);
+    label4_->AlignToReference(ALIGN_MID_LEFT, viewGroup_, g_ofsX, g_ofsY);
+
+    label5_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label5_->SetText("CENTER_IND:");
+    label5_->SetTouchable(true);
+    label5_->Resize(g_buttonW, g_buttonH);
+    label5_->AlignToReference(ALIGN_MID_MID, viewGroup_, g_ofsX, g_ofsY);
+    label5_->SetStyle(STYLE_TEXT_COLOR, Color::Green().full);
+    
+    label6_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label6_->SetText("RIGHT_MID:");
+    label6_->SetTouchable(true);
+    label6_->Resize(g_buttonW, g_buttonH);
+    label6_->AlignToReference(ALIGN_MID_RIGHT, viewGroup_, g_ofsX, g_ofsY);
+    label6_->SetStyle(STYLE_TEXT_COLOR, Color::Blue().full);
+}
+
+void UITestDynamicAlignment::UIKitAlignDynamicButtom()
+{
+    label7_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label7_->SetText("BOT_LEFT:");
+    label7_->SetTouchable(true);
+    label7_->Resize(g_buttonW, g_buttonH);
+    label7_->SetStyle(STYLE_TEXT_COLOR, Color::Yellow().full);
+    label7_->AlignToReference(ALIGN_BOTTOM_LEFT, viewGroup_, g_ofsX, g_ofsY);
+
+    label8_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label8_->SetText("BOT_MID:");
+    label8_->SetTouchable(true);
+    label8_->Resize(g_buttonW, g_buttonH);
+    label8_->AlignToReference(ALIGN_BOTTOM_MID, viewGroup_, g_ofsX, g_ofsY);
+    label8_->SetStyle(STYLE_TEXT_COLOR, Color::Green().full);
+    
+    label9_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label9_->SetText("BOT_RIGHT:");
+    label9_->SetTouchable(true);
+    label9_->Resize(g_buttonW, g_buttonH);
+    label9_->AlignToReference(ALIGN_BOTTOM_RIGHT, viewGroup_, g_ofsX, g_ofsY);
+    label9_->SetStyle(STYLE_TEXT_COLOR, Color::Blue().full);
+}
+
+void UITestDynamicAlignment::UIKitAlignDynamicTest001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    container_->Add(viewGroup_);
+    viewGroup_->Add(label1_);
+    viewGroup_->Add(label2_);
+    viewGroup_->Add(label3_);
+    viewGroup_->Add(label4_);
+    viewGroup_->Add(label5_);
+    viewGroup_->Add(label6_);
+    viewGroup_->Add(label7_);
+    viewGroup_->Add(label8_);
+    viewGroup_->Add(label9_);
+    
+    viewGroup_->SetPosition(g_rx, g_ry, g_rw, g_rh);
+    viewGroup_->SetStyle(STYLE_TEXT_COLOR, Color::Red().full);
+    viewGroup_->SetStyle(STYLE_BORDER_COLOR, Color::White().full);
+    viewGroup_->SetStyle(STYLE_BORDER_OPA, HALF_OPA_OPAQUE);
+    viewGroup_->SetStyle(STYLE_BORDER_WIDTH, VIEW_STYLE_BORDER_WIDTH);
+    viewGroup_->SetStyle(STYLE_BORDER_RADIUS, VIEW_STYLE_BORDER_RADIUS);
+    viewGroup_->SetStyle(STYLE_BACKGROUND_OPA, 0);
+    list_->Add(viewGroup_);
+    UIKitAlignDynamicTop();
+    UIKitAlignDynamicMid();
+    UIKitAlignDynamicButtom();
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_dynamic.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_dynamic.h
new file mode 100644 (file)
index 0000000..978d8d5
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_ALIGNMENT3_H
+#define UI_TEST_ALIGNMENT3_H
+
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "components/ui_image_view.h"
+#include "layout/list_layout.h"
+#include "ui_test.h"
+#include "animator/animator.h"
+
+namespace OHOS {
+class UITestDynamicAlignment : public UITest, public AnimatorCallback {
+public:
+    UITestDynamicAlignment() : animator_(this, nullptr, 1000, true) // 1000: the animator duration time is 1000ms
+    {}
+    ~UITestDynamicAlignment() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    void Callback(UIView* view) override;
+    int16_t angleValue_ = 0;
+    Vector2<float> scaleValue_ = {1.0f, 1.0f};
+    float scaleStep_ = 0.01f;
+    const Vector2<float> VIEW_CENTER = {75, 75};
+    const Vector2<float> GROUP_CENTER = {200, 200};
+
+    /**
+     * @brief Test align Function
+     */
+    void UIKitAlignDynamicTest001();
+    void UIKitAlignDynamicTop();
+    void UIKitAlignDynamicMid();
+    void UIKitAlignDynamicButtom();
+
+private:
+    Animator animator_;
+    UIScrollView* container_ = nullptr;
+    ListLayout* list_ = nullptr;
+    UIViewGroup* viewGroup_ = nullptr;
+    UILabel* label1_ = nullptr;
+    UILabel* label2_ = nullptr;
+    UILabel* label3_ = nullptr;
+    UILabel* label4_ = nullptr;
+    UILabel* label5_ = nullptr;
+    UILabel* label6_ = nullptr;
+    UILabel* label7_ = nullptr;
+    UILabel* label8_ = nullptr;
+    UILabel* label9_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_ALIGNMENT3_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_external.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_external.cpp
new file mode 100644 (file)
index 0000000..bf832de
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_alignment_external.h"
+
+#include "common/screen.h"
+#include "components/ui_view.h"
+
+static int16_t g_deltaY1 = 150;
+static int16_t g_deltaY2 = 25;
+static int16_t g_buttonx = 255;
+static int16_t g_buttony = 255;
+static int16_t g_buttonW = 216;
+static int16_t g_buttonH = 200;
+namespace OHOS {
+
+void UITestExternalAlignment::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+    }
+    label_ = new UILabel();
+    label1_ = new UILabel();
+    label2_ = new UILabel();
+    label3_ = new UILabel();
+    label4_ = new UILabel();
+    label5_ = new UILabel();
+    label6_ = new UILabel();
+    label7_ = new UILabel();
+    label8_ = new UILabel();
+    label9_ = new UILabel();
+    label10_ = new UILabel();
+    label11_ = new UILabel();
+    label12_ = new UILabel();
+}
+
+void UITestExternalAlignment::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+    label_ = nullptr;
+    label1_ = nullptr;
+    label2_ = nullptr;
+    label3_ = nullptr;
+    label4_ = nullptr;
+    label5_ = nullptr;
+    label6_ = nullptr;
+    label7_ = nullptr;
+    label8_ = nullptr;
+    label9_ = nullptr;
+    label10_ = nullptr;
+    label11_ = nullptr;
+    label12_ = nullptr;
+}
+
+const UIView* UITestExternalAlignment::GetTestView()
+{
+    UIKitAlignExternalTest001();
+    return container_;
+}
+
+void UITestExternalAlignment::UIKitAlignExternalTop()
+{
+    label1_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label1_->SetText("OUT_TOP_LEFT:");
+    label1_->SetTouchable(true);
+    label1_->Resize(g_buttonW, g_buttonH);
+    label1_->SetStyle(STYLE_TEXT_COLOR, Color::Yellow().full);
+    label1_->SetStyle(STYLE_BORDER_OPA, Color::Gray().full);
+    label1_->AlignToReference(ALIGN_OUT_TOP_LEFT, label_, 0, g_deltaY1);
+    container_->Add(label1_);
+
+    label2_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label2_->SetText("OUT_TOP_MID:");
+    label2_->SetTouchable(true);
+    label2_->Resize(g_buttonW, g_buttonH);
+    label2_->AlignToReference(ALIGN_OUT_TOP_MID, label_, 0, g_deltaY1);
+    label2_->SetStyle(STYLE_TEXT_COLOR, Color::Green().full);
+    container_->Add(label2_);
+    
+    label3_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label3_->SetText("OUT_TOP_RIGHT:");
+    label3_->SetTouchable(true);
+    label3_->Resize(g_buttonW, g_buttonH);
+    label3_->AlignToReference(ALIGN_OUT_TOP_RIGHT, label_, 0, g_deltaY1);
+    label3_->SetStyle(STYLE_TEXT_COLOR, Color::Blue().full);
+    container_->Add(label3_);
+}
+void UITestExternalAlignment::UIKitAlignExternalBottom()
+{
+    label4_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label4_->SetText("OUT_BOTTOM_LEFT:");
+    label4_->SetTouchable(true);
+    label4_->Resize(g_buttonW, g_buttonH);
+    label4_->SetStyle(STYLE_TEXT_COLOR, Color::Yellow().full);
+    label4_->AlignToReference(ALIGN_OUT_BOTTOM_LEFT, label_, 0, -g_deltaY1);
+    container_->Add(label4_);
+
+    label5_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label5_->SetText("OUT_BOTTOM_MID:");
+    label5_->SetTouchable(true);
+    label5_->Resize(g_buttonW, g_buttonH);
+    label5_->AlignToReference(ALIGN_OUT_BOTTOM_MID, label_, 0, -g_deltaY1);
+    label5_->SetStyle(STYLE_TEXT_COLOR, Color::Green().full);
+    container_->Add(label5_);
+    
+    label6_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label6_->SetText("OUT_BOTTOM_RIGHT:");
+    label6_->SetTouchable(true);
+    label6_->Resize(g_buttonW, g_buttonH);
+    label6_->AlignToReference(ALIGN_OUT_BOTTOM_RIGHT, label_, 0, -g_deltaY1);
+    label6_->SetStyle(STYLE_TEXT_COLOR, Color::Blue().full);
+    container_->Add(label6_);
+}
+
+void UITestExternalAlignment::UIKitAlignExternalLeft()
+{
+    label7_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label7_->SetText("OUT_LEFT_TOP:");
+    label7_->SetTouchable(true);
+    label7_->Resize(g_buttonW, g_buttonH);
+    label7_->SetStyle(STYLE_TEXT_COLOR, Color::Yellow().full);
+    label7_->AlignToReference(ALIGN_OUT_LEFT_TOP, label_, 0, -g_deltaY2);
+    container_->Add(label7_);
+
+    label8_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label8_->SetText("OUT_LEFT_MID:");
+    label8_->SetTouchable(true);
+    label8_->Resize(g_buttonW, g_buttonH);
+    label8_->AlignToReference(ALIGN_OUT_LEFT_MID, label_, 0, 0);
+    label8_->SetStyle(STYLE_TEXT_COLOR, Color::Green().full);
+    container_->Add(label8_);
+    
+    label9_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label9_->SetText("OUT_LEFT_BOTTOM:");
+    label9_->SetTouchable(true);
+    label9_->Resize(g_buttonW, g_buttonH);
+    label9_->AlignToReference(ALIGN_OUT_LEFT_BOTTOM, label_, 0, g_deltaY2);
+    label9_->SetStyle(STYLE_TEXT_COLOR, Color::Blue().full);
+    container_->Add(label9_);
+}
+
+void UITestExternalAlignment::UIKitAlignExternalRight()
+{
+    label10_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label10_->SetText("OUT_RIGHT_TOP:");
+    label10_->SetTouchable(true);
+    label10_->Resize(g_buttonW, g_buttonH);
+    label10_->SetStyle(STYLE_TEXT_COLOR, Color::Yellow().full);
+    label10_->AlignToReference(ALIGN_OUT_RIGHT_TOP, label_, 0, -g_deltaY2);
+    container_->Add(label10_);
+
+    label11_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label11_->SetText("OUT_RIGHT_MID:");
+    label11_->SetTouchable(true);
+    label11_->Resize(g_buttonW, g_buttonH);
+    label11_->AlignToReference(ALIGN_OUT_RIGHT_MID, label_, 0, 0);
+    label11_->SetStyle(STYLE_TEXT_COLOR, Color::Green().full);
+    container_->Add(label11_);
+    
+    label12_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label12_->SetText("OUT_RIGHT_BOTTOM:");
+    label12_->SetTouchable(true);
+    label12_->Resize(g_buttonW, g_buttonH);
+    label12_->AlignToReference(ALIGN_OUT_RIGHT_BOTTOM, label_, 0, g_deltaY2);
+    label12_->SetStyle(STYLE_TEXT_COLOR, Color::Blue().full);
+    container_->Add(label12_);
+}
+
+void UITestExternalAlignment::UIKitAlignExternalTest001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    
+    label_->SetPosition(g_buttonx, g_buttony, g_buttonW, g_buttonH);
+    label_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label_->SetText("参考控件:");
+    label_->SetStyle(STYLE_TEXT_COLOR, Color::Red().full);
+    label_->SetStyle(STYLE_BORDER_OPA, Color::Gray().full);
+    label_->SetTouchable(true);
+    container_->Add(label_);
+
+    UIKitAlignExternalTop();
+    UIKitAlignExternalBottom();
+    UIKitAlignExternalLeft();
+    UIKitAlignExternalRight();
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_external.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_external.h
new file mode 100644 (file)
index 0000000..34834ad
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_ALIGNMENT2_H
+#define UI_TEST_ALIGNMENT2_H
+
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestExternalAlignment : public UITest {
+public:
+    UITestExternalAlignment() : container_(nullptr) {}
+    ~UITestExternalAlignment() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    /**
+     * @brief Test align Function
+     */
+    void UIKitAlignExternalTest001();
+    void UIKitAlignExternalTop();
+    void UIKitAlignExternalBottom();
+    void UIKitAlignExternalLeft();
+    void UIKitAlignExternalRight();
+
+private:
+    UIScrollView* container_ = nullptr;
+    UILabel* label_ = nullptr;
+    UILabel* label1_ = nullptr;
+    UILabel* label2_ = nullptr;
+    UILabel* label3_ = nullptr;
+    UILabel* label4_ = nullptr;
+    UILabel* label5_ = nullptr;
+    UILabel* label6_ = nullptr;
+    UILabel* label7_ = nullptr;
+    UILabel* label8_ = nullptr;
+    UILabel* label9_ = nullptr;
+    UILabel* label10_ = nullptr;
+    UILabel* label11_ = nullptr;
+    UILabel* label12_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_ALIGNMENT2_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_internal.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_internal.cpp
new file mode 100644 (file)
index 0000000..0fcb6aa
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_alignment_internal.h"
+
+#include "common/screen.h"
+#include "components/ui_view.h"
+
+
+static int16_t g_deltaY = 0;
+static int16_t g_buttonW = 150;
+static int16_t g_buttonH = 170;
+static int16_t g_rx = 40;
+static int16_t g_ry = 40;
+static int16_t g_rw = 375;
+static int16_t g_rh = 325;
+static int16_t xofs = 10;
+static int16_t yofs = 10;
+
+namespace OHOS {
+
+void UITestInternalAlignment::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+    }
+    viewGroup_ = new UIViewGroup();
+    label1_ = new UILabel();
+    label2_ = new UILabel();
+    label3_ = new UILabel();
+    label4_ = new UILabel();
+    label5_ = new UILabel();
+    label6_ = new UILabel();
+    label7_ = new UILabel();
+    label8_ = new UILabel();
+    label9_ = new UILabel();
+}
+
+void UITestInternalAlignment::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+    viewGroup_ = nullptr;
+    label1_ = nullptr;
+    label2_ = nullptr;
+    label3_ = nullptr;
+    label4_ = nullptr;
+    label5_ = nullptr;
+    label6_ = nullptr;
+    label7_ = nullptr;
+    label8_ = nullptr;
+    label9_ = nullptr;
+}
+
+const UIView* UITestInternalAlignment::GetTestView()
+{
+    UIKitAlignInternalTest001();
+    return container_;
+}
+
+void UITestInternalAlignment::UIKitAlignInternalTop()
+{
+    label1_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label1_->SetText("TOP_LEFT:");
+    label1_->SetTouchable(true);
+    label1_->Resize(g_buttonW, g_buttonH);
+    label1_->SetStyle(STYLE_TEXT_COLOR, Color::Yellow().full);
+    label1_->AlignToReference(ALIGN_TOP_LEFT, viewGroup_, xofs, yofs);
+
+    label2_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label2_->SetText("TOP_MID:");
+    label2_->SetTouchable(true);
+    label2_->Resize(g_buttonW, g_buttonH);
+    label2_->AlignToReference(ALIGN_TOP_MID, viewGroup_, xofs, yofs);
+    label2_->SetStyle(STYLE_TEXT_COLOR, Color::Green().full);
+    
+    label3_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label3_->SetText("TOP_RIGHT:");
+    label3_->SetTouchable(true);
+    label3_->Resize(g_buttonW, g_buttonH);
+    label3_->AlignToReference(ALIGN_TOP_RIGHT, viewGroup_, xofs, yofs);
+    label3_->SetStyle(STYLE_TEXT_COLOR, Color::Blue().full);
+}
+
+void UITestInternalAlignment::UIKitAlignInternalBottom()
+{
+    label7_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label7_->SetText("BOTTOM_LEFT:");
+    label7_->SetTouchable(true);
+    label7_->Resize(g_buttonW, g_buttonH);
+    label7_->SetStyle(STYLE_TEXT_COLOR, Color::Yellow().full);
+    label7_->AlignToReference(ALIGN_BOTTOM_LEFT, viewGroup_, xofs, yofs);
+
+    label8_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label8_->SetText("BOTTOM_MID:");
+    label8_->SetTouchable(true);
+    label8_->Resize(g_buttonW, g_buttonH);
+    label8_->AlignToReference(ALIGN_BOTTOM_MID, viewGroup_, xofs, yofs);
+    label8_->SetStyle(STYLE_TEXT_COLOR, Color::Green().full);
+    
+    label9_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label9_->SetText("BOTTOM_RIGHT:");
+    label9_->SetTouchable(true);
+    label9_->Resize(g_buttonW, g_buttonH);
+    label9_->AlignToReference(ALIGN_BOTTOM_RIGHT, viewGroup_, xofs, yofs);
+    label9_->SetStyle(STYLE_TEXT_COLOR, Color::Blue().full);
+}
+void UITestInternalAlignment::UIKitAlignInternalMid()
+{
+    label4_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label4_->SetText("LEFT_MID:");
+    label4_->SetTouchable(true);
+    label4_->Resize(g_buttonW, g_buttonH);
+    label4_->SetStyle(STYLE_TEXT_COLOR, Color::Yellow().full);
+    label4_->AlignToReference(ALIGN_MID_LEFT, viewGroup_, xofs, yofs);
+
+    label5_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label5_->SetText("CENTER_IND:");
+    label5_->SetTouchable(true);
+    label5_->Resize(g_buttonW, g_buttonH);
+    label5_->AlignToReference(ALIGN_MID_MID, viewGroup_, xofs, yofs);
+    label5_->SetStyle(STYLE_TEXT_COLOR, Color::Green().full);
+    
+    label6_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label6_->SetText("RIGHT_MID:");
+    label6_->SetTouchable(true);
+    label6_->Resize(g_buttonW, g_buttonH);
+    label6_->AlignToReference(ALIGN_MID_RIGHT, viewGroup_, xofs, yofs);
+    label6_->SetStyle(STYLE_TEXT_COLOR, Color::Blue().full);
+}
+
+void UITestInternalAlignment::UIKitAlignInternalTest001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    container_->Add(viewGroup_);
+    viewGroup_->Add(label1_);
+    viewGroup_->Add(label2_);
+    viewGroup_->Add(label3_);
+    viewGroup_->Add(label4_);
+    viewGroup_->Add(label5_);
+    viewGroup_->Add(label6_);
+    viewGroup_->Add(label7_);
+    viewGroup_->Add(label8_);
+    viewGroup_->Add(label9_);
+    
+    viewGroup_->SetPosition(g_rx, g_ry, g_rw, g_rh);
+    viewGroup_->SetStyle(STYLE_TEXT_COLOR, Color::Red().full);
+    viewGroup_->SetStyle(STYLE_BORDER_COLOR, Color::White().full);
+    viewGroup_->SetStyle(STYLE_BORDER_OPA, HALF_OPA_OPAQUE);
+    viewGroup_->SetStyle(STYLE_BORDER_WIDTH, VIEW_STYLE_BORDER_WIDTH);
+    viewGroup_->SetStyle(STYLE_BORDER_RADIUS, VIEW_STYLE_BORDER_RADIUS);
+    viewGroup_->SetStyle(STYLE_BACKGROUND_OPA, 0);
+    UIKitAlignInternalTop();
+    UIKitAlignInternalBottom();
+    UIKitAlignInternalMid();
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_internal.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_alignment/ui_test_alignment_internal.h
new file mode 100644 (file)
index 0000000..006beb5
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_ALIGNMENT1_H
+#define UI_TEST_ALIGNMENT1_H
+
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestInternalAlignment : public UITest {
+public:
+    UITestInternalAlignment() : container_(nullptr) {}
+    ~UITestInternalAlignment() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    /**
+     * @brief Test align Function
+     */
+    void UIKitAlignInternalTest001();
+    void UIKitAlignInternalTop();
+    void UIKitAlignInternalBottom();
+    void UIKitAlignInternalMid();
+
+private:
+    UIScrollView* container_ = nullptr;
+    UIViewGroup* viewGroup_ = nullptr;
+    UILabel* label1_ = nullptr;
+    UILabel* label2_ = nullptr;
+    UILabel* label3_ = nullptr;
+    UILabel* label4_ = nullptr;
+    UILabel* label5_ = nullptr;
+    UILabel* label6_ = nullptr;
+    UILabel* label7_ = nullptr;
+    UILabel* label8_ = nullptr;
+    UILabel* label9_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_ALIGNMENT1_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bitmap/test_resource_config.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bitmap/test_resource_config.h
new file mode 100644 (file)
index 0000000..f899a88
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+ 
+#ifndef TEST_RESOURCE_CONFIG_H
+#define TEST_RESOURCE_CONFIG_H
+ 
+namespace OHOS {
+#if defined QT_COMPILER
+#define IMAGE_DIR "..\\..\\simulator\\config\\images\\"
+#define FACE_DIR "..\\..\\simulator\\config\\faces\\default\\"
+#elif defined _WIN32
+#define IMAGE_DIR "..\\config\\images\\"
+#define FACE_DIR "..\\config\\faces\\default\\"
+#else
+#define IMAGE_DIR RES_PATH
+#define FACE_DIR RES_PATH
+#endif
+ 
+#define BLUE_RGB888_IMAGE_PATH (IMAGE_DIR "blue_rgb888.bin")
+#define BLUE_ARGB8888_IMAGE_PATH (IMAGE_DIR "blue_argb8888.bin")
+#define BLUE_RGB565_IMAGE_PATH (IMAGE_DIR "blue_rgb565.bin")
+#define BLUE_IMAGE_PATH (IMAGE_DIR "blue.png")
+#define RED_IMAGE_PATH (IMAGE_DIR "red.png")
+#define GREEN_IMAGE_PATH (IMAGE_DIR "green.png")
+#define YELLOW_IMAGE_PATH (IMAGE_DIR "yellow.png")
+#define IMAGE_ANIMATOR_0_PATH (IMAGE_DIR "image_animator_0.bin")
+#define IMAGE_ANIMATOR_1_PATH (IMAGE_DIR "image_animator_1.bin")
+#define IMAGE_ANIMATOR_2_PATH (IMAGE_DIR "image_animator_2.bin")
+#define IMAGE_ANIMATOR_3_PATH (IMAGE_DIR "image_animator_3.bin")
+#define B024_002_IMAGE_PATH (FACE_DIR "B024_002.bin")
+#define B024_009_IMAGE_PATH (FACE_DIR "B024_009.bin")
+#define B024_010_IMAGE_PATH (FACE_DIR "B024_010.bin")
+#define B024_011_IMAGE_PATH (FACE_DIR "B024_011.bin")
+#define SLIDER_BACKGROUND_IMAGE_PATH (IMAGE_DIR "sliderBackground.bin")
+#define SLIDER_INDICATOR_IMAGE_PATH (IMAGE_DIR "sliderIndicator.bin")
+#define SLIDER_KNOB_IMAGE_PATH (IMAGE_DIR "sliderKnob.bin")
+#define JPEG_IMAGE_PATH (IMAGE_DIR "jpeg.jpg")
+#define PNG_1_PALETTE_IMAGE_PATH (IMAGE_DIR "png_1_palette.png")
+#define PNG_2_PALETTE_IMAGE_PATH (IMAGE_DIR "png_2_palette.png")
+#define PNG_4_PALETTE_IMAGE_PATH (IMAGE_DIR "png_4_palette.png")
+#define PNG_8_PALETTE_IMAGE_PATH (IMAGE_DIR "png_8_palette.png")
+#define PNG_8_GRAY_IMAGE_PATH (IMAGE_DIR "png_8_gray.png")
+#define PNG_16_GRAY_IMAGE_PATH (IMAGE_DIR "png_16_gray.png")
+#define PNG_24_RGB_IMAGE_PATH (IMAGE_DIR "png_24_rgb.png")
+#define PNG_32_RGB_ALPHA_IMAGE_PATH (IMAGE_DIR "png_32_rgba.png")
+#ifndef VERSION_LITE
+#define GIF_IMAGE_PATH1 (IMAGE_DIR "gif_image1.gif")
+#define GIF_IMAGE_PATH2 (IMAGE_DIR "gif_image2.gif")
+#define GIF_IMAGE_PATH_ERROR (IMAGE_DIR "gif_error.gif")
+#define TIF_IMAGE_PATH (IMAGE_DIR "tif_image.tif")
+#endif
+#define VIDEO_SOURCE_DIRECTORY (IMAGE_DIR "video.mp4")
+#define TEST_RIGHT_ARROW (IMAGE_DIR "ic_arrow_right.png")
+#define TEST_BACK_LEFT_ARROW (IMAGE_DIR "ic_back.png")
+#define TEST_CIRCLE_FORE_IMAGE (FACE_DIR "fore.png")
+} // namespace OHOS
+#endif // TEST_RESOURCE_CONFIG_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bitmap/ui_test_view_bitmap.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bitmap/ui_test_view_bitmap.cpp
new file mode 100644 (file)
index 0000000..7ab48eb
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_view_bitmap.h"
+
+#include "securec.h"
+
+#include "common/screen.h"
+#include "components/ui_label_button.h"
+#include "test_resource_config.h"
+
+const uint16_t bitmap_positionX_ = 100;
+const uint16_t bitmap_positionY_ = 100;
+const uint16_t offsetY = 100;
+namespace OHOS {
+class ViewBitmapListener : public UIView::OnClickListener {
+public:
+    ViewBitmapListener(UIViewGroup* container, UIImageView* img) : container_(container), img_(img)
+    {
+        memset_s(&info_, sizeof(ImageInfo), 0, sizeof(ImageInfo));
+        if ((img != nullptr) && (container != nullptr)) {
+            container->Add(img);
+            img->SetVisible(false);
+        }
+    }
+    virtual ~ViewBitmapListener()
+    {
+        if (info_.data != nullptr) {
+            ImageCacheFree(info_);
+        }
+    }
+
+    bool OnClick(UIView& view, const ClickEvent& event) override
+    {
+        if (img_ == nullptr) {
+            return false;
+        }
+        if (info_.data != nullptr) {
+            ImageCacheFree(info_);
+        }
+        view.GetBitmap(info_);
+        img_->SetVisible(true);
+        img_->SetSrc(&info_);
+        img_->Invalidate();
+        return false;
+    }
+
+    UIViewGroup* container_;
+    UIImageView* img_;
+    ImageInfo info_;
+};
+
+class ScreenBitmapListener : public UIView::OnClickListener {
+public:
+    ScreenBitmapListener(UIViewGroup* container, UIImageView* img) : container_(container), img_(img)
+    {
+        memset_s(&info_, sizeof(ImageInfo), 0, sizeof(ImageInfo));
+        if ((img != nullptr) && (container != nullptr)) {
+            container->Add(img);
+            img->SetVisible(false);
+        }
+    }
+    virtual ~ScreenBitmapListener()
+    {
+        if (info_.data != nullptr) {
+            ImageCacheFree(info_);
+        }
+    }
+    bool OnClick(UIView& view, const ClickEvent& event) override
+    {
+        if (img_ == nullptr) {
+            return false;
+        }
+        if (info_.data != nullptr) {
+            ImageCacheFree(info_);
+        }
+        if (!Screen::GetInstance().GetCurrentScreenBitmap(info_)) {
+            return false;
+        }
+        img_->SetVisible(true);
+        img_->SetSrc(&info_);
+        img_->Invalidate();
+        return false;
+    }
+
+    UIViewGroup* container_;
+    UIImageView* img_;
+    ImageInfo info_;
+};
+
+void UITestViewBitmap::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        container_->SetHorizontalScrollState(false);
+    }
+    if (viewBitmap_ == nullptr) {
+        viewBitmap_ = new UIImageView();
+        // 500 : x pos of image; 50: y pos of image; 960 width of image; 480 : height of image.
+        viewBitmap_->SetPosition(500, 50, 960, 480);
+    }
+    if (screenBitmap_ == nullptr) {
+        screenBitmap_ = new UIImageView();
+        // 0 : x pos of image; 210: y pos of image; 960 width of image; 480 : height of image.
+        screenBitmap_->SetPosition(0, 210, 960, 480);
+    }
+    if (viewBitmapListener_ == nullptr) {
+        viewBitmapListener_ = new ViewBitmapListener(container_, viewBitmap_);
+    }
+    if (screenBitmapListener_ == nullptr) {
+        screenBitmapListener_ = new ScreenBitmapListener(container_, screenBitmap_);
+    }
+}
+
+void UITestViewBitmap::TearDown()
+{
+    if (viewBitmapListener_ != nullptr) {
+        delete viewBitmapListener_;
+        viewBitmapListener_ = nullptr;
+    }
+    if (screenBitmapListener_ != nullptr) {
+        delete screenBitmapListener_;
+        screenBitmapListener_ = nullptr;
+    }
+    DeleteChildren(container_);
+    container_ = nullptr;
+
+    viewBitmap_ = nullptr;
+    screenBitmap_ = nullptr;
+}
+
+const UIView* UITestViewBitmap::GetTestView()
+{
+    UIKitBitmapTestGetViewBitmap001();
+    UIKitBitmapTestGetScreenBitmap001();
+    return container_;
+}
+
+void UITestViewBitmap::UIKitBitmapTestGetViewBitmap001()
+{
+    UILabelButton* btn = new UILabelButton();
+    container_->Add(btn);
+    // 100 : x pos of button; 50: y pos of  button.
+    btn->SetPosition(bitmap_positionX_, bitmap_positionY_, BUTTON_WIDHT3, BUTTON_HEIGHT3);
+    btn->SetText("测试组件截屏");
+    btn->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
+    btn->SetOnClickListener(viewBitmapListener_);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+}
+
+void UITestViewBitmap::UIKitBitmapTestGetScreenBitmap001()
+{
+    UILabelButton* btn = new UILabelButton();
+    container_->Add(btn);
+    // 100 : x pos of button; 150: y pos of  button.
+    btn->SetPosition(bitmap_positionX_, bitmap_positionY_ + offsetY, BUTTON_WIDHT3, BUTTON_HEIGHT3);
+    btn->SetText("测试全屏截屏");
+    btn->SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
+    btn->SetOnClickListener(screenBitmapListener_);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+    btn->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+}
+} // namespace OHOS
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bitmap/ui_test_view_bitmap.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bitmap/ui_test_view_bitmap.h
new file mode 100644 (file)
index 0000000..3592114
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_VIEW_BITMAP_H
+#define UI_TEST_VIEW_BITMAP_H
+
+#include "components/ui_image_view.h"
+#include "components/ui_scroll_view.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestViewBitmap : public UITest {
+public:
+    UITestViewBitmap() {}
+    ~UITestViewBitmap() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    void UIKitBitmapTestGetViewBitmap001();
+    void UIKitBitmapTestGetScreenBitmap001();
+private:
+    UIScrollView* container_ = nullptr;
+    UIImageView* viewBitmap_ = nullptr;
+    UIImageView* screenBitmap_ = nullptr;
+    UIView::OnClickListener* viewBitmapListener_ = nullptr;
+    UIView::OnClickListener* screenBitmapListener_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_VIEW_BITMAP_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bounds/test_resource_config.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bounds/test_resource_config.h
new file mode 100644 (file)
index 0000000..f899a88
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+ 
+#ifndef TEST_RESOURCE_CONFIG_H
+#define TEST_RESOURCE_CONFIG_H
+ 
+namespace OHOS {
+#if defined QT_COMPILER
+#define IMAGE_DIR "..\\..\\simulator\\config\\images\\"
+#define FACE_DIR "..\\..\\simulator\\config\\faces\\default\\"
+#elif defined _WIN32
+#define IMAGE_DIR "..\\config\\images\\"
+#define FACE_DIR "..\\config\\faces\\default\\"
+#else
+#define IMAGE_DIR RES_PATH
+#define FACE_DIR RES_PATH
+#endif
+ 
+#define BLUE_RGB888_IMAGE_PATH (IMAGE_DIR "blue_rgb888.bin")
+#define BLUE_ARGB8888_IMAGE_PATH (IMAGE_DIR "blue_argb8888.bin")
+#define BLUE_RGB565_IMAGE_PATH (IMAGE_DIR "blue_rgb565.bin")
+#define BLUE_IMAGE_PATH (IMAGE_DIR "blue.png")
+#define RED_IMAGE_PATH (IMAGE_DIR "red.png")
+#define GREEN_IMAGE_PATH (IMAGE_DIR "green.png")
+#define YELLOW_IMAGE_PATH (IMAGE_DIR "yellow.png")
+#define IMAGE_ANIMATOR_0_PATH (IMAGE_DIR "image_animator_0.bin")
+#define IMAGE_ANIMATOR_1_PATH (IMAGE_DIR "image_animator_1.bin")
+#define IMAGE_ANIMATOR_2_PATH (IMAGE_DIR "image_animator_2.bin")
+#define IMAGE_ANIMATOR_3_PATH (IMAGE_DIR "image_animator_3.bin")
+#define B024_002_IMAGE_PATH (FACE_DIR "B024_002.bin")
+#define B024_009_IMAGE_PATH (FACE_DIR "B024_009.bin")
+#define B024_010_IMAGE_PATH (FACE_DIR "B024_010.bin")
+#define B024_011_IMAGE_PATH (FACE_DIR "B024_011.bin")
+#define SLIDER_BACKGROUND_IMAGE_PATH (IMAGE_DIR "sliderBackground.bin")
+#define SLIDER_INDICATOR_IMAGE_PATH (IMAGE_DIR "sliderIndicator.bin")
+#define SLIDER_KNOB_IMAGE_PATH (IMAGE_DIR "sliderKnob.bin")
+#define JPEG_IMAGE_PATH (IMAGE_DIR "jpeg.jpg")
+#define PNG_1_PALETTE_IMAGE_PATH (IMAGE_DIR "png_1_palette.png")
+#define PNG_2_PALETTE_IMAGE_PATH (IMAGE_DIR "png_2_palette.png")
+#define PNG_4_PALETTE_IMAGE_PATH (IMAGE_DIR "png_4_palette.png")
+#define PNG_8_PALETTE_IMAGE_PATH (IMAGE_DIR "png_8_palette.png")
+#define PNG_8_GRAY_IMAGE_PATH (IMAGE_DIR "png_8_gray.png")
+#define PNG_16_GRAY_IMAGE_PATH (IMAGE_DIR "png_16_gray.png")
+#define PNG_24_RGB_IMAGE_PATH (IMAGE_DIR "png_24_rgb.png")
+#define PNG_32_RGB_ALPHA_IMAGE_PATH (IMAGE_DIR "png_32_rgba.png")
+#ifndef VERSION_LITE
+#define GIF_IMAGE_PATH1 (IMAGE_DIR "gif_image1.gif")
+#define GIF_IMAGE_PATH2 (IMAGE_DIR "gif_image2.gif")
+#define GIF_IMAGE_PATH_ERROR (IMAGE_DIR "gif_error.gif")
+#define TIF_IMAGE_PATH (IMAGE_DIR "tif_image.tif")
+#endif
+#define VIDEO_SOURCE_DIRECTORY (IMAGE_DIR "video.mp4")
+#define TEST_RIGHT_ARROW (IMAGE_DIR "ic_arrow_right.png")
+#define TEST_BACK_LEFT_ARROW (IMAGE_DIR "ic_back.png")
+#define TEST_CIRCLE_FORE_IMAGE (FACE_DIR "fore.png")
+} // namespace OHOS
+#endif // TEST_RESOURCE_CONFIG_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bounds/ui_test_view_bounds.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bounds/ui_test_view_bounds.cpp
new file mode 100644 (file)
index 0000000..f9d0db0
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_view_bounds.h"
+
+#if ENABLE_DEBUG
+#include "common/screen.h"
+#include "components/root_view.h"
+#include "components/ui_button.h"
+#include "components/ui_checkbox.h"
+#include "components/ui_digital_clock.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_radio_button.h"
+#include "components/ui_toggle_button.h"
+#include "font/ui_font.h"
+#include "test_resource_config.h"
+
+#include "dfx/ui_view_bounds.h"
+
+const uint16_t offsetx_ = 13;
+const uint16_t offsety_ = 30;
+const uint16_t bound_positionY_ = 50;
+const uint16_t bound_positionW_ = 400;
+const uint16_t bound_positionH_ = 50;
+const uint16_t screenH_ = 150;
+const uint16_t width = 40;
+const uint16_t height = 40;
+const uint16_t offset = 5;
+namespace OHOS {
+UITestViewBounds::~UITestViewBounds()
+{
+    if (viewBoundsChangeListener_ != nullptr) {
+        delete viewBoundsChangeListener_;
+        viewBoundsChangeListener_ = nullptr;
+    }
+}
+void UITestViewBounds::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+        container_->SetHorizontalScrollState(false);
+        container_->SetThrowDrag(true);
+    }
+}
+
+void UITestViewBounds::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+}
+
+const UIView* UITestViewBounds::GetTestView()
+{
+    UIKitViewBoundsSetState001();
+    UIKitViewBoundsMargin001();
+    UIKitViewBoundsPadding001();
+    UIKitViewBoundsBorder001();
+    UIKitViewBounds001();
+    UIKitViewBoundsInvisible001();
+    UIKitViewBoundsSmallView001();
+    return container_;
+}
+
+class ViewBoundsChangeListener : public UIToggleButton::OnChangeListener {
+public:
+    ViewBoundsChangeListener() {}
+    ~ViewBoundsChangeListener() {}
+
+    bool OnChange(UICheckBox::UICheckBoxState state) override
+    {
+        switch (state) {
+            case UICheckBox::SELECTED:
+                UIViewBounds::GetInstance()->SetShowState(true);
+                break;
+
+            case UICheckBox::UNSELECTED:
+                UIViewBounds::GetInstance()->SetShowState(false);
+                break;
+            default:
+                break;
+        }
+        return true;
+    }
+};
+
+UILabel* UITestViewBounds::CreateTitleLabel() const
+{
+    UILabel* label = new UILabel();
+    label->SetHeight(TITLE_LABEL_DEFAULT_HEIGHT);
+    label->SetLineBreakMode(UILabel::LINE_BREAK_STRETCH);
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE + offsetx_, TEXT_DISTANCE_TO_TOP_SIDE + offsety_);
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    return label;
+}
+
+void UITestViewBounds::UIKitViewBoundsSetState001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UIViewGroup* group1 = new UIViewGroup();
+    container_->Add(group1);
+    UILabel* title1 = CreateTitleLabel();
+    group1->Add(title1);
+
+    UIViewGroup* group = new UIViewGroup();
+    container_->Add(group);
+    group->SetViewId("UIKitViewBoundsSetState001");
+    group->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE + offsetx_, bound_positionY_, bound_positionW_, bound_positionH_);
+    UILabel* viewBoundsLabel = new UILabel();
+    group->Add(viewBoundsLabel);
+    viewBoundsLabel->SetHeight(30); // 30: height
+    viewBoundsLabel->LayoutCenterOfParent();
+    viewBoundsLabel->LayoutLeftOfParent(offset); // 5: offset
+    viewBoundsLabel->SetLineBreakMode(UILabel::LINE_BREAK_STRETCH);
+    viewBoundsLabel->SetText("Show View Bounds: ");
+
+    UIToggleButton* toggle = new UIToggleButton();
+    group->Add(toggle);
+    toggle->SetWidth(width);  // 50: width
+    toggle->SetHeight(width); // 50: height
+    toggle->LayoutCenterOfParent();
+    toggle->LayoutRightOfParent(offset); // 5: offset
+    if (viewBoundsChangeListener_ != nullptr) {
+        delete viewBoundsChangeListener_;
+    }
+    viewBoundsChangeListener_ = new ViewBoundsChangeListener();
+    toggle->SetOnChangeListener(viewBoundsChangeListener_);
+    if (UIViewBounds::GetInstance()->GetShowState()) {
+        toggle->SetState(true);
+    } else {
+        toggle->SetState(false);
+    }
+}
+
+void UITestViewBounds::UIKitViewBoundsMargin001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UIViewGroup* group = new UIViewGroup();
+    container_->Add(group);
+    group->Resize(Screen::GetInstance().GetWidth(), screenH_); // 150: height
+    group->SetViewId("UIKitViewBoundsMargin001");
+    group->LayoutBottomToSibling("UIKitViewBoundsSetState001");
+
+    UILabel* title = CreateTitleLabel();
+    group->Add(title);
+    title->SetText("Test View bounds with margin: ");
+    title->SetViewId("margin_title");
+
+    UIView* view1 = new UIView();
+    group->Add(view1);
+    view1->Resize(width, width);                            // 50: view size
+    view1->LayoutBottomToSibling("margin_title", 10); // 10: offset
+    view1->AlignLeftToSibling("margin_title");
+    view1->SetStyle(STYLE_BACKGROUND_COLOR, Color::Gray().full);
+    view1->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    view1->SetStyle(STYLE_MARGIN_LEFT, 50); // 50: margin size
+}
+
+void UITestViewBounds::UIKitViewBoundsPadding001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UIViewGroup* group = new UIViewGroup();
+    container_->Add(group);
+    group->Resize(Screen::GetInstance().GetWidth(), screenH_); // 150: height
+    group->SetViewId("UIKitViewBoundsPadding001");
+    group->LayoutBottomToSibling("UIKitViewBoundsMargin001");
+
+    UILabel* title = CreateTitleLabel();
+    group->Add(title);
+    title->SetText("Test View bounds with padding: ");
+    title->SetViewId("padding_title");
+
+    UIView* view1 = new UIView();
+    group->Add(view1);
+    view1->Resize(width, width);                             // 50: view width and height
+    view1->LayoutBottomToSibling("padding_title", 10); // 10: offset
+    view1->AlignLeftToSibling("padding_title");
+    view1->SetStyle(STYLE_BACKGROUND_COLOR, Color::Gray().full);
+    view1->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    view1->SetStyle(STYLE_PADDING_LEFT, 50); // 50: padding size
+}
+
+void UITestViewBounds::UIKitViewBoundsBorder001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UIViewGroup* group = new UIViewGroup();
+    container_->Add(group);
+    group->Resize(Screen::GetInstance().GetWidth(), screenH_); // 150: height
+    group->SetViewId("UIKitViewBoundsBorder001");
+    group->LayoutBottomToSibling("UIKitViewBoundsPadding001");
+
+    UILabel* title = CreateTitleLabel();
+    group->Add(title);
+    title->SetText("Test View bounds with border:");
+    title->SetViewId("border_title");
+
+    UIView* view1 = new UIView();
+    group->Add(view1);
+    view1->Resize(width, width);                            // 50: view size
+    view1->LayoutBottomToSibling("border_title", 10); // 10: offset
+    view1->AlignLeftToSibling("border_title");
+    view1->SetStyle(STYLE_BACKGROUND_COLOR, Color::Gray().full);
+    view1->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    view1->SetStyle(STYLE_BORDER_COLOR, Color::Red().full);
+    view1->SetStyle(STYLE_BORDER_OPA, OPA_OPAQUE);
+    view1->SetStyle(STYLE_BORDER_WIDTH, 20); // 20: border size
+}
+
+void UITestViewBounds::UIKitViewBounds001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UIViewGroup* group = new UIViewGroup();
+    container_->Add(group);
+    group->Resize(Screen::GetInstance().GetWidth(), screenH_); // 150: height
+    group->SetViewId("UIKitViewBounds001");
+    group->LayoutBottomToSibling("UIKitViewBoundsBorder001");
+
+    UILabel* title = CreateTitleLabel();
+    group->Add(title);
+    title->SetText("Test View bounds with margin/padding/border:");
+    title->SetViewId("margin_padding_border_title");
+
+    UIView* view1 = new UIView();
+    group->Add(view1);
+    view1->Resize(width, width);                                           // 50: view size
+    view1->LayoutBottomToSibling("margin_padding_border_title", 10); // 10: offset
+    view1->AlignLeftToSibling("margin_padding_border_title");
+    view1->SetStyle(STYLE_BACKGROUND_COLOR, Color::Gray().full);
+    view1->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    view1->SetStyle(STYLE_BORDER_COLOR, Color::Yellow().full);
+    view1->SetStyle(STYLE_BORDER_OPA, OPA_OPAQUE);
+    view1->SetStyle(STYLE_BORDER_WIDTH, 20); // 20: border size
+    view1->SetStyle(STYLE_MARGIN_LEFT, 20);  // 20: margin size
+    view1->SetStyle(STYLE_PADDING_LEFT, 50); // 50: padding size
+}
+
+void UITestViewBounds::UIKitViewBoundsInvisible001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UIViewGroup* group = new UIViewGroup();
+    container_->Add(group);
+    group->Resize(Screen::GetInstance().GetWidth(), screenH_); // 150: height
+    group->SetViewId("UIKitViewBoundsInvisible001");
+    group->LayoutBottomToSibling("UIKitViewBounds001");
+
+    UILabel* title = CreateTitleLabel();
+    group->Add(title);
+    title->SetText("Test View bounds when view is invisible: ");
+    title->SetViewId("invisible_title");
+
+    UIView* view1 = new UIView();
+    group->Add(view1);
+    view1->Resize(width, width);                               // 50: view size
+    view1->LayoutBottomToSibling("invisible_title", 10); // 10: offset
+    view1->AlignLeftToSibling("invisible_title");
+    view1->SetStyle(STYLE_BACKGROUND_COLOR, Color::Gray().full);
+    view1->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    view1->SetStyle(STYLE_MARGIN_LEFT, 20); // 20: margin size
+    view1->SetVisible(false);
+}
+
+void UITestViewBounds::UIKitViewBoundsSmallView001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+    UIViewGroup* group = new UIViewGroup();
+    container_->Add(group);
+    group->Resize(Screen::GetInstance().GetWidth(), screenH_); // 150: height
+    group->SetViewId("UIKitViewBoundsSmallView001");
+    group->LayoutBottomToSibling("UIKitViewBoundsInvisible001");
+
+    UILabel* title = CreateTitleLabel();
+    group->Add(title);
+    title->SetText("Test View bounds when view is small: ");
+    title->SetViewId("small_title");
+
+    UIView* view1 = new UIView();
+    group->Add(view1);
+    view1->Resize(10, 10);                           // 10: view size
+    view1->LayoutBottomToSibling("small_title", 10); // 10: offset
+    view1->AlignLeftToSibling("small_title");
+    view1->SetStyle(STYLE_BACKGROUND_COLOR, Color::Gray().full);
+    view1->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+}
+
+void UITestViewBounds::UIKitViewBoundsPostDraw001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = new UIViewGroup();
+    container_->Add(group);
+    group->Resize(Screen::GetInstance().GetWidth(), screenH_); // 150: height
+    group->SetViewId("UIKitViewBoundsPostDraw001");
+    group->LayoutBottomToSibling("UIKitViewBoundsSmallView001");
+
+    UILabel* title = CreateTitleLabel();
+    group->Add(title);
+    title->SetText("Test View bounds when child view override OnPostDraw: ");
+    title->SetViewId("postdraw_title");
+
+    UIView* view1 = new UIView();
+    group->Add(view1);
+    view1->Resize(10, 10);                           // 10: view size
+    view1->LayoutBottomToSibling("small_title", 10); // 10: offset
+    view1->AlignLeftToSibling("small_title");
+    view1->SetStyle(STYLE_BACKGROUND_COLOR, Color::Gray().full);
+    view1->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+}
+} // namespace OHOS
+#endif
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bounds/ui_test_view_bounds.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_bounds/ui_test_view_bounds.h
new file mode 100644 (file)
index 0000000..e707ebc
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_VIEW_BOUNDS_H
+#define UI_TEST_VIEW_BOUNDS_H
+
+#include "graphic_config.h"
+
+#if ENABLE_DEBUG
+#include "components/ui_scroll_view.h"
+#include "components/ui_toggle_button.h"
+#include "components/ui_label.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestViewBounds : public UITest {
+public:
+    UITestViewBounds() {}
+    ~UITestViewBounds();
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+
+    /**
+     * @brief test show or hide view bounds
+     *
+     */
+    void UIKitViewBoundsSetState001();
+
+    /**
+     * @brief test view bounds with margin
+     *
+     */
+    void UIKitViewBoundsMargin001();
+
+    /**
+     * @brief test view bounds with padding
+     *
+     */
+    void UIKitViewBoundsPadding001();
+
+    /**
+     * @brief test view bounds with border
+     *
+     */
+    void UIKitViewBoundsBorder001();
+
+    /**
+     * @brief test view bounds with margin/padding/border
+     *
+     */
+    void UIKitViewBounds001();
+
+    /**
+     * @brief test small view which width or height small than 20px
+     *
+     */
+    void UIKitViewBoundsSmallView001();
+
+    /**
+     * @brief test view which is invisible
+     *
+     */
+    void UIKitViewBoundsInvisible001();
+
+    /**
+     * @brief test child view override OnPostDraw
+     *
+     */
+    void UIKitViewBoundsPostDraw001();
+
+private:
+    UILabel* CreateTitleLabel() const;
+    UIScrollView* container_ = nullptr;
+    UICheckBox::OnChangeListener* viewBoundsChangeListener_ = nullptr;
+};
+} // namespace OHOS
+#endif // ENABLE_DEBUG
+#endif // UI_TEST_VIEW_BOUNDS_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_group/ui_test_view_group.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_group/ui_test_view_group.cpp
new file mode 100644 (file)
index 0000000..00ad7b0
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_view_group.h"
+
+#include "common/screen.h"
+
+namespace OHOS {
+void UITestViewGroup::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+    }
+}
+
+void UITestViewGroup::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+}
+
+const UIView* UITestViewGroup::GetTestView()
+{
+    UIKitViewGroupTestAddRemove001();
+    UIKitViewGroupTestAddError001();
+    UIKitViewGroupTestInsertError001();
+    return container_;
+}
+
+UIViewGroup* UITestViewGroup::CreateTestCaseGroup() const
+{
+    UIViewGroup* group = new UIViewGroup();
+    group->Resize(Screen::GetInstance().GetWidth(), 200); // 200: height
+    return group;
+}
+
+UILabel* UITestViewGroup::CreateTitleLabel() const
+{
+    UILabel* label = new UILabel();
+    // 300: label width
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE, TEXT_DISTANCE_TO_TOP_SIDE, 300, TITLE_LABEL_DEFAULT_HEIGHT);
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+
+    return label;
+}
+
+UILabelButton* UITestViewGroup::CreateButton(std::string text, int16_t width, int16_t height) const
+{
+    UILabelButton* button = new UILabelButton();
+    button->Resize(width, height);
+    button->SetText(text.c_str());
+    button->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    button->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+    button->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+    button->SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_PRESS, UIButton::PRESSED);
+
+    return button;
+}
+
+void UITestViewGroup::UIKitViewGroupTestAddRemove001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->Resize(Screen::GetInstance().GetWidth(), 250);   // 250:height
+    group->SetViewId("UIKitViewGroupTestAddRemove001");
+    group->SetPosition(0, 0);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    label->SetText("UIViewGroup 添加/删除组件:");
+    label->SetViewId("label_text");
+    label->LayoutLeftOfParent(80);  // 80: offset
+    label->LayoutTopOfParent(50);  // 50: offset
+
+    removeBtn_ = CreateButton("删除View", 150, 40); // 150: width 40:height
+    group->Add(removeBtn_);
+    removeBtn_->SetOnClickListener(this);
+    removeBtn_->SetViewId("removeBtn");
+    removeBtn_->LayoutBottomOfParent();
+    removeBtn_->LayoutLeftOfParent(50); // 50: offset
+    
+    addBtn_ = CreateButton("添加View", 150, 40); // 150: width 40:height
+    group->Add(addBtn_);
+    addBtn_->SetOnClickListener(this);
+    addBtn_->SetViewId("addBtn");
+    addBtn_->LayoutBottomOfParent();
+    addBtn_->LayoutLeftOfParent(50);     // 50: offset
+    addBtn_->LayoutTopToSibling("removeBtn", 10); // 10: offset
+
+    removeAddBtn_ = CreateButton("删除再添加View", 160, 40); // 160: width 40:height
+    group->Add(removeAddBtn_);
+    removeAddBtn_->SetOnClickListener(this);
+    removeAddBtn_->SetViewId("removeAddBtn");
+    removeAddBtn_->LayoutBottomOfParent();
+    removeAddBtn_->LayoutRightToSibling("removeBtn", 0); // 10: offset
+
+    container_->Add(group);
+}
+
+void UITestViewGroup::UIKitViewGroupTestAddError001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKitViewGroupTestAddError001");
+    container_->Add(group);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    // 2: half of screen width
+    label->Resize(Screen::GetInstance().GetWidth() / 2, TITLE_LABEL_DEFAULT_HEIGHT);
+    label->SetText("测试重复添加子组件问题:");
+
+    addTwiceBtn_ = CreateButton("重复add", 150, 40); // 150: width 40:height
+    group->Add(addTwiceBtn_);
+    addTwiceBtn_->SetViewId("addTwiceBtn");
+    addTwiceBtn_->SetOnClickListener(this);
+    addTwiceBtn_->LayoutCenterOfParent();
+    addTwiceBtn_->LayoutLeftOfParent(30); // 30: offset
+
+    addMultiParentBtn_ = CreateButton("add到不同父节点", 200, 40); // 200: width 40:height
+    group->Add(addMultiParentBtn_);
+    addMultiParentBtn_->SetViewId("addMultiParentBtn");
+    addMultiParentBtn_->SetOnClickListener(this);
+    addMultiParentBtn_->LayoutCenterOfParent();
+    addMultiParentBtn_->LayoutRightToSibling("addTwiceBtn", 10); // 10: offset
+
+    addSelfBtn_ = CreateButton("add到自己", 150, 40); // 150: width 40:height
+    group->Add(addSelfBtn_);
+    addSelfBtn_->SetViewId("addSelfBtn");
+    addSelfBtn_->SetOnClickListener(this);
+    addSelfBtn_->LayoutCenterOfParent();
+    addSelfBtn_->LayoutBottomToSibling("addTwiceBtn", 10); // 10: offset
+
+    group->LayoutBottomToSibling("UIKitViewGroupTestAddRemove001", 10); // 10: offset
+}
+
+void UITestViewGroup::UIKitViewGroupTestInsertError001()
+{
+    if (container_ == nullptr) {
+        return;
+    }
+
+    UIViewGroup* group = CreateTestCaseGroup();
+    group->SetViewId("UIKitViewGroupTestInsertError001");
+    container_->Add(group);
+
+    UILabel* label = CreateTitleLabel();
+    group->Add(label);
+    // 2: half of screen width
+    label->Resize(Screen::GetInstance().GetWidth() / 2, TITLE_LABEL_DEFAULT_HEIGHT);
+    label->SetText("测试Insert子组件问题:");
+
+    insertTwiceBtn_ = CreateButton("重复insert", 150, 40); // 150: width 40:height
+    group->Add(insertTwiceBtn_);
+    insertTwiceBtn_->SetViewId("insertTwiceBtn");
+    insertTwiceBtn_->SetOnClickListener(this);
+    insertTwiceBtn_->LayoutCenterOfParent();
+    insertTwiceBtn_->LayoutLeftOfParent(30); // 30: offset
+
+    insertMultiParentBtn_ = CreateButton("insert到不同父节点", 200, 40); // 200: width 40:height
+    group->Add(insertMultiParentBtn_);
+    insertMultiParentBtn_->SetViewId("insertMultiParentBtn");
+    insertMultiParentBtn_->SetOnClickListener(this);
+    insertMultiParentBtn_->LayoutCenterOfParent();
+    insertMultiParentBtn_->LayoutRightToSibling("insertTwiceBtn", 10); // 10: offset
+
+    insertSelfBtn_ = CreateButton("insert到自己", 150, 40); // 150: width 40:height
+    group->Add(insertSelfBtn_);
+    insertSelfBtn_->SetViewId("addSelfBtn");
+    insertSelfBtn_->SetOnClickListener(this);
+    insertSelfBtn_->LayoutCenterOfParent();
+    insertSelfBtn_->LayoutBottomToSibling("insertTwiceBtn", 10); // 10: offset
+
+    group->LayoutBottomToSibling("UIKitViewGroupTestAddError001", 10); // 10: offset
+}
+
+bool UITestViewGroup::OnClick(UIView& view, const ClickEvent& event)
+{
+    if (&view == addBtn_) {
+        AddView();
+    } else if (&view == removeBtn_) {
+        RemoveView();
+    } else if (&view == removeAddBtn_) {
+        RemoveAndAddView();
+    } else if (&view == addTwiceBtn_) {
+        UIView* view = new UIView();
+        container_->Add(view);
+        container_->Add(view);
+    } else if (&view == addMultiParentBtn_) {
+        AddMultiParent();
+    } else if (&view == addSelfBtn_) {
+        container_->Add(container_);
+    } else if (&view == insertTwiceBtn_) {
+        UIView* view = new UIView();
+        container_->Insert(nullptr, view);
+        container_->Insert(nullptr, view);
+    } else if (&view == insertMultiParentBtn_) {
+        InsertMultiParent();
+    } else if (&view == insertSelfBtn_) {
+        container_->Insert(nullptr, container_);
+    }
+    return true;
+}
+
+void UITestViewGroup::AddView()
+{
+    UIView* view = new UIView();
+    view->Resize(200, 50);  // 200 : width , 50 height
+    view->SetPosition(90, 90);  // 90 : Coordinates of the top left corner of the circle
+    ColorType color = Color::GetColorFromRGB(std::rand() % 256, std::rand() % 256, std::rand() % 256);
+    view->SetStyle(STYLE_BACKGROUND_COLOR, color.full);
+    view->SetViewId("id_view1");
+    UIViewGroup* vg = static_cast<UIViewGroup*>(container_->GetChildById("UIKitViewGroupTestAddRemove001"));
+    if (vg != nullptr) {
+        vg->Add(view);
+        vg->Invalidate();
+    }
+}
+
+void UITestViewGroup::RemoveView()
+{
+    UIViewGroup* vg = static_cast<UIViewGroup*>(container_->GetChildById("UIKitViewGroupTestAddRemove001"));
+    UIView* view1 = container_->GetChildById("id_view1");
+    if ((vg != nullptr) && (view1 != nullptr)) {
+        vg->Remove(view1);
+        vg->Invalidate();
+    }
+}
+
+void UITestViewGroup::RemoveAndAddView()
+{
+    UIViewGroup* vg = static_cast<UIViewGroup*>(container_->GetChildById("UIKitViewGroupTestAddRemove001"));
+    UIView* view1 = container_->GetChildById("id_view1");
+    if ((vg != nullptr) && (view1 != nullptr)) {
+        vg->Remove(view1);
+        vg->Add(view1);
+        vg->Invalidate();
+    }
+}
+
+void UITestViewGroup::AddMultiParent()
+{
+    UIView* view = new UIView();
+    UIViewGroup* vg = static_cast<UIViewGroup*>(container_->GetChildById("UIKitViewGroupTestAddError001"));
+    if ((vg != nullptr) && (view != nullptr)) {
+        vg->Add(view);
+    }
+    container_->Add(view);
+}
+
+void UITestViewGroup::InsertMultiParent()
+{
+    UIView* view = new UIView();
+    UIViewGroup* vg = static_cast<UIViewGroup*>(container_->GetChildById("UIKitViewGroupTestInsertError001"));
+    if ((vg != nullptr) && (view != nullptr)) {
+        vg->Insert(nullptr, view);
+    }
+    container_->Insert(nullptr, view);
+}
+} // namespace OHOS
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_group/ui_test_view_group.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_group/ui_test_view_group.h
new file mode 100644 (file)
index 0000000..8ab3a22
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: Lottie
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_VIEW_GROUP_H
+#define UI_TEST_VIEW_GROUP_H
+
+#include <cstdlib>
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "components/ui_view_group.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestViewGroup : public UITest, public UIView::OnClickListener {
+public:
+    UITestViewGroup() : container_(nullptr) {}
+    ~UITestViewGroup() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    bool OnClick(UIView& view, const ClickEvent& event) override;
+
+    /**
+     * @brief Test Add/Rmove Function
+     */
+    void UIKitViewGroupTestAddRemove001();
+
+    /**
+     * @brief Test add child multi time
+     */
+    void UIKitViewGroupTestAddError001();
+
+    /**
+     * @brief Test insert child multi time
+     */
+    void UIKitViewGroupTestInsertError001();
+
+private:
+    UIViewGroup* CreateTestCaseGroup() const;
+    UILabel* CreateTitleLabel() const;
+    UILabelButton* CreateButton(std::string text, int16_t width, int16_t height) const;
+    void AddView();
+    void RemoveView();
+    void RemoveAndAddView();
+    void AddMultiParent();
+    void InsertMultiParent();
+
+    UIScrollView* container_ = nullptr;
+    UILabelButton* addBtn_ = nullptr;
+    UILabelButton* removeBtn_ = nullptr;
+    UILabelButton* removeAddBtn_ = nullptr;
+    UILabelButton* addTwiceBtn_ = nullptr;
+    UILabelButton* addMultiParentBtn_ = nullptr;
+    UILabelButton* addSelfBtn_ = nullptr;
+    UILabelButton* insertTwiceBtn_ = nullptr;
+    UILabelButton* insertSelfBtn_ = nullptr;
+    UILabelButton* insertMultiParentBtn_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_VIEW_GROUP_H
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_percent/ui_test_view_percent.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_percent/ui_test_view_percent.cpp
new file mode 100644 (file)
index 0000000..9492d5c
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_view_percent.h"
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+#include "common/screen.h"
+#include "components/ui_label.h"
+#include "components/ui_label_button.h"
+#include "layout/grid_layout.h"
+
+namespace OHOS {
+namespace {
+    const uint16_t LABEL_HEIGHT = 60;
+    const uint16_t DEFAULT_WIDITH = 80;
+    const uint16_t DEFAULT_HEIGHT = 60;
+    const uint16_t DEFAULT_PERCENT = 10;
+    static int16_t g_widthpercent = DEFAULT_PERCENT;
+    const uint16_t MAX_PERCENT = 100;
+    const float DEFAULT_PERCENT_INTERVAL = 100.0f;
+    const int16_t TEXT_H = 30;
+    const int16_t GAP = 10;
+    static int16_t g_vieW1Widthpercent = DEFAULT_PERCENT;
+    static int16_t g_vieW1Heightpercent = DEFAULT_PERCENT;
+    static int16_t g_vieW2Widthpercent = DEFAULT_PERCENT;
+    static int16_t g_vieW2Heightpercent = DEFAULT_PERCENT;
+    const uint16_t OFFSETX = 80;
+    const uint16_t OFFSETY = 100;
+    const uint16_t OPTIONX = 20;
+    const uint16_t OFFSETW = 260;
+    const uint16_t HEIGHT = 60;
+    const uint16_t RADIUS = 5;
+}
+
+void UITestViewPercent::SetUp()
+{
+    if (container_ == nullptr) {
+        InitContainer();
+    }
+    viewGroup = new UIViewGroup();
+    view1_ = new UIButton();
+    view2_ = new UIView();
+    view3_ = new UIView();
+    resetfBtn_ = new UILabelButton();
+    BiggerBtn_ = new UILabelButton();
+    SmallerBtn_ = new UILabelButton();
+    positionX_ = 20; // default start x-coordinate as 20
+    positionY_ = RADIUS; // default start y-coordinate as 5
+}
+
+void UITestViewPercent::TearDown()
+{
+    DeleteChildren(container_);
+    container_ = nullptr;
+    g_widthpercent = DEFAULT_PERCENT;
+    g_vieW1Widthpercent = DEFAULT_PERCENT;
+    g_vieW1Heightpercent = DEFAULT_PERCENT;
+    g_vieW2Widthpercent = DEFAULT_PERCENT;
+    g_vieW2Heightpercent = DEFAULT_PERCENT;
+}
+
+const UIView* UITestViewPercent::GetTestView()
+{
+    InitView();
+    return container_;
+}
+
+void UITestViewPercent::InitContainer()
+{
+    container_ = new UIScrollView();
+    container_->SetThrowDrag(true);
+    container_->SetHorizontalScrollState(false);
+    container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+}
+
+void UITestViewPercent::InitView()
+{
+    if (container_ == nullptr) {
+        InitContainer();
+    }
+
+    UILabel* label1 = new UILabel();
+    container_->Add(label1);
+    positionY_ += (TEXT_H + GAP);
+    label1->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE + OFFSETX, positionY_ + OFFSETY,
+        Screen::GetInstance().GetWidth(), TITLE_LABEL_DEFAULT_HEIGHT);
+
+    UILabel* label = new UILabel();
+    container_->Add(label);
+    positionY_ += OFFSETY;
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE + OFFSETX, positionY_,
+        Screen::GetInstance().GetWidth(), TITLE_LABEL_DEFAULT_HEIGHT);
+    label->SetText("Flex布局效果 ");
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    positionY_ += (TEXT_H + GAP);
+
+    flexLayout_ = new FlexLayout();
+    container_->Add(flexLayout_);
+    InitFlexLayout();
+    positionY_ += flexLayout_->GetHeight() + GAP;
+
+    InitViewGroup();
+    positionY_ += viewGroup->GetHeight() + GAP;
+
+    GridLayout* gridLayout = new GridLayout();
+    container_->Add(gridLayout);
+    gridLayout->Resize(OFFSETW, HEIGHT); // 260: OFFSETX; 60: HEIGHT
+    gridLayout->SetLayoutDirection(LAYOUT_HOR);
+    gridLayout->SetPosition(OPTIONX, positionY_); // 260: OFFSETX; 60: HEIGHT
+    // 2: half of screen OFFSETX; 2: half of gridLayout
+    gridLayout->LayoutLeftOfParent(Screen::GetInstance().GetWidth() / 2 - gridLayout->GetWidth() / 2);
+    gridLayout->SetRows(1); // set gridlayout row as 1
+    gridLayout->SetCols(3); // set gridlayout column as 3
+
+    SetUpButton(*gridLayout, *resetfBtn_, "reset");
+    SetUpButton(*gridLayout, *BiggerBtn_, "Bigger");
+    SetUpButton(*gridLayout, *SmallerBtn_, "Smaller");
+    gridLayout->LayoutChildren(true);
+    container_->LayoutChildren(true);
+}
+
+void UITestViewPercent::InitFlexLayout()
+{
+    flexLayout_->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE  + OFFSETX, positionY_);
+    flexLayout_->SetWidthPercent(0.5f); // set default OFFSETX percent as 0.9
+    flexLayout_->SetHeightPercent(0.5f); // set default HEIGHT percent as 0.9
+    flexLayout_->SetStyle(STYLE_BORDER_COLOR, Color::White().full);
+    flexLayout_->SetStyle(STYLE_BORDER_OPA, HALF_OPA_OPAQUE);
+    flexLayout_->SetStyle(STYLE_BORDER_WIDTH, VIEW_STYLE_BORDER_WIDTH);
+    flexLayout_->SetStyle(STYLE_BORDER_RADIUS, VIEW_STYLE_BORDER_RADIUS);
+    flexLayout_->SetStyle(STYLE_BACKGROUND_OPA, 0);
+    for (int16_t i = 0; i < TEST_VP_LABEL_COUNT; i++) {
+        AddElement(i);
+    }
+    flexLayout_->SetFlexWrap(1);
+    flexLayout_->SetLayoutDirection(LAYOUT_HOR);
+    flexLayout_->SetMajorAxisAlign(ALIGN_START);
+    flexLayout_->SetSecondaryAxisAlign(ALIGN_CENTER);
+    flexLayout_->LayoutChildren();
+}
+
+void UITestViewPercent::InitViewGroup() const
+{
+    container_->Add(viewGroup);
+    viewGroup->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE + OFFSETX, positionY_);
+    viewGroup->SetWidthPercent(0.5f); // set default OFFSETX percent as 0.5
+    viewGroup->SetHeightPercent(0.5f); // set default HEIGHT percent as 0.5
+    viewGroup->SetStyle(STYLE_BORDER_COLOR, Color::White().full);
+    viewGroup->SetStyle(STYLE_BORDER_OPA, HALF_OPA_OPAQUE);
+    viewGroup->SetStyle(STYLE_BORDER_WIDTH, VIEW_STYLE_BORDER_WIDTH);
+    viewGroup->SetStyle(STYLE_BORDER_RADIUS, VIEW_STYLE_BORDER_RADIUS);
+    viewGroup->SetStyle(STYLE_BACKGROUND_OPA, 0);
+    viewGroup->Add(view1_);
+    view1_->SetViewId("view1");
+    view1_->SetPositionPercent(0.1, 0.1); // set view1 position percent x-percent=0.1, y-percent=0.1
+    view1_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Green().full);
+    view1_->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    view1_->SetStyle(STYLE_BORDER_COLOR, Color::Black().full);
+    view1_->SetStyle(STYLE_BORDER_OPA, OPA_OPAQUE);
+    view1_->SetStyle(STYLE_BORDER_WIDTH, 1); // set border OFFSETX 1
+    view1_->SetStyle(STYLE_BORDER_RADIUS, RADIUS); // set border RADIUS 5
+    view1_->SetHeightPercent(g_vieW1Widthpercent / DEFAULT_PERCENT_INTERVAL);
+    view1_->SetWidthPercent(g_vieW1Heightpercent / DEFAULT_PERCENT_INTERVAL);
+
+    viewGroup->Add(view2_);
+    view2_->SetViewId("view2");
+    view2_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Blue().full);
+    view2_->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    view2_->SetStyle(STYLE_BORDER_COLOR, Color::Blue().full);
+    view2_->SetStyle(STYLE_BORDER_OPA, OPA_OPAQUE);
+    view2_->SetStyle(STYLE_BORDER_WIDTH, 1); // set border OFFSETX 1
+    view2_->SetStyle(STYLE_BORDER_RADIUS, RADIUS);  // set border RADIUS 5
+    view2_->SetPositionPercent(
+        0.3, 0.1, /* set view2 position percent x-percent=0.3, y-percent=0.1 */
+        g_vieW2Widthpercent / DEFAULT_PERCENT_INTERVAL, g_vieW2Heightpercent / DEFAULT_PERCENT_INTERVAL);
+
+    viewGroup->Add(view3_);
+    view3_->SetViewId("view3");
+    view3_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    view3_->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    view3_->SetStyle(STYLE_BORDER_COLOR, Color::Red().full);
+    view3_->SetStyle(STYLE_BORDER_OPA, OPA_OPAQUE);
+    view3_->SetStyle(STYLE_BORDER_WIDTH, 1);  // set border OFFSETX 1
+    view3_->SetStyle(STYLE_BORDER_RADIUS, RADIUS);  // set border RADIUS 5
+    view3_->SetXPercent(0.5); // set view3 x-percent=0.5
+    view3_->SetYPercent(0.1); // set view3 , y-percent=0.1
+    view3_->SetWidthPercent(g_vieW2Widthpercent / DEFAULT_PERCENT_INTERVAL);
+    view3_->SetHeightPercent(g_vieW2Heightpercent / DEFAULT_PERCENT_INTERVAL);
+}
+
+void UITestViewPercent::AddElement(int16_t index)
+{
+    if (flexLayout_ == nullptr) {
+        InitView();
+    }
+
+    UILabel* label = new UILabel();
+    flexLayout_->Add(label);
+    float percent = DEFAULT_PERCENT / DEFAULT_PERCENT_INTERVAL;
+    label->SetWidthPercent(percent);
+    label->SetHeightPercent(percent);
+    label->SetText(std::to_string(index).c_str());
+    label->SetFont("HYQiHei-65S.otf", 20); // set default font size as 20
+    label->SetStyle(STYLE_TEXT_COLOR, Color::Black().full);
+    label->SetStyle(STYLE_BACKGROUND_COLOR, Color::White().full);
+    label->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    label->SetStyle(STYLE_BORDER_COLOR, Color::Black().full);
+    label->SetStyle(STYLE_BORDER_OPA, OPA_OPAQUE);
+    label->SetStyle(STYLE_BORDER_WIDTH, 1); // set border OFFSETX 1
+    label->SetStyle(STYLE_BORDER_RADIUS, RADIUS);  // set border RADIUS 5
+    label->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+    labels_[index] = label;
+}
+
+void UITestViewPercent::UpdateLabelsPercent()
+{
+    for (int i = 0; i < TEST_VP_LABEL_COUNT; i++) {
+        float percent = g_widthpercent / DEFAULT_PERCENT_INTERVAL;
+        labels_[i]->SetWidthPercent(percent);
+        labels_[i]->SetHeightPercent(percent);
+    }
+}
+
+bool UITestViewPercent::OnClick(UIView& view, const ClickEvent& event)
+{
+    if (&view == resetfBtn_) {
+        g_widthpercent = DEFAULT_PERCENT;
+        g_vieW1Heightpercent = DEFAULT_PERCENT;
+        g_vieW1Widthpercent = DEFAULT_PERCENT;
+        g_vieW2Heightpercent = DEFAULT_PERCENT;
+        g_vieW2Widthpercent = DEFAULT_PERCENT;
+        view1_->ResizePercent(g_vieW1Widthpercent / DEFAULT_PERCENT_INTERVAL,
+            g_vieW1Heightpercent / DEFAULT_PERCENT_INTERVAL);
+        view2_->ResizePercent(g_vieW2Widthpercent / DEFAULT_PERCENT_INTERVAL,
+            g_vieW2Heightpercent / DEFAULT_PERCENT_INTERVAL);
+        UpdateLabelsPercent();
+    } else if (&view == BiggerBtn_) {
+        if (g_widthpercent < DEFAULT_PERCENT) {
+            g_widthpercent++;
+            UpdateLabelsPercent();
+        }
+        g_vieW1Heightpercent++;
+        g_vieW1Widthpercent++;
+        g_vieW2Heightpercent++;
+        g_vieW2Widthpercent++;
+        view1_->ResizePercent(g_vieW1Widthpercent / DEFAULT_PERCENT_INTERVAL,
+            g_vieW1Heightpercent / DEFAULT_PERCENT_INTERVAL);
+        view2_->ResizePercent(g_vieW2Widthpercent / DEFAULT_PERCENT_INTERVAL,
+            g_vieW2Heightpercent / DEFAULT_PERCENT_INTERVAL);
+    } else if (&view == SmallerBtn_) {
+        g_vieW1Heightpercent--;
+        g_vieW1Widthpercent--;
+        g_vieW2Heightpercent--;
+        g_vieW2Widthpercent--;
+        view1_->ResizePercent(g_vieW1Widthpercent / DEFAULT_PERCENT_INTERVAL,
+            g_vieW1Heightpercent / DEFAULT_PERCENT_INTERVAL);
+        view2_->ResizePercent(g_vieW2Widthpercent / DEFAULT_PERCENT_INTERVAL,
+            g_vieW2Heightpercent / DEFAULT_PERCENT_INTERVAL);
+        if (g_widthpercent > 2) { // 2: min value
+            g_widthpercent--;
+            UpdateLabelsPercent();
+        }
+    }
+    container_->Invalidate();
+    return true;
+}
+}
+
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_percent/ui_test_view_percent.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_percent/ui_test_view_percent.h
new file mode 100644 (file)
index 0000000..6d6d08d
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_VIEW_PERCENT_H
+#define UI_TEST_VIEW_PERCENT_H
+
+#include <string>
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "components/ui_view.h"
+#include "components/ui_view_group.h"
+#include "graphic_config.h"
+#include "layout/flex_layout.h"
+#include "layout/layout.h"
+#include "ui_test.h"
+
+namespace OHOS {
+const int TEST_VP_LABEL_COUNT = 10;
+class UITestViewPercent : public UITest, public UIView::OnClickListener {
+public:
+    UITestViewPercent() {}
+    ~UITestViewPercent() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    bool OnClick(UIView& view, const ClickEvent& event) override;
+
+private:
+    void SetUpButton(Layout& controller, UILabelButton& btn, const std::string title)
+    {
+        controller.Add(&btn);
+        btn.Resize(BUTTON_WIDHT1, BUTTON_HEIGHT1);
+        btn.SetText(title.c_str());
+        btn.SetFont(DEFAULT_VECTOR_FONT_FILENAME, BUTTON_LABEL_SIZE);
+        btn.SetOnClickListener(this);
+        btn.SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::RELEASED);
+        btn.SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::PRESSED);
+        btn.SetStyleForState(STYLE_BORDER_RADIUS, BUTTON_STYLE_BORDER_RADIUS_VALUE, UIButton::INACTIVE);
+        btn.SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::RELEASED);
+        btn.SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::PRESSED);
+        btn.SetStyleForState(STYLE_BACKGROUND_COLOR, BUTTON_STYLE_BACKGROUND_COLOR_VALUE, UIButton::INACTIVE);
+    }
+    void InitView();
+    void InitFlexLayout();
+    void InitViewGroup() const;
+    void InitContainer();
+    void AddElement(int16_t index);
+    void UpdateLabelsPercent();
+    UIScrollView* container_ = nullptr;
+    FlexLayout* flexLayout_ = nullptr;
+    UIViewGroup* viewGroup = nullptr;
+    UIView* view1_ = nullptr;
+    UIView* view2_ = nullptr;
+    UIView* view3_ = nullptr;
+    UILabelButton* resetfBtn_ = nullptr;
+    UILabelButton* BiggerBtn_ = nullptr;
+    UILabelButton* SmallerBtn_ = nullptr;
+    UILabel* labels_[TEST_VP_LABEL_COUNT];
+};
+} // namespace OHOS
+#endif // UI_TEST_VIEW_PERCENT_H
+
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_scale_rotate/test_resource_config.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_scale_rotate/test_resource_config.h
new file mode 100644 (file)
index 0000000..f899a88
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+ 
+#ifndef TEST_RESOURCE_CONFIG_H
+#define TEST_RESOURCE_CONFIG_H
+ 
+namespace OHOS {
+#if defined QT_COMPILER
+#define IMAGE_DIR "..\\..\\simulator\\config\\images\\"
+#define FACE_DIR "..\\..\\simulator\\config\\faces\\default\\"
+#elif defined _WIN32
+#define IMAGE_DIR "..\\config\\images\\"
+#define FACE_DIR "..\\config\\faces\\default\\"
+#else
+#define IMAGE_DIR RES_PATH
+#define FACE_DIR RES_PATH
+#endif
+ 
+#define BLUE_RGB888_IMAGE_PATH (IMAGE_DIR "blue_rgb888.bin")
+#define BLUE_ARGB8888_IMAGE_PATH (IMAGE_DIR "blue_argb8888.bin")
+#define BLUE_RGB565_IMAGE_PATH (IMAGE_DIR "blue_rgb565.bin")
+#define BLUE_IMAGE_PATH (IMAGE_DIR "blue.png")
+#define RED_IMAGE_PATH (IMAGE_DIR "red.png")
+#define GREEN_IMAGE_PATH (IMAGE_DIR "green.png")
+#define YELLOW_IMAGE_PATH (IMAGE_DIR "yellow.png")
+#define IMAGE_ANIMATOR_0_PATH (IMAGE_DIR "image_animator_0.bin")
+#define IMAGE_ANIMATOR_1_PATH (IMAGE_DIR "image_animator_1.bin")
+#define IMAGE_ANIMATOR_2_PATH (IMAGE_DIR "image_animator_2.bin")
+#define IMAGE_ANIMATOR_3_PATH (IMAGE_DIR "image_animator_3.bin")
+#define B024_002_IMAGE_PATH (FACE_DIR "B024_002.bin")
+#define B024_009_IMAGE_PATH (FACE_DIR "B024_009.bin")
+#define B024_010_IMAGE_PATH (FACE_DIR "B024_010.bin")
+#define B024_011_IMAGE_PATH (FACE_DIR "B024_011.bin")
+#define SLIDER_BACKGROUND_IMAGE_PATH (IMAGE_DIR "sliderBackground.bin")
+#define SLIDER_INDICATOR_IMAGE_PATH (IMAGE_DIR "sliderIndicator.bin")
+#define SLIDER_KNOB_IMAGE_PATH (IMAGE_DIR "sliderKnob.bin")
+#define JPEG_IMAGE_PATH (IMAGE_DIR "jpeg.jpg")
+#define PNG_1_PALETTE_IMAGE_PATH (IMAGE_DIR "png_1_palette.png")
+#define PNG_2_PALETTE_IMAGE_PATH (IMAGE_DIR "png_2_palette.png")
+#define PNG_4_PALETTE_IMAGE_PATH (IMAGE_DIR "png_4_palette.png")
+#define PNG_8_PALETTE_IMAGE_PATH (IMAGE_DIR "png_8_palette.png")
+#define PNG_8_GRAY_IMAGE_PATH (IMAGE_DIR "png_8_gray.png")
+#define PNG_16_GRAY_IMAGE_PATH (IMAGE_DIR "png_16_gray.png")
+#define PNG_24_RGB_IMAGE_PATH (IMAGE_DIR "png_24_rgb.png")
+#define PNG_32_RGB_ALPHA_IMAGE_PATH (IMAGE_DIR "png_32_rgba.png")
+#ifndef VERSION_LITE
+#define GIF_IMAGE_PATH1 (IMAGE_DIR "gif_image1.gif")
+#define GIF_IMAGE_PATH2 (IMAGE_DIR "gif_image2.gif")
+#define GIF_IMAGE_PATH_ERROR (IMAGE_DIR "gif_error.gif")
+#define TIF_IMAGE_PATH (IMAGE_DIR "tif_image.tif")
+#endif
+#define VIDEO_SOURCE_DIRECTORY (IMAGE_DIR "video.mp4")
+#define TEST_RIGHT_ARROW (IMAGE_DIR "ic_arrow_right.png")
+#define TEST_BACK_LEFT_ARROW (IMAGE_DIR "ic_back.png")
+#define TEST_CIRCLE_FORE_IMAGE (FACE_DIR "fore.png")
+} // namespace OHOS
+#endif // TEST_RESOURCE_CONFIG_H
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_scale_rotate/ui_test_view_scale_rotate.cpp b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_scale_rotate/ui_test_view_scale_rotate.cpp
new file mode 100644 (file)
index 0000000..5863c77
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#include "ui_test_view_scale_rotate.h"
+#include "common/screen.h"
+#include "components/ui_label.h"
+#include "core/render_manager.h"
+#include "test_resource_config.h"
+
+const uint16_t rotate_positionx_ = 150;
+const uint16_t rotate_positiony_ = 50;
+const uint16_t rotate_positionw_ = 300;
+const uint16_t rotate_positionh_ = 200;
+const uint16_t rotatex_ = 20;
+const uint16_t rotatey_ = 10;
+const uint16_t rotatew_ = 50;
+const uint16_t rotateh_ = 150;
+const uint16_t offsetX = 150;
+const uint16_t offsetY = 150;
+const uint16_t offsetb = 100;
+namespace OHOS {
+void UITestViewScaleRotate::SetUp()
+{
+    if (container_ == nullptr) {
+        container_ = new UIScrollView();
+        container_->Resize(Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight() - BACK_BUTTON_HEIGHT);
+    }
+
+    if (list_ == nullptr) {
+        list_ = new ListLayout(UISwipeView::VERTICAL);
+        uint16_t width = Screen::GetInstance().GetWidth();
+        uint16_t height = Screen::GetInstance().GetHeight();
+        list_->SetPosition(VIEW_DISTANCE_TO_LEFT_SIDE, 0, width, height + 1);
+        container_->Add(list_);
+    }
+}
+
+void UITestViewScaleRotate::TearDown()
+{
+    animator_.Stop();
+    DeleteChildren(container_);
+    container_ = nullptr;
+    list_ = nullptr;
+}
+
+const UIView* UITestViewScaleRotate::GetTestView()
+{
+    UIKitViewScaleRotateTestLabel001();
+    UIKitViewScaleRotateTestLabelButton002();
+    UIKitViewScaleRotateTestCanvas003();
+    UIKitViewScaleRotateTestUIBoxProgress004();
+    UIKitViewScaleRotateTestUICircleProgress005();
+    UIKitViewScaleRotateTestUIDigitalClock006();
+    UIKitViewScaleRotateTestGroup007();
+
+    animator_.Start();
+    return container_;
+}
+
+void UITestViewScaleRotate::Callback(UIView* view)
+{
+    angleValue_++;
+
+    if (scaleValue_.x_ < 0.2f) {
+        scaleStep_ = 0.01f;
+    } else if (scaleValue_.x_ > 1.5f) {
+        scaleStep_ = -0.01f;
+    }
+    scaleValue_.x_ += scaleStep_;
+    scaleValue_.y_ += scaleStep_;
+
+    button1_->Rotate(angleValue_, VIEW_CENTER);
+    button1_->Scale(scaleValue_, VIEW_CENTER);
+    group1_->Rotate(angleValue_, GROUP_CENTER);
+    group1_->Scale(scaleValue_, GROUP_CENTER);
+    canvas_->Rotate(angleValue_, GROUP_CENTER);
+    canvas_->Scale(scaleValue_, GROUP_CENTER);
+    boxProgress_->Rotate(angleValue_, VIEW_CENTER);
+    boxProgress_->Scale(scaleValue_, VIEW_CENTER);
+    circleProgress_->Rotate(angleValue_, VIEW_CENTER);
+    circleProgress_->Scale(scaleValue_, VIEW_CENTER);
+    dClock_->Rotate(angleValue_, VIEW_CENTER);
+    dClock_->Scale(scaleValue_, VIEW_CENTER);
+    label_->Rotate(angleValue_, VIEW_CENTER);
+    label_->Scale(scaleValue_, VIEW_CENTER);
+}
+
+void UITestViewScaleRotate::SetUpLabel(const char* title) const
+{
+    UILabel* label = new UILabel();
+    label->SetPosition(TEXT_DISTANCE_TO_LEFT_SIDE + offsetX, TEXT_DISTANCE_TO_TOP_SIDE,
+        Screen::GetInstance().GetWidth(), TITLE_LABEL_DEFAULT_HEIGHT);
+    label->SetText(title);
+    label->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    list_->Add(label);
+}
+
+void UITestViewScaleRotate::UIKitViewScaleRotateTestLabel001()
+{
+    UIViewGroup* group1 = new UIViewGroup();
+    group1->SetPosition(rotate_positionx_, rotate_positiony_, offsetX, offsetY);
+    list_->Add(group1);
+
+    SetUpLabel("UILabel组件旋转 ");
+    UIViewGroup* group = new UIViewGroup();
+    group->SetPosition(rotate_positionx_, rotate_positiony_, groupWidht, groupHeight);
+    label_ = new UILabel();
+    label_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, FONT_DEFAULT_SIZE);
+    label_->SetText("Test UILabel");
+    label_->SetPosition(offsetb, offsetb, rotate_positionh_, rotatew_); // 100: x 100: y 200: width 50: height
+    group->Add(label_);
+    list_->Add(group);
+}
+
+void UITestViewScaleRotate::UIKitViewScaleRotateTestLabelButton002()
+{
+    SetUpLabel("UILabelButton组件旋转 ");
+    UIViewGroup* group = new UIViewGroup();
+    group->SetPosition(rotate_positionx_, rotate_positiony_, groupWidht, groupHeight);
+    list_->Add(group);
+    button1_ = new UILabelButton();
+    button1_->SetPosition(offsetb, offsetb, rotate_positionh_, rotatew_); // 100: x 100: y 200: width 50: height
+    button1_->SetText("Test UILabelButton");
+    group->Add(button1_);
+}
+
+void UITestViewScaleRotate::UIKitViewScaleRotateTestCanvas003()
+{
+    SetUpLabel("UICanvas组件旋转 ");
+    UIViewGroup* group = new UIViewGroup();
+    group->SetPosition(rotate_positionx_, rotate_positiony_, groupWidht, groupHeight);
+    list_->Add(group);
+    canvas_ = new UICanvas();
+    group->Add(canvas_);
+
+    canvas_->SetPosition(0, 0, rotate_positionw_, rotate_positionh_);
+    canvas_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Gray().full);
+
+    Paint paint;
+    paint.SetStrokeWidth(rotatex_); // 20: StrokeWidth
+    canvas_->DrawLine({rotateh_, rotateh_}, {rotate_positionw_, rotate_positionw_}, paint);
+
+    paint.SetStrokeColor(Color::Red());
+    canvas_->DrawCurve({offsetb, rotatew_}, {rotateh_, rotate_positiony_},
+        {rotateh_, rotate_positiony_}, {rotateh_, offsetb}, paint);
+    canvas_->DrawRect({rotatey_, rotatey_}, rotatew_, rotatew_, paint); // 10: x 10: y 50: width 50: height
+}
+
+void UITestViewScaleRotate::UIKitViewScaleRotateTestUIBoxProgress004()
+{
+    SetUpLabel("UIBoxProgress组件旋转 ");
+    UIViewGroup* group = new UIViewGroup();
+    group->SetPosition(rotate_positionx_, rotate_positiony_, groupWidht, groupHeight);
+    list_->Add(group);
+
+    boxProgress_ = new UIBoxProgress();
+    boxProgress_->EnableBackground(true);
+    boxProgress_->SetPosition(offsetb, offsetb, rotate_positionh_, rotatew_); // 100: x 100:y 200:width 50: height
+    boxProgress_->SetValue(80); // 80: value
+    boxProgress_->SetBackgroundStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    boxProgress_->SetBackgroundStyle(STYLE_BACKGROUND_COLOR, Color::Red().full);
+    group->Add(boxProgress_);
+}
+
+void UITestViewScaleRotate::UIKitViewScaleRotateTestUICircleProgress005()
+{
+    SetUpLabel("UICircleProgress组件旋转 ");
+    UIViewGroup* group = new UIViewGroup();
+    group->SetPosition(rotate_positionx_, rotate_positiony_, groupWidht, groupHeight);
+    list_->Add(group);
+    circleProgress_ = new UICircleProgress();
+    circleProgress_->SetPosition(rotatex_, rotatey_, rotateh_, rotateh_); // 10: x 10: y 150: width 150: height
+    circleProgress_->SetCenterPosition(75, 75);     // 75: position x 75: position y
+    circleProgress_->SetRadius(rotatew_);                 // 50: radius
+    circleProgress_->SetValue(rotatex_);                  // 20: value
+    circleProgress_->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    circleProgress_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Yellow().full);
+    group->Add(circleProgress_);
+}
+void UITestViewScaleRotate::UIKitViewScaleRotateTestUIDigitalClock006()
+{
+    SetUpLabel("UIDigitalClock组件旋转 ");
+    UIViewGroup* group = new UIViewGroup();
+    group->SetPosition(rotate_positionx_, rotate_positiony_, groupWidht, groupHeight);
+    list_->Add(group);
+    dClock_ = new UIDigitalClock();
+    dClock_->SetPosition(rotatex_, rotatey_, rotateh_, rotateh_);             // 10: x 10:y 150: width 150: height
+    dClock_->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 30); // 30: font size
+    dClock_->SetTime24Hour(7, 25, 50);                  // 7: hour, 25: minute, 50: second
+    group->Add(dClock_);
+}
+
+void UITestViewScaleRotate::UIKitViewScaleRotateTestGroup007()
+{
+    SetUpLabel("UIViewGroup组件旋转 ");
+    UIViewGroup* group = new UIViewGroup();
+    group->SetPosition(rotate_positionx_, rotate_positiony_, groupWidht, groupHeight);
+    list_->Add(group);
+
+    group1_ = new UIViewGroup();
+    group1_->SetPosition(rotatex_, 0, rotate_positionw_, rotate_positionh_);
+    group1_->SetStyle(STYLE_BACKGROUND_OPA, OPA_OPAQUE);
+    group1_->SetStyle(STYLE_BACKGROUND_COLOR, Color::Yellow().full);
+    group->Add(group1_);
+
+    UISlider* slider = new UISlider();
+    slider->SetPosition(rotatex_, rotatey_, rotate_positionh_, rotatew_); // 10: x 10: y 200: width 50: height
+    slider->SetValue(rotatew_); // 50: value
+    slider->SetDirection(UISlider::Direction::DIR_LEFT_TO_RIGHT);
+    group1_->Add(slider);
+
+    UILabelButton* button = new UILabelButton();
+    button->SetPosition(rotatex_, offsetb, rotate_positionh_, rotatew_); // 10: x 100:y 200: width 50: height
+    button->SetText("test ViewGroup");
+    group1_->Add(button);
+}
+} // namespace OHOS
\ No newline at end of file
diff --git a/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_scale_rotate/ui_test_view_scale_rotate.h b/code/sdk/middleware/services/gui/uikit/sample/uitest/components/ui_test_view_scale_rotate/ui_test_view_scale_rotate.h
new file mode 100644 (file)
index 0000000..d3e8abf
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2025. All rights reserved.
+ * Description: TestCase
+ * Author: Hisi Graphic Team
+ * Created: 2025-6
+ */
+
+#ifndef UI_TEST_VIEW_SCALE_ROTATE_H
+#define UI_TEST_VIEW_SCALE_ROTATE_H
+
+#include <cstdio>
+#include "components/ui_arc_label.h"
+#include "components/ui_box_progress.h"
+#include "components/ui_button.h"
+#include "components/ui_canvas.h"
+#include "components/ui_circle_progress.h"
+#include "components/ui_digital_clock.h"
+#include "components/ui_image_view.h"
+#include "components/ui_label_button.h"
+#include "components/ui_scroll_view.h"
+#include "components/ui_slider.h"
+#include "components/ui_swipe_view.h"
+#include "gfx_utils/sys_info.h"
+#include "layout/list_layout.h"
+#include "ui_test.h"
+
+namespace OHOS {
+class UITestViewScaleRotate : public UITest, public AnimatorCallback {
+public:
+    UITestViewScaleRotate() : animator_(this, nullptr, 1000, true) // 1000: the animator duration time is 1000ms
+    {
+    }
+    virtual ~UITestViewScaleRotate() {}
+    void SetUp() override;
+    void TearDown() override;
+    const UIView* GetTestView() override;
+    void Callback(UIView* view) override;
+
+    void UIKitViewScaleRotateTestLabel001();
+    void UIKitViewScaleRotateTestLabelButton002();
+    void UIKitViewScaleRotateTestCanvas003();
+    void UIKitViewScaleRotateTestUIBoxProgress004();
+    void UIKitViewScaleRotateTestUICircleProgress005();
+    void UIKitViewScaleRotateTestUIDigitalClock006();
+    void UIKitViewScaleRotateTestGroup007();
+private:
+    const int groupWidht = 454;
+    const int groupHeight = 300;
+    const Vector2<float> VIEW_CENTER = {75, 75};
+    const Vector2<float> GROUP_CENTER = {200, 200};
+
+    void SetUpLabel(const char* title) const;
+
+    UIScrollView* container_ = nullptr;
+    ListLayout* list_ = nullptr;
+    int16_t angleValue_ = 0;
+    Vector2<float> scaleValue_ = {1.0f, 1.0f};
+    float scaleStep_ = 0.01f;
+
+    Animator animator_;
+    UILabel* label_ = nullptr;
+    UICanvas* canvas_ = nullptr;
+    UILabelButton* button1_ = nullptr;
+    UIBoxProgress* boxProgress_ = nullptr;
+    UICircleProgress* circleProgress_ = nullptr;
+    UIDigitalClock* dClock_ = nullptr;
+    UIViewGroup* group1_ = nullptr;
+};
+} // namespace OHOS
+#endif // UI_TEST_BOX_PROGRESS_H
index 2d60969..aa90b81 100644 (file)
@@ -67,5 +67,7 @@ UITestApp::~UITestApp()
         delete mainList_;
         mainList_ = nullptr;
     }
+
+    UITestGroup::GetInstance()->TearDownTestCase();
 }
 } // namespace OHOS
index bfd6638..3a41ff7 100644 (file)
@@ -60,6 +60,9 @@
 #if CAPABILITY_HW_JPEG_DECODE
 #include "ui_test_image/ui_test_jpeg.h"
 #endif
+#if ENABLE_JPEG_AND_PNG
+#include "ui_test_image/ui_test_png.h"
+#endif
 #if ENABLE_ICU && ENABLE_MULTI_FONT && ENABLE_SHAPING
 #include "ui_test_font/ui_test_multi_font.h"
 #endif
 #include "ui_test_coverflow/ui_test_coverflow2.h"
 #include "ui_test_kaleidoscope/ui_test_kaleidoscope.h"
 #include "ui_test_roller_view/ui_test_roller_view.h"
-#include "ui_test_transform_list/ui_test_scale_list.h"
 #include "ui_test_emoji/ui_test_emoji.h"
 #include "ui_test_particle/ui_test_particle.h"
 #include "ui_test_lottie/ui_test_lottie.h"
+#include "ui_test_lottie/ui_test_trim_path.h"
+#include "ui_test_button/ui_test_button.h"
+#include "ui_test_picker/ui_test_ui_picker.h"
+#include "ui_test_progress_bar/ui_test_box_progress.h"
+#include "ui_test_progress_bar/ui_test_circle_progress.h"
+#include "ui_test_ui_list/ui_test_ui_list.h"
+#include "ui_test_ui_list/ui_test_ui_list.h"
+#include "ui_test_ui_list_view/ui_test_list_layout.h"
+#include "ui_test_ui_scroll_view/ui_test_ui_scroll_view.h"
+#include "ui_test_ui_swipe_view/ui_test_ui_swipe_view.h"
+#include "ui_test_canvas/ui_test_canvas.h"
+#include "ui_test_scroll_bar/ui_test_scroll_bar.h"
+#include "ui_test_input_event/ui_test_input_event.h"
+#include "ui_test_view_group/ui_test_view_group.h"
+#include "ui_test_animator/ui_test_animator.h"
+#include "ui_test_border_margin_padding/ui_test_border_margin_padding.h"
+#include "ui_test_digital_clock/ui_test_digital_clock.h"
+#include "ui_test_draw_line/ui_test_draw_line.h"
+#include "ui_test_event_injector/ui_test_event_injector.h"
+#include "ui_test_focus_manager/ui_test_focus_manager.h"
+#include "ui_test_image_animator/ui_test_image_animator.h"
+#include "ui_test_opacity/ui_test_opacity.h"
+#include "ui_test_render/ui_test_render.h"
+#if ENABLE_VECTOR_FONT
+#include "ui_test_vector_font/ui_test_vector_font.h"
+#endif
+#include "ui_test_rotate_input/ui_test_rotate_input.h"
+#include "ui_test_analog_clock/ui_test_analog_clock.h"
+#include "ui_test_view_bounds/ui_test_view_bounds.h"
+#include "ui_test_view_percent/ui_test_view_percent.h"
+#include "ui_test_view_scale_rotate/ui_test_view_scale_rotate.h"
+#include "ui_test_dump_dom_tree/ui_test_dump_dom.h"
+#include "ui_test_view_bitmap/ui_test_view_bitmap.h"
+#include "ui_test_view_alignment/ui_test_alignment_external.h"
+#include "ui_test_view_alignment/ui_test_alignment_internal.h"
+#include "ui_test_view_alignment/ui_test_alignment_dynamic.h"
+#include "ui_test_simple_list/ui_test_simple_list.h"
+#include "ui_test_simple_list/ui_test_simple_transform_list.h"
+#include "ui_test_float_box/ui_test_float_box.h"
+#include "ui_test_chart/ui_test_scatter_plot.h"
 
 namespace OHOS {
 void UITestGroup::AddTestCase(TestCaseInfo testCaseInfo)
@@ -105,7 +147,10 @@ void UITestGroup::SetUpTestCase()
         return;
     }
     testCaseList_->Clear();
+    testCaseList_->PushBack(TestCaseInfo{"散点图", new UITestScatterPlot()});
+    testCaseList_->PushBack(TestCaseInfo{"悬浮框", new UITestFloatBox()});
     testCaseList_->PushBack(TestCaseInfo{"Lottie", new UITestLottie()});
+    testCaseList_->PushBack(TestCaseInfo{"路径裁剪", new UITestTrimPath()});
     testCaseList_->PushBack(TestCaseInfo{"粒子效果", new UITestParticle()});
     testCaseList_->PushBack(TestCaseInfo{"瀑布列表", new UITestWaterfallList()});
     testCaseList_->PushBack(TestCaseInfo{"老虎头", new UITestTiger()});
@@ -114,10 +159,10 @@ void UITestGroup::SetUpTestCase()
 #endif
     testCaseList_->PushBack(TestCaseInfo{"无变换滑动列表", new UITestListFPS()});
     testCaseList_->PushBack(TestCaseInfo{"带缩放滑动列表", new UITestListExt()});
-    testCaseList_->PushBack(TestCaseInfo{"自定义变换滑动列表", new UITestScaleList()});
+    testCaseList_->PushBack(TestCaseInfo{"简易列表", new UITestSimpleList()});
+    testCaseList_->PushBack(TestCaseInfo{"简易变换列表", new UITestSimpleTransformList()});
     testCaseList_->PushBack(TestCaseInfo{"扫秒", new UITestSweepClock()});
     testCaseList_->PushBack(TestCaseInfo{"指南针", new UITestCompass()});
-    testCaseList_->PushBack(TestCaseInfo{"界面切换", new UITestClockDial()});
     testCaseList_->PushBack(TestCaseInfo{"全屏文字", new UITestTextFPS()});
     testCaseList_->PushBack(TestCaseInfo{"立方体旋转", new UITestCubeRotate()});
     testCaseList_->PushBack(TestCaseInfo{"卡片切换", new UITestCardSwitch()});
@@ -153,6 +198,9 @@ void UITestGroup::SetUpTestCase()
 #endif
 #if CAPABILITY_HW_JPEG_DECODE
     testCaseList_->PushBack(TestCaseInfo{"JPEG显示", new UITestJPEG()});
+#endif
+#if ENABLE_JPEG_AND_PNG
+    testCaseList_->PushBack(TestCaseInfo{"PNG显示", new UITestPNG()});
 #endif
     testCaseList_->PushBack(TestCaseInfo{"弧形文字", new UITestArcLabel()});
     testCaseList_->PushBack(TestCaseInfo{"图片旋转缩放动画", new UITestTextureMapper()});
@@ -182,6 +230,40 @@ void UITestGroup::SetUpTestCase()
     testCaseList_->PushBack(TestCaseInfo{"列表", new UITestList()});
     testCaseList_->PushBack(TestCaseInfo{"滑动条", new UITestSlider()});
     testCaseList_->PushBack(TestCaseInfo{"图片动画", new UITestImageFPS()});
+    testCaseList_->PushBack(TestCaseInfo{"切换动效", new UITestClockDial()});
+    testCaseList_->PushBack(TestCaseInfo{"透明度", new UITestOpacity()});
+    testCaseList_->PushBack(TestCaseInfo{"播放图片动画", new UITestImageAnimator()});
+    testCaseList_->PushBack(TestCaseInfo{"焦点管理", new UITestFocusManager()});
+    testCaseList_->PushBack(TestCaseInfo{"绘制线条", new UITestDrawLine()});
+    testCaseList_->PushBack(TestCaseInfo{"数字时钟", new UITestDigitalClock()});
+    testCaseList_->PushBack(TestCaseInfo{"边界间隔", new UITestBorderMarginPadding()});
+    testCaseList_->PushBack(TestCaseInfo{"动效", new UITestAnimator()});
+    testCaseList_->PushBack(TestCaseInfo{"视图组", new UITestViewGroup()});
+    testCaseList_->PushBack(TestCaseInfo{"事件测试", new UITestInputEvent()});
+    testCaseList_->PushBack(TestCaseInfo{"滚动条", new UITestScrollBar()});
+    testCaseList_->PushBack(TestCaseInfo{"画布", new UITestCanvas()});
+    testCaseList_->PushBack(TestCaseInfo{"Swipe视图", new UITestUISwipeView()});
+    testCaseList_->PushBack(TestCaseInfo{"滑动视图", new UITestUIScrollView()});
+    testCaseList_->PushBack(TestCaseInfo{"列表布局", new UITestListLayout()});
+    testCaseList_->PushBack(TestCaseInfo{"列表", new UITestUIList()});
+    testCaseList_->PushBack(TestCaseInfo{"按钮", new UITestButton()});
+    testCaseList_->PushBack(TestCaseInfo{"选择", new UITestUIPicker()});
+    testCaseList_->PushBack(TestCaseInfo{"圆形进度条", new UITestCircleProgress()});
+    testCaseList_->PushBack(TestCaseInfo{"盒状进度条", new UITestBoxProgress()});
+    testCaseList_->PushBack(TestCaseInfo{"事件模拟", new UITestEventInjector()});
+    testCaseList_->PushBack(TestCaseInfo{"DOM转储", new UITestDumpDomTree()});
+    testCaseList_->PushBack(TestCaseInfo{"旋转", new UITestViewScaleRotate()});
+    testCaseList_->PushBack(TestCaseInfo{"视图比例", new UITestViewPercent()});
+    testCaseList_->PushBack(TestCaseInfo{"视图边界", new UITestViewBounds()});
+#if ENABLE_VECTOR_FONT
+    testCaseList_->PushBack(TestCaseInfo{"矢量文字", new UITestVectorFont()});
+#endif
+    testCaseList_->PushBack(TestCaseInfo{"模拟时钟", new UITestAnalogClock()});
+    testCaseList_->PushBack(TestCaseInfo{"旋转输入", new UITestRotateInput()});
+    testCaseList_->PushBack(TestCaseInfo{"渲染", new UITestRender()});
+    testCaseList_->PushBack(TestCaseInfo{"外部对齐", new UITestExternalAlignment()});
+    testCaseList_->PushBack(TestCaseInfo{"内部对齐", new UITestInternalAlignment()});
+    testCaseList_->PushBack(TestCaseInfo{"动态对齐", new UITestDynamicAlignment()});
 }
 
 List<TestCaseInfo>& UITestGroup::GetTestCase()
index dbd4e2e..09d8134 100644 (file)
@@ -27,6 +27,7 @@ AnimatorManager* AnimatorManager::GetInstance()
 
 void AnimatorManager::Init()
 {
+    SetPeriod(0); // Animator的默认处理周期受RTC/TE刷新周期控制
     Task::Init();
 }
 
index ea8d6f7..9e55455 100644 (file)
@@ -22,7 +22,9 @@
 #include "imgdecode/cache_manager.h"
 #include "common/image_cache_manager.h"
 #if ENABLE_JPEG_AND_PNG
+#if !CAPABILITY_HW_JPEG_DECODE
 #include "jpeglib.h"
+#endif
 #include "png.h"
 #endif
 #include "securec.h"
index a1d44f4..24f68be 100644 (file)
@@ -30,10 +30,8 @@ InputDeviceManager* InputDeviceManager::GetInstance()
 
 void InputDeviceManager::Init()
 {
-    if (INDEV_READ_PERIOD > 0) {
-        SetPeriod(INDEV_READ_PERIOD);
-        TaskManager::GetInstance()->Add(this);
-    }
+    SetPeriod(0);
+    TaskManager::GetInstance()->Add(this);
 }
 
 void InputDeviceManager::Add(InputDevice* device)
index 9ad0ce4..c287e8c 100644 (file)
@@ -19,6 +19,8 @@
 #include "engines/gfx/gfx_engine_manager.h"
 #include "engines/gfx/lite_m_gfx_engine.h"
 #include "gfx_utils/mem_api.h"
+#include "imgdecode/image_load.h"
+#include "hals/display_dev.h"
 #include "securec.h"
 
 namespace OHOS {
@@ -38,19 +40,34 @@ uint16_t Screen::GetHeight()
     return BaseGfxEngine::GetInstance()->GetScreenHeight();
 }
 
+uint16_t Screen::GetRadius()
+{
+    return BaseGfxEngine::GetInstance()->GetScreenRadius();
+}
+
 bool Screen::GetCurrentScreenBitmap(ImageInfo& info)
 {
     return GetScreenBitmapByRect(info, nullptr);
 }
 
-bool Screen::GetScreenBitmapByRect(ImageInfo& info, const Rect* rect)
+bool Screen::GetScreenBitmapByRect(ImageInfo& info, const Rect* rect, float scale, bool isClearMem)
 {
     BufferInfo* fbInfo = BaseGfxEngine::GetInstance()->GetFBBufferInfo();
     if (fbInfo == nullptr) {
         GRAPHIC_LOGE("GetFBBufferInfo failed.");
         return false;
     }
-    BufferInfo srcInfo = *fbInfo;
+    return GetBitMapFromBuffer(*fbInfo, info, rect, scale, isClearMem);
+}
+
+ScreenShape Screen::GetScreenShape()
+{
+    return BaseGfxEngine::GetInstance()->GetScreenShape();
+}
+
+bool Screen::GetBitMapFromBuffer(const BufferInfo &srcBuf, ImageInfo& info, const Rect *rect, float scale, bool isClearMem)
+{
+    BufferInfo srcInfo = srcBuf;
     Rect mask;
     if (rect == nullptr) {
         mask = srcInfo.rect;
@@ -64,57 +81,87 @@ bool Screen::GetScreenBitmapByRect(ImageInfo& info, const Rect* rect)
     }
     srcInfo.rect = mask;
 
-    info.header.width = mask.GetWidth();
-    info.header.height = mask.GetHeight();
+    info.header.width = mask.GetWidth() * scale;
+    info.header.height = mask.GetHeight() * scale;
+#if ENABLE_FB_COMPRESS
+    info.header.compressMode = COMPRESS_MODE_HFBC_3X;
+#else
+    info.header.compressMode = COMPRESS_MODE_NONE;
+#endif
+
 #ifdef VERSION_IOT
 #ifdef _WIN32
     info.header.colorMode = ARGB8888;
     info.dataSize = ALIGN_BYTE(info.header.width, BYTE_ALIGNMENT) * info.header.height * 4; // 4: bpp
 #else
     info.header.colorMode = RGB888;
-    info.dataSize = ALIGN_BYTE(info.header.width, BYTE_ALIGNMENT) * info.header.height * 3; // 3: bpp
+    uint32_t stride = DisplayDev::GetInstance()->CalcStride(info.header.width,
+        PIXEL_FMT_RGB_888, info.header.compressMode);
+    info.dataSize = DisplayDev::GetInstance()->CalcSize(stride, info.header.height, info.header.compressMode);
 #endif
 #else
     info.header.colorMode = ARGB8888;
     info.dataSize = info.header.width *  info.header.height * 4; // 4: bpp
 #endif
+
+    Rect dstRect = {0, 0, info.header.width - 1, info.header.height - 1};
+    BlendOption opt;
+    opt.opacity = OPA_OPAQUE;
+    opt.mode = BLEND_SRC_OVER;
+    opt.transMap.SetTransMapRect(srcInfo.rect);
+    opt.transMap.Scale(Vector2<float>(scale, scale), Vector2<float>(0.0, 0.0));
+    opt.transMap.Translate(Vector2<int16_t>(-srcInfo.rect.GetX(), -srcInfo.rect.GetY()));
+    if (!dstRect.Intersect(dstRect, opt.transMap.GetBoxRect())) {
+        return false;
+    }
     if (ImageCacheMalloc(info) == nullptr) {
         return false;
     }
 
-    Rect dstRect = {0, 0, mask.GetWidth() - 1, mask.GetHeight() - 1};
     BufferInfo dstInfo;
     memset_s(&dstInfo, sizeof(BufferInfo), 0, sizeof(BufferInfo));
+    dstInfo.width = info.header.width;
+    dstInfo.height = info.header.height;
 #ifdef VERSION_IOT
 #ifdef _WIN32
     dstInfo.mode = ARGB8888;
-    dstInfo.stride = ALIGN_BYTE(mask.GetWidth(), BYTE_ALIGNMENT) * 4; // 4: bpp
+    dstInfo.stride = ALIGN_BYTE(info.header.width, BYTE_ALIGNMENT) * 4; // 4: bpp
 #else
     dstInfo.mode = RGB888;
-    dstInfo.stride = ALIGN_BYTE(mask.GetWidth(), BYTE_ALIGNMENT) * 3; // 3: bpp
+#if ENABLE_FB_COMPRESS
+    dstInfo.compressMode = COMPRESS_MODE_HFBC_3X;
+#else
+    dstInfo.compressMode = COMPRESS_MODE_NONE;
+#endif
+    dstInfo.stride = DisplayDev::GetInstance()->CalcStride(dstInfo.width,
+        PIXEL_FMT_RGB_888, dstInfo.compressMode);
 #endif
 #else
     dstInfo.mode = ARGB8888;
-    dstInfo.stride = mask.GetWidth() * 4; // 4: bpp
+    dstInfo.stride = info.header.width * 4; // 4: bpp
 #endif
     dstInfo.phyAddr = (void*)info.phyAddr;
     dstInfo.virAddr = (void*)info.data;
-    dstInfo.width = mask.GetWidth();
-    dstInfo.height = mask.GetHeight();
     dstInfo.rect = dstRect;
 
-    BlendOption opt;
-    opt.opacity = OPA_OPAQUE;
-    opt.mode = BLEND_SRC;
+    if (isClearMem) {
+        int fillHeight = info.header.height;
+        int fileWeight = info.header.width;
+#ifdef VERSION_IOT
+        fileWeight = ALIGN_BYTE(info.header.width, BYTE_ALIGNMENT);
+#if ENABLE_FB_COMPRESS
+        fileWeight = ALIGN_BYTE(info.header.width, 4) / 4;  // 4£º4×Ö½Ú¶ÔÆë£¬4*4ѹËõ
+        fillHeight = ALIGN_BYTE(info.header.height, 4) / 4; // 4£º4×Ö½Ú¶ÔÆë£¬4*4ѹËõ
+#endif
+#endif
+        Rect fillArea = {0, 0, fileWeight - 1, fillHeight - 1}; // 4: bpp
+        BaseGfxEngine::GetInstance()->Fill(dstInfo, fillArea, Color::Black(), OPA_OPAQUE);
+    }
+
     BaseGfxEngine::GetInstance()->Blit(dstInfo, {0, 0}, srcInfo, dstRect, opt);
 #if ENABLE_VGU_ENGINE
     LiteMGfxEngine::GetInstance()->SyncHwDraw();
 #endif
     return true;
 }
-
-ScreenShape Screen::GetScreenShape()
-{
-    return BaseGfxEngine::GetInstance()->GetScreenShape();
-}
 } // namespace OHOS
index cc3f5a0..a30de03 100644 (file)
@@ -406,6 +406,7 @@ void RootView::DrawInvalidMap(const Rect& buffRect)
 }
 
 #else
+
 void RootView::OptimizeAddRect(Rect& rect)
 {
     Rect joinRect;
@@ -465,6 +466,7 @@ void RootView::AddInvalidateRect(Rect& rect, UIView* view)
             invalidRects[0].Join(invalidRects[0], commonRect);
         }
 #else
+        isDrawBeforeBlurViews_[view] = view->IsVisible();
         OptimizeAddRect(commonRect);
 #endif
         if (!renderFlag_) {
@@ -500,10 +502,18 @@ void RootView::MeasureView(UIView* view)
 {
     int16_t stackCount = 0;
     UIView* curView = view;
+    bool isDrawAfterBlurView = false;
     while (stackCount >= 0) {
         while (curView != nullptr) {
             if (curView->IsVisible()) {
                 curView->ReMeasure();
+                curView->UpdatePos();
+                if (curView == blurView_) {
+                    isDrawAfterBlurView = true;
+                }
+                if (isDrawAfterBlurView && isDrawBeforeBlurViews_.find(curView) != isDrawBeforeBlurViews_.end()) {
+                    isDrawBeforeBlurViews_.erase(curView);
+                }
                 if (curView->IsViewGroup() && stackCount < COMPONENT_NESTING_DEPTH) {
                     g_viewStack[stackCount++] = curView;
                     curView = static_cast<UIViewGroup*>(curView)->GetChildrenHead();
@@ -612,10 +622,12 @@ bool RootView::Render()
     invalidateMapDrawing_.swap(invalidateMap_);
 #else
     if (renderFlag_) {
+        isBlurCacheNeedRefresh_ = (blurView_ != nullptr && !isDrawBeforeBlurViews_.empty());
         if (blurView_ != nullptr) {
             Rect rect = blurView_->GetRect();
             AddInvalidateRect(rect, blurView_);
         }
+        isDrawBeforeBlurViews_.clear();
     }
 #endif
     Rect invalidRectTmp = invalidRect_;
@@ -804,7 +816,8 @@ void RootView::DrawTop(UIView* view, const Rect& rect)
                         (curView->GetViewType() != UI_CANVAS_EXT) && (curView->GetViewType() != UI_MENU_ITEM) &&
                         (curView->GetViewType() != UI_MAP_VIEW) && (curView->GetViewType() != UI_LABEL_EXT) &&
                         (curView->GetViewType() != UI_LABEL) && (curView->GetViewType() != UI_TRANSFORM_GROUP) &&
-                         !curView->IsTransInvalid() && !enableAnimator) {
+                        (curView->GetViewType() != UI_IMAGE_ANIMATOR_VIEW) && (curView->GetViewType() != UI_SLIDER) &&
+                        (curView->GetViewType() != UI_LOTT_VIEW) && !curView->IsTransInvalid() && !enableAnimator) {
                         origRect = curView->GetOrigRect();
                         relativeRect = curView->GetRelativeRect();
                         curView->GetTransformMap().SetInvalid(true);
@@ -838,7 +851,7 @@ void RootView::DrawTop(UIView* view, const Rect& rect)
                     }
 #else
                     if (curView == blurView_) {
-                        curView->HandleGaussianBlur(*dc_.bufferInfo);
+                        curView->HandleGaussianBlur(*dc_.bufferInfo, isBlurCacheNeedRefresh_);
                     }
                     curView->OnDraw(*dc_.bufferInfo, curViewRect);
 #endif
index cc01aa0..2823ad9 100644 (file)
@@ -79,6 +79,7 @@ UIView* TextAdapter::GetView(UIView* inView, int16_t index)
     }
 
     if (label != nullptr) {
+        label->SetDirect(direct_);
         label->UIView::SetStyle(style_);
         if (fontName_ == nullptr) {
             label->SetFontId(fontId_);
@@ -145,7 +146,6 @@ UILabel* TextAdapter::CreateUILabel()
         newView->SetOnClickListener(clickListener_);
         newView->SetTouchable(true);
     }
-    newView->SetDirect(direct_);
     return newView;
 }
 
index 8ba6674..414f990 100644 (file)
@@ -260,7 +260,13 @@ void UIBoxProgress::DrawBackground(BufferInfo& gfxDstBuffer, const Rect& invalid
 
     Rect coords(startPoint.x, startPoint.y, startPoint.x + progressWidth - 1, startPoint.y + progressHeight - 1);
 
-    DrawValidRect(gfxDstBuffer, backgroundImage_, coords, invalidatedArea, *backgroundStyle_, radius);
+    if (transMap_ != nullptr) {
+        transMap_->SetTransMapRect(coords);
+        DrawValidRect(gfxDstBuffer, backgroundImage_, transMap_->GetBoxRect(), invalidatedArea, *backgroundStyle_, radius);
+        transMap_->SetTransMapRect(GetOrigRect());
+    } else {
+        DrawValidRect(gfxDstBuffer, backgroundImage_, coords, invalidatedArea, *backgroundStyle_, radius);
+    }
 }
 
 void UIBoxProgress::DrawForeground(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, Rect& coords)
index a2c4f7e..9661f31 100644 (file)
@@ -266,17 +266,14 @@ bool UIButton::InitImage()
 bool UIButton::OnPreDraw(Rect& invalidatedArea) const
 {
     Rect rect(GetRect());
-    int16_t r = buttonStyles_[styleState_]->borderRadius_;
-    if (r == COORD_MAX) {
+    int16_t topRadius = buttonStyles_[styleState_]->GetStyle(STYLE_TOP_BORDER_RADIUS);
+    int16_t bottomRadius = buttonStyles_[styleState_]->GetStyle(STYLE_BOTTOM_BORDER_RADIUS);
+    if (topRadius == bottomRadius && topRadius == COORD_MAX) {
         return true;
     }
 
-    if (r != 0) {
-        r = ((r & 0x1) == 0) ? (r >> 1) : ((r + 1) >> 1);
-        rect.SetLeft(rect.GetX() + r);
-        rect.SetWidth(rect.GetWidth() - r);
-        rect.SetTop(rect.GetY() + r);
-        rect.SetHeight(rect.GetHeight() - r);
+    if (topRadius != 0 || bottomRadius != 0) {
+        rect = GetInnerRect(rect, topRadius, bottomRadius);
     }
     if (rect.IsContains(invalidatedArea)) {
         return true;
index 19ce574..6a1050e 100644 (file)
@@ -542,7 +542,7 @@ void UIChartPillar::HWDrawLine(BufferInfo& gfxDstBuffer, const Rect& mask, Point
     path->cmds[1] = CMD_VLINE_TO;
     path->data[0] = start.x;
     path->data[1] = start.y;
-    path->data[2] = enableReverse_ ? end.y - capRadius_ : end.y + capRadius_;
+    path->data[2] = end.y;
 
     VGUStrokeAttr strokeAttr = {static_cast<VGULineCap>(CapType::CAP_NONE),
         static_cast<VGUJointType>(JoinType::JOIN_BEVEL), 0, width};
@@ -550,6 +550,7 @@ void UIChartPillar::HWDrawLine(BufferInfo& gfxDstBuffer, const Rect& mask, Point
     strokeAttr.style = &strokeStyle;
     if (style_->lineCap_ == CapType::CAP_ROUND) {
         strokeAttr.cap = VGU_LINECAP_ROUND;
+        path->data[2] = enableReverse_ ? end.y - capRadius_ : end.y + capRadius_;
     }
 
     if (isDrawGradient_) {
index fb93119..08f589e 100644 (file)
@@ -46,11 +46,13 @@ UICheckBox::UICheckBox()
 {
     touchable_ = true;
     style_ = &(StyleDefault::GetBackgroundTransparentStyle());
+#if !ENABLE_VGU_ENGINE
     image_[UNSELECTED].SetSrc(GetCheckBoxOffInfo());
     image_[SELECTED].SetSrc(GetCheckBoxOnInfo());
     ImageHeader header = {0};
     image_[UNSELECTED].GetHeader(header);
     Resize(header.width, header.height);
+#endif
 #if DEFAULT_ANIMATION
     runTime_ = 0;
     checkBoxAnimator_ = Animator(this, this, DEFAULT_ANIMATOR_TIME, false);
@@ -163,6 +165,13 @@ void UICheckBox::SelectedStateSoftwareDrawing(BufferInfo& gfxDstBuffer,
                             CIRCLE_IN_DEGREE - QUARTER_IN_DEGREE / half,
                             SEMICIRCLE_IN_DEGREE - QUARTER_IN_DEGREE / half,
                             nullptr};
+#if ENABLE_VGU_ENGINE && CAPABILITY_HWDRAW_LINE
+    start.x -= 1;
+    start.y -= 1;
+    mid.y += 1;
+    end.x += 1;
+    end.y -= 1;
+#endif
     styleSelect.lineColor_ = Color::White();
     styleSelect.lineOpa_ = backgroundOpacity_;
     uint8_t opa = DrawUtils::GetMixOpacity(opaScale_, backgroundOpacity_);
@@ -242,6 +251,7 @@ void UICheckBox::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
         }
         CalculateSize();
         int16_t rectLineWidth = borderWidth_ / DEFAULT_BORDER_WIDTH;
+        rectLineWidth = (rectLineWidth == 0) ? 1: rectLineWidth;
         int16_t borderRadius = rectLineWidth * DEFAULT_RATIO_BORDER_RADIUS_LINE_WIDTH;
         BaseGfxEngine::GetInstance()->DrawRect(gfxDstBuffer, GetRect(), invalidatedArea, *style_, opaScale_);
         int16_t x = contentRect.GetX() + (width_ - borderWidth_) / 2;  // 2: half
index a17be15..4387313 100644 (file)
@@ -61,21 +61,6 @@ void UICircleProgress::GetStartEndAngle(int16_t& start, int16_t& end) const
     }
 }
 
-#if ENABLE_VGU_ENGINE && CAPABILITY_HWDRAW_PATH
-static void HwGetAngleRange(int16_t &start, int16_t &end)
-{
-    int16_t range = end - start;
-    int16_t absRange = (range < 0 ? -range : range);
-    if (absRange >= CIRCLE_IN_DEGREE) {
-        start = 0;
-        end = CIRCLE_IN_DEGREE;
-        return;
-    }
-    start = (start < 0 ? (start % CIRCLE_IN_DEGREE + CIRCLE_IN_DEGREE) : (start % CIRCLE_IN_DEGREE));
-    end = start + range;
-}
-#endif
-
 void UICircleProgress::GetAngleRange(int16_t& start, int16_t& end) const
 {
     GetStartEndAngle(start, end);
index a8fc124..ca993f4 100644 (file)
@@ -206,7 +206,7 @@ void UIDigitalClock::SetHorizontal()
     if (align == TEXT_ALIGNMENT_CENTER) {
         x = (rect.GetWidth() >> 1) - (totalWidth >> 1);
     } else if (align == TEXT_ALIGNMENT_RIGHT) {
-        x = rect.GetRight() - totalWidth;
+        x = rect.GetWidth() - totalWidth;
     }
     timeLabels_[HOUR_ELEMENT]->SetPosition(x, 0);
     int16_t width = timeLabels_[HOUR_ELEMENT]->GetWidth();
index 996115f..b005724 100644 (file)
@@ -384,11 +384,7 @@ void UIImageView::UpdateDrawTransMap(bool updateContentMatrix)
         return;
     }
     // merge the transMap and content matrix
-    auto rect = transMap_->GetTransMapRect();
-    auto translate = Matrix4<float>::Translate(Vector3<float>(-rect.GetX(), -rect.GetY(), 0));
-    auto matrix = transMap_->GetTransformMatrix() * translate;
-    matrix = matrix * (*contentMatrix_);
-    drawTransMap_->SetMatrix(matrix);
+    drawTransMap_->SetMatrix(transMap_->GetOrigTransformMatrix() * (*contentMatrix_));
 }
 
 void UIImageView::SetHeight(int16_t height)
index 567e748..7fedf80 100644 (file)
@@ -49,6 +49,11 @@ public:
         startPos_ = pos;
     }
 
+    void SetMarqueeBlankWidth(uint16_t size)
+    {
+        marqueeBlankWidth_ = size;
+    }
+
     void UpdateWidth(uint16_t textWidth, uint16_t labelWidth)
     {
         textWidth_ = textWidth;
@@ -136,7 +141,19 @@ private:
             offsetX_ -= 1; // At lest move one pixel
             decimal_ = 0;
         }
-        offsetX_ = ((offsetX_ - labelWidth_) % (textWidth_ + labelWidth_)) + labelWidth_;
+        // the range of offsetX_ => [-textWidth_ - marqueeBlankWidth_, labelWidth_]
+        offsetX_ = offsetX_ % (textWidth_ + marqueeBlankWidth_);
+
+        /*
+         * the cyclicText always appears a fixed lengths behind original Text. 
+         * tx = x + textWidth_ + marqueeBlankWidth_
+         * when x == labelWidth_, set x = 0
+         */ 
+        if (offsetX_ == labelWidth_) { 
+            offsetX_ = 0;
+        }
+
+        static_cast<UILabel*>(view)->nextOffsetX_ = offsetX_ + textWidth_ + marqueeBlankWidth_;
         static_cast<UILabel*>(view)->offsetX_ = offsetX_;
         view->Invalidate();
     }
@@ -190,9 +207,15 @@ private:
     bool startFlag_ = true;
     uint32_t startTime_ = 0;
     float decimal_;
+    uint16_t marqueeBlankWidth_;
     UILabel::LineBreakMode animatorMode_ = UILabel::LINE_BREAK_MARQUEE;
 };
 
+inline uint16_t CalcBlankSpaceWidth(uint16_t num)
+{
+    return num * UIFont::GetInstance()->GetWidth((uint32_t)(' '), 0);
+}
+
 UILabel::UILabel()
     : labelText_(nullptr),
       needRefresh_(false),
@@ -202,6 +225,7 @@ UILabel::UILabel()
       ellipsisIndex_(Text::TEXT_ELLIPSIS_END_INV),
       truncateIndex_(Text::TEXT_TRUNCATE_END_INV),
       offsetX_(0),
+      nextOffsetX_(0),
       textColor_(Color::White()),
       animator_{nullptr}
 {
@@ -482,8 +506,10 @@ void UILabel::RemeasureForAnimation(int16_t textWidth, LineBreakMode mode)
         return;
     }
     int16_t rectWidth = GetWidth();
+
     if (textWidth > rectWidth) {
         offsetX_ = GetRollStartPos();
+        nextOffsetX_ = offsetX_ + textWidth + CalcBlankSpaceWidth(marqueeBlankNum_); // set tOffset big than rectWidth
         if (labelText_->GetDirect() == TEXT_DIRECT_RTL) {
             labelText_->SetAlign(TEXT_ALIGNMENT_RIGHT, labelText_->GetVerAlign());
         } else {
@@ -502,6 +528,7 @@ void UILabel::RemeasureForAnimation(int16_t textWidth, LineBreakMode mode)
             animator_.animator = animator;
             hasAnimator_ = true;
         }
+        static_cast<LabelAnimator*>(animator_.animator)->SetMarqueeBlankWidth(CalcBlankSpaceWidth(marqueeBlankNum_));
         if (animator_.animator->GetState() == Animator::PAUSE) {
             animator_.animator->Resume();
         } else {
@@ -509,6 +536,7 @@ void UILabel::RemeasureForAnimation(int16_t textWidth, LineBreakMode mode)
         }
     } else {
         offsetX_ = 0;
+        nextOffsetX_ = rectWidth; // Set text outside the display area
         labelText_->SetAlign(horAlign_, labelText_->GetVerAlign());
         if (hasAnimator_) {
             animator_.animator->Stop();
@@ -558,6 +586,11 @@ void UILabel::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
     if (lineBreakMode_ != LINE_BREAK_TRUNCATE) {
         labelText_->OnDraw(gfxDstBuffer, invalidatedArea, GetOrigRect(),
                            origContentRect, offsetX_, style, ellipsisIndex_, opa);
+        // when tOffsetX is a valid value, use nextOffsetX_ to redraw the text from the right side to left (achieve a looping display effect).
+        if (lineBreakMode_ == LINE_BREAK_MARQUEE && nextOffsetX_ <= GetWidth()) {
+            labelText_->OnDraw(gfxDstBuffer, invalidatedArea, GetOrigRect(),
+                           origContentRect, nextOffsetX_, style, ellipsisIndex_, opa);
+        }
     } else {
         labelText_->OnDraw(gfxDstBuffer, invalidatedArea, GetOrigRect(),
                            origContentRect, offsetX_, style, truncateIndex_, opa);
index 75d331a..b425dc5 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "components/ui_abstract_scroll_bar.h"
 #include "gfx_utils/graphic_log.h"
+#include "components/common_adapter.h"
 
 namespace OHOS {
 UIList::Recycle::~Recycle()
@@ -91,14 +92,34 @@ UIView* UIList::Recycle::GetView(int16_t index)
     UIView* inView = nullptr;
     UIView* retView = nullptr;
 
+    auto currentNode = scrapView_.Begin();
     if (scrapView_.Size() != 0) {
-        inView = scrapView_.Back();
+        CommonAdapter* adapter = dynamic_cast<CommonAdapter*>(adapter_);
+        if (adapter != nullptr) {
+            uint32_t type = adapter->GetViewType(index);
+            if (type != 0) {
+                UIView* tempView = nullptr;
+                while (currentNode != scrapView_.End()) {
+                    tempView = currentNode->data_;
+                    if ((reinterpret_cast<uint32_t>(tempView->GetViewId()) & 0xff) == type) {
+                        inView = currentNode->data_;
+                        break;
+                    }
+                    currentNode = scrapView_.Next(currentNode);
+                }
+            }
+        } else {
+            inView = scrapView_.Back();
+            currentNode = scrapView_.Tail();
+        }
     }
 
     retView = adapter_->GetView(inView, index);
     if (retView != nullptr) {
         retView->SetViewIndex(index);
-        scrapView_.PopBack();
+        if (inView != nullptr && inView == retView) {
+            scrapView_.Remove(currentNode);
+        }
     }
     return retView;
 }
index f00e576..ef4dd04 100644 (file)
@@ -300,13 +300,13 @@ void UIScrollView::CalculateReboundDistance(int16_t& dragDistanceX, int16_t& dra
     int16_t scrollWidth = GetWidth();
     if (scrollBlankSizeTop_ < top) {
         dragDistanceY = scrollBlankSizeTop_ - top;
-    } else if (bottom < scrollHeight - 1) {
+    } else if (bottom < (scrollHeight - scrollBlankSizeBottom_ - 1)) {
         dragDistanceY = scrollHeight - scrollBlankSizeBottom_ - bottom - 1;
     }
 
     if (scrollBlankSizeLeft_ < left) {
         dragDistanceX = scrollBlankSizeLeft_ - left;
-    } else if (right < scrollWidth - 1) {
+    } else if (right < (scrollWidth - scrollBlankSizeRight_ - 1)) {
         dragDistanceX = scrollWidth - scrollBlankSizeRight_ - right - 1;
     }
 }
index e246f1c..2677817 100644 (file)
@@ -146,7 +146,19 @@ void UISlider::DrawKnob(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea, c
             GRAPHIC_LOGW("UISlider::DrawKnob Direction error!\n");
         }
     }
-    DrawValidRect(gfxDstBuffer, knobImage_, knobBar, invalidatedArea, *knobStyle_, 0);
+    if (transMap_ != nullptr) {
+        transMap_->SetTransMapRect(knobBar);
+        Rect updateKnobBar = transMap_->GetBoxRect();
+        if (!knobBar.IsValid()) {
+            updateKnobBar = knobBar;
+        }
+        transMap_->SetTransMapRect(invalidatedArea);
+        Rect updateInvalidatedArea = transMap_->GetBoxRect();
+        DrawValidRect(gfxDstBuffer, knobImage_, updateKnobBar, updateInvalidatedArea, *knobStyle_, 0);
+        transMap_->SetTransMapRect(GetOrigRect());
+    } else {
+        DrawValidRect(gfxDstBuffer, knobImage_, knobBar, invalidatedArea, *knobStyle_, 0);
+    }
 }
 
 bool UISlider::InitImage()
@@ -244,8 +256,19 @@ void UISlider::DrawForeground(BufferInfo& gfxDstBuffer, const Rect& invalidatedA
         }
     }
     Rect tmp;
-    if (tmp.Intersect(coords, invalidatedArea)) {
-        DrawValidRect(gfxDstBuffer, foregroundImage_, foregroundRect, tmp, *foregroundStyle_, radius);
+    if (transMap_ != nullptr) {
+        transMap_->SetTransMapRect(coords);
+        Rect updateCoords = transMap_->GetBoxRect();
+        transMap_->SetTransMapRect(foregroundRect);
+        foregroundRect = transMap_->GetBoxRect();
+        if (tmp.Intersect(updateCoords, invalidatedArea)) {
+            DrawValidRect(gfxDstBuffer, foregroundImage_, foregroundRect, tmp, *foregroundStyle_, radius);
+        }
+        transMap_->SetTransMapRect(GetOrigRect());
+    } else {
+        if (tmp.Intersect(coords, invalidatedArea)) {
+            DrawValidRect(gfxDstBuffer, foregroundImage_, foregroundRect, tmp, *foregroundStyle_, radius);
+        }
     }
 }
 
index 35f6dac..d6352fd 100644 (file)
@@ -26,6 +26,7 @@
 #include "gfx_utils/mem_api.h"
 #include "securec.h"
 #include "themes/theme_manager.h"
+#include "hals/gralloc_engines.h"
 #include <cstdio>
 
 namespace OHOS {
@@ -44,9 +45,12 @@ UIView::UIView()
       fullScreenBlur_(false),
       opaScale_(OPA_OPAQUE),
       index_(0),
+      pPrevWidth_(0),
+      pPrevHeight_(0),
       id_(nullptr),
       parent_(nullptr),
       nextSibling_(nullptr),
+      alignType_(ALIGN_DEFAULT),
       style_(nullptr),
       transMap_(nullptr),
       onClickListener_(nullptr),
@@ -89,21 +93,48 @@ UIView::~UIView()
         style_ = nullptr;
         styleAllocFlag_ = false;
     }
+    if (blurCache_ != nullptr) {
+        GrallocEngines::GetInstance()->FreeBuffer(reinterpret_cast<uint8_t *>(blurCache_->virAddr));
+        UIFree(blurCache_);
+        blurCache_ = nullptr;
+    }
+}
+
+Rect UIView::GetInnerRect(const Rect &rect, int16_t topRadius, int16_t bottomRadius) const
+{
+    int16_t minR = MATH_MIN(rect.GetHeight(), rect.GetWidth()) / 2;  // 2: half
+    topRadius = MATH_MIN(topRadius, minR);
+    bottomRadius = MATH_MIN(bottomRadius, minR);
+    topRadius = (topRadius + 1) / 2;        // 2: half
+    bottomRadius = (bottomRadius + 1) / 2;  // 2: half
+
+    int16_t x = rect.GetX();
+    int16_t y = rect.GetY();
+    Rect innerRect;
+    if (topRadius >= bottomRadius) {
+        innerRect.SetLeft(x + topRadius);
+        innerRect.SetTop(y + topRadius);
+        innerRect.SetWidth(rect.GetWidth() - 2 * topRadius);  // 2: half
+    } else {
+        innerRect.SetLeft(x + bottomRadius);
+        innerRect.SetTop(y + topRadius);
+        innerRect.SetWidth(rect.GetWidth() - 2 * bottomRadius);  // 2: half
+    }
+    innerRect.SetHeight(rect.GetHeight() - topRadius - bottomRadius);
+
+    return innerRect;
 }
 
 bool UIView::OnPreDraw(Rect& invalidatedArea) const
 {
     Rect rect(GetRect());
-    int16_t r = style_->borderRadius_;
-    if (r == COORD_MAX) {
+    int16_t topRadius = style_->GetStyle(STYLE_TOP_BORDER_RADIUS);
+    int16_t bottomRadius = style_->GetStyle(STYLE_BOTTOM_BORDER_RADIUS);
+    if (topRadius == bottomRadius && topRadius == COORD_MAX) {
         return true;
     }
-    if (r != 0) {
-        r = ((r & 0x1) == 0) ? (r >> 1) : ((r + 1) >> 1);
-        rect.SetLeft(rect.GetX() + r);
-        rect.SetWidth(rect.GetWidth() - r);
-        rect.SetTop(rect.GetY() + r);
-        rect.SetHeight(rect.GetHeight() - r);
+    if (topRadius != 0 || bottomRadius != 0) {
+        rect = GetInnerRect(rect, topRadius, bottomRadius);
     }
     if (rect.IsContains(invalidatedArea)) {
         return true;
@@ -112,7 +143,58 @@ bool UIView::OnPreDraw(Rect& invalidatedArea) const
     return false;
 }
 
-void UIView::HandleGaussianBlur(BufferInfo& gfxDstBuffer)
+#if ENABLE_VGU_ENGINE
+void UIView::SaveBlurCache(const BufferInfo& gfxDstBuffer, const Rect &mask)
+{
+    BufferInfo srcInfo = gfxDstBuffer;
+    srcInfo.rect = mask;
+    if (blurCache_ != nullptr) {
+        GrallocEngines::GetInstance()->FreeBuffer(reinterpret_cast<uint8_t *>(blurCache_->virAddr));
+        UIFree(blurCache_);
+        blurCache_ = nullptr;
+    }
+    blurCache_ = static_cast<BufferInfo *>(UIMalloc(sizeof(BufferInfo)));
+    if (blurCache_ == nullptr) {
+        return;
+    }
+
+    ImageInfo info;
+    if (!Screen::GetInstance().GetBitMapFromBuffer(gfxDstBuffer, info, &mask)) {
+        UIFree(blurCache_);
+        blurCache_ = nullptr;
+        return;
+    }
+    blurCache_->rect = {0, 0, mask.GetWidth() - 1, mask.GetHeight() - 1};
+    blurCache_->stride = info.dataSize / info.header.height;
+    blurCache_->virAddr = static_cast<void*>(const_cast<uint8_t*>(info.data));
+    blurCache_->phyAddr = static_cast<void*>(const_cast<uint8_t*>(info.data));
+    blurCache_->width = info.header.width;
+    blurCache_->height = info.header.height;
+    blurCache_->mode = static_cast<ColorMode>(info.header.colorMode);
+    blurCache_->color = 0;
+#ifdef VERSION_IOT
+    blurCache_->compressMode = info.header.compressMode;
+#endif
+}
+
+void UIView::DrawBlurCache(BufferInfo& gfxDstBuffer, const Rect &mask)
+{
+    BlendOption opt;
+    opt.mode = BLEND_SRC_OVER;
+    opt.opacity = OPA_OPAQUE;
+    opt.transMap.SetTransMapRect(blurCache_->rect);
+    opt.transMap.Translate(Vector2<int16_t>{mask.GetX(), mask.GetY()});
+    BufferInfo src = *blurCache_;
+    auto minFunc = [](int16_t a, int16_t b) -> int16_t {
+        return a < b ? a : b;
+    };
+    src.rect.SetWidth(minFunc(blurCache_->rect.GetWidth(), mask.GetWidth()));
+    src.rect.SetHeight(minFunc(mask.GetHeight(), blurCache_->rect.GetHeight()));
+    BaseGfxEngine::GetInstance()->Blit(gfxDstBuffer, {0, 0}, src, mask, opt);
+}
+#endif
+
+void UIView::HandleGaussianBlur(BufferInfo& gfxDstBuffer, bool isNeedRefresh)
 {
     if (visible_ && (!FloatEqual(blurRadius_, 0.0f))) {
         BufferInfo gfxTargetBuffer = gfxDstBuffer;
@@ -125,10 +207,45 @@ void UIView::HandleGaussianBlur(BufferInfo& gfxDstBuffer)
             }
         }
         gfxTargetBuffer.rect = mask;
+#if ENABLE_VGU_ENGINE
+        if (!isNeedRefresh && blurCache_ != nullptr && !IsFullScreenBlur() &&
+            lastBlurMask_ == mask && lastBlurRadius_ == blurRadius_) {
+            DrawBlurCache(gfxDstBuffer, mask);
+            return;
+        }
+        lastBlurMask_ = mask;
+        lastBlurRadius_ = blurRadius_;
+#endif
         BaseGfxEngine::GetInstance()->Blur(gfxTargetBuffer, blurRadius_);
+#if ENABLE_VGU_ENGINE
+        if (isGaussCacheEnabled_ && !IsFullScreenBlur()) {
+            SaveBlurCache(gfxDstBuffer, mask);
+        }
+#endif
+    }
+}
+
+#if ENABLE_VGU_ENGINE
+void UIView::EnableGaussianBlurCache(bool enable)
+{
+    isGaussCacheEnabled_ = enable;
+    if (!isGaussCacheEnabled_) {
+        if (blurCache_ != nullptr) {
+            LiteMGfxEngine::GetInstance()->SyncHwDraw();
+            GrallocEngines::GetInstance()->FreeBuffer(reinterpret_cast<uint8_t *>(blurCache_->virAddr));
+            UIFree(blurCache_);
+            blurCache_ = nullptr;
+        }
     }
+    Invalidate();
 }
 
+bool UIView::IsGaussianBlurCacheEnable() const
+{
+    return isGaussCacheEnabled_;
+}
+#endif
+
 void UIView::OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea)
 {
     uint8_t opa = GetMixOpaScale();
@@ -286,10 +403,7 @@ void UIView::Rotate(int16_t angle, const Vector3<float>& pivotStart, const Vecto
 #endif
 {
 #if !ENABLE_MAP_BUFFER
-    UIViewType type = GetViewType();
-    if ((type != UI_IMAGE_VIEW) && (type != UI_TEXTURE_MAPPER) && (type != UI_CANVAS_EXT) && (type != UI_MAP_VIEW) &&
-        (type != UI_MENU_ITEM) && (type != UI_LABEL_EXT) && (type != UI_LABEL) && (type != UI_TRANSFORM_GROUP)) {
-        GRAPHIC_LOGE("Rotate is not supported for view type %d if ENABLE_MAP_BUFFER is 0", type);
+    if (!CheckIsNeedMapBufferToTrans(__PRETTY_FUNCTION__)) {
         return;
     }
 #endif
@@ -320,10 +434,7 @@ void UIView::Scale(const Vector2<float>& scale, const Vector2<float>& pivot)
 void UIView::Scale(const Vector3<float>& scale, const Vector3<float>& pivot)
 {
 #if !ENABLE_MAP_BUFFER
-    UIViewType type = GetViewType();
-    if ((type != UI_IMAGE_VIEW) && (type != UI_TEXTURE_MAPPER) && (type != UI_CANVAS_EXT) && (type != UI_MAP_VIEW) &&
-        (type != UI_MENU_ITEM) && (type != UI_LABEL_EXT) && (type != UI_LABEL) && (type != UI_TRANSFORM_GROUP)) {
-        GRAPHIC_LOGE("Scale is not supported for view type %d if ENABLE_MAP_BUFFER is 0", type);
+    if (!CheckIsNeedMapBufferToTrans(__PRETTY_FUNCTION__)) {
         return;
     }
 #endif
@@ -355,10 +466,7 @@ void UIView::Scale(const Vector3<float>& scale, const Vector3<float>& pivot)
 void UIView::Shear(const Vector2<float>& shearX, const Vector2<float>& shearY, const Vector2<float>& shearZ)
 {
 #if !ENABLE_MAP_BUFFER
-    UIViewType type = GetViewType();
-    if ((type != UI_IMAGE_VIEW) && (type != UI_TEXTURE_MAPPER) && (type != UI_CANVAS_EXT) && (type != UI_MAP_VIEW) &&
-        (type != UI_MENU_ITEM)) {
-        GRAPHIC_LOGE("Shear is not supported for view type %d if ENABLE_MAP_BUFFER is 0", type);
+    if (!CheckIsNeedMapBufferToTrans(__PRETTY_FUNCTION__)) {
         return;
     }
 #endif
@@ -388,10 +496,7 @@ void UIView::Translate(const Vector2<int16_t>& trans)
 void UIView::Translate(const Vector3<int16_t>& trans)
 {
 #if !ENABLE_MAP_BUFFER
-    UIViewType type = GetViewType();
-    if ((type != UI_IMAGE_VIEW) && (type != UI_TEXTURE_MAPPER) && (type != UI_CANVAS_EXT) && (type != UI_MAP_VIEW) &&
-        (type != UI_MENU_ITEM) && (type != UI_LABEL_EXT) && (type != UI_LABEL) && (type != UI_TRANSFORM_GROUP)) {
-        GRAPHIC_LOGE("Translate is not supported for view type %d if ENABLE_MAP_BUFFER is 0", type);
+    if (!CheckIsNeedMapBufferToTrans(__PRETTY_FUNCTION__)) {
         return;
     }
 #endif
@@ -479,7 +584,12 @@ void UIView::SetBackgroundBlur(float radius)
     } else if (RootView::GetInstance()->SetBlurView(this)) {
         blurRadius_ = radius;
     }
-    RootView::GetInstance()->Invalidate();
+    if (fullScreenBlur_) {
+        RootView::GetInstance()->Invalidate();
+    } else {
+        Invalidate();
+    }
+    
 }
 
 void UIView::ClearBackgroundBlur()
@@ -487,7 +597,11 @@ void UIView::ClearBackgroundBlur()
     if (!FloatEqual(blurRadius_, 0.0f)) {
         RootView::GetInstance()->ClearBlurView(this);
         blurRadius_ = 0.0f;
-        RootView::GetInstance()->Invalidate();
+        if (fullScreenBlur_) {
+            RootView::GetInstance()->Invalidate();
+        } else {
+            Invalidate();
+        }
     }
 }
 
@@ -789,10 +903,7 @@ Rect UIView::GetVisibleRect() const
 void UIView::SetTransformMap(const TransformMap& transMap)
 {
 #if !ENABLE_MAP_BUFFER
-    UIViewType type = GetViewType();
-    if ((type != UI_IMAGE_VIEW) && (type != UI_TEXTURE_MAPPER) && (type != UI_CANVAS_EXT) && (type != UI_MAP_VIEW) &&
-        (type != UI_MENU_ITEM) && (type != UI_LABEL) && (type != UI_LABEL_EXT) && (type != UI_TRANSFORM_GROUP)) {
-        GRAPHIC_LOGE("SetTransformMap is not supported for view type %d if ENABLE_MAP_BUFFER is 0", type);
+    if (!CheckIsNeedMapBufferToTrans(__PRETTY_FUNCTION__)) {
         return;
     }
 #endif
@@ -1043,6 +1154,103 @@ void UIView::AlignVerCenterToSibling(const char* id, int16_t offset)
     }
 }
 
+void UIView::UpdatePos()
+{
+    // Èç¹ûûÓÐÉèÖùý¶ÔÆë¹ØÏµ, »òÕ߸¸ÈÝÆ÷²»´æÔÚ£¬²»´¦Àí
+    if (alignType_ == ALIGN_DEFAULT || parent_ == nullptr) {
+        return;
+    }
+
+    int16_t rx = parent_->GetX();
+    int16_t ry = parent_->GetY();
+    int16_t rw = parent_->GetWidth();
+    int16_t rh = parent_->GetHeight();
+ 
+    // Èç¹û¸¸ÈÝÆ÷³ß´çûÓз¢Éú±ä»¯£¬²»ÐèÒª´¦Àí
+    if (IsParentSizeStabled(rw, rh)) {
+        return;
+    }
+ 
+    int16_t x = 0;
+    int16_t y = 0;
+    int16_t w = GetWidth();
+    int16_t h = GetHeight();
+
+    // ÌáÈ¡¶ÔÆëλÖà(¸ßµÍ¸÷Õ¼4λ)
+    uint8_t alignHigh = (alignType_ & ALIGN_UP_MASK) >> 4;
+    uint8_t alignLow = (alignType_ & ALIGN_DOWUN_MASK);
+    
+    x = alignLow * (rw - w) / 2;
+    y = alignHigh * (rh - h) / 2;
+    
+    // ¼ÆËãÆ«ÒÆÁ¿
+    x += ofsX_;
+    y += ofsY_;
+    SetPosition(x, y);
+}
+ 
+void UIView::AlignToReference(AlignmentType alignType, UIView* referView, int16_t ofsX, int16_t ofsY)
+{
+    if (referView == nullptr && parent_ == nullptr) {
+        return;
+    }
+
+    // Êµ¼ÊʹÓõIJο¼¿Ø¼þ
+    UIView* actualReferView = (referView != nullptr) ? referView : parent_;
+
+    if (actualReferView == parent_) {
+        if (alignType >= ALIGN_OUT_TOP_LEFT) {
+            GRAPHIC_LOGE("UIView::AlignToReference, alignment type set invalid");
+            return;
+        } else {
+            alignType_ = alignType;
+            pPrevWidth_ = parent_->GetWidth();
+            pPrevHeight_ = parent_->GetHeight();
+        }
+    }
+
+    // »ñÈ¡²Î¿¼¿Ø¼þµÄ¼¸ºÎÐÅÏ¢
+    int16_t rx = actualReferView->GetX();
+    int16_t ry = actualReferView->GetY();
+    int16_t rw = actualReferView->GetWidth();
+    int16_t rh = actualReferView->GetHeight();
+ 
+    // »ñÈ¡´ý¶ÔÆë¿Ø¼þµÄ¼¸ºÎÐÅÏ¢
+    int16_t x = 0;
+    int16_t y = 0;
+    int16_t w = GetWidth();
+    int16_t h = GetHeight();
+ 
+    bool isOuter = (alignType & ALIGN_OUTER_MASK) != 0;
+    
+    // ÌáÈ¡¶ÔÆëλÖà(¸ßµÍ¸÷Õ¼4λ)
+    uint8_t alignHigh = (alignType & ALIGN_UP_MASK) >> 4;
+    uint8_t alignLow = (alignType & ALIGN_DOWUN_MASK);
+ 
+    // »ù´¡¶ÔÆë¼ÆËã
+    if (!isOuter) {
+        x = alignLow * (rw - w) / 2;
+        y = alignHigh * (rh - h) / 2;
+    } else {
+        // Íⲿ¶ÔÆë¼ÆËã
+        if (alignHigh <= 1) {
+            x = rx + alignLow * (rw - w) / 2;
+            y = ry + (alignHigh * (rh + h)) - h;
+        } else {
+            x = rx + ((alignHigh - 2) * (rw + w)) - w;
+            y = ry + alignLow * (rh - h) / 2;
+        }
+    }
+ 
+    ofsX_ = ofsX;
+    ofsY_ = ofsY;
+ 
+    // ¼ÆËãÆ«ÒÆÁ¿
+    x += ofsX;
+    y += ofsY;
+    SetPosition(x, y);
+}
+
 void UIView::LayoutLeftToSibling(const char* id, int16_t offset)
 {
     if (parent_ == nullptr) {
@@ -1234,4 +1442,18 @@ std::string UIView::GetGuiInfo() const
 {
     return "";
 }
+
+#if !ENABLE_MAP_BUFFER
+bool UIView::CheckIsNeedMapBufferToTrans(const char* funcName)
+{
+    UIViewType type = GetViewType();
+    if ((type != UI_IMAGE_VIEW) && (type != UI_TEXTURE_MAPPER) && (type != UI_CANVAS_EXT) && (type != UI_MAP_VIEW) &&
+        (type != UI_MENU_ITEM) && (type != UI_LABEL_EXT) && (type != UI_LABEL) && (type != UI_TRANSFORM_GROUP) &&
+        (type != UI_IMAGE_ANIMATOR_VIEW) && (type != UI_SLIDER) && (type != UI_LOTT_VIEW) && (type != UI_TRANSFORM_BUTTON)) {
+        GRAPHIC_LOGE("%s is not supported for view type %d if ENABLE_MAP_BUFFER is 0", funcName, type);
+        return false;
+    }
+    return true;
+}
+#endif
 } // namespace OHOS
index d14718d..14acadc 100644 (file)
@@ -170,14 +170,15 @@ void UIViewGroup::RemoveAndDeleteAllRecursively(UIViewGroup*& group)
 
     UIViewType type = group->GetViewType();
     if ((type == UI_DIGITAL_CLOCK) || (type == UI_PICKER) || (type == UI_TIME_PICKER) || (type == UI_MENU_ITEM) ||
-        (type == UI_IMAGE_PICKER) || (type == UI_ROLLER_VIEW) || (type == UI_COVER_FLOW) || (type == UI_LIST)) {
+        (type == UI_IMAGE_PICKER) || (type == UI_ROLLER_VIEW) || (type == UI_COVER_FLOW) || (type == UI_LIST) ||
+        (type == UI_OPTION_BOX) || (type == UI_VIDEO)) {
         delete group;
         group = nullptr;
         return;
     }
 
-    if (type == UI_CROSS_VIEW) {
-        GRAPHIC_LOGE("Need to remove UICardPage in UICrossView manully !!");
+    if ((type == UI_CROSS_VIEW) || (type == UI_CARD_CONTAINER) || (type == UI_SLIP_FLOW)) {
+        GRAPHIC_LOGE("Need to delete other children mannually !!");
         delete group;
         group = nullptr;
         return;
index 60f5984..26c29e9 100644 (file)
@@ -77,9 +77,12 @@ void TaskManager::TaskHandler()
         Task* currentTask = node->data_;
 #if CAPABILITY_SW_DFX_FRAME_TRACE
         TASK_TRACE_START();
+        FRAME_TRACE_BEGIN_TRACE();
 #endif
         currentTask->TaskExecute();
 #if CAPABILITY_SW_DFX_FRAME_TRACE
+        FRAME_TRACE_SHOW();
+        FRAME_TRACE_END_TRACE();
         TASK_TRACE_END();
 #endif
 
index 6a14683..2529fea 100644 (file)
@@ -23,6 +23,7 @@ namespace OHOS {
 ImageInfo checkBoxOnInfo = {0};
 ImageInfo checkBoxOffInfo = {0};
 
+#if !ENABLE_VGU_ENGINE
 const uint8_t CHECK_BOX_ON_MAP[] = {
     /* Pixel format: ARGB8888 */
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -1593,6 +1594,17 @@ void DeinitCheckBoxRes()
     checkBoxOnInfo = {{0}};
     checkBoxOffInfo = {{0}};
 }
+#else
+void InitCheckBoxRes()
+{
+
+}
+
+void DeinitCheckBoxRes()
+{
+
+}
+#endif
 
 ImageInfo* GetCheckBoxOnInfo()
 {
index c994bcc..13f0e7c 100644 (file)
@@ -196,56 +196,6 @@ void PointerInputDevice::DispatchReleaseEvent(UIViewGroup* rootView)
     touchableView_ = nullptr;
 }
 
-extern "C" {
-
-static uint16_t DRAG_LIMIT_X = INDEV_DRAG_LIMIT;
-static uint16_t DRAG_LIMIT_Y = INDEV_DRAG_LIMIT;
-/**
- * param direction 0 = X , 1 = Y
-*/
-void enable_drag(uint8_t direction, uint8_t enable)
-{
-    if (enable == 0 ) //disable drag
-    {
-        if (direction == 0) //X
-        {
-            DRAG_LIMIT_X = 0xFFFF;
-        }else{ //Y
-            DRAG_LIMIT_Y= 0xFFFF;
-        }
-    }else{ //enable drag
-        if (direction == 0) //X
-        {
-            DRAG_LIMIT_X = INDEV_DRAG_LIMIT;
-        }else{ //Y
-            DRAG_LIMIT_Y= INDEV_DRAG_LIMIT;
-        }
-    }
-
-}
-
-void set_drag_limit(uint8_t direction, uint16_t limit)
-{
-    
-    if (direction == 0) //X
-    {
-        DRAG_LIMIT_X = limit;
-    }else{ //Y
-        DRAG_LIMIT_Y= limit;
-    }
-}
-
-uint16_t get_drag_limit(uint8_t direction)
-{
-     if (direction == 0)
-     {
-        return DRAG_LIMIT_X;
-     }else{
-        return DRAG_LIMIT_Y;
-     }
-}
-
-}
 void PointerInputDevice::DispatchDragStartEvent()
 {
     if (draggableView_ == nullptr) {
@@ -256,18 +206,10 @@ void PointerInputDevice::DispatchDragStartEvent()
     dragLen_.x += dragStep_.x;
     dragLen_.y += dragStep_.y;
     if (!isDragging_) {
-        if ((MATH_ABS(dragLen_.x) >= DRAG_LIMIT_X) || (MATH_ABS(dragLen_.y) >= DRAG_LIMIT_Y)) {
-        // if ((MATH_ABS(dragLen_.x) >= INDEV_DRAG_LIMIT) || (MATH_ABS(dragLen_.y) >= INDEV_DRAG_LIMIT)) {
-            // HISI delete begin
+        if ((MATH_ABS(dragLen_.x) >= INDEV_DRAG_LIMIT) || (MATH_ABS(dragLen_.y) >= INDEV_DRAG_LIMIT)) {
             if ((touchableView_ != nullptr) && !cancelSent_) {
                 DispatchCancelEvent();
             }
-            // HISI delete end
-            // printf("=====PointerInputDevice::DispatchDragStartEvent absx(%d) limitx(%d) absy(%d) limity(%d) \r\n",
-            // MATH_ABS(dragLen_.x),DRAG_LIMIT_X,
-            // MATH_ABS(dragLen_.y),DRAG_LIMIT_Y);
-
-            // Send Drag Begin Event.
             DragEvent evt(curPos_, lastPos_, dragLen_);
             UIView* parent = draggableView_->GetParent();
             if (!draggableView_->OnDragStartEvent(evt)) {
index 9c2db2c..52c7162 100644 (file)
 
 namespace OHOS {
 BaseGfxEngine* BaseGfxEngine::baseEngine_ = nullptr;
+
+BaseGfxEngine::BaseGfxEngine()
+{
+}
+
 void BaseGfxEngine::DrawArc(BufferInfo& dst,
                             ArcInfo& arcInfo,
                             const Rect& mask,
index c3506b8..d51fdae 100644 (file)
@@ -299,8 +299,10 @@ RetCode CacheManager::TryDecode(const char* path, const Style& style, CacheEntry
     Image::ImageType type = Image::CheckImgType(path);
     if (type == Image::IMG_PNG) {
         decoder = &(PngImgDecoder::GetInstance());
+#if !CAPABILITY_HW_JPEG_DECODE
     } else if (type == Image::IMG_JPEG) {
         decoder = &(JpegImgDecoder::GetInstance());
+#endif
     }
 #endif
     if (decoder == nullptr) {
index ef1e3bc..0d6b58f 100644 (file)
@@ -156,10 +156,15 @@ public:
 
     virtual uint16_t GetScreenHeight()
     {
-        // return height_;
+               // return height_;
         return VERTICAL_RESOLUTION;
     }
 
+    virtual uint16_t GetScreenRadius()
+    {
+        return radius_;
+    }
+
     virtual void SetScreenShape(ScreenShape screenShape)
     {
         screenShape_ = screenShape;
@@ -194,11 +199,19 @@ public:
     {
         height_ = height;
     }
+
+    void SetScreenRadius(uint16_t radius)
+    {
+        radius_ = radius;
+    }
 #endif
 protected:
+    BaseGfxEngine();
     static BaseGfxEngine* baseEngine_;
     uint16_t width_ = HORIZONTAL_RESOLUTION;
     uint16_t height_ = VERTICAL_RESOLUTION;
+     /* The radius of the rounded corners for the rounded rectangle screen. The default value is 0. */
+    uint16_t radius_ = 0;
     ScreenShape screenShape_ = RECTANGLE;
 };
 }
diff --git a/code/sdk/middleware/services/gui/uikit/ui/interfaces/kits/common/alignment.h b/code/sdk/middleware/services/gui/uikit/ui/interfaces/kits/common/alignment.h
new file mode 100644 (file)
index 0000000..f0927c2
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025-2025 Huawei Device Co., Ltd.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file alignment.h
+ *
+ * @brief Define view relative alignment type.
+ *
+ * @since 1.0
+ * @version 1.0
+ */
+
+#ifndef ALIGNMENT_H
+#define ALIGNMENT_H
+namespace OHOS {
+enum AlignmentType : uint16_t {
+    ALIGN_DEFAULT      = 0xFF00,    // 默认值,不对齐
+    ALIGN_TOP_LEFT     = 0x0000,    // 控件左上角对齐到父容器内容区左上角
+    ALIGN_TOP_MID      = 0x0001,    // 控件顶部中点对齐到父容器内容区顶部中点
+    ALIGN_TOP_RIGHT    = 0x0002,    // 控件右上角对齐到父容器内容区右上角
+    ALIGN_MID_LEFT     = 0x0010,    // 控件右下角对齐到父容器内容区右下角
+    ALIGN_MID_MID      = 0x0011,    // 控件中心对齐到父容器内容区中心
+    ALIGN_MID_RIGHT    = 0x0012,    // 控件右边缘中点对齐到父容器内容区右边缘中点
+    ALIGN_BOTTOM_LEFT  = 0x0020,    // 控件左下角对齐到父容器内容区左下角
+    ALIGN_BOTTOM_MID   = 0x0021,    // 控件底部中点对齐到父容器内容区底部中点
+    ALIGN_BOTTOM_RIGHT = 0x0022,    // 控件右下角对齐到父容器内容区右下角
+    // 外部对齐方式
+    ALIGN_OUT_TOP_LEFT     = 0x1000,  // 控件左下角对齐到参考对象左上角
+    ALIGN_OUT_TOP_MID      = 0x1001,  // 控件底部中点对齐到参考对象顶部中点
+    ALIGN_OUT_TOP_RIGHT    = 0x1002,  // 控件右下角对齐到参考对象右上角
+    ALIGN_OUT_BOTTOM_LEFT  = 0x1010,  // 控件左上角对齐到参考对象左下角
+    ALIGN_OUT_BOTTOM_MID   = 0x1011,  // 控件顶部中点对齐到参考对象底部中点
+    ALIGN_OUT_BOTTOM_RIGHT = 0x1012,  // 控件右上角对齐到参考对象右下角
+    ALIGN_OUT_LEFT_TOP     = 0x1020,  // 控件右上角对齐到参考对象左上角
+    ALIGN_OUT_LEFT_MID     = 0x1021,  // 控件右侧中点对齐到参考对象左侧中点
+    ALIGN_OUT_LEFT_BOTTOM  = 0x1022,  // 控件右下角对齐到参考对象左下角
+    ALIGN_OUT_RIGHT_TOP    = 0x1030,  // 控件左上角对齐到参考对象右上角
+    ALIGN_OUT_RIGHT_MID    = 0x1031,  // 控件左侧中点对齐到参考对象右侧中点
+    ALIGN_OUT_RIGHT_BOTTOM = 0x1032,  // 控件左下角对齐到参考对象右下角
+};
+ 
+// 对齐方式编码定义
+#define ALIGN_OUTER_MASK   0x1000  // 外部对齐标志
+#define ALIGN_UP_MASK      0x00F0  // TOP|BOTTOM, LEFT|RIGHT对齐掩码
+#define ALIGN_DOWUN_MASK   0x000F  // LEFT|MID|RIGHT, TOP|MID|BOTTOM对齐掩码
+}
+#endif // ALIGNMENT_H
+/**
+ * @}
+ */
\ No newline at end of file
index f94431e..6388c60 100644 (file)
@@ -40,6 +40,7 @@
 #ifdef VERSION_IOT
 #include "gfx_utils/rect.h"
 #endif
+#include "gfx_utils/graphic_buffer.h"
 namespace OHOS {
 /**
  * @brief Represents the screen info of the device.
@@ -73,6 +74,15 @@ public:
      */
     uint16_t GetHeight();
 
+    /**
+     * @brief Obtains the radius of this screen.
+     *
+     * @return Returns the screen radius.
+     * @since 1.0
+     * @version 1.0
+     */
+    uint16_t GetRadius();
+
     /**
      * @brief 获取当前屏幕的bitmap截图.请注意该接口会申请内存,请在需要释放时使用{@link ImageCacheFree()}接口.
      * @param info bitmap存储对象,获取的截图将被存到该引用中.
@@ -90,7 +100,7 @@ public:
      * @since 5.0
      * @version 3.0
      */
-    bool GetScreenBitmapByRect(ImageInfo& info, const Rect* rect);
+    bool GetScreenBitmapByRect(ImageInfo& info, const Rect* rect, float scale = 1.0, bool isClearMem = false);
 
     /**
      * @brief 获取当前屏幕的形状.
@@ -99,6 +109,8 @@ public:
      */
     ScreenShape GetScreenShape();
 
+    bool GetBitMapFromBuffer(const BufferInfo &srcBuf, ImageInfo& info, const Rect *rect, float scale = 1.0, bool isClearMem = false);
+
 private:
     Screen() {}
     virtual ~Screen() {}
index 6db6c05..c086159 100644 (file)
@@ -51,8 +51,8 @@
 #include "events/virtual_device_event.h"
 #include "gfx_utils/list.h"
 
-#if LOCAL_RENDER
 #include <map>
+#if LOCAL_RENDER
 #include "gfx_utils/vector.h"
 #endif
 #if DOUBLE_BUFFER
@@ -452,6 +452,8 @@ private:
     void OptimizeAddRect(Rect& rect);
     void OptimizeInvalidateRects();
     List<Rect> invalidateRects_;
+    std::map<UIView*, bool> isDrawBeforeBlurViews_;
+    bool isBlurCacheNeedRefresh_ = false;
 #endif
     bool renderFlag_ = false;
     Rect invalidRect_;
index ad125bf..a9dac83 100644 (file)
@@ -481,6 +481,16 @@ public:
         enableHeadPoint_ = enable;
     }
 
+    /**
+     * @brief enableHeadPoint_.
+     *
+     * @return Returns enableHeadPoint_.
+     */
+    bool GetEnableHeadPoint() const
+    {
+        return enableHeadPoint_;
+    }
+
     /**
      * @brief Enables the feature of drawing the top point of a polyline. If there are multiple top points,
      *        only the first one is drawn.
@@ -495,6 +505,16 @@ public:
         enableTopPoint_ = enable;
     }
 
+    /**
+     * @brief enableTopPoint_.
+     *
+     * @return Returns enableTopPoint_.
+     */
+    bool GetEnableTopPoint() const
+    {
+        return enableTopPoint_;
+    }
+
     /**
      * @brief Enables the feature of drawing the bottom point of a polyline. If there are multiple bottom points,
      *        only the first one is drawn.
@@ -509,6 +529,16 @@ public:
         enableBottomPoint_ = enable;
     }
 
+    /**
+     * @brief enableBottomPoint_.
+     *
+     * @return Returns enableBottomPoint_.
+     */
+    bool GetEnableBottomPoint() const
+    {
+        return enableBottomPoint_;
+    }
+
     void DrawPoint(BufferInfo& gfxDstBuffer, const Rect& mask);
 
     void Refresh();
@@ -753,6 +783,7 @@ protected:
     void DrawDataSerials(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) override;
 
 private:
+    friend class UIChartPillarExt;
     static constexpr float DEFAULT_MARK_PERCENTAGE = 0.1f;
     VGUGradient gradient_ = {0};
     bool isDrawGradient_ = false;
index a739d31..d99b477 100644 (file)
@@ -442,6 +442,15 @@ public:
      */
     uint8_t GetAnimRealState();
 
+    void SetMarqueeBlankNum(uint16_t size)
+    {
+        marqueeBlankNum_ = size;
+    }
+
+    Text* GetLabelText()
+    {
+        return labelText_;
+    }
 #if ENABLE_FONT_VECTOR_GLOBAL
     virtual void ForceResetText() {};
 #endif
@@ -463,6 +472,8 @@ private:
     uint16_t ellipsisIndex_;
     uint16_t truncateIndex_;
     int16_t offsetX_;
+    int16_t nextOffsetX_;  // x offset of next text (circleText)
+    uint16_t marqueeBlankNum_ = 3; //The blank space after the entire text has been displayed, only used in marquee mode 
     ColorType textColor_;
 
     static constexpr uint16_t DEFAULT_ANIMATOR_SPEED = 35;
index c04ff29..fd78299 100644 (file)
@@ -324,6 +324,15 @@ public:
      */
     void SetVideoPlayerListener(VideoPlayerListener* listener);
 
+    /**
+     * @brief Get current view type.
+     *
+     */
+    UIViewType GetViewType() const override
+    {
+        return UI_VIDEO;
+    }
+ 
 private:
     class SliderAnimatorCallback : public AnimatorCallback {
     public:
index 02f2943..052e31b 100644 (file)
@@ -56,6 +56,7 @@
 #include "gfx_utils/image_info.h"
 #include "gfx_utils/style.h"
 #include "gfx_utils/transform.h"
+#include "common/alignment.h"
 
 namespace OHOS {
 /* Enumerates view types. */
@@ -115,6 +116,7 @@ enum UIViewType : uint8_t {
     UI_CARD_PAGE,
     UI_COVER_FLOW,
     UI_SLIP_FLOW,
+    UI_FOLDABLE_VIEW,
     UI_CROSS_VIEW,
     UI_BARCODE,
     UI_MAP_VIEW,
@@ -129,6 +131,20 @@ enum UIViewType : uint8_t {
     UI_WATERFALL_LIST,
     UI_SPHERE_VIEW,
     UI_PARTICLE_VIEW,
+    UI_PLANET_LIST,
+    UI_OPTION_BOX,
+    UI_CARD_CONTAINER,
+    UI_VIDEO,
+    UI_LOTT_VIEW,
+    UI_FLOAT_BOX_VIEW,
+    UI_CHART_PILLAR_EXT,
+    UI_CUSTOM_PLANET_LIST,
+    UI_LIST_EXT,
+    UI_LIST_NESTED,
+    UI_SCATTER_PLOT,
+    UI_SCROLL_VIEW_NESTED,
+    UI_SWIPE_VIEW_NESTED,
+    UI_TRANSFORM_BUTTON,
     UI_NUMBER_MAX
 };
 
@@ -1458,6 +1474,25 @@ public:
      */
     void AlignVerCenterToSibling(const char* id, int16_t offset = 0);
 
+     /**
+     * @brief  Align the view with the reference view in alignType.
+     * @param alignType Indicates the alignment relationship.
+     * @param referView Indicates the view to be aligned.
+     * @param ofsX Indicates the offset added to the x-axis after the view is alignend.
+     * @param ofsY Indicates the offset added to the y-axis after the view is alignend.
+     * @since 1.0
+     * @version 1.0
+     */
+    void AlignToReference(AlignmentType alignType, UIView* referView, int16_t ofsX = 0, int16_t ofsY = 0);
+
+    /**
+     * @brief  Update child view position when this size of parent view changed.
+     * @param view Parent view pointer, the view align with it.
+     * @since 1.0
+     * @version 1.0
+     */
+    void UpdatePos();
+
     /**
      * @brief Lays out the view on the left of a sibling view.
      * @param id Indicates the pointer to the ID of the sibling view.
@@ -1806,7 +1841,14 @@ public:
      * @brief If this view is the blurView with blurRadius, need to call this method
      *        to apply blur effect to the background.
      */
-    void HandleGaussianBlur(BufferInfo& gfxDstBuffer);
+    void HandleGaussianBlur(BufferInfo& gfxDstBuffer, bool isNeedRefresh = true);
+
+#if ENABLE_VGU_ENGINE
+    void EnableGaussianBlurCache(bool enable);
+
+    bool IsGaussianBlurCacheEnable() const;
+#endif
+
 
     /**
      * @brief Check whether this view is lite surface view or it contains lite surface view
@@ -1834,9 +1876,14 @@ protected:
     bool fullScreenBlur_ : 1;
     uint8_t opaScale_;
     int16_t index_;
+    int16_t pPrevWidth_;
+    int16_t pPrevHeight_;
+    int16_t ofsX_;
+    int16_t ofsY_;
     const char* id_;
     UIView* parent_;
     UIView* nextSibling_;
+    AlignmentType alignType_;
     Style* style_;
     TransformMap* transMap_;
     OnClickListener* onClickListener_;
@@ -1857,11 +1904,30 @@ protected:
     void DrawViewBounds(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea);
     void UpdateRectInfo(uint8_t key, const Rect& rect);
     void PrintImgInfo(const ImageInfo* info);
+    bool IsParentSizeStabled(int16_t rw, int16_t rh)
+    {
+        bool stable = (rw == pPrevWidth_ && rh == pPrevHeight_);
+        pPrevWidth_ = rw;
+        pPrevHeight_ = rh;
+        return stable;
+    }
+    void SaveBlurCache(const BufferInfo& gfxDstBuffer, const Rect &mask);
+    void DrawBlurCache(BufferInfo& gfxDstBuffer, const Rect &mask);
+    Rect GetInnerRect(const Rect &rect, int16_t topRadius, int16_t bottomRadius) const;
 
 private:
     Rect rect_;
     Rect* visibleRect_;
     void SetupThemeStyles();
+#if !ENABLE_MAP_BUFFER
+    bool CheckIsNeedMapBufferToTrans(const char* funcName);
+#endif
+#if ENABLE_VGU_ENGINE
+    BufferInfo *blurCache_ = nullptr;
+    bool isGaussCacheEnabled_ = false;
+    Rect lastBlurMask_;
+    float lastBlurRadius_ = -1.0;
+#endif
 };
 } // namespace OHOS
 #endif // GRAPHIC_LITE_UI_VIEW_H
index 10412f9..a2e41be 100644 (file)
@@ -122,8 +122,9 @@ public:
      *           don't delete it using this method unless it have been specially handled. for example:
      *           2.1 if delete all, You can delete it using this method:
      *               - UIPicker UITimePicker UIImagePicker UIDigitalClock UIRollerView UICoverFlow UIMenuItem UIList
+     *                 UIOptionBox  UIVideo
      *           2.2 if delete some, You can delete it using this method, and need to delete other children mannually:
-     *               - UICrossView
+     *               - UICrossView UICardContainer UISlipflowView
      * @since 1.0
      * @version 1.0
      */
index d544bf7..b35fbef 100644 (file)
@@ -62,6 +62,9 @@ float Acos(float value)
 #if defined(ENABLE_CMATH) && ENABLE_CMATH
     return acos(value);
 #else
+    if (value < -1.0f || value > 1.0f) {
+        return 0.0f;
+    }
     float result, l, r;
     l = 0;
     r = UI_PI;
index 89c2437..22cdef6 100644 (file)
 #endif
 
 namespace {
-#ifndef _WIN32
+#ifdef _WIN32
+constexpr int32_t HUNDRED_NS_PER_MS = 10000;
+#elif defined(_LITEOS) || defined(VERSION_IOT)
+#else
 constexpr int16_t MS_PER_SECOND = 1000;
 constexpr int32_t NS_PER_MS = 1000000;
 #endif
-constexpr int32_t HUNDRED_NS_PER_MS = 10000;
 } // namespace
 
 namespace OHOS {
index 2f8614a..852117c 100644 (file)
@@ -58,7 +58,9 @@ Style::Style()
       lineColor_(Color::GetColorFromRGB(0x20, 0x20, 0x20)),
       lineOpa_(OPA_OPAQUE),
       lineCap_(CapType::CAP_NONE),
-      lineWidth_(2) // 2 : default line width
+      lineWidth_(2), // 2 : default line width
+      topBorderRadius_(0),
+      bottomBorderRadius_(0)
 {
 }
 
@@ -71,6 +73,10 @@ int64_t Style::GetStyle(uint8_t key) const
             return bgOpa_;
         case STYLE_BORDER_RADIUS:
             return borderRadius_;
+        case STYLE_TOP_BORDER_RADIUS:
+            return topBorderRadius_ != 0 ? topBorderRadius_ : borderRadius_;
+        case STYLE_BOTTOM_BORDER_RADIUS:
+            return bottomBorderRadius_ != 0 ? bottomBorderRadius_ : borderRadius_;
         case STYLE_BORDER_COLOR:
             return borderColor_.full;
         case STYLE_BORDER_OPA:
@@ -132,6 +138,12 @@ void Style::SetStyle(uint8_t key, int64_t value)
         case STYLE_BORDER_RADIUS:
             borderRadius_ = value;
             break;
+        case STYLE_TOP_BORDER_RADIUS:
+            topBorderRadius_ = value;
+            break;
+        case STYLE_BOTTOM_BORDER_RADIUS:
+            bottomBorderRadius_ = value;
+            break;
         case STYLE_BORDER_COLOR:
             borderColor_.full = value;
             break;
index 606fd90..82edde1 100644 (file)
@@ -72,6 +72,12 @@ namespace OHOS {
  * @brief Dfx cmds, which is enabled by default.
  */
 #define ENABLE_DFX_CMD                    1
+#if ENABLE_DFX_CMD && defined(__LITEOS_M__)
+/**
+ * @brief Dfx traceui cmds, used for visualizing performance analysis
+ */
+#define ENABLE_DFX_TRACEUI                1
+#endif
 /**
  * @brief Font shaping, which is disabled by default.
  *        Cannot take effect without ENABLE_ICU.
@@ -110,20 +116,14 @@ namespace OHOS {
  * @brief Static Bitmap type font, which is disabled by default.
  */
 #define ENABLE_STATIC_FONT                0
-
-#ifdef XTS_SUPPORT
+/**
+ * @brief Jpeg and png, which is enabled by default.
+ */
 #define ENABLE_JPEG_AND_PNG               1
-#else
-#define ENABLE_JPEG_AND_PNG               0
-#endif
 /**
  * @brief Cache the decoded content for Jpeg and Png image
  */
-#ifdef XTS_SUPPORT
 #define CACHE_JPEG_AND_PNG                1
-#else
-#define CACHE_JPEG_AND_PNG                0
-#endif
 /**
  * @brief Customize the memory area when loading image resources
  */
@@ -516,6 +516,7 @@ namespace OHOS {
 #define GILROY_MEDIUM_FONT                "Gilroy_Medium.ttf"
 #define SHEEPING_CATS_FONT                "Sheeping_Cats.ttf"
 #define AUDIOWIDE_REGULAR_FONT            "Audiowide_Regular.ttf"
+#define BOLD_VECTOR_FONT_FILENAME         "HarmonyOS_Sans_SC_Bold.ttf"
 //多国语言字体
 #define KOREA_FONT                        "Orbit-Regular.ttf" //韩语
 #define HINDI_FONT                        "hindi.ttf"    //印地语
@@ -667,6 +668,8 @@ static constexpr uint16_t MAX_LINE_WIDTH = 128;
 static constexpr uint32_t QRCODE_VAL_MAX = 512;
 /* Rotate sensitivity factor. The default value is <b>1.0<b> time. */
 static constexpr float ROTATE_SENSITIVITY = 1.0;
+/* Set the drag-back area. */
+static constexpr int16_t MAX_X_IN_DRAG_REGION = HORIZONTAL_RESOLUTION;
 
 static constexpr float DEFAULT_SWIPE_VIEW_ROTATE_FACTOR = 1.4;
 static constexpr float DEFAULT_LIST_ROTATE_FACTOR = 0.6;
index f85e4be..42673c7 100644 (file)
@@ -130,7 +130,7 @@ public:
 #endif
     }
 
-    ~GraphicCond()
+    virtual ~GraphicCond()
     {
 #ifdef _WIN32
         CloseHandle(cond_);
@@ -175,7 +175,7 @@ public:
 #endif
     }
 
-private:
+protected:
 #if defined(_WIN32)
     HANDLE cond_;
 #elif defined(__FREERTOS__)
index c0a7993..bea6861 100644 (file)
@@ -49,8 +49,11 @@ enum : uint8_t {
     STYLE_BACKGROUND_COLOR,
     /** Background opacity */
     STYLE_BACKGROUND_OPA,
-    /** Border radius */
+    /** Border radius: The priority of STYLE_TOP_BORDER_RADIUS and STYLE_BOTTOM_BORDER_RADIUS is higher than that of
+       STYLE_BORDER_RADIUS. */
     STYLE_BORDER_RADIUS,
+    STYLE_TOP_BORDER_RADIUS,
+    STYLE_BOTTOM_BORDER_RADIUS,
     /** Border color */
     STYLE_BORDER_COLOR,
     /** Border opacity */
@@ -186,6 +189,10 @@ public:
     uint8_t lineOpa_;
     uint8_t lineCap_;
     int16_t lineWidth_;
+    /* extent style */
+private:
+    int16_t topBorderRadius_;
+    int16_t bottomBorderRadius_;
 };
 
 /**
index c16d6a7..beef70d 100644 (file)
@@ -20,6 +20,10 @@ if (RAM_COMPONENT_SET MATCHES "media")
     set(MODULE_NAME "media")
     set(AUTO_DEF_FILE_ID TRUE)
     add_subdirectory(foundation)
+    set(COMPONENT_FFMPEG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/component)
+    if (EXISTS ${COMPONENT_FFMPEG_DIR})
+        add_subdirectory(${COMPONENT_FFMPEG_DIR})
+    endif()
     set(COMPONENT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/component/hmf_demuxer)
     if (EXISTS ${COMPONENT_DIR})
         add_subdirectory(${COMPONENT_DIR})
index 7e96479..28e6c79 100644 (file)
@@ -15,6 +15,7 @@ if("${CHIP}" STREQUAL "brandy")
     add_subdirectory(audiomanager manager)
     add_subdirectory(player player)
     add_subdirectory(audio_capturer capturer)
+    add_subdirectory(audio_recorder recorder)
 elseif("${CHIP}" STREQUAL "socmn1")
     set(CDEFINES ${DEFINES} "ONLY_SUPPORT_HSO")
     set(CCDEFINES ${DEFINES} "ONLY_SUPPORT_HSO")
index d53c132..4c8ad5b 100644 (file)
 #include "msg_center_protocol.h"\r
 #include "cmsis_os2.h"\r
 #include "audio_capturer.h"\r
+#include "js_async_work.h"\r
 \r
 #ifdef __cplusplus\r
 extern "C" {\r
 #endif\r
-\r
-\r
+using namespace OHOS::ACELite;\r
 using namespace OHOS::Media;\r
 using namespace OHOS::Audio;\r
 using namespace::Audio;\r
@@ -42,14 +42,34 @@ using Audio::InterruptListener;
 using Audio::AudioInterrupt;\r
 using Audio::AudioManager;\r
 \r
-#define DIRECTORY_PERMISSION 0755\r
-#define PARAM_NUMBER 6\r
-#define PLAYER_CONTROL_CMD_LEN  20\r
-#define READ_RETRY_TIME_US 10000\r
-#define READ_COUNT_MAX 1000\r
-#define GET_AUDIO_TIME_INTERVAL_TIMES 100\r
-#define MAX_ARGC 5\r
-#define PATH_STR_SIZE 64\r
+const uint32_t DIRECTORY_PERMISSION = 0755;\r
+const uint32_t PARAM_NUMBER = 6;\r
+const uint32_t PLAYER_CONTROL_CMD_LEN = 20;\r
+const uint32_t READ_RETRY_TIME_US = 10000;\r
+const uint32_t READ_COUNT_MAX = 1000;\r
+const uint32_t GET_AUDIO_TIME_INTERVAL_TIMES = 100;\r
+const uint32_t MAX_ARGC = 5;\r
+const uint32_t PATH_STR_SIZE = 64;\r
+const uint32_t DEFAULT_SAMPLE_RATE = 16000;\r
+const uint32_t DEFAULT_CHANNEL_CNT = 1;\r
+const AudioBitWidth DEFAULT_BIT_WIDTH = BIT_WIDTH_16;\r
+const uint32_t DEFAULT_SAMPLE_TIME = 10; // ms\r
+const uint32_t SECOND_TO_MICROSECOND = 1000;\r
+const uint32_t BYTE_SIZE = 8;\r
+const uint32_t OPUS_HEAD_LEN = 8;\r
+const uint32_t DEFAULT_BUFFER_SIZE = DEFAULT_SAMPLE_RATE *\r
+                                    DEFAULT_BIT_WIDTH / BYTE_SIZE *\r
+                                    DEFAULT_SAMPLE_TIME / SECOND_TO_MICROSECOND *\r
+                                    DEFAULT_CHANNEL_CNT * 2; // equals 2 pcm frames size\r
+const char XIAODU_VOICE[] = "XiaoduVoice";\r
+const char AUDIO_CAPTURER[] = "AudioCapturer";\r
+const char PROP_SUCCESS[] = "success";\r
+const char PROP_FAIL[] = "fail";\r
+const char PROP_BUFFER_SIZE[] = "framesize";\r
+const char PROP_FORMAT[] = "format";\r
+const char PROP_SAMPLE_RATE[] = "samplerate";\r
+const char PROP_BITEWIDTH[] = "bitwidth";\r
+const char PROP_CHANNEL_CNT[] = "channelcnt";\r
 \r
 struct SampleAudioCapturerInfo {\r
     /** Audio source type */\r
@@ -57,15 +77,15 @@ struct SampleAudioCapturerInfo {
     /** Audio codec format */\r
     AudioCodecFormat audioFormat = AUDIO_DEFAULT;\r
     /** Sampling rate */\r
-    int32_t sampleRate = 0;\r
+    int32_t sampleRate = DEFAULT_SAMPLE_RATE;\r
     /** Bit rate */\r
     int32_t bitRate = 0;\r
     /** Number of audio channels */\r
-    int32_t channelCount = 0;\r
+    int32_t channelCount = DEFAULT_CHANNEL_CNT;\r
     /** Audio stream type */\r
     AudioStreamType streamType = TYPE_MEDIA;\r
     /** Bit width */\r
-    AudioBitWidth bitWidth = BIT_WIDTH_16;\r
+    AudioBitWidth bitWidth = DEFAULT_BIT_WIDTH;\r
     /** Session id */\r
     AudioSession sessionID = AUDIO_SESSION_ID_NONE;\r
 };\r
@@ -75,20 +95,37 @@ struct NameAudioFormat {
     AudioCodecFormat audioFormat;\r
 };\r
 \r
-typedef struct {\r
+typedef struct AudioSourceInput {\r
     size_t framesize;\r
+    int32_t buffersize = DEFAULT_BUFFER_SIZE;\r
     uint8_t *buffer;\r
+    uint8_t *storedBuffer;\r
     AudioCapturer *audioCap;\r
     AudioCodecFormat audioFormat;\r
-    bool bThreadRun;\r
+#ifdef SAVE_LOCAL_FILE\r
+    FILE *fd;\r
+#endif\r
 } AudioSourceInput;\r
 \r
-typedef struct TagTestSample {\r
+struct JsCaptureParams {\r
+    JSIValue thisVal = JSI::CreateUndefined();\r
+    JSIValue successCb = JSI::CreateUndefined();\r
+    JSIValue failCb = JSI::CreateUndefined();\r
+};\r
+\r
+typedef enum AudioCapturerState {\r
+    OFF = 0,\r
+    ON,\r
+} AudioCapturerState;\r
+\r
+typedef struct JsCapturerContext {\r
     char control[PLAYER_CONTROL_CMD_LEN];\r
     bool needStop;\r
+    AudioCapturerState capturerState;\r
+    AudioCapturerState listenerState;\r
     AudioInterrupt interrupt;\r
     MediaThreadIdHandle audioCaptureProcess;\r
-} TestSample;\r
+} JsCapturerContext;\r
 \r
 static NameAudioFormat g_audioCodecFormat[] = {\r
     {"mp3", MP3},\r
@@ -107,7 +144,7 @@ static NameAudioFormat g_audioCodecFormat[] = {
 \r
 static bool g_interruptHintStop = false;\r
 static std::shared_ptr<AudioCapturer> g_audioCap;\r
-\r
+static MediaMutexHandle g_jsCaptureMutex = nullptr;\r
 class CaptureInterruptListener : public InterruptListener {\r
 public:\r
     CaptureInterruptListener() {};\r
@@ -132,8 +169,28 @@ public:
 \r
 static AudioSourceInput g_audioSourceProcessInput;\r
 static AudioManager& g_amInstance = AudioManager::GetInstance();\r
-static TestSample g_sample;\r
+static JsCapturerContext g_capturerCtx;\r
 static std::shared_ptr<CaptureInterruptListener> g_captureInterruptListener;\r
+static struct JsCaptureParams g_jsCaptureParams;\r
+\r
+static void InitResource()\r
+{\r
+    g_jsCaptureParams.thisVal = JSI::CreateUndefined();\r
+    g_jsCaptureParams.successCb = JSI::CreateUndefined();\r
+    g_jsCaptureParams.failCb = JSI::CreateUndefined();\r
+    g_jsCaptureMutex = MediaMutexCreate(nullptr);\r
+}\r
+\r
+static void DestroyResource()\r
+{\r
+    JSI::ReleaseValueList(g_jsCaptureParams.thisVal,\r
+        g_jsCaptureParams.successCb,\r
+        g_jsCaptureParams.failCb);\r
+    g_jsCaptureParams.thisVal = JSI::CreateUndefined();\r
+    g_jsCaptureParams.successCb = JSI::CreateUndefined();\r
+    g_jsCaptureParams.failCb = JSI::CreateUndefined();\r
+    MediaMutexDestroy(&g_jsCaptureMutex);\r
+}\r
 \r
 static void AudioCaptureExit()\r
 {\r
@@ -147,22 +204,50 @@ static void AudioCaptureExit()
     delete g_audioSourceProcessInput.buffer;\r
     g_audioSourceProcessInput.buffer = nullptr;\r
 \r
-    if (g_amInstance.DeactivateAudioInterrupt(g_sample.interrupt) != 0) {\r
+    if (g_amInstance.DeactivateAudioInterrupt(g_capturerCtx.interrupt) != 0) {\r
         MEDIA_ERR_LOG("record deactivate audio interrupt failed");\r
     }\r
     g_audioCap.reset();\r
-    g_audioSourceProcessInput.bThreadRun = false;\r
     MEDIA_INFO_LOG("record AudioCaptureProcess end");\r
 }\r
 \r
+static void SuccessCallBackDispatch(void *arg)\r
+{\r
+    JSIValue *jsiValue = (JSIValue *)arg;\r
+    if (JSI::ValueIsUndefined(g_jsCaptureParams.successCb)) {\r
+        MEDIA_ERR_LOG("success cbk undefined!");\r
+        return;\r
+    }\r
+    if (JSI::ValueIsUndefined(*jsiValue)) {\r
+        JSI::CallFunction(g_jsCaptureParams.successCb, g_jsCaptureParams.thisVal, nullptr, 0);\r
+    } else {\r
+        JSI::CallFunction(g_jsCaptureParams.successCb, g_jsCaptureParams.thisVal, jsiValue, ARGC_ONE);\r
+    }\r
+}\r
+\r
+static void SuccessCallBack(JSIValue *jsiValue)\r
+{\r
+    JsAsyncWork::DispatchAsyncWork(SuccessCallBackDispatch, static_cast<void *>(jsiValue));\r
+}\r
+\r
+static void FailCallBack(int ret, const char* errLog)\r
+{\r
+    JSIValue errCode = JSI::CreateNumber(ret);\r
+    JSIValue errInfo = JSI::CreateString(errLog);\r
+    JSIValue argv[ARGC_TWO] = {errInfo, errCode};\r
+    if (!JSI::ValueIsUndefined(g_jsCaptureParams.failCb)) {\r
+        JSI::CallFunction(g_jsCaptureParams.failCb, g_jsCaptureParams.thisVal, argv, ARGC_TWO);\r
+    }\r
+    JSI::ReleaseValueList(errInfo, errCode, ARGS_END);\r
+}\r
+\r
 static void* AudioCaptureProcess(void* arg)\r
 {\r
     MEDIA_UNUSED(arg);\r
     int32_t readCnt = 0;\r
     Timestamp timeStamp;\r
-    g_audioSourceProcessInput.bThreadRun = true;\r
     pcm_stream_queue_msg msg = {MSGCENTER_TYPE_ID_XIAODU_SEND_PCM_STREAM, nullptr, 0};\r
-    while (!g_sample.needStop && !g_interruptHintStop) {\r
+    while (!g_capturerCtx.needStop && !g_interruptHintStop) {\r
         int32_t ret = g_audioCap->Read(g_audioSourceProcessInput.buffer, g_audioSourceProcessInput.framesize, false);\r
         if (ret == -1) {\r
             MEDIA_ERR_LOG("audio recording failed:0x%x", ret);\r
@@ -203,24 +288,159 @@ static void* AudioCaptureProcess(void* arg)
     return nullptr;\r
 }\r
 \r
-static void AudioCaptureGetFormat(const char **argv, AudioCodecFormat &audioFormat)\r
+static int32_t SendBuffer(int32_t &bufferOffset, const int32_t readLen)\r
 {\r
-    char formatType[10];\r
-    if (strncpy_s(formatType, sizeof(formatType), argv[0x1], strlen(argv[0x1])) != 0) {\r
-        MEDIA_ERR_LOG("record strncpy_s failed");\r
+    int32_t outDataSize = 0;\r
+    outDataSize = bufferOffset >=  g_audioSourceProcessInput.buffersize ?\r
+        g_audioSourceProcessInput.buffersize : bufferOffset;\r
+    if (bufferOffset + readLen >= static_cast<int32_t>(g_audioSourceProcessInput.buffersize) ||\r
+        g_capturerCtx.needStop) {\r
+        uint8_t *arrayPtr = nullptr;\r
+        JSIValue result = JSI::CreateObject();\r
+        JSIValue arrayBuffer = JSI::CreateArrayBuffer(bufferOffset, arrayPtr);\r
+        if (memcpy_s(arrayPtr, bufferOffset,\r
+            g_audioSourceProcessInput.storedBuffer,\r
+            bufferOffset) != 0) {\r
+            JSI::ReleaseValueList(result, arrayBuffer);\r
+            FailCallBack(MEDIA_ERR, "memcpy failed!");\r
+            MEDIA_ERR_LOG("memcpy failed!");\r
+            return MEDIA_ERR;\r
+        }\r
+        JSI::SetNumberProperty(result, "ret", MEDIA_OK);\r
+        JSI::SetNumberProperty(result, "dataLen", bufferOffset);\r
+        JSI::SetNamedProperty(result, "data", arrayBuffer);\r
+        SuccessCallBack(&result);\r
+        JSI::ReleaseValueList(result, arrayBuffer);\r
+        if (memset_s(g_audioSourceProcessInput.storedBuffer, outDataSize, 0, outDataSize) != 0) {\r
+            FailCallBack(MEDIA_ERR, "memset_s failed!");\r
+            MEDIA_ERR_LOG("memset_s failed!");\r
+            return MEDIA_ERR;\r
+        }\r
+        bufferOffset = 0;\r
+    }\r
+    int32_t readOffset = g_audioSourceProcessInput.audioFormat == OPUS ?\r
+        OPUS_HEAD_LEN : 0;\r
+    if (memcpy_s(g_audioSourceProcessInput.storedBuffer + bufferOffset,\r
+        g_audioSourceProcessInput.buffersize - bufferOffset,\r
+        g_audioSourceProcessInput.buffer + readOffset,\r
+        readLen - readOffset) != 0) {\r
+        FailCallBack(MEDIA_ERR, "memcpy failed!");\r
+        MEDIA_ERR_LOG("memcpy failed!");\r
+        return MEDIA_ERR;\r
     }\r
-    std::string inputFormat = formatType;\r
+    bufferOffset += readLen;\r
+    return MEDIA_OK;\r
+}\r
+\r
+static void* AudioStreamCaptureProcess(void* arg)\r
+{\r
+    int32_t bufferOffset = 0;\r
+    g_audioSourceProcessInput.storedBuffer = new uint8_t[g_audioSourceProcessInput.buffersize];\r
+    MEDIA_INFO_LOG("start audio capture");\r
+    while (true) {\r
+        MediaMutexLock(g_jsCaptureMutex);\r
+        if (g_capturerCtx.needStop || g_interruptHintStop) {\r
+            MediaMutexUnLock(g_jsCaptureMutex);\r
+            break;\r
+        }\r
+        int32_t readLen = g_audioCap->Read(g_audioSourceProcessInput.buffer,\r
+            g_audioSourceProcessInput.framesize, false);\r
+        if (readLen <= 0) {\r
+            usleep(READ_RETRY_TIME_US);\r
+            MediaMutexUnLock(g_jsCaptureMutex);\r
+            continue;\r
+        }\r
+#ifdef SAVE_LOCAL_FILE\r
+        uint32_t writeLen = fwrite(g_audioSourceProcessInput.buffer, 1, readLen, g_audioSourceProcessInput.fd);\r
+        if (writeLen != (uint32_t)readLen) {\r
+            MEDIA_ERR_LOG("errno:%d, errmsg:%s", errno, strerror(errno));\r
+            MediaMutexUnLock(g_jsCaptureMutex);\r
+            break;\r
+        }\r
+#endif\r
+        if (SendBuffer(bufferOffset, readLen) != MEDIA_OK) {\r
+            MediaMutexUnLock(g_jsCaptureMutex);\r
+            MEDIA_ERR_LOG("SendBuffer failed");\r
+            break;\r
+        }\r
+        MediaMutexUnLock(g_jsCaptureMutex);\r
+    }\r
+    if (bufferOffset != 0) {\r
+        MediaMutexLock(g_jsCaptureMutex);\r
+        SendBuffer(bufferOffset, 0);\r
+        MediaMutexUnLock(g_jsCaptureMutex);\r
+    }\r
+#ifdef SAVE_LOCAL_FILE\r
+    fclose(g_audioSourceProcessInput.fd);\r
+    g_audioSourceProcessInput.fd = nullptr;\r
+#endif\r
+    delete g_audioSourceProcessInput.storedBuffer;\r
+    AudioCaptureExit();\r
+    MEDIA_INFO_LOG("exit audio captrue");\r
+    return nullptr;\r
+}\r
+\r
+static int32_t AudioCaptureGetFormat(const char *format, AudioCodecFormat &audioFormat)\r
+{\r
+    std::string inputFormat = format;\r
     for (size_t i = 0; i < (sizeof(g_audioCodecFormat) / sizeof(g_audioCodecFormat[0])); i++) {\r
         if (inputFormat == g_audioCodecFormat[i].name) {\r
             audioFormat = g_audioCodecFormat[i].audioFormat;\r
             MEDIA_INFO_LOG("record [AudioCaptureSample] set audioFormat %s", g_audioCodecFormat[i].name.c_str());\r
+            return MEDIA_OK;\r
+        }\r
+    }\r
+    MEDIA_ERR_LOG("invalid input format!");\r
+    return MEDIA_INVALID_PARAM;\r
+}\r
+\r
+static int32_t AudioStreamCaptureGetInfo(const JSIValue* argv, SampleAudioCapturerInfo &audioCapturerInfo)\r
+{\r
+    JSIValue buffersize = JSI::GetNamedProperty(argv[0], PROP_BUFFER_SIZE);\r
+    if (JSI::ValueIsUndefined(buffersize)) {\r
+        FailCallBack(MEDIA_ERR, "invalid buffer size!");\r
+        JSI::ReleaseValueList(buffersize);\r
+        return MEDIA_ERR;\r
+    }\r
+    int32_t size = static_cast<int32_t>(JSI::ValueToNumber(buffersize));\r
+    /* 1: buffersize */\r
+    g_audioSourceProcessInput.buffersize = size < DEFAULT_BUFFER_SIZE ? DEFAULT_BUFFER_SIZE : size;\r
+    MEDIA_INFO_LOG("record set capture parameter buffersize:%d", g_audioSourceProcessInput.buffersize);\r
+    JSIValue format = JSI::GetNamedProperty(argv[0], PROP_FORMAT);\r
+    if (!JSI::ValueIsUndefined(format)) {\r
+        /* 2: audioFormat */\r
+        if (AudioCaptureGetFormat(JSI::ValueToString(format), audioCapturerInfo.audioFormat) != MEDIA_OK) {\r
+            FailCallBack(MEDIA_ERR, "invalld format!");\r
+            JSI::ReleaseValueList(buffersize, format);\r
+            return MEDIA_ERR;\r
         }\r
+        MEDIA_INFO_LOG("record set capture parameter audioFormat:%d", audioCapturerInfo.audioFormat);\r
+    }\r
+    JSIValue sampleRate = JSI::GetNamedProperty(argv[0], PROP_SAMPLE_RATE);\r
+    if (!JSI::ValueIsUndefined(sampleRate)) {\r
+        /* 3: samplerate */\r
+        audioCapturerInfo.sampleRate = static_cast<int32_t>(JSI::ValueToNumber(sampleRate));\r
+        MEDIA_INFO_LOG("record set capture parameter sampleRate:%d", audioCapturerInfo.sampleRate);\r
+    }\r
+    JSIValue channelCount = JSI::GetNamedProperty(argv[0], PROP_CHANNEL_CNT);\r
+    if (!JSI::ValueIsUndefined(channelCount)) {\r
+        /* 4: channelCount */\r
+        audioCapturerInfo.channelCount = static_cast<int32_t>(JSI::ValueToNumber(channelCount));\r
+        MEDIA_INFO_LOG("record set capture parameter channelCount:%d", audioCapturerInfo.channelCount);\r
     }\r
+    JSIValue bitWidth = JSI::GetNamedProperty(argv[0], PROP_BITEWIDTH);\r
+    if (!JSI::ValueIsUndefined(bitWidth)) {\r
+        /* 5: bitWidth */\r
+        audioCapturerInfo.bitWidth = static_cast<AudioBitWidth>((AudioBitWidth)JSI::ValueToNumber(bitWidth));\r
+        MEDIA_INFO_LOG("record set capture parameter bitWidth:%d", audioCapturerInfo.bitWidth);\r
+    }\r
+    JSI::ReleaseValueList(buffersize, format, sampleRate, channelCount, bitWidth);\r
+    return MEDIA_OK;\r
 }\r
 \r
 static int32_t AudioCaptureGetInfo(const char **argv, SampleAudioCapturerInfo &audioCapturerInfo, std::string &filePath)\r
 {\r
-    AudioCaptureGetFormat(argv, audioCapturerInfo.audioFormat);\r
+    AudioCaptureGetFormat(argv[0x1], audioCapturerInfo.audioFormat);\r
     audioCapturerInfo.sampleRate = atoi(argv[0x2]); /* 2: samplerate */\r
     MEDIA_INFO_LOG("record set capture parameter sampleRate:%d", audioCapturerInfo.sampleRate);\r
     audioCapturerInfo.channelCount = atoi(argv[0x3]); /* 3: channel */\r
@@ -229,7 +449,7 @@ static int32_t AudioCaptureGetInfo(const char **argv, SampleAudioCapturerInfo &a
     MEDIA_INFO_LOG("record set capture parameter bitWidth:%d", audioCapturerInfo.bitWidth);\r
     MEDIA_INFO_LOG("record input argv[5]:%s.", argv[5]); /* 5: filePath */\r
 \r
-    if (strlen(argv[0x5]) < PATH_MAX) {\r
+    if (std::strlen(argv[0x5]) < PATH_MAX) {\r
         filePath = argv[0x5];\r
     } else {\r
         MEDIA_ERR_LOG("record input path too long");\r
@@ -258,15 +478,16 @@ static int32_t AudioCaptureSetInfo(SampleAudioCapturerInfo audioCapturerInfo)
         return -1;\r
     }\r
     size_t frameCount = g_audioCap->GetFrameCount();\r
-    if (!frameCount) {\r
+    if (frameCount == 0) {\r
         MEDIA_ERR_LOG("record Can't GetFrameCount");\r
         (void)g_audioCap->Release();\r
         return -1;\r
     }\r
     MEDIA_INFO_LOG("GetFrameCount:%d", frameCount);\r
-    g_audioSourceProcessInput.framesize = frameCount * info.channelCount * info.bitWidth / 8; /* 8: byte width */\r
+    g_audioSourceProcessInput.framesize = frameCount * info.channelCount * info.bitWidth / BYTE_SIZE;\r
     g_audioSourceProcessInput.buffer = new uint8_t[g_audioSourceProcessInput.framesize];\r
     if (g_audioSourceProcessInput.buffer == nullptr) {\r
+        MEDIA_ERR_LOG("buffer malloc fail");\r
         (void)g_audioCap->Release();\r
         return -1;\r
     }\r
@@ -280,23 +501,26 @@ static int32_t AudioCaptureSetInfo(SampleAudioCapturerInfo audioCapturerInfo)
     return 0;\r
 }\r
 \r
-static int32_t ActivateAudioInterrupt(AudioSession &sessionId)\r
+static int32_t ActivateAudioInterrupt(AudioSession &sessionId, AudioStreamType type)\r
 {\r
     g_amInstance.Initialize();\r
     sessionId = g_amInstance.MakeSessionId();\r
     if (sessionId == AUDIO_SESSION_ID_NONE) {\r
         MEDIA_ERR_LOG("record session is none");\r
-        return -1;\r
+        return MEDIA_ERR;\r
     }\r
     MEDIA_INFO_LOG("sessionId:%d", sessionId);\r
     g_captureInterruptListener = std::make_shared<CaptureInterruptListener>();\r
-    g_sample.interrupt = { AUDIO_STREAM_VOICE_ASSISTANT, sessionId, g_captureInterruptListener };\r
-\r
-    if (g_amInstance.ActivateAudioInterrupt(g_sample.interrupt) == INTERRUPT_FAILED) {\r
+    if (g_captureInterruptListener.get() == nullptr) {\r
+        MEDIA_ERR_LOG("g_captureInterruptListener create failed!");\r
+        return MEDIA_ERR;\r
+    }\r
+    g_capturerCtx.interrupt = { type, sessionId, g_captureInterruptListener };\r
+    if (g_amInstance.ActivateAudioInterrupt(g_capturerCtx.interrupt) == INTERRUPT_FAILED) {\r
         MEDIA_ERR_LOG("record ActivateAudioInterrupt failed");\r
-        return -1;\r
+        return MEDIA_ERR;\r
     }\r
-    return 0;\r
+    return MEDIA_OK;\r
 }\r
 \r
 static int32_t CheckInputParam(int32_t argc, const char **argv)\r
@@ -336,6 +560,51 @@ int MakeAudioDir(const char *dir)
     return 0;\r
 }\r
 \r
+static int32_t AudioStreamCaptureInit(const JSIValue *argv)\r
+{\r
+    SampleAudioCapturerInfo audioCapturerInfo;\r
+    int32_t ret = AudioStreamCaptureGetInfo(argv, audioCapturerInfo);\r
+    if (ret != 0) {\r
+        return ret;\r
+    }\r
+\r
+    AudioSession sessionId = AUDIO_SESSION_ID_NONE;\r
+    ret = ActivateAudioInterrupt(sessionId, AUDIO_STREAM_VOICE_RECORD);\r
+    if (ret != 0) {\r
+        return ret;\r
+    }\r
+    g_audioCap = std::make_shared<AudioCapturer>();\r
+    if (g_audioCap.get() == nullptr) {\r
+        MEDIA_ERR_LOG("audio capture is nullptr");\r
+        (void)g_amInstance.DeactivateAudioInterrupt(g_capturerCtx.interrupt);\r
+        return -1;\r
+    }\r
+#ifdef SAVE_LOCAL_FILE\r
+    g_audioSourceProcessInput.fd = fopen("/user/js_audio_cap.mp3", "w+");\r
+    if (g_audioSourceProcessInput.fd == nullptr) {\r
+        MEDIA_ERR_LOG("open file failed");\r
+        g_audioCap.reset();\r
+        (void)g_amInstance.DeactivateAudioInterrupt(g_capturerCtx.interrupt);\r
+        return -1;\r
+    }\r
+#endif\r
+    audioCapturerInfo.sessionID = sessionId;\r
+    audioCapturerInfo.inputSource = AUDIO_MIC;\r
+    audioCapturerInfo.streamType = AUDIO_STREAM_VOICE_RECORD;\r
+    ret = AudioCaptureSetInfo(audioCapturerInfo);\r
+    if (ret != 0) {\r
+#ifdef SAVE_LOCAL_FILE\r
+        fclose(g_audioSourceProcessInput.fd);\r
+        g_audioSourceProcessInput.fd = nullptr;\r
+#endif\r
+        g_audioCap.reset();\r
+        (void)g_amInstance.DeactivateAudioInterrupt(g_capturerCtx.interrupt);\r
+        FailCallBack(MEDIA_ERR, "set info failed!");\r
+        return ret;\r
+    }\r
+    return ret;\r
+}\r
+\r
 static int32_t AudioCaptureInit(const char **argv)\r
 {\r
     SampleAudioCapturerInfo audioCapturerInfo = {};\r
@@ -346,14 +615,14 @@ static int32_t AudioCaptureInit(const char **argv)
     }\r
 \r
     AudioSession sessionId = AUDIO_SESSION_ID_NONE;\r
-    ret = ActivateAudioInterrupt(sessionId);\r
+    ret = ActivateAudioInterrupt(sessionId, AUDIO_STREAM_VOICE_ASSISTANT);\r
     if (ret != 0) {\r
         return ret;\r
     }\r
     g_audioCap = std::make_shared<AudioCapturer>();\r
-    if (g_audioCap == nullptr || g_audioCap.get() == nullptr) {\r
+    if (g_audioCap.get() == nullptr) {\r
         MEDIA_ERR_LOG("audio capture is nullptr");\r
-        (void)g_amInstance.DeactivateAudioInterrupt(g_sample.interrupt);\r
+        (void)g_amInstance.DeactivateAudioInterrupt(g_capturerCtx.interrupt);\r
         return -1;\r
     }\r
 \r
@@ -369,7 +638,7 @@ static int32_t AudioCaptureInit(const char **argv)
     ret = AudioCaptureSetInfo(audioCapturerInfo);\r
     if (ret != 0) {\r
         g_audioCap.reset();\r
-        (void)g_amInstance.DeactivateAudioInterrupt(g_sample.interrupt);\r
+        (void)g_amInstance.DeactivateAudioInterrupt(g_capturerCtx.interrupt);\r
         return ret;\r
     }\r
     return ret;\r
@@ -377,7 +646,6 @@ static int32_t AudioCaptureInit(const char **argv)
 \r
 int32_t AudioCaptureStartSample(int32_t argc, const char **argv)\r
 {\r
-    errcode_t res;\r
     for (int32_t i = 0; i < argc; i++) {\r
         MEDIA_INFO_LOG("argv[%d]:%s", i, argv[i]);\r
     }\r
@@ -386,7 +654,7 @@ int32_t AudioCaptureStartSample(int32_t argc, const char **argv)
         return ret;\r
     }\r
 \r
-    g_sample.needStop = false;\r
+    g_capturerCtx.needStop = false;\r
     g_interruptHintStop = false;\r
     ret = AudioCaptureInit(argv);\r
     if (ret != 0) {\r
@@ -401,19 +669,35 @@ int32_t AudioCaptureStartSample(int32_t argc, const char **argv)
     }\r
 \r
     MediaThreadattr attr = { "AudioCaptureTask", 0x2000, THREAD_SCHED_INVALID, 0, false };\r
-    g_sample.audioCaptureProcess = MediaThreadCreate(AudioCaptureProcess, nullptr, &attr);\r
-    if (g_sample.audioCaptureProcess == nullptr) {\r
+    g_capturerCtx.audioCaptureProcess = MediaThreadCreate(AudioCaptureProcess, nullptr, &attr);\r
+    if (g_capturerCtx.audioCaptureProcess == nullptr) {\r
         MEDIA_ERR_LOG("thread create failed");\r
         return -1;\r
     }\r
 \r
     /* send record start */\r
-    res = msg_center_xiaodu_start_record(MSGCENTER_CMD_XIAODU, MSGCENTER_TYPE_ID_XIAODU_START_RECORD, NULL, 0);\r
+    errcode_t res = msg_center_xiaodu_start_record(MSGCENTER_CMD_XIAODU, MSGCENTER_TYPE_ID_XIAODU_START_RECORD, NULL, 0);\r
     if (res != ERRCODE_SUCC) {\r
         MEDIA_ERR_LOG("send start fail.\r\n");\r
         return res;\r
     }\r
+    return 0;\r
+}\r
 \r
+static int32_t AudioStreamCaptureStart(const JSIValue *args)\r
+{\r
+    g_capturerCtx.needStop = false;\r
+    g_interruptHintStop = false;\r
+    int32_t ret = AudioStreamCaptureInit(args);\r
+    if (ret != 0) {\r
+        return ret;\r
+    }\r
+    MediaThreadattr attr = { "AudioStreamCaptureProcess", 0x4000, THREAD_SCHED_INVALID, 0, false };\r
+    g_capturerCtx.audioCaptureProcess = MediaThreadCreate(AudioStreamCaptureProcess, nullptr, &attr);\r
+    if (g_capturerCtx.audioCaptureProcess == nullptr) {\r
+        MEDIA_ERR_LOG("thread create failed");\r
+        return -1;\r
+    }\r
     return 0;\r
 }\r
 \r
@@ -428,8 +712,53 @@ JSIValue AudioCapturerModule::Start(const JSIValue thisVal, const JSIValue *args
     MEDIA_UNUSED(thisVal);\r
     MEDIA_UNUSED(args);\r
     MEDIA_UNUSED(argsSize);\r
-    const char *pars[6] = { "", "opus", "16000", "1", "16", "/user/log/xiaodu/xiaodu.opus" };\r
-    return JSI::CreateBoolean(AudioCaptureStartSample(PARAM_NUMBER, pars));\r
+    const char *params[PARAM_NUMBER] = { "", "opus", "16000", "1", "16", "/user/log/xiaodu/xiaodu.opus" };\r
+    return JSI::CreateBoolean(AudioCaptureStartSample(PARAM_NUMBER, params));\r
+}\r
+\r
+JSIValue AudioCapturerModule::start(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    if (argsSize == 0) {\r
+        const char *params[PARAM_NUMBER] = { "", "opus", "16000", "1", "16", "/user/log/xiaodu/xiaodu.opus" };\r
+        return JSI::CreateBoolean(AudioCaptureStartSample(PARAM_NUMBER, params));\r
+    }\r
+    if (g_capturerCtx.capturerState == ON) {\r
+        FailCallBack(MEDIA_OK, "Already start,no need to start!");\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    if (args == nullptr || JSI::ValueIsUndefined(args[0])) {\r
+        FailCallBack(MEDIA_ERR, "invalid parameter!");\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    if (g_capturerCtx.listenerState == OFF) {\r
+        InitResource();\r
+    }\r
+    if (AudioStreamCaptureStart(args) != MEDIA_OK) {\r
+        FailCallBack(MEDIA_ERR, "Start AudioCapturer fail!");\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    g_capturerCtx.capturerState = ON;\r
+    return JSI::CreateBoolean(true);\r
+}\r
+\r
+JSIValue AudioCapturerModule::stop(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    if (g_capturerCtx.capturerState == OFF) {\r
+        FailCallBack(MEDIA_ERR, "Already stop, no need to stop");\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    MEDIA_UNUSED(thisVal);\r
+    MEDIA_UNUSED(args);\r
+    MEDIA_UNUSED(argsSize);\r
+    MediaMutexLock(g_jsCaptureMutex);\r
+    g_capturerCtx.needStop = true;\r
+    MediaMutexUnLock(g_jsCaptureMutex);\r
+    MediaThreadJoin(&g_capturerCtx.audioCaptureProcess);\r
+    if (g_capturerCtx.listenerState == OFF) {\r
+        DestroyResource();\r
+    }\r
+    g_capturerCtx.capturerState = OFF;\r
+    return JSI::CreateBoolean(true);\r
 }\r
 \r
 JSIValue AudioCapturerModule::Stop(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
@@ -437,9 +766,54 @@ JSIValue AudioCapturerModule::Stop(const JSIValue thisVal, const JSIValue *args,
     MEDIA_UNUSED(thisVal);\r
     MEDIA_UNUSED(args);\r
     MEDIA_UNUSED(argsSize);\r
-    g_sample.needStop = true;\r
-    MediaThreadJoin(&g_sample.audioCaptureProcess);\r
-    return JSI::CreateBoolean(0);\r
+    g_capturerCtx.needStop = true;\r
+    MediaThreadJoin(&g_capturerCtx.audioCaptureProcess);\r
+    return JSI::CreateBoolean(true);\r
+}\r
+\r
+JSIValue AudioCapturerModule::ListenerOn(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    if (g_capturerCtx.listenerState == ON) {\r
+        FailCallBack(MEDIA_OK, "No need to turn on!");\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    if (args == nullptr || argsSize == 0) {\r
+        FailCallBack(MEDIA_OK, "invalid parameter!");\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    if (!JSI::ValueIsObject(args[0])) {\r
+        FailCallBack(MEDIA_OK, "invalid object!");\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    if (g_capturerCtx.capturerState == OFF) {\r
+        InitResource();\r
+    }\r
+    MediaMutexLock(g_jsCaptureMutex);\r
+    g_jsCaptureParams.thisVal = JSI::AcquireValue(thisVal);\r
+    g_jsCaptureParams.successCb = JSI::GetNamedProperty(args[0], PROP_SUCCESS);\r
+    g_jsCaptureParams.failCb = JSI::GetNamedProperty(args[0], PROP_FAIL);\r
+    g_capturerCtx.listenerState = ON;\r
+    MediaMutexUnLock(g_jsCaptureMutex);\r
+    return JSI::CreateBoolean(SUCCESS);\r
+}\r
+\r
+JSIValue AudioCapturerModule::ListenerOff(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    if (g_capturerCtx.listenerState == OFF) {\r
+        FailCallBack(MEDIA_ERR, "Already off, no need to start!");\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    MediaMutexLock(g_jsCaptureMutex);\r
+    if (!JSI::ValueIsUndefined(g_jsCaptureParams.successCb)) {\r
+        JSI::ReleaseValueList(g_jsCaptureParams.successCb);\r
+        g_jsCaptureParams.successCb = JSI::CreateUndefined();\r
+    }\r
+    MediaMutexUnLock(g_jsCaptureMutex);\r
+    if (g_capturerCtx.capturerState == OFF) {\r
+        DestroyResource();\r
+    }\r
+    g_capturerCtx.listenerState = OFF;\r
+    return JSI::CreateBoolean(SUCCESS);\r
 }\r
 \r
 JSIValue AudioCapturerModule::Cancel(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
@@ -453,9 +827,37 @@ JSIValue AudioCapturerModule::Cancel(const JSIValue thisVal, const JSIValue *arg
 \r
 void AudioCapturerModule::ExceptionStop(void)\r
 {\r
-    if (g_sample.needStop == false) {\r
-        g_sample.needStop = true;\r
+    if (!g_capturerCtx.needStop) {\r
+        g_capturerCtx.needStop = true;\r
+    }\r
+}\r
+\r
+void AudioCapturerModule::OnDestroy()\r
+{\r
+    if (g_capturerCtx.listenerState == OFF && g_capturerCtx.capturerState == OFF) {\r
+        return;\r
+    }\r
+    MediaMutexLock(g_jsCaptureMutex);\r
+    g_capturerCtx.needStop = true;\r
+    MediaMutexUnLock(g_jsCaptureMutex);\r
+    MediaThreadJoin(&g_capturerCtx.audioCaptureProcess);\r
+    DestroyResource();\r
+    g_capturerCtx.listenerState = OFF;\r
+    g_capturerCtx.capturerState = OFF;\r
+}\r
+\r
+void AudioCapturerModule::OnTerminate()\r
+{\r
+    if (g_capturerCtx.listenerState == OFF && g_capturerCtx.capturerState == OFF) {\r
+        return;\r
     }\r
+    MediaMutexLock(g_jsCaptureMutex);\r
+    g_capturerCtx.needStop = true;\r
+    MediaMutexUnLock(g_jsCaptureMutex);\r
+    MediaThreadJoin(&g_capturerCtx.audioCaptureProcess);\r
+    DestroyResource();\r
+    g_capturerCtx.listenerState = OFF;\r
+    g_capturerCtx.capturerState = OFF;\r
 }\r
 \r
 void InitAudioCapturerModule(JSIValue exports)\r
@@ -463,6 +865,12 @@ void InitAudioCapturerModule(JSIValue exports)
     JSI::SetModuleAPI(exports, "Start", AudioCapturerModule::Start);\r
     JSI::SetModuleAPI(exports, "Stop", AudioCapturerModule::Stop);\r
     JSI::SetModuleAPI(exports, "cancel", AudioCapturerModule::Cancel);\r
+    JSI::SetModuleAPI(exports, "start", AudioCapturerModule::start);\r
+    JSI::SetModuleAPI(exports, "stop", AudioCapturerModule::stop);\r
+    JSI::SetModuleAPI(exports, "on", AudioCapturerModule::ListenerOn);\r
+    JSI::SetModuleAPI(exports, "off", AudioCapturerModule::ListenerOff);\r
+    JSI::SetOnDestroy(exports, AudioCapturerModule::OnDestroy);\r
+    JSI::SetOnTerminate(exports, AudioCapturerModule::OnTerminate);\r
 }\r
 \r
 }\r
index 1389938..f13cf2d 100644 (file)
@@ -46,14 +46,39 @@ public:
     static JSIValue Stop(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
 \r
     /**\r
-     handle exception\r
+     * Start\r
+     * Start XiaoduVoice when args[0] == "XiaoduVoice", no input param\r
+     * Start AudioCaptruer otherwise\r
+     * @inputparam args, include properties buffersize, format, etc\r
      */\r
-    static void ExceptionStop(void);\r
+    static JSIValue start(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+\r
+    /**\r
+     * Stop\r
+     */\r
+    static JSIValue stop(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+\r
+    /**\r
+     * ListenerOn\r
+     * @inputparam args, include properties success, fail\r
+     */\r
+    static JSIValue ListenerOn(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
 \r
     /**\r
      * Cancel\r
      */\r
     static JSIValue Cancel(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+       /**\r
+     * ListenerOff\r
+     */\r
+    static JSIValue ListenerOff(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+\r
+    /**\r
+     handle exception\r
+     */\r
+    static void ExceptionStop(void);\r
+    static void OnDestroy(void);\r
+    static void OnTerminate(void);\r
 };\r
 \r
 void InitAudioCapturerModule(JSIValue exports);\r
diff --git a/code/sdk/middleware/services/media/foundation/audio_recorder/CMakeLists.txt b/code/sdk/middleware/services/media/foundation/audio_recorder/CMakeLists.txt
new file mode 100644 (file)
index 0000000..15af0e2
--- /dev/null
@@ -0,0 +1,6 @@
+#===============================================================================
+# @brief    cmake file
+# Copyright (c) CompanyNameMagicTag 2023-2023. All rights reserved.
+#===============================================================================
+add_subdirectory(frameworks re_f)
+add_subdirectory(interfaces/kits/audio_recorder_lite/ re)
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/foundation/audio_recorder/frameworks/CMakeLists.txt b/code/sdk/middleware/services/media/foundation/audio_recorder/frameworks/CMakeLists.txt
new file mode 100644 (file)
index 0000000..682e6a3
--- /dev/null
@@ -0,0 +1,64 @@
+#===============================================================================
+# @brief    cmake file
+# Copyright (c) CompanyNameMagicTag 2023-2023. All rights reserved.
+#===============================================================================
+enable_language(C)
+set(COMPONENT_NAME "audio_recorder")
+
+set(SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/audio_recorder.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/muxer/src/audio_recorder_muxer.c
+)
+
+set(PUBLIC_HEADER
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../audio_recorder/interfaces
+)
+
+set(OPENMG_DIR ${ROOT_DIR}/open_source/openharmony)
+set(PRIVATE_HEADER_COM ${PRIVATE_HEADER})
+list(APPEND PRIVATE_HEADER_COM
+    ${CMAKE_CURRENT_SOURCE_DIR}/../interfaces
+    ${CMAKE_CURRENT_SOURCE_DIR}/muxer/include
+)
+
+if(${CHIP} MATCHES "socmn2")
+    set(CDEFINES ${CDEFINES} "SUPPORT_FEATURE_CONFIG" "SUPPORT_SEA_CONFIG" "SUPPORT_ERROR_CODE" "SUPPORT_AUDIO_STREAM_IN_C")
+endif()
+if ("${CHIP}" STREQUAL "brandy")
+    list(APPEND PRIVATE_HEADER_COM
+        ${OPENMG_DIR}/drivers/peripheral/format/interfaces/include
+    )
+endif()
+if(${CHIP} MATCHES "socmn2|3322")
+    set(CDEFINES ${CDEFINES} "SUPPORT_NEW_FORMAT")
+endif()
+
+set(PRIVATE_HEADER
+   ${PRIVATE_HEADER_COM}
+)
+
+
+set(PRIVATE_DEFINES
+    ${CDEFINES}
+)
+
+set(NEWDEFINES "SUPPORT_AUDIO_RECORDER")
+set(PUBLIC_DEFINES
+    ${NEWDEFINES}
+)
+
+# use this when you want to add ccflags like -include xxx
+set(COMPONENT_PUBLIC_CCFLAGS
+)
+
+set(WHOLE_LINK
+    true
+)
+
+set(MAIN_COMPONENT
+    false
+)
+
+set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib/media/${BOARD}_${APPLICATION}/${COMPONENT_NAME})
+
+build_component()
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/foundation/audio_recorder/frameworks/audio_recorder.c b/code/sdk/middleware/services/media/foundation/audio_recorder/frameworks/audio_recorder.c
new file mode 100644 (file)
index 0000000..3b5ef7c
--- /dev/null
@@ -0,0 +1,1235 @@
+/*\r
+ * Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.\r
+ * Description: audio recorder define\r
+ * Author: Media Software Group\r
+ * Create: 2025-03-15\r
+ */\r
+\r
+#include "audio_recorder.h"\r
+#include <stdlib.h>\r
+#include <errno.h>\r
+#include <limits.h>\r
+#include <fcntl.h>\r
+#include <unistd.h>\r
+#include <time.h>\r
+#include <string.h>\r
+#include "securec.h"\r
+#include "audio_recorder_muxer.h"\r
+#ifdef SUPPORT_AUDIO_STREAM_IN_C\r
+#include "audio_stream_in.h"\r
+#else\r
+#include "audio_manager_c_wrapper.h"\r
+#endif\r
+#include "media_log.h"\r
+#include "media_thread_adapt.h"\r
+#if defined(SUPPORT_FEATURE_CONFIG)\r
+#include "feature_config.h"\r
+#endif\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+#define AUDIO_RECORDER_MODE_NAME "AudioRecorder"\r
+#define AUDIO_RECORDER_ERR_LOG(fmt, ...) MEDIA_ERR_LOG(fmt, ##__VA_ARGS__)\r
+#define AUDIO_RECORDER_INFO_LOG(fmt, ...) MEDIA_INFO_LOG(fmt, ##__VA_ARGS__)\r
+#define AUDIO_RECORDER_MUTEX_CREATE(attr) MediaMutexCreate(attr)\r
+#define AUDIO_RECORDER_MUTEX_LOCK(lock) MediaMutexLock(lock)\r
+#define AUDIO_RECORDER_MUTEX_UNLOCK(lock) MediaMutexUnLock(lock)\r
+#define AUDIO_RECORDER_INIT_STATIC_MUTEX_LOCK(mutex) MediaInitStaticMutexLock(mutex)\r
+#define AUDIO_RECORDER_MUTEX_DESTROY(mutex) MediaMutexDestroy(mutex)\r
+#define AUDIO_RECORDER_THREAD_CREATE(func, argument, attr) MediaThreadCreate(func, argument, attr)\r
+#define AUDIO_RECORDER_THREAD_COND_CREATE()   MediaThreadCondCreate()\r
+#define AUDIO_RECORDER_THREAD_COND_SIGNAL(condHandle)   MediaThreadCondSignal(condHandle)\r
+#define AUDIO_RECORDER_THREAD_COND_TIME_WAIT(condHandle, mutexHandle, delayUs) \\r
+    MediaThreadCondTimeWait(condHandle, mutexHandle, delayUs)\r
+#define AUDIO_RECORDER_THREAD_COND_DESTROY(condHandle) MediaThreadCondDestroy(condHandle)\r
+#define AUDIO_RECORDER_THREAD_JOIN(thdId) MediaThreadJoin(thdId)\r
+#define AUDIO_MAX_MEMOR_THRESHOLD_PER 100\r
+#define OPUS_ENCODE_HEADER_SIZE 8\r
+#define AUDIO_RECORDER_FILE_INFO_SIZE 350\r
+#define WAV_MAX_DATA_BUFFER_SIZE (16 * 1024)\r
+#define OGG_MAX_DATA_BUFFER_SIZE (28)\r
+#define MP3_MAX_DATA_BUFFER_SIZE (2 * 1024)\r
+#define SILK_MAX_DATA_BUFFER_SIZE (256)\r
+\r
+#define AUDIO_RECORD_CHECK_NULL_RETURN(ptr, ret, outStr) \\r
+do { \\r
+    if ((ptr) == NULL) { \\r
+        AUDIO_RECORDER_ERR_LOG("%s ", ((outStr) != NULL) ? (outStr) : " "); \\r
+        return (ret); \\r
+    } \\r
+} while (0)\r
+\r
+#define AUDIO_RECORD_CHECK_FAILED_RETURN(ptr, ret, outStr) \\r
+do { \\r
+    if (!(ptr)) { \\r
+        AUDIO_RECORDER_ERR_LOG("%s ", ((outStr) != NULL) ? (outStr) : " "); \\r
+        return (ret); \\r
+    } \\r
+} while (0)\r
+\r
+#define AUDIO_RECORD_CHECK_FAILED_RETURN_WITH_UNLOCK(value, target, ret, printfString, mutex) \\r
+do { \\r
+    if ((value) != (target)) { \\r
+        AUDIO_RECORDER_ERR_LOG("%s, ret:%d", (printfString) ? (printfString) : " ", ret); \\r
+        AUDIO_RECORDER_MUTEX_UNLOCK((mutex)); \\r
+        return ret; \\r
+    } \\r
+} while (0)\r
+\r
+#define AUDIO_RECORD_CHECK_COND_RETURN(value, ret, outStr) \\r
+do { \\r
+    if ((value)) { \\r
+        AUDIO_RECORDER_ERR_LOG("%s ret: %d", ((outStr) != NULL) ? (outStr) : " ", (value)); \\r
+        return (ret); \\r
+    } \\r
+} while (0)\r
+#ifdef SUPPORT_AUDIO_STREAM_IN_C\r
+#define MAX_PRODUCER_THREAD_STACK_SIZE 0x800\r
+#else\r
+#define MAX_PRODUCER_THREAD_STACK_SIZE 0x1800\r
+#endif\r
+#define MAX_CONSUMER_THREAD_STACK_SIZE 0x1000\r
+#define AUDIO_RECORDER_MAX_CONTINOUS_REND_FRAME_FULL_COUNT 200\r
+#define AUDIO_RECORDER_MAX_INSTANCE_NUM 1\r
+#define AUDIO_RECORDER_RENDER_EMPTY_SLEEP_TIME_US  5000u\r
+#define AUDIO_RECORDER_MAX_MEMORY_SLEEP_TIME_US  10000000u\r
+#ifdef SUPPORT_FEATURE_CONFIG\r
+#define CAPTURE_ONE_FRAME_TIME (1000 / CONFIG_AUDIO_AI_FRAME_PER_SEC)\r
+#define AUDIO_RECORDER_ONE_FRAME  ((1000 / CONFIG_AUDIO_AI_FRAME_PER_SEC) * 1000)\r
+#else\r
+#define AUDIO_RECORDER_ONE_FRAME  10000u\r
+#define CAPTURE_ONE_FRAME_TIME 10\r
+#endif\r
+#ifdef SUPPORT_ERROR_CODE\r
+#define AUDIO_RECORDER_RETRY_READ (ERRCODE_MEDIA_AUDIO_RETRY_READ)\r
+#else\r
+#define AUDIO_RECORDER_RETRY_READ (-7)\r
+#endif\r
+#define AUDIO_RECORDER_NOT_SUPPORT_GET_FRAME (-8)\r
+#define AUDIO_RECORDER_OK 0\r
+#define AUDIO_RECORDER_ERR (-1)\r
+#define AUDIO_RECORDER_NO_MEM (-2)\r
+#define AUDIO_RECORDER_FAIL (-3)\r
+#define AUDIO_RECORDER_INVALID_PARAM (-4)\r
+#define AUDIO_RECORDER_CAPTURE_FATEL (-5)\r
+#define AUDIO_RECORDER_INVAILD_ID 0xFFFF\r
+#define MAX_PREEMPTION_TIMES 2\r
+#define AUDIO_CONSUMER_BUFFER_FULL_SLEEP_TIME_US  1000000u\r
+#define AUDIO_CONSUMER_BUFFER_FREE_SLEEP_TIME_US  1000000u\r
+#define AUDIO_CONSUMER_BUFFER_WRITE_FAIL_SLEEP_US  10000u\r
+\r
+#define AUDIO_RECORDER_MAGIC_ID 0xAAAB\r
+#define HANDLE_SHIFT_LEN 16\r
+#define GET_AUDIO_RECORDER_MAGIC_ID(handle) (((uint32_t)(handle)) >> HANDLE_SHIFT_LEN)\r
+#define GET_AUDIO_RECORDER_HANDLE(id) ((AUDIO_RECORDER_MAGIC_ID << HANDLE_SHIFT_LEN) | (id))\r
+#define GET_AUDIO_RECORDER_ID(handle) (((uint32_t)(handle)) & 0xFFFF)\r
+#define BUFFER_SIZE 20\r
+#define SET_DB_VOLUME "setdbvol"\r
+#define AUDIO_RECORD_MEDIA_PATH_MAX 256\r
+#define CAPTURE_ONE_SECOND_SAMPLE_RATE 1000\r
+#define RECORDE_PARAM_BUF_LEN 25\r
+#define RECORDE_MAX_BUF_SIZE 2\r
+\r
+typedef struct {\r
+    void *data;\r
+    uint32_t dataSize;\r
+    int64_t pts;\r
+} RecorderBuffer;\r
+\r
+typedef struct {\r
+    RecorderBuffer buffer[RECORDE_MAX_BUF_SIZE];\r
+    uint32_t front;\r
+    uint32_t rear;\r
+    uint32_t wraparound;\r
+    void *lock;\r
+} ThreadSafeQueue;\r
+\r
+typedef struct {\r
+    AudioCodecFormat audioFormat;\r
+    uint32_t maxBufferSize;\r
+}AudioRecorderFormatBufferSize;\r
+\r
+static AudioRecorderFormatBufferSize g_formatBufferSizeMapping[] = {\r
+    {MP3, MP3_MAX_DATA_BUFFER_SIZE},\r
+    {SILK, SILK_MAX_DATA_BUFFER_SIZE},\r
+    {PCM, WAV_MAX_DATA_BUFFER_SIZE},\r
+    {OPUS, OGG_MAX_DATA_BUFFER_SIZE},\r
+};\r
+\r
+typedef struct {\r
+    const void *cookie;\r
+    RecorderCallback eventFunc;\r
+#ifdef SUPPORT_AUDIO_STREAM_IN_C\r
+    AudioStreamInHandle audioStreamInHandle;\r
+#endif\r
+    FormatFrame audioFrame;\r
+    AudioRecorderStates state;\r
+    void *instanceLock;\r
+    void *producerLock;\r
+    void *producerCond;\r
+    void *consumerCond;\r
+    void *producerProcess;\r
+    void *consumerProcess;\r
+    bool producerThreadExit;\r
+    bool consumerThreadExit;\r
+    uint32_t producerSleepTime;\r
+    uint32_t consumerSleepTime;\r
+    bool isUsed;\r
+    AudioRecorderMuxer muxerHandle;\r
+    CapturerInputConfig config;\r
+    bool enableOverwriteFiles;\r
+    uint32_t storageWarningThresholdPercent;\r
+    MuxerCallback callBack;\r
+    ThreadSafeQueue freeDataQueue;\r
+    ThreadSafeQueue fullDataQueue;\r
+    bool isNeedReadNewBuffer;\r
+    uint32_t maxBufferSize;\r
+} AudioRecorderContext;\r
+\r
+typedef enum {\r
+    AUDIO_RECORD_SET_CALLBACK, /* Set the callback function. */\r
+    AUDIO_RECORD_SET_DELETE_OLD_FILES_ENABLE, /* Setting whether to delete old files */\r
+    AUDIO_RECORD_SET_MAX_STORAGE_THREAHOLD, /* Setting the Maximum Storage Space Threshold */\r
+    AUDIO_RECORD_SET_MARK,\r
+    AUDIO_RECORD_CURRENT_STORAGE_REMAIND_TIME, /* Obtains the remaining time of the current storage space. */\r
+    AUDIO_RECORD_CURRENT_FILE_REMAIND_TIME, /* Obtains the remaining recording time of the current file. */\r
+    AUDIO_RECORD_CURRENT_FILE_INFO,\r
+} AudioRecordInvokeId;\r
+\r
+static AudioRecorderContext g_audioRecorder[AUDIO_RECORDER_MAX_INSTANCE_NUM] = {\r
+    {.instanceLock = NULL, .muxerHandle = NULL},\r
+};\r
+\r
+static int16_t g_audioRecorderId[AUDIO_RECORDER_MAX_INSTANCE_NUM] = {-1};\r
+static void *g_audioRecorderMutex = NULL;\r
+\r
+static int32_t InitQueue(ThreadSafeQueue *queue)\r
+{\r
+    if (queue == NULL) {\r
+        AUDIO_RECORDER_ERR_LOG("Queue is NULL!");\r
+        return AUDIO_RECORDER_INVALID_PARAM;\r
+    }\r
+    queue->front = 0;\r
+    queue->rear = 0;\r
+    queue->wraparound = 0;\r
+    if (queue->lock == NULL) {\r
+        queue->lock = AUDIO_RECORDER_MUTEX_CREATE(NULL);\r
+        if (queue->lock == NULL) {\r
+            AUDIO_RECORDER_ERR_LOG("Queue mutex create failed!");\r
+            return AUDIO_RECORDER_ERR;\r
+        }\r
+    }\r
+    return AUDIO_RECORDER_OK;\r
+}\r
+\r
+static bool QueueFull(const ThreadSafeQueue *queue)\r
+{\r
+    bool full = false;\r
+    if (queue->rear > queue->front) {\r
+        full = (queue->rear - queue->front) == RECORDE_MAX_BUF_SIZE;\r
+    } else {\r
+        full = (queue->front - queue->rear) == RECORDE_MAX_BUF_SIZE;\r
+    }\r
+    return full;\r
+}\r
+\r
+static bool QueueEmpty(const ThreadSafeQueue *queue)\r
+{\r
+    return queue->rear == queue->front && queue->wraparound == 0;\r
+}\r
+\r
+static void Enqueue(ThreadSafeQueue *queue, const RecorderBuffer *buffer)\r
+{\r
+    if (queue == NULL || buffer == NULL) {\r
+        AUDIO_RECORDER_ERR_LOG("queue or buffer is NULL!");\r
+        return;\r
+    }\r
+    AUDIO_RECORDER_MUTEX_LOCK(queue->lock);\r
+    if (QueueFull(queue)) {\r
+        AUDIO_RECORDER_ERR_LOG("Queue is full, cannot enqueue!");\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(queue->lock);\r
+        return;\r
+    }\r
+    if (queue->rear >= RECORDE_MAX_BUF_SIZE) {\r
+        queue->rear = (queue->rear) % RECORDE_MAX_BUF_SIZE;\r
+        queue->wraparound++;\r
+    }\r
+    queue->buffer[queue->rear].data = buffer->data;\r
+    queue->buffer[queue->rear].dataSize = buffer->dataSize;\r
+    queue->buffer[queue->rear].pts = buffer->pts;\r
+    queue->rear++;\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(queue->lock);\r
+}\r
+\r
+static RecorderBuffer *Dequeue(ThreadSafeQueue *queue)\r
+{\r
+    RecorderBuffer *value = NULL;\r
+    if (queue == NULL) {\r
+        AUDIO_RECORDER_ERR_LOG("queue is NULL!");\r
+        return value;\r
+    }\r
+    AUDIO_RECORDER_MUTEX_LOCK(queue->lock);\r
+    if (QueueEmpty(queue)) {\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(queue->lock);\r
+        return value;\r
+    }\r
+    if (queue->front >= RECORDE_MAX_BUF_SIZE) {\r
+        queue->front = (queue->front) % RECORDE_MAX_BUF_SIZE;\r
+        queue->wraparound--;\r
+    }\r
+    value = &queue->buffer[queue->front];\r
+    queue->front++;\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(queue->lock);\r
+    return value;\r
+}\r
+\r
+void DeinitQueue(ThreadSafeQueue *queue)\r
+{\r
+    AUDIO_RECORDER_MUTEX_DESTROY(&queue->lock);\r
+}\r
+\r
+static AudioRecorderContext *GetAudioRecorderContext(const AudioRecorderHandle handle)\r
+{\r
+    AudioRecorderContext *recorderContext = NULL;\r
+    uint16_t audioRecorderId;\r
+    AUDIO_RECORDER_MUTEX_LOCK(g_audioRecorderMutex);\r
+    if (GET_AUDIO_RECORDER_MAGIC_ID(handle) != AUDIO_RECORDER_MAGIC_ID) {\r
+        AUDIO_RECORDER_ERR_LOG("invalid audio recorder handle!");\r
+        goto EXIT;\r
+    }\r
+    audioRecorderId = GET_AUDIO_RECORDER_ID(handle);\r
+    if (audioRecorderId >= AUDIO_RECORDER_MAX_INSTANCE_NUM) {\r
+        AUDIO_RECORDER_ERR_LOG("invalid audio recorder id: %u!", audioRecorderId);\r
+        goto EXIT;\r
+    }\r
+    if (!g_audioRecorder[audioRecorderId].isUsed) {\r
+        AUDIO_RECORDER_ERR_LOG("audio recorder handle: 0x%x error, isUsed: %d",\r
+            handle, g_audioRecorder[audioRecorderId].isUsed);\r
+        goto EXIT;\r
+    }\r
+    recorderContext = &g_audioRecorder[audioRecorderId];\r
+EXIT:\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(g_audioRecorderMutex);\r
+    return recorderContext;\r
+}\r
+\r
+static uint16_t GetNewAudioRecorderId(void)\r
+{\r
+    uint16_t audioRecorderId;\r
+    for (audioRecorderId = 0; audioRecorderId < AUDIO_RECORDER_MAX_INSTANCE_NUM; audioRecorderId++) {\r
+        if (g_audioRecorderId[audioRecorderId] == -1) {\r
+            g_audioRecorderId[audioRecorderId] = audioRecorderId;\r
+            break;\r
+        }\r
+    }\r
+    return audioRecorderId;\r
+}\r
+\r
+static uint16_t GetAudioRecorderAvailableId(void)\r
+{\r
+    uint16_t audioRecorderId = GetNewAudioRecorderId();\r
+    if (audioRecorderId >= AUDIO_RECORDER_MAX_INSTANCE_NUM) {\r
+        for (audioRecorderId = 0; audioRecorderId < AUDIO_RECORDER_MAX_INSTANCE_NUM; audioRecorderId++) {\r
+            if (!g_audioRecorder[audioRecorderId].isUsed) {\r
+                g_audioRecorderId[audioRecorderId] = -1;\r
+            }\r
+        }\r
+        audioRecorderId = GetNewAudioRecorderId();\r
+    }\r
+    return audioRecorderId;\r
+}\r
+\r
+static int32_t AudioStreamSinkStart(AudioRecorderContext *recorderContext)\r
+{\r
+    int32_t ret = AUDIO_RECORDER_OK;\r
+#ifdef SUPPORT_AUDIO_STREAM_IN_C\r
+    ret = AudioStreamInCreate(&recorderContext->audioStreamInHandle);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("create failed");\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    ret = AudioStreamInInit(recorderContext->audioStreamInHandle, &recorderContext->config,\r
+        NULL, NULL);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("init failed");\r
+        AudioStreamInDestroy(recorderContext->audioStreamInHandle);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    ret = AudioStreamInStart(recorderContext->audioStreamInHandle);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("start failed");\r
+        goto EXIT;\r
+    }\r
+    return ret;\r
+EXIT:\r
+    AudioStreamInRelease(recorderContext->audioStreamInHandle);\r
+    AudioStreamInDestroy(recorderContext->audioStreamInHandle);\r
+#else\r
+    ret = AudioStreamInInit(recorderContext->config);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("create failed");\r
+        return ret;\r
+    }\r
+    ret = AudioStreamInStart();\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("start failed");\r
+        AudioStreamInDeinit();\r
+    }\r
+#endif\r
+    return ret;\r
+}\r
+\r
+static bool AudioRecorderGetMaxBufferSize(AudioRecorderContext *recorderContext, AudioCodecFormat audioFormat)\r
+{\r
+    if (recorderContext == NULL) {\r
+        AUDIO_RECORDER_ERR_LOG("recorderContext is NULL!");\r
+        return false;\r
+    }\r
+    for (uint32_t i = 0; i < sizeof(g_formatBufferSizeMapping) / sizeof(AudioRecorderFormatBufferSize); i++) {\r
+        if (g_formatBufferSizeMapping[i].audioFormat == audioFormat) {\r
+            recorderContext->maxBufferSize = g_formatBufferSizeMapping[i].maxBufferSize;\r
+            return true;\r
+        }\r
+    }\r
+    AUDIO_RECORDER_ERR_LOG("not found support format[%d]", audioFormat);\r
+    return false;\r
+}\r
+\r
+static uint32_t AudioRecorderGetPacketLength(AudioRecorderContext *recorderContext)\r
+{\r
+    uint32_t len = 0;\r
+    uint32_t bitWidth = recorderContext->config.bitWidth / 0x8;\r
+    len = recorderContext->config.channelCount *\r
+        (recorderContext->config.sampleRate / CAPTURE_ONE_SECOND_SAMPLE_RATE * CAPTURE_ONE_FRAME_TIME) * bitWidth;\r
+    return len;\r
+}\r
+\r
+static int32_t AudioRecorderInitBufferData(AudioRecorderContext *recorderContext)\r
+{\r
+    int32_t ret = InitQueue(&recorderContext->freeDataQueue);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    ret = InitQueue(&recorderContext->fullDataQueue);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        goto DEINIT_FREE_QUEUE;\r
+    }\r
+    for (size_t i = 0; i < RECORDE_MAX_BUF_SIZE; i++) {\r
+        RecorderBuffer buffer = {};\r
+        buffer.data = malloc(recorderContext->maxBufferSize);\r
+        if (buffer.data == NULL) {\r
+            AUDIO_RECORDER_ERR_LOG("audio recorder malloc Data failed! i = %d", i);\r
+            goto DEINIT_FULL_QUEUE;\r
+        }\r
+        buffer.dataSize = 0;\r
+        buffer.pts = 0;\r
+        Enqueue(&recorderContext->freeDataQueue, &buffer);\r
+    }\r
+    return AUDIO_RECORDER_OK;\r
+DEINIT_FULL_QUEUE:\r
+    DeinitQueue(&recorderContext->fullDataQueue);\r
+DEINIT_FREE_QUEUE:\r
+    DeinitQueue(&recorderContext->freeDataQueue);\r
+    return AUDIO_RECORDER_ERR;\r
+}\r
+\r
+static void AudioRecorderDestroyBufferData(AudioRecorderContext *recorderContext)\r
+{\r
+    for (size_t i = 0; i < RECORDE_MAX_BUF_SIZE; i++) {\r
+        if (recorderContext->freeDataQueue.buffer[i].data != NULL) {\r
+            free(recorderContext->freeDataQueue.buffer[i].data);\r
+            recorderContext->freeDataQueue.buffer[i].data = NULL;\r
+        }\r
+    }\r
+    DeinitQueue(&recorderContext->freeDataQueue);\r
+    DeinitQueue(&recorderContext->fullDataQueue);\r
+}\r
+\r
+static RecorderBuffer *AudioRecorderGetFreeBuffer(AudioRecorderContext *recorderContext)\r
+{\r
+    return Dequeue(&recorderContext->freeDataQueue);\r
+}\r
+\r
+static void AudioRecorderPutFreeBuffer(AudioRecorderContext *recorderContext, const RecorderBuffer *buffer)\r
+{\r
+    Enqueue(&recorderContext->freeDataQueue, buffer);\r
+}\r
+\r
+static void AudioRecorderPutFullBuffer(AudioRecorderContext *recorderContext, const RecorderBuffer *buffer)\r
+{\r
+    Enqueue(&recorderContext->fullDataQueue, buffer);\r
+}\r
+\r
+static RecorderBuffer *AudioRecorderGetFullBuffer(AudioRecorderContext *recorderContext)\r
+{\r
+    return Dequeue(&recorderContext->fullDataQueue);\r
+}\r
+\r
+static int32_t AudioRecorderPushPacketToFile(AudioRecorderContext *recorderContext, RecorderBuffer *buffer)\r
+{\r
+    int32_t ret = 0;\r
+    recorderContext->audioFrame.data = buffer->data;\r
+    recorderContext->audioFrame.len = buffer->dataSize;\r
+    recorderContext->audioFrame.timestampUs = buffer->pts;\r
+    ret = AudioRecorderMuxerWriteData(recorderContext->muxerHandle, &recorderContext->audioFrame);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("audio recorder Write Data failed!");\r
+    }\r
+    buffer->dataSize = 0;\r
+    AudioRecorderPutFreeBuffer(recorderContext, buffer);\r
+    AUDIO_RECORDER_THREAD_COND_SIGNAL(recorderContext->producerCond);\r
+    return ret;\r
+}\r
+\r
+static void AudioRecorderSendData(AudioRecorderContext *recorderContext,\r
+    RecorderBuffer *buffer, uint32_t size)\r
+{\r
+    if (buffer == NULL) {\r
+        return;\r
+    }\r
+    if (buffer->dataSize > 0) {\r
+#ifdef SUPPORT_AUDIO_STREAM_IN_C\r
+        float frameNum = buffer->dataSize / (size * 1.0f);\r
+        buffer->pts += frameNum * AUDIO_RECORDER_ONE_FRAME;\r
+#endif\r
+        AudioRecorderPutFullBuffer(recorderContext, buffer);\r
+        AUDIO_RECORDER_THREAD_COND_SIGNAL(recorderContext->consumerCond);\r
+        recorderContext->isNeedReadNewBuffer = true;\r
+    }\r
+}\r
+\r
+static int32_t AudioRecorderGetPacketfromProducer(AudioRecorderContext *recorderContext,\r
+    RecorderBuffer *buffer, uint32_t size)\r
+{\r
+    int32_t ret = 0;\r
+    CapturerBuffer capturebuffer = { 0 };\r
+    struct timespec timestamp = {};\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(buffer, AUDIO_RECORDER_ERR, "buffer is NULL!");\r
+    capturebuffer.size = recorderContext->maxBufferSize - buffer->dataSize;\r
+    capturebuffer.data = (uint8_t *)buffer->data + buffer->dataSize;\r
+    int32_t readSize = 0;\r
+#ifdef SUPPORT_AUDIO_STREAM_IN_C\r
+    ret = AudioStreamInObtainBuffer(recorderContext->audioStreamInHandle, &capturebuffer);\r
+    readSize = ret;\r
+#else\r
+    ret = AudioStreamInObtainBuffer(capturebuffer.data, &capturebuffer.size);\r
+    readSize = capturebuffer.size;\r
+    int64_t pos = -1;\r
+    (void)AudioStreamInGetPosition(&pos);\r
+    if (pos != -1) {\r
+        buffer->pts = pos;\r
+    }\r
+#endif\r
+    if (ret < AUDIO_RECORDER_OK) {\r
+        if (ret == AUDIO_RECORDER_NOT_SUPPORT_GET_FRAME) {\r
+            AudioRecorderSendData(recorderContext, buffer, size);\r
+            return AUDIO_RECORDER_OK;\r
+        }\r
+        recorderContext->producerSleepTime = AUDIO_RECORDER_RENDER_EMPTY_SLEEP_TIME_US;\r
+        return ret;\r
+    }\r
+    buffer->dataSize += readSize;\r
+#ifdef SUPPORT_AUDIO_STREAM_IN_C\r
+    if (buffer->dataSize == recorderContext->maxBufferSize) {\r
+        AudioRecorderSendData(recorderContext, buffer, size);\r
+    }\r
+#endif\r
+    return AUDIO_RECORDER_OK;\r
+}\r
+\r
+static void *AudioRecorderProducerProcess(void *priv)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(priv, NULL, "priv is NULL");\r
+    AudioRecorderContext *record = (AudioRecorderContext *)priv;\r
+    int32_t ret = AUDIO_RECORDER_OK;\r
+#ifdef SUPPORT_AUDIO_STREAM_IN_C\r
+    uint32_t size = AudioRecorderGetPacketLength(record);\r
+    if (size <= 0) {\r
+        AUDIO_RECORDER_ERR_LOG("audio recorder get packet length failed!");\r
+        return NULL;\r
+    }\r
+#else\r
+    uint32_t size = 0;\r
+#endif\r
+    RecorderBuffer *buffer = NULL;\r
+    record->isNeedReadNewBuffer = true;\r
+    while (true) {\r
+        AUDIO_RECORDER_MUTEX_LOCK(record->producerLock);\r
+        if (record->producerThreadExit) {\r
+            AudioRecorderSendData(record, buffer, size);\r
+            AUDIO_RECORDER_INFO_LOG("audio producer sch process exit");\r
+            goto EXIT;\r
+        }\r
+        record->producerSleepTime = 0;\r
+        if (record->isNeedReadNewBuffer) {\r
+            buffer = AudioRecorderGetFreeBuffer(record);\r
+            if (buffer == NULL) {\r
+                record->producerSleepTime = AUDIO_CONSUMER_BUFFER_FULL_SLEEP_TIME_US;\r
+                goto CONTINUE;\r
+            }\r
+            record->isNeedReadNewBuffer = false;\r
+        }\r
+        ret = AudioRecorderGetPacketfromProducer(record, buffer, size);\r
+        if (ret != AUDIO_RECORDER_OK) {\r
+            if ((uint32_t)ret == AUDIO_RECORDER_RETRY_READ) {\r
+                goto CONTINUE;\r
+            }\r
+            goto EXIT;\r
+        }\r
+    CONTINUE:\r
+        if (record->producerSleepTime > 0) {\r
+            AUDIO_RECORDER_THREAD_COND_TIME_WAIT(record->producerCond, record->producerLock, record->producerSleepTime);\r
+        }\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(record->producerLock);\r
+    }\r
+EXIT:\r
+    record->producerThreadExit = true;\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(record->producerLock);\r
+    return NULL;\r
+}\r
+\r
+static void* AudioRecorderConsumerProcess(void *priv)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(priv, NULL, "priv is NULL");\r
+    AudioRecorderContext *record = (AudioRecorderContext *)priv;\r
+    RecorderBuffer *buffer = NULL;\r
+    while (true) {\r
+        AUDIO_RECORDER_MUTEX_LOCK(record->instanceLock);\r
+        if (record->consumerThreadExit && buffer == NULL) {\r
+            AUDIO_RECORDER_INFO_LOG("audio consumer sch process exit");\r
+            goto EXIT;\r
+        }\r
+        record->consumerSleepTime = 0;\r
+        buffer = AudioRecorderGetFullBuffer(record);\r
+        if (buffer == NULL) {\r
+            record->consumerSleepTime = AUDIO_CONSUMER_BUFFER_FREE_SLEEP_TIME_US;\r
+            goto CONTINUE;\r
+        }\r
+        int32_t ret = AudioRecorderPushPacketToFile(record, buffer);\r
+        if (ret != AUDIO_RECORDER_OK) {\r
+            if ((uint32_t)ret == AUDIO_RECORDER_RETRY_READ) {\r
+                AUDIO_RECORDER_ERR_LOG("AudioRecorderPushPacketToFile AUDIO_RECORDER_RETRY_READ");\r
+                goto CONTINUE;\r
+            }\r
+            AUDIO_RECORDER_ERR_LOG("audio recorder send data failed! ret = %d", ret);\r
+            goto EXIT;\r
+        }\r
+CONTINUE:\r
+        if (record->consumerSleepTime > 0) {\r
+            AUDIO_RECORDER_THREAD_COND_TIME_WAIT(record->consumerCond, record->instanceLock, record->consumerSleepTime);\r
+        }\r
+        buffer = NULL;\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(record->instanceLock);\r
+    }\r
+EXIT:\r
+    record->consumerThreadExit = true;\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(record->instanceLock);\r
+    return NULL;\r
+}\r
+\r
+static int32_t InitAudioRecorderMutexAndCond(uint16_t audioRecorderId)\r
+{\r
+    if (g_audioRecorder[audioRecorderId].instanceLock == NULL) {\r
+        g_audioRecorder[audioRecorderId].instanceLock = AUDIO_RECORDER_MUTEX_CREATE(NULL);\r
+        if (g_audioRecorder[audioRecorderId].instanceLock == NULL) {\r
+            AUDIO_RECORDER_ERR_LOG("mutex instanceLock create failed!");\r
+            return AUDIO_RECORDER_ERR;\r
+        }\r
+    }\r
+    g_audioRecorder[audioRecorderId].producerCond = AUDIO_RECORDER_THREAD_COND_CREATE();\r
+    if (g_audioRecorder[audioRecorderId].producerCond == NULL) {\r
+        AUDIO_RECORDER_ERR_LOG("producercond create failed!");\r
+        goto INSTANCE_LOCK;\r
+    }\r
+    g_audioRecorder[audioRecorderId].consumerCond = AUDIO_RECORDER_THREAD_COND_CREATE();\r
+    if (g_audioRecorder[audioRecorderId].consumerCond == NULL) {\r
+        AUDIO_RECORDER_ERR_LOG("consumerCond create failed!");\r
+        goto PRODUCER_COND;\r
+    }\r
+    if (g_audioRecorder[audioRecorderId].producerLock == NULL) {\r
+        g_audioRecorder[audioRecorderId].producerLock = AUDIO_RECORDER_MUTEX_CREATE(NULL);\r
+        if (g_audioRecorder[audioRecorderId].producerLock == NULL) {\r
+            AUDIO_RECORDER_ERR_LOG("mutex producerLock create failed!");\r
+            goto CONSUMER_COND;\r
+        }\r
+    }\r
+    return AUDIO_RECORDER_OK;\r
+CONSUMER_COND:\r
+    AUDIO_RECORDER_THREAD_COND_DESTROY(&g_audioRecorder[audioRecorderId].consumerCond);\r
+PRODUCER_COND:\r
+    AUDIO_RECORDER_THREAD_COND_DESTROY(&g_audioRecorder[audioRecorderId].producerCond);\r
+INSTANCE_LOCK:\r
+    AUDIO_RECORDER_MUTEX_DESTROY(&g_audioRecorder[audioRecorderId].instanceLock);\r
+    return AUDIO_RECORDER_ERR;\r
+}\r
+\r
+static int32_t InitAudioRecorderContext(uint16_t audioRecorderId)\r
+{\r
+    g_audioRecorder[audioRecorderId].state = AUDIO_RECORD_STATUS_IDLE;\r
+    g_audioRecorder[audioRecorderId].config.audioFormat = PCM;\r
+    g_audioRecorder[audioRecorderId].config.streamType = AUDIO_STREAM_VOICE_RECORD;\r
+    g_audioRecorder[audioRecorderId].config.channelCount = 1;\r
+    g_audioRecorder[audioRecorderId].config.linkDir = AUDIO_UP_LINK;\r
+    g_audioRecorder[audioRecorderId].config.sampleRate = 0;\r
+#ifdef SUPPORT_SEA_CONFIG\r
+    g_audioRecorder[audioRecorderId].config.micType = CAPTURE_MIC_TYPE_0;\r
+    g_audioRecorder[audioRecorderId].config.isProductTestMode = false;\r
+#endif\r
+    g_audioRecorder[audioRecorderId].config.sessionID = 0;\r
+    g_audioRecorder[audioRecorderId].audioFrame.data = NULL;\r
+    g_audioRecorder[audioRecorderId].audioFrame.len = 0;\r
+#ifdef SUPPORT_AUDIO_STREAM_IN_C\r
+    g_audioRecorder[audioRecorderId].audioStreamInHandle = NULL;\r
+#endif\r
+    g_audioRecorder[audioRecorderId].producerThreadExit = false;\r
+    g_audioRecorder[audioRecorderId].consumerThreadExit = false;\r
+    g_audioRecorder[audioRecorderId].consumerProcess = NULL;\r
+    g_audioRecorder[audioRecorderId].producerProcess = NULL;\r
+    g_audioRecorder[audioRecorderId].producerSleepTime = 0;\r
+    g_audioRecorder[audioRecorderId].consumerSleepTime = 0;\r
+    g_audioRecorder[audioRecorderId].eventFunc = NULL;\r
+    int32_t ret = InitAudioRecorderMutexAndCond(audioRecorderId);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("InitAudioRecorderMutexAndCond failed!");\r
+    }\r
+    return ret;\r
+}\r
+\r
+static int32_t MuxerOnErrorCallback(void *handle, EventErrorType type, int32_t ext)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "handle is NULL");\r
+    AudioRecorderContext *recorderContext = (AudioRecorderContext *)(handle);\r
+    switch (type) {\r
+        case ERROR_TYPE_CREATE_FILE_FAIL:\r
+        case ERROR_TYPE_WRITE_FILE_FAIL:\r
+        case ERROR_TYPE_CLOSE_FILE_FAIL:\r
+        case ERROR_TYPE_INTERNAL_OPERATION_FAIL:\r
+            AUDIO_RECORDER_INFO_LOG("AUDIO_RECORD_EVENT_ERROR type = %d!", type);\r
+            recorderContext->eventFunc(AUDIO_RECORD_EVENT_ERROR, &ext, recorderContext->cookie);\r
+            break;\r
+        default:\r
+            break;\r
+    }\r
+    return AUDIO_RECORDER_OK;\r
+}\r
+\r
+static int32_t MuxerOnInfoCallback(void *handle, EventInfoType type, int32_t ext)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "handle is NULL");\r
+    AudioRecorderContext *recorderContext = (AudioRecorderContext *)(handle);\r
+    switch (type) {\r
+        case MAX_DURATION_APPROACHING:\r
+            AUDIO_RECORDER_INFO_LOG("MAX_DURATION_APPROACHING!");\r
+            break;\r
+        case MAX_FILESIZE_APPROACHING:\r
+            AUDIO_RECORDER_INFO_LOG("MAX_FILESIZE_APPROACHING!");\r
+            break;\r
+        case MAX_FILESIZE_REACHED:\r
+            AUDIO_RECORDER_INFO_LOG("MAX_FILESIZE_REACHED!");\r
+            break;\r
+        case MAX_DURATION_REACHED:\r
+            AUDIO_RECORDER_INFO_LOG("MAX_DURATION_REACHED!");\r
+            break;\r
+        case MAX_MEMORYSIZE_REACHED:\r
+            recorderContext->eventFunc(AUDIO_RECORD_STORAGE_REACHE_MAX_VALUE, &ext, recorderContext->cookie);\r
+            recorderContext->consumerSleepTime = AUDIO_RECORDER_MAX_MEMORY_SLEEP_TIME_US;\r
+            break;\r
+        default:\r
+            break;\r
+    }\r
+    return AUDIO_RECORDER_OK;\r
+}\r
+\r
+errcode_t AudioRecorderCreate(AudioRecorderHandle *handle)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "handle is NULL");\r
+    AUDIO_RECORDER_INIT_STATIC_MUTEX_LOCK(&g_audioRecorderMutex);\r
+    AUDIO_RECORDER_MUTEX_LOCK(g_audioRecorderMutex);\r
+    int32_t ret = AUDIO_RECORDER_OK;\r
+    uint16_t audioRecorderId = GetAudioRecorderAvailableId();\r
+    if (audioRecorderId >= AUDIO_RECORDER_MAX_INSTANCE_NUM) {\r
+        AUDIO_RECORDER_ERR_LOG("not found free audio recorder handle id!");\r
+        goto EXIT;\r
+    }\r
+    ret = AudioRecorderMuxerCreate(&g_audioRecorder[audioRecorderId].muxerHandle);\r
+    if (ret != AUDIO_RECORDER_OK || g_audioRecorder[audioRecorderId].muxerHandle == NULL) {\r
+        AUDIO_RECORDER_ERR_LOG("create muxer failed! ret = %d", ret);\r
+        goto EXIT;\r
+    }\r
+    ret = InitAudioRecorderContext(audioRecorderId);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("init audio recorder context failed!");\r
+        goto EXIT;\r
+    }\r
+    g_audioRecorder[audioRecorderId].isUsed = true;\r
+    *handle = (AudioRecorderHandle)GET_AUDIO_RECORDER_HANDLE(audioRecorderId);\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(g_audioRecorderMutex);\r
+    return AUDIO_RECORDER_OK;\r
+EXIT:\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(g_audioRecorderMutex);\r
+    return AUDIO_RECORDER_ERR;\r
+}\r
+\r
+errcode_t AudioRecorderSetInfo(const AudioRecorderHandle handle, const CapturerInputConfig *config)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "audio recorder is NULL!");\r
+    AudioRecorderContext *recorderContext = GetAudioRecorderContext(handle);\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(recorderContext, AUDIO_RECORDER_INVALID_PARAM, "recorderContext is NULL!");\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(config, AUDIO_RECORDER_INVALID_PARAM, "config is NULL!");\r
+    AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+    if (recorderContext->state != AUDIO_RECORD_STATUS_IDLE) {\r
+        AUDIO_RECORDER_ERR_LOG("the call is not allowed in the current state.state = %d", recorderContext->state);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    if (!AudioRecorderGetMaxBufferSize(recorderContext, config->audioFormat)) {\r
+        AUDIO_RECORDER_ERR_LOG("get max buffer size failed!");\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    int32_t ret = AudioRecorderInitBufferData(recorderContext);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("AudioRecorderInitBufferData failed!");\r
+        AudioRecorderDestroyBufferData(recorderContext);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return ret;\r
+    }\r
+    recorderContext->config.audioFormat = config->audioFormat;\r
+    recorderContext->config.streamType = config->streamType;\r
+    recorderContext->config.channelCount = config->channelCount;\r
+    recorderContext->config.bitWidth = config->bitWidth;\r
+    recorderContext->config.linkDir = config->linkDir;\r
+    recorderContext->config.sampleRate = config->sampleRate;\r
+#ifdef SUPPORT_SEA_CONFIG\r
+    recorderContext->config.isProductTestMode = config->isProductTestMode;\r
+    recorderContext->config.micType = config->micType;\r
+#endif\r
+    recorderContext->config.sessionID = config->sessionID;\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    return AUDIO_RECORDER_OK;\r
+}\r
+\r
+errcode_t AudioRecorderSetOutputPath(const AudioRecorderHandle handle, const char *outPath, uint32_t outPathLen)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "audio recorder is NULL!");\r
+    AudioRecorderContext *recorderContext = GetAudioRecorderContext(handle);\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(recorderContext, AUDIO_RECORDER_INVALID_PARAM, "recorderContext is NULL!");\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(outPath, AUDIO_RECORDER_INVALID_PARAM, "filepath is NULL!");\r
+    if (outPathLen > AUDIO_RECORD_MEDIA_PATH_MAX) {\r
+        AUDIO_RECORDER_ERR_LOG("filePathLen is invalid!");\r
+        return AUDIO_RECORDER_INVALID_PARAM;\r
+    }\r
+    AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+    if (recorderContext->state != AUDIO_RECORD_STATUS_IDLE) {\r
+        AUDIO_RECORDER_ERR_LOG("the call is not allowed in the current state.state = %d", recorderContext->state);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+#ifdef SUPPORT_AUDIO_STREAM_IN_C\r
+#ifndef ONLY_UT_TEST\r
+    char startWith[] = "/user/";\r
+    if (strncmp(outPath, startWith, strlen(startWith)) != 0) {\r
+        AUDIO_RECORDER_ERR_LOG("path is not start with '/user/' !");\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+#endif\r
+#endif\r
+    errcode_t ret = AudioRecorderMuxerSetOutputPath(recorderContext->muxerHandle,\r
+        recorderContext->config.audioFormat, outPath, outPathLen);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("muxer set source failed, ret:%d", ret);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    ret = AudioRecorderMuxerAddTrack(recorderContext->muxerHandle, &recorderContext->config);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("muxer add track source failed, ret:%d", ret);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    recorderContext->state = AUDIO_RECORD_STATUS_INIT;\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    return AUDIO_RECORDER_OK;\r
+}\r
+\r
+errcode_t AudioRecorderPrepare(const AudioRecorderHandle handle)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "audio recorder is NULL!");\r
+    AudioRecorderContext *recorderContext = GetAudioRecorderContext(handle);\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(recorderContext, AUDIO_RECORDER_INVALID_PARAM, "recorderContext is NULL!");\r
+    AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+    if (recorderContext->state != AUDIO_RECORD_STATUS_INIT) {\r
+        AUDIO_RECORDER_ERR_LOG("the call is not allowed in the current state.state = %d", recorderContext->state);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    errcode_t ret = AudioRecorderMuxerPrepare(recorderContext->muxerHandle);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("muxer perpare failed! ret = %d", ret);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    recorderContext->callBack.handle = recorderContext;\r
+    recorderContext->callBack.OnErrorCallback = MuxerOnErrorCallback;\r
+    recorderContext->callBack.OnInfoCallback = MuxerOnInfoCallback;\r
+    ret = AudioRecorderMuxerSetCallBack(recorderContext->muxerHandle, &recorderContext->callBack);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("audio recorder muxer set callback failed! ret = %d", ret);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    recorderContext->state = AUDIO_RECORD_STATUS_PREPARED;\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    return AUDIO_RECORDER_OK;\r
+}\r
+\r
+errcode_t AudioRecorderEnableOverwriteFiles(const AudioRecorderHandle handle, bool enable)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "audio recorder is NULL!");\r
+    AudioRecorderContext *recorderContext = GetAudioRecorderContext(handle);\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(recorderContext, AUDIO_RECORDER_INVALID_PARAM, "recorderContext is NULL!");\r
+    AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+    if (recorderContext->state > AUDIO_RECORD_STATUS_PREPARED) {\r
+        AUDIO_RECORDER_INFO_LOG("can not to set enable Over write Files!,curState = %d", recorderContext->state);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    ParameterItem item = {};\r
+    item.key = AUDIO_RECORD_SET_DELETE_OLD_FILES_ENABLE;\r
+    if (enable) {\r
+        item.value.u32Value = 1;\r
+    } else {\r
+        item.value.u32Value = 0;\r
+    }\r
+    errcode_t ret = AudioRecorderMuxerSetParameter(recorderContext->muxerHandle, &item, 1);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_INFO_LOG("audio recorder muxer set parameter failed, ret = %d", ret);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    return AUDIO_RECORDER_OK;\r
+}\r
+\r
+errcode_t AudioRecorderSetStorageWarningThreshold(const AudioRecorderHandle handle, uint32_t percent)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "audio recorder is NULL!");\r
+    AudioRecorderContext *recorderContext = GetAudioRecorderContext(handle);\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(recorderContext, AUDIO_RECORDER_INVALID_PARAM, "recorderContext is NULL!");\r
+    AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+    ParameterItem item = {};\r
+    errcode_t ret = 0;\r
+    if (recorderContext->state > AUDIO_RECORD_STATUS_PREPARED) {\r
+        AUDIO_RECORDER_INFO_LOG("can not to set memory threshold percent!,curState = %d", recorderContext->state);\r
+        goto ERROR;\r
+    }\r
+    if (percent < 1 || percent > AUDIO_MAX_MEMOR_THRESHOLD_PER) {\r
+        AUDIO_RECORDER_INFO_LOG("The current threshold[%u] setting ratio is not supported. = %d", percent);\r
+        goto ERROR;\r
+    }\r
+    item.key = AUDIO_RECORD_SET_MAX_STORAGE_THREAHOLD;\r
+    item.value.u32Value = percent;\r
+    ret = AudioRecorderMuxerSetParameter(recorderContext->muxerHandle, &item, 1);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_INFO_LOG("audio recorder muxer set parameter failed, ret = %d", ret);\r
+        goto ERROR;\r
+    }\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    return AUDIO_RECORDER_OK;\r
+ERROR:\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    return AUDIO_RECORDER_ERR;\r
+}\r
+\r
+errcode_t AudioRecorderWriteMarks(const AudioRecorderHandle handle, const uint8_t *buffer, const int32_t bufLen)\r
+{\r
+    MEDIA_UNUSED(buffer);\r
+    MEDIA_UNUSED(bufLen);\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "audio recorder is NULL!");\r
+    AudioRecorderContext *recorderContext = GetAudioRecorderContext(handle);\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(recorderContext, AUDIO_RECORDER_INVALID_PARAM, "recorderContext is NULL!");\r
+    AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+    ParameterItem item = {};\r
+    errcode_t ret = 0;\r
+    if (recorderContext->state != AUDIO_RECORD_STATUS_START) {\r
+        AUDIO_RECORDER_INFO_LOG("can not to set memory threshold percent!,curState = %d", recorderContext->state);\r
+        goto ERROR;\r
+    }\r
+    item.key = AUDIO_RECORD_SET_MARK;\r
+    item.value.u32Value = 0;\r
+    ret = AudioRecorderMuxerSetParameter(recorderContext->muxerHandle, &item, 1);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_INFO_LOG("audio recorder muxer set parameter failed, ret = %d", ret);\r
+        goto ERROR;\r
+    }\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    return AUDIO_RECORDER_OK;\r
+ERROR:\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    return AUDIO_RECORDER_ERR;\r
+}\r
+\r
+errcode_t AudioRecorderSetMaxDuration(const AudioRecorderHandle handle, uint32_t duration)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "audio recorder is NULL!");\r
+    AudioRecorderContext *recorderContext = GetAudioRecorderContext(handle);\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(recorderContext, AUDIO_RECORDER_INVALID_PARAM, "recorderContext is NULL!");\r
+    AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+    if (recorderContext->state > AUDIO_RECORD_STATUS_PREPARED) {\r
+        AUDIO_RECORDER_ERR_LOG("the call is not allowed in the current state.state = %d", recorderContext->state);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    errcode_t ret = AudioRecorderMuxerSetMaxDuration(recorderContext->muxerHandle, duration);\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    return ret;\r
+}\r
+\r
+errcode_t AudioRecorderSetMaxFileSize(const AudioRecorderHandle handle, uint64_t size)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "audio recorder is NULL!");\r
+    AudioRecorderContext *recorderContext = GetAudioRecorderContext(handle);\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(recorderContext, AUDIO_RECORDER_INVALID_PARAM, "recorderContext is NULL!");\r
+    AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+    if (recorderContext->state > AUDIO_RECORD_STATUS_PREPARED) {\r
+        AUDIO_RECORDER_ERR_LOG("the call is not allowed in the current state.state = %d", recorderContext->state);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    errcode_t ret = AudioRecorderMuxerSetMaxFileSize(recorderContext->muxerHandle, size);\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    return ret;\r
+}\r
+\r
+errcode_t AudioRecorderSetCallback(const AudioRecorderHandle handle, RecorderCallback callback, const void *cookie)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "audio recorder is NULL!");\r
+    AudioRecorderContext *recorderContext = GetAudioRecorderContext(handle);\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(recorderContext, AUDIO_RECORDER_INVALID_PARAM, "recorderContext is NULL!");\r
+    AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+    recorderContext->cookie = cookie;\r
+    recorderContext->eventFunc = callback;\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    return AUDIO_RECORDER_OK;\r
+}\r
+\r
+errcode_t AudioRecorderGetRemainingTime(const AudioRecorderHandle handle, uint32_t type, uint32_t *time)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "audio recorder is NULL!");\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(time, AUDIO_RECORDER_INVALID_PARAM, "time is NULL!");\r
+    AudioRecorderContext *recorderContext = GetAudioRecorderContext(handle);\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(recorderContext, AUDIO_RECORDER_INVALID_PARAM, "recorderContext is NULL!");\r
+    AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+    if (recorderContext->state != AUDIO_RECORD_STATUS_START) {\r
+        AUDIO_RECORDER_ERR_LOG("the call is not allowed in the current state.state = %d", recorderContext->state);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    ParameterItem item = {};\r
+    if (type == AUDIO_RECORD_CURRENT_FILE_REMAIN_TIME) {\r
+        item.key = AUDIO_RECORD_CURRENT_FILE_REMAIND_TIME;\r
+    } else if (type == AUDIO_RECORD_CURRENT_STORAGE_REMAIN_TIME) {\r
+        item.key = AUDIO_RECORD_CURRENT_STORAGE_REMAIND_TIME;\r
+    }\r
+    item.value.u32Value = AudioRecorderGetPacketLength(recorderContext);\r
+    errcode_t ret = AudioRecorderMuxerGetParameter(recorderContext->muxerHandle, &item, 1);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_INFO_LOG("audio recorder muxer set parameter failed, ret = %d", ret);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    *time = item.value.u32Value;\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    return AUDIO_RECORDER_OK;\r
+}\r
+\r
+errcode_t AudioRecorderGetFileInfo(const AudioRecorderHandle handle, RecordFileInfo *info)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "audio recorder is NULL!");\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(info, AUDIO_RECORDER_INVALID_PARAM, "info is NULL!");\r
+    AudioRecorderContext *recorderContext = GetAudioRecorderContext(handle);\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(recorderContext, AUDIO_RECORDER_INVALID_PARAM, "recorderContext is NULL!");\r
+    AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+    if (recorderContext->state < AUDIO_RECORD_STATUS_PREPARED ||\r
+        recorderContext->state > AUDIO_RECORD_STATUS_START) {\r
+        AUDIO_RECORDER_ERR_LOG("the call is not allowed in the current state.state = %d", recorderContext->state);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    ParameterItem item = {};\r
+    item.key = AUDIO_RECORD_CURRENT_FILE_INFO;\r
+    char value[AUDIO_RECORDER_FILE_INFO_SIZE] = {};\r
+    item.value.pValue = value;\r
+    int32_t ret = AudioRecorderMuxerGetParameter(recorderContext->muxerHandle, &item, 1);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_INFO_LOG("audio recorder muxer set parameter failed, ret = %d", ret);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    ret = sscanf_s((const char *)item.value.pValue, "%llu,%u,%u,%u,%u,%u,%u,%u=%s",\r
+        &info->fileSize, &info->fileDateYear, &info->fileDateMonth, &info->fileDateDay, &info->fileDateHour,\r
+        &info->fileDateMin, &info->fileDateSec, &info->fileDuration, info->fileName, MAX_PATH_LEN);\r
+    if (ret == -1) {\r
+        MEDIA_ERR_LOG("sscanf_s failed, ret = %d", ret);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    return AUDIO_RECORDER_OK;\r
+}\r
+\r
+int32_t AudioRecorderCreateThread(AudioRecorderContext *recorderContext)\r
+{\r
+    MediaThreadattr producerAttr = { "AudioRecordProducerSch", MAX_PRODUCER_THREAD_STACK_SIZE,\r
+        THREAD_SCHED_INVALID, 80, false };\r
+    recorderContext->producerProcess = AUDIO_RECORDER_THREAD_CREATE(AudioRecorderProducerProcess,\r
+        recorderContext, &producerAttr);\r
+    if (recorderContext->producerProcess == NULL) {\r
+        AUDIO_RECORDER_ERR_LOG("record prosucer sch process thread create failed");\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    MediaThreadattr consumerAttr = { "AudioRecordConsumerSch", MAX_CONSUMER_THREAD_STACK_SIZE,\r
+        THREAD_SCHED_INVALID, 80, false };\r
+    recorderContext->consumerProcess = AUDIO_RECORDER_THREAD_CREATE(AudioRecorderConsumerProcess,\r
+        recorderContext, &consumerAttr);\r
+    if (recorderContext->consumerProcess == NULL) {\r
+        AUDIO_RECORDER_ERR_LOG("record consumer sch process thread create failed");\r
+        AUDIO_RECORDER_MUTEX_LOCK(recorderContext->producerLock);\r
+        recorderContext->producerThreadExit = true;\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->producerLock);\r
+        AUDIO_RECORDER_THREAD_COND_SIGNAL(recorderContext->producerCond);\r
+        AUDIO_RECORDER_THREAD_JOIN(&recorderContext->producerProcess);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    return AUDIO_RECORDER_OK;\r
+}\r
+\r
+errcode_t AudioRecorderStart(const AudioRecorderHandle handle)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "recorder is NULL!");\r
+    AudioRecorderContext *recorderContext = GetAudioRecorderContext(handle);\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(recorderContext, AUDIO_RECORDER_INVALID_PARAM, "recorderContext is NULL!");\r
+    AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+    if (recorderContext->state == AUDIO_RECORD_STATUS_START) {\r
+        AUDIO_RECORDER_INFO_LOG("no need to repeat record operation");\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    if (recorderContext->state != AUDIO_RECORD_STATUS_PREPARED) {\r
+        AUDIO_RECORDER_ERR_LOG("The status is incorrect. The recored cannot be performed.state = %d",\r
+            recorderContext->state);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    errcode_t ret = AudioRecorderMuxerStart(recorderContext->muxerHandle);\r
+    AUDIO_RECORD_CHECK_FAILED_RETURN_WITH_UNLOCK(ret, 0, ret, "muxer start failed", recorderContext->instanceLock);\r
+    ret = AudioStreamSinkStart(recorderContext);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("SinkStart failed");\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    if (AudioRecorderCreateThread(recorderContext) != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("AudioRecorderCreateThread failed");\r
+        AudioRecorderDestroyBufferData(recorderContext);\r
+        if (recorderContext->producerCond != NULL) {\r
+            AUDIO_RECORDER_THREAD_COND_DESTROY(&recorderContext->producerCond);\r
+        }\r
+        if (recorderContext->consumerCond != NULL) {\r
+            AUDIO_RECORDER_THREAD_COND_DESTROY(&recorderContext->consumerCond);\r
+        }\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    recorderContext->state = AUDIO_RECORD_STATUS_START;\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    return AUDIO_RECORDER_OK;\r
+}\r
+\r
+errcode_t AudioRecorderStop(const AudioRecorderHandle handle)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "lite recorder is NULL!");\r
+    AudioRecorderContext *recorderContext = GetAudioRecorderContext(handle);\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(recorderContext, AUDIO_RECORDER_INVALID_PARAM, "recorderContext is NULL!");\r
+    AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+    if ((recorderContext->state != AUDIO_RECORD_STATUS_START) &&\r
+        (recorderContext->state !=AUDIO_RECORD_STATUS_ERR)) {\r
+        AUDIO_RECORDER_INFO_LOG("current state: %d, no need to do stop", recorderContext->state);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return AUDIO_RECORDER_ERR;\r
+    }\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    if (recorderContext->producerProcess != NULL) {\r
+        AUDIO_RECORDER_MUTEX_LOCK(recorderContext->producerLock);\r
+        recorderContext->producerThreadExit = true;\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->producerLock);\r
+        AUDIO_RECORDER_THREAD_COND_SIGNAL(recorderContext->producerCond);\r
+        AUDIO_RECORDER_THREAD_JOIN(&recorderContext->producerProcess);\r
+        recorderContext->producerProcess = NULL;\r
+    }\r
+    if (recorderContext->consumerProcess != NULL) {\r
+        AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+        recorderContext->consumerThreadExit = true;\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        AUDIO_RECORDER_THREAD_COND_SIGNAL(recorderContext->consumerCond);\r
+        AUDIO_RECORDER_THREAD_JOIN(&recorderContext->consumerProcess);\r
+        recorderContext->consumerProcess = NULL;\r
+    }\r
+    AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+#ifdef SUPPORT_AUDIO_STREAM_IN_C\r
+    errcode_t ret = AudioStreamInStop(recorderContext->audioStreamInHandle);\r
+#else\r
+    int32_t ret = AudioStreamInStop();\r
+#endif\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("stream out stop failed = %d", ret);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return ret;\r
+    }\r
+    ret = AudioRecorderMuxerStop(recorderContext->muxerHandle);\r
+    if (ret != AUDIO_RECORDER_OK) {\r
+        AUDIO_RECORDER_ERR_LOG("muxer stop failed = %d", ret);\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        return ret;\r
+    }\r
+    recorderContext->state = AUDIO_RECORD_STATUS_STOPPED;\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    return AUDIO_RECORDER_OK;\r
+}\r
+\r
+errcode_t AudioRecorderDestroy(const AudioRecorderHandle handle)\r
+{\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(handle, AUDIO_RECORDER_INVALID_PARAM, "audio recorder is NULL!");\r
+    AudioRecorderContext *recorderContext = GetAudioRecorderContext(handle);\r
+    AUDIO_RECORD_CHECK_NULL_RETURN(recorderContext, AUDIO_RECORDER_INVALID_PARAM, "recorderContext is NULL!");\r
+    AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+    if (recorderContext->state != AUDIO_RECORD_STATUS_IDLE &&\r
+        recorderContext->state != AUDIO_RECORD_STATUS_STOPPED) {\r
+        AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+        AudioRecorderStop(handle);\r
+        AUDIO_RECORDER_MUTEX_LOCK(recorderContext->instanceLock);\r
+    }\r
+    AudioRecorderMuxerDestroy(recorderContext->muxerHandle);\r
+#ifdef SUPPORT_AUDIO_STREAM_IN_C\r
+    AudioStreamInRelease(recorderContext->audioStreamInHandle);\r
+    AudioStreamInDestroy(recorderContext->audioStreamInHandle);\r
+#else\r
+    AudioStreamInDeinit();\r
+#endif\r
+    AudioRecorderDestroyBufferData(recorderContext);\r
+    if (recorderContext->producerCond != NULL) {\r
+        AUDIO_RECORDER_THREAD_COND_DESTROY(&recorderContext->producerCond);\r
+    }\r
+    if (recorderContext->consumerCond != NULL) {\r
+        AUDIO_RECORDER_THREAD_COND_DESTROY(&recorderContext->consumerCond);\r
+    }\r
+    recorderContext->isUsed = false;\r
+    AUDIO_RECORDER_MUTEX_UNLOCK(recorderContext->instanceLock);\r
+    AUDIO_RECORDER_MUTEX_DESTROY(&recorderContext->producerLock);\r
+    return AUDIO_RECORDER_OK;\r
+}\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
diff --git a/code/sdk/middleware/services/media/foundation/audio_recorder/frameworks/muxer/include/audio_recorder_muxer.h b/code/sdk/middleware/services/media/foundation/audio_recorder/frameworks/muxer/include/audio_recorder_muxer.h
new file mode 100644 (file)
index 0000000..4212c7b
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+ * Description: audio recorder muxer define
+ * Author: Media Software Group
+ * Create: 2025-03-15
+ */
+
+#ifndef AUDIO_RECORDER_MUXER_H
+#define AUDIO_RECORDER_MUXER_H
+
+#include <stdint.h>
+#include "audio_base_type.h"
+#include "format_type.h"
+#include "format_interface.h"
+#include "parameter_item.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void *AudioRecorderMuxer;
+
+typedef enum {
+    ERROR_TYPE_CREATE_FILE_FAIL,
+    ERROR_TYPE_WRITE_FILE_FAIL,
+    ERROR_TYPE_CLOSE_FILE_FAIL,
+    ERROR_TYPE_INTERNAL_OPERATION_FAIL,
+    EVENT_ERROR_BUTT,
+} EventErrorType;
+
+typedef enum {
+    MAX_DURATION_APPROACHING,
+    MAX_FILESIZE_APPROACHING,
+    MAX_DURATION_REACHED,
+    MAX_FILESIZE_REACHED,
+    NEXT_OUTPUT_FILE_STARTED,
+    FILE_SPLIT_FINISHED,
+    FILE_START_TIME_MS,
+    NEXT_FILE_FD_NOT_SET,
+    DEMUXER_PREPARED = 10000,
+    DEMUXER_SEEK_COMPLETE,
+    DEMUXER_NETWORK_DISCONNECTED,
+    DEMUXER_NETWORK_RECONNECTED,
+    MAX_MEMORYSIZE_REACHED,
+    EVENT_INFO_BUTT,
+} EventInfoType;
+
+typedef struct {
+    void *handle;
+    int32_t (*OnInfoCallback)(void *handle, EventInfoType type, int32_t ext);
+    int32_t (*OnErrorCallback)(void *handle, EventErrorType type, int32_t ext);
+} MuxerCallback;
+
+int32_t AudioRecorderMuxerCreate(AudioRecorderMuxer *muxerHandle);
+int32_t AudioRecorderMuxerSetOutputPath(AudioRecorderMuxer muxerHandle,
+    AudioCodecFormat formatType, const char *outPath, const uint32_t outPathLen);
+int32_t AudioRecorderMuxerAddTrack(AudioRecorderMuxer muxerHandle, const CapturerInputConfig *info);
+int32_t AudioRecorderMuxerSetMaxDuration(AudioRecorderMuxer muxerHandle, int64_t duration);
+int32_t AudioRecorderMuxerSetMaxFileSize(AudioRecorderMuxer muxerHandle, int64_t fileSize);
+int32_t AudioRecorderMuxerSetCallBack(AudioRecorderMuxer muxerHandle, const MuxerCallback *callBack);
+int32_t AudioRecorderMuxerPrepare(AudioRecorderMuxer muxerHandle);
+int32_t AudioRecorderMuxerStart(AudioRecorderMuxer muxerHandle);
+int32_t AudioRecorderMuxerWriteData(AudioRecorderMuxer muxerHandle, FormatFrame *frame);
+int32_t AudioRecorderMuxerSetParameter(AudioRecorderMuxer muxerHandle, const ParameterItem *item, int32_t itemNum);
+int32_t AudioRecorderMuxerGetParameter(AudioRecorderMuxer muxerHandle, ParameterItem *item, int32_t itemNum);
+int32_t AudioRecorderMuxerStop(AudioRecorderMuxer muxerHandle);
+int32_t AudioRecorderMuxerDestroy(AudioRecorderMuxer muxerHandle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/foundation/audio_recorder/frameworks/muxer/src/audio_recorder_muxer.c b/code/sdk/middleware/services/media/foundation/audio_recorder/frameworks/muxer/src/audio_recorder_muxer.c
new file mode 100644 (file)
index 0000000..d1a1a41
--- /dev/null
@@ -0,0 +1,376 @@
+/*\r
+ * Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.\r
+ * Description: audio recorder muxer define\r
+ * Author: Media Software Group\r
+ * Create: 2025-03-10\r
+ */\r
+\r
+#include "audio_recorder_muxer.h"\r
+#include "media_log.h"\r
+#include "format_interface.h"\r
+#include "format_type.h"\r
+#include "securec.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#define LOG_MODULE_NAME "AudioRecorderMuxer"\r
+#define READ_FRAME_TIMEOUT 20\r
+#define MUXER_INSTANCE_NUM 2\r
+#define HANDLE_SHIFT_LEN 16\r
+#define MUXER_INVAILD_ID 0xFFFF\r
+#define MUXER_MAGIC_ID 0xBBBA\r
+#define GET_MUXER_MAGIC_ID(handle) (((uint32_t)(handle)) >> HANDLE_SHIFT_LEN)\r
+#define GET_MUXER_HANDLE(id) ((MUXER_MAGIC_ID << HANDLE_SHIFT_LEN) | (id))\r
+#define GET_MUXER_ID(handle) (((uint32_t)(handle)) & 0xFFFF)\r
+\r
+#define CHECK_NULL_RETURN(ptr, ret, outStr) \\r
+do { \\r
+    if ((ptr) == NULL) { \\r
+        MEDIA_ERR_LOG("%s ", ((outStr) != NULL) ? (outStr) : " "); \\r
+        return (ret); \\r
+    } \\r
+} while (0)\r
+\r
+#define CHECK_FAILED_RETURN(value, target, ret, outStr) \\r
+do { \\r
+    if ((value) != (target)) { \\r
+        MEDIA_ERR_LOG("%s ", ((outStr) != NULL) ? (outStr) : " "); \\r
+        return (ret); \\r
+    } \\r
+} while (0)\r
+\r
+typedef struct {\r
+    bool inited;\r
+    bool prepared;\r
+    bool started;\r
+    void *formatMuxerHandle;\r
+    FormatCallback formatListener;\r
+    int64_t maxFileSize;\r
+    int64_t maxDuration;\r
+    bool isUsed;\r
+    MuxerCallback callBack;\r
+    void *priv;\r
+    FormatOutputConfig outputConfig;\r
+} AudioRecorderMuxerContext;\r
+\r
+\r
+static AudioRecorderMuxerContext g_muxerContext[MUXER_INSTANCE_NUM] = {\r
+    {.formatMuxerHandle = NULL},\r
+    {.formatMuxerHandle = NULL},\r
+};\r
+\r
+static int32_t g_muxerContextId[MUXER_INSTANCE_NUM] = { -1, -1};\r
+\r
+static AudioRecorderMuxerContext *GetMuxerContext(const AudioRecorderMuxer handle)\r
+{\r
+    AudioRecorderMuxerContext *muxerContext = NULL;\r
+    uint16_t muxerId;\r
+    if (GET_MUXER_MAGIC_ID(handle) != MUXER_MAGIC_ID) {\r
+        MEDIA_ERR_LOG("invalid muxer handle!");\r
+        goto EXIT;\r
+    }\r
+    muxerId = GET_MUXER_ID(handle);\r
+    if (muxerId >= MUXER_INSTANCE_NUM) {\r
+        MEDIA_ERR_LOG("invalid muxer id: %u!", muxerId);\r
+        goto EXIT;\r
+    }\r
+    if (!g_muxerContext[muxerId].isUsed) {\r
+        MEDIA_ERR_LOG("muxer handle: 0x%x error, isUsed: %d", handle, g_muxerContext[muxerId].isUsed);\r
+        goto EXIT;\r
+    }\r
+    muxerContext = &g_muxerContext[muxerId];\r
+EXIT:\r
+    return muxerContext;\r
+}\r
+\r
+static uint16_t GetNewMuxerId(void)\r
+{\r
+    uint16_t muxerId;\r
+    for (muxerId = 0; muxerId < MUXER_INSTANCE_NUM; muxerId++) {\r
+        if (g_muxerContextId[muxerId] == -1) {\r
+            g_muxerContextId[muxerId] = muxerId;\r
+            break;\r
+        }\r
+    }\r
+    return muxerId;\r
+}\r
+\r
+static uint16_t GetMuxerAvailableId(void)\r
+{\r
+    uint16_t muxerId = GetNewMuxerId();\r
+    if (muxerId >= MUXER_INSTANCE_NUM) {\r
+        for (muxerId = 0; muxerId < MUXER_INSTANCE_NUM; muxerId++) {\r
+            if (!g_muxerContext[muxerId].isUsed) {\r
+                g_muxerContextId[muxerId] = -1;\r
+            }\r
+        }\r
+        muxerId = GetNewMuxerId();\r
+    }\r
+    return muxerId;\r
+}\r
+\r
+static int32_t ErrorEventProc(void *handle, int32_t errorType, int32_t errorCode)\r
+{\r
+    AudioRecorderMuxerContext *muxerContext = (AudioRecorderMuxerContext *)handle;\r
+    CHECK_NULL_RETURN(muxerContext, MEDIA_INVALID_PARAM, "handle is NULL!");\r
+    if (muxerContext->callBack.OnErrorCallback == NULL || muxerContext->callBack.handle == NULL) {\r
+        MEDIA_ERR_LOG("ErrorCallBack or handle is NULL");\r
+        return MEDIA_INVALID_PARAM;\r
+    }\r
+    return muxerContext->callBack.OnErrorCallback(muxerContext->callBack.handle, errorType, errorCode);\r
+}\r
+\r
+static int32_t InfoEventProc(void *handle, int32_t type, int32_t extra)\r
+{\r
+    AudioRecorderMuxerContext *muxerContext = (AudioRecorderMuxerContext *)handle;\r
+    CHECK_NULL_RETURN(muxerContext, MEDIA_INVALID_PARAM, "handle is NULL!");\r
+    if (muxerContext->callBack.OnInfoCallback == NULL || muxerContext->callBack.handle == NULL) {\r
+        MEDIA_ERR_LOG("InfoCallBack or handle is NULL");\r
+        return MEDIA_INVALID_PARAM;\r
+    }\r
+    return muxerContext->callBack.OnInfoCallback(muxerContext->callBack.handle, type, extra);\r
+}\r
+\r
+int32_t AudioRecorderMuxerCreate(AudioRecorderMuxer *muxerHandle)\r
+{\r
+    CHECK_NULL_RETURN(muxerHandle, MEDIA_INVALID_PARAM, "handle is NULL!");\r
+    uint16_t muxerId = GetMuxerAvailableId();\r
+    if (muxerId >= MUXER_INSTANCE_NUM) {\r
+        *muxerHandle = NULL;\r
+        MEDIA_ERR_LOG("not found free asi handle id!");\r
+        return MEDIA_ERR;\r
+    }\r
+    g_muxerContext[muxerId].inited = false;\r
+    g_muxerContext[muxerId].prepared = false;\r
+    g_muxerContext[muxerId].started = false;\r
+    g_muxerContext[muxerId].formatMuxerHandle = NULL;\r
+    g_muxerContext[muxerId].outputConfig.type = OUTPUT_TYPE_URI;\r
+    g_muxerContext[muxerId].outputConfig.fd = -1;\r
+    g_muxerContext[muxerId].outputConfig.format = OUTPUT_FORMAT_INVALID;\r
+    g_muxerContext[muxerId].maxFileSize = -1;\r
+    g_muxerContext[muxerId].maxDuration = -1;\r
+    g_muxerContext[muxerId].formatListener.OnError = ErrorEventProc;\r
+    g_muxerContext[muxerId].formatListener.OnInfo = InfoEventProc;\r
+    g_muxerContext[muxerId].formatListener.privateDataHandle = &g_muxerContext[muxerId];\r
+    g_muxerContext[muxerId].isUsed = true;\r
+    g_muxerContext[muxerId].priv = NULL;\r
+    *muxerHandle = (AudioRecorderMuxer)GET_MUXER_HANDLE(muxerId);\r
+    \r
+    return MEDIA_OK;\r
+}\r
+\r
+static void ConvertFormat(AudioCodecFormat formatType, FormatOutputConfig *outputConfig)\r
+{\r
+    if (outputConfig == NULL) {\r
+        MEDIA_ERR_LOG("outputConfig is NULL!");\r
+        return;\r
+    }\r
+    switch (formatType) {\r
+        case MP3:\r
+            outputConfig->format = OUTPUT_FORMAT_MP3;\r
+            break;\r
+        case PCM:\r
+            outputConfig->format = OUTPUT_FORMAT_WAV;\r
+            break;\r
+        case SILK:\r
+            outputConfig->format = OUTPUT_FORMAT_SILK;\r
+            break;\r
+        case OPUS:\r
+            outputConfig->format = OUTPUT_FORMAT_OGG;\r
+            break;\r
+        default:
+            MEDIA_ERR_LOG("not support format type = %d,", formatType);
+            break;\r
+    }\r
+}\r
+\r
+int32_t AudioRecorderMuxerSetOutputPath(AudioRecorderMuxer muxerHandle,\r
+    AudioCodecFormat formatType, const char *outPath, const uint32_t outPathLen)\r
+{\r
+    CHECK_NULL_RETURN(muxerHandle, MEDIA_INVALID_PARAM, "muxer handle is null");\r
+    AudioRecorderMuxerContext *muxerContext = GetMuxerContext(muxerHandle);\r
+    CHECK_NULL_RETURN(muxerContext, MEDIA_INVALID_PARAM, "muxer context is invalid!");\r
+    if (memcpy_s(muxerContext->outputConfig.url, URL_LEN, outPath, outPathLen) != EOK) {\r
+        MEDIA_ERR_LOG("memcpy_s failed %s", outPath);\r
+        return MEDIA_INVALID_PARAM;\r
+    }\r
+    ConvertFormat(formatType, &muxerContext->outputConfig);\r
+    int32_t ret = FormatMuxerCreate(&muxerContext->formatMuxerHandle, &muxerContext->outputConfig);\r
+    if (ret != MEDIA_OK || muxerContext->formatMuxerHandle == NULL) {\r
+        muxerContext->isUsed = false;\r
+        MEDIA_ERR_LOG("FormatMuxerCreate failed");\r
+        return MEDIA_ERR;\r
+    }\r
+    muxerContext->inited = true;\r
+    return MEDIA_OK;\r
+}\r
+\r
+int32_t AudioRecorderMuxerAddTrack(AudioRecorderMuxer muxerHandle, const CapturerInputConfig *info)\r
+{\r
+    CHECK_NULL_RETURN(muxerHandle, MEDIA_INVALID_PARAM, "muxer handle is null");\r
+    AudioRecorderMuxerContext *muxerContext = GetMuxerContext(muxerHandle);\r
+    CHECK_NULL_RETURN(muxerContext, MEDIA_INVALID_PARAM, "muxer context is invalid!");\r
+    TrackSource trackSource = {};\r
+    trackSource.trackSourceType = TRACK_SOURCE_TYPE_AUDIO;\r
+    trackSource.trackSourceInfo.audioInfo.codecType = CODEC_PCM;\r
+    trackSource.trackSourceInfo.audioInfo.sampleRate = info->sampleRate;\r
+    trackSource.trackSourceInfo.audioInfo.channelCount = info->channelCount;\r
+#ifdef SUPPORT_NEW_FORMAT\r
+    trackSource.trackSourceInfo.audioInfo.sampleBitWidth = (FormatAudioSampleFmt)info->bitWidth;\r
+#else\r
+    trackSource.trackSourceInfo.audioInfo.sampleBitWidth = (AudioSampleFmt)info->bitWidth;\r
+#endif\r
+    trackSource.trackSourceInfo.audioInfo.samplesPerFrame = 0;\r
+    trackSource.trackSourceInfo.audioInfo.avgBytesPerSec = 0;\r
+    return FormatMuxerAddTrack(muxerContext->formatMuxerHandle, &trackSource);\r
+}\r
+\r
+int32_t AudioRecorderMuxerSetMaxDuration(AudioRecorderMuxer muxerHandle, int64_t duration)\r
+{\r
+    CHECK_NULL_RETURN(muxerHandle, MEDIA_INVALID_PARAM, "muxer handle is null");\r
+    AudioRecorderMuxerContext *muxerContext = GetMuxerContext(muxerHandle);\r
+    CHECK_NULL_RETURN(muxerContext, MEDIA_INVALID_PARAM, "muxer context is invalid!");\r
+    if (muxerContext->started) {\r
+        MEDIA_ERR_LOG("Recorder is started ,SetMaxDuration must be setted before Prepare");\r
+        return MEDIA_ERR;\r
+    }\r
+    if (duration <= 0) {\r
+        MEDIA_ERR_LOG("invalid  MaxDuration size:%lld", duration);\r
+        return MEDIA_INVALID_PARAM;\r
+    }\r
+    muxerContext->maxDuration = duration;\r
+    if (!muxerContext->prepared) {\r
+        MEDIA_ERR_LOG("current state is not prepared, can not set!");\r
+        return MEDIA_ERR;\r
+    }\r
+    return FormatMuxerSetMaxFileDuration(muxerContext->formatMuxerHandle, duration);\r
+}\r
+\r
+int32_t AudioRecorderMuxerSetMaxFileSize(AudioRecorderMuxer muxerHandle, int64_t fileSize)\r
+{\r
+    CHECK_NULL_RETURN(muxerHandle, MEDIA_INVALID_PARAM, "muxer handle is null");\r
+    AudioRecorderMuxerContext *muxerContext = GetMuxerContext(muxerHandle);\r
+    CHECK_NULL_RETURN(muxerContext, MEDIA_INVALID_PARAM, "muxer context is invalid!");\r
+    if (muxerContext->started) {\r
+        MEDIA_ERR_LOG("Recorder is started ,SetMaxFileSize must be setted before Prepare");\r
+        return MEDIA_ERR;\r
+    }\r
+    if (fileSize <= 0) {\r
+        MEDIA_ERR_LOG("invalid  MaxFileSize size:%lld", fileSize);\r
+        return MEDIA_INVALID_PARAM;\r
+    }\r
+    muxerContext->maxFileSize = fileSize;\r
+    if (!muxerContext->prepared) {\r
+        MEDIA_ERR_LOG("current state is not prepared, can not set!");\r
+        return MEDIA_ERR;\r
+    }\r
+    return FormatMuxerSetMaxFileSize(muxerContext->formatMuxerHandle, fileSize);\r
+}\r
+\r
+int32_t AudioRecorderMuxerSetCallBack(AudioRecorderMuxer muxerHandle, const MuxerCallback *callBack)\r
+{\r
+    CHECK_NULL_RETURN(muxerHandle, MEDIA_INVALID_PARAM, "muxer handle is null");\r
+    CHECK_NULL_RETURN(callBack, MEDIA_INVALID_PARAM, "callBack is null");\r
+    AudioRecorderMuxerContext *muxerContext = GetMuxerContext(muxerHandle);\r
+    CHECK_NULL_RETURN(muxerContext, MEDIA_INVALID_PARAM, "muxer context is invalid!");\r
+    muxerContext->callBack = *callBack;\r
+    return MEDIA_OK;\r
+}\r
+\r
+int32_t AudioRecorderMuxerPrepare(AudioRecorderMuxer muxerHandle)\r
+{\r
+    CHECK_NULL_RETURN(muxerHandle, MEDIA_INVALID_PARAM, "muxer handle is null");\r
+    AudioRecorderMuxerContext *muxerContext = GetMuxerContext(muxerHandle);\r
+    CHECK_FAILED_RETURN(muxerContext->inited, true, MEDIA_INVALID_PARAM, "not inited");\r
+    if (muxerContext->prepared) {\r
+        return MEDIA_OK;\r
+    }\r
+    if (muxerContext->maxDuration != -1) {\r
+        int32_t ret = FormatMuxerSetMaxFileDuration(muxerContext->formatMuxerHandle, muxerContext->maxDuration);\r
+        if (ret != MEDIA_OK) {\r
+            MEDIA_ERR_LOG("FormatMuxersetMaxFileDuration failed 0x%x", ret);\r
+        }\r
+    }\r
+    if (muxerContext->maxFileSize != -1) {\r
+        int32_t ret = FormatMuxerSetMaxFileSize(muxerContext->formatMuxerHandle, muxerContext->maxFileSize);\r
+        if (ret != MEDIA_OK) {\r
+            MEDIA_ERR_LOG("FormatMuxersetMaxFileSize failed 0x%x", ret);\r
+        }\r
+    }\r
+    if (FormatMuxerSetCallBack(muxerContext->formatMuxerHandle, &muxerContext->formatListener) != 0) {\r
+        MEDIA_ERR_LOG("FormatMuxerSetCallBack failed");\r
+    }\r
+    muxerContext->prepared = true;\r
+    return MEDIA_OK;\r
+}\r
+\r
+int32_t AudioRecorderMuxerStart(AudioRecorderMuxer muxerHandle)\r
+{\r
+    CHECK_NULL_RETURN(muxerHandle, MEDIA_INVALID_PARAM, "muxer handle is null");\r
+    AudioRecorderMuxerContext *muxerContext = GetMuxerContext(muxerHandle);\r
+    CHECK_NULL_RETURN(muxerContext, MEDIA_INVALID_PARAM, "muxer context is invalid!");\r
+    CHECK_FAILED_RETURN(muxerContext->prepared, true, -1, "not prepared");\r
+    int32_t ret = FormatMuxerStart(muxerContext->formatMuxerHandle);\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("FormatMuxerStart failed 0x%x", ret);\r
+        return ret;\r
+    }\r
+    muxerContext->started = true;\r
+    return MEDIA_OK;\r
+}\r
+\r
+int32_t AudioRecorderMuxerWriteData(AudioRecorderMuxer muxerHandle, FormatFrame *frame)\r
+{\r
+    CHECK_NULL_RETURN(muxerHandle, MEDIA_INVALID_PARAM, "muxer handle is null");\r
+    AudioRecorderMuxerContext *muxerContext = GetMuxerContext(muxerHandle);\r
+    CHECK_NULL_RETURN(muxerContext, MEDIA_INVALID_PARAM, "muxer context is invalid!");\r
+    CHECK_FAILED_RETURN(muxerContext->started, true, -1, "not started");\r
+    return FormatMuxerWriteFrame(muxerContext->formatMuxerHandle, frame);\r
+}\r
+\r
+int32_t AudioRecorderMuxerSetParameter(AudioRecorderMuxer muxerHandle, const ParameterItem *item, int32_t itemNum)\r
+{\r
+    CHECK_NULL_RETURN(muxerHandle, MEDIA_INVALID_PARAM, "muxer handle is null");\r
+    AudioRecorderMuxerContext *muxerContext = GetMuxerContext(muxerHandle);\r
+    CHECK_NULL_RETURN(muxerContext, MEDIA_INVALID_PARAM, "muxer context is invalid!");\r
+    CHECK_FAILED_RETURN(muxerContext->prepared, true, -1, "not prepared");\r
+    return FormatMuxerSetParameter(muxerContext->formatMuxerHandle, 0, item, itemNum);\r
+}\r
+\r
+int32_t AudioRecorderMuxerGetParameter(AudioRecorderMuxer muxerHandle, ParameterItem *item, int32_t itemNum)\r
+{\r
+    CHECK_NULL_RETURN(muxerHandle, MEDIA_INVALID_PARAM, "muxer handle is null");\r
+    AudioRecorderMuxerContext *muxerContext = GetMuxerContext(muxerHandle);\r
+    CHECK_NULL_RETURN(muxerContext, MEDIA_INVALID_PARAM, "muxer context is invalid!");\r
+    CHECK_FAILED_RETURN(muxerContext->started, true, -1, "not started");\r
+    return FormatMuxerGetParameter(muxerContext->formatMuxerHandle, 0, item, itemNum);\r
+}\r
+\r
+int32_t AudioRecorderMuxerStop(AudioRecorderMuxer muxerHandle)\r
+{\r
+    CHECK_NULL_RETURN(muxerHandle, MEDIA_INVALID_PARAM, "muxer handle is null");\r
+    AudioRecorderMuxerContext *muxerContext = GetMuxerContext(muxerHandle);\r
+    CHECK_NULL_RETURN(muxerContext, MEDIA_INVALID_PARAM, "muxer context is invalid!");\r
+    if (muxerContext->formatMuxerHandle == NULL) {\r
+        return MEDIA_OK;\r
+    }\r
+    return FormatMuxerStop(muxerContext->formatMuxerHandle, true);\r
+}\r
+\r
+int32_t AudioRecorderMuxerDestroy(AudioRecorderMuxer muxerHandle)\r
+{\r
+    CHECK_NULL_RETURN(muxerHandle, MEDIA_INVALID_PARAM, "muxer handle is null");\r
+    AudioRecorderMuxerContext *muxerContext = GetMuxerContext(muxerHandle);\r
+    CHECK_NULL_RETURN(muxerContext, MEDIA_INVALID_PARAM, "muxer context is invalid!");\r
+    if (muxerContext->formatMuxerHandle != NULL) {\r
+        FormatMuxerDestroy(muxerContext->formatMuxerHandle);\r
+        muxerContext->formatMuxerHandle = NULL;\r
+    }\r
+    muxerContext->isUsed = false;\r
+    return MEDIA_OK;\r
+}\r
+#ifdef __cplusplus\r
+}\r
+#endif
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/audio_recorder.h b/code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/audio_recorder.h
new file mode 100644 (file)
index 0000000..6e51866
--- /dev/null
@@ -0,0 +1,442 @@
+/*\r
+ * Copyright (c) CompanyNameMagicTag. 2024-2024. All rights reserved.\r
+ * Description: audio recorder\r
+ * Author: Media Software Group\r
+ * Create: 2024-08-22\r
+ */\r
+\r
+#ifndef AUDIO_RECORDER_H\r
+#define AUDIO_RECORDER_H\r
+\r
+#include <stdint.h>\r
+#include "audio_base_type.h"\r
+#include "errcode.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+typedef void* AudioRecorderHandle;\r
+\r
+#define MAX_PATH_LEN 256\r
+\r
+typedef enum {\r
+    AUDIO_RECORD_STATUS_ERR = 0, /*!< @if Eng error status.\r
+                                        @else   错误状态 @endif */\r
+    AUDIO_RECORD_STATUS_IDLE = 1, /*!< @if Eng idle status.\r
+                                        @else   就绪状态 @endif */\r
+    AUDIO_RECORD_STATUS_INIT = 2, /*!< @if Eng init status.\r
+                                        @else   初始化状态 @endif */\r
+    AUDIO_RECORD_STATUS_PREPARING = 3, /*!< @if Eng Prepareing status.\r
+                                        @else   准备中状态 @endif */\r
+    AUDIO_RECORD_STATUS_PREPARED = 4, /*!< @if Eng Prepared status.\r
+                                        @else   准备状态 @endif */\r
+    AUDIO_RECORD_STATUS_START = 5, /*!< @if Eng start status.\r
+                                        @else   记录开始状态 @endif */\r
+    AUDIO_RECORD_STATUS_STOPPED = 6, /*!< @if Eng stop status.\r
+                                        @else   记录停止状态 @endif */\r
+} AudioRecorderStates;\r
+\r
+typedef enum {\r
+    AUDIO_RECORD_EVENT_ERROR, /*!< @if Eng error event.\r
+                                        @else   错误事件 @endif */\r
+    AUDIO_RECORD_STORAGE_REACHE_MAX_VALUE, /*!< @if Eng The storage reaches the maximum value.\r
+                                        @else   录制内存达到最大值事件 @endif */\r
+    AUDIO_RECORD_EVENT_BUTT\r
+} AudioRecorderEvent;\r
+\r
+typedef enum {\r
+    AUDIO_RECORD_CURRENT_FILE_REMAIN_TIME, /*!< @if Eng Obtains the remaining recording time of the current file.\r
+                                            @else   获取当前文件剩余录制时间 @endif */\r
+    AUDIO_RECORD_CURRENT_STORAGE_REMAIN_TIME, /*!< @if Eng Obtains the remaining recording time of the current space.\r
+                                            @else   获取当前空间剩余录制时间 @endif */\r
+} RemainTimeType;\r
+\r
+typedef struct {\r
+    char fileName[MAX_PATH_LEN];\r
+    uint64_t fileSize;\r
+    uint32_t fileDateYear;\r
+    uint32_t fileDateMonth;\r
+    uint32_t fileDateDay;\r
+    uint32_t fileDateHour;\r
+    uint32_t fileDateMin;\r
+    uint32_t fileDateSec;\r
+    uint32_t fileDuration;\r
+} RecordFileInfo;\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief recorder callback function.\r
+ *\r
+ * Sets the callback event reported when the record is successful or abnormal.\r
+ *\r
+ * @param [in] enEvent Indicates the Callback Event Type, see {@link AudioRecorderEvent}.\r
+ * @param [in] data Indicates the Event return value.\r
+ * @param [in] cookie Indicates the Context transferred by the callback function.\r
+ * @return void.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief 本地录音回调函数。\r
+ *\r
+ * 设置记录成功或异常时上报的回调事件。\r
+ *\r
+ * @param [in] enEvent 回调事件类型,参考{@link AudioRecorderEvent}。\r
+ * @param [in] data 事件返回值。\r
+ * @param [in] cookie 回调函数传入的Context。\r
+ * @return void.\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+typedef void (*RecorderCallback)(uint32_t enEvent, const void *data, const void *cookie);\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief create recorder.\r
+ *\r
+ * @param [out] handle Indicates the recorder instance.\r
+ * @return Returns <b>0</b> if the setting is successful; otherwise is failed.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief 创建本地录音。\r
+ *\r
+ * @param [out] handle 本地录音实例。\r
+ * @return 如果设置成功返回<b>0</b>,否则返回失败。\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+errcode_t AudioRecorderCreate(AudioRecorderHandle *handle);\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief Setting the Recording Configuration Information.\r
+ *\r
+ * @param [in] handle Indicates the recorder instance.[in]\r
+ * @param [in] config Indicates the Recording collection configuration information.[in]\r
+ * @return Returns <b>0</b> if the setting is successful; otherwise is failed.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief 设置录音配置信息。\r
+ *\r
+ * @param [in] handle 本地录音实例。\r
+ * @param [in] config 录音采集配置信息。\r
+ * @return 如果设置成功返回<b>0</b>,否则返回失败。\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+errcode_t AudioRecorderSetInfo(const AudioRecorderHandle handle, const CapturerInputConfig *config);\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief Setting the directory for recording files.\r
+ *\r
+ * @param [in] handle Indicates the recorder instance.\r
+ * @param [in] outPath Indicates the output directory.\r
+ * @param [in] outPathLen Indicates the length of the output directory.\r
+ * @return Returns <b>0</b> if the setting is successful; otherwise is failed.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief设置录制文件的目录。\r
+ *\r
+ * @param [in] handle 本地录音实例。\r
+ * @param [in] outPath 输出目录。\r
+ * @param [in] outPathLen 输出目录长度。\r
+ * @return 如果设置成功返回<b>0</b>,否则返回失败。\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+errcode_t AudioRecorderSetOutputPath(const AudioRecorderHandle handle, const char *outPath, uint32_t outPathLen);\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief sets whether to overwrite the earliest recording file when the recording file is full.\r
+ *\r
+ * sets the enable after the AudioRecorderPrepare is be called.\r
+ *\r
+ * @param [in] handle Indicates the recorder instance.\r
+ * @param [in] enable Indicates whether to overwrite the earliest recording file cyclically.\r
+ * @return Returns <b>0</b> Indicates that the setting is successful.; otherwise is failed.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief 设置录音文件满时是否覆盖最早的录音文件。\r
+ *\r
+ * 此函数必须在{@link AudioRecorderPrepare}之后调用。\r
+ *\r
+ * @param [in] handle 本地录音实例。\r
+ * @param [in] enable 是否循环覆盖最早的录像文件。\r
+ * @return 返回 <b>0</b>表示设置成功。;否则失败。\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+errcode_t AudioRecorderEnableOverwriteFiles(const AudioRecorderHandle handle, bool enable);\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief setting the Warning Threshold for Remaining Storage.\r
+ *\r
+ * sets the percent after the AudioRecorderPrepare is be called.\r
+ *\r
+ * @param [in] handle Indicates the recorder instance.\r
+ * @param [in] percent Indicates the percentage of the storage space. the value ranges from 0 to 100.\r
+ * @return Returns <b>0</b> Indicates that the setting is successful.; otherwise is failed.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief 设置剩余存储空间的警告阈值。\r
+ *\r
+ * 此函数必须在{@link AudioRecorderPrepare}之后调用。\r
+ *\r
+ * @param [in] handle 本地录音实例。\r
+ * @param [in] percent 存储空间百分比,取值范围0~100。\r
+ * @return 返回 <b>0</b>表示设置成功。;否则失败。\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+\r
+errcode_t AudioRecorderSetStorageWarningThreshold(const AudioRecorderHandle handle, uint32_t percent);\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief setting the Maximum Duration for Splitting a File.\r
+ *\r
+ * This function must be called after {@link AudioRecorderPrepare}.\r
+ *\r
+ * @param [in] handle Indicates the recorder instance.\r
+ * @param [in] duration Indicates the total duration for splitting a file.\r
+ * @return Returns <b>0</b> Indicates that the setting is successful.; otherwise is failed.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief 设置文件分割的最大时长。\r
+ *\r
+ * 此函数必须在{@link AudioRecorderPrepare}之后调用。\r
+ *\r
+ * @param [in] handle 本地录音实例。\r
+ * @param [in] duration 表示拆分文件的总时长。\r
+ * @return 返回 <b>0</b>表示设置成功。;否则失败。\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+errcode_t AudioRecorderSetMaxDuration(const AudioRecorderHandle handle, uint32_t duration);\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief setting the Maximum size for Splitting a File.\r
+ *\r
+ * This function must be called after {@link AudioRecorderPrepare}.\r
+ *\r
+ * @param [in] handle Indicates the recorder instance.\r
+ * @param [in] size Indicates the total size for splitting a file.\r
+ * @return Returns <b>0</b> Indicates that the setting is successful.; otherwise is failed.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief 设置分割文件的最大大小。\r
+ *\r
+ * 此函数必须在{@link AudioRecorderPrepare}之后调用。\r
+ *\r
+ * @param [in] handle 本地录音实例。\r
+ * @param [in] size 表示分割文件的总大小。\r
+ * @return 返回 <b>0</b>表示设置成功。;否则失败。\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+errcode_t AudioRecorderSetMaxFileSize(const AudioRecorderHandle handle, uint64_t size);\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief Registers the recorder callback function.\r
+ *\r
+ * @param [in] handle Indicates the recorder instance.\r
+ * @param [in] callback Indicates the callback function pointer.\r
+ * @param [in] cookie Indicates the Context transferred by the callback function.\r
+ * @return Returns <b>0</b> Indicates that the registration is successful.; otherwise is failed.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief 注册本地录音回调函数。\r
+ *\r
+ * @param [in] handle 本地录音实例。\r
+ * @param [in] callback 回调函数指针。\r
+ * @param [in] cookie 回调函数传入的Context。\r
+ * @return 返回 <b>0</b>表示注册成功。;否则失败。\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+errcode_t AudioRecorderSetCallback(const AudioRecorderHandle handle, RecorderCallback callback, const void *cookie);\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief Record the current timestamp position of the audio file.\r
+ *\r
+ * If only recording the current dot position is required, no parameters are needed;\r
+ * simply pass in the parameters NULL and a length of 0.\r
+ * @param [in] handle Indicates the recorder instance.\r
+ * @param [in] buffer Indicates the input parameter.\r
+ * @param [in] buf_len Indicates the Length of input parameter.\r
+ * @return Returns <b>0</b> Indicates that the record is successful.; otherwise is failed.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief 记录当前音频文件打点位置。\r
+ * 如果只是记录当前的打点位置,\r
+ * 则不需要参数,直接传入参数NULL和长度0。\r
+ * @param [in] handle 本地录音实例。\r
+ * @param [in] buffer 预留的可能需要的其他参数.\r
+ * @param [in] bufLen 预留的可能需要的其他参数长度.\r
+ *\r
+ * @return 返回 <b>0</b>表示记录成功。;否则失败。\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+errcode_t AudioRecorderWriteMarks(const AudioRecorderHandle handle, const uint8_t *buffer, const int32_t bufLen);\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief get remaining recording time.\r
+ *\r
+ * @param [in] handle Indicates the recorder instance.\r
+ * @param [in] type Indicates the type of the obtained time. see {@link RemainTimeType}.\r
+ * @param [out] time Indicates the time of acquisition.\r
+ * @return Returns <b>0</b> if the playback is paused; otherwise is failed.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief 获取剩余录制时间。\r
+ *\r
+ * @param [in] handle 本地录音实例。\r
+ * @param [in] type 获取的时间类型参见{@link RemainTimeType}。\r
+ * @param [out] time 表示获取的时间。\r
+ * @return 如果暂停播放,则返回<b>0</b>,否则返回失败。\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+errcode_t AudioRecorderGetRemainingTime(const AudioRecorderHandle handle, uint32_t type, uint32_t *time);\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief get recorded file info.\r
+ *\r
+ * @param [in] handle Indicates the recorder instance.\r
+ * @param [out] info Indicates the info of the record file. see {@link RecordFileInfo}.[out]\r
+ * @return Returns <b>0</b> if get file info correctly; otherwise is failed.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief 获取录音文件信息\r
+ *\r
+ * @param [in] handle 本地录音实例。\r
+ * @param [out] info 获取的录音文件信息{@link RecordFileInfo}。\r
+ * @return 如果正确获取录音文件信息,则返回<b>0</b>,否则返回失败。\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+errcode_t AudioRecorderGetFileInfo(const AudioRecorderHandle handle, RecordFileInfo *info);\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief prepare the recording environment and create the recording file.\r
+ *\r
+ * This function must be called after {@link AudioRecorderSetOutputPath} and before {@link AudioRecorderSetInfo}.\r
+ *\r
+ * @param [in] handle Indicates the recorder instance.\r
+ * @return Returns <b>0</b> if the repared the recording environment and created the recording file;\r
+ * otherwise is failed.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief 准备录音环境,创建录音文件。\r
+ *\r
+ * 该函数必须在{@link AudioRecorderSetOutputPath}之后调用,在{@link AudioRecorderSetInfo}之前调用。\r
+ *\r
+ * @param [in] handle 本地录音实例。\r
+ * @return如果准备了录音环境并创建了录音文件,则返回<b>0</b>;\r
+ * 否则失败。\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+errcode_t AudioRecorderPrepare(const AudioRecorderHandle handle);\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief start recording.\r
+ *\r
+ * This function must be called after {@link AudioRecorderPrepare}.\r
+ *\r
+ * @param [in] handle Indicates the recorder instance.\r
+ * @return Returns <b>0</b> if the record started; otherwise is failed.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief 开始录制。\r
+ *\r
+ * 此函数必须在{@link AudioRecorderPrepare}之后调用。\r
+ *\r
+ * @param [in] handle 本地录音实例。\r
+ * @return如果记录已开始,则返回<b>0</b>;否则失败。\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+errcode_t AudioRecorderStart(const AudioRecorderHandle handle);\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief stop recording.\r
+ *\r
+ * @param [in] handle Indicates the recorder instance.\r
+ * @return Returns <b>0</b> if the record is stopped; otherwise is failed.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief 停止录制。\r
+ *\r
+ * @param [in] handle 本地录音实例。\r
+ * @return如果记录停止,则返回<b>0</b>,否则返回失败。\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+errcode_t AudioRecorderStop(const AudioRecorderHandle handle);\r
+\r
+/**\r
+ * @if Eng\r
+ * @brief destroy recorder.\r
+ *\r
+ * @param [in] handle Indicates the recorder instance.\r
+ * @return Returns <b>0</b> Indicates that the handle is deleted successfully; otherwise is failed.\r
+ * @since 1.0\r
+ * @version 1.0\r
+ * @else\r
+ * @brief 销毁本地录音。\r
+ *\r
+ * @param [in] handle 本地录音实例。\r
+ * @return Returns <b>0</b>表示删除句柄成功,否则失败。\r
+ * @自1.0起\r
+ * @版本1.0\r
+ * @endif\r
+ */\r
+errcode_t AudioRecorderDestroy(const AudioRecorderHandle handle);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif\r
diff --git a/code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/kits/audio_recorder_lite/CMakeLists.txt b/code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/kits/audio_recorder_lite/CMakeLists.txt
new file mode 100644 (file)
index 0000000..62c4cc5
--- /dev/null
@@ -0,0 +1,54 @@
+#===============================================================================
+# @brief    cmake file
+# Copyright (c) CompanyNameMagicTag 2022-2022. All rights reserved.
+#===============================================================================
+
+enable_language(CXX)
+
+set(COMPONENT_NAME "js_audio_recorder")
+
+set(SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/audio_recorder_module.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/audio_recorder_listener.cpp
+)
+
+set(PUBLIC_HEADER
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+)
+set(OPENMG_DIR ${ROOTDIR}/open_source/openharmony)
+set(PRIVATE_HEADER
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../../utils/include
+    ${OPENMG_DIR}/utils/native/lite/js/builtin/filekit/include
+    ${OPENMG_DIR}/utils/native/lite/js/builtin/common/include
+)
+
+set(PRIVATE_DEFINES
+    
+)
+
+set(PUBLIC_DEFINES
+)
+
+# use this when you want to add ccflags like -include xxx
+set(COMPONENT_PUBLIC_CCFLAGS
+)
+
+set(COMPONENT_FLAGS ${ccflags})
+list(REMOVE_ITEM COMPONENT_FLAGS -std=gnu99 -std=c99 -std=gnu11 -std=c11)
+list(APPEND COMPONENT_FLAGS -std=c++11 -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -nostdlibinc)
+set(COMPONENT_CCFLAGS
+    ${COMPONENT_FLAGS}
+)
+
+set(WHOLE_LINK
+    true
+)
+
+set(MAIN_COMPONENT
+    false
+)
+
+set(LIBRARY_OUTPUT_PATH ${BIN_DIR}/${CHIP}/libs/media/${BOARD}_${APPLICATION})
+
+build_component()
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/kits/audio_recorder_lite/include/audio_recorder_listener.h b/code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/kits/audio_recorder_lite/include/audio_recorder_listener.h
new file mode 100644 (file)
index 0000000..93de95e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: audio recorder listener
+* Author: Media Software Group
+* Create: 2025-09-20
+*/
+
+#ifndef AUDIO_RECORDER_LISTENER_H
+#define AUDIO_RECORDER_LISTENER_H
+
+#include <string>
+#include "jsi.h"
+
+namespace OHOS {
+namespace ACELite {
+
+class AudioRecorderListener {
+public:
+    AudioRecorderListener() = default;
+
+    explicit AudioRecorderListener(JSIValue callback, JSIValue thisVal);
+
+    ~AudioRecorderListener();
+
+    void OnTrigger() const;
+
+private:
+    JSIValue callback_;
+    JSIValue thisVal_;
+};
+
+void TriggerRecorderListener(const AudioRecorderListener *listener);
+void AsyncExecuteRecorderCallback(void *arg);
+
+} // namespace ACELite
+} // namespace OHOS
+#endif
diff --git a/code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/kits/audio_recorder_lite/include/audio_recorder_module.h b/code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/kits/audio_recorder_lite/include/audio_recorder_module.h
new file mode 100644 (file)
index 0000000..8049405
--- /dev/null
@@ -0,0 +1,69 @@
+/*\r
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.\r
+* Description: audio recorder module\r
+* Author: Media Software Group\r
+* Create: 2025-09-20\r
+*/\r
+\r
+#ifndef AUDIO_RECORDER_MODULE_H\r
+#define AUDIO_RECORDER_MODULE_H\r
+\r
+#include <cstdint>\r
+#include <string>\r
+#include <memory>\r
+#include "jsi.h"\r
+#include "audio_recorder_listener.h"\r
+#include "audio_manager.h"\r
+\r
+namespace OHOS {\r
+namespace ACELite {\r
+class AudioRecorderModule final : public MemoryHeap {\r
+public:\r
+    AudioRecorderModule();\r
+    ~AudioRecorderModule();\r
+    static JSIValue Prepare(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+\r
+    static JSIValue Start(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+\r
+    static JSIValue Pause(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+\r
+    static JSIValue Resume(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+\r
+    static JSIValue Stop(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+\r
+    static JSIValue Release(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+\r
+    static JSIValue RegCallBack(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+    static void OnTerminate();\r
+private:\r
+    static int32_t ActivateAudioInterrupt(uint32_t &sessionId);\r
+    static int32_t AudioRecorderAllPrepare(void);\r
+    static int32_t AudioRecorderGetInfo(CapturerInputConfig &capturerInfo, std::string &uri,\r
+        const JSIValue *args, uint8_t argsSize);\r
+    static void AudioRecordEventHandle(uint32_t enEvent, const void *data, const void *cookie);\r
+    static JSIValue OnPrepareSetter(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+    static JSIValue OnStartSetter(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+    static JSIValue OnPauseSetter(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+    static JSIValue OnResumeSetter(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+    static JSIValue OnStopSetter(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+    static JSIValue OnReleaseSetter(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+    static JSIValue OnErrorSetter(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+    static AudioRecorderListener *CreateAudioRecorderListener(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize);\r
+    static int32_t AudioCaptureGetFormat(std::string format, AudioCodecFormat &audioFormat);\r
+    static AudioRecorderListener *onPrepareListener_;\r
+    static AudioRecorderListener *onStartedListener_;\r
+    static AudioRecorderListener *onPauseListener_;\r
+    static AudioRecorderListener *onResumeListener_;\r
+    static AudioRecorderListener *onStopListener_;\r
+    static AudioRecorderListener *onReleaseListener_;\r
+    static AudioRecorderListener *onErrorListener_;\r
+    static void *recorderHandle_;\r
+    static Audio::AudioInterrupt interrupt_;\r
+};\r
+\r
+void InitAudioRecorderModule(JSIValue exports);\r
+}\r
+}\r
+\r
+\r
+#endif\r
diff --git a/code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/kits/audio_recorder_lite/src/audio_recorder_listener.cpp b/code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/kits/audio_recorder_lite/src/audio_recorder_listener.cpp
new file mode 100644 (file)
index 0000000..ec1b65a
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: audio recorder listener
+* Author: Media Software Group
+* Create: 2025-09-20
+*/
+
+#include "audio_recorder_listener.h"
+#include <cerrno>
+#include <sys/prctl.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include "js_async_work.h"
+#include "media_log.h"
+
+namespace OHOS {
+namespace ACELite {
+
+void TriggerRecorderListener(const AudioRecorderListener *listener)
+{
+    if (listener == nullptr) {
+        MEDIA_ERR_LOG("listener is NULL");
+        return;
+    }
+    if (!JsAsyncWork::DispatchAsyncWork(AsyncExecuteRecorderCallback, const_cast<AudioRecorderListener *>(listener))) {
+        MEDIA_ERR_LOG("dispatch async work failed.");
+    }
+}
+
+void AsyncExecuteRecorderCallback(void *arg)
+{
+    AudioRecorderListener *listener = static_cast<AudioRecorderListener *>(arg);
+    if (listener == nullptr) {
+        MEDIA_ERR_LOG("async execute callback failed.");
+        return;
+    }
+    listener->OnTrigger();
+}
+
+AudioRecorderListener::AudioRecorderListener(JSIValue callback, JSIValue thisVal)
+    : callback_(JSI::AcquireValue(callback)),
+    thisVal_(thisVal)
+{}
+
+AudioRecorderListener::~AudioRecorderListener()
+{
+    if (!JSI::ValueIsUndefined(callback_)) {
+        JSI::ReleaseValue(callback_);
+        callback_ = JSI::CreateUndefined();
+    }
+}
+
+void AudioRecorderListener::OnTrigger() const
+{
+    if (JSI::ValueIsFunction(callback_)) {
+        JSI::CallFunction(callback_, thisVal_, nullptr, 0);
+        MEDIA_INFO_LOG("Listener OnTrigger.");
+    }
+}
+}  // namespace ACELite
+}  // namespace OHOS
diff --git a/code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/kits/audio_recorder_lite/src/audio_recorder_module.cpp b/code/sdk/middleware/services/media/foundation/audio_recorder/interfaces/kits/audio_recorder_lite/src/audio_recorder_module.cpp
new file mode 100644 (file)
index 0000000..c0fdef1
--- /dev/null
@@ -0,0 +1,451 @@
+/*\r
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.\r
+* Description: audio recorder module\r
+* Author: Media Software Group\r
+* Create: 2025-09-25\r
+*/\r
+\r
+#include "audio_recorder_module.h"\r
+#include <cstdio>\r
+#include <cstring>\r
+#include <cstdlib>\r
+#include <unistd.h>\r
+#include <climits>\r
+#include "securec.h"\r
+#include "audio_manager.h"\r
+#include "media_log.h"\r
+#include "media_thread_adapt.h"\r
+#include "audio_manager.h"\r
+#include "audio_recorder.h"\r
+#include "nativeapi_fs.h"\r
+\r
+#define DELETE_NOT_NULL(pointer) \\r
+    if ((pointer) != nullptr) {  \\r
+        delete (pointer);        \\r
+        (pointer) = nullptr;     \\r
+    }\r
+using namespace::Audio;\r
+using Audio::AudioManager;\r
+namespace OHOS {\r
+namespace ACELite {\r
+\r
+ AudioRecorderListener *AudioRecorderModule::onPrepareListener_ = nullptr;\r
+ AudioRecorderListener *AudioRecorderModule::onStartedListener_ = nullptr;\r
+ AudioRecorderListener *AudioRecorderModule::onPauseListener_ = nullptr;\r
+ AudioRecorderListener *AudioRecorderModule::onResumeListener_ = nullptr;\r
+ AudioRecorderListener *AudioRecorderModule::onStopListener_ = nullptr;\r
+ AudioRecorderListener *AudioRecorderModule::onReleaseListener_ = nullptr;\r
+ AudioRecorderListener *AudioRecorderModule::onErrorListener_ = nullptr;\r
+ void *AudioRecorderModule::recorderHandle_ = nullptr;\r
+ Audio::AudioInterrupt AudioRecorderModule::interrupt_ = {};\r
+\r
+ const uint64_t PER_FILE_STORAGE_MAX_DURATION = 60;\r
+ const uint64_t DEFAULTE_MAX_STORAGE_THEARHOLD = 90;\r
+ const uint64_t PER_FILE_STORAGE_MAX_SIZE = 2ULL * 1024 * 1024 * 1024;\r
+ const uint8_t INDEX_0 = 0;\r
+ const uint8_t INDEX_1 = 1;\r
+ const uint8_t INDEX_2 = 2;\r
+ const uint8_t INDEX_3 = 3;\r
+ const uint8_t INDEX_4 = 4;\r
+ const uint8_t PARAM_NUM_2 = 2;\r
+ constexpr char AUDIO_ENCODE_BIT_RATE[] = "audioEncodeBitRate";\r
+ constexpr char AUDIO_SAMPLE_RATE[] = "audioSampleRate";\r
+ constexpr char NUMBER_OF_CHANNELS[] = "numberOfChannels";\r
+ constexpr char INPUT_URI[] = "uri";\r
+ constexpr char AUDIO_ENCODER_MIME[] = "audioEncoderMime";\r
+ constexpr char FILE_FORMAT[] = "fileFormat";\r
+ static Audio::AudioManager &g_amInstance = Audio::AudioManager::GetInstance();\r
+\r
+ struct NameAudioFormat {\r
+     std::string name;\r
+     AudioCodecFormat audioFormat;\r
+ };\r
+\r
+ static NameAudioFormat g_audioCodecFormat[] = {\r
+    {"audio/mp3", MP3},\r
+    {"audio/opus", OPUS},\r
+    {"audio/silk", SILK},\r
+    {"audio/pcm", PCM}\r
+ };\r
+\r
+ int32_t AudioRecorderModule::AudioCaptureGetFormat(std::string format, AudioCodecFormat &audioFormat)\r
+ {\r
+     for (size_t i = 0; i < (sizeof(g_audioCodecFormat) / sizeof(g_audioCodecFormat[0])); i++) {\r
+         if (format == g_audioCodecFormat[i].name) {\r
+             audioFormat = g_audioCodecFormat[i].audioFormat;\r
+             MEDIA_INFO_LOG("record [AudioCaptureSample] set audioFormat %s", g_audioCodecFormat[i].name.c_str());\r
+             return MEDIA_OK;\r
+         }\r
+     }\r
+     MEDIA_ERR_LOG("invalid input format[%s]!", format.c_str());\r
+     return MEDIA_INVALID_PARAM;\r
+ }\r
+\r
+ class AudioRecorderInterruptListener : public InterruptListener {\r
+     public:\r
+     AudioRecorderInterruptListener() {};\r
+     ~AudioRecorderInterruptListener() override {};\r
+\r
+     void OnInterrupt(int32_t type, int32_t hint) override\r
+     {\r
+         MEDIA_INFO_LOG("AudioRecorderInterruptListener OnInterrupt, type:%d, hint:%d", type, hint);\r
+         if (type == INTERRUPT_TYPE_BEGIN && hint == INTERRUPT_HINT_PAUSE) {\r
+             MEDIA_INFO_LOG("OnInterrupt pause not supported");\r
+         }\r
+         if (type == INTERRUPT_TYPE_END && hint == INTERRUPT_HINT_RESUME) {\r
+             MEDIA_INFO_LOG("OnInterrupt resume not supported");\r
+         }\r
+         if (type == INTERRUPT_TYPE_BEGIN && hint == INTERRUPT_HINT_STOP) {\r
+             AudioRecorderModule::Stop(nullptr, nullptr, 0);\r
+             AudioRecorderModule::Release(nullptr, nullptr, 0);\r
+         }\r
+         if (type == INTERRUPT_TYPE_END && hint == INTERRUPT_HINT_STOP) {\r
+             MEDIA_INFO_LOG("OnInterrupt stop not supported");\r
+         }\r
+     }\r
+ };\r
+\r
+ AudioRecorderModule::AudioRecorderModule()\r
+ {\r
+\r
+ }\r
+\r
+ AudioRecorderModule::~AudioRecorderModule()\r
+ {\r
+ }\r
+\r
+JSIValue AudioRecorderModule::Prepare(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    CapturerInputConfig capturerInfo = {};\r
+    std::string uri = "";\r
+    errcode_t ret = ActivateAudioInterrupt(capturerInfo.sessionID);\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("ActivateAudioInterrupt failed!");\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    ret = AudioRecorderGetInfo(capturerInfo, uri, args, argsSize);\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("AudioRecorderGetInfo failed!");\r
+        goto DEACTIVATE;\r
+    }\r
+    ret = AudioRecorderCreate(&recorderHandle_);\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("AudioRecorderCreate failed!");\r
+        goto DESTORY;\r
+    }\r
+    ret = AudioRecorderSetInfo(recorderHandle_, &capturerInfo);\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("audio recorder set info failed!");\r
+        goto DESTORY;\r
+    }\r
+    ret = AudioRecorderSetOutputPath(recorderHandle_, uri.c_str(), uri.size() + 1);\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("audio recorder set output path failed!");\r
+        goto DESTORY;\r
+    }\r
+    ret = AudioRecorderAllPrepare();\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("audio recorder all prepare failed!");\r
+        goto DESTORY;\r
+    }\r
+    ret = AudioRecorderSetCallback(recorderHandle_, AudioRecordEventHandle, NULL);\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("audio recorder set max call back failed!");\r
+        goto DESTORY;\r
+    }\r
+    TriggerRecorderListener(onPrepareListener_);\r
+    return JSI::CreateBoolean(true);\r
+DESTORY:\r
+    AudioRecorderDestroy(recorderHandle_);\r
+    recorderHandle_ = NULL;\r
+DEACTIVATE:\r
+    g_amInstance.DeactivateAudioInterrupt(interrupt_);\r
+    return JSI::CreateBoolean(false);\r
+}\r
+\r
+JSIValue AudioRecorderModule::Start(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    errcode_t ret = AudioRecorderStart(recorderHandle_);\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("audio recorder start failed!");\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    TriggerRecorderListener(onStartedListener_);\r
+    return JSI::CreateBoolean(true);\r
+}\r
+\r
+JSIValue AudioRecorderModule::Pause(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    MEDIA_UNUSED(thisVal);\r
+    MEDIA_UNUSED(args);\r
+    MEDIA_UNUSED(argsSize);\r
+    MEDIA_ERR_LOG("Not support!");\r
+    TriggerRecorderListener(onPauseListener_);\r
+    return JSI::CreateBoolean(false);\r
+}\r
+\r
+JSIValue AudioRecorderModule::Resume(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    MEDIA_UNUSED(thisVal);\r
+    MEDIA_UNUSED(args);\r
+    MEDIA_UNUSED(argsSize);\r
+    MEDIA_ERR_LOG("Not support!");\r
+    TriggerRecorderListener(onResumeListener_);\r
+    return JSI::CreateBoolean(false);\r
+}\r
+\r
+JSIValue AudioRecorderModule::Stop(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    MEDIA_UNUSED(thisVal);\r
+    MEDIA_UNUSED(args);\r
+    MEDIA_UNUSED(argsSize);\r
+    errcode_t ret = AudioRecorderStop(recorderHandle_);\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("audio recorder stop failed!");\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    TriggerRecorderListener(onStopListener_);\r
+    return JSI::CreateBoolean(true);\r
+}\r
+\r
+JSIValue AudioRecorderModule::Release(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    MEDIA_UNUSED(thisVal);\r
+    MEDIA_UNUSED(args);\r
+    MEDIA_UNUSED(argsSize);\r
+    if (recorderHandle_ == nullptr) {\r
+        return JSI::CreateBoolean(true);\r
+    }\r
+    (void)AudioRecorderDestroy(recorderHandle_);\r
+    recorderHandle_ = nullptr;\r
+    g_amInstance.DeactivateAudioInterrupt(interrupt_);\r
+    TriggerRecorderListener(onReleaseListener_);\r
+    return JSI::CreateBoolean(true);\r
+}\r
+\r
+JSIValue AudioRecorderModule::RegCallBack(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    if (argsSize < PARAM_NUM_2) {\r
+        MEDIA_ERR_LOG("The number of parameters is less than 2!");\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    std::string type = std::string(JSI::ValueToString(args[INDEX_0]));\r
+    if (type == "prepare") {\r
+        return OnPrepareSetter(thisVal, args, argsSize);\r
+    } else if (type == "start") {\r
+        return OnStartSetter(thisVal, args, argsSize);\r
+    } else if (type == "pause") {\r
+        return OnPauseSetter(thisVal, args, argsSize);\r
+    } else if (type == "resume") {\r
+        return OnResumeSetter(thisVal, args, argsSize);\r
+    } else if (type == "stop") {\r
+        return OnStopSetter(thisVal, args, argsSize);\r
+    } else if (type == "release") {\r
+        return OnReleaseSetter(thisVal, args, argsSize);\r
+    } else if (type == "error") {\r
+        return OnErrorSetter(thisVal, args, argsSize);\r
+    }\r
+    return JSI::CreateBoolean(true);\r
+}\r
+\r
+int32_t AudioRecorderModule::AudioRecorderAllPrepare(void)\r
+{\r
+    errcode_t ret = AudioRecorderPrepare(recorderHandle_);\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("audio recorder prepare failed!");\r
+        return ret;\r
+    }\r
+    ret = AudioRecorderEnableOverwriteFiles(recorderHandle_, false);\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("audio recorder enable over write files failed!");\r
+        return ret;\r
+    }\r
+    ret = AudioRecorderSetStorageWarningThreshold(recorderHandle_, DEFAULTE_MAX_STORAGE_THEARHOLD);\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("audio recorder set storage warning threshold failed!");\r
+        return ret;\r
+    }\r
+    ret = AudioRecorderSetMaxDuration(recorderHandle_, PER_FILE_STORAGE_MAX_DURATION);\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("audio recorder set max duration failed!");\r
+        return ret;\r
+    }\r
+    ret = AudioRecorderSetMaxFileSize(recorderHandle_, PER_FILE_STORAGE_MAX_SIZE);\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("audio recorder set max file size failed!");\r
+        return ret;\r
+    }\r
+    return ret;\r
+}\r
+\r
+int32_t AudioRecorderModule::ActivateAudioInterrupt(uint32_t &sessionId)\r
+{\r
+    sessionId = g_amInstance.MakeSessionId();\r
+    if (sessionId == AUDIO_SESSION_ID_NONE) {\r
+        MEDIA_ERR_LOG("AUDIO_SESSION_ID_NONE");\r
+        return MEDIA_ERR;\r
+    }\r
+    std::shared_ptr<AudioRecorderInterruptListener> recorderInterruptListener =\r
+        std::make_shared<AudioRecorderInterruptListener>();\r
+    interrupt_ = { AUDIO_STREAM_VOICE_RECORD, sessionId, recorderInterruptListener };\r
+    int32_t ret = g_amInstance.ActivateAudioInterrupt(interrupt_);\r
+    if (ret != MEDIA_OK) {\r
+        MEDIA_ERR_LOG("ActivateAudioInterrupt failed");\r
+    }\r
+    return ret;\r
+}\r
+\r
+int32_t AudioRecorderModule::AudioRecorderGetInfo(CapturerInputConfig &capturerInfo, std::string &uri,\r
+    const JSIValue *args, uint8_t argsSize)\r
+{\r
+    if (argsSize < 1) {\r
+        MEDIA_ERR_LOG("The number of parameters is less than 1!");\r
+        return MEDIA_ERR;\r
+    }\r
+    int32_t bitRate = static_cast<int32_t>(JSI::ValueToNumber(JSI::GetNamedProperty(args[0], AUDIO_ENCODE_BIT_RATE)));\r
+    capturerInfo.sampleRate = static_cast<int32_t>(JSI::ValueToNumber(JSI::GetNamedProperty(args[0], AUDIO_SAMPLE_RATE)));\r
+    capturerInfo.channelCount = static_cast<int32_t>(JSI::ValueToNumber(JSI::GetNamedProperty(args[0], NUMBER_OF_CHANNELS)));\r
+    uri = std::string(JSI::ValueToString(JSI::GetNamedProperty(args[0], INPUT_URI)));\r
+    MEDIA_INFO_LOG("relative path = %s!", uri.c_str());\r
+    char destFullPath[FILE_NAME_MAX_LEN + 1] = {};\r
+    NativeapiFs::GetFullPath(uri.c_str(), destFullPath, FILE_NAME_MAX_LEN + 1);\r
+    MEDIA_INFO_LOG("absolute path = %s!", destFullPath);\r
+    uri = std::string(destFullPath);\r
+    std::string format = std::string(JSI::ValueToString(JSI::GetNamedProperty(args[0], AUDIO_ENCODER_MIME)));\r
+    int32_t ret = AudioCaptureGetFormat(format, capturerInfo.audioFormat);\r
+    if (ret != MEDIA_OK) {\r
+        return ret;\r
+    }\r
+    capturerInfo.bitWidth = BIT_WIDTH_16;\r
+    capturerInfo.streamType = AUDIO_STREAM_VOICE_RECORD;\r
+    capturerInfo.linkDir = AUDIO_UP_LINK;\r
+    return MEDIA_OK;\r
+}\r
+\r
+void AudioRecorderModule::AudioRecordEventHandle(uint32_t enEvent, const void *data, const void *cookie)\r
+{\r
+    MEDIA_UNUSED(data);\r
+    MEDIA_UNUSED(cookie);\r
+    if (enEvent == AUDIO_RECORD_STORAGE_REACHE_MAX_VALUE ||\r
+        enEvent == AUDIO_RECORD_EVENT_ERROR) {\r
+        TriggerRecorderListener(onErrorListener_);\r
+    } else {\r
+        MEDIA_ERR_LOG("not support envent type!");\r
+    }\r
+}\r
+\r
+JSIValue AudioRecorderModule::OnPrepareSetter(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    DELETE_NOT_NULL(onPrepareListener_);\r
+    onPrepareListener_ = CreateAudioRecorderListener(thisVal, args, argsSize);\r
+    if (onPrepareListener_ == nullptr) {\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    return JSI::CreateBoolean(true);\r
+}\r
+\r
+JSIValue AudioRecorderModule::OnStartSetter(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    DELETE_NOT_NULL(onStartedListener_);\r
+    onStartedListener_ = CreateAudioRecorderListener(thisVal, args, argsSize);\r
+    if (onStartedListener_ == nullptr) {\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    return JSI::CreateBoolean(true);\r
+}\r
+\r
+JSIValue AudioRecorderModule::OnPauseSetter(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    DELETE_NOT_NULL(onPauseListener_);\r
+    onPauseListener_ = CreateAudioRecorderListener(thisVal, args, argsSize);\r
+    if (onPauseListener_ == nullptr) {\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    return JSI::CreateBoolean(true);\r
+}\r
+\r
+JSIValue AudioRecorderModule::OnResumeSetter(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    DELETE_NOT_NULL(onResumeListener_);\r
+    onResumeListener_ = CreateAudioRecorderListener(thisVal, args, argsSize);\r
+    if (onResumeListener_ == nullptr) {\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    return JSI::CreateBoolean(true);\r
+}\r
+\r
+JSIValue AudioRecorderModule::OnStopSetter(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    DELETE_NOT_NULL(onStopListener_);\r
+    onStopListener_ = CreateAudioRecorderListener(thisVal, args, argsSize);\r
+    if (onStopListener_ == nullptr) {\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    return JSI::CreateBoolean(true);\r
+}\r
+\r
+JSIValue AudioRecorderModule::OnReleaseSetter(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    DELETE_NOT_NULL(onReleaseListener_);\r
+    onReleaseListener_ = CreateAudioRecorderListener(thisVal, args, argsSize);\r
+    if (onReleaseListener_ == nullptr) {\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    return JSI::CreateBoolean(true);\r
+}\r
+\r
+JSIValue AudioRecorderModule::OnErrorSetter(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    DELETE_NOT_NULL(onErrorListener_);\r
+    onErrorListener_ = CreateAudioRecorderListener(thisVal, args, argsSize);\r
+    if (onErrorListener_ == nullptr) {\r
+        return JSI::CreateBoolean(false);\r
+    }\r
+    return JSI::CreateBoolean(true);\r
+}\r
+\r
+AudioRecorderListener *AudioRecorderModule::CreateAudioRecorderListener(const JSIValue thisVal, const JSIValue *args, uint8_t argsSize)\r
+{\r
+    if (argsSize < PARAM_NUM_2) {\r
+        MEDIA_ERR_LOG("2 argument is required.");\r
+        return nullptr;\r
+    }\r
+    JSIValue callback = args[INDEX_1];\r
+    if (!JSI::ValueIsFunction(callback)) {\r
+        MEDIA_ERR_LOG("a function is required.");\r
+        return nullptr;\r
+    }\r
+    AudioRecorderListener *listener = new AudioRecorderListener(callback, thisVal);\r
+    if (listener == nullptr) {\r
+        MEDIA_ERR_LOG("out of memory.");\r
+    }\r
+    return listener;\r
+}\r
+\r
+void AudioRecorderModule::OnTerminate(void)\r
+{\r
+    AudioRecorderModule::Release(nullptr, nullptr, 0);\r
+    DELETE_NOT_NULL(onPrepareListener_);\r
+    DELETE_NOT_NULL(onStartedListener_);\r
+    DELETE_NOT_NULL(onPauseListener_);\r
+    DELETE_NOT_NULL(onStopListener_);\r
+    DELETE_NOT_NULL(onReleaseListener_);\r
+    DELETE_NOT_NULL(onErrorListener_);\r
+}\r
+\r
+void InitAudioRecorderModule(JSIValue exports)\r
+{\r
+    g_amInstance.Initialize();\r
+    JSI::SetOnTerminate(exports, AudioRecorderModule::OnTerminate);\r
+    JSI::SetModuleAPI(exports, "prepare", AudioRecorderModule::Prepare);\r
+    JSI::SetModuleAPI(exports, "start", AudioRecorderModule::Start);\r
+    JSI::SetModuleAPI(exports, "pause", AudioRecorderModule::Pause);\r
+    JSI::SetModuleAPI(exports, "resume", AudioRecorderModule::Resume);\r
+    JSI::SetModuleAPI(exports, "stop", AudioRecorderModule::Stop);\r
+    JSI::SetModuleAPI(exports, "reset", AudioRecorderModule::Release);\r
+    JSI::SetModuleAPI(exports, "release", AudioRecorderModule::Release);\r
+    JSI::SetModuleAPI(exports, "on", AudioRecorderModule::RegCallBack);\r
+}\r
+\r
+}\r
+}\r
index 339a93c..4b8395f 100644 (file)
@@ -116,10 +116,9 @@ int32_t StartSource(uintptr_t handle);
  *
  * @param handle 指定的流
  * @param buffer buffer信息
- * @param isBlocking 是否阻塞
  * @return 正常返回0,否则返回非0
  */
-int32_t ObtainSourceBuffer(uintptr_t handle, const CapturerBuffer *buffer, bool isBlocking);
+int32_t ObtainSourceBuffer(uintptr_t handle, const CapturerBuffer *buffer);
 
 /**
  * @brief 将指定的流停止
index a44343b..8a12e2f 100644 (file)
@@ -281,9 +281,8 @@ int32_t StartSource(uintptr_t handle)
     return AUDIO_SUCCESS;
 }
 
-int32_t ObtainSourceBuffer(uintptr_t handle, const CapturerBuffer *buffer, bool isBlocking)
+int32_t ObtainSourceBuffer(uintptr_t handle, const CapturerBuffer *buffer)
 {
-    AUDIO_UNUSED(isBlocking);
     SourceHandleContext *context = (SourceHandleContext *)handle;
     CHK_NULL_RETURN(context, AUDIO_ERROR, "source handle is NULL");
     if (context->state != RUNNING) {
@@ -294,11 +293,11 @@ int32_t ObtainSourceBuffer(uintptr_t handle, const CapturerBuffer *buffer, bool
     uint64_t readlen = ERR_INVALID_READ;
     int32_t ret = context->capture->CaptureFrame(context->capture, buffer->data, buffer->size, &readlen);
     if (ret != AUDIO_SUCCESS) {
-        if (ret != AUDIO_RETRY_READ) {
+        if (ret != AUDIO_RETRY_READ &&
+            ret != AUDIO_NOT_SUPPORT_GET_FRAME) {
             ALOGE("CaptureFrame failed 0x%x", ret);
-            return ERR_INVALID_READ;
         }
-        return AUDIO_RETRY_READ;
+        return ret;
     }
     return (int32_t)readlen;
 }
index 78ec15a..0f341d2 100644 (file)
@@ -33,7 +33,7 @@ int32_t AudioStreamInGetTimestamp(AudioStreamInHandle handle, struct timespec *t
 int32_t AudioStreamInStart(AudioStreamInHandle handle);
 int32_t AudioStreamInStop(AudioStreamInHandle handle);
 int32_t AudioStreamInSetInputDevice(AudioStreamInHandle handle, int32_t deviceId);
-int32_t AudioStreamInObtainBuffer(AudioStreamInHandle handle, const CapturerBuffer *buffer, bool isBlocking);
+int32_t AudioStreamInObtainBuffer(AudioStreamInHandle handle, const CapturerBuffer *buffer);
 int32_t AudioStreamInRelease(AudioStreamInHandle handle);
 int32_t AudioStreamInDestroy(AudioStreamInHandle handle);
 #endif
index 02cee7f..dd8a92a 100644 (file)
@@ -142,8 +142,9 @@ int32_t AudioStreamIn::SetInputDevice(int32_t deviceId, AudioRendererConfig &ren
 int32_t AudioStreamIn::ObtainBuffer(CapturerBuffer &buffer, bool isBlocking) const
 {
     int32_t ret;
+    AUDIO_UNUSED(isBlocking);
     MediaMutexLock(mutex);
-    ret = ObtainSourceBuffer(streamHandle_, &buffer, isBlocking);
+    ret = ObtainSourceBuffer(streamHandle_, &buffer);
     MediaMutexUnLock(mutex);
     return ret;
 }
index 462e6f8..f6dbf6a 100644 (file)
@@ -432,6 +432,7 @@ typedef struct {
     uint32_t channelCount;\r
     AudioLinkDirection linkDir;\r
     uint16_t sampleFmt;\r
+    AudioBitWidth bitWidth;\r
 } AudioRendererConfig;\r
 \r
 typedef struct {\r
@@ -441,6 +442,7 @@ typedef struct {
     uint32_t sessionID;\r
     uint32_t channelCount;\r
     AudioLinkDirection linkDir;\r
+    AudioBitWidth bitWidth;\r
 } CapturerInputConfig;\r
 \r
 typedef enum {\r
index 6d6e5d6..9446640 100644 (file)
@@ -40,10 +40,11 @@ enum {
     AUDIO_NO_INIT            = -5,
     AUDIO_NO_MEM             = -6,
     AUDIO_RETRY_READ         = -7,
-    AUDIO_DEAD_OBJECT        = -7,
-    AUDIO_BAD_STATE          = -8,
-    AUDIO_NOT_FOUND_ACTIVE_STREAM          = -9,
-    AUDIO_NOT_SUPPORT = -10,
+    AUDIO_NOT_SUPPORT_GET_FRAME = -8,
+    AUDIO_DEAD_OBJECT        = -9,
+    AUDIO_BAD_STATE          = -10,
+    AUDIO_NOT_FOUND_ACTIVE_STREAM          = -11,
+    AUDIO_NOT_SUPPORT = -12,
 };
 
 #endif // AUDIO_ERRORS_H
index 8071868..66fbd3b 100644 (file)
@@ -59,7 +59,7 @@ if(NOT "${OS_TYPE}" STREQUAL "Linux")
         )
     endif()
 
-    set(CCDEFINES ${CCDEFINES} "_GNU_SOURCE" "_XOPEN_SOURCE=700" "UNSUPPORT_AUDIO_DECODER")
+    set(CCDEFINES ${CCDEFINES} "_GNU_SOURCE" "_XOPEN_SOURCE=700" "UNSUPPORT_AUDIO_DECODER" "SUPPORT_AUDIO_VIDEO_SYNC")
     if ("${CHIP}" STREQUAL "brandy")
         if("MEMORY_MINI" IN_LIST DEFINES)
             set(CCDEFINES ${CCDEFINES} "UNSUPPORT_VIDEO_DECODER")
index 90f14e9..79ace39 100644 (file)
@@ -35,7 +35,7 @@ enum PlayerControlError {
     PLAYERCONTROL_ERROR_DEMUX_FAIL,          /* The file fails to be played. */
     PLAYERCONTROL_ERROR_TIMEOUT,             /* Operation timeout. For example, reading data timeout. */
     PLAYERCONTROL_ERROR_NOT_SUPPORT,         /* The file format is not supportted. */
-    PLAYERCONTROL_ERROR_UNKNOW,              /* Unknown error. */
+    PLAYERCONTROL_ERROR_UNKNOWN,              /* Unknown error. */
     PLAYERCONTROL_ERROR_ILLEGAL_STATEACTION, /* illegal action at cur state. */
     PLAYERCONTROL_ERROR_BUTT,
 };
@@ -51,6 +51,7 @@ enum PlayerControlEvent {
     PLAYERCONTROL_BUFFER_EMPTY,              /* audio buffer empty */
     PLAYERCONTROL_FIRST_VIDEO_FRAME,
     PLAYERCONTROL_FIRST_AUDIO_FRAME,
+    PLAYERCONTROL_EVENT_PAUSED,              /* play pause */
     PLAYERCONTROL_EVENT_BUTT
 };
 
index 3633c2e..1a9f75d 100644 (file)
@@ -74,11 +74,42 @@ typedef enum {
     EVNET_BUTT
 } EventCbType;
 
+typedef enum {
+    TPLAY_DIRECT_FORWARD,
+    TPLAY_DIRECT_BACKWARD,
+    TPLAY_DIRECT_BUTT
+} TplayDirect;
+
+typedef enum {
+    TPLAY_MODE_FULL_PLAY,
+    TPLAY_MODE_ONLY_I_FRAME,
+    TPLAY_MODE_BUTT
+} TplayMode;
+
+typedef enum {
+    TPLAY_SPEED_64X_REWIND = -64,  /* 64 x speed rewind */
+    TPLAY_SPEED_32X_REWIND = -32,  /* 32 x speed rewind */
+    TPLAY_SPEED_16X_REWIND = -16,  /* 16 x speed rewind */
+    TPLAY_SPEED_8X_REWIND = -8,    /* 8 x speed rewind */
+    TPLAY_SPEED_4X_REWIND = -4,    /* 4 x speed rewind */
+    TPLAY_SPEED_2X_REWIND = -2,    /* 2 x speed rewind */
+    TPLAY_SPEED_1X_REWIND = -1,    /* 1 x speed rewind */
+    TPLAY_SPEED_BASE = 1,
+    TPLAY_SPEED_2X_FAST = 2,     /* 2 x speed fast */
+    TPLAY_SPEED_4X_FAST = 4,     /* 4 x speed fast */
+    TPLAY_SPEED_8X_FAST = 8,     /* 8 x speed fast */
+    TPLAY_SPEED_16X_FAST = 16,   /* 16 x speed fast */
+    TPLAY_SPEED_32X_FAST = 32,   /* 32 x speed fast */
+    TPLAY_SPEED_64X_FAST = 64,   /* 64 x speed fast */
+    TPLAY_SPEED_BUTT             /* Invalid speed value */
+} TplaySpeed;
+
 typedef enum {
     PLAY_STATUS_IDLE = 0,
     PLAY_STATUS_INIT,
     PLAY_STATUS_PREPARED,
     PLAY_STATUS_PLAY,
+    PLAY_STATUS_TPLAY,
     PLAY_STATUS_PAUSE,
     PLAY_STATUS_ERR,
     PLAY_STATUS_BUTT
index 6512086..2d09bc0 100644 (file)
@@ -45,12 +45,15 @@ const uint32_t RENDER_FULL_SLEEP_TIME_US = 10000u;
 // 2. waiting interval time for loop playback\r
 const uint32_t RENDER_EOS_SLEEP_TIME_US = 3000000u;\r
 const uint32_t WAIT_BUFFER_EMPTY_SLEEP_TIME_US = 1000000u;\r
+const uint32_t WAIT_PAUSE_TIME_OUT_US = 1000000u;\r
 const uint32_t DECODER_DEFAULT_WIDTH = 1920;\r
 const uint32_t DECODER_DEFAULT_HEIGHT = 1080;\r
 const uint32_t QUEUE_BUFFER_FULL_SLEEP_TIME_US = 10000u;\r
 const uint32_t NO_DATA_READ_SLEEP_TIME_US = 5000u;\r
 const uint32_t MAX_EVENT_MESSAGE_NUM = 128;\r
-const uint32_t MAX_THREAD_STACK_SIZE = 0x1800u;\r
+const uint32_t MAX_THREAD_STACK_SIZE = 0x1B00u;\r
+const uint32_t MAX_THREAD_STACK_SIZE_M3U8 = 0x4000u;\r
+\r
 const uint32_t REQUEST_BUFFER_RETRY_WAIT_TIME_US = 10000u;\r
 const float YCBCR420SP_BUFFER_SIZE_COEFFICIENT = 1.5;\r
 #ifdef DEBUG_LOW_POWER\r
@@ -179,6 +182,7 @@ PlayerControl::PlayerControl()
       lastReadPktStrmIdx_(-1),\r
       lastReadPktPts_(0),\r
       lastSendPktPts_(0),\r
+      speed_(TPLAY_SPEED_BASE),\r
       isVideoStarted_(false),\r
       isAudioStarted_(false),\r
       strmReadEnd_(false),\r
@@ -195,10 +199,13 @@ PlayerControl::PlayerControl()
       rightVolume_(-1.0f),\r
       schMutex_(nullptr),\r
       schCond_(nullptr),\r
+      pauseCond_(nullptr),\r
       schProcess_(nullptr),\r
       seekToTimeMs_(-1),\r
       sourceType_(SOURCE_TYPE_BUT),\r
       firstAudioFrameAfterSeek_(false),\r
+      firstAudioFrameSend_(false),\r
+      firstVideoFrameSend_(false),\r
       firstPosAfterSeek_(0),\r
       fd_(-1),\r
       offset_(0),\r
@@ -311,6 +318,12 @@ int32_t PlayerControl::Init(const PlayerControlParam &createParam)
         MediaMutexDestroy(&schMutex_);\r
         return HI_FAILURE;\r
     }\r
+    pauseCond_ = MediaThreadCondCreate();\r
+    if (pauseCond_ == nullptr) {\r
+        MEDIA_ERR_LOG("create pause cond failed");\r
+        MediaMutexDestroy(&schMutex_);\r
+        return HI_FAILURE;\r
+    }\r
     isInited_ = true;\r
 #ifdef PLAYER_KPI_ON\r
     RecordTime(startPlayStartTime_);\r
@@ -326,6 +339,7 @@ int32_t PlayerControl::Deinit()
     DestroyDecoder();\r
     MediaMutexDestroy(&schMutex_);\r
     MediaThreadCondDestroy(&schCond_);\r
+    MediaThreadCondDestroy(&pauseCond_);\r
     isInited_ = false;\r
     return HI_SUCCESS;\r
 }\r
@@ -416,8 +430,10 @@ int32_t PlayerControl::Seek(int64_t timeInMs)
     if ((fmtFileInfo_.s64Duration > 0) && (fmtFileInfo_.s64Duration < timeInMs)) {\r
         return HI_ERR_PLAYERCONTROL_ILLEGAL_PARAM;\r
     }\r
+    MediaMutexLock(schMutex_);\r
     seekToTimeMs_ = timeInMs;\r
     MediaThreadCondSignal(schCond_);\r
+    MediaMutexUnLock(schMutex_);\r
     return HI_SUCCESS;\r
 }\r
 \r
@@ -451,6 +467,9 @@ int32_t PlayerControl::SetSurface(LvSurfaceView *surface)
 \r
 int32_t PlayerControl::SetPlaybackSpeed(float speed)\r
 {\r
+    if (speed == TPLAY_SPEED_BASE) {\r
+        return Play();\r
+    }\r
     float setSpeed = speed;\r
     MsgInfo msg = {};\r
     msg.what = PLAYERCONTROL_MSG_SETSPEED;\r
@@ -503,6 +522,10 @@ void PlayerControl::EventProcess(EventCbType event)
             }\r
             break;\r
         case EVNET_VIDEO_RUNNING_ERR:\r
+            playerError = PLAYERCONTROL_ERROR_VID_PLAY_FAIL;\r
+            isPlayErr_ = true;\r
+            EventCallback(PLAYERCONTROL_EVENT_ERROR, &playerError);\r
+            break;\r
         case EVNET_AUDIO_RUNNING_ERR:\r
             playerError = PLAYERCONTROL_ERROR_AUD_PLAY_FAIL;\r
             isPlayErr_ = true;\r
@@ -937,7 +960,7 @@ int32_t PlayerControl::SinkStart(void)
     /* get offload flag */\r
     GetOffloadSupport();\r
 \r
-    if (metaData_.key == KEY_TYPE_EXTRADATA && hasAudio_) {\r
+    if (metaData_.key == KEY_TYPE_EXTRADATA) {\r
         std::string key("extradata");\r
         ret = sinkManager_->SetParam(key, DATA_TYPE_PTR, metaData_.value.pValue, metaData_.size);\r
         CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "sinkManager_ SetParam failed");\r
@@ -1101,7 +1124,7 @@ void PlayerControl::GetRenderFullSleepThresholdTime(AudioCodecFormat codecFormat
 \r
 void PlayerControl::DataSchPreProcess(PlayerControl *play, bool *isContinue)\r
 {\r
-    if (play->hasRenderAudioEos_) {\r
+    if (play->IsPlayEos()) {\r
         int32_t info = PLAYERCONTROL_ERROR_AUD_PLAY_FAIL;\r
         play->EventCallback(PLAYERCONTROL_EVENT_ERROR, &info);\r
         MEDIA_ERR_LOG("player waiting for the EOS callback timed out.");\r
@@ -1112,6 +1135,11 @@ void PlayerControl::DataSchPreProcess(PlayerControl *play, bool *isContinue)
 \r
     if (play->paused_) {\r
         // blocking wait ensures that the system goes into deep sleep for reducing power consumption\r
+        int32_t info = PLAYERCONTROL_EVENT_PAUSED;\r
+        play->EventCallback(PLAYERCONTROL_EVENT_PAUSED, &info);\r
+        play->firstAudioFrameSend_ = false;\r
+        play->firstVideoFrameSend_ = false;\r
+               MediaThreadCondSignal(play->pauseCond_);\r
         MediaThreadCondWait(play->schCond_, play->schMutex_);\r
         *isContinue = true;\r
     }\r
@@ -1145,7 +1173,9 @@ inline static bool IsValidPacket(FormatFrame &packet)
 \r
 int32_t PlayerControl::DequeueInputDataFromDemuxer(void)\r
 {\r
-    if (GetCurState() != PLAY_STATUS_PLAY) {\r
+    PlayerStatus state = GetCurState();\r
+    if (state != PLAY_STATUS_PLAY && state != PLAY_STATUS_TPLAY) {\r
+        MEDIA_ERR_LOG("not play state, goto sleep");\r
         renderSleepTime_ = WAIT_MAIN_THREAD_SWITCH_TO_PLAY_STATUS_TIME_US;\r
         return HI_FAILURE;\r
     }\r
@@ -1157,7 +1187,12 @@ int32_t PlayerControl::DequeueInputDataFromDemuxer(void)
     RecordTime(readPacketStartTime);\r
 #endif\r
 \r
-    int32_t ret = ReadPacket();\r
+    int32_t ret;\r
+    if (speed_ != TPLAY_SPEED_BASE) {\r
+        ret = TplayReadPacket();\r
+    } else {\r
+        ret = ReadPacket();\r
+    }\r
     if (ret == HI_RET_NODATA) {\r
         renderSleepTime_ = NO_DATA_READ_SLEEP_TIME_US;\r
         goto RE_SEND;\r
@@ -1170,6 +1205,11 @@ int32_t PlayerControl::DequeueInputDataFromDemuxer(void)
 #endif\r
 \r
     if (formatPacket_.data == nullptr && formatPacket_.len == 0) {\r
+        if (speed_ < 0) {\r
+            TPlayRewindToNormal();\r
+            MEDIA_INFO_LOG("rewind end, resume to normal play");\r
+            return HI_FAILURE;\r
+        }\r
         strmReadEnd_ = true;\r
         formatPacket_.timestampUs = -1;\r
         gettimeofday(&streamEndTime_, nullptr);\r
@@ -1325,7 +1365,7 @@ int32_t PlayerControl::QueueOutputBufferToVideoDecoder(void)
 \r
     // 2. request video output buffer from surface\r
 #if defined(ENABLE_UIKIT)\r
-    surfaceBuf_ = surface_->RequestBuffer();\r
+    surfaceBuf_ = surface_->RequestBuffer(1); // 1 means RequestBuffer blockly\r
 #elif defined(ENABLE_LVGL)\r
     surfaceBuf_ = LvRequestBuffer(reinterpret_cast<lv_obj_t *>(surface_), 0);\r
 #endif\r
@@ -1493,7 +1533,14 @@ int32_t PlayerControl::ProcessInputData(bool isAudio, bool isVideo)
 {\r
     if (isAudio) {\r
 #ifdef UNSUPPORT_AUDIO_DECODER\r
-        return QueueInputDataToAudioSink();\r
+        int32_t retValue = QueueInputDataToAudioSink();\r
+        if (!firstAudioFrameSend_ &&\r
+            !firstVideoFrameSend_ &&\r
+            retValue == HI_SUCCESS) {\r
+            firstAudioFrameSend_ = true;\r
+            int32_t info = PLAYERCONTROL_FIRST_AUDIO_FRAME;\r
+            EventCallback(PLAYERCONTROL_FIRST_AUDIO_FRAME, &info);\r
+        }\r
 #else\r
         QueueInputDataToAudioDecoder();\r
         DequeueOutputBufferAndRenderAudioFrame();\r
@@ -1506,6 +1553,13 @@ int32_t PlayerControl::ProcessInputData(bool isAudio, bool isVideo)
         }\r
         QueueInputDataToVideoDecoder();\r
         DequeueOutputBufferAndRenderVideoFrame();\r
+        if (!firstVideoFrameSend_ &&\r
+            !firstAudioFrameSend_ &&\r
+            retValue == HI_SUCCESS) {\r
+            firstVideoFrameSend_ = true;\r
+            int32_t info = PLAYERCONTROL_FIRST_VIDEO_FRAME;\r
+            EventCallback(PLAYERCONTROL_FIRST_VIDEO_FRAME, &info);\r
+        }\r
 #endif\r
     }\r
     return HI_SUCCESS;\r
@@ -1536,6 +1590,7 @@ void *PlayerControl::DataSchProcess(void *priv)
 \r
         bool isContinue = false;\r
         DataSchPreProcess(play, &isContinue);\r
+        MediaMutexUnLock(play->schMutex_);\r
         if (isContinue) {\r
             goto CONTINUE;\r
         }\r
@@ -1552,8 +1607,8 @@ void *PlayerControl::DataSchProcess(void *priv)
 \r
         if (ret == SINK_RENDER_FATEL || ret == REQUEST_SURFACE_BUFFER_FATAL) {\r
             play->EventQueueProcess();\r
-            MediaMutexUnLock(play->schMutex_);\r
-            break;\r
+            play->renderSleepTime_ = WAIT_BUFFER_EMPTY_SLEEP_TIME_US;\r
+            goto CONTINUE;\r
         } else if (ret != HI_SUCCESS) {\r
             goto CONTINUE;\r
         }\r
@@ -1562,9 +1617,10 @@ void *PlayerControl::DataSchProcess(void *priv)
 \r
     CONTINUE:\r
         if (play->renderSleepTime_ > 0) {\r
+            MediaMutexLock(play->schMutex_);\r
             MediaThreadCondTimeWait(play->schCond_, play->schMutex_, play->renderSleepTime_);\r
+            MediaMutexUnLock(play->schMutex_);\r
         }\r
-        MediaMutexUnLock(play->schMutex_);\r
     }\r
 \r
     MediaMutexLock(play->schMutex_);\r
@@ -1596,7 +1652,11 @@ int32_t PlayerControl::DoPlay()
         CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "playerSource_ Start failed");\r
         MediaMutexLock(schMutex_);\r
         paused_ = true;\r
-        MediaThreadattr attr = { "PlaySch", MAX_THREAD_STACK_SIZE, THREAD_SCHED_INVALID, 80, false };\r
+        uint32_t stackSize = MAX_THREAD_STACK_SIZE;\r
+        if (filePath_.find(".m3u8") != 0) {\r
+            stackSize = MAX_THREAD_STACK_SIZE_M3U8;\r
+        }\r
+        MediaThreadattr attr = { "PlaySch", stackSize, THREAD_SCHED_INVALID, 80, false };\r
         schProcess_ = MediaThreadCreate(DataSchProcess, this, &attr);\r
         if (schProcess_ == nullptr) {\r
             MEDIA_ERR_LOG("thread create failed %d", ret);\r
@@ -1609,6 +1669,12 @@ int32_t PlayerControl::DoPlay()
     } else if (playerState == PLAY_STATUS_PAUSE) {\r
         ret = PauseResume();\r
         CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "PauseResume failed");\r
+    } else if (playerState == PLAY_STATUS_TPLAY) {\r
+        ret = DoSetPlaybackSpeed(TPLAY_SPEED_BASE);  // resume to normal speed\r
+        CHECK_FAILED_RETURN(ret, HI_SUCCESS, ret, "DoSetPlaybackSpeed 1.0 failed");\r
+    } else if (playerState == PLAY_STATUS_PLAY) {\r
+        MEDIA_INFO_LOG("no need to repeat play operation");\r
+        return 0;\r
     } else {\r
         return HI_ERR_PLAYERCONTROL_ILLEGAL_STATE_ACTION;\r
     }\r
@@ -1623,6 +1689,106 @@ int32_t PlayerControl::DoSetVolume(const VolumeAttr &volumeAttr)
     return sinkManager_->SetVolume(volumeAttr.leftVolume, volumeAttr.rightVolume);\r
 }\r
 \r
+void PlayerControl::TPlayRewindToNormal()\r
+{\r
+    DecoderAndSinkReset();\r
+    sinkManager_->SetSpeed(TPLAY_SPEED_BASE);\r
+    speed_ = TPLAY_SPEED_BASE;\r
+    curState_ = PLAY_STATUS_PLAY;\r
+    seekToTimeMs_ = 0;\r
+    StateChangeCallback(curState_);\r
+}\r
+\r
+int32_t PlayerControl::TPlayBeforeFrameRead()\r
+{\r
+    int32_t ret = HI_SUCCESS;\r
+\r
+    if (tplayMode_ != TPLAY_MODE_ONLY_I_FRAME) {\r
+        return ret;\r
+    }\r
+\r
+    if (isTplayLastFrame_) {\r
+        MEDIA_INFO_LOG("TPlayBeforeFrameRead TPlayIsFileReadEnd");\r
+        return HI_RET_FILE_EOF;\r
+    }\r
+\r
+    int64_t seekTimeInMs = lastReadPktPts_ + curSeekOffset_;\r
+    TplayDirect direction = speed_ < 0 ? TPLAY_DIRECT_BACKWARD : TPLAY_DIRECT_FORWARD;\r
+    FormatSeekMode seekFlag = (speed_ < 0) ? FORMAT_SEEK_MODE_BACKWARD_KEY :\r
+        FORMAT_SEEK_MODE_FORWARD_KEY;\r
+    if (seekTimeInMs <= 0 && direction == TPLAY_DIRECT_BACKWARD) {\r
+        seekTimeInMs = 0;\r
+        isTplayLastFrame_ = true;\r
+    } else if (seekTimeInMs >= fmtFileInfo_.s64Duration && direction == TPLAY_DIRECT_FORWARD) {\r
+        seekTimeInMs = fmtFileInfo_.s64Duration;\r
+        seekFlag = FORMAT_SEEK_MODE_BACKWARD_KEY;\r
+        isTplayLastFrame_ = true;\r
+    } else if (lastReadPktPts_ == 0 && !isTplayStartRead_) {\r
+        seekTimeInMs = 0;\r
+        seekFlag = FORMAT_SEEK_MODE_BACKWARD_KEY;\r
+        isTplayLastFrame_ = false;\r
+    }\r
+    ret = playerSource_->Seek(fmtFileInfo_.s32UsedVideoStreamIndex, seekTimeInMs, seekFlag);\r
+    if (ret != HI_SUCCESS) {\r
+        MEDIA_INFO_LOG("playerSource_ seek failed maybe seek to file end, ret:%d", ret);\r
+        return HI_RET_FILE_EOF;\r
+    }\r
+\r
+    return HI_SUCCESS;\r
+}\r
+\r
+int32_t PlayerControl::TPlayAfterFrameRead(FormatFrame &packet)\r
+{\r
+    bool isSkipPkt = false;\r
+\r
+    if ((packet.timestampUs == lastReadPktPts_) && isTplayStartRead_) {\r
+        lastReadPktPts_ += curSeekOffset_;\r
+        isSkipPkt = true;\r
+    } else {\r
+        lastReadPktPts_ = packet.timestampUs;\r
+    }\r
+\r
+    return isSkipPkt ? HI_RET_SKIP_PACKET : HI_SUCCESS;\r
+}\r
+\r
+int32_t PlayerControl::TplayReadPacket()\r
+{\r
+    int32_t ret = HI_SUCCESS;\r
+    if (cachedPacket_) {\r
+        return ret;\r
+    }\r
+\r
+    ret = TPlayBeforeFrameRead();\r
+    if (ret == HI_RET_FILE_EOF) {\r
+        if (memset_s(&formatPacket_, sizeof(formatPacket_), 0, sizeof(FormatFrame)) != EOK) {\r
+            MEDIA_ERR_LOG("SET  formatPacket_ failed");\r
+            return HI_FAILURE;\r
+        }\r
+        cachedPacket_ = true;  // send eos\r
+        return HI_SUCCESS;\r
+    }\r
+    ret = ReadFrameFromSource(formatPacket_);\r
+    if (ret == HI_RET_FILE_EOF) {\r
+        if (memset_s(&formatPacket_, sizeof(formatPacket_), 0, sizeof(FormatFrame)) != EOK) {\r
+            MEDIA_ERR_LOG("SET  formatPacket_ failed");\r
+            return HI_FAILURE;\r
+        }\r
+    } else if (ret != HI_SUCCESS) {\r
+        MEDIA_ERR_LOG("ReadFrameFromSource failed , ret:%d", ret);\r
+        NotifyError(PLAYERCONTROL_ERROR_DEMUX_FAIL);\r
+        return HI_FAILURE;\r
+    }\r
+    cachedPacket_ = true;\r
+    ret = TPlayAfterFrameRead(formatPacket_);\r
+    if (ret == HI_RET_SKIP_PACKET) {\r
+        ClearCachePacket();\r
+        return ret;\r
+    }\r
+    isTplayStartRead_ = true;\r
+    strmReadEnd_ = false;\r
+    return ret;\r
+}\r
+\r
 int32_t PlayerControl::ReadPacket()\r
 {\r
     int32_t ret = HI_SUCCESS;\r
@@ -1771,11 +1937,13 @@ int32_t PlayerControl::DoPause(void)
     CHECK_STATE_SAME_RETURN(playerState, PLAY_STATUS_PAUSE, "state same");\r
     CHECK_NULL_RETURN(sinkManager_, HI_FAILURE, "sinkManager_ nullptr");\r
 \r
-    if (playerState == PLAY_STATUS_PLAY) {\r
+    if (playerState == PLAY_STATUS_PLAY || playerState == PLAY_STATUS_TPLAY) {\r
         MediaMutexLock(schMutex_);\r
         int32_t ret = sinkManager_->Pause();\r
         CHECK_FAILED_PRINT(ret, 0, "sinkManager_ pause failed:%d");\r
         paused_ = true;\r
+               MediaThreadCondSignal(schCond_);\r
+        MediaThreadCondTimeWait(pauseCond_, schMutex_, WAIT_PAUSE_TIME_OUT_US);\r
         MediaMutexUnLock(schMutex_);\r
     } else {\r
         return HI_ERR_PLAYERCONTROL_ILLEGAL_STATE_ACTION;\r
@@ -1842,13 +2010,72 @@ int32_t PlayerControl::DoSetMedia(const PlayerControlStreamAttr &mediaAttr)
     return ret;\r
 }\r
 \r
-int32_t PlayerControl::DoSetPlaybackSpeed(float speed) const\r
+TplayMode PlayerControl::TPlayGetPlayMode()\r
+{\r
+    if (speed_ < 0) {\r
+        return TPLAY_MODE_ONLY_I_FRAME;\r
+    }\r
+\r
+    if ((fmtFileInfo_.u32Width <= 0) || (fmtFileInfo_.u32Height <= 0) || (fmtFileInfo_.fFrameRate <= 0)) {\r
+        MEDIA_ERR_LOG("get stream info failed");\r
+        return TPLAY_MODE_FULL_PLAY;\r
+    }\r
+\r
+    TplayMode tplayMode = TPLAY_MODE_ONLY_I_FRAME;\r
+    uint64_t resolution = fmtFileInfo_.u32Width * fmtFileInfo_.u32Height;\r
+    if (resolution <= FULL_TPLAY_RESULITON_LIMIT &&\r
+        fmtFileInfo_.fFrameRate * speed_ <= FULL_TPLAY_FRAMERATE_LIMIT) {\r
+        tplayMode = TPLAY_MODE_FULL_PLAY;\r
+    }\r
+\r
+    return tplayMode;\r
+}\r
+\r
+/* Calculate the seeking offset in ONLY_I_FRAME mode.\r
+ * offset = (Number of I-frames needed per second) / (Target tplay frame rate) * (I-frame interval)\r
+ * = ((srcFps * speed / gop) / tPlayFps) * ((1000 * gop) / srcFps).\r
+ * Note: It is necessary to set an appropriate GOP_SIZE. For mjpeg format, GOP_SIZE should be set to 1,\r
+ * but for H.264, other values need to be set.\r
+ */\r
+int32_t PlayerControl::TPlayGetSeekOffset(float speed)\r
+{\r
+    int32_t positiveSpeed = (speed < 0 ? -speed : speed);\r
+    float srcFps = fmtFileInfo_.fFrameRate;\r
+    float tPlayFps = FULL_TPLAY_FRAMERATE_LIMIT;\r
+\r
+    float gopPts = MS_SCALE * GOP_SIZE / srcFps;\r
+    float skipIFrameNum = (srcFps * positiveSpeed / GOP_SIZE) / tPlayFps;\r
+    float skipPts = skipIFrameNum * gopPts;\r
+    float seekOffset = (speed < 0 ? -skipPts : skipPts);\r
+\r
+    return static_cast<int32_t>(seekOffset);\r
+}\r
+\r
+int32_t PlayerControl::DoSetPlaybackSpeed(float speed)\r
 {\r
     MediaMutexLock(schMutex_);\r
-    int ret = sinkManager_->SetSpeed(speed);\r
+    ClearCachePacket();\r
+    int32_t ret = DecoderAndSinkReset();\r
     if (ret != HI_SUCCESS) {\r
-        MEDIA_ERR_LOG("DoSetPlaybackSpeed failed:%d", ret);\r
+        MEDIA_ERR_LOG("DecoderAndSinkReset failed, ret:%d", ret);\r
+        MediaMutexUnLock(schMutex_);\r
+        return ret;\r
+    }\r
+    ret = sinkManager_->SetSpeed(speed);\r
+    if (ret != HI_SUCCESS) {\r
+        MEDIA_ERR_LOG("sink manager set speed failed, ret:%d", ret);\r
+        MediaMutexUnLock(schMutex_);\r
+        return ret;\r
     }\r
+    speed_ = speed;\r
+    lastReadPktPts_ = currentPosition_;\r
+    isTplayLastFrame_ = false;\r
+    tplayMode_ = TPlayGetPlayMode();\r
+    if (tplayMode_ == TPLAY_MODE_ONLY_I_FRAME) {\r
+        curSeekOffset_ = TPlayGetSeekOffset(speed);\r
+    }\r
+    MEDIA_DEBUG_LOG("DoSetPlaybackSpeed speed_:%f, curSeekOffset_:%d, tplayMode_:%d",\r
+        speed_, curSeekOffset_, tplayMode_);\r
     MediaMutexUnLock(schMutex_);\r
     return HI_SUCCESS;\r
 }\r
@@ -1867,9 +2094,11 @@ void PlayerControl::EventCallback(PlayerControlEvent event, const void *data) co
 \r
 void PlayerControl::PlayerControlCondSignal(void)\r
 {\r
-    if (fmtFileInfo_.s32UsedVideoStreamIndex < 0) {\r
+    MediaMutexLock(schMutex_);\r
+    if (fmtFileInfo_.s32UsedVideoStreamIndex < 0 && !hasRenderAudioEos_ && renderSleepTime_ > 0) {\r
         MediaThreadCondSignal(schCond_);\r
     }\r
+    MediaMutexUnLock(schMutex_);\r
 }\r
 \r
 void PlayerControl::EnableSingleLooping(bool loop)\r
@@ -1962,6 +2191,7 @@ int32_t PlayerControl::AyncSeek(int64_t seekTime)
     CHECK_NULL_RETURN(playerSource_, HI_FAILURE, "playerSource_ nullptr");\r
     int64_t seekTimeInMs = seekTime;\r
     int32_t ret = 0;\r
+    sinkManager_->Reset();\r
     ClearCachePacket();\r
     if (fmtFileInfo_.s32UsedVideoStreamIndex != HI_DEMUXER_NO_MEDIA_STREAM) {\r
         ret = playerSource_->Seek(fmtFileInfo_.s32UsedVideoStreamIndex, seekTimeInMs, FORMAT_SEEK_MODE_BACKWARD_KEY);\r
@@ -1978,6 +2208,11 @@ int32_t PlayerControl::AyncSeek(int64_t seekTime)
         }\r
     }\r
     currentPosition_ = seekTimeInMs;\r
+    if (speed_ != TPLAY_SPEED_BASE) {\r
+        lastReadPktPts_ = currentPosition_;\r
+        isTplayStartRead_ = (currentPosition_ == 0) ? false : true;\r
+        isTplayLastFrame_ = false;\r
+    }\r
     EventCallback(PLAYERCONTROL_EVENT_PROGRESS, &currentPosition_);\r
     EventCallback(PLAYERCONTROL_EVENT_SEEK_END, static_cast<void *>(&seekTimeInMs));\r
     return HI_SUCCESS;\r
@@ -2237,12 +2472,17 @@ PlayerStatus PlayerControl::GetCurState(void)
 \r
 PlayerStatus PlayerControl::FindTransition(PlayerStatus state, int32_t event) const\r
 {\r
+    PlayerStatus nextState = state;\r
     for (uint32_t i = 0; i < STATE_TRANS_STATE_SIZE; i++) {\r
         if (event == STATE_MACHINE[state][i].msgType) {\r
-            return STATE_MACHINE[state][i].newState;\r
+            nextState = STATE_MACHINE[state][i].newState;\r
+            break;\r
         }\r
     }\r
-    return state;\r
+    if (nextState == PLAY_STATUS_PLAY && speed_ != TPLAY_SPEED_BASE) {\r
+        nextState = PLAY_STATUS_TPLAY;\r
+    }\r
+    return nextState;\r
 }\r
 \r
 bool PlayerControl::EventValidAtCurState(PlayerControlMsgType type)\r
index acd3c1d..a5d6181 100644 (file)
@@ -82,23 +82,23 @@ using StateMap = struct {
 status table of operation, false is not support
 *******************************************************************/
 const bool LITEPLAY_STATE[PLAYERCONTROL_MSG_BUTT][PLAY_STATUS_BUTT] = {
-    /* idle, init,  prepare play, pause, err */
-    { false, false, true,  false, false, false }, /* setMedia */
-    { true,  true,  true,  true,  true,  true },  /* regCallbk */
-    { true,  false, false, false, false, false }, /* setsrc_fd */
-    { true,  false, false, false, false, false }, /* setsrc_uri */
-    { true,  false, false, false, false, false }, /* setsrc_stream */
-    { false, true,  true,  false, false, false }, /* prepare */
-    { false, false, true,  true,  true,  false }, /* play */
-    { false, false, false, true,  true,  false }, /* seek */
-    { false, false, false, true,  true,  false }, /* pause */
-    { false, false, false, true,  false, false }, /* setspeed */
-    { true,  true,  true,  true,  true,  true },  /* stop */
-    { false, false, true,  true,  true,  false }, /* getInfo */
-    { true,  false, false, true,  true,  false }, /* handledata */
-    { true,  true,  true,  true,  true,  true },  /* Error */
-    { false, true,  true,  true,  true,  false }, /* setVolume */
-    { true,  true,  true,  true,  true,  true },  /* invoke */
+    /* idle, init,  prepare play, tplay, pause, err */
+    { false, false, true,  false, false, false, false }, /* setMedia */
+    { true,  true,  true,  true,  false, true,  true },  /* regCallbk */
+    { true,  false, false, false, false, false, false }, /* setsrc_fd */
+    { true,  false, false, false, false, false, false }, /* setsrc_uri */
+    { true,  false, false, false, false, false, false }, /* setsrc_stream */
+    { false, true,  true,  false, false, false, false }, /* prepare */
+    { false, false, true,  true,  true,  true,  false }, /* play */
+    { false, false, false, true,  false, true,  false }, /* seek */
+    { false, false, false, true,  true,  true,  false }, /* pause */
+    { false, false, false, true,  true,  false, false }, /* setspeed */
+    { true,  true,  true,  true,  true,  true,  true },  /* stop */
+    { false, false, true,  true,  false, true,  false }, /* getInfo */
+    { true,  false, false, true,  false, true,  false }, /* handledata */
+    { true,  true,  true,  true,  true,  true,  true },  /* Error */
+    { false, true,  true,  true,  false, true,  false }, /* setVolume */
+    { true,  true,  true,  true,  false, true,  true },  /* invoke */
 };
 
 const uint32_t STATE_TRANS_STATE_SIZE = 4u;
@@ -122,10 +122,16 @@ const StateMap STATE_MACHINE[][STATE_TRANS_STATE_SIZE] = {
         {PLAYERCONTROL_MSG_BUTT,    PLAY_STATUS_PREPARED}
     },
     { /* play */
-        {PLAYERCONTROL_MSG_STOP,    PLAY_STATUS_IDLE},
-        {PLAYERCONTROL_MSG_PAUSE,   PLAY_STATUS_PAUSE},
-        {PLAYERCONTROL_MSG_ERROR,   PLAY_STATUS_ERR},
-        {PLAYERCONTROL_MSG_BUTT,    PLAY_STATUS_PLAY}
+        {PLAYERCONTROL_MSG_STOP,     PLAY_STATUS_IDLE},
+        {PLAYERCONTROL_MSG_PAUSE,    PLAY_STATUS_PAUSE},
+        {PLAYERCONTROL_MSG_ERROR,    PLAY_STATUS_ERR},
+        {PLAYERCONTROL_MSG_SETSPEED, PLAY_STATUS_TPLAY}
+    },
+    { /* tplay */
+        {PLAYERCONTROL_MSG_STOP,     PLAY_STATUS_IDLE},
+        {PLAYERCONTROL_MSG_PAUSE,    PLAY_STATUS_PAUSE},
+        {PLAYERCONTROL_MSG_PLAY,     PLAY_STATUS_PLAY},
+        {PLAYERCONTROL_MSG_ERROR,    PLAY_STATUS_ERR},
     },
     { /* pause */
         {PLAYERCONTROL_MSG_STOP,    PLAY_STATUS_IDLE},
@@ -227,7 +233,7 @@ protected:
 
     int32_t DoSetMedia(const PlayerControlStreamAttr &mediaAttr);
 
-    int32_t DoSetPlaybackSpeed(float speed) const;
+    int32_t DoSetPlaybackSpeed(float speed);
 
     int32_t DoInvoke(const InvokeParameter &invokeParam);
     void ClearCachePacket(void);
@@ -308,6 +314,12 @@ private:
 #endif
     void FillAudioFrameInfo(EsFrameInfo &outInfo);
     void GetRenderFullSleepThresholdTime(AudioCodecFormat codecFormat);
+    void TPlayRewindToNormal();
+    TplayMode TPlayGetPlayMode(void);
+    int32_t TPlayGetSeekOffset(float speed);
+    int32_t TplayReadPacket();
+    int32_t TPlayBeforeFrameRead(void);
+    int32_t TPlayAfterFrameRead(FormatFrame& packet);
 
 private:
     bool isInited_;
@@ -325,6 +337,13 @@ private:
     int64_t lastReadPktPts_;
     int64_t lastSendPktPts_;
 
+    // TPlay
+    float speed_;
+    TplayMode tplayMode_;
+    int32_t curSeekOffset_;
+    bool isTplayStartRead_;
+    bool isTplayLastFrame_;
+
     bool isVideoStarted_;
     bool isAudioStarted_;
     bool strmReadEnd_;
@@ -346,11 +365,14 @@ private:
     float rightVolume_;
     MediaMutexHandle schMutex_;
     MediaThreadCondHandle schCond_;
+    MediaThreadCondHandle pauseCond_;
     MediaThreadIdHandle schProcess_;
     int64_t seekToTimeMs_;
     SourceType sourceType_;
     bool firstAudioFrameAfterSeek_;
     bool firstVideoFrameAfterSeek_;
+    bool firstAudioFrameSend_;
+    bool firstVideoFrameSend_;
     int64_t firstPosAfterSeek_;
     int32_t fd_;
     uint64_t offset_;
index 16e8994..8160496 100644 (file)
@@ -27,13 +27,14 @@ extern "C" {
 static const uint32_t  MS_SCALE   = 1000;
 static const int64_t INVALID_PTS = -1;
 
-static const uint32_t FULL_TPLAY_FRAMERATE_LIMIT = 30;
+static const float FULL_TPLAY_FRAMERATE_LIMIT = 60.0;
 /* DEFAULT_BITRATE: 2 * 1024 */
 static const uint32_t FULL_TPLAY_BITRATE_LIMIT = 2048;
-/* TPLAY_FULL_LIMIT_RESULITON: 1024 * 576 */
-static const uint32_t FULL_TPLAY_RESULITON_LIMIT   = 589824;
+/* TPLAY_FULL_LIMIT_RESULITON: 500 * 500 */
+static const uint32_t FULL_TPLAY_RESULITON_LIMIT   = 250000;
 static const uint32_t HI_RET_SKIP_PACKET   = 1;
 static const uint32_t EXTRA_MBUF_LEN = 1500;
+static const uint32_t GOP_SIZE = 1;
 
 static const uint32_t TPLAY_SPEED_DECIMAL_PRECISION  = 1000;
 static const uint32_t AUDIO_BITWIDTH = 16;
index 27864f3..68dca9e 100644 (file)
@@ -160,9 +160,6 @@ int32_t AudioSink::Init(const SinkAttr &atrr)
 void AudioSink::ResetRendStartTime()
 {
     lastRendFrameCnt_ = 0;
-#ifdef MINI_MEMORY_SUPPORT
-    lastRenderPosition_ = 0;
-#endif
     lastRendPts_ = AV_INVALID_PTS;
     rendStartTime_ = AV_INVALID_PTS;
 }
@@ -456,7 +453,7 @@ int32_t AudioSink::RenderEsFrame(const EsFrameInfo &frame)
         return SINK_RENDER_DELAY;
     }
 
-    ret = (syncHdl_ != nullptr) ? syncHdl_->ProcAudFrame(posNs / NANOS_PER_MILLISECOND, syncRet) : SINK_SUCCESS;
+    ret = (syncHdl_ != nullptr) ? syncHdl_->ProcAudFrame(renderFrame.pts, syncRet) : SINK_SUCCESS;
     if (ret != HI_SUCCESS) {
         MEDIA_ERR_LOG("process audio frame pts: %lld failed", posNs / NANOS_PER_MILLISECOND);
         ReleaseQueHeadEsFrame();
@@ -477,7 +474,11 @@ int32_t AudioSink::RenderEsFrame(const EsFrameInfo &frame)
     }
 
     if (ret == SINK_SUCCESS || ret == SINK_RENDER_ERROR) {
+#ifdef MINI_MEMORY_SUPPORT
+        lastRendPts_ = posNs / NANOS_PER_MILLISECOND;
+#else
         lastRendPts_ = frame.pts;
+#endif
         rendFrameCnt_++;
     }
     return ret;
@@ -674,7 +675,7 @@ int32_t AudioSink::SetOutputDevice(const int32_t deviceId) const
 void AudioSink::RecordLastPosition()
 {
 #ifdef MINI_MEMORY_SUPPORT
-    lastRenderPosition_ = lastRendPts_;
+    lastRenderPosition_ += lastRendPts_;
 #endif
 }
 
index 4dc4089..44acadd 100644 (file)
@@ -240,11 +240,23 @@ int32_t SinkManager::SetSpeed(const float speed)
     if (speed_ == speed) {
         return 0;
     }
-    ret = audioSinkInfo_[0].sink->SetSpeed(speed);
-    if (ret != 0) {
-        MEDIA_ERR_LOG("m_syncHdl  TPlay Ret: %d", ret);
+    if (audioSinkInfo_[0].sink != nullptr) {
+        MEDIA_ERR_LOG("support only video stream");
+        return -1;
+    }
+
+    ret = sync_->Reset(SYNC_CHN_VID);
+    if (ret != HI_SUCCESS) {
+        MEDIA_ERR_LOG("sync reset vid failed, ret: %d", ret);
         return ret;
     }
+
+    ret = sync_->SetSpeed(speed);
+    if (ret != HI_SUCCESS) {
+        MEDIA_ERR_LOG("sync set speed failed, ret: %d", ret);
+        return ret;
+    }
+
     speed_ = speed;
     return 0;
 }
index c02d70d..ec4b3e1 100644 (file)
@@ -67,6 +67,32 @@ SyncRet PlayerSync::CheckAVDiff(int64_t latenessMs, uint32_t &continueLost)
     return syncRet;
 }
 
+/* Synchronization processing in tplay mode, considering only video
+ * stream which using system time as the reference.
+ * lateness = (system time difference) * speed - PTS) / speed.
+ */
+int32_t PlayerSync::TPlayProcess(int64_t timestampUs, SyncRet &syncRet)
+{
+    int64_t nowTsUs;
+    int64_t latenessUs = 0;
+    int64_t realTimeElapseUs = GetCurTimeUs() - frstVidFrameTime_;
+    int64_t trickTimeElapseUs = static_cast<int64_t>(realTimeElapseUs * speed_);
+
+    if (speed_ > 0) {
+        nowTsUs = firstVidFrameTs_ + trickTimeElapseUs;
+        latenessUs = (nowTsUs - timestampUs);
+    } else {  // backward
+        nowTsUs = firstVidFrameTs_ - trickTimeElapseUs;
+        if (nowTsUs < 0) {
+            nowTsUs = 0;
+        }
+        latenessUs = (timestampUs - nowTsUs);
+    }
+    int64_t latenessMs = (speed_ != 0) ? (latenessUs / (static_cast<int>(speed_ * MS_SCALE))) : 0;
+    syncRet = CheckAVDiff(latenessMs, continousVidLost_);
+    return HI_SUCCESS;
+}
+
 int32_t PlayerSync::Reset(SyncChn syncChn)
 {
     diffAvRenderTime_ = 0;
@@ -194,6 +220,18 @@ int32_t PlayerSync::Start(SyncChn syncChn)
     return HI_SUCCESS;
 }
 
+int32_t PlayerSync::SetSpeed(float speed)
+{
+    if (!isInited_) {
+        MEDIA_ERR_LOG("sync SetSpeed before inited");
+        return HI_FAILURE;
+    }
+    MediaMutexLock(vidSyncLock_);
+    speed_ = speed;
+    MediaMutexUnLock(vidSyncLock_);
+    return HI_SUCCESS;
+}
+
 /* only used to resume from tplay to normal */
 int32_t PlayerSync::Resume()
 {
@@ -266,11 +304,6 @@ int32_t PlayerSync::CheckVidSyncEnable(SyncRet &result, int32_t &ret)
         ret = HI_FAILURE;
         return HI_FAILURE;
     }
-    if (!isAudEnable_) {
-        MEDIA_DEBUG_LOG("pure video no need sync");
-        result = SYNC_RET_PLAY;
-        return HI_FAILURE;
-    }
     return HI_SUCCESS;
 }
 
@@ -300,7 +333,7 @@ int32_t PlayerSync::ProcVidFrame(int64_t ptsMs, SyncRet &result)
     int32_t ret = HI_SUCCESS;
 
     MediaMutexLock(vidSyncLock_);
-    if (CheckVidSyncEnable(ret) != HI_SUCCESS) {\r
+    if (CheckVidSyncEnable(result, ret) != HI_SUCCESS) {\r
         goto UNLOCK;\r
     }
     if (syncAttr_.refType == PLAYER_SYNC_REF_NONE) {
@@ -317,6 +350,11 @@ int32_t PlayerSync::ProcVidFrame(int64_t ptsMs, SyncRet &result)
         result = ProcessFristVideoFrame(ptsUs);
         goto UNLOCK;
     }
+    if (speed_ != 1.0) {
+        (void)TPlayProcess(ptsUs, result);
+        lastVideoTsUs_ = ptsUs;
+        goto UNLOCK;
+    }
     nowUs = GetCurTimeUs() - vidTimeSourceDelta_;
     UpdateCurTimeWithAudio(nowUs);
     diffAvRenderTime_ = (nowUs - ptsUs) / MS_SCALE;
@@ -346,7 +384,7 @@ void PlayerSync::WaitForFirstVideoFrame(SyncRet &result, bool &timeOut)
         firstAudFrameTime_ = GetCurTimeUs();
     }
     if (GetCurTimeUs() - firstAudFrameTime_ <= FIRST_AUDIO_RENDER_WAIT_VID_TIME) {
-        result = SYNC_RET_REPEAT;
+        result = SYNC_RET_DROP;
         timeOut = false;
     } else {
         timeOut = true;
@@ -355,10 +393,6 @@ void PlayerSync::WaitForFirstVideoFrame(SyncRet &result, bool &timeOut)
 
 int32_t PlayerSync::ProcessFristAudioFrame(int64_t timeUs)
 {
-    // need consider first audio frame pts is not 0
-    if ((lastVideoTsUs_ != AV_INVALID_PTS) && (lastVideoTsUs_ < timeUs)) {
-        return HI_FAILURE;
-    }
     // caculate pts and clock delta of first frame
     int64_t firstTimeUs = GetCurTimeUs();
     audTimeSourceDelta_ = firstTimeUs - timeUs;
index b07be27..a8754a4 100644 (file)
@@ -83,6 +83,7 @@ public:
     int32_t SetAttr(PlayerSyncAttr &syncAttr);
     int32_t GetAttr(PlayerSyncAttr &syncAttr);
     int32_t Resume();
+    int32_t SetSpeed(float speed);
 
 private:
     void WaitForFirstVideoFrame(SyncRet &result, bool &timeOut);
@@ -93,6 +94,7 @@ private:
     SyncRet ProcessFristVideoFrame(int64_t ptsUs);
     int32_t CheckVidSyncEnable(SyncRet &result, int32_t &ret);
     int32_t CheckAudSyncEnable(SyncRet &result, int32_t &ret);
+    int32_t TPlayProcess(int64_t timestampUs, SyncRet &syncRet);
 private:
     PlayerSyncAttr syncAttr_;
     MediaMutexHandle audSyncLock_;
index 54d396b..03e8e74 100644 (file)
@@ -310,11 +310,10 @@ int32_t VideoSink::RegisterCallBack(const PlayEventCallback &callback)
 
 void VideoSink::QueueRenderFrame(OutputInfo &frame, bool cacheQueue)
 {
-    MediaMutexLock(mutex_);
-    if (frame.type != AUDIO_DECODER || frame.bufferCnt == 0) {
-        MediaMutexUnLock(mutex_);
+    if (frame.bufferCnt == 0) {
         return;
     }
+    MediaMutexLock(mutex_);
     if (cacheQueue) {
         frameCacheQue_.push_back(frame);
     } else {
@@ -360,9 +359,22 @@ void VideoSink::ReleaseQueAllFrame(void)
         return;
     }
     for (i = 0; i < queSize; i++) {
-        frameReleaseQue_.push_back(frameCacheQue_[i]);
+        OutputInfo frame = frameCacheQue_[0];
+        frameCacheQue_.erase(frameCacheQue_.begin());
+        frameReleaseQue_.push_back(frame);
+#if defined(ENABLE_UIKIT)
+        Surface *surface = attr_.vidAttr.surface;
+        if (surface != nullptr) {
+            surface->CancelBuffer(static_cast<SurfaceBuffer *>(frame.vendorPrivate));
+        }
+#elif defined(ENABLE_LVGL)
+        LvSurfaceView *surface = attr_.vidAttr.surface;
+        if (surface != nullptr) {
+            LvFlushBuffer(reinterpret_cast<lv_obj_t *>(surface), static_cast<LvSurfaceBuffer *>(frame.vendorPrivate));
+        }
+#endif
     }
-    frameCacheQue_.clear();
+
     MediaMutexUnLock(mutex_);
 }
 
index d3dca70..7ca15da 100644 (file)
@@ -202,6 +202,7 @@ void PlayerDemuxer::GetFormatFileInfoFromProgramInfo(int32_t trackId[], int32_t
                 fileInfo.u32Width = programInfo->track[i].vidTrack.width;
                 fileInfo.u32Height = programInfo->track[i].vidTrack.height;
                 fileInfo.enVideoType = programInfo->track[i].vidTrack.format;
+                fileInfo.fFrameRate = programInfo->track[i].vidTrack.fpsNum;
             } else if (programInfo->track[i].trackType == TRACK_TYPE_AUDIO) {
                 fileInfo.s32UsedAudioStreamIndex = programInfo->track[i].trackId;
                 fileInfo.u32AudioChannelCnt = programInfo->track[i].audTrack.channels;
index 5d42f96..513cd7b 100644 (file)
@@ -215,6 +215,23 @@ void Player::PlayerImpl::UpdateState(PlayerImpl *curPlayer, PlayerStatus state)
     MEDIA_INFO_LOG("@@player UpdateState, state:%d", state);
 }
 
+void Player::PlayerImpl::PlayerControlDefaultEventCb(PlayerImpl *curPlayer, PlayerControlEvent enEvent, const void *pData)
+{
+    if (pData == nullptr || curPlayer == nullptr) {\r
+        return;\r
+    }
+    PlayerControlEvent subEventData = *static_cast<const PlayerControlEvent *>(pData);\r
+    int32_t eventType = enEvent;\r
+    if (eventType == PLAYERCONTROL_FIRST_AUDIO_FRAME ||\r
+        eventType == PLAYERCONTROL_FIRST_VIDEO_FRAME) {\r
+        eventType = PlayerCallback::PlayerInfoType::PLAYER_INFO_PLAYING;
+    } else if (eventType == PLAYERCONTROL_EVENT_PAUSED) {\r
+        eventType = PlayerCallback::PlayerInfoType::PLAYER_INFO_PAUSED;\r
+\r
+    }
+    curPlayer->OnInfoPlayCallBack(eventType, subEventData);
+}
+
 void Player::PlayerImpl::PlayerControlEventCb(void *pPlayer, PlayerControlEvent enEvent, const void *pData)
 {
     PlayerControlError subErr = PLAYERCONTROL_ERROR_BUTT;
@@ -237,30 +254,31 @@ void Player::PlayerImpl::PlayerControlEventCb(void *pPlayer, PlayerControlEvent
         case PLAYERCONTROL_EVENT_SOF:
             MEDIA_INFO_LOG("start of file");
             break;
-        case PLAYERCONTROL_EVENT_ERROR:
-            if (pData == nullptr) {
-                return;
-            }
-            subErr = *static_cast<const PlayerControlError *>(pData);
-            MEDIA_ERR_LOG("error: %d", subErr);
-            if (curPlayer->callback_ != nullptr) {
-                curPlayer->callback_->OnError(0, subErr);
-            }
+        case PLAYERCONTROL_EVENT_ERROR:\r
+            if (pData == nullptr) {\r
+                return;\r
+            }\r
+            subErr = *static_cast<const PlayerControlError *>(pData);\r
+            MEDIA_ERR_LOG("error: %d", subErr);\r
+            if (curPlayer->callback_ != nullptr) {\r
+                curPlayer->callback_->OnError(subErr, subErr);\r
+            }\r
             break;
-        case PLAYERCONTROL_EVENT_PROGRESS:
-            if (pData == nullptr) {
-                return;
-            }
-            curPlayer->currentPosition_ = *static_cast<const int64_t *>(pData);
-            break;
-        case PLAYERCONTROL_EVENT_SEEK_END:
-            if (pData == nullptr) {
-                return;
-            }
-            MEDIA_INFO_LOG("seek action end, time is %lld",  *static_cast<const int64_t *>(pData));
-            curPlayer->NotifySeekComplete(curPlayer, *static_cast<const int64_t *>(pData));
+        case PLAYERCONTROL_EVENT_PROGRESS:\r
+            if (pData == nullptr) {\r
+                return;\r
+            }\r
+            curPlayer->currentPosition_ = *static_cast<const int64_t *>(pData);\r
+            break;\r
+        case PLAYERCONTROL_EVENT_SEEK_END:\r
+            if (pData == nullptr) {\r
+                return;\r
+            }\r
+            MEDIA_INFO_LOG("seek action end, time is %lld",  *static_cast<const int64_t *>(pData));\r
+            curPlayer->NotifySeekComplete(curPlayer, *static_cast<const int64_t *>(pData));\r
             break;
         default:
+            PlayerControlDefaultEventCb(curPlayer, enEvent, pData);
             break;
     }
 }
@@ -344,29 +362,24 @@ int32_t Player::PlayerImpl::Play()
     MediaMutexLock(lock_);
     CHECK_TRUE_CONDITION_RETURN_WITH_UNLOCK(released_, -1, "have released or not create", lock_);
     CHK_NULL_RETURN_WITH_UNLOCK(player_, lock_, "player_ is nullptr");
-    if (currentState_ == PLAYER_STARTED) {
-        MEDIA_INFO_LOG("no need to repeat operation");
-        MediaMutexUnLock(lock_);
-        return 0;
-    }
-    if (currentState_ != PLAYER_PREPARED && currentState_ != PLAYER_PAUSED) {
+    if (currentState_ != PLAYER_PREPARED && currentState_ != PLAYER_PAUSED &&
+        currentState_ != PLAYER_STARTED) {
         MEDIA_ERR_LOG("Can not Play, currentState is %d", currentState_);
         MediaMutexUnLock(lock_);
         return -1;
     }
-    if (currentState_ == PLAYER_PAUSED) {
-        goto play;
+    if (currentState_ == PLAYER_PREPARED) {
+        ret = SetMediaStream();
+        CHECK_FAILED_RETURN_WITH_UNLOCK(ret, 0, ret, "SetMeidaStream failed", lock_);
     }
 
-    ret = SetMediaStream();
-    CHECK_FAILED_RETURN_WITH_UNLOCK(ret, 0, ret, "SetMeidaStream failed", lock_);
-play:
     ret = player_->Play();
     if (ret != 0) {
         MEDIA_ERR_LOG("Play exec failed %x", ret);
         MediaMutexUnLock(lock_);
         return -1;
     }
+    OnInfoPlayCallBack(PlayerCallback::PlayerInfoType::PLAYER_INFO_PLAY_START, 0);
     currentState_ = PLAYER_STARTED;
     MediaMutexUnLock(lock_);
     MEDIA_INFO_LOG("process out");
@@ -435,6 +448,7 @@ int32_t Player::PlayerImpl::Stop()
         }
     }
     currentState_ = PLAYER_STOPPED;
+    OnInfoPlayCallBack(PlayerCallback::PlayerInfoType::PLAYER_INFO_STOPPED, 0);
     MediaMutexUnLock(lock_);
     MEDIA_INFO_LOG("process out");
     return 0;
@@ -464,6 +478,7 @@ int32_t Player::PlayerImpl::RewindInner(int64_t mSeconds, PlayerSeekMode mode)
 
     rewindPosition_ = mSeconds;
     rewindMode_ = mode;
+    OnInfoPlayCallBack(PlayerCallback::PlayerInfoType::PLAYER_INFO_SEEK_START, 0);
     ret = player_->Seek(mSeconds);
     if (ret != 0) {
         MEDIA_ERR_LOG("do seek failed, ret is %d", ret);
@@ -624,13 +639,42 @@ int32_t Player::PlayerImpl::GetDuration(int64_t &durationMs)
     return 0;
 }
 
+bool Player::PlayerImpl::IsSpeedValid(float speed)
+{
+    if (speed > 0 && speed <= TPLAY_SPEED_2X_FAST) {
+        return true;
+    }
+    bool isValid = false;
+    switch ((int)speed) {
+        case TPLAY_SPEED_64X_REWIND:
+        case TPLAY_SPEED_32X_REWIND:
+        case TPLAY_SPEED_16X_REWIND:
+        case TPLAY_SPEED_8X_REWIND:
+        case TPLAY_SPEED_4X_REWIND:
+        case TPLAY_SPEED_2X_REWIND:
+        case TPLAY_SPEED_1X_REWIND:
+        case TPLAY_SPEED_BASE:
+        case TPLAY_SPEED_2X_FAST:
+        case TPLAY_SPEED_4X_FAST:
+        case TPLAY_SPEED_8X_FAST:
+        case TPLAY_SPEED_16X_FAST:
+        case TPLAY_SPEED_32X_FAST:
+        case TPLAY_SPEED_64X_FAST:
+            isValid = true;
+            break;
+        default:
+            break;
+    }
+    return isValid;
+}
+
 int32_t Player::PlayerImpl::SetPlaybackSpeed(float speed)
 {
     MEDIA_INFO_LOG("process in");
     MediaMutexLock(lock_);
     CHECK_TRUE_CONDITION_RETURN_WITH_UNLOCK(released_, -1, "have released or not create", lock_);
-    if (speed <= 0.f || speed > 2.0f) {
-        MEDIA_ERR_LOG(" speed is %d", speed);
+    if (!IsSpeedValid(speed)) {
+        MEDIA_ERR_LOG(" speed:%f is invalid", speed);
         MediaMutexUnLock(lock_);
         return -1;
     }
@@ -650,6 +694,12 @@ int32_t Player::PlayerImpl::SetPlaybackSpeed(float speed)
         return -1;
     }
 
+    if (formatFileInfo_.s32UsedVideoStreamIndex == -1 || formatFileInfo_.s32UsedAudioStreamIndex != -1) {
+        MEDIA_ERR_LOG("audio movie not support abnormal speed");
+        MediaMutexUnLock(lock_);
+        return -1;
+    }
+
     CHECK_FAILED_PRINT(player_->SetPlaybackSpeed(speed), 0, "tplayer failed");
     speed_ = speed;
     MediaMutexUnLock(lock_);
@@ -854,6 +904,7 @@ void Player::PlayerImpl::NotifyPlaybackComplete(PlayerImpl *curPlayer)
         curPlayer->currentState_ = PLAYER_PLAYBACK_COMPLETE;
         MEDIA_INFO_LOG("OnPlayBackComplete, iscallbackNull:%d", (curPlayer->callback_ == nullptr));
         if (curPlayer != nullptr && curPlayer->callback_ != nullptr) {
+            curPlayer->OnInfoPlayCallBack(PlayerCallback::PlayerInfoType::PLAYER_INFO_PLAY_END, 0);
             curPlayer->callback_->OnPlaybackComplete();
         }
         return;
@@ -884,6 +935,7 @@ void Player::PlayerImpl::NotifySeekComplete(PlayerImpl *curPlayer, int64_t seekT
     curPlayer->rewindPosition_ = -1;
     if (curPlayer->callback_ != nullptr && extraRewind_) {
         extraRewind_ = false;
+        curPlayer->OnInfoPlayCallBack(PlayerCallback::PlayerInfoType::PLAYER_INFO_SEEK_END, 0);
         curPlayer->callback_->OnRewindToComplete();
     }
     MediaMutexUnLock(curPlayer->rewindLock_);
@@ -915,7 +967,7 @@ int32_t Player::PlayerImpl::SetUriSource(const Source &source)
         MEDIA_ERR_LOG("SetUriSource failed, uri source do not set uri parameter");
         return -1;
     }
-    if (uri.find("http") != 0) {
+    if (uri.find("http") != 0) {\r
         char filePath[PATH_MAX];
 #if !defined(_WIN32)
         if (realpath(uri.c_str(), filePath) == nullptr) {
@@ -928,7 +980,7 @@ int32_t Player::PlayerImpl::SetUriSource(const Source &source)
         if (access(filePath, R_OK) == -1) {
             MEDIA_ERR_LOG("No permission to read the file");
             return -1;
-        }
+        }\r
     }
     int32_t ret = player_->SetDataSource(uri.c_str());
     if (ret != 0) {
@@ -1442,6 +1494,13 @@ void Player::PlayerImpl::PlayerThreadCondSignal(void)
     player_->PlayerControlCondSignal();
 }
 
+void Player::PlayerImpl::OnInfoPlayCallBack(int32_t type, int32_t extra)
+{
+    if (callback_ != nullptr) {
+        callback_->OnInfo(type, extra);
+    }
+}
+
 int32_t Player::PlayerImpl::DumpInfo(PlayerDebugInfo *playerInfo)
 {
     if (playerInfo == nullptr) {\r
index a4502e7..b1d3a35 100644 (file)
@@ -109,7 +109,7 @@ public:
     int32_t GetRoutedDeviceId(int32_t &deviceId);
     int32_t DumpInfo(PlayerDebugInfo *playerInfo);
     void PlayerThreadCondSignal(void);
-
+    void OnInfoPlayCallBack(int32_t type, int32_t extra);
 private:
     void PrintPlayerDumpInfo(const PlayerDebugInfo *playerInfo);
     void PrintControlDumpInfo(const PlayerControlDebugInfo *playerControlInfo);
@@ -125,6 +125,7 @@ private:
     bool IsValidRewindMode(PlayerSeekMode mode);
     void UpdateState(PlayerImpl *curPlayer, PlayerStatus state);
     static void PlayerControlEventCb(void* pPlayer, PlayerControlEvent enEvent, const void* pData);
+    static void PlayerControlDefaultEventCb(PlayerImpl *curPlayer, PlayerControlEvent enEvent, const void *pData);
     int GetPlayer();
     static int32_t GetReadableSize(const void *handle);
     static void ResetPlayerBuffer(PlayerImpl *playImpl, BufferInfo info);
@@ -135,13 +136,13 @@ private:
     int32_t SetMediaStream(void);
     bool IsValidStreamType(int32_t type);
     static int32_t GetStreamParam(const Format &format, StreamParam &param);
+    bool IsSpeedValid(float speed);
 
     std::shared_ptr<PlayerControl> player_;
     float speed_;
     FormatFileInfo formatFileInfo_;
     PlayerControlStreamAttr mediaAttr_;
     PlayerStatus playerControlState_;
-
     bool isSingleLoop_;
     int64_t currentPosition_;
     int64_t rewindPosition_;
index 9df3599..a7fbbdc 100644 (file)
@@ -122,8 +122,14 @@ struct PlayerDebugInfo {
 class PlayerCallback {\r
 public:\r
     enum PlayerInfoType : int32_t {\r
-        /** Pushed the first video frame for rendering */\r
-        PLAYER_INFO_RENDER_START = 0,\r
+        PLAYER_INFO_PLAY_START = 0,\r
+        PLAYER_INFO_PLAYING,\r
+        PLAYER_INFO_PLAY_END,\r
+        PLAYER_INFO_SEEK_START,\r
+        PLAYER_INFO_SEEK_END,\r
+        PLAYER_INFO_STOPPED,\r
+        PLAYER_INFO_PAUSED,\r
+        PLAYER_INFO_BUTT,\r
     };\r
 \r
     enum PlayerErrorType : int32_t {\r
@@ -131,13 +137,13 @@ public:
     };\r
 \r
     enum PlayerErrorCode : int32_t {\r
-        PLAYER_ERROR_CODE_VID_PLAY_FAIL = 0x0, /* The video fails to be played. */\r
+        PLAYER_ERROR_CODE_VID_PLAY_FAIL = 0, /* The video fails to be played. */\r
         PLAYER_ERROR_CODE_AUD_PLAY_FAIL,       /* The audio fails to be played. */\r
         PLAYER_ERROR_CODE_DEMUX_FAIL,          /* The file fails to be played. */\r
         PLAYER_ERROR_CODE_TIMEOUT,             /* Operation timeout. For example, reading data timeout. */\r
         PLAYER_ERROR_CODE_NOT_SUPPORT,         /* The file format is not supportted. */\r
-        PLAYER_ERROR_CODE_UNKNOW,              /* Unknown error. */\r
         PLAYER_ERROR_CODE_ILLEGAL_STATEACTION, /* illegal action at cur state. */\r
+        PLAYER_ERROR_CODE_UNKNOWN,              /* Unknown error. */\r
         PLAYER_ERROR_CODE_BUTT,\r
     };\r
 \r
@@ -170,7 +176,7 @@ public:
     * @since 1.0\r
     * @version 1.0\r
     */\r
-    virtual void OnInfo(int type, int extra) = 0;\r
+    virtual void OnInfo(int32_t type, int32_t extra) = 0;\r
 \r
     /**\r
     * @brief Called when the rewind is complete.\r
index 1bb76eb..0261e24 100644 (file)
@@ -9,7 +9,6 @@ if ("${CHIP}" STREQUAL "brandy")
         set(SOURCES
             ${CMAKE_CURRENT_SOURCE_DIR}/player_sample_wrapper.cpp
             ${CMAKE_CURRENT_SOURCE_DIR}/audio_manager_c_wrapper.cpp
-            
         )
     else()
         set(SOURCE_COM ${SOURCES})
@@ -19,10 +18,11 @@ if ("${CHIP}" STREQUAL "brandy")
             ${CMAKE_CURRENT_SOURCE_DIR}/player_sample_wrapper.cpp
             ${CMAKE_CURRENT_SOURCE_DIR}/video_player_sample_wrapper.cpp
             ${CMAKE_CURRENT_SOURCE_DIR}/voice_call_volte_sample_wrapper.cpp
-            ${CMAKE_CURRENT_SOURCE_DIR}/voice_call_volte_bluetooth_wrapper.cpp
             ${CMAKE_CURRENT_SOURCE_DIR}/audio_manager_c_wrapper.cpp
             ${CMAKE_CURRENT_SOURCE_DIR}/audio_player_service.cpp
             ${CMAKE_CURRENT_SOURCE_DIR}/audio_player_test.cpp
+            ${CMAKE_CURRENT_SOURCE_DIR}/voice_call_volte_bluetooth_wrapper.cpp
+            ${CMAKE_CURRENT_SOURCE_DIR}/audio_recorder_sample.cpp
         )
         if ("ENABLE_UIKIT" IN_LIST DEFINES)
             list(APPEND SOURCE_COM
@@ -90,7 +90,7 @@ if ("${CHIP}" STREQUAL "brandy")
     )
 endif()
 
-set(CCDEFINES ${CCDEFINES} "_GNU_SOURCE" "_XOPEN_SOURCE=700" "LOCAL_VOICE_CALL" "HMF_DECRYPT_DATA_ENABLE")
+set(CCDEFINES ${CCDEFINES} "_GNU_SOURCE" "_XOPEN_SOURCE=700" "LOCAL_VOICE_CALL" "HMF_DECRYPT_DATA_ENABLE" "AUDIO_OGG_SUPPORT")
 list(REMOVE_ITEM CCDEFINES VERSION_STANDARD)
 set(PRIVATE_DEFINES
     ${CCDEFINES}
index cea1dd8..3a907c6 100644 (file)
@@ -6,8 +6,8 @@
 */
 
 #include "audio_capture_wrapper.h"
-#include <stdio.h>
-#include <string.h>
+#include <cstdio>
+#include <cstring>
 #include <climits>
 #include <cstdlib>
 #include <unistd.h>
 #include "audio_manager.h"
 #include "media_log.h"
 #include "media_thread_adapt.h"
+#ifdef AUDIO_OGG_SUPPORT
 #include "ogg.h"
+#endif
+
 #include "custom_utils.h"
 
 #ifdef __cplusplus
@@ -47,6 +50,7 @@ using Audio::AudioManager;
 #define READ_COUNT_MAX 17000*2 //改过的 20分钟
 #define GET_AUDIO_TIME_INTERVAL_TIMES 100
 #define MAX_ARGC 5
+#define BYTE_SIZE 8
 #define CHK_NULL_RETURN(ptr, printfString) \
 do { \
     if ((ptr) == nullptr) { \
@@ -56,13 +60,13 @@ do { \
 } while (0)
 #define CHK_OK_RETURN(ret, printfString) \
 do { \
-    if ((ret) != MEDIA_OK || (ret) != 0) { \
+    if ((ret) != MEDIA_OK) { \
         MEDIA_ERR_LOG("%s", printfString); \
         return MEDIA_ERR; \
     } \
 } while (0)
 const uint32_t MILLSECOND_TO_SECOND = 1000;
-const uint32_t HEADER_STRLEN = 8;
+const uint32_t HEADER_STRLEN = 9;
 const uint32_t OPUS_DELAY_TIME_DIVISOR = 0;
 const uint32_t OPUS_DELAY_TIME_DIVIDED = 100;
 const uint32_t OPUS_ID_HEADER_LEN = 19;
@@ -72,13 +76,6 @@ const uint32_t OPUS_ENCODE_HEADER_SIZE = 8;
 const uint32_t OPUS_OPUSTAGS_LEN = 12;
 const uint32_t OPUS_SAMPLERATE = 48000;
 
-static AudioStreamType g_streamType = AUDIO_STREAM_VOICE_ASSISTANT;
-
-void factory_set_recoder_streamType(void)
-{
-    g_streamType = AUDIO_STREAM_VOICE_RECORD;
-}
-
 typedef struct {
     size_t framesize;
     uint8_t *buffer;
@@ -119,24 +116,25 @@ struct SampleAudioCapturerInfo {
     AudioSession sessionID = AUDIO_SESSION_ID_NONE;
 };
 
-typedef struct CaptureOggContext{
-    ogg_stream_state oggStream;
+#ifdef AUDIO_OGG_SUPPORT
+typedef struct CaptureOggContext {
+    ogg_stream_state oggStream = {};
     int64_t sampleRate;
     int64_t channels;
     int64_t granulepos;
     int64_t packetCount;
-    int32_t serialno; 
-    bool isEnd;
+    int32_t serialno;
+    bool isInited;
     ogg_page *page;
     ogg_packet *packet;
     unsigned char *idHeader;
     unsigned char *commentHeader;
 } CaptureOggContext;
-
 static CaptureOggContext g_oggCtx = {};
+#endif
+
 static bool g_interruptHintStop = false;
 static std::shared_ptr<AudioCapturer> g_audioCap;
-static uint32_t g_ai_record_thread_handle = 0; /* AI录音线程句柄(自定义线程API创建) */
 static NameAudioFormat g_audioCodecFormat[] = {
     {"mp3", MP3},
     {"ape", APE},
@@ -153,14 +151,14 @@ static NameAudioFormat g_audioCodecFormat[] = {
     {"sbc",SBC}
 };
 
-class CaptureInterruptListener : public InterruptListener {
+class AudioCaptureInterruptListener : public InterruptListener {
 public:
-    CaptureInterruptListener() {};
-    ~CaptureInterruptListener() override {};
+    AudioCaptureInterruptListener() {};
+    ~AudioCaptureInterruptListener() override {};
 
     void OnInterrupt(int32_t type, int32_t hint) override
     {
-        MEDIA_INFO_LOG("CaptureInterruptListener OnInterrupt, type:%d, hint:%d", type, hint);
+        MEDIA_INFO_LOG("AudioCaptureInterruptListener OnInterrupt, type:%d, hint:%d", type, hint);
 
         if (type == INTERRUPT_TYPE_BEGIN && hint == INTERRUPT_HINT_PAUSE) {
             MEDIA_INFO_LOG("OnInterrupt pause not supported");
@@ -181,8 +179,9 @@ public:
 static AudioSourceInput g_audioSourceProcessInput;
 static AudioManager& g_amInstance = AudioManager::GetInstance();
 static TestSample g_sample;
-static std::shared_ptr<CaptureInterruptListener> g_captureInterruptListener;
+static std::shared_ptr<AudioCaptureInterruptListener> g_audioCaptureInterruptListener;
 
+#ifdef AUDIO_OGG_SUPPORT
 static void MediaMemFree(void **src)
 {
     if (src == nullptr || *src == nullptr) {
@@ -212,15 +211,20 @@ static void *MediaMemCalloc(const size_t bytesNum)
 
 static int32_t AudioCapturerOggHeaderInit(SampleAudioCapturerInfo &info)
 {
+    const char *idHeader = "OpusHead";
+    const char *commentHeader = "OpusTags";
+    const char *vendor = "libogg-1.3.5";
+    uint32_t vendorLen = strlen(vendor);
+    uint32_t preSkip = g_oggCtx.sampleRate * OPUS_DELAY_TIME_DIVISOR / OPUS_DELAY_TIME_DIVIDED;
     g_oggCtx.idHeader = static_cast<unsigned char*>(MediaMemCalloc(OPUS_ID_HEADER_LEN));
-    CHK_NULL_RETURN(g_oggCtx.idHeader, "malloc failed!");
-    if (memcpy_s(g_oggCtx.idHeader, HEADER_STRLEN, "OpusHead", HEADER_STRLEN) != 0) {
-        MEDIA_ERR_LOG("memcpy failed!");
-        return MEDIA_ERR;
-    }  
+    uint32_t commentHeaderResLen = OPUS_COMMENT_HEADER_LEN - OPUS_OPUSTAGS_LEN;
+    CHK_NULL_RETURN(g_oggCtx.idHeader, "ogg idHeader malloc failed!");
+    if (memcpy_s(g_oggCtx.idHeader, OPUS_ID_HEADER_LEN, idHeader, strlen(idHeader)) != 0) {
+        MEDIA_ERR_LOG("ogg idHeader memcpy failed!");
+        goto FREE_ID_HEADER;
+    }
     g_oggCtx.idHeader[0x8] = 0x01;
     g_oggCtx.idHeader[0x9] = info.channelCount;
-    uint32_t preSkip = g_oggCtx.sampleRate * OPUS_DELAY_TIME_DIVISOR / OPUS_DELAY_TIME_DIVIDED;
     g_oggCtx.idHeader[0xA] = preSkip & 0xFF;
     g_oggCtx.idHeader[0xB] = (preSkip >> 0x8); // 8 for Little-endian byte order
     g_oggCtx.idHeader[0xC] = g_oggCtx.sampleRate & 0xFF;
@@ -229,23 +233,29 @@ static int32_t AudioCapturerOggHeaderInit(SampleAudioCapturerInfo &info)
     g_oggCtx.idHeader[0xF] = (g_oggCtx.sampleRate >> 0x18) & 0xFF; // 24 for Little-endian byte order
 
     g_oggCtx.commentHeader = static_cast<unsigned char*>(MediaMemCalloc(OPUS_COMMENT_HEADER_LEN));
-    CHK_NULL_RETURN(g_oggCtx.commentHeader, "malloc failed!");
-    if (memcpy_s(g_oggCtx.commentHeader, HEADER_STRLEN, "OpusTags", HEADER_STRLEN) != 0) {
-        MEDIA_ERR_LOG("Opus idHeader memcpy failed!");
-        return MEDIA_ERR;
+    if (g_oggCtx.commentHeader == nullptr) {
+        MEDIA_ERR_LOG("ogg commentHeader malloc failed!");
+        goto FREE_ID_HEADER;
+    }
+    if (memcpy_s(g_oggCtx.commentHeader, OPUS_COMMENT_HEADER_LEN, commentHeader, strlen(commentHeader)) != 0) {
+        MEDIA_ERR_LOG("ogg commentHeader memcpy failed!");
+        goto FREE_COMMENT_HEADER;
     }
-    const char *vendor = "libogg-1.3.5";
-    uint32_t vendorLen = std::strlen(vendor);
     g_oggCtx.commentHeader[0x8] = vendorLen & 0xFF;
     g_oggCtx.commentHeader[0x9] = (vendorLen >> 0x8) & 0xFF; // 8 for Little-endian byte order
     g_oggCtx.commentHeader[0xA] = (vendorLen >> 0x10) & 0xFF; // 16 for Little-endian byte order
     g_oggCtx.commentHeader[0xB] = (vendorLen >> 0x18) & 0xFF; // 24 for Little-endian byte order
 
-    if (memcpy_s(g_oggCtx.commentHeader + OPUS_OPUSTAGS_LEN, vendorLen, vendor, vendorLen) != 0) {
-        MEDIA_ERR_LOG("Opus commentHeader memcpy failed!");
-        return MEDIA_ERR;
+    if (memcpy_s(g_oggCtx.commentHeader + OPUS_OPUSTAGS_LEN, commentHeaderResLen, vendor, strlen(vendor)) != 0) {
+        MEDIA_ERR_LOG("ogg vendor memcpy failed!");
+        goto FREE_COMMENT_HEADER;
     }
     return MEDIA_OK;
+FREE_COMMENT_HEADER:
+    MediaMemFree((void **)&g_oggCtx.commentHeader);
+FREE_ID_HEADER:
+    MediaMemFree((void **)&g_oggCtx.idHeader);
+    return MEDIA_ERR;
 }
 
 static int32_t AudioCaptureOggStreamFlush(FILE *pfd)
@@ -265,39 +275,74 @@ static int32_t AudioCaptureOggStreamFlush(FILE *pfd)
     return MEDIA_OK;
 }
 
-static int32_t AudioCapturerOggCtxInit(FILE *pfd, SampleAudioCapturerInfo &info)
+static void AudioCapturerOggParamInit(SampleAudioCapturerInfo &info)
 {
-    g_oggCtx.packet = (ogg_packet *)MediaMemCalloc(sizeof(ogg_packet));
-    CHK_NULL_RETURN(g_oggCtx.packet, "malloc failed!");
-    g_oggCtx.page = (ogg_page *)MediaMemCalloc(sizeof(ogg_page));
-    CHK_NULL_RETURN(g_oggCtx.page, "malloc failed!");
     g_oggCtx.sampleRate = info.sampleRate;
     g_oggCtx.channels = info.channelCount;
-    g_oggCtx.granulepos = -1; // -1 means start page
+    g_oggCtx.granulepos = 0;
     g_oggCtx.packetCount = 0;
-    g_oggCtx.isEnd = false;
     g_oggCtx.serialno = 0x1; // unique serialno
-    CHK_OK_RETURN(ogg_stream_init(&g_oggCtx.oggStream, g_oggCtx.serialno), "ogg stream init failed");
-    CHK_OK_RETURN(AudioCapturerOggHeaderInit(info), "Header init failed!");
-    g_oggCtx.packet->packet = g_oggCtx.idHeader;
-    g_oggCtx.packet->bytes = OPUS_ID_HEADER_LEN;
-    g_oggCtx.packet->b_o_s = 1; // 1 means begining of ogg stream
-    g_oggCtx.packet->e_o_s = 0;
-    g_oggCtx.packet->granulepos = g_oggCtx.granulepos;
-    g_oggCtx.packetCount = g_oggCtx.packetCount;
-    g_oggCtx.packet->packetno = g_oggCtx.packetCount++;
-    g_oggCtx.granulepos = 0;
-    ogg_stream_packetin(&g_oggCtx.oggStream, g_oggCtx.packet);
-    CHK_OK_RETURN(AudioCaptureOggStreamFlush(pfd), "flush failed!");
-    g_oggCtx.packet->packet = g_oggCtx.commentHeader;
-    g_oggCtx.packet->bytes = OPUS_COMMENT_HEADER_LEN;
-    g_oggCtx.packet->b_o_s = 0;
+}
+
+static void AudioCapturerOggPacketIn(unsigned char *packet, int64_t bytes)
+{
+    g_oggCtx.packet->packet = packet;
+    g_oggCtx.packet->bytes = bytes;
+    g_oggCtx.packet->b_o_s = g_oggCtx.packetCount != 0 ? 0 : 1; // 1 means first page
     g_oggCtx.packet->e_o_s = 0;
-    g_oggCtx.packet->granulepos = 0;
+    g_oggCtx.packet->granulepos = g_oggCtx.packetCount != 0 ? g_oggCtx.granulepos : -1; // -1 means first page
     g_oggCtx.packet->packetno = g_oggCtx.packetCount++;
     ogg_stream_packetin(&g_oggCtx.oggStream, g_oggCtx.packet);
-    CHK_OK_RETURN(AudioCaptureOggStreamFlush(pfd), "flush failed!");
+}
+
+static int32_t AudioCapturerOggCtxInit(FILE *pfd, SampleAudioCapturerInfo &info)
+{
+    if (g_oggCtx.isInited) {
+        MEDIA_ERR_LOG("Ogg context has inited!");
+        goto EXIT;
+    }
+    g_oggCtx.packet = (ogg_packet *)MediaMemCalloc(sizeof(ogg_packet));
+    if (g_oggCtx.packet == nullptr) {
+        MEDIA_ERR_LOG("ogg context packet malloc failed!");
+        goto EXIT;
+    }
+    g_oggCtx.page = (ogg_page *)MediaMemCalloc(sizeof(ogg_page));
+    if (g_oggCtx.page == nullptr) {
+        MEDIA_ERR_LOG("ogg context page malloc failed!");
+        goto FREE_PACKET;
+    }
+    AudioCapturerOggParamInit(info);
+    if (ogg_stream_init(&g_oggCtx.oggStream, g_oggCtx.serialno) != MEDIA_OK) {
+        MEDIA_ERR_LOG("ogg stream init failed!");
+        goto FREE_PAGE;
+    }
+    if (AudioCapturerOggHeaderInit(info) != MEDIA_OK) {
+        MEDIA_ERR_LOG("Header init failed!");
+        goto STREAM_CLEAR;
+    }
+    AudioCapturerOggPacketIn(g_oggCtx.idHeader, OPUS_ID_HEADER_LEN);
+    if (AudioCaptureOggStreamFlush(pfd) != MEDIA_OK) {
+        MEDIA_ERR_LOG("ogg packet flush failed!");
+        goto HEADER_FREE;
+    }
+    AudioCapturerOggPacketIn(g_oggCtx.commentHeader, OPUS_COMMENT_HEADER_LEN);
+    if (AudioCaptureOggStreamFlush(pfd) != MEDIA_OK) {
+        MEDIA_ERR_LOG("ogg header flush failed!");
+        goto HEADER_FREE;
+    }
+    g_oggCtx.isInited = true;
     return MEDIA_OK;
+HEADER_FREE:
+    MediaMemFree((void **)&g_oggCtx.idHeader);
+    MediaMemFree((void **)&g_oggCtx.commentHeader);
+STREAM_CLEAR:
+    ogg_stream_clear(&g_oggCtx.oggStream);
+FREE_PAGE:
+    MediaMemFree((void **)&g_oggCtx.page);
+FREE_PACKET:
+    MediaMemFree((void **)&g_oggCtx.packet);
+EXIT:
+    return MEDIA_ERR;
 }
 
 static void AudioCapturerOggCtxDeInit()
@@ -311,29 +356,7 @@ static void AudioCapturerOggCtxDeInit()
     MediaMemFree((void **)&g_oggCtx.idHeader);
     MediaMemFree((void **)&g_oggCtx.commentHeader);
     ogg_stream_clear(&g_oggCtx.oggStream);
-}
-
-static void AudioCaptureStop()
-{
-    MediaMutexLock(g_sample.mutex);
-    if (!g_audioCap->Stop()) {
-        MEDIA_ERR_LOG("Stop failed");
-    }
-    if (!g_audioCap->Release()) {
-        MEDIA_ERR_LOG("Release failed");
-    }
-
-    delete g_audioSourceProcessInput.buffer;
-    g_audioSourceProcessInput.buffer = nullptr;
-
-    if (g_amInstance.DeactivateAudioInterrupt(g_sample.interrupt) != 0) {
-        MEDIA_ERR_LOG("deactivate audio interrupt failed");
-    }
-    g_audioCap.reset();
-    g_audioCap = nullptr;
-    g_audioSourceProcessInput.bThreadRun = false;
-    MediaMutexUnLock(g_sample.mutex);
-    (void)MediaMutexDestroy(&g_sample.mutex);
+    g_oggCtx.isInited = false;
 }
 
 static int32_t AudioCaptureWritePage(FILE *pfd)
@@ -353,25 +376,52 @@ static int32_t AudioCaptureWritePage(FILE *pfd)
     return MEDIA_OK;
 }
 
-static int32_t AudioCapturerWriteInOGG(uint8_t *buffer, int64_t bufferLen, FILE *pfd, bool isEos)
+static int32_t AudioCapturerWritePacket(uint8_t *buffer, int64_t bufferLen, FILE *pfd)
 {
     if (bufferLen < 0) {
         MEDIA_ERR_LOG("input buffer invalid");
         return MEDIA_ERR;
     }
-    g_oggCtx.packet->packet = (unsigned char *)(buffer + OPUS_ENCODE_HEADER_SIZE);
-    g_oggCtx.packet->bytes = bufferLen - OPUS_ENCODE_HEADER_SIZE;
+    AudioCapturerOggPacketIn((unsigned char *)(buffer), bufferLen);
+    g_oggCtx.granulepos += OPUS_SAMPLERATE * 10 / MILLSECOND_TO_SECOND; // capture frequency is 10ms for each frame
+    return AudioCaptureWritePage(pfd);
+}
+
+static int32_t AudioCapturerWriteEosPacket(FILE *pfd)
+{
+    unsigned char emptyData = 0;
+    g_oggCtx.packet->packet = &emptyData;
+    g_oggCtx.packet->bytes = 1;
     g_oggCtx.packet->b_o_s = 0;
-    g_oggCtx.packet->e_o_s = isEos ? 1 : 0;
+    g_oggCtx.packet->e_o_s = 1;
     g_oggCtx.packet->granulepos = g_oggCtx.granulepos;
-    g_oggCtx.packet->packetno = g_oggCtx.packetCount++;
-    g_oggCtx.granulepos += OPUS_SAMPLERATE * 10 / MILLSECOND_TO_SECOND; //capture frequency is 10ms for each frame
+    g_oggCtx.packet->packetno = g_oggCtx.packetCount;
     ogg_stream_packetin(&g_oggCtx.oggStream, g_oggCtx.packet);
-    if (!isEos) {
-        return AudioCaptureWritePage(pfd);
-    } else {
-        return AudioCaptureOggStreamFlush(pfd);
+    return AudioCaptureOggStreamFlush(pfd);
+}
+#endif
+
+static void AudioCaptureStop()
+{
+    MediaMutexLock(g_sample.mutex);
+    if (!g_audioCap->Stop()) {
+        MEDIA_ERR_LOG("Stop failed");
+    }
+    if (!g_audioCap->Release()) {
+        MEDIA_ERR_LOG("Release failed");
+    }
+
+    delete g_audioSourceProcessInput.buffer;
+    g_audioSourceProcessInput.buffer = nullptr;
+
+    if (g_amInstance.DeactivateAudioInterrupt(g_sample.interrupt) != 0) {
+        MEDIA_ERR_LOG("deactivate audio interrupt failed");
     }
+    g_audioCap.reset();
+    g_audioCap = nullptr;
+    g_audioSourceProcessInput.bThreadRun = false;
+    MediaMutexUnLock(g_sample.mutex);
+    (void)MediaMutexDestroy(&g_sample.mutex);
 }
 
 static void* AudioCaptureProcess(void* arg)
@@ -380,52 +430,61 @@ static void* AudioCaptureProcess(void* arg)
     int32_t readCnt = 0;
     Timestamp timeStamp;
     g_audioSourceProcessInput.bThreadRun = true;
-    bool isEos = false;
     while (true) {
+        if (g_sample.needStop || g_interruptHintStop || readCnt > READ_COUNT_MAX) {
+            MEDIA_INFO_LOG("quit AudioCapturer Process");
+            break;
+        }
         int32_t ret = g_audioCap->Read(g_audioSourceProcessInput.buffer, g_audioSourceProcessInput.framesize, false);
         if (ret <= 0) {
-               if (ret == ERR_RETRY_READ) {
-                   usleep(READ_RETRY_TIME_US);
-                   continue;
-               }
-               usleep(READ_RETRY_TIME_US);
-            MEDIA_DEBUG_LOG("audioCap Read failed:0x%x", ret);
+            if (ret == ERR_RETRY_READ) {
+                usleep(READ_RETRY_TIME_US);
+                continue;
+            }
+            MEDIA_DEBUG_LOG("audioCap Read failed ret %x", ret);
+            usleep(READ_RETRY_TIME_US);
             continue;
         }
-
-        if (g_sample.needStop || g_interruptHintStop || readCnt++ > READ_COUNT_MAX ) {
-            isEos = true;
-        }
-
+        readCnt++;
+        bool hasWrite = false;
         if (g_audioSourceProcessInput.audioFormat == OPUS) {
-            if(AudioCapturerWriteInOGG(g_audioSourceProcessInput.buffer, ret, pfd, isEos) != MEDIA_OK) {
+#ifdef AUDIO_OGG_SUPPORT
+            if (AudioCapturerWritePacket(g_audioSourceProcessInput.buffer, ret, pfd) != MEDIA_OK) {
                 MEDIA_ERR_LOG("Write file failed!");
                 break;
-            }    
-        } else {
+            }
+            hasWrite = true;
+#endif
+        } 
+        if (!hasWrite) {
             int32_t writeLen = fwrite(g_audioSourceProcessInput.buffer, 1, ret, pfd);
             if (writeLen != ret) {
                 MEDIA_ERR_LOG("errno:%d, errmsg:%s", errno, strerror(errno));
                 break;
             }
         }
-        if (isEos) {
-            MEDIA_ERR_LOG("quit capture process");
-            break;
-        }
         if (readCnt % GET_AUDIO_TIME_INTERVAL_TIMES == 0) {
             if (g_audioCap->GetAudioTime(timeStamp, Timestamp::Timebase::MONOTONIC)) {
                 MEDIA_INFO_LOG("read %d frames timestamp seconds:%ld, nanoseconds:%ld",
                     readCnt, timeStamp.time.tv_sec, timeStamp.time.tv_nsec);
             }
         }
-        // MEDIA_INFO_LOG("audioCap Read readCnt = %d, size = %d", readCnt, ret);
+        MEDIA_DEBUG_LOG("audioCap Read readCnt = %d, size = %d", readCnt, ret);
     }
+#ifdef AUDIO_OGG_SUPPORT
     if (g_audioSourceProcessInput.audioFormat == OPUS) {
+        if (AudioCapturerWriteEosPacket(pfd) != MEDIA_OK) {
+            MEDIA_INFO_LOG("ogg write eos failed!");
+        }
         AudioCapturerOggCtxDeInit();
     }
+#endif
     fclose(pfd);
     AudioCaptureStop();
+    if (!g_sample.needStop) {
+        MediaThreadSetDetach(g_sample.audioCaptureProcess, true);
+               g_sample.audioCaptureProcess = nullptr;
+    }
     MEDIA_INFO_LOG("AudioCaptureProcess end");
     return nullptr;
 }
@@ -475,6 +534,8 @@ static int32_t HandleAudioCaptureCmd(int32_t argc, const char **argv)
         if ((strncmp(g_sample.control, "stop", strlen("stop")) == 0)) {
             if (g_audioSourceProcessInput.bThreadRun) {
                 g_sample.needStop = true;
+                MediaThreadJoin(&g_sample.audioCaptureProcess);
+                g_audioSourceProcessInput.bThreadRun = false;
                 MEDIA_INFO_LOG("set g_sample.needStop:%d", g_sample.needStop);
             } else {
                 MEDIA_INFO_LOG("bThreadRun:%d no need stop", g_audioSourceProcessInput.bThreadRun);
@@ -541,7 +602,7 @@ static int32_t AudioCaptureSetInfo(SampleAudioCapturerInfo audioCapturerInfo)
     }
     MEDIA_INFO_LOG("GetFrameCount:%d", frameCount);
     g_audioSourceProcessInput.audioFormat = info.audioFormat;
-    g_audioSourceProcessInput.framesize = frameCount * info.channelCount;
+    g_audioSourceProcessInput.framesize = frameCount * info.channelCount * info.bitWidth / BYTE_SIZE;
     g_audioSourceProcessInput.buffer = new uint8_t[g_audioSourceProcessInput.framesize];
     if (g_audioSourceProcessInput.buffer == nullptr) {
         (void)g_audioCap->Release();
@@ -567,9 +628,8 @@ static int32_t ActivateAudioInterrupt(AudioSession &sessionId)
         return -1;
     }
     MEDIA_INFO_LOG("sessionId:%d", sessionId);
-    g_captureInterruptListener = std::make_shared<CaptureInterruptListener>();
-    g_sample.interrupt = { AUDIO_STREAM_VOICE_RECORD, sessionId, g_captureInterruptListener };
-    
+    g_audioCaptureInterruptListener = std::make_shared<AudioCaptureInterruptListener>();
+    g_sample.interrupt = { AUDIO_STREAM_VOICE_RECORD, sessionId, g_audioCaptureInterruptListener };
 
     if (g_amInstance.ActivateAudioInterrupt(g_sample.interrupt) == INTERRUPT_FAILED) {
         MEDIA_ERR_LOG("ActivateAudioInterrupt failed");
@@ -599,6 +659,7 @@ int32_t AudioCaptureSample(int32_t argc, const char **argv)
     g_sample.needStop = false;
     g_interruptHintStop = false;
     g_sample.mutex = MediaMutexCreate(nullptr);
+    g_audioSourceProcessInput.bThreadRun = true;
     if (g_sample.mutex == nullptr) {
         MEDIA_ERR_LOG("create mutex failed");
         g_audioSourceProcessInput.bThreadRun = false;
@@ -607,7 +668,7 @@ int32_t AudioCaptureSample(int32_t argc, const char **argv)
     SampleAudioCapturerInfo audioCapturerInfo = {};
     AudioSession sessionId = AUDIO_SESSION_ID_NONE;
     FILE *pfd = nullptr;
-    MediaThreadattr attr = { "AudioCaptureTask", 0x2000, THREAD_SCHED_INVALID, 0, true };
+    MediaThreadattr attr = {"AudioCaptureTask", 0x2000, THREAD_SCHED_INVALID, 0, false};
     int32_t ret = CheckInputParam(argc, argv);
     if (ret != 0) {
         goto EXIT;
@@ -627,7 +688,7 @@ int32_t AudioCaptureSample(int32_t argc, const char **argv)
         goto EXIT;
     }
     pfd = fopen(filePath.c_str(), "w+");
-    if (pfd == NULL) {
+    if (pfd == nullptr) {
         MEDIA_ERR_LOG("open file failed");
         g_audioCap.reset();
         (void)g_amInstance.DeactivateAudioInterrupt(g_sample.interrupt);
@@ -641,16 +702,21 @@ int32_t AudioCaptureSample(int32_t argc, const char **argv)
         MEDIA_ERR_LOG("AudioCapture set failed");
         goto FCLOSE_EXIT;
     }
+#ifdef AUDIO_OGG_SUPPORT
     if (audioCapturerInfo.audioFormat == OPUS) {
         ret = AudioCapturerOggCtxInit(pfd, audioCapturerInfo);
-        if (ret != 0) {
+        if (ret != MEDIA_OK) {
             MEDIA_ERR_LOG("OggCtx init failed");
             goto FCLOSE_EXIT;
         }
     }
+#endif
     g_sample.audioCaptureProcess = MediaThreadCreate(AudioCaptureProcess, pfd, &attr);
     if (g_sample.audioCaptureProcess == nullptr) {
         MEDIA_ERR_LOG("thread create failed");
+#ifdef AUDIO_OGG_SUPPORT
+        AudioCapturerOggCtxDeInit();
+#endif
         goto FCLOSE_EXIT;
     }
     return 0;
@@ -670,6 +736,7 @@ EXIT:
 #include "bleService.h"
 static uint32_t AI_audio_size=0;
 static uint8_t Cur_AI_Model= 0;
+static uint32_t g_ai_record_thread_handle = 0; /* AI录音线程句柄(自定义线程API创建) */
 static void* AudioCaptureProcess_AI(void* arg)
 {
     #if AI_RECORD_TEST
index dedc718..b944053 100644 (file)
@@ -45,6 +45,8 @@ extern "C" {
 #define SEA_BUFFER_SIZE        (VQE_PARAM_SIZE + VQE_PREFIX_LEN)
 #define AEF_BUFFER_SIZE        (PEQ_PARAM_SIZE + PEQ_PREFIX_LEN)
 #define AEF_BUFFER_LEN         256
+#define SEC_TO_US            1000000
+#define US_TO_NS             1000
 
 static AudioManager& g_amInstance = AudioManager::GetInstance();
 static std::shared_ptr<AudioStreamIn> g_streamIn = nullptr;
@@ -77,7 +79,6 @@ public:
 
     void OnInterrupt(int32_t type, int32_t hint) override
     {
-        printf("OnInterrupt xxxxxxxxxxxxxxxxxxxxxxxxxx\r\n");
         ALOGI("type:%d hint:%d", type, hint);
     }
 };
@@ -215,12 +216,28 @@ int32_t AudioStreamInObtainBuffer(uint8_t *data, uint32_t *size)
     buffer.size = *size;
     int32_t ret = g_streamIn->ObtainBuffer(buffer, false);
     if (ret < 0) {
-        return AUDIO_ERROR;
+        return ret;
     }
     *size = static_cast<uint32_t>(ret);
     return AUDIO_SUCCESS;
 }
 
+int32_t AudioStreamInGetPosition(int64_t *pos)
+{
+    if (pos == NULL) {
+        ALOGE("pos is NULL!");
+        return AUDIO_ERROR;
+    }
+    struct timespec timestamp = {};
+    int32_t ret = g_streamIn->GetTimestamp(timestamp, ::Audio::Timebase::MONOTONIC);
+    if (ret != AUDIO_SUCCESS) {
+        ALOGE("streamIn_::GetTimestamp failed:0x%x", ret);
+        return AUDIO_ERROR;
+    }
+    *pos = timestamp.tv_sec *SEC_TO_US + timestamp.tv_nsec / US_TO_NS;
+    return AUDIO_SUCCESS;
+}
+
 int32_t AudioStreamInSetBitRate(uint32_t bitrate)
 {
     std::string str("setbitrate = " + std::to_string(bitrate));
@@ -277,33 +294,17 @@ int32_t AudioStreamOutInit(AudioRendererConfig renderConfig)
     ALOGD("success");
     return AUDIO_SUCCESS;
 }
-// int32_t GetTimestamp(struct timespec &timeStamp) const;
-
-int32_t AudioStreamGetTimestamp(struct timespec *timeStamp)
-{
-    g_streamOut->GetTimestamp(*timeStamp);
-    return AUDIO_SUCCESS;
-}
-
-
 
 int32_t AudioStreamOutSetMute(bool mute)
 {
-    if(g_streamOut)
-    {
-        int32_t ret = g_streamOut->SetMute(mute);
-        if (ret != AUDIO_SUCCESS) {
-            ALOGE("audio stream out set mute failed 0x%x", ret);
-            return AUDIO_ERROR;
-        }
-        
-
-        ALOGD("success");
-        return AUDIO_SUCCESS;
+    int32_t ret = g_streamOut->SetMute(mute);
+    if (ret != AUDIO_SUCCESS) {
+        ALOGE("audio stream out set mute failed 0x%x", ret);
+        return AUDIO_ERROR;
     }
-    ALOGD("g_streamOut is null");
-    return AUDIO_ERROR;
-  
+
+    ALOGD("success");
+    return AUDIO_SUCCESS;
 }
 
 int32_t AudioManagerSetSeaEnable(bool enable)
@@ -554,7 +555,7 @@ int32_t AudioManagerSetSeaParam(const uint8_t *seaParam, uint16_t len)
         free(seaBuf);
         return AUDIO_ERROR;
     }
-    int32_t ret = g_amInstance.SetParam(AUDIO_UP_LINK, seaBuf, BUFFER_SIZE);
+    int32_t ret = g_amInstance.SetParam(AUDIO_UP_LINK, seaBuf, AEF_BUFFER_LEN);
     if (ret != AUDIO_SUCCESS) {
         ALOGE("set param failed");
         free(seaBuf);
index 19344ad..61663d8 100644 (file)
@@ -43,6 +43,8 @@ int32_t AudioStreamInStart(void);
 
 int32_t AudioStreamInObtainBuffer(uint8_t *data, uint32_t *size);
 
+int32_t AudioStreamInGetPosition(int64_t *pos);
+
 int32_t AudioStreamInSetBitRate(uint32_t bitrate);
 
 int32_t AudioStreamInStop(void);
@@ -63,8 +65,6 @@ int32_t AudioStreamOutDeinit(void);
 
 int32_t AudioStreamOutFlush(void);
 
-int32_t AudioStreamGetTimestamp(struct timespec *timeStamp);
-
 /**
  * @brief Sets audio effect algorithm parameters.
  *
index 05e3693..cf20cdb 100644 (file)
@@ -86,6 +86,7 @@ public:
     std::string GetCurrentPlaySource(void);\r
     int32_t GetDuration(int64_t &durationMs);\r
     void GetAlbumInfo(AudioPlayerAlbumInfo &albumInfo, const char *src);\r
+    bool HasM3U8(const std::string& str);\r
 protected:\r
     void OnPlaybackComplete() override;\r
     void OnError(int32_t errorType, int32_t errorCode) override;\r
diff --git a/code/sdk/middleware/services/media/foundation/sample/wrapper/audio_recorder_sample.cpp b/code/sdk/middleware/services/media/foundation/sample/wrapper/audio_recorder_sample.cpp
new file mode 100644 (file)
index 0000000..b4fb73b
--- /dev/null
@@ -0,0 +1,554 @@
+/*
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: audio recorder sample
+* Author: Media Software Group
+* Create: 2024-07-30
+*/
+
+#include "audio_recorder_sample.h"
+#include <stdio.h>\r
+#include <string.h>\r
+#include <string>\r
+#include <iostream>\r
+#include <strings.h>\r
+#include <climits>\r
+#include <stdlib.h>\r
+#include <unistd.h>\r
+#include <sys/select.h>\r
+#include <sys/time.h>\r
+#include <sys/types.h>\r
+#include <sys/stat.h>\r
+#include <fcntl.h>
+#include "securec.h"
+#include "audio_manager.h"
+#include "media_log.h"
+#include "media_thread_adapt.h"
+#ifdef SUPPORT_AUDIO_RECORDER
+#include "audio_recorder.h"\r
+#endif\r
+
+#ifdef __cplusplus
+extern "C" {
+#endif\r
+#ifdef SUPPORT_AUDIO_RECORDER\r
+using namespace::Audio;\r
+using Audio::AudioManager;
+const uint64_t RECORDER_CONTROL_CMD_LEN = 30;
+const uint64_t MEDIA_PATH_MAX = 260;
+const uint64_t PER_FILE_STORAGE_MAX_DURATION = 60;
+const uint64_t DEFAULTE_MAX_STORAGE_THEARHOLD = 90;
+const uint64_t PER_FILE_STORAGE_MAX_SIZE = 2ULL * 1024 * 1024 * 1024;
+static AudioManager &g_amInstance = AudioManager::GetInstance();
+
+#define TEST_SAMPLE_RETURN_VAL_IF_NULL(condition)                                           \
+    do {                                                                               \
+        if ((condition) == nullptr) {                                                  \
+            MEDIA_ERR_LOG("" #condition " is nullptr error");    \
+            return -1;                                                         \
+        }                                                                              \
+    } while (0)
+
+typedef struct {
+    char outDir[MEDIA_PATH_MAX];
+    AudioSourceType inputSource;
+    AudioCodecFormat audioFormat;
+    int32_t sampleRate;
+    int32_t channelCount;
+    AudioStreamType streamType;
+    AudioBitWidth bitWidth;
+    AudioSession sessionID;
+    RecorderCallback callback;
+    void *cookie;
+    uint32_t splitFileDuration;
+    uint64_t splitFileSize;
+    bool enableOverwriteFiles;
+    uint32_t storageWarningThresholdPercent;
+} AudioRecordInfo;
+
+typedef struct TagTestSample {
+    char    filePath[MEDIA_PATH_MAX];
+    char control[RECORDER_CONTROL_CMD_LEN];
+    bool needStop;
+    AudioRecorderHandle recorderHandle;
+    AudioInterrupt interrupt;
+    MediaThreadIdHandle audioRecordProcess;
+    AudioRecordInfo audioRecordInfo;
+    bool isRecording;
+    MediaMutexHandle mutex;
+    MediaThreadCondHandle cond;
+    uint32_t splitFileDuration;
+    uint64_t splitFileSize;
+    bool enableOverwriteFiles;
+    uint32_t storageWarningThresholdPercent;
+} TestSample;
+
+typedef int32_t (*InvokeFunc)(int32_t argc, const char *argv[]);
+
+typedef struct {
+    const char *cmdName;
+    InvokeFunc invoke;
+} RecordTestInvoke;
+
+static bool g_interruptHintStop = false;
+static TestSample g_sample = {
+    .splitFileDuration = PER_FILE_STORAGE_MAX_DURATION,
+    .splitFileSize = PER_FILE_STORAGE_MAX_SIZE,
+    .enableOverwriteFiles = false,
+    .storageWarningThresholdPercent = DEFAULTE_MAX_STORAGE_THEARHOLD,
+};
+
+struct NameAudioFormat {
+    std::string name;
+    AudioCodecFormat audioFormat;
+};
+
+static NameAudioFormat g_audioCodecFormat[] = {
+    {"mp3", MP3},
+    {"opus", OPUS},
+    {"pcm", PCM},
+    {"silk", SILK},
+};
+
+class AudioRecorderInterruptListener : public InterruptListener {
+    public:
+    AudioRecorderInterruptListener() {};
+    ~AudioRecorderInterruptListener() override {};
+
+    void OnInterrupt(int32_t type, int32_t hint) override
+    {
+        MEDIA_INFO_LOG("AudioRecorderInterruptListener OnInterrupt, type:%d, hint:%d", type, hint);
+
+        if (type == INTERRUPT_TYPE_BEGIN && hint == INTERRUPT_HINT_PAUSE) {
+            MEDIA_INFO_LOG("OnInterrupt pause not supported");
+        }
+        if (type == INTERRUPT_TYPE_END && hint == INTERRUPT_HINT_RESUME) {
+            MEDIA_INFO_LOG("OnInterrupt resume not supported");
+        }
+        if (type == INTERRUPT_TYPE_BEGIN && hint == INTERRUPT_HINT_STOP) {
+            g_interruptHintStop = true;
+        }
+        if (type == INTERRUPT_TYPE_END && hint == INTERRUPT_HINT_STOP) {
+            MEDIA_INFO_LOG("OnInterrupt stop not supported");
+        }
+    }
+};
+
+static void AudioCaptureGetFormat(const char **argv, AudioCodecFormat &audioFormat)
+{
+    std::string inputFormat = std::string(argv[0x1]);
+    for (size_t i = 0; i < (sizeof(g_audioCodecFormat) / sizeof(g_audioCodecFormat[0])); i++) {
+        if (inputFormat == g_audioCodecFormat[i].name) {
+            audioFormat = g_audioCodecFormat[i].audioFormat;
+            MEDIA_INFO_LOG("[AudioCaptureSample] set audioFormat %s", g_audioCodecFormat[i].name.c_str());
+        }
+    }
+}
+
+static int32_t AudioRecordGetInfo(const char **argv, AudioRecordInfo *audioRecordInfo)
+{
+    AudioCaptureGetFormat(argv, audioRecordInfo->audioFormat);
+    audioRecordInfo->sampleRate = atoi(argv[0x2]); /* 2: samplerate */
+    MEDIA_INFO_LOG("set capture parameter sampleRate:%d", audioRecordInfo->sampleRate);
+    audioRecordInfo->channelCount = atoi(argv[0x3]); /* 3: channel */
+    MEDIA_INFO_LOG("set capture parameter channel:%d", audioRecordInfo->channelCount);
+    audioRecordInfo->bitWidth = (AudioBitWidth)atoi(argv[0x4]); /* 4: bitWidth */
+    MEDIA_INFO_LOG("set capture parameter bitWidth:%d", audioRecordInfo->bitWidth);
+    MEDIA_INFO_LOG("input argv[5]:%s.", argv[0x5]); /* 5: filePath set argv[3] */
+    if (strlen(argv[0x5]) >= MEDIA_PATH_MAX) {
+        MEDIA_ERR_LOG("input path too long");
+        return MEDIA_ERR;
+    }
+    if (memcpy_s(audioRecordInfo->outDir, MEDIA_PATH_MAX, argv[0x5], strlen(argv[0x5]) + 1) != EOK) {
+        MEDIA_ERR_LOG("memcpy_s failed");
+        return MEDIA_ERR;
+    }
+    return MEDIA_OK;
+}
+
+static void AudioRecordEeventHandle(uint32_t enEvent, const void *data, const void *cookie)
+{
+    MEDIA_UNUSED(data);
+    TestSample *sample = (TestSample *)cookie;
+    if (enEvent == AUDIO_RECORD_STORAGE_REACHE_MAX_VALUE ||
+        enEvent == AUDIO_RECORD_EVENT_ERROR) {
+        MediaMutexLock(sample->mutex);
+        sample->isRecording = false;
+        MediaMutexUnLock(sample->mutex);
+        MediaThreadCondSignal(sample->cond);
+    } else {
+        MEDIA_ERR_LOG("not support envent type!");
+    }
+}
+
+static int32_t ActivateAudioInterrupt(TestSample *sample, AudioSession *sessionId)
+{
+    bool init = g_amInstance.Initialize();\r
+    if (!init) {\r
+        MEDIA_ERR_LOG("audiomanager init failed");\r
+        return MEDIA_ERR;\r
+    }\r
+    *sessionId = g_amInstance.MakeSessionId();\r
+    if (*sessionId == AUDIO_SESSION_ID_NONE) {\r
+        MEDIA_ERR_LOG("AUDIO_SESSION_ID_NONE");\r
+        return MEDIA_ERR;\r
+    }
+    sample->mutex = MediaMutexCreate(nullptr);
+    if (sample->mutex == nullptr) {
+        MEDIA_ERR_LOG("create mutex failed");
+        return MEDIA_ERR;
+    }
+    sample->cond = MediaThreadCondCreate();
+    if (sample->cond == nullptr) {
+        MEDIA_ERR_LOG("create cond failed");
+        (void)MediaMutexDestroy(&sample->mutex);
+        return MEDIA_ERR;
+    }
+    std::shared_ptr<AudioRecorderInterruptListener> recorderInterruptListener =\r
+        std::make_shared<AudioRecorderInterruptListener>();\r
+    sample->interrupt = { AUDIO_STREAM_VOICE_RECORD, *sessionId, recorderInterruptListener };\r
+    int32_t ret = g_amInstance.ActivateAudioInterrupt(sample->interrupt);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("ActivateAudioInterrupt failed");
+        (void)MediaMutexDestroy(&sample->mutex);
+        (void)MediaThreadCondDestroy(&sample->cond);
+        return MEDIA_ERR;
+    }
+    return MEDIA_OK;
+}
+
+static int32_t CheckInputParam(int32_t argc)
+{
+    if (argc < 0x5) {
+        MEDIA_ERR_LOG("argc:%d is invalid, must be 5 parameters", argc);
+        return -1;
+    }
+    return 0;
+}
+
+static void ConvertRecordInfo(CapturerInputConfig *current, const AudioRecordInfo *src)
+{
+    current->audioFormat = src->audioFormat;
+    current->sampleRate = src->sampleRate;
+    current->channelCount = src->channelCount;
+    current->streamType = src->streamType;
+    current->bitWidth = src->bitWidth;
+    current->sessionID = src->sessionID;
+    current->linkDir = AUDIO_UP_LINK;
+}
+
+static errcode_t AudioRecorderAllPrepare(AudioRecorderHandle handle, const AudioRecordInfo *recordInfo)
+{
+    errcode_t ret = AudioRecorderPrepare(handle);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("audio recorder prepare failed!");
+        return ret;
+    }
+    ret = AudioRecorderEnableOverwriteFiles(handle, recordInfo->enableOverwriteFiles);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("audio recorder enable over write files failed!");
+        return ret;
+    }
+    ret = AudioRecorderSetStorageWarningThreshold(handle, recordInfo->storageWarningThresholdPercent);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("audio recorder set storage warning threshold failed!");
+        return ret;
+    }
+    ret = AudioRecorderSetMaxDuration(handle, recordInfo->splitFileDuration);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("audio recorder set max duration failed!");
+        return ret;
+    }
+    ret = AudioRecorderSetMaxFileSize(handle, recordInfo->splitFileSize);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("audio recorder set max file size failed!");
+        return ret;
+    }
+    return ret;
+}
+
+static errcode_t AudioRecorderServiceStart(AudioRecorderHandle *handle, const AudioRecordInfo *recordInfo)
+{
+    if (recordInfo == nullptr) {
+        MEDIA_ERR_LOG("recordInfo is nullptr!");
+        return MEDIA_ERR;
+    }
+    CapturerInputConfig capturerInfo = {};
+    ConvertRecordInfo(&capturerInfo, recordInfo);
+    errcode_t ret = AudioRecorderCreate(handle);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("AudioRecorderCreate failed!");
+        return MEDIA_ERR;
+    }
+    ret = AudioRecorderSetInfo(*handle, &capturerInfo);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("audio recorder set info failed!");
+        goto EXIT;
+    }
+    ret = AudioRecorderSetOutputPath(*handle, recordInfo->outDir, strlen(recordInfo->outDir) + 1);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("audio recorder set output path failed!");
+        goto EXIT;
+    }
+    ret = AudioRecorderAllPrepare(*handle, recordInfo);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("audio recorder all prepare failed!");
+        goto EXIT;
+    }
+    ret = AudioRecorderSetCallback(*handle, recordInfo->callback, recordInfo->cookie);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("audio recorder set max call back failed!");
+        goto EXIT;
+    }
+    ret = AudioRecorderStart(*handle);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("audio recorder set max start failed!");
+        goto EXIT;
+    }
+    return MEDIA_OK;
+EXIT:
+    AudioRecorderDestroy(*handle);
+    return MEDIA_ERR;
+}
+
+static errcode_t AudioRecorderServiceStop(const AudioRecorderHandle handle)
+{
+    errcode_t ret = AudioRecorderStop(handle);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("audio recorder stop failed!");
+    }
+    ret = AudioRecorderDestroy(handle);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("audio recorder destroy failed!");
+    }
+    return ret;
+}
+
+static void *AudioRecordProcess(void *arg)
+{
+    TestSample *sample = (TestSample *)arg;
+    AudioSession sessionId = AUDIO_SESSION_ID_NONE;
+    int32_t ret = ActivateAudioInterrupt(sample, &sessionId);
+    if (ret != MEDIA_OK) {
+        return nullptr;
+    }
+    sample->audioRecordInfo.sessionID = sessionId;
+    sample->audioRecordInfo.inputSource = AUDIO_MIC;
+    sample->audioRecordInfo.streamType = AUDIO_STREAM_VOICE_RECORD;
+    sample->audioRecordInfo.callback = AudioRecordEeventHandle;
+    sample->audioRecordInfo.cookie = sample;
+    sample->audioRecordInfo.splitFileDuration = sample->splitFileDuration;
+    sample->audioRecordInfo.splitFileSize = sample->splitFileSize;
+    sample->audioRecordInfo.enableOverwriteFiles = sample->enableOverwriteFiles;
+    sample->audioRecordInfo.storageWarningThresholdPercent = sample->storageWarningThresholdPercent;
+    ret = AudioRecorderServiceStart(&sample->recorderHandle, &sample->audioRecordInfo);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("AudioRecordStart failed!");
+        goto EXIT;
+    }
+    while (true) {
+        MediaMutexLock(sample->mutex);
+        if (!sample->isRecording) {
+            MediaMutexUnLock(sample->mutex);
+            break;
+        }
+        MediaThreadCondWait(sample->cond, sample->mutex);
+        MediaMutexUnLock(sample->mutex);
+    }
+    AudioRecorderServiceStop(sample->recorderHandle);
+EXIT:
+    MediaMutexDestroy(&sample->mutex);
+    MediaThreadCondDestroy(&sample->cond);
+    g_sample.isRecording = false;
+    (void)g_amInstance.DeactivateAudioInterrupt(sample->interrupt);
+    MEDIA_INFO_LOG("AudioRecord exit success!");
+    return nullptr;
+}
+
+int32_t SampleAudioRecorderStart(int32_t argc, const char **argv)
+{
+    int32_t ret = CheckInputParam(argc);
+    if (ret != MEDIA_OK) {
+        return ret;
+    }
+    if (g_sample.isRecording) {
+        MEDIA_INFO_LOG("audio capture is running, please input control cmd");
+        return MEDIA_ERR;
+    }
+    MediaThreadattr attr = { "AudioRecordTask", 0x1000, THREAD_SCHED_INVALID, 0, false };
+    g_sample.isRecording = true;
+    if (memset_s(g_sample.filePath, MEDIA_PATH_MAX, 0, MEDIA_PATH_MAX) != EOK) {
+        MEDIA_ERR_LOG("memset_s failed");
+        goto EXIT;
+    }
+    ret = AudioRecordGetInfo(argv, &g_sample.audioRecordInfo);
+    if (ret != MEDIA_OK) {
+        goto EXIT;
+    }
+    g_sample.audioRecordProcess = MediaThreadCreate(AudioRecordProcess, &g_sample, &attr);
+    if (g_sample.audioRecordProcess == nullptr) {
+        MEDIA_ERR_LOG("thread create failed");
+        goto EXIT;
+    }
+    return MEDIA_OK;
+EXIT:
+    g_sample.isRecording = false;
+    return MEDIA_ERR;
+}
+
+int32_t SampleAudioRecorderStop(int32_t argc, const char **argv)
+{
+    MEDIA_UNUSED(argc);
+    MEDIA_UNUSED(argv);
+    MediaMutexLock(g_sample.mutex);
+    if (!g_sample.isRecording) {
+        MEDIA_INFO_LOG("audio record has been stoped, not need to stop!");
+        MediaMutexUnLock(g_sample.mutex);
+        return MEDIA_OK;
+    }
+    g_sample.isRecording = false;
+    MediaThreadCondSignal(g_sample.cond);
+    MediaMutexUnLock(g_sample.mutex);
+    MediaThreadJoin(&g_sample.audioRecordProcess);
+    g_sample.audioRecordProcess = nullptr;
+    MEDIA_INFO_LOG("stop command excute success");
+    MediaMutexUnLock(g_sample.mutex);
+    return MEDIA_OK;
+}
+
+int32_t SampleSetDeleteFileEnable(int32_t argc, const char **argv)
+{
+    if (argc < 2) {\r
+        MEDIA_ERR_LOG("argc:%d is invalid, must be 2 parameters", argc);
+        return MEDIA_INVALID_PARAM;\r
+    }
+    bool isNeedDeleteFile = true;
+    uint32_t value = strtoul(argv[1], NULL, 0xA);
+    if (value == 0) {
+        isNeedDeleteFile = false;
+    }
+    g_sample.enableOverwriteFiles = isNeedDeleteFile;
+    return MEDIA_OK;
+}
+
+int32_t SampleGetFileRemainTime(int32_t argc, const char **argv)
+{
+    uint32_t time = 0;
+    int32_t ret = AudioRecorderGetRemainingTime(g_sample.recorderHandle,
+        AUDIO_RECORD_CURRENT_FILE_REMAIN_TIME, &time);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("Get file Remaining Time failed!");
+        return ret;
+    }
+    MEDIA_INFO_LOG("Get file Remaining Time %u!", time);
+    return MEDIA_OK;
+}
+
+int32_t SampleGetStorageRemainTime(int32_t argc, const char **argv)
+{
+    uint32_t time = 0;
+    int32_t ret = AudioRecorderGetRemainingTime(g_sample.recorderHandle,
+        AUDIO_RECORD_CURRENT_STORAGE_REMAIN_TIME, &time);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("get storage remaining time failed!");
+        return ret;
+    }
+    MEDIA_INFO_LOG("get storage remaining Time %u!", time);
+    return MEDIA_OK;
+}
+
+int32_t SampleSetMaxStorageThreshold(int32_t argc, const char **argv)
+{
+    if (argc < 2) {\r
+        MEDIA_ERR_LOG("argc:%d is invalid, must be 2 parameters", argc);
+        return MEDIA_INVALID_PARAM;\r
+    }
+    g_sample.storageWarningThresholdPercent = strtoull(argv[1], NULL, 0xA);
+    return MEDIA_OK;
+}
+
+int32_t SampleSplitFileDuration(int32_t argc, const char **argv)
+{
+    if (argc < 2) {\r
+        MEDIA_ERR_LOG("argc:%d is invalid, must be 2 parameters", argc);
+        return MEDIA_INVALID_PARAM;\r
+    }
+    g_sample.splitFileDuration = strtoul(argv[1], NULL, 0xA);
+    return MEDIA_OK;
+}
+
+int32_t SampleSplitFileSize(int32_t argc, const char **argv)
+{
+    if (argc < 2) {\r
+        MEDIA_ERR_LOG("argc:%d is invalid, must be 2 parameters", argc);
+        return MEDIA_INVALID_PARAM;\r
+    }
+    g_sample.splitFileSize = strtoull(argv[1], NULL, 0xA);
+    return MEDIA_OK;
+}
+
+int32_t SampleGetFileInfo(int32_t argc, const char **argv)
+{
+    MEDIA_UNUSED(argc);
+    MEDIA_UNUSED(argv);
+    RecordFileInfo info = {};
+    int32_t ret = AudioRecorderGetFileInfo(g_sample.recorderHandle, &info);
+    if (ret != MEDIA_OK) {
+        MEDIA_ERR_LOG("get file info failed!");
+        return ret;
+    }
+    MEDIA_INFO_LOG("current file name[ %s ]!", info.fileName);
+    MEDIA_INFO_LOG("current file size[ %llu ]!", info.fileSize);
+    MEDIA_INFO_LOG("current file date[ %04u-%02u-%02u,%02u:%02u:%02u ]!", info.fileDateYear,
+        info.fileDateMonth, info.fileDateDay, info.fileDateHour, info.fileDateMin, info.fileDateSec);
+    MEDIA_INFO_LOG("current file duration[ %u ]!", info.fileDuration);
+    return MEDIA_OK;
+}
+
+static RecordTestInvoke g_recordInvokeFuncList[] = {
+    {"start", SampleAudioRecorderStart},
+    {"stop", SampleAudioRecorderStop},
+    {"deletefile", SampleSetDeleteFileEnable},
+    {"getfileremaintime", SampleGetFileRemainTime},
+    {"getstorageremaintime", SampleGetStorageRemainTime},
+    {"maxstoragethreshold", SampleSetMaxStorageThreshold},
+    {"splitfileduration", SampleSplitFileDuration},
+    {"splitfilesize", SampleSplitFileSize},
+    {"getinfo", SampleGetFileInfo},
+};
+#endif
+
+int32_t AudioRecorderSample(int32_t argc, const char *argv[])
+{
+#ifdef SUPPORT_AUDIO_RECORDER
+    TEST_SAMPLE_RETURN_VAL_IF_NULL(argv);
+    MEDIA_INFO_LOG("enter");
+    if (argc < 1) {
+        MEDIA_ERR_LOG("at least one parameter is required!");
+        return MEDIA_INVALID_PARAM;
+    }
+    for (int32_t i = 0; i < argc; i++) {
+        MEDIA_INFO_LOG("argv[%d]: %s\n", i, argv[i]);
+    }
+    size_t size = sizeof(g_recordInvokeFuncList) / sizeof(RecordTestInvoke);
+    InvokeFunc invokeFunc = nullptr;
+    for (size_t i = 0; i < size; i++) {
+        if (strcmp(argv[0], g_recordInvokeFuncList[i].cmdName) == 0) {
+            invokeFunc = g_recordInvokeFuncList[i].invoke;
+            break;
+        }
+    }
+    if (invokeFunc == nullptr) {
+        MEDIA_ERR_LOG("not support cmd!");
+        return MEDIA_INVALID_PARAM;
+    }
+    return invokeFunc(argc, argv);
+#else
+    MEDIA_UNUSED(argv);\r
+    MEDIA_UNUSED(argc);\r
+    return 0;
+#endif
+}
+
+#ifdef __cplusplus
+};
+#endif
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/foundation/sample/wrapper/audio_recorder_sample.h b/code/sdk/middleware/services/media/foundation/sample/wrapper/audio_recorder_sample.h
new file mode 100644 (file)
index 0000000..d4de909
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: audio recorder sample
+* Author: Media Software Group
+* Create: 2025-09-24
+*/
+
+#ifndef AUDIO_RECORDER_SAMPLE_H
+#define AUDIO_RECORDER_SAMPLE_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int32_t AudioRecorderSample(int32_t argc, const char *argv[]);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
\ No newline at end of file
index b59e458..f2118f8 100644 (file)
@@ -66,6 +66,7 @@ const uint32_t MAX_ARGC = 5;
 #define MEDIA_MAX_PLAYER_TASK 6\r
 #define DEFAULE_HTTP_1 "http://openaudio.cos.tx.xmcdn.com/group64/M0B/02/30/wKgMaV1whaLAcRGQAE_0uZWMCp8270.mp3"\r
 #define DEFAULE_HTTP_2 "http://cdn.gohudong.com/Public/Hudong/Games/GameShake2019/assets/audio/game_running.mp3"\r
+#define DEFAULE_HTTP_3 "https://music.163.com/song/media/outer/url?id=2166584564.mp3"\r
 \r
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))\r
 \r
@@ -201,6 +202,7 @@ typedef struct {
 static PlaySampleHttpPath g_httpPathlist[] = {\r
     { "http1://", DEFAULE_HTTP_1 },\r
     { "http2://", DEFAULE_HTTP_2 },\r
+    { "http3://", DEFAULE_HTTP_3 },\r
 };\r
 \r
 PlaySampleType g_funlist[] = {\r
@@ -517,9 +519,14 @@ public:
 \r
     void OnInfo(int32_t type, int32_t extra) override\r
     {\r
-        MEDIA_UNUSED(type);\r
-        MEDIA_UNUSED(extra);\r
-        MEDIA_INFO_LOG("OnInfo test");\r
+        MEDIA_INFO_LOG("PlayerCallback OnInfo, current state:%s",\r
+            (type == PlayerInfoType::PLAYER_INFO_PLAY_START) ? "play start" :\r
+            (type == PlayerInfoType::PLAYER_INFO_PLAYING) ? "playing" :\r
+            (type == PlayerInfoType::PLAYER_INFO_PLAY_END) ? "playEnd" :\r
+            (type == PlayerInfoType::PLAYER_INFO_SEEK_START) ? "seek start" :\r
+            (type == PlayerInfoType::PLAYER_INFO_SEEK_END) ? "seek end" :\r
+            (type == PlayerInfoType::PLAYER_INFO_PAUSED) ? "paused" :\r
+            (type == PlayerInfoType::PLAYER_INFO_STOPPED) ? "stoped" : "unknown");\r
     }\r
 \r
     void OnRewindToComplete() override\r
index d1ab1f6..aa3b7fa 100644 (file)
@@ -171,6 +171,11 @@ static bool InitPlayerResources(MediaVideoPlay *videoPlay)
         return false;\r
     }\r
 \r
+    // prepare buffers which are used to playing video\r
+    LiteSurface* liteSurface = dynamic_cast<LiteSurface*>(videoPlay->surface_);\r
+    if (liteSurface != nullptr) {\r
+        liteSurface->PrepareBuffers();\r
+    }\r
     videoPlay->player_ = player;\r
     return true;\r
 }\r
@@ -376,6 +381,9 @@ void *MediaVideoPlay::VideoPlayThread(void *arg)
     }\r
     int32_t ret = RunVideoPlay(videoPlay);\r
     if (ret != 0) {\r
+        // clear buffers\r
+        LiteSurface* liteSurface = dynamic_cast<LiteSurface*>(videoPlay->surface_);\r
+        liteSurface->AsyncClearBuffers();\r
         MEDIA_ERR_LOG("run video play failed\n");\r
     }\r
 \r
@@ -446,12 +454,6 @@ int32_t MediaVideoPlay::StartVideoPlay(void)
         return MEDIA_OK;\r
     }\r
 \r
-    // prepare buffers which are used to playing video\r
-    LiteSurface* liteSurface = dynamic_cast<LiteSurface*>(surface_);\r
-    if (liteSurface != nullptr) {\r
-        liteSurface->PrepareBuffers();\r
-    }\r
-\r
     isEntered_ = true;\r
     ResetVideoPlayState();\r
     MediaThreadattr attr = { "VideoPlayThread", 0x2000, THREAD_SCHED_INVALID, 0, true };\r
@@ -587,7 +589,6 @@ int32_t MediaVideoPlay::StopVideoPlay(void)
     if (isSyncExitMode_) {\r
         MediaMutexUnLock(mutex_);\r
         MediaThreadJoin(&threadHandle_);\r
-        dynamic_cast<LiteSurface*>(surface_)->ClearBuffers(); // clear buffers safely in sync mode to reduce peak memory\r
         play = nullptr;\r
         return MEDIA_OK;\r
     }\r
index 8b5b58a..0b93f7e 100644 (file)
@@ -628,38 +628,35 @@ static void *VoiceCallVolteThread(void *priv)
 
 static int32_t StartVoiceCall(const char **param)
 {
-    MEDIA_ERR_LOG("StartVoiceCall");
-    
+    MediaInitStaticMutexLock(&g_voiceCallVolteContextMutex);
     MediaMutexLock(g_voiceCallVolteContextMutex);
-    int32_t type = 0;//strtol(param[0x1], nullptr, NUMBER_BASE);
+    int32_t type = strtol(param[0x1], nullptr, NUMBER_BASE);
     if (g_voiceCallVolteContext != nullptr) {
         MEDIA_ERR_LOG("invalid operation");
-        goto EXIT;
+        MediaMutexUnLock(g_voiceCallVolteContextMutex);
+        return MEDIA_ERR;
     }
     g_voiceCallVolteContext = (VoiceCallVolteContext *)malloc(sizeof(VoiceCallVolteContext));
     if (g_voiceCallVolteContext == nullptr) {
         MEDIA_ERR_LOG("malloc failed");
-        goto EXIT;
+        MediaMutexUnLock(g_voiceCallVolteContextMutex);
+        return MEDIA_ERR;
     }
     if (memset_s(g_voiceCallVolteContext, sizeof(VoiceCallVolteContext), 0, sizeof(VoiceCallVolteContext)) != EOK) {
         MEDIA_ERR_LOG("memset_s failed");
+        MediaMutexUnLock(g_voiceCallVolteContextMutex);
         goto EXIT;
     }
-    MediaMutexUnLock(g_voiceCallVolteContextMutex);
-    MediaThreadJoin(&g_voiceCallVolteContext->taskHandle);
     g_voiceCallVolteContext->type = type;
-
-    MEDIA_ERR_LOG("g_voiceCallVolteContext->taskHandle");
-
+    MediaMutexUnLock(g_voiceCallVolteContextMutex);
     if (type == 0) {
-        MediaThreadattr attr = { "VoiceCallVolteThread", 0x2000, THREAD_SCHED_INVALID, 0, true };
+        MediaThreadattr attr = { "VoiceCallVolteThread", 0x2000, THREAD_SCHED_INVALID, 0, false };
         MediaThreadIdHandle taskHandle = MediaThreadCreate(VoiceCallVolteThread, g_voiceCallVolteContext, &attr);
         if (taskHandle == nullptr) {
             MEDIA_ERR_LOG("create voice call volte  thread failed");
-            free(g_voiceCallVolteContext);
-            g_voiceCallVolteContext = nullptr;
-            return -1;
+            goto EXIT;
         }
+        g_voiceCallVolteContext->taskHandle = taskHandle;
     } else {
         g_voiceCallVolteContext->data = (uint8_t *)malloc(0x400);
         g_voiceCallVolteContext->size = 0x400;
@@ -667,21 +664,21 @@ static int32_t StartVoiceCall(const char **param)
         MediaThreadIdHandle taskHandle = MediaThreadCreate(LocalVoiceCallVolteThread, g_voiceCallVolteContext, &attr);
         if (taskHandle == nullptr) {
             MEDIA_ERR_LOG("create voice call volte  thread failed");
-            free(g_voiceCallVolteContext);
-            g_voiceCallVolteContext = nullptr;
-            return -1;
+            goto EXIT;
         }
         g_voiceCallVolteContext->taskHandle = taskHandle;
     }
-    return 0;
+    return MEDIA_OK;
 EXIT:
-    MediaMutexUnLock(g_voiceCallVolteContextMutex);
-    return -1;
+    free(g_voiceCallVolteContext);
+    g_voiceCallVolteContext = nullptr;
+    return MEDIA_ERR;
 }
 
 static int32_t StopVoiceCall(const char **param)
 {
     MEDIA_UNUSED(param);
+    MediaInitStaticMutexLock(&g_voiceCallVolteContextMutex);
     MediaMutexLock(g_voiceCallVolteContextMutex);
     if (g_voiceCallVolteContext == nullptr) {
         MEDIA_ERR_LOG("voice call volte context is null, execute start command first");
@@ -713,8 +710,7 @@ static int32_t VoiceCAllSeaEnable(const char **param)
         MEDIA_ERR_LOG("not support set sae enable!");
         return -1;
     }
-    int32_t enable = 1;//strtol(param[0x1], nullptr, NUMBER_BASE);
-    MEDIA_ERR_LOG("enable %d",enable);
+    int32_t enable = strtol(param[0x1], nullptr, NUMBER_BASE);
     int32_t ret = 0;
     if (enable == 0) {
         ret = AudioManagerSetSeaEnable(false);
index 50679e1..cbb9274 100644 (file)
@@ -211,6 +211,8 @@ typedef struct {
     MediaThreadIdHandle mainId;
     MediaThreadIdHandle subId;
     bool detached;
+       MediaThreadCondHandle cond;
+    void *stackMem;
 } MediaThreadMember;
 
 #define THREAD_MANAGER_MAX_CNT 10
@@ -244,6 +246,13 @@ static uint32_t MediaGetThreadManagerIdxFromIdHandle(const MediaThreadIdHandle i
     return UINT32_MAX;
 }
 
+static void FreeStackMemory(MediaThreadMember *member) {
+    if (member != nullptr && member->stackMem != nullptr) {
+        free(member->stackMem);
+        member->stackMem = nullptr;
+    }
+}
+
 #define THREAD_EVENT_EXIT_FLAG 0x45584954U /* EXIT ascii */
 #ifdef CMSIS_SUPPORT
 static void MediaThreadFunc(void *arg)
@@ -266,12 +275,14 @@ static void *MediaThreadFunc(void *arg)
         if (idx < THREAD_MANAGER_MAX_CNT) {
             g_mediaThreadManager[idx] = nullptr;
         }
+        MediaThreadCondDestroy(&member->cond);
+        FreeStackMemory(member);
         free(arg);
     }
 #ifdef CMSIS_SUPPORT
 #ifndef CMSIS_SUPPORT_JOIN
     else {
-        osThreadFlagsSet(member->mainId, THREAD_EVENT_EXIT_FLAG);
+        MediaThreadCondSignal(member->cond);
     }
 #endif
 #endif
@@ -291,11 +302,21 @@ static int32_t MediaDoCreateThread(MediaThreadMember *member, const MediaThreada
 #ifdef CMSIS_SUPPORT_JOIN
         uint32_t attrBits = attr->detached ? osThreadDetached : osThreadJoinable;
 #else
+        if (!attr->detached) {
+            member->cond = MediaThreadCondCreate();
+            if (member->cond == NULL) {
+                return -1;
+            }
+        }
         uint32_t attrBits = osThreadDetached;
 #endif
         osThreadAttr_t taskAttr = {
             attr->name, attrBits, nullptr, 0, nullptr, attr->stackSize, osPriorityNormal, 0, 0
         };
+        if (strcmp(attr->name, "AudioPlayThread") == 0) {
+            taskAttr.stack_mem = memalign(16, attr->stackSize); // 16×Ö½Ú¶ÔÆë£¬ÉêÇëÄÚ´æµ½psram
+            member->stackMem = taskAttr.stack_mem;
+        }
         MediaSetCmsisThreadPriorityAttr(taskAttr, attr->prioty);
         subId = osThreadNew(MediaThreadFunc, member, &taskAttr);
     }
@@ -341,7 +362,6 @@ MediaThreadIdHandle MediaThreadCreate(MediaThreadFunType func, void *argument, c
     uint32_t idx = MediaGetValidThreadManagerIdx();
     if (idx >= THREAD_MANAGER_MAX_CNT) {
         free(member);
-        member = nullptr;
         goto EXIT;
     }
 
@@ -349,9 +369,11 @@ MediaThreadIdHandle MediaThreadCreate(MediaThreadFunType func, void *argument, c
     member->argument = argument;
     member->mainId = MediaThreadGetId();
     member->detached = attr != nullptr ? attr->detached : false;
+    member->stackMem = nullptr;
+    member->cond = nullptr;
     if (MediaDoCreateThread(member, attr) != 0) {
+        FreeStackMemory(member);
         free(member);
-        member = nullptr;
         goto EXIT;
     }
     g_mediaThreadManager[idx] = member;
@@ -379,12 +401,6 @@ void MediaThreadJoin(MediaThreadIdHandle *thdId)
 #ifdef CMSIS_SUPPORT
 #ifdef CMSIS_SUPPORT_JOIN
     osThreadJoin((osThreadId_t)*thdId);
-#else
-    /*
-     * MediaThreadMember *member = *thdId;
-     * osThreadJoin not support join, can use osThreadFlagsSet/osThreadFlagsWait replace
-     */
-    osThreadFlagsWait(THREAD_EVENT_EXIT_FLAG, osFlagsWaitAll, osWaitForever);
 #endif
 #else
     pthread_join((pthread_t)(uintptr_t)*thdId, nullptr);
@@ -395,10 +411,18 @@ void MediaThreadJoin(MediaThreadIdHandle *thdId)
         MediaThreadMember *member = g_mediaThreadManager[idx];
         if (member != nullptr && member->detached) { /* detach sub thread, will free handle after sub thread exit */
             *thdId = nullptr;
+            FreeStackMemory(member);
             MediaMutexUnLock(g_mediaThreadManagerLock);
             return;
         }
+#ifdef CMSIS_SUPPORT
+#ifndef CMSIS_SUPPORT_JOIN
+        MediaThreadCondWait(member->cond, g_mediaThreadManagerLock);
+        MediaThreadCondDestroy(&member->cond);
+#endif
+#endif
         g_mediaThreadManager[idx] = nullptr;
+        FreeStackMemory(member);
         free(member);
         member = nullptr;
     }
index ac203a3..692d1ee 100644 (file)
@@ -492,7 +492,7 @@ static int32_t SubPortTrackInit(SubPortContext *portCtx, const struct PortPlugin
     portTrackCtx->common.GetVolume = AudioBluetoothSubPortTrackGetVolume;
     portTrackCtx->common.Invoke = AudioBluetoothSubPortInvoke;
     portTrackCtx->common.RegCallback = AudioBluetoothSubPortTrackRegCallback;
-    portTrackCtx->isRaw = false;
+    portTrackCtx->isRaw = IsRawFormat(inputAttr->audioFormat);
     portTrackCtx->subPortCtx = portCtx;
     portTrackCtx->isHandlePublicResource = true;
     MEDIA_HAL_LOGD(MODULE_NAME, "success");
@@ -1350,7 +1350,10 @@ static int32_t BluetoothDetachInternal(const SubPortTrackContext *portTrackCtx)
         bt_audio_port_params portParam = {};
         portParam.port_type = A2DP;
         portParam.share_mem_id = portTrackCtx->outputAdpHandle;
+        ret = bt_stop_audio_stream(portTrackCtx->btStreamHandle);
+        CHK_FAILED_NO_RETURN(ret, MEDIA_HAL_OK, "bt stop stream failed");
         ret = BtDetachHandle(portTrackCtx, portParam);
+        CHK_FAILED_NO_RETURN(ret, MEDIA_HAL_OK, "bt detach handle failed");
     }
 #endif
     MEDIA_HAL_LOGD(MODULE_NAME, "success");
index 44d92d7..7afbe27 100644 (file)
@@ -34,7 +34,6 @@ extern "C" {
 
 typedef enum {
     AUDIO_MOD_AI = 0,
-    AUDIO_MOD_AI_SEA,
     AUDIO_MOD_ADP,
     AUDIO_MOD_ADEC,
     AUDIO_MOD_AENC,
@@ -65,7 +64,7 @@ typedef struct {
 
 void VolumePercentToDb(float volume, int32_t *db);
 
-bool IsRawFormat(struct PortPluginAttr inputAttr);
+bool IsRawFormat(enum AudioFormat audioFormat);
 
 #ifdef AUDIO_SDK_SUPPORT
 
@@ -103,8 +102,6 @@ int32_t GetParamByValue(uint8_t *param, uint32_t paramLen, const char *value,
     uint32_t valueLen, uint32_t configLen);
 
 int32_t SetSeaEnable(td_handle seaHandle, const char *value, uint32_t valueLen);
-
-bool isMultipleSeaOpen(void);
 #endif
 
 int32_t ExtraParamsInvoke(AudioHandle portHandle, struct InvokeAttr *invokeAttr,
index fee0715..0126bbc 100644 (file)
@@ -38,12 +38,9 @@ extern "C" {
 #define MODULE_NAME "AudioPortPluginCommon"
 #define WAIT_CREATE_AENC_LOOP_CNT 100
 #define WAIT_CREATE_AENC_SUCCESS_US 10000
-#define DEFAULT_SAMPLERATE 16000
 
 static bool g_audioSdkIsInited = false;
-static int32_t g_isCreateAencCount = 0;
-static int32_t g_subPortSeaOpenCount = 0;
-td_handle g_seaHandle = 0;
+static bool g_isCanCreateAenc = true;
 static MediaHalMutexHandle g_audioSdkInitLock = NULL;
 #ifdef SUPPORT_NV
 static audio_vqe_param_t g_vqeParam = { 0 };
@@ -66,11 +63,11 @@ void VolumePercentToDb(float volume, int32_t *db)
     *db = (int32_t)tmpDb;
 }
 
-bool IsRawFormat(struct PortPluginAttr inputAttr)
+bool IsRawFormat(enum AudioFormat audioFormat)
 {
-    if (inputAttr.audioFormat == AUDIO_FORMAT_PCM_16_BIT &&
-        inputAttr.sampleRate == DEFAULT_SAMPLERATE &&
-        inputAttr.channelCount == 1) {
+    // The 24-bit PCM is processed as the ES stream and decoded by the ADEC.
+    // The 16-bit PCM is processed as the ES stream for BT SCO msbc and cvsd pipeline same.
+    if (audioFormat == AUDIO_FORMAT_PCM_8_BIT || audioFormat == AUDIO_FORMAT_PCM_32_BIT) {
         return true;
     }
     return false;
@@ -428,22 +425,8 @@ static int32_t SetSeaAfeAttr(td_handle seaHandle)
     return MEDIA_HAL_OK;
 }
 
-bool isMultipleSeaOpen(void)
-{
-    printf("%s %d\r\n","g_subPortSeaOpenCount",g_subPortSeaOpenCount);
-
-    return g_subPortSeaOpenCount > 1;
-}
-
 int32_t AudioSDKSeaOpen(td_handle *seaHandle, struct PortPluginAttr inputAttr)
 {
-    MediaHalMutexLock(g_audioSdkInitLock);
-    if (g_subPortSeaOpenCount > 0) {
-        *seaHandle = g_seaHandle;
-        g_subPortSeaOpenCount++;
-        MediaHalMutexUnLock(g_audioSdkInitLock);
-        return MEDIA_HAL_OK;
-    }
     int32_t ret;
     uapi_sea_attr seaAttr = {};
     uapi_sea_eng_sel seaEng = {};
@@ -479,38 +462,23 @@ int32_t AudioSDKSeaOpen(td_handle *seaHandle, struct PortPluginAttr inputAttr)
     if (ret != MEDIA_HAL_OK) {
         MEDIA_HAL_LOGW(MODULE_NAME, "set sea param failed");
     }
-    g_seaHandle = *seaHandle;
-    g_subPortSeaOpenCount++;
     MEDIA_HAL_LOGD(MODULE_NAME, "success");
-    printf("AudioSDKSeaOpen %s %d\r\n","g_subPortSeaOpenCount",g_subPortSeaOpenCount);
-    MediaHalMutexUnLock(g_audioSdkInitLock);
     return MEDIA_HAL_OK;
 
 SEA_UNLOAD_ENGINE:
     (void)uapi_sea_unload_engine(UAPI_SEA_LIB_SEE, "imedia_2mic");
-    MediaHalMutexUnLock(g_audioSdkInitLock);
     return ret;
 }
 
 int32_t AudioSDKSeaClose(td_handle seaHandle)
 {
-    MediaHalMutexLock(g_audioSdkInitLock);
     int32_t ret;
-    g_subPortSeaOpenCount--;
-    if (g_subPortSeaOpenCount > 0) {
-        MediaHalMutexUnLock(g_audioSdkInitLock);
-        return MEDIA_HAL_OK;
-    }
-    printf("AudioSDKSeaClose %s %d\r\n","g_subPortSeaOpenCount",g_subPortSeaOpenCount);
-
     MEDIA_HAL_DOFUNC_TIME(ret = uapi_sea_destroy(seaHandle));
     CHK_FAILED_NO_RETURN(ret, MEDIA_HAL_OK, "destroy sea failed");
 
     MEDIA_HAL_DOFUNC_TIME(ret = uapi_sea_unload_engine(UAPI_SEA_LIB_SEE, "imedia_2mic"));
     CHK_FAILED_NO_RETURN(ret, MEDIA_HAL_OK, "unload sea engine failed");
     MEDIA_HAL_LOGD(MODULE_NAME, "success");
-    g_seaHandle = 0;
-    MediaHalMutexUnLock(g_audioSdkInitLock);
     return MEDIA_HAL_OK;
 }
 
@@ -519,7 +487,8 @@ static int32_t WaitCreateAnec(void)
     int32_t cnt = 0;
     while (cnt < WAIT_CREATE_AENC_LOOP_CNT) {
         MediaHalMutexLock(g_audioSdkInitLock);
-        if (g_isCreateAencCount < 0x2) {
+        if (g_isCanCreateAenc) {
+            g_isCanCreateAenc = false;
             MediaHalMutexUnLock(g_audioSdkInitLock);
             return MEDIA_HAL_OK;
         }
@@ -539,9 +508,10 @@ int32_t AudioSDKAencOpen(td_handle *aencHandle, uapi_aenc_attr aencAttr)
         return ret;
     }
     MEDIA_HAL_DOFUNC_TIME(ret = uapi_aenc_create(aencHandle));
-    if (ret != MEDIA_HAL_OK) {
-        MEDIA_HAL_LOGE(MODULE_NAME, "uapi_aenc_create failed");
-        return ret;
+    if (ret != MEDIA_HAL_OK) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "uapi_aenc_create failed");\r
+        g_isCanCreateAenc = true;\r
+        return ret;\r
     }
 
     MEDIA_HAL_LOGI(MODULE_NAME, "codec_id: 0x%x", aencAttr.codec_id);
@@ -550,24 +520,22 @@ int32_t AudioSDKAencOpen(td_handle *aencHandle, uapi_aenc_attr aencAttr)
         MEDIA_HAL_LOGE(MODULE_NAME, "uapi_aenc_set_attr failed: 0x%x, codec id: 0x%x", ret, aencAttr.codec_id);
         goto CLOSE;
     }
-#ifndef MELODY_AUDIO_SUPPORT
-    if (aencAttr.codec_id == UAPI_ACODEC_ID_OPUS) {
-        uint32_t bitRate = OPUS_ENC_BIT_RATE;
-        ret = uapi_aenc_set_param(*aencHandle, UAPI_AENC_PARAM_BIT_RATE, &bitRate, sizeof(uint32_t));
-        if (ret != MEDIA_HAL_OK) {
-            MEDIA_HAL_LOGE(MODULE_NAME, "uapi set aenc send cmd bit Rate faild, ret: 0x%x", ret);
-            goto CLOSE;
-        }
-    }
+#ifndef MELODY_AUDIO_SUPPORT\r
+    if (aencAttr.codec_id == UAPI_ACODEC_ID_OPUS) {\r
+        uint32_t bitRate = OPUS_ENC_BIT_RATE;\r
+        ret = uapi_aenc_set_param(*aencHandle, UAPI_AENC_PARAM_BIT_RATE, &bitRate, sizeof(uint32_t));\r
+        if (ret != MEDIA_HAL_OK) {\r
+            MEDIA_HAL_LOGE(MODULE_NAME, "uapi set aenc send cmd bit Rate faild, ret: 0x%x", ret);\r
+            goto CLOSE;\r
+        }\r
+    }\r
 #endif
-    MediaHalMutexLock(g_audioSdkInitLock);
-    g_isCreateAencCount++;
-    MediaHalMutexUnLock(g_audioSdkInitLock);
     MEDIA_HAL_LOGD(MODULE_NAME, "success");
     return MEDIA_HAL_OK;
 
 CLOSE:
     MEDIA_HAL_DOFUNC_TIME((void)uapi_aenc_destroy(*aencHandle));
+    g_isCanCreateAenc = true;
     return ret;
 }
 
@@ -577,7 +545,7 @@ int32_t AudioSDKAencClose(td_handle aencHandle)
     MEDIA_HAL_DOFUNC_TIME(ret = uapi_aenc_destroy(aencHandle));
     CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_aenc_destroy failed");
     MediaHalMutexLock(g_audioSdkInitLock);
-    g_isCreateAencCount--;
+    g_isCanCreateAenc = true;
     MediaHalMutexUnLock(g_audioSdkInitLock);
     MEDIA_HAL_LOGD(MODULE_NAME, "success");
     return MEDIA_HAL_OK;
@@ -591,13 +559,6 @@ int32_t AudioSDKAttach(AudioSDKModuleType modType, td_handle srcHandle, td_handl
             MEDIA_HAL_DOFUNC_TIME(ret = uapi_ai_attach_output(srcHandle, dstHandle));
             CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_ai_attach_output");
             break;
-        case AUDIO_MOD_AI_SEA:
-            if (g_subPortSeaOpenCount <= 1) { // Sea only needs to be bound once.
-                printf("AudioSDKAttach %X %X\r\n",srcHandle,dstHandle);
-                MEDIA_HAL_DOFUNC_TIME(ret = uapi_ai_attach_output(srcHandle, dstHandle));
-                CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_ai_attach_output");
-            }
-            break;
         case AUDIO_MOD_ADP:
             MEDIA_HAL_DOFUNC_TIME(ret = uapi_adp_attach_output(srcHandle, dstHandle));
             CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_adp_attach_output failed");
@@ -635,14 +596,6 @@ int32_t AudioSDKDetach(AudioSDKModuleType modType, td_handle srcHandle, td_handl
             MEDIA_HAL_DOFUNC_TIME(ret = uapi_ai_detach_output(srcHandle, dstHandle));
             CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_ai_detach_output failed");
             break;
-        case AUDIO_MOD_AI_SEA:
-            if (g_subPortSeaOpenCount <= 1) { // Sea only needs to be unbound once.
-                printf("AudioSDKDetach AUDIO_MOD_AI_SEA %X %X\r\n",srcHandle,dstHandle);
-
-                MEDIA_HAL_DOFUNC_TIME(ret = uapi_ai_detach_output(srcHandle, dstHandle));
-                CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_ai_detach_output failed");
-            }
-            break;
         case AUDIO_MOD_ADP:
             MEDIA_HAL_DOFUNC_TIME(ret = uapi_adp_detach_output(srcHandle, dstHandle));
             CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_adp_detach_output failed");
@@ -656,8 +609,6 @@ int32_t AudioSDKDetach(AudioSDKModuleType modType, td_handle srcHandle, td_handl
             CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_aenc_detach_output failed");
             break;
         case AUDIO_MOD_SEA:
-            printf("AudioSDKDetach AUDIO_MOD_SEA %X %X\r\n",srcHandle,dstHandle);
-
             MEDIA_HAL_DOFUNC_TIME(ret = uapi_sea_detach_output(srcHandle, UAPI_SEA_OUTPUT_ASR_SRC, dstHandle));
             CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_sea_detach_output failed");
             break;
@@ -815,19 +766,19 @@ int32_t GetParamByValue(uint8_t *param, uint32_t paramLen, const char *value,
     uint32_t valueLen, uint32_t configLen)
 {
     uint32_t prefixlen = 0;
-    for (uint32_t i = 0; i < valueLen; i++) {
-        if (value[i] == ':') {
-            prefixlen = i + 1;
-            break;
-        }
+    for (uint32_t i = 0; i < valueLen; i++) {\r
+        if (value[i] == ':') {\r
+            prefixlen = i + 1;\r
+            break;\r
+        }\r
     }
-    if (prefixlen == 0) {
+    if (prefixlen == 0) {\r
         MEDIA_HAL_LOGE(MODULE_NAME, "prefix is not found.");
-        return MEDIA_HAL_ERR;
+        return MEDIA_HAL_ERR;\r
     }
-    if (memcpy_s(param, paramLen, value + prefixlen, configLen) != EOK) {
+    if (memcpy_s(param, paramLen, value + prefixlen, configLen) != EOK) {\r
         MEDIA_HAL_LOGE(MODULE_NAME, "set spk cali coef memcpy_s failed!");
-        return MEDIA_HAL_ERR;
+        return MEDIA_HAL_ERR;\r
     }
     return MEDIA_HAL_OK;
 }
index 7351283..bdc7a42 100644 (file)
@@ -45,6 +45,7 @@ extern "C" {
 #define SET_SEA_PARAM "setseaparam"
 #define SET_BIT_RATE  "setbitrate"
 #define SEA_PARAM_LEN 256
+#define OGG_HEAD_LEN 8
 #define MP3_ENC_BIT_RATE_PRECISION 1000
 
 static enum AudioFormat g_supportFormats[] = {
@@ -71,6 +72,8 @@ typedef struct {
     /* attr context */
     bool isRaw;
     struct PortPluginAttr inputAttr;
+    bool isSupportMultiFrame;
+    int32_t offset;
 } SubPortTrackInContext;
 
 typedef struct {
@@ -104,14 +107,6 @@ static SubPortTrackInCapabilities g_caps[] = {
     { AUDIO_IN_COMMUNICATION, AUDIO_FORMAT_MP3, 16000, 1 },
 };
 
-static bool isMultipleAIOpen(void)
-{
-    MediaHalMutexLock(g_subPortTrackInLock);
-    bool ret = g_subPortTrackInOpened > 1;
-    MediaHalMutexUnLock(g_subPortTrackInLock);
-    return ret;
-}
-
 static bool IsSupported(const struct PortPluginAttr *inputAttr)
 {
     for (uint32_t i = 0; i < ARRAY_SIZE(g_caps); i++) {
@@ -154,6 +149,7 @@ static int32_t SubPortTrackInInit(SubPortTrackInContext *portTrackInCtx, const s
     portTrackInCtx->common.SetVolume = AudioPrimarySubPortInSetVolume;
     portTrackInCtx->common.GetVolume = AudioPrimarySubPortInGetVolume;
     portTrackInCtx->common.Invoke = AudioPrimarySubPortInInvoke;
+    portTrackInCtx->isSupportMultiFrame = false;
     MEDIA_HAL_LOGD(MODULE_NAME, "success");
     return MEDIA_HAL_OK;
 }
@@ -200,15 +196,9 @@ static int32_t AIDevOpen(td_handle *aiHandle, enum AudioCategory audioCategory)
             return ret;
         }
         uapi_ai_gain gain = {};
-        MEDIA_HAL_DOFUNC_TIME(ret = uapi_ai_get_volume(*aiHandle, &gain));
-        CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_ai_get_volume failed");
-#ifdef BOARD_FD230
-        gain.integer = gain.integer - 9; // 前端mic灵敏度不同可通过此处调增,增加4db增益  默认gain.integer = gain.integer+4
-#elif defined(BORAD_N9) || defined(BORAD_W9)
-        gain.integer = gain.integer + 10; // 前端mic灵敏度不同可通过此处调增,增加4db增益  默认gain.integer = gain.integer+4
-#elif defined(LEINIAO) 
-        gain.integer = gain.integer +3; // 前端mic灵敏度不同可通过此处调增,增加4db增益  默认gain.integer = gain.integer+4
-#endif
+        gain.integer = DEFAULTE_AI_VOL_DB_INTERGER;
+        gain.decimal = 0;
+        MEDIA_HAL_LOGI(MODULE_NAME, "set default AI volume.integer = %d,  decimal = %d", gain.integer, gain.decimal);
         MEDIA_HAL_DOFUNC_TIME(ret = uapi_ai_set_volume(*aiHandle, &gain));
         CHK_FAILED_NO_RETURN(ret, MEDIA_HAL_OK, "uapi_ai_set_volume failed");
     }
@@ -267,6 +257,7 @@ static int32_t AudioSDKOpenInternal(SubPortTrackInContext *portTrackInCtx)
     aencAttr.param.interleaved = true;
     if (inputAttrTemp.type == AUDIO_IN_MEDIA) {
         aencAttr.frame_mode_output = TD_TRUE;
+        portTrackInCtx->isSupportMultiFrame = !aencAttr.frame_mode_output;
     }
     aencAttr.param.channels = inputAttrTemp.channelCount;
     aencAttr.param.bit_depth = inputAttrTemp.bitWidth;
@@ -326,7 +317,7 @@ static int32_t AudioSDKCloseInternal(SubPortTrackInContext *portTrackInCtx)
 static int32_t AudioSDKAttachInternal(td_handle aiHandle, SubPortTrackInContext *portTrackInCtx)
 {
 #ifdef AUDIO_SEA_SUPPORT
-    int32_t ret = AudioSDKAttach(AUDIO_MOD_AI_SEA, aiHandle, portTrackInCtx->seaHandle);
+    int32_t ret = AudioSDKAttach(AUDIO_MOD_AI, aiHandle, portTrackInCtx->seaHandle);
     CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "ai attach sea failed");
 
     ret = AudioSDKAttach(AUDIO_MOD_SEA, portTrackInCtx->seaHandle, portTrackInCtx->aencHandle);
@@ -355,7 +346,7 @@ static int32_t AudioSDKAttachInternal(td_handle aiHandle, SubPortTrackInContext
 SEA_DETACH_AENC:
     (void)AudioSDKDetach(AUDIO_MOD_SEA, portTrackInCtx->seaHandle, portTrackInCtx->aencHandle);
 AI_DETACH_SEA:
-    (void)AudioSDKDetach(AUDIO_MOD_AI_SEA, portTrackInCtx->aiHandle, portTrackInCtx->seaHandle);
+    (void)AudioSDKDetach(AUDIO_MOD_AI, portTrackInCtx->aiHandle, portTrackInCtx->seaHandle);
 #else
 AI_DETACH_AENC:
     (void)AudioSDKDetach(AUDIO_MOD_AI, portTrackInCtx->aiHandle, portTrackInCtx->aencHandle);
@@ -368,33 +359,15 @@ AI_DETACH_AENC:
 static int32_t EstablishPipeline(td_handle aiHandle, SubPortTrackInContext *portTrackInCtx)
 {
     int32_t ret;
-    portTrackInCtx->isRaw = IsRawFormat(portTrackInCtx->inputAttr);
+    portTrackInCtx->isRaw = IsRawFormat(portTrackInCtx->inputAttr.audioFormat);
     if (portTrackInCtx->isRaw) {
         ret = AudioSDKAdpOpen(&portTrackInCtx->outputAdpHandle);
         CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "output adp open failed");
-#ifdef AUDIO_SEA_SUPPORT
-        ret = AudioSDKSeaOpen(&portTrackInCtx->seaHandle, portTrackInCtx->inputAttr);
-        if (ret != MEDIA_HAL_OK) {
-            MEDIA_HAL_LOGE(MODULE_NAME, "sea open failed");
-            goto ADP_CLOSE;
-        }
-        ret = AudioSDKAttach(AUDIO_MOD_AI_SEA, aiHandle, portTrackInCtx->seaHandle);
-        if (ret != MEDIA_HAL_OK) {
-            MEDIA_HAL_LOGE(MODULE_NAME, "ai attach sea failed!");
-            goto SEA_CLOSE;
-        }
-        ret = AudioSDKAttach(AUDIO_MOD_SEA, portTrackInCtx->seaHandle, portTrackInCtx->outputAdpHandle);
-        if (ret != MEDIA_HAL_OK) {
-            MEDIA_HAL_LOGE(MODULE_NAME, "sea attach aenc failed");
-            goto AI_DETACH_SEA;
-        }
-#else
         ret = AudioSDKAttach(AUDIO_MOD_AI, aiHandle, portTrackInCtx->outputAdpHandle);
         if (ret != MEDIA_HAL_OK) {
             MEDIA_HAL_LOGE(MODULE_NAME, "ai attach adp failed");
             goto ADP_CLOSE;
         }
-#endif
     } else {
         ret = AudioSDKOpenInternal(portTrackInCtx);
         CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "AudioSDKOpenInternal failed");
@@ -411,14 +384,6 @@ static int32_t EstablishPipeline(td_handle aiHandle, SubPortTrackInContext *port
 
 AUDIO_SDK_CLOSE:
     (void)AudioSDKCloseInternal(portTrackInCtx);
-#ifdef AUDIO_SEA_SUPPORT
-    if (portTrackInCtx->isRaw) {
-AI_DETACH_SEA:
-        (void)AudioSDKDetach(AUDIO_MOD_AI_SEA, portTrackInCtx->aiHandle, portTrackInCtx->seaHandle);
-SEA_CLOSE:
-        AudioSDKSeaClose(portTrackInCtx->seaHandle);
-#endif
-    }
 ADP_CLOSE:
     (void)AudioSDKAdpClose(portTrackInCtx->outputAdpHandle);
     return ret;
@@ -429,21 +394,13 @@ static int32_t AIDetach(const SubPortTrackInContext *portTrackInCtx)
 {
 #ifdef AUDIO_SDK_SUPPORT
     int32_t ret;
+
     if (portTrackInCtx->isRaw) {
-#ifdef AUDIO_SEA_SUPPORT
-        ret = AudioSDKDetach(AUDIO_MOD_AI_SEA, portTrackInCtx->aiHandle, portTrackInCtx->seaHandle);
-        CHK_FAILED_NO_RETURN(ret, MEDIA_HAL_OK, "ai detach sea failed");
-        ret = AudioSDKDetach(AUDIO_MOD_SEA, portTrackInCtx->seaHandle, portTrackInCtx->outputAdpHandle);
-        CHK_FAILED_NO_RETURN(ret, MEDIA_HAL_OK, "sea detach outputAdpHandle failed");
-        ret = AudioSDKSeaClose(portTrackInCtx->seaHandle);
-        CHK_FAILED_NO_RETURN(ret, MEDIA_HAL_OK, "sea close failed");
-#else
         ret = AudioSDKDetach(AUDIO_MOD_AI, portTrackInCtx->aiHandle, portTrackInCtx->outputAdpHandle);
         CHK_FAILED_NO_RETURN(ret, MEDIA_HAL_OK, "ai detach adp failed");
-#endif
     } else {
 #ifdef AUDIO_SEA_SUPPORT
-        ret = AudioSDKDetach(AUDIO_MOD_AI_SEA, portTrackInCtx->aiHandle, portTrackInCtx->seaHandle);
+        ret = AudioSDKDetach(AUDIO_MOD_AI, portTrackInCtx->aiHandle, portTrackInCtx->seaHandle);
         CHK_FAILED_NO_RETURN(ret, MEDIA_HAL_OK, "ai detach sea failed");
         ret = AudioSDKDetach(AUDIO_MOD_SEA, portTrackInCtx->seaHandle, portTrackInCtx->aencHandle);
         CHK_FAILED_NO_RETURN(ret, MEDIA_HAL_OK, "sea detach aenc failed");
@@ -484,21 +441,19 @@ int32_t AudioPrimarySubPortInEnableTrack(AudioHandle trackHandle)
 {
 #ifdef AUDIO_SDK_SUPPORT
     SubPortTrackInContext *portTrackInCtx = (SubPortTrackInContext *)trackHandle;
-    int32_t ret = MEDIA_HAL_OK;
-    if (!isMultipleAIOpen()) {
-        MEDIA_HAL_DOFUNC_TIME(ret = uapi_ai_start(portTrackInCtx->aiHandle));
-        CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_ai_start failed");
-    }
+
+    int32_t ret;
+    MEDIA_HAL_DOFUNC_TIME(ret = uapi_ai_start(portTrackInCtx->aiHandle));
+    CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_ai_start failed");
+
+    if (!portTrackInCtx->isRaw) {
 #ifdef AUDIO_SEA_SUPPORT
-        if (!isMultipleSeaOpen()) {
-            MEDIA_HAL_DOFUNC_TIME(ret = uapi_sea_start(portTrackInCtx->seaHandle));
-            if (ret != MEDIA_HAL_OK) {
-                MEDIA_HAL_LOGI(MODULE_NAME, "uapi_sea_start failed");
-                goto AI_STOP;
-            }
+        MEDIA_HAL_DOFUNC_TIME(ret = uapi_sea_start(portTrackInCtx->seaHandle));
+        if (ret != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGI(MODULE_NAME, "uapi_sea_start failed");
+            goto AI_STOP;
         }
 #endif
-    if (!portTrackInCtx->isRaw) {
         MEDIA_HAL_DOFUNC_TIME(ret = uapi_aenc_start(portTrackInCtx->aencHandle));
         if (ret != MEDIA_HAL_OK) {
             MEDIA_HAL_LOGI(MODULE_NAME, "uapi_aenc_start failed");
@@ -529,18 +484,16 @@ int32_t AudioPrimarySubPortInDisableTrack(AudioHandle trackHandle)
 {
 #ifdef AUDIO_SDK_SUPPORT
     SubPortTrackInContext *portTrackInCtx = (SubPortTrackInContext *)trackHandle;
+
     int32_t ret;
-    if (!isMultipleAIOpen()) {
-        MEDIA_HAL_DOFUNC_TIME(ret = uapi_ai_stop(portTrackInCtx->aiHandle));
-        CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_ai_stop failed");
-    }
+    MEDIA_HAL_DOFUNC_TIME(ret = uapi_ai_stop(portTrackInCtx->aiHandle));
+    CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_ai_stop failed");
+
+    if (!portTrackInCtx->isRaw) {
 #ifdef AUDIO_SEA_SUPPORT
-        if (!isMultipleSeaOpen()) {
-            MEDIA_HAL_DOFUNC_TIME(ret = uapi_sea_stop(portTrackInCtx->seaHandle));
-            CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_sea_stop failed");
-        }
+        MEDIA_HAL_DOFUNC_TIME(ret = uapi_sea_stop(portTrackInCtx->seaHandle));
+        CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_sea_stop failed");
 #endif
-    if (!portTrackInCtx->isRaw) {
         MEDIA_HAL_DOFUNC_TIME(ret = uapi_aenc_stop(portTrackInCtx->aencHandle));
         CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_aenc_stop failed");
     }
@@ -553,26 +506,33 @@ int32_t AudioPrimarySubPortInDisableTrack(AudioHandle trackHandle)
 }
 
 static int32_t CheckParam(SubPortTrackInContext *portTrackInCtx, uint8_t *buffer,
-    uint64_t requestBytes, uapi_stream_buf audioStream)
+    uint64_t requestBytes, uapi_stream_buf *audioStream)
 {
-    if (requestBytes < audioStream.size) {
-        MEDIA_HAL_LOGE(MODULE_NAME, "input buffer too small, actual: %llu vs except: %u",
-            requestBytes, audioStream.size);
-        return MEDIA_HAL_INVALID_PARAM;
+    if (requestBytes < audioStream->size) {
+        if (portTrackInCtx->isSupportMultiFrame) {
+            audioStream->size = requestBytes;
+        } else {
+            MEDIA_HAL_LOGW(MODULE_NAME, "The requested data length is shorter than the current frame length!");
+            return MEDIA_HAL_NOT_SUPPORT_GET_MULT_FRAME;
+        }
     }
-
     if (requestBytes > SIZE_MAX) {
         MEDIA_HAL_LOGE(MODULE_NAME, "input buffer size overflow");
         return MEDIA_HAL_INVALID_PARAM;
     }
-
-    if (memcpy_s(buffer, (size_t)requestBytes, audioStream.data, audioStream.size) != EOK) {
+    if (portTrackInCtx->inputAttr.audioFormat == AUDIO_FORMAT_OPUS) {
+        portTrackInCtx->offset = OGG_HEAD_LEN;
+    } else {
+        portTrackInCtx->offset = 0;
+    }
+    if (memcpy_s(buffer, (size_t)requestBytes, audioStream->data + portTrackInCtx->offset,
+        audioStream->size - portTrackInCtx->offset) != EOK) {
         MEDIA_HAL_LOGE(MODULE_NAME, "memcpy_s failed");
         return MEDIA_HAL_ERR;
     }
     int64_t sec = 0;
     int64_t nsec = 0;
-    int32_t ret = MediaHalConvertUSecToSecAndNSec(audioStream.pts, &sec, &nsec);
+    int32_t ret = MediaHalConvertUSecToSecAndNSec(audioStream->pts, &sec, &nsec);
     if (ret != MEDIA_HAL_OK) {
         MEDIA_HAL_LOGE(MODULE_NAME, "convert time from us to sec and nsec failed");
         return MEDIA_HAL_ERR;
@@ -589,21 +549,22 @@ int32_t AudioPrimarySubPortInAcquireFrame(AudioHandle trackHandle, uint8_t *buff
 {
 #ifdef AUDIO_SDK_SUPPORT
     SubPortTrackInContext *portTrackInCtx = (SubPortTrackInContext *)trackHandle;
-
     uapi_stream_buf audioStream = {};
     int32_t ret = uapi_adp_acquire_stream(portTrackInCtx->outputAdpHandle, &audioStream);
     if (ret != MEDIA_HAL_OK) {
         *replyBytes = 0;
         return MEDIA_HAL_ERR_AGAIN;
     }
-    *replyBytes = audioStream.size;
-    ret = CheckParam(portTrackInCtx, buffer, requestBytes, audioStream);
+    ret = CheckParam(portTrackInCtx, buffer, requestBytes, &audioStream);
     if (ret != MEDIA_HAL_OK) {
+        if (ret == MEDIA_HAL_NOT_SUPPORT_GET_MULT_FRAME) {
+            return ret;
+        }
         MEDIA_HAL_LOGE(MODULE_NAME, "param is invalid");
         (void)uapi_adp_release_stream(portTrackInCtx->outputAdpHandle, &audioStream);
         return ret;
     }
-
+    *replyBytes = audioStream.size - portTrackInCtx->offset;
     ret = uapi_adp_release_stream(portTrackInCtx->outputAdpHandle, &audioStream);
     if (ret != MEDIA_HAL_OK) {
         MEDIA_HAL_LOGE(MODULE_NAME, "release stream failed: 0x%x", ret);
@@ -928,13 +889,12 @@ FREE_TRACK_IN:
 int32_t AudioPrimarySubPortInDestroyTrack(AudioHandle portHandle, AudioHandle trackHandle)
 {
 #ifdef AUDIO_SDK_SUPPORT
-    SubPortInContext *portInCtx = (SubPortInContext *)portHandle;
     SubPortTrackInContext *portTrackInCtx = (SubPortTrackInContext *)trackHandle;
 
     int32_t ret = AIDetach(portTrackInCtx);
     CHK_FAILED_NO_RETURN(ret, MEDIA_HAL_OK, "AIDetach failed");
 
-    ret = AIDevClose(portInCtx->aiHandle);
+    ret = AIDevClose(portTrackInCtx->aiHandle);
     CHK_FAILED_NO_RETURN(ret, MEDIA_HAL_OK, "AIDevClose failed");
 
     free(portTrackInCtx);
index aa40c37..73e0ab4 100644 (file)
@@ -378,12 +378,6 @@ static int32_t AODevOpen(SubPortOutContext *portOutCtx, const enum AudioCategory
             MediaHalMutexUnLock(g_subPortTrackOutLock);
             return ret;
         }
-#ifdef BOARD_LEINIAO
-        uapi_snd_gain gain;
-        gain.integer = -4;
-        gain.decimal = 0;
-        uapi_snd_set_volume(portOutCtx->sndHandle, sndAttr.port_attr[0].out_port, &gain, TD_NULL);
-#endif
         if (audioCategory == AUDIO_IN_COMMUNICATION) {
             ret = uapi_snd_set_track_mode(portOutCtx->sndHandle, sndAttr.port_attr[0].out_port, SND_TRACK_MODE_BT_SCO);
         } else if (audioCategory == AUDIO_IN_MEDIA) {
@@ -450,7 +444,7 @@ static int32_t SndCreateTrackFromFormat(SubPortOutContext *portOutCtx, SubPortTr
         ret = uapi_snd_create_track(&(portTrackOutCtx->trackHandle), portOutCtx->sndHandle, &sndTrackDefAttr));
     CHK_FAILED_RETURN(ret, MEDIA_HAL_OK, ret, "uapi_snd_create_track failed");
 
-    portTrackOutCtx->isRaw = false;
+    portTrackOutCtx->isRaw = IsRawFormat(portTrackOutCtx->inputAttr.audioFormat);
 #else
     MEDIA_HAL_UNUSED(portOutCtx);
     MEDIA_HAL_UNUSED(portTrackOutCtx);
index a21a5b8..b9f59e9 100644 (file)
@@ -365,10 +365,10 @@ int32_t AudioCaptureCaptureFrame(struct AudioCapture *capture, void *frame,
     }
     int32_t ret = hwCapture->trackHandle->AcquireFrame(hwCapture->trackHandle, frame, requestBytes, replyBytes);
     if (ret != MEDIA_HAL_OK) {
-        if (ret != MEDIA_HAL_ERR_AGAIN) {
+        if (ret != MEDIA_HAL_ERR_AGAIN &&
+            ret != MEDIA_HAL_NOT_SUPPORT_GET_MULT_FRAME) {
             MEDIA_HAL_LOGE(MODULE_NAME, "AudioPortTrack AcquireFrame failed: 0x%x", ret);
         }
-
         MediaHalMutexUnLock(hwCapture->mutex);
         return ret;
     }
index 5e4c4e7..9bb1600 100644 (file)
@@ -265,7 +265,7 @@ int32_t HwCameraStreamsCreate(uint32_t cameraId,
     *streamIdList = ONLY_ONE_CAMERA_DEVICE - 1;
     DemuxerSource source = { 0 };
     source.type = DEMUXER_SOURCE_TYPE_URI;
-    if (strcpy_s(source.url, PLUGIN_URL_LEN, g_hwCameraContext.url) != EOK) {
+    if (strcpy_s(source.url, URL_LEN, g_hwCameraContext.url) != EOK) {
         MEDIA_HAL_LOGE(MODULE_NAME, "strcpy_s failed");
         MediaHalMutexUnLock(g_mutex);
         return MEDIA_HAL_ERR;
index 1aebeec..3d22114 100644 (file)
@@ -311,9 +311,6 @@ static int32_t NativeDoDecode(jpeg_decompress_ptr dinfo, OutputInfo *curOutBuffe
     dst.uv_offset = dinfo->output.size[0];
     dst.vir_buf = (td_char *)curOutBuffer->buffers[0].addr;
     dst.phy_buf = (td_u32)(uintptr_t)dst.vir_buf;
-    if (memset_s(dst.vir_buf, curOutBuffer->buffers[0].length, 0, curOutBuffer->buffers[0].length) != EOK) {
-        MEDIA_HAL_LOGE(MODULE_NAME, "memset_s failed");
-    }
 
     uint64_t startTime = GetTimeTicks64();
     int32_t ret = uapi_jpeg_decompress_start(dinfo, &dst);
index a494ca8..58fd758 100644 (file)
@@ -41,6 +41,7 @@ typedef void* HalHandle;
 #define MEDIA_HAL_PERMISSION_DENIED (-5)
 #define MEDIA_HAL_TIMEOUT (-6)
 #define MEDIA_HAL_ERR_AGAIN (-7)
+#define MEDIA_HAL_NOT_SUPPORT_GET_MULT_FRAME (-8)
 
 #define MEDIA_HAL_LOG_ENABLE  1
 #define MEDIA_HAL_UNUSED(x) ((void)(x))
@@ -247,6 +248,9 @@ int64_t CalcDiffTimeUs(struct timeval begin, struct timeval end);
 bool MediaHalIntMulIsOverflow64(const int64_t a, const int64_t b, int64_t *value);
 
 void *MediaMallocz(uint32_t len);
+void *MediaHalMalloc(const size_t bytesNum);
+void *MediaHalCalloc(const size_t bytesNum);
+void MediaHalFree(const void *src);
 
 int32_t MediaHalConvertUSecToSecAndNSec(int64_t usec, int64_t *sec, int64_t *nsec);
 
index ceb8219..431826c 100644 (file)
@@ -215,7 +215,6 @@ void *MediaMallocz(uint32_t len)
     if (len == 0) {
         return NULL;
     }
-
     void *ptr = malloc(len);
     if (ptr == NULL) {
         MEDIA_HAL_LOGE(MODULE_NAME, "malloc failed");
@@ -224,13 +223,45 @@ void *MediaMallocz(uint32_t len)
 
     if (memset_s(ptr, len, 0, len) != EOK) {
         MEDIA_HAL_LOGE(MODULE_NAME, "memset_s failed");
-        free(ptr);
+        MediaHalFree(ptr);
         return NULL;
     }
 
     return ptr;
 }
 
+void *MediaHalMalloc(const size_t bytesNum)
+{
+    if (bytesNum == 0) {
+        return NULL;
+    }
+    void *ptr = malloc(bytesNum);
+    return ptr;
+}
+
+void *MediaHalCalloc(const size_t bytesNum)
+{
+    void *tmp = malloc(bytesNum);
+    if (tmp == NULL) {
+        return NULL;
+    }
+
+    if (memset_s(tmp, bytesNum, 0, bytesNum) != EOK) {
+        MediaHalFree(tmp);
+        return NULL;
+    } else {
+        return tmp;
+    }
+}
+
+void MediaHalFree(const void *src)
+{
+    if (src == NULL) {
+        return;
+    }
+    free((void *)src);
+}
+
 uint64_t GetTimeTicks64(void)
 {
     struct timespec stTv = { 0, 0 };
index 593481c..eee71f0 100644 (file)
@@ -213,6 +213,8 @@ typedef struct {
     MediaHalThreadIdHandle mainId;
     MediaHalThreadIdHandle subId;
     bool detached;
+       MediaHalThreadCondHandle cond;
+    void *stackMem;
 } MediaHalThreadMember;
 
 #define THREAD_MANAGER_MAX_CNT 10
@@ -246,40 +248,50 @@ static uint32_t MediaHalGetThreadManagerIdxFromIdHandle(const MediaHalThreadIdHa
     return UINT32_MAX;
 }
 
+static void HalFreeStackMemory(MediaHalThreadMember *member)
+{
+    if (member != NULL && member->stackMem != NULL) {
+        free(member->stackMem);
+        member->stackMem = NULL;
+    }
+}
+
 #define THREAD_EVENT_EXIT_FLAG 0x45584954U /* EXIT ascii */
+#ifdef CMSIS_SUPPORT
 static void MediaHalThreadFunc(void *arg)
+#else
+static void *MediaHalThreadFunc(void *arg)
+#endif
 {
     if (arg == NULL) {
+#ifdef CMSIS_SUPPORT
         return;
+#else
+        return NULL;
+#endif
     }
-
+    MediaHalThreadMember *member = (MediaHalThreadMember *)arg;
+    member->process(member->argument);
     MediaHalMutexLock(g_mediaHalThreadManagerLock);
-    MediaHalThreadMember member = {};
-    if (memcpy_s(&member, sizeof(MediaHalThreadMember), arg, sizeof(MediaHalThreadMember)) != EOK) {
-        MEDIA_HAL_LOGE(MODULE_NAME, "memcpy_s failed");
-        return;
-    }
-
-    MediaHalMutexUnLock(g_mediaHalThreadManagerLock);
-
-    member.process(member.argument);
-
-#ifdef CMSIS_SUPPORT
-#ifndef CMSIS_SUPPORT_JOIN
-    if (!member.detached) {
-        osThreadFlagsSet(member.mainId, THREAD_EVENT_EXIT_FLAG);
-    }
-#endif
-#endif
-    if (member.detached) {
-        MediaHalMutexLock(g_mediaHalThreadManagerLock);
-        uint32_t idx = MediaHalGetThreadManagerIdxFromIdHandle(member.subId);
+    if (member->detached) {
+        uint32_t idx = MediaHalGetThreadManagerIdxFromIdHandle(member->subId);
         if (idx < THREAD_MANAGER_MAX_CNT) {
             g_mediaHalThreadManager[idx] = NULL;
         }
+        MediaHalThreadCondDestroy(&member->cond);
+        HalFreeStackMemory(member);
         free(arg);
-        MediaHalMutexUnLock(g_mediaHalThreadManagerLock);
+    } else {
+#ifdef CMSIS_SUPPORT
+#ifndef CMSIS_SUPPORT_JOIN
+        MediaHalThreadCondSignal(member->cond);
+#endif
+#endif
     }
+    MediaHalMutexUnLock(g_mediaHalThreadManagerLock);
+#ifndef CMSIS_SUPPORT
+    return NULL;
+#endif
 }
 
 static int32_t MediaHalDoCreateThread(MediaHalThreadMember *member, const MediaHalThreadattr *attr)
@@ -292,9 +304,19 @@ static int32_t MediaHalDoCreateThread(MediaHalThreadMember *member, const MediaH
 #ifdef CMSIS_SUPPORT_JOIN
         uint32_t attrBits = attr->detached ? osThreadDetached : osThreadJoinable;
 #else
+        if (!attr->detached) {
+            member->cond = MediaHalThreadCondCreate();
+            if (member->cond == NULL) {
+                return -1;
+            }
+        }
         uint32_t attrBits = osThreadDetached;
 #endif
         osThreadAttr_t taskAttr = { attr->name, attrBits, NULL, 0, NULL, attr->stackSize, osPriorityNormal, 0, 0 };
+        if (strcmp(attr->name, "BufferThread") == 0) {
+            taskAttr.stack_mem = memalign(16, attr->stackSize); // 16字节对齐,申请内存到psram
+            member->stackMem = taskAttr.stack_mem;
+        }
         MediaHalSetCmsisThreadPriorityAttr(&taskAttr, attr->prioty);
         subId = osThreadNew(MediaHalThreadFunc, member, &taskAttr);
     }
@@ -309,7 +331,10 @@ static int32_t MediaHalDoCreateThread(MediaHalThreadMember *member, const MediaH
 
     pthread_t thdId = 0;
     if (pthread_create(&thdId, pTaskAttr, MediaHalThreadFunc, member) != 0) {
-        MEDIA_HAL_LOGE(MODULE_NAME, "pthread_create fail!");
+        if (needSetAttr) {
+            (void)pthread_attr_destroy(&taskAttr);
+        }
+        return -1;
     }
     if (needSetAttr) {
         (void)pthread_attr_destroy(&taskAttr);
@@ -344,7 +369,9 @@ MediaHalThreadIdHandle MediaHalThreadCreate(MediaHalThreadFunType func, void *ar
     member->argument = argument;
     member->mainId = MediaHalThreadGetId();
     member->detached = attr != NULL ? attr->detached : false;
+    member->stackMem = NULL;
     if (MediaHalDoCreateThread(member, attr) != 0) {
+        HalFreeStackMemory(member);
         free(member);
         goto EXIT;
     }
@@ -374,12 +401,6 @@ void MediaHalThreadJoin(MediaHalThreadIdHandle *thdId)
 #ifdef CMSIS_SUPPORT
 #ifdef CMSIS_SUPPORT_JOIN
     osThreadJoin((osThreadId_t)*thdId);
-#else
-    /*
-     * MediaHalThreadMember *member = *thdId;
-     * osThreadJoin not support join, can use osThreadFlagsSet/osThreadFlagsWait replace
-     */
-    osThreadFlagsWait(THREAD_EVENT_EXIT_FLAG, osFlagsWaitAll, osWaitForever);
 #endif
 #else
     pthread_join((pthread_t)(uintptr_t)*thdId, NULL);
@@ -390,10 +411,18 @@ void MediaHalThreadJoin(MediaHalThreadIdHandle *thdId)
         MediaHalThreadMember *member = g_mediaHalThreadManager[idx];
         if (member != NULL && member->detached) { /* detach sub thread, will free handle after sub thread exit */
             *thdId = NULL;
+            HalFreeStackMemory(member);
             MediaHalMutexUnLock(g_mediaHalThreadManagerLock);
             return;
         }
+#ifdef CMSIS_SUPPORT
+#ifndef CMSIS_SUPPORT_JOIN
+        MediaHalThreadCondWait(member->cond, g_mediaHalThreadManagerLock);
+        MediaHalThreadCondDestroy(&member->cond);
+#endif
+#endif
         g_mediaHalThreadManager[idx] = NULL;
+        HalFreeStackMemory(member);
         free(member);
     }
     MediaHalMutexUnLock(g_mediaHalThreadManagerLock);
index 0b86053..4b77b7d 100644 (file)
@@ -4,18 +4,31 @@
 #===============================================================================\r
 set(COMPONENT_NAME "format_hw")\r
 \r
-set(COMPONENT_DIR ${ROOT_DIR}/middleware/services/media/component/hmf_demuxer)\r
+set(HMF_DMX_DIR ${ROOT_DIR}/middleware/services/media/component/hmf_demuxer)\r
+set(FFMPEG_DIR ${ROOT_DIR}/middleware/services/media/component/ffmpeg_adp)\r
 if (EXISTS ${COMPONENT_DIR})\r
     add_subdirectory(plugins/hmf_demuxer)\r
     add_subdirectory(plugins/protocol_https)\r
     add_subdirectory(plugins/mjpeg_demuxer)\r
 endif()\r
+if (EXISTS ${FFMPEG_DIR})\r
+    add_subdirectory(plugins/ffmpeg_demuxer)\r
+endif()\r
 add_subdirectory(plugins/raw_demuxer)
+add_subdirectory(plugins/raw_muxer)\r
+add_subdirectory(plugins/wav_muxer)\r
+add_subdirectory(plugins/ogg_muxer)\r
+add_subdirectory(plugins/common/dtcf)\r
+add_subdirectory(plugins/common/dtcf_manager)\r
 add_subdirectory(src/decrypt)\r
 # use build env and option camke\r
 include(../../build/build_env.cmake)\r
 include(../../build/build_option.cmake)\r
 \r
+if (NOT "JS_ENABLE" IN_LIST DEFINES)\r
+    option(ENABLE_BUFFER_MANAGER "buffer manager" ON)\r
+endif()\r
+\r
 set(SOURCES\r
     ${CMAKE_CURRENT_SOURCE_DIR}/src/format_manager.c\r
     ${CMAKE_CURRENT_SOURCE_DIR}/src/demuxer_manager/src/demuxer_manager.c\r
@@ -27,6 +40,11 @@ set(SOURCES
     ${CMAKE_CURRENT_SOURCE_DIR}/src/protocol_plugins_manager/src/protocol_plugins_manager.c\r
 )\r
 \r
+if(ENABLE_BUFFER_MANAGER)\r
+    set(SOURCES ${SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/src/demuxer_manager/src/demuxer_buffer.c)\r
+    set(CDEFINES ${CDEFINES} "ENABLE_BUFFER_MANAGER")\r
+endif()\r
+\r
 set(PUBLIC_HEADER\r
 )\r
 \r
@@ -41,14 +59,22 @@ set(PRIVATE_HEADER
     ${CMAKE_CURRENT_SOURCE_DIR}/src/protocol_plugins_manager/include\r
     ${CMAKE_CURRENT_SOURCE_DIR}/plugins/hmf_demuxer\r
     ${CMAKE_CURRENT_SOURCE_DIR}/plugins/raw_demuxer
+    ${CMAKE_CURRENT_SOURCE_DIR}/plugins/ffmpeg_demuxer\r
     ${CMAKE_CURRENT_SOURCE_DIR}/../common/include\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/plugins/wav_muxer\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/plugins/raw_muxer\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/plugins/ogg_muxer\r
     ${ROOT_DIR}/open_source/openharmony/drivers/peripheral/format/interfaces/include\r
 )\r
 \r
-set(CDEFINES ${CDEFINES} "ENABLE_DEMUXER" "ENABLE_PROTOCOL_PLUGIN")\r
-set(PRIVATE_DEFINES\r
-    ${CDEFINES}\r
-)\r
+ set(CDEFINES ${CDEFINES} "ENABLE_DEMUXER" "-DENABLE_MUXER" "ENABLE_PROTOCOL_PLUGIN")\r
+\r
+ if("${CHIP}" STREQUAL "brandy")\r
+    set(CDEFINES ${CDEFINES} "CONFIG_SUPPORT_FILESYSTEM" "PRE_ASIC")\r
+ endif()\r
+ set(PRIVATE_DEFINES\r
+     ${CDEFINES}\r
+ )\r
 \r
 set(PUBLIC_DEFINES\r
 )\r
index ed20e3f..1b6532c 100644 (file)
@@ -36,6 +36,7 @@ typedef struct {
 } StreamResolution;
 
 typedef struct {
+    char *formatName;  /**< File format name, in the unit of byte. */
     int64_t s64FileSize;  /* File size, in the unit of byte. */
     int64_t s64StartTime; /* the media file begin time */
     int64_t s64Duration;  /* Total duration of a file, in the unit of ms. */
index d0e45e4..4454d81 100644 (file)
@@ -75,7 +75,7 @@ typedef struct {
     uint64_t offset; /* Local file descriptor */
     union {
         int fd; /* Local file descriptor */
-        char url[PLUGIN_URL_LEN]; /* Network URI or local file path. The maximum length is
+        char url[URL_LEN]; /* Network URI or local file path. The maximum length is
                                    * specified by <b>URL_LEN</b>. */
         DemuxerBufferStream stream; /* Pointer to the function for reading buffer stream data */
     };
index 011c24c..1336006 100644 (file)
@@ -29,7 +29,7 @@ typedef struct {
     OutType type;        /* Output type. For details, see {@link OutputType}. */
     union {
         int32_t fd;         /* File descriptor */
-        char url[PLUGIN_URL_LEN];  /* File path. For details, see {@link URL_LEN}. */
+        char url[URL_LEN];  /* File path. For details, see {@link URL_LEN}. */
     };
     FormatType format;    /* File format */
 } MuxerOutput;
index 6bb08e5..7d29451 100644 (file)
@@ -20,7 +20,7 @@ extern "C" {
 
 #define MIN_FILE_SURFIX_LEN  2
 #define MAX_FILE_SURFIX_LEN  32
-#define PLUGIN_URL_LEN 4096 /* Indicates the URL length. */
+#define URL_LEN 256 /* Indicates the URL length. */
 
 typedef struct {
     uint32_t codecId;
@@ -45,8 +45,12 @@ typedef struct {
 
 typedef enum {
     INVOKE_SET_CALLBACK, /* 设置回调函数 */
-    INVOKE_SET_SPIT_CONFIG, /* 设置紧急分片属性 */
-    INVOKE_SET_BUFFER_CONFIG, /* 设置网络缓存信息 */
+    INVOKE_SET_DELETE_OLD_FILES_ENABLE, /* Setting whether to delete old files */
+    INVOKE_SET_MAX_STORAGE_THRESHOLD, /* Setting the Maximum Storage Space Threshold */
+    INVOKE_RECORDE_WRITE_MARKS,
+    INVOKE_CURRENT_STORAGE_REMAIND_TIME, /* Obtains the remaining time of the current storage space. */
+    INVOKE_CURRENT_FILE_REMAIND_TIME, /* Obtains the remaining recording time of the current file. */
+    INVOKE_CURRENT_FILE_INFO,
     INVOKE_SET_LOCATION, /* 设置位置信息 */
     INVOKE_SET_DEGREE, /* 设置角度信息 */
     INVOKE_SET_LOG_LEVEL, /* 设置日志级别 */
@@ -189,6 +193,9 @@ typedef enum {
     FORMAT_TYPE_THREE_GPP = 2, /* 3GPP */
     FORMAT_TYPE_HEIF = 3, /* HEIF */
     FORMAT_TYPE_OGG = 4, /* Ogg */
+    FORMAT_TYPE_WAV = 5, /* Wav */
+    FORMAT_TYPE_MP3 = 6, /* Mp3 */
+    FORMAT_TYPE_SILK = 7, /* Silk */
     FORMAT_TYPE_INVALID /* Invalid format */
 } FormatType;
 
@@ -233,6 +240,7 @@ typedef enum {
                                               */
     DEMUXER_NETWORK_DISCONNECTED,       /* The network is disconnected during network playback. */
     DEMUXER_NETWORK_RECONNECTED,        /* The network is automatically reconnected during network playback. */
+    MAX_MEMORYSIZE_REACHED,             /* Maximum storage space has been reached. */
 } PluginInfoType;
 
 
@@ -265,6 +273,18 @@ typedef struct {
     int (*protocol_close)(void *handle);
 } ProtocolFun;
 
+typedef struct {
+    char fileName[URL_LEN];
+    uint64_t fileSize;
+    uint32_t fileDateYear;
+    uint32_t fileDateMonth;
+    uint32_t fileDateDay;
+    uint32_t fileDateHour;
+    uint32_t fileDateMin;
+    uint32_t fileDateSec;
+    uint32_t fileDuration;
+} MuxerFileInfo;
+
 #ifdef __cplusplus
 #if __cplusplus
 }
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/common/dtcf/CMakeLists.txt b/code/sdk/middleware/services/media/hal/format/plugins/common/dtcf/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1b9d615
--- /dev/null
@@ -0,0 +1,47 @@
+#===============================================================================\r
+# @brief    cmake file\r
+# Copyright (c) CompanyNameMagicTag 2022-2022. All rights reserved.\r
+#===============================================================================\r
+set(COMPONENT_NAME "dtcf")\r
+\r
+# use build env and option camke\r
+include(../../../../../build/build_env.cmake)\r
+include(../../../../../build/build_option.cmake)\r
+\r
+set(SOURCES\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/dtcf.c\r
+)\r
+\r
+set(PUBLIC_HEADER\r
+)\r
+\r
+set(PRIVATE_HEADER\r
+    ${CMAKE_CURRENT_SOURCE_DIR}\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/include\r
+)\r
+\r
+set(CDEFINES ${CDEFINES} "CMSIS_SUPPORT")\r
+set(PRIVATE_DEFINES\r
+    ${CDEFINES}\r
+)\r
+\r
+set(PUBLIC_DEFINES\r
+)\r
+\r
+# use this when you want to add ccflags like -include xxx\r
+set(COMPONENT_PUBLIC_CCFLAGS\r
+)\r
+\r
+set(COMPONENT_CCFLAGS\r
+)\r
+\r
+set(WHOLE_LINK\r
+    true\r
+)\r
+\r
+set(MAIN_COMPONENT\r
+    false\r
+)\r
+set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib/media/${BOARD}_${APPLICATION}/${OS}/${COMPONENT_NAME})\r
+\r
+build_component()
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/common/dtcf/include/dtcf.h b/code/sdk/middleware/services/media/hal/format/plugins/common/dtcf/include/dtcf.h
new file mode 100644 (file)
index 0000000..4f21210
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: dtcf
+* Author: Media Software Group
+* Create: 2025-09-20
+*/
+
+#ifndef DTCF_H_
+#define DTCF_H_
+#include <stdint.h>
+#include <time.h>
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** \addtogroup     DTCF */
+/* [DTCF] */
+
+#define MODULE_NAME_DTCF  "DTCF"
+
+#define FILE_PATH_LEN_MAX         (256)
+#define DIR_LEN_MAX               (64)
+
+/* DataTime Error number base */
+#define DTCF_ERRNO_BASE 0x2A00
+/* Parameter is invalid */
+#define DTCF_ERR_EINVAL_PARAMETER    (DTCF_ERRNO_BASE + 1)
+/* Null pointer */
+#define DTCF_ERR_NULL_PTR            (DTCF_ERRNO_BASE + 2)
+/* failure caused by malloc memory */
+#define DTCF_ERR_NOMEM               (DTCF_ERRNO_BASE + 3)
+/* not support file path */
+#define DTCF_UNSUPPORT_PATH          (DTCF_ERRNO_BASE + 4)
+/* the same directory */
+#define DTCF_SAME_DIR_PATH           (DTCF_ERRNO_BASE + 5)
+/* Status error, operation not allowed */
+#define DTCF_ERR_STATUS_ERROR        (DTCF_ERRNO_BASE + 6)
+/* Empty directory */
+#define DTCF_ERR_EMPTEY_DIR          (DTCF_ERRNO_BASE + 7)
+/* directory not define */
+#define DTCF_ERR_UNDEFINE_DIR        (DTCF_ERRNO_BASE + 8)
+/* System error */
+#define DTCF_ERR_SYSTEM_ERROR        (DTCF_ERRNO_BASE + 9)
+/* the same filename */
+#define DTCF_SAME_FILENAME_PATH      (DTCF_ERRNO_BASE + 10)
+/* the path is not a directory */
+#define DTCF_PATH_IS_NDIR_ERROR   (DTCF_ERRNO_BASE + 11)
+
+/**
+ * File Directory Type
+ */
+typedef enum {
+    DTCF_DIR_RECORD_WAV_FILE,
+    DTCF_DIR_RECORD_MP3_FILE,
+    DTCF_DIR_RECORD_SILK_FILE,
+    DTCF_DIR_RECORD_OGG_FILE,
+    DTCF_DIR_BUTT,
+} DTCF_DIR_E;
+
+/**
+ * File Type.
+ */
+typedef enum {
+    DTCF_FILE_TYPE_WAV,
+    DTCF_FILE_TYPE_MP3,
+    DTCF_FILE_TYPE_SILK,
+    DTCF_FILE_TYPE_OGG,
+    DTCF_FILE_TYPE_BUTT
+} DTCF_FILE_TYPE_E;
+
+/**
+  *    @brief init DTCF
+  *
+  *    init DTCF
+  *    @param[in]  pazRootDir:  root of DTCF
+  *    @return     0 success, non-zero error code
+  */
+int32_t DtcfInit(const char *pazRootDir);
+
+/**
+  *    @brief DeInit DTCF
+  *
+  *    DeInit DTCF
+  *    @return     0 success, non-zero error code
+  */
+int32_t DtcfDeInit(void);
+
+/**
+  *    @brief scan files
+  *
+  *    scan files in some directories.
+  *    @param[in]    enDirs:  directories to scan.
+  *    @param[in]    u32DirCount: count of directory.
+  *    @param[out]   pu32FileAmount:files amount.
+  *    @return       0 success, non-zero error code
+  */
+int32_t DtcfScanFiles(const DTCF_DIR_E enDirs[], uint32_t u32DirCount, uint32_t *pu32FileAmount);
+
+/**
+  *    @brief create file full path
+  *    @param[in]    enFileType:  type of file.
+  *    @param[in]    enDir: type of directory.
+  *    @param[out]   pazFilePath: file full path.
+  *    @param[in]   u32Length: file full path length.
+  *    @return       0 success, non-zero error code
+  */
+int32_t DtcfCreateFilePath(DTCF_FILE_TYPE_E enFileType, DTCF_DIR_E enDir,
+    char *pazFilePath, uint32_t u32Length);
+
+/**
+  *    @brief get related file full path.
+  *    @param[in]    pazSrcFilePath:  source file full path.
+  *    @param[in]    enDir: related file directory.
+  *    @param[out]   pazDstFilePath : related file full path.
+  *    @param[in]   u32Length: file full path length.
+  *    @return       0 success, non-zero error code
+  */
+int32_t DtcfGetRelatedFilePath(const char *pazSrcFilePath, DTCF_DIR_E enDir,
+    char *pazDstFilePath, uint32_t u32Length);
+
+/**
+  *    @brief get current file time.
+  *    @param[in]    fileTime:  struct to get file time.
+  *    @return       0 success, non-zero error code
+  */
+int32_t DtcfGetCurrentFileTime(struct tm *fileTime);
+
+int32_t DtcfGetOldestFilePath(DTCF_DIR_E enDir, char *pazFilePath, uint32_t u32Length);
+
+int32_t DtcfMakeFileDir(char *pazFilePath, uint32_t u32Length);
+
+int32_t CheckToMkdirForInit(DTCF_DIR_E dirType);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* DTCF_H_ */
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/common/dtcf/include/dtcf_qsort.h b/code/sdk/middleware/services/media/hal/format/plugins/common/dtcf/include/dtcf_qsort.h
new file mode 100644 (file)
index 0000000..e894ecc
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: dtcf qsort
+* Author: Media Software Group
+* Create: 2025-09-20
+*/
+
+#ifndef DTCF_QSORT_H_
+#define DTCF_QSORT_H_
+
+#include <stddef.h>
+
+#define MIN(A, B) (A) < (B) ? (A) : (B)
+
+static inline void Swap(char *a, char *b, int n)
+{
+    long i = n;
+    char *pi = a;
+    char *pj = b;
+    if (a < b) {
+        pi = a + n - 1;
+        pj = b + n - 1;
+    }
+    do {
+        char t = *pi;
+        *pi-- = *pj;
+        *pj-- = t;
+    } while (--i > 0);
+}
+
+static inline void VecSwap(char *a, char *b, int n)
+{
+    if (n > 0) {
+        Swap(a, b, n);
+    }
+}
+
+static inline char *Med3(char *a, char *b, char *c, int (*cmp)(const void *a, const void *b))
+{
+    return cmp(a, b) < 0 ? (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a)) :
+                           (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c));
+}
+
+static void SubSwap(char *a, size_t n, size_t es, int (*cmp)(const void *a, const void *b))
+{
+    char *pm = a + (n / 2) * es; // 2:get mid pointer
+    if (n > 7) { // 7: sort list big than 7
+        char *pl;
+        char *pn;
+        pl = a;
+        pn = a + (n - 1) * es;
+        if (n > 40) { // 40: sort list big than 40
+            int d = (n / 8) * es; // 8: 1/8 of n as distance
+            pl = Med3(pl, pl + d, pl + 2 * d, cmp); // 2: double distance
+            pm = Med3(pm - d, pm, pm + d, cmp);
+            pn = Med3(pn - 2 * d, pn - d, pn, cmp); // 2:doubule distance
+        }
+        pm = Med3(pl, pm, pn, cmp);
+    }
+    Swap(a, pm, es);
+}
+
+void Qsort(void *a, size_t n, size_t es, int (*cmp)(const void *a, const void *b))
+{
+    char *pa, *pb, *pc, *pd, *pn;
+    int ret;
+
+    SubSwap(a, n, es, cmp);
+
+    pa = pb = a;
+    pc = pd = (char *)a + (n - 1) * es;
+    for (;;) {
+        while (pb <= pc && (ret = cmp(pb, a)) <= 0) {
+            if (ret == 0) {
+                Swap(pa, pb, es);
+                pa += es;
+            }
+            pb += es;
+        }
+        while (pc >= pb && (ret = cmp(pc, a)) >= 0) {
+            if (ret == 0) {
+                Swap(pc, pd, es);
+                pd -= es;
+            }
+            pc -= es;
+        }
+
+        if (pb > pc) {
+            break;
+        }
+        Swap(pb, pc, es);
+        pb += es;
+        pc -= es;
+    }
+
+    pn = (char *)a + n * es;
+    ret = MIN(pa - (char *)a, pb - pa);
+    VecSwap(a, pb - ret, ret);
+    ret = MIN(pd - pc, pn - pd - (int)es);
+    VecSwap(pb, pn - ret, ret);
+    if ((ret = pb - pa) > (int)es) {
+        qsort(a, ret / es, es, cmp);
+    }
+
+    if ((ret = pd - pc) > (int)es) {
+        qsort(pn - ret, ret / es, es, cmp);
+    }
+}
+
+#endif /* DTCF_QSORT_H_ */
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/common/dtcf/src/dtcf.c b/code/sdk/middleware/services/media/hal/format/plugins/common/dtcf/src/dtcf.c
new file mode 100644 (file)
index 0000000..daf02de
--- /dev/null
@@ -0,0 +1,836 @@
+/*
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: dtcf
+* Author: Media Software Group
+* Create: 2025-09-20
+*/
+
+#include "dtcf.h"
+#include <dirent.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "securec.h"
+#include "dtcf_qsort.h"
+#include "media_hal_common.h"
+#include "media_hal_thread_adapt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef MW_VERSION
+#define MW_VERSION "0.0.0"
+#endif
+
+// default directory name
+#define WAV_DIR          "wav"
+#define MP3_DIR          "mp3"
+#define SILK_DIR         "silk"
+#define OGG_DIR          "ogg"
+
+#define DTCF_DIR_MODE    (0760)
+
+#define FILE_SUFFIX_LEN_MAX       (8)
+
+#define DTCF_TIME_STR_LEN         (20)
+#define FILE_NAME_LEN_MIN         (23) // e.g. YYYY_MM_DD_HHMMSS_XX.TS
+
+#define DTCF_SCAN_FILE_AMOUNT_MAX (10 * 1024) // 10240
+
+#define CHECK_DTCF_NULL_PTR(ptr) \
+    do { \
+        if ((ptr) == NULL) \
+        { \
+            MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "DTCF NULL pointer\n"); \
+            return DTCF_ERR_NULL_PTR; \
+        } \
+    } while (0)
+
+typedef enum {
+    DTCF_STATUS_CREATED = 0,
+    DTCF_STATUS_SCANED,
+    DTCF_STATUS_DESTROY,
+    DTCF_STATUS_BUTT
+} DTCF_STATUS_E;
+
+
+typedef struct {
+    char azTmpDir[FILE_PATH_LEN_MAX];
+    uint32_t u32DirNameLen;
+    DTCF_DIR_E enDir;
+    DTCF_FILE_TYPE_E enType;
+    char azTimeStr[DTCF_TIME_STR_LEN + 1];
+} DTCF_TEMP_DIR_S;
+
+typedef struct {
+    struct dirent *pdirent;
+    DTCF_DIR_E enDir;
+} DTCF_DIRENT_S;
+
+typedef struct {
+    DTCF_DIRENT_S *pstDirentList;
+    uint32_t u32DirentlistCount;
+    uint32_t u32listCount;
+    DTCF_DIR_E enScanDirs[DTCF_DIR_BUTT];
+    uint32_t u32ScanDirCount;
+} DTCF_SCAN_FILE_LIST_S;
+
+static DTCF_SCAN_FILE_LIST_S g_dtcfScanFileList = {NULL, 0, 0, {0}, 0};
+
+static char g_azRootDir[FILE_PATH_LEN_MAX] = {0};
+static DTCF_STATUS_E g_dtcfStatu = DTCF_STATUS_BUTT;
+static MediaHalMutexHandle g_dtcfInterfaceLock = NULL;
+
+static struct tm g_lastTime = {};
+static int32_t g_num = -1;
+
+static char g_azDirNames[DTCF_DIR_BUTT][DIR_LEN_MAX] = {
+    WAV_DIR,
+    MP3_DIR,
+    SILK_DIR,
+    OGG_DIR
+};
+
+static char g_szFileTypeSuffix[DTCF_FILE_TYPE_BUTT][FILE_SUFFIX_LEN_MAX] = {
+    "wav",
+    "mp3",
+    "silk",
+    "ogg",
+};
+
+static char g_szFileNameSuffix[DTCF_DIR_BUTT][FILE_SUFFIX_LEN_MAX] = {
+    "",
+};
+
+static int32_t CheckDtcfStatusCreate(void)
+{
+    if ((g_dtcfStatu != DTCF_STATUS_CREATED) && (g_dtcfStatu != DTCF_STATUS_SCANED)) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF,
+            "status is not DTCF_STATUS_CREATED|DTCF_STATUS_SCANED, current status:%d\n", g_dtcfStatu);
+        return DTCF_ERR_STATUS_ERROR;
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t CheckDtcfStatusScan(void)
+{
+    if (g_dtcfStatu != DTCF_STATUS_SCANED) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "status is not DTCF_STATUS_SCANED, current status:%d\n", g_dtcfStatu);
+        return DTCF_ERR_STATUS_ERROR;
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t CheckDtcfPathIsDir(const char *path)
+{
+    struct stat sBuf = {0};
+    if (stat(path, &sBuf) != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, " stat sys errno:%d\n", errno);
+        return DTCF_ERR_SYSTEM_ERROR;
+    }
+    if (!S_ISDIR(sBuf.st_mode)) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "%s is not a directory\n", path);
+        return DTCF_PATH_IS_NDIR_ERROR;
+    }
+    return MEDIA_HAL_OK;
+}
+
+static void DtcfThreadMutexLock(void)
+{
+    MediaHalInitStaticMutexLock(&g_dtcfInterfaceLock);
+    MediaHalMutexLock(g_dtcfInterfaceLock);
+}
+
+static void DtcfThreadMutexUnLock(void)
+{
+    if (g_dtcfInterfaceLock != NULL) {
+        MediaHalMutexUnLock(g_dtcfInterfaceLock);
+    }
+}
+
+static bool IsDigitChar(char c, const char min, const char max)
+{
+    if ((max < c) || (c < min)) {
+        return false;
+    }
+    return true;
+}
+
+static bool IsSameChar(const char c, const char target)
+{
+    if (c != target) {
+        return false;
+    }
+    return true;
+}
+
+static void DtcfFreeScanNameList(void)
+{
+    while (g_dtcfScanFileList.u32DirentlistCount > 0) {
+        g_dtcfScanFileList.u32DirentlistCount--;
+        if (g_dtcfScanFileList.pstDirentList[g_dtcfScanFileList.u32DirentlistCount].pdirent != NULL) {
+            free(g_dtcfScanFileList.pstDirentList[g_dtcfScanFileList.u32DirentlistCount].pdirent);
+            g_dtcfScanFileList.pstDirentList[g_dtcfScanFileList.u32DirentlistCount].pdirent = NULL;
+        }
+    }
+    free(g_dtcfScanFileList.pstDirentList);
+    g_dtcfScanFileList.pstDirentList = NULL;
+    g_dtcfScanFileList.u32DirentlistCount = 0;
+    g_dtcfScanFileList.u32ScanDirCount = 0;
+    g_dtcfScanFileList.u32listCount = 0;
+    int32_t ret = memset_s(&g_dtcfScanFileList.enScanDirs, sizeof(DTCF_DIR_E) * DTCF_DIR_BUTT,
+        0, sizeof(DTCF_DIR_E) * DTCF_DIR_BUTT);
+    if (ret != EOK) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "memset_s err: 0x%x\n", ret);
+        return;
+    }
+}
+
+static bool DtcfFileNameRuleCheckFileTypeSuffix(const char *pFileTypeSuffix, const uint32_t u32Len)
+{
+    uint32_t suffexLen, i;
+    for (i = 0; i < DTCF_FILE_TYPE_BUTT; i++) {
+        suffexLen = (uint32_t)strlen(g_szFileTypeSuffix[i]);
+        if ((strncmp(g_szFileTypeSuffix[i], pFileTypeSuffix, suffexLen) == 0) && (u32Len == suffexLen)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static bool DtcfFileNameRuleCheckFileNameSuffix(const char *pFileNameSuffix, const uint32_t u32Len)
+{
+    if ((pFileNameSuffix[0] == 's') && (pFileNameSuffix[1] == '.')) {
+        return DtcfFileNameRuleCheckFileTypeSuffix(&pFileNameSuffix[2], u32Len - 2); /* 2: file suffix begin */
+    } else if (pFileNameSuffix[0] == 'b') {
+        if (pFileNameSuffix[1] == '.') {
+            return DtcfFileNameRuleCheckFileTypeSuffix(&pFileNameSuffix[2], u32Len - 2); /* 2: file suffix begin */
+        } else if ((pFileNameSuffix[1] == '_') && /* 1: the first letter of the string before the file type */
+            (pFileNameSuffix[2] == 's') && /* 2: the second letter of the string before the file type */
+            (pFileNameSuffix[3] == '.')) { /* 3: the third letter of the string before the file type */
+            return DtcfFileNameRuleCheckFileTypeSuffix(&pFileNameSuffix[4], u32Len - 4); /* 4: file suffix begin */
+        }
+    }
+    return false;
+}
+
+/**
+ * 1970_01_01_182605.MP4
+ * 1970_01_01_182605_s.MP4
+ * 1970_01_01_182605_b.MP4
+ * 1970_01_01_182605_b_s.MP4
+ */
+static bool CheckFileNameOtherpart(const char *pazPath)
+{
+    /* To fix [Cmetrics] dolphin, each char for checking will make cyclomatic complexity greater than 20. */
+    if ((IsSameChar(pazPath[10], '_')) &&        /* Check char array[10] of File name  */
+        (IsDigitChar(pazPath[11], '0', '9')) &&  /* Check char array[11] of File name  */
+        (IsDigitChar(pazPath[12], '0', '9')) &&  /* Check char array[12] of File name  */
+        (IsDigitChar(pazPath[13], '0', '9')) &&  /* Check char array[13] of File name  */
+        (IsDigitChar(pazPath[14], '0', '9')) &&  /* Check char array[14] of File name  */
+        IsDigitChar(pazPath[15], '0', '9') &&  /* Check char array[15] of File name  */
+        IsDigitChar(pazPath[16], '0', '9') &&  /* Check char array[16] of File name  */
+        IsSameChar(pazPath[17], '_') &&        /* Check char array[17] of File name  */
+        IsDigitChar(pazPath[18], '0', '9') &&  /* Check char array[18] of File name  */
+        IsDigitChar(pazPath[19], '0', '9')) {  /* Check char array[19] of File name  */
+            return true;
+        }
+        return false;
+}
+
+static bool IsFileNameRight(const char *pazPath)
+{
+    if (IsDigitChar(pazPath[0], '1', '9') &&   /* Check char array[0] of File name  */
+        IsDigitChar(pazPath[1], '0', '9') &&   /* Check char array[1] of File name  */
+        IsDigitChar(pazPath[2], '0', '9') &&   /* Check char array[2] of File name  */
+        IsDigitChar(pazPath[3], '0', '9') &&   /* Check char array[3] of File name  */
+        IsSameChar(pazPath[4], '_') &&         /* Check char array[4] of File name  */
+        IsDigitChar(pazPath[5], '0', '9') &&   /* Check char array[5] of File name  */
+        IsDigitChar(pazPath[6], '0', '9') &&   /* Check char array[6] of File name  */
+        IsSameChar(pazPath[7], '_') &&         /* Check char array[7] of File name  */
+        IsDigitChar(pazPath[8], '0', '9') &&   /* Check char array[8] of File name  */
+        IsDigitChar(pazPath[9], '0', '9') &&   /* Check char array[9] of File name  */
+        CheckFileNameOtherpart(pazPath)) {
+        return true;
+    }
+    return false;
+}
+
+static bool DtcfFileNameRuleCheck(const char *pazPath, const uint32_t u32Len)
+{
+    if (u32Len < FILE_NAME_LEN_MIN) {
+        return false;
+    }
+    // check string such as 1970_01_01_182605_00
+    if (!IsFileNameRight(pazPath)) {
+        return false;
+    }
+    switch (pazPath[20]) { /* Check char array[20] of File name  */
+        case '.': /* 20: check string such as 1970_01_01_182605_00.MP4 */
+            return DtcfFileNameRuleCheckFileTypeSuffix(&pazPath[21], u32Len - 21); /* 21: file suffix begin */
+        case '_': /* 20: check string such as 1970_01_01_182605_00_*.MP4 */
+            /* 21: file suffix with name rule tail */
+            return DtcfFileNameRuleCheckFileNameSuffix(&pazPath[21], u32Len - 21);
+        default:
+            return false;
+    }
+}
+
+static int32_t DtcfCheckRootDir(const char* pszRootDir)
+{
+    char aszPath[FILE_PATH_LEN_MAX] = {0};
+
+    uint32_t u32Len = (uint32_t)strlen(pszRootDir);
+    if ((u32Len >= FILE_PATH_LEN_MAX) || (u32Len == 0)) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "RootDir:%s too long", pszRootDir);
+        return DTCF_UNSUPPORT_PATH;
+    }
+
+    int32_t ret = snprintf_s(aszPath, FILE_PATH_LEN_MAX,
+        FILE_PATH_LEN_MAX - 1, "%s", pszRootDir);
+    if (ret < 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "RootDir:%s is invalid path", pszRootDir);
+        return DTCF_UNSUPPORT_PATH;
+    }
+
+    for (uint32_t i = 0; i < u32Len; i++) {
+        if ((i == 0) && (aszPath[i] != '/')) {
+            MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "RootDir:%s is invalid path", pszRootDir);
+            return DTCF_UNSUPPORT_PATH;
+        }
+
+        if (aszPath[i] == '/') {
+            continue;
+        }
+
+        if (!(((aszPath[i] >= 'a') && (aszPath[i] <= 'z')) ||
+            ((aszPath[i] >= 'A') && (aszPath[i] <= 'Z')) ||
+            ((aszPath[i] >= '0') && (aszPath[i] <= '9')) ||
+            (aszPath[i] == '_') || (aszPath[i] == '.'))) {
+            MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "RootDir:%s is invalid path", pszRootDir);
+            return DTCF_UNSUPPORT_PATH;
+        }
+    }
+
+    return MEDIA_HAL_OK;
+}
+
+static int32_t Selector(const struct dirent *dir)
+{
+    CHECK_DTCF_NULL_PTR(dir);
+    uint32_t len = (uint32_t)strlen(dir->d_name);
+    if (DtcfFileNameRuleCheck(dir->d_name, len)) {
+        return 1;
+    }
+    MEDIA_HAL_LOGI(MODULE_NAME_DTCF, "dir->d_name:%s\n", dir->d_name);
+    return MEDIA_HAL_OK;
+}
+
+static int32_t SortBydnameDesc(const void *a, const void *b)
+{
+    DTCF_DIRENT_S *aa = (DTCF_DIRENT_S *)a;
+    DTCF_DIRENT_S *bb = (DTCF_DIRENT_S *)b;
+    return strcmp(bb->pdirent->d_name, aa->pdirent->d_name);
+}
+
+static int32_t DtcfMkdir(const char *dir, mode_t mode)
+{
+    int32_t ret = mkdir(dir, mode);
+    if (ret < 0) {
+        if (errno == EEXIST) {
+            return CheckDtcfPathIsDir(dir);
+        } else {
+            MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "mkdir %s fail ret:%d\n", dir, ret);
+            MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "[%d] \n", errno);
+            return DTCF_ERR_EINVAL_PARAMETER;
+        }
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t DtcfMakedirs(const char *muldir, mode_t mode)
+{
+    uint32_t i;
+    uint32_t len;
+    char str[FILE_PATH_LEN_MAX + 1] = { 0 };
+    int32_t ret = strncpy_s(str, FILE_PATH_LEN_MAX + 1, muldir, FILE_PATH_LEN_MAX);
+    if (ret != EOK) {
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+    len = (uint32_t)strlen(str);
+    for (i = 0; i < len; i++) {
+        if ((i == 0) && (str[i] == '/')) {
+            continue;
+        }
+        if (str[i] == '/') {
+            str[i] = '\0';
+            ret = mkdir(str, mode);
+            if ((ret < 0) && (errno == EEXIST) && (CheckDtcfPathIsDir(str) == MEDIA_HAL_OK)) {
+                str[i] = '/';
+                continue;
+            } else if (ret < 0) {
+                MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "mkdir str:%s fail ret:%d\n", str, ret);
+                return ret;
+            }
+            str[i] = '/';
+        }
+    }
+    if (len <= 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "str len not enough\n");
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+    ret = mkdir(str, mode);
+    MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "str = %s", str);
+    if (ret < 0) {
+        if (errno == EEXIST) {
+            return CheckDtcfPathIsDir(str);
+        }
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, " stat sys errno:%d\n", errno);
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "mkdir str:%s fail ret:%d len:%u\n", str, ret, len);
+        return ret;
+    }
+    return MEDIA_HAL_OK;
+}
+
+static void DtcfResetDirNames(void)
+{
+    const char azDirNames[DTCF_DIR_BUTT][DIR_LEN_MAX] = {
+        WAV_DIR,
+    };
+    if (memcpy_s(g_azDirNames, sizeof(g_azDirNames), azDirNames,
+        sizeof(char) * DIR_LEN_MAX * DTCF_DIR_BUTT) != EOK) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "reset dtcf dir name failed\n");
+        return;
+    }
+    g_azRootDir[0] = '\0';
+}
+
+static int32_t DtcfExpandFileList(uint32_t u32size)
+{
+    uint32_t u32ChangePoit = 10;
+    if ((g_dtcfScanFileList.u32DirentlistCount + u32size) > DTCF_SCAN_FILE_AMOUNT_MAX) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "u32DirentlistCount:%d +  u32size:%u > DTCF_SCAN_FILE_AMOUNT_MAX:%d\n",
+            g_dtcfScanFileList.u32DirentlistCount, u32size, DTCF_SCAN_FILE_AMOUNT_MAX);
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+
+    if ((g_dtcfScanFileList.u32DirentlistCount + u32size) >= g_dtcfScanFileList.u32listCount) {
+        while (u32ChangePoit < DTCF_SCAN_FILE_AMOUNT_MAX) {
+            if (u32ChangePoit < (g_dtcfScanFileList.u32DirentlistCount + u32size)) {
+                u32ChangePoit = u32ChangePoit * 2; /* 2: add fileList size */
+            } else {
+                break;
+            }
+        }
+        DTCF_DIRENT_S *newDirEnt = (DTCF_DIRENT_S *) malloc ((u32ChangePoit) * sizeof(DTCF_DIRENT_S));
+        if (newDirEnt == NULL) {
+            MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "malloc mem error, errno:%d\n", errno);
+            return DTCF_ERR_SYSTEM_ERROR;
+        }
+        if (memset_s(newDirEnt, u32ChangePoit * sizeof(DTCF_DIRENT_S), 0x0,
+            u32ChangePoit * sizeof(DTCF_DIRENT_S)) != EOK) {
+            MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "memset_s newDirEnt error, errno:%d\n", errno);
+            free(newDirEnt);
+            newDirEnt = NULL;
+            return DTCF_ERR_EINVAL_PARAMETER;
+        }
+        if (g_dtcfScanFileList.pstDirentList != NULL) {
+            if (memcpy_s(newDirEnt, (u32ChangePoit) * sizeof(DTCF_DIRENT_S), g_dtcfScanFileList.pstDirentList,
+                (g_dtcfScanFileList.u32DirentlistCount * sizeof(DTCF_DIRENT_S))) != EOK) {
+                free(newDirEnt);
+                newDirEnt = NULL;
+                return DTCF_ERR_EINVAL_PARAMETER;
+            }
+            free(g_dtcfScanFileList.pstDirentList);
+            g_dtcfScanFileList.pstDirentList = NULL;
+        }
+
+        g_dtcfScanFileList.pstDirentList = newDirEnt;
+        g_dtcfScanFileList.u32listCount = u32ChangePoit;
+    }
+    return MEDIA_HAL_OK;
+}
+
+int32_t CheckToMkdirForInit(DTCF_DIR_E dirType)
+{
+    char azTmpDir[FILE_PATH_LEN_MAX] = { 0 };
+    if (dirType >= DTCF_DIR_BUTT) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "not support dir[%d]", dirType);
+        return DTCF_ERR_EINVAL_PARAMETER;\r
+    }
+    int32_t ret = snprintf_s(azTmpDir, FILE_PATH_LEN_MAX, FILE_PATH_LEN_MAX - 1,
+        "%s/%s", g_azRootDir, g_azDirNames[dirType]);
+    if (ret <= 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "snprintf_s stTmpDir.azTmpDir fail, ret:%d", ret);
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+    MEDIA_HAL_LOGI(MODULE_NAME_DTCF, "azTmpDir:%s", azTmpDir);
+    ret = DtcfMkdir(azTmpDir, DTCF_DIR_MODE);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "mkdir g_azDirNames[%d]:%s fail ret:%d", dirType, g_azDirNames[dirType], ret);
+        return ret;
+    }
+    return MEDIA_HAL_OK;
+}
+
+int32_t DtcfInit(const char *pazRootDir)
+{
+    CHECK_DTCF_NULL_PTR(pazRootDir);
+    DtcfThreadMutexLock();
+    int32_t ret = DtcfCheckRootDir(pazRootDir);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "DTCF init failed:0x%x\n", ret);
+        DtcfThreadMutexUnLock();
+        return ret;
+    }
+    if (((g_dtcfStatu != DTCF_STATUS_BUTT) && (g_dtcfStatu != DTCF_STATUS_DESTROY)) ||
+        (g_dtcfStatu == DTCF_STATUS_CREATED)) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "status error, current status:%d\n", g_dtcfStatu);
+        DtcfThreadMutexUnLock();
+        return DTCF_ERR_STATUS_ERROR;
+    }
+    ret = DtcfMakedirs(pazRootDir, DTCF_DIR_MODE);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "DTCF_Mkdirs azRootDir:%s fail ret:%x\n", pazRootDir, ret);
+        DtcfThreadMutexUnLock();
+        return ret;
+    }
+    ret = snprintf_s(g_azRootDir, FILE_PATH_LEN_MAX, FILE_PATH_LEN_MAX - 1, "%s", pazRootDir);
+    if (ret <= 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "snprintf_s pazFilePath fail, ret:%d\n", ret);
+        DtcfThreadMutexUnLock();
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+    g_dtcfStatu = DTCF_STATUS_CREATED;
+    DtcfThreadMutexUnLock();
+    return MEDIA_HAL_OK;
+}
+
+int32_t DtcfDeInit(void)
+{
+    if (((g_dtcfStatu == DTCF_STATUS_BUTT) || (g_dtcfStatu == DTCF_STATUS_DESTROY)) &&
+        (g_dtcfStatu != DTCF_STATUS_CREATED)) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "status error, current status:%d\n", g_dtcfStatu);
+        return DTCF_ERR_STATUS_ERROR;
+    }
+
+    DtcfThreadMutexLock();
+    if (g_dtcfScanFileList.pstDirentList != NULL) {
+        DtcfFreeScanNameList();
+    }
+    DtcfResetDirNames();
+    g_dtcfStatu = DTCF_STATUS_DESTROY;
+    DtcfThreadMutexUnLock();
+
+    return MEDIA_HAL_OK;
+}
+
+static int32_t DtcfScanDir(const DTCF_DIR_E enDirs[DTCF_DIR_BUTT], uint32_t u32DirCount)
+{
+    for (uint32_t i = 0; i < u32DirCount; i++) {
+        struct dirent **dirNameList = NULL;
+        if (enDirs[i] >= DTCF_DIR_BUTT) {
+            MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "DTCF enDir:%d out of Range\n", enDirs[i]);
+            return DTCF_ERR_EINVAL_PARAMETER;
+        } else if (g_azDirNames[(int32_t)enDirs[i]][0] == '\0') {
+            return DTCF_ERR_EINVAL_PARAMETER;
+        }
+        char dirBuf[FILE_PATH_LEN_MAX] = { 0 };
+        int32_t ret = snprintf_s(dirBuf, FILE_PATH_LEN_MAX, FILE_PATH_LEN_MAX - 1, "%s/%s/",
+            g_azRootDir, g_azDirNames[(int32_t)enDirs[i]]);
+        if (ret <= 0) {
+            MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "snprintf_s stTmpDir.dirBuf fail, ret:%d\n", ret);
+            return DTCF_ERR_EINVAL_PARAMETER;
+        }
+        // in order to clean codeDEX warning
+        const char *dirp = dirBuf;
+        int32_t scanNamelistCount = scandir(dirp, &dirNameList, Selector, NULL);
+        if (scanNamelistCount <= 0) {
+            if (dirNameList != NULL) {
+                free(dirNameList);
+            }
+            continue;
+        }
+        if (dirNameList == NULL) {
+            g_dtcfScanFileList.enScanDirs[i] = enDirs[i];
+            continue;
+        }
+        ret = DtcfExpandFileList(scanNamelistCount);
+        if (ret != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "DTCF_ExpandFileList fail, ret:%x\n", ret);
+            int32_t node = 0;
+            while (node < scanNamelistCount) {
+                free(dirNameList[node]);
+                node++;
+            }
+            free(dirNameList);
+            return ret;
+        }
+        for (int32_t n = 0; n < scanNamelistCount; n++) {
+            g_dtcfScanFileList.pstDirentList[g_dtcfScanFileList.u32DirentlistCount + (uint32_t)n].pdirent =
+                dirNameList[n];
+            g_dtcfScanFileList.pstDirentList[g_dtcfScanFileList.u32DirentlistCount + (uint32_t)n].enDir = enDirs[i];
+        }
+        g_dtcfScanFileList.u32DirentlistCount = g_dtcfScanFileList.u32DirentlistCount + (uint32_t)scanNamelistCount;
+        free(dirNameList);
+        g_dtcfScanFileList.enScanDirs[i] = enDirs[i];
+    }
+    return MEDIA_HAL_OK;
+}
+
+int32_t DtcfScanFiles(const DTCF_DIR_E enDirs[], uint32_t u32DirCount, uint32_t *pu32FileAmount)
+{
+    CHECK_DTCF_NULL_PTR(enDirs);
+    int32_t ret = CheckDtcfStatusCreate();
+    if (ret != MEDIA_HAL_OK) {
+        return ret;
+    }
+    DtcfThreadMutexLock();
+    if ((u32DirCount == 0) || (u32DirCount > DTCF_DIR_BUTT)) {
+        DtcfThreadMutexUnLock();
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+
+    if (g_dtcfScanFileList.pstDirentList != NULL) {
+        DtcfFreeScanNameList();
+    }
+
+    ret = DtcfScanDir(enDirs, u32DirCount);
+    if (ret != MEDIA_HAL_OK) {
+        DtcfThreadMutexUnLock();
+        return ret;
+    }
+
+    g_dtcfScanFileList.u32ScanDirCount = u32DirCount;
+    *pu32FileAmount = g_dtcfScanFileList.u32DirentlistCount;
+    if ((g_dtcfScanFileList.u32DirentlistCount > 0) && (g_dtcfScanFileList.pstDirentList != NULL)) {
+        Qsort(g_dtcfScanFileList.pstDirentList, g_dtcfScanFileList.u32DirentlistCount,
+            sizeof(DTCF_DIRENT_S), SortBydnameDesc);
+    }
+    g_dtcfStatu = DTCF_STATUS_SCANED;
+    DtcfThreadMutexUnLock();
+    return MEDIA_HAL_OK;
+}
+
+static int32_t FindFilePath(DTCF_DIR_E enDir, char *pazFilePath, uint32_t u32Length, DTCF_TEMP_DIR_S stTmpDir)
+{
+    int32_t index = -1;
+    MEDIA_HAL_LOGI(MODULE_NAME_DTCF, "enDir:%d u32DirentlistCount:%d\n", enDir, g_dtcfScanFileList.u32DirentlistCount);
+    for (int32_t i = (int32_t)g_dtcfScanFileList.u32DirentlistCount - 1; i >= 0; i--) {
+        MEDIA_HAL_LOGI(MODULE_NAME_DTCF, "i:%d g_dtcfScanFileList.pstDirentList[i].enDir:%d \n",
+            i, g_dtcfScanFileList.pstDirentList[i].enDir);
+        if (enDir == g_dtcfScanFileList.pstDirentList[i].enDir) {
+            index = i;
+            break;
+        }
+    }
+    if (u32Length == 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "error: pazFilePath lenth is 0\n");
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+    if ((index < 0) || ((uint32_t)index >= g_dtcfScanFileList.u32DirentlistCount)) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "can't find enDir:%d file index:%d\n", enDir, index);
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+    int32_t ret = snprintf_s(pazFilePath, u32Length, u32Length - 1, "%s%s", stTmpDir.azTmpDir,
+        g_dtcfScanFileList.pstDirentList[index].pdirent->d_name);
+    if (ret <= 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "GetOldestFilePath snprintf_s pazFilePath fail, ret:%d\n", ret);
+        return DTCF_ERR_EINVAL_PARAMETER;
+    } else if ((uint32_t)ret >= u32Length) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF,
+            "GetOldestFilePath snprintf_s u32Length:%d is not length enough, ret:%d\n", u32Length, ret);
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+    return MEDIA_HAL_OK;
+}
+
+int32_t DtcfGetOldestFilePath(DTCF_DIR_E enDir, char *pazFilePath, uint32_t u32Length)
+{
+    CHECK_DTCF_NULL_PTR(pazFilePath);
+    if (enDir >= DTCF_DIR_BUTT) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "DTCF enDir:%d out of Range\n", enDir);
+        return DTCF_ERR_EINVAL_PARAMETER;
+    } else if (CheckDtcfStatusScan() != MEDIA_HAL_OK) {
+        return DTCF_ERR_STATUS_ERROR;
+    } else if (u32Length == 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "DTCF file path length is 0\n");
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+    DtcfThreadMutexLock();
+    if (strlen(g_azDirNames[enDir]) == 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "g_azDirNames[%d] undefined\n", enDir);
+        DtcfThreadMutexUnLock();
+        return DTCF_ERR_UNDEFINE_DIR;
+    }
+    DTCF_TEMP_DIR_S stTmpDir = {{0}, 0, DTCF_DIR_BUTT, DTCF_FILE_TYPE_BUTT, {0}};
+    int32_t ret = snprintf_s(stTmpDir.azTmpDir, FILE_PATH_LEN_MAX, FILE_PATH_LEN_MAX - 1, "%s/%s/",
+        g_azRootDir, g_azDirNames[enDir]);
+    if (ret <= 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "GetOldestFilePath snprintf_s stTmpDir.azTmpDir fail, ret:%d\n", ret);
+        DtcfThreadMutexUnLock();
+        return DTCF_ERR_EINVAL_PARAMETER;
+    } else if (ret >= FILE_PATH_LEN_MAX) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF,
+            "GetOldestFilePath snprintf_s u32Length:%d is not length enough, ret:%d\n", u32Length, ret);
+        DtcfThreadMutexUnLock();
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+    ret = FindFilePath(enDir, pazFilePath, u32Length, stTmpDir);
+    if (ret != MEDIA_HAL_OK) {
+        DtcfThreadMutexUnLock();
+        return ret;
+    }
+    DtcfThreadMutexUnLock();
+    return MEDIA_HAL_OK;
+}
+
+int32_t DtcfGetCurrentFileTime(struct tm *fileTime)
+{
+    CHECK_DTCF_NULL_PTR(fileTime);
+    fileTime->tm_year = g_lastTime.tm_year;
+    fileTime->tm_mon = g_lastTime.tm_mon;
+    fileTime->tm_mday = g_lastTime.tm_mday;
+    fileTime->tm_hour = g_lastTime.tm_hour;
+    fileTime->tm_min = g_lastTime.tm_min;
+    fileTime->tm_sec = g_lastTime.tm_sec;
+    return MEDIA_HAL_OK;
+}
+
+static int32_t DtcfGetTime(char *pazTime, uint32_t u32BufSize)
+{
+    CHECK_DTCF_NULL_PTR(pazTime);
+    struct tm t;
+    struct timeval tv;
+    if (gettimeofday(&tv, NULL) != 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "gettimeofday error, errno:%d\n", errno);
+        return DTCF_ERR_SYSTEM_ERROR;
+    }
+
+    if (tv.tv_usec > 500000) { /* 500000: Unit Conversion */
+        tv.tv_sec++;
+    }
+
+    localtime_r((time_t *)&tv.tv_sec, &t);
+
+    if (t.tm_year == 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "localtime_r error, errno:%d\n", errno);
+        return DTCF_ERR_SYSTEM_ERROR;
+    }
+    MEDIA_HAL_LOGI(MODULE_NAME_DTCF, "%4d_%02d%02d_%02d%02d%02d  %lld\n",
+        /* the correct time need to plus 1900 */
+        t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, (int64_t)tv.tv_usec);
+    if ((t.tm_year == g_lastTime.tm_year) &&
+        (t.tm_mon == g_lastTime.tm_mon) &&
+        (t.tm_mday == g_lastTime.tm_mday) &&
+        (t.tm_hour == g_lastTime.tm_hour) &&
+        (t.tm_min == g_lastTime.tm_min) &&
+        (t.tm_sec == g_lastTime.tm_sec)) {
+        g_num++;
+    } else {
+        g_num = 0;
+    }
+
+    // if this API was called 100 times or more IN THE SAME SECOND, will cause string length over DTCF_TIME_STR_LEN
+    if (g_num >= 100) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "num=%d, file name over lenght error!\n", g_num);
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+
+    int32_t ret = memcpy_s(&g_lastTime, sizeof(g_lastTime), &t, sizeof(struct tm));
+    if (ret != EOK) {
+        return DTCF_ERR_SYSTEM_ERROR;
+    }
+    ret = snprintf_s(pazTime, u32BufSize, DTCF_TIME_STR_LEN, "%4d_%02d_%02d_%02d%02d%02d_%02d",
+        t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, g_num); /* 1900: count begin */
+    if (ret < 0 || ret >= DTCF_TIME_STR_LEN) {
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+    return MEDIA_HAL_OK;
+}
+
+int32_t DtcfCreateFilePath(DTCF_FILE_TYPE_E enFileType, DTCF_DIR_E enDir,
+    char *pazFilePath, uint32_t u32Length)
+{
+    CHECK_DTCF_NULL_PTR(pazFilePath);
+    if (enDir >= DTCF_DIR_BUTT) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "DTCF enDir:%d out of Range\n", enDir);
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+    if (enFileType >= DTCF_FILE_TYPE_BUTT) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "DTCF fileType out of Range\n");
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+    int32_t ret = CheckDtcfStatusCreate();
+    if (ret != MEDIA_HAL_OK) {
+        return ret;
+    }
+    if (u32Length == 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "DTCF file path length is 0\n");
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+    DtcfThreadMutexLock();
+    if (strlen(g_azDirNames[enDir]) == 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "g_azDirNames[%d] undefined\n", enDir);
+        DtcfThreadMutexUnLock();
+        return DTCF_ERR_UNDEFINE_DIR;
+    }
+
+    char azTime[DTCF_TIME_STR_LEN + 1] = {0};
+    ret = DtcfGetTime(azTime, DTCF_TIME_STR_LEN + 1);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "SS_DTCF_GetTime fail, ret:0x%x\n", ret);
+        DtcfThreadMutexUnLock();
+        return ret;
+    }
+    ret = snprintf_s(pazFilePath, u32Length, u32Length - 1, "%s/%s/%s%s.%s", g_azRootDir,
+        g_azDirNames[enDir], azTime, g_szFileNameSuffix[enDir], g_szFileTypeSuffix[enFileType]);
+    if (ret <= 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "CreateFilePath snprintf_s pazFilePath fail, ret:%d\n", ret);
+        DtcfThreadMutexUnLock();
+        return DTCF_ERR_EINVAL_PARAMETER;
+    } else if ((uint32_t)ret >= u32Length) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF,
+            "CreateFilePath snprintf_s u32Length:%d is not length enough, ret:%d\n", u32Length, ret);
+        DtcfThreadMutexUnLock();
+        return DTCF_ERR_EINVAL_PARAMETER;
+    }
+    DtcfThreadMutexUnLock();
+    return MEDIA_HAL_OK;
+}
+
+int32_t DtcfMakeFileDir(char *pazFilePath, uint32_t u32Length)
+{
+    char dir[FILE_PATH_LEN_MAX] = {};
+    char *lastSlash = strrchr(pazFilePath, '/');
+    if (lastSlash != NULL) {
+        int32_t dirLen = lastSlash - pazFilePath;
+        if (dirLen >= FILE_PATH_LEN_MAX - 1) {\r
+            MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "The file path is too long to create!");
+            return -1;\r
+        }
+        if (strncpy_s(dir, FILE_PATH_LEN_MAX, pazFilePath, dirLen) != 0) {
+            MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "copy path error");
+            return -1;
+        }
+        dir[dirLen] = '\0';
+    }
+    int32_t ret = DtcfMakedirs(dir, DTCF_DIR_MODE);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME_DTCF, "DTCF_Mkdirs azRootDir:%s fail ret:%x\n", dir, ret);
+        return ret;
+    }
+    return 0;
+}
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/common/dtcf_manager/CMakeLists.txt b/code/sdk/middleware/services/media/hal/format/plugins/common/dtcf_manager/CMakeLists.txt
new file mode 100644 (file)
index 0000000..08b66ad
--- /dev/null
@@ -0,0 +1,47 @@
+#===============================================================================\r
+# @brief    cmake file\r
+# Copyright (c) CompanyNameMagicTag 2022-2022. All rights reserved.\r
+#===============================================================================\r
+set(COMPONENT_NAME "dtcf_manager")\r
+\r
+# use build env and option camke\r
+include(../../../../../build/build_env.cmake)\r
+include(../../../../../build/build_option.cmake)\r
+\r
+set(SOURCES\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/dtcf_manager.c\r
+)\r
+\r
+set(PUBLIC_HEADER\r
+)\r
+\r
+set(PRIVATE_HEADER\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/include\r
+    ${CMAKE_CURRENT_SOURCE_DIR}/../dtcf/include\r
+)\r
+\r
+set(CDEFINES ${CDEFINES} "CMSIS_SUPPORT")\r
+set(PRIVATE_DEFINES\r
+    ${CDEFINES}\r
+)\r
+\r
+set(PUBLIC_DEFINES\r
+)\r
+\r
+# use this when you want to add ccflags like -include xxx\r
+set(COMPONENT_PUBLIC_CCFLAGS\r
+)\r
+\r
+set(COMPONENT_CCFLAGS\r
+)\r
+\r
+set(WHOLE_LINK\r
+    true\r
+)\r
+\r
+set(MAIN_COMPONENT\r
+    false\r
+)\r
+set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib/media/${BOARD}_${APPLICATION}/${OS}/${COMPONENT_NAME})\r
+\r
+build_component()
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/common/dtcf_manager/include/dtcf_manager.h b/code/sdk/middleware/services/media/hal/format/plugins/common/dtcf_manager/include/dtcf_manager.h
new file mode 100644 (file)
index 0000000..7bc8ed1
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: dtcf manager interface
+* Author: Media Software Group
+* Create: 2025-03-10
+*/
+
+#ifndef DTCF_MANAGER_H
+#define DTCF_MANAGER_H
+#include <stdint.h>
+#include "media_hal_common.h"
+#include "dtcf.h"
+
+#define MW_CHECK_RETURN(s32Ret) \
+    do { \
+        if ((s32Ret) != MEDIA_HAL_OK) { \
+            return s32Ret; \
+        } \
+    } while (0)
+
+#define REC_FILE_NAME_LEN (256)
+
+typedef enum {
+    MEMORY_REACH_THE_MAXIMUM_VALUE,  /* The memory reaches the maximum value. */
+    DELETE_THE_OLDEST_FAILED,        /* Failed to delete the oldest file.. */
+    MEMORY_MONITOR_ERROR,            /* Other memory monitoring errors */
+} DtcfCallBackType;
+
+typedef struct {
+    void *handle;
+    int32_t (*CallBack)(void *handle, DtcfCallBackType type, int32_t extra);
+} DtcfCallBack;
+
+typedef struct {
+    uint32_t fileDateYear;
+    uint32_t fileDateMonth;
+    uint32_t fileDateDay;
+    uint32_t fileDateHour;
+    uint32_t fileDateMin;
+    uint32_t fileDateSec;
+} FileDate;
+
+int32_t DtcfMgrFileOptInit(const char *path, uint32_t len, DtcfCallBack callBack);
+int32_t DtcfMgrRequestFileNames(DTCF_FILE_TYPE_E fileType, DTCF_DIR_E dirType,
+    char (*paszFileNames)[REC_FILE_NAME_LEN]);
+int32_t DtcfMgrFileOptDeInit(void);
+int32_t DtcfMgrGetStorageMaxSize(uint64_t *size);
+int32_t DtcfMgrHandleRecordMaxSize(uint64_t currentSize, uint64_t recordMaxSize);
+uint64_t DtcfMgrGetCurrentRecordedSize(void);
+uint64_t DtcfMgrGetCurrentMemorySize(uint64_t maxMemory);
+void DtcfMgrSetDeleteFileEnable(bool enable);
+void DtcfMgrSetMaxStorageThreshold(uint32_t threshold);
+int32_t DtcfMgrGetCurrentFileDate(FileDate *fileDate);
+bool DtcfMgrIsFile(const char *path, uint32_t len);
+int32_t DtcfMgrMakeDir(const char *path, uint32_t len);
+#endif
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/common/dtcf_manager/src/dtcf_manager.c b/code/sdk/middleware/services/media/hal/format/plugins/common/dtcf_manager/src/dtcf_manager.c
new file mode 100644 (file)
index 0000000..d1f2c2d
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: dtcf manager
+* Author: Media Software Group
+* Create: 2025-03-10
+*/
+#include "dtcf_manager.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/statfs.h>
+#include <sys/stat.h>
+#include "media_hal_thread_adapt.h"
+#include "dtcf.h"
+
+#define MODULE_NAME "DtcfManager"
+#define BYTE_UNIT 1024
+#define FILE_NAME_SIZE 1024
+#define NORM_DIR_NUM 4
+#define EMR_DIR_NUM 4
+#define RM_RECORDERED_START_RATIO 20 /* 20 / 100 */
+#define RM_RECORDERED_END_RATIO 30 /* 20 / 100 */
+#define PERSENTAGE 100.0
+#define DEFALUT_REMAIN_SPACE_THESHOLD 0.9
+#define MEMORY_CHECK_INTERVAL_MS 5000
+#define FILE_PATH_LEN_MAX         (256)
+
+typedef struct {
+    bool fileOptInited;
+    float remainSpaceThreshold;
+    bool overwriteOldestFiles;
+    uint32_t fileAmount;
+    DtcfCallBack callBack;
+    char path[FILE_PATH_LEN_MAX];
+    MediaHalMutexHandle mutex;
+    uint64_t currentRecordedSize;
+    FileDate fileDate;
+    DTCF_DIR_E dirType;
+} FileOptContext;
+
+const uint64_t MEMORY_STORAGE_DEFAULT_MAX_SIZE = 8ULL * 1024 * 1024 * 1024;
+static FileOptContext g_fileOptContext = {};
+
+int32_t DtcfMgrGetStorageMaxSize(uint64_t *size)
+{
+#if defined(ONLY_UT_TEST)
+    *size = MEMORY_STORAGE_DEFAULT_MAX_SIZE;
+    return MEDIA_HAL_OK;
+#endif
+    struct statfs sfs;
+    int result;
+    uint64_t freeSize;
+    (void)memset_s(&sfs, sizeof(sfs), 0, sizeof(sfs));
+    result = statfs("/user/", &sfs);
+    if (result != 0 || sfs.f_type == 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "[UPG] statfs failed! errno = %d, sfs.f_type = %d", errno, (sfs.f_type));
+        MEDIA_HAL_LOGE(MODULE_NAME, "[UPG] statfs failed! Invalid argument! result = %d", result);
+        return MEDIA_HAL_ERR;
+    }
+    freeSize = (uint64_t)sfs.f_bsize * sfs.f_bfree;
+    if (freeSize <= MEMORY_STORAGE_DEFAULT_MAX_SIZE && freeSize > 0) {
+        *size = freeSize;
+    } else {
+        *size = MEMORY_STORAGE_DEFAULT_MAX_SIZE;
+    }
+    MEDIA_HAL_LOGI(MODULE_NAME, "max memory size = %llu", *size);
+    return MEDIA_HAL_OK;
+}
+
+static int32_t OverwriteOldestFile(FileOptContext *context)
+{
+#ifdef TIME_CONSUMING_PRINTING
+    uint32_t startTime;
+    uint32_t endTime;
+    uint32_t totalTime;
+    startTime = uapi_tcxo_get_ms();
+#endif
+    DTCF_DIR_E azScanDir[DTCF_DIR_BUTT] = {
+        DTCF_DIR_RECORD_WAV_FILE,
+        DTCF_DIR_RECORD_MP3_FILE,
+        DTCF_DIR_RECORD_SILK_FILE,
+        DTCF_DIR_RECORD_OGG_FILE,
+    };
+    int32_t ret = 0;
+    ret = DtcfScanFiles(azScanDir, DTCF_DIR_BUTT, &context->fileAmount);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "DtcfScanFiles fail %d", ret);
+        context->callBack.CallBack(context->callBack.handle, DELETE_THE_OLDEST_FAILED, 0);
+        return MEDIA_HAL_ERR;
+    }
+    char path[FILE_PATH_LEN_MAX] = {0};
+    ret = DtcfGetOldestFilePath(context->dirType, path, FILE_PATH_LEN_MAX);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "SS_DTCF_GetOldestFilePath fail %d", ret);
+        return MEDIA_HAL_ERR;
+    }
+#ifdef TIME_CONSUMING_PRINTING
+    endTime = uapi_tcxo_get_ms();
+    totalTime = endTime - startTime;
+    MEDIA_HAL_LOGI(MODULE_NAME, " DtcfScanFiles totalTime = %ums", totalTime);
+    startTime = uapi_tcxo_get_ms();
+#endif
+    struct stat fileInfo = { 0 };
+    ret = stat(path, &fileInfo);
+    if (ret != 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "stat file: %s failed! errno = %d", path, errno);
+        return MEDIA_HAL_ERR;
+    }
+    ret = remove(path);
+    if (ret != 0) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "remove file %s failed! errno = %d", path, errno);
+        return MEDIA_HAL_ERR;
+    }
+    context->currentRecordedSize -= fileInfo.st_size;
+#ifdef TIME_CONSUMING_PRINTING
+    endTime = uapi_tcxo_get_ms();
+    totalTime = endTime - startTime;
+    MEDIA_HAL_LOGI(MODULE_NAME, " remove totalTime = %ums", totalTime);
+#endif
+    return MEDIA_HAL_OK;
+}
+
+int32_t DtcfMgrHandleRecordMaxSize(uint64_t currentSize, uint64_t recordMaxSize)
+{
+    MediaHalMutexLock(g_fileOptContext.mutex);
+    g_fileOptContext.currentRecordedSize += currentSize;
+    if (g_fileOptContext.currentRecordedSize >= (recordMaxSize * g_fileOptContext.remainSpaceThreshold)) {
+        if (g_fileOptContext.overwriteOldestFiles) {
+            int32_t ret = OverwriteOldestFile(&g_fileOptContext);
+            if (ret != MEDIA_HAL_OK) {
+                MEDIA_HAL_LOGE(MODULE_NAME, "OverwriteOldestFile filed!");
+                g_fileOptContext.callBack.CallBack(g_fileOptContext.callBack.handle, DELETE_THE_OLDEST_FAILED, 0);
+                MediaHalMutexUnLock(g_fileOptContext.mutex);
+                return MEDIA_HAL_ERR;
+            }
+        } else {
+            MEDIA_HAL_LOGE(MODULE_NAME, "DtcfMgrHandleRecordMaxSize start");
+            g_fileOptContext.callBack.CallBack(g_fileOptContext.callBack.handle, MEMORY_REACH_THE_MAXIMUM_VALUE, 0);
+            MEDIA_HAL_LOGE(MODULE_NAME, "DtcfMgrHandleRecordMaxSize end");
+        }
+    }
+    MediaHalMutexUnLock(g_fileOptContext.mutex);
+    return MEDIA_HAL_OK;
+}
+
+uint64_t DtcfMgrGetCurrentRecordedSize(void)
+{
+    MediaHalMutexLock(g_fileOptContext.mutex);
+    uint64_t currentRecordedSize = g_fileOptContext.currentRecordedSize;
+    MediaHalMutexUnLock(g_fileOptContext.mutex);
+    return currentRecordedSize;
+}
+
+uint64_t DtcfMgrGetCurrentMemorySize(uint64_t maxMemory)
+{
+    MediaHalMutexLock(g_fileOptContext.mutex);
+    uint64_t currentMemorySize = maxMemory * g_fileOptContext.remainSpaceThreshold;
+    MediaHalMutexUnLock(g_fileOptContext.mutex);
+    return currentMemorySize;
+}
+
+void DtcfMgrSetDeleteFileEnable(bool enable)
+{
+    MediaHalMutexLock(g_fileOptContext.mutex);
+    if (g_fileOptContext.fileOptInited) {
+        g_fileOptContext.overwriteOldestFiles = enable;
+        MEDIA_HAL_LOGI(MODULE_NAME, "set OverwriteOldestFile enable = %d!", enable);
+    }
+    MediaHalMutexUnLock(g_fileOptContext.mutex);
+}
+
+void DtcfMgrSetMaxStorageThreshold(uint32_t threshold)
+{
+    MediaHalMutexLock(g_fileOptContext.mutex);
+    if (g_fileOptContext.fileOptInited) {
+        g_fileOptContext.remainSpaceThreshold = threshold / PERSENTAGE;
+        MEDIA_HAL_LOGI(MODULE_NAME, "set max storage threshold = %u!", threshold);
+    }
+    MediaHalMutexUnLock(g_fileOptContext.mutex);
+}
+
+int32_t DtcfMgrGetCurrentFileDate(FileDate *fileDate)
+{
+    CHK_NULL_RETURN(fileDate, MEDIA_HAL_INVALID_PARAM, "fileDate is NULL!");
+    struct tm t = {};
+    int32_t ret = DtcfGetCurrentFileTime(&t);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "get current file time failed!");
+        return MEDIA_HAL_ERR;
+    }
+    fileDate->fileDateYear = t.tm_year + 1900;  /* the correct time need to plus 1900 */
+    fileDate->fileDateMonth = t.tm_mon + 1;
+    fileDate->fileDateDay = t.tm_mday;
+    fileDate->fileDateHour = t.tm_hour;
+    fileDate->fileDateMin = t.tm_min;
+    fileDate->fileDateSec = t.tm_sec;
+    return MEDIA_HAL_OK;
+}
+
+int32_t FileOptInitContext(const char *path, uint32_t len, DtcfCallBack callBack)
+{
+    g_fileOptContext.callBack = callBack;
+    g_fileOptContext.fileOptInited = false;
+    g_fileOptContext.overwriteOldestFiles = true;
+    g_fileOptContext.remainSpaceThreshold = DEFALUT_REMAIN_SPACE_THESHOLD;
+    g_fileOptContext.fileAmount = 0;
+    g_fileOptContext.mutex = MediaHalMutexCreate(NULL);
+    if (g_fileOptContext.mutex == NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "MediaHalMutexCreate failed!");
+        return MEDIA_HAL_ERR;
+    }
+    if (memcpy_s(g_fileOptContext.path, FILE_PATH_LEN_MAX, path, len) != EOK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "memcpy_s failed");
+        return MEDIA_HAL_ERR;
+    }
+    return MEDIA_HAL_OK;
+}
+
+int32_t DtcfMgrFileOptInit(const char *path, uint32_t len, DtcfCallBack callBack)
+{
+    if (g_fileOptContext.fileOptInited) {
+        return MEDIA_HAL_OK;
+    }
+    if (path == NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "input path is NULL");
+        return MEDIA_HAL_ERR;
+    }
+    int32_t ret = FileOptInitContext(path, len, callBack);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "file init context failed!");
+        return ret;
+    }
+    ret = DtcfInit(path);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "SS_DTCF_Init fail %d", ret);
+        return MEDIA_HAL_ERR;
+    }
+    g_fileOptContext.fileOptInited = true;
+    return MEDIA_HAL_OK;
+}
+
+int32_t DtcfMgrFileOptDeInit(void)
+{
+    if (!g_fileOptContext.fileOptInited) {
+        return MEDIA_HAL_OK;
+    }
+    g_fileOptContext.fileOptInited = false;
+    MediaHalMutexDestroy(&g_fileOptContext.mutex);
+    return DtcfDeInit();
+}
+
+int32_t DtcfMgrRequestFileNames(DTCF_FILE_TYPE_E fileType, DTCF_DIR_E dirType,
+    char (*paszFileNames)[REC_FILE_NAME_LEN])
+{
+    int32_t s32Ret = CheckToMkdirForInit(dirType);
+    if (s32Ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "CheckToMkdirForInit failed!");
+        return MEDIA_HAL_ERR;
+    }
+    s32Ret = DtcfCreateFilePath(fileType, dirType,
+        paszFileNames[0], REC_FILE_NAME_LEN);
+    if (s32Ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "DtcfCreateFilePath failed!");
+        return MEDIA_HAL_ERR;
+    }
+    g_fileOptContext.dirType = dirType;
+    return s32Ret;
+}
+
+bool DtcfMgrIsFile(const char *path, uint32_t len)
+{
+    MEDIA_HAL_UNUSED(len);
+    char *lastSlash = strrchr(path, '/');
+    if (lastSlash == NULL) {
+        lastSlash = (char *)path;
+    } else {
+        if (lastSlash + 1 >= (path + len)) {
+            return false;
+        }
+        lastSlash++;
+    }
+    char *dot = strchr(lastSlash, '.');
+    if (dot != NULL && (dot - lastSlash) < strlen(lastSlash) - 1) {
+        return true;
+    }
+    return false;
+}
+
+int32_t DtcfMgrMakeDir(const char *path, uint32_t len)
+{
+    return DtcfMakeFileDir(path, len);
+}
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/ffmpeg_demuxer/CMakeLists.txt b/code/sdk/middleware/services/media/hal/format/plugins/ffmpeg_demuxer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..132c770
--- /dev/null
@@ -0,0 +1,54 @@
+#===============================================================================
+# @brief    cmake file
+# Copyright (c) CompanyNameMagicTag 2022-2022. All rights reserved.
+#===============================================================================
+set(COMPONENT_NAME "plugin_demuxer_ffmpeg")
+
+set(COMPONENT_CCFLAGS  -march=rv32imafc -mabi=ilp32f)
+set(FFMPEG_ROOT_DIR ${ROOT_DIR}/middleware/services/media/component/ffmpeg_adp/ffmpeg-5.1.6)
+
+# use build env and option camke
+include(../../../../build/build_env.cmake)
+include(../../../../build/build_option.cmake)
+
+set(SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/ff_demuxer_plugin.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/ff_format.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/ff_wrapper.c
+)
+
+set(PUBLIC_HEADER
+)
+
+set(PRIVATE_HEADER
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../include
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../common/include
+    ${FFMPEG_ROOT_DIR}/libavformat
+    ${FFMPEG_ROOT_DIR}/libavcodec
+    ${FFMPEG_ROOT_DIR}/libavutil
+    ${FFMPEG_ROOT_DIR}
+)
+
+set(CDEFINES ${CDEFINES} "ENABLE_FFMPEG_DEMUXER")
+set(PUBLIC_DEFINES
+    ${CDEFINES}
+)
+
+# use this when you want to add ccflags like -include xxx
+set(COMPONENT_PUBLIC_CCFLAGS
+)
+
+set(COMPONENT_CCFLAGS
+)
+
+set(WHOLE_LINK
+    true
+)
+
+set(MAIN_COMPONENT
+    false
+)
+set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib/media/${BOARD}_${APPLICATION}/${OS})
+
+build_component()
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/ffmpeg_demuxer/ff_demuxer_plugin.h b/code/sdk/middleware/services/media/hal/format/plugins/ffmpeg_demuxer/ff_demuxer_plugin.h
new file mode 100644 (file)
index 0000000..85ecfc6
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+* Copyright (c) @CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: ffmpeg demuxer header
+* Author: Media Software Group
+* Create: 2025-08-08
+*/
+
+#ifndef FF_DEMUXER_PLUGIN_H
+#define FF_DEMUXER_PLUGIN_H
+
+#include "demuxer_interface.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif
+#endif /* End of #ifdef __cplusplus */
+
+typedef void *VoidPtr;
+
+#ifdef ENABLE_DL_DEMUXER_PLUGIN
+const DemuxerPluginEntry *GetDemuxer(void);
+#else
+extern DemuxerPluginEntry g_ffDemuxerEntry;
+#endif
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif
+#endif /* __cplusplus */
+
+#endif /* FF_DEMUXER_PLUGIN_H */
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/ffmpeg_demuxer/ff_format.h b/code/sdk/middleware/services/media/hal/format/plugins/ffmpeg_demuxer/ff_format.h
new file mode 100644 (file)
index 0000000..6c33702
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag. 2025-2025. All rights reserved.
+ * Description: ffmpeg foramt function
+ * Author: Media Software Group
+ * Create: 2025-08-08
+ */
+
+#ifndef FF_FORMAT_H
+#define FF_FORMAT_H
+
+#include "ff_wrapper.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* End of #ifdef __cplusplus */
+
+int32_t FfFormatFree(FfDemuxContext *demux, const FormatPacket *fmtFrame);
+void FfFormatClose(FfDemuxContext *demux);
+int32_t FfFormatProbe(FfDemuxContext *demux);
+int32_t FfFormatRead(FfDemuxContext *demux, FormatPacket *fmtFrame);
+int32_t FfFormatSeek(FfDemuxContext *demux, int32_t streamIndex, int64_t toMs, uint32_t flag);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* FF_FORMAT_H */
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/ffmpeg_demuxer/ff_wrapper.h b/code/sdk/middleware/services/media/hal/format/plugins/ffmpeg_demuxer/ff_wrapper.h
new file mode 100644 (file)
index 0000000..0c047bb
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag. 2025-2025. All rights reserved.
+ * Description: ffmpeg wrapper header
+ * Author: Media Software Group
+ * Create: 2025-08-08
+ */
+
+#ifndef FF_WRAPPER_H
+#define FF_WRAPPER_H
+
+#include <pthread.h>
+#include "libavformat/avformat.h"
+#include "libavutil/log.h"
+#include "demuxer_common.h"
+#include "demuxer_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* End of #ifdef __cplusplus */
+
+#define UNUSED_ATTR __attribute__((unused))
+
+/* 30720 = 30 * 1024 = 30k */
+#define FF_AAC_BUFFER_LEN 30720
+#define HI_FALSE 0
+#define HI_TRUE 1
+
+typedef enum {
+    HI_FFDEMUX_FORMAT_MP4 = 0,
+    HI_FFDEMUX_FORMAT_TS,
+    HI_FFDEMUX_FORMAT_WAV,
+    HI_FFDEMUX_FORMAT_MP3,
+    HI_FFDEMUX_FORMAT_AAC,
+    HI_FFDEMUX_FORMAT_HLS,
+    HI_FFDEMUX_FORMAT_BUTT
+} FfDemuxFormat;
+
+typedef struct {
+    pthread_mutex_t mutex;
+    char filePath[PATH_MAX + 1];
+    int64_t fileSize;
+
+    AVFormatContext *formatContext;
+    AVPacket *pkt;
+    int64_t lastReadPts; /* unit AV_TIME_BASE */
+    const char *formatName;
+    FfDemuxFormat formatType;
+
+    AVStream *audioStream;
+    enum AVCodecID audioCodeId;
+    int32_t audioStreamIndex;
+    uint32_t sampleRate;
+    uint32_t chnnum;
+    uint8_t aacBuf[FF_AAC_BUFFER_LEN]; /* store aac contains adts header */
+    AVPacket *pktBak;
+    bool cached;
+    int64_t cacheLastPts;
+} FfDemuxContext;
+
+int32_t FfOpen(FfDemuxContext *demux, const char *fileName, uint32_t fileNameLen);
+void FfClean(FfDemuxContext *demux);
+void FfClose(FfDemuxContext *demux);
+int32_t FfFreePacket(const FfDemuxContext *demux, AVPacket *pkt);
+int32_t FfProbe(FfDemuxContext *demux);
+void FfDiscardStream(AVStream *stream);
+int32_t FfProbeAudio(FfDemuxContext *demux, bool *hasAudio);
+int32_t FfGetinfo(const FfDemuxContext *demux, MediaFileInfo *fmtInfo);
+bool FfHasAudio(const FfDemuxContext *demux);
+int32_t FfReadPacket(const FfDemuxContext *demux, AVPacket *pkt);
+void FfGenFrameByAvPacket(FfDemuxContext *demux, FormatPacket *fmtFrame);
+int32_t FfSeek(FfDemuxContext *demux, int32_t streamIndex, int64_t toMs, uint32_t flag);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* FF_WRAPPER_H */
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/ogg_muxer/CMakeLists.txt b/code/sdk/middleware/services/media/hal/format/plugins/ogg_muxer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b3590da
--- /dev/null
@@ -0,0 +1,53 @@
+#===============================================================================
+# @brief    cmake file
+# Copyright (c) CompanyNameMagicTag 2025-2025. All rights reserved.
+#===============================================================================
+set(COMPONENT_NAME "plugin_demuxer_ogg")
+
+# use build env and option camke
+include(../../../../build/build_env.cmake)
+include(../../../../build/build_option.cmake)
+
+set(SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/ogg_manager.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/ogg_muxer.c
+)
+
+set(PUBLIC_HEADER
+)
+
+set(OPENMG_DIR ${ROOT_DIR}/open_source/openharmony)
+set(OGG_INCLUDE ${OPENMG_DIR}/../libogg/libogg-1.3.5/include)
+set(PRIVATE_HEADER
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../include
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../common/include
+    ${OGG_INCLUDE}
+    ${OGG_INCLUDE}/ogg/
+)
+
+set(PRIVATE_DEFINES
+)
+
+set(NEWCDEFINES "ENABLE_PLUGIN_MUXER_OGG")
+set(PUBLIC_DEFINES
+    ${NEWCDEFINES}
+)
+
+set(COMPONENT_PUBLIC_CCFLAGS
+)
+
+set(COMPONENT_CCFLAGS
+)
+
+set(WHOLE_LINK
+    true
+)
+
+set(MAIN_COMPONENT
+    false
+)
+
+set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib/media/${BOARD}_${APPLICATION}/${OS}/${COMPONENT_NAME})
+
+build_component()
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/ogg_muxer/ogg_manager.c b/code/sdk/middleware/services/media/hal/format/plugins/ogg_muxer/ogg_manager.c
new file mode 100644 (file)
index 0000000..8914f1a
--- /dev/null
@@ -0,0 +1,249 @@
+/*\r
+ * Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.\r
+ * Description: ogg manager file\r
+ * Author: Media Software Group\r
+ * Create: 2025-09-28\r
+ */\r
+#include "ogg_manager.h"\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <limits.h>\r
+#include <stdlib.h>\r
+#include <unistd.h>\r
+#include <fcntl.h>\r
+#ifdef SUPPORT_SYS_PRCTL\r
+#include <sys/prctl.h>\r
+#endif\r
+#include "securec.h"\r
+#include "media_hal_common.h"\r
+#include "ogg.h"\r
+\r
+#define MODULE_NAME "ogg_manager"\r
+\r
+#define HEADER_STRLEN 9\r
+#define OPUS_DELAY_TIME_DIVISOR 0\r
+#define OPUS_DELAY_TIME_DIVIDED 100\r
+#define OPUS_ID_HEADER_LEN 19\r
+#define OPUS_COMMENT_HEADER_LEN 25\r
+#define OPUS_COMMENT_TAIL_LEN 4\r
+#define OPUS_OPUSTAGS_LEN 12\r
+#define OPUS_SAMPLERATE 48000\r
+\r
+typedef struct {\r
+    ogg_stream_state oggStream;\r
+    int32_t sampleRate;\r
+    int32_t channels;\r
+    int64_t granulepos;\r
+    int64_t packetCount;\r
+    int32_t serialno;\r
+    bool isInited;\r
+    ogg_page *page;\r
+    ogg_packet *packet;\r
+    unsigned char *idHeader;\r
+    unsigned char *commentHeader;\r
+} OggContext;\r
+\r
+static OggContext g_oggCtx = {};\r
+\r
+static int32_t OggHeaderInit(int32_t channels)\r
+{\r
+    const char *idHeader = "OpusHead";\r
+    const char *commentHeader = "OpusTags";\r
+    const char *vendor = "libogg-1.3.5";\r
+    uint32_t vendorLen = strlen(vendor);\r
+    uint32_t preSkip = g_oggCtx.sampleRate * OPUS_DELAY_TIME_DIVISOR / OPUS_DELAY_TIME_DIVIDED;\r
+    g_oggCtx.idHeader = (uint8_t *)(MediaHalCalloc(OPUS_ID_HEADER_LEN));\r
+    uint32_t commentHeaderResLen = OPUS_COMMENT_HEADER_LEN - OPUS_OPUSTAGS_LEN;\r
+    CHK_NULL_RETURN(g_oggCtx.idHeader, MEDIA_HAL_ERR, "ogg idHeader malloc failed!");\r
+    if (memcpy_s(g_oggCtx.idHeader, OPUS_ID_HEADER_LEN, idHeader, strlen(idHeader)) != 0) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "ogg idHeader memcpy failed!");\r
+        goto FREE_ID_HEADER;\r
+    }\r
+    g_oggCtx.idHeader[0x8] = 0x01;\r
+    g_oggCtx.idHeader[0x9] = channels;\r
+    g_oggCtx.idHeader[0xA] = preSkip & 0xFF;\r
+    g_oggCtx.idHeader[0xB] = (preSkip >> 0x8);\r
+    g_oggCtx.idHeader[0xC] = g_oggCtx.sampleRate & 0xFF;\r
+    g_oggCtx.idHeader[0xD] = (g_oggCtx.sampleRate >> 0x8) & 0xFF;\r
+    g_oggCtx.idHeader[0xE] = (g_oggCtx.sampleRate >> 0x10) & 0xFF;\r
+    g_oggCtx.idHeader[0xF] = (g_oggCtx.sampleRate >> 0x18) & 0xFF;\r
+    g_oggCtx.commentHeader = (uint8_t *)(MediaHalCalloc(OPUS_COMMENT_HEADER_LEN));\r
+    if (g_oggCtx.commentHeader == NULL) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "ogg commentHeader malloc failed!");\r
+        goto FREE_ID_HEADER;\r
+    }\r
+    if (memcpy_s(g_oggCtx.commentHeader, OPUS_COMMENT_HEADER_LEN, commentHeader, strlen(commentHeader)) != 0) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "ogg commentHeader memcpy failed!");\r
+        goto FREE_COMMENT_HEADER;\r
+    }\r
+    g_oggCtx.commentHeader[0x8] = vendorLen & 0xFF;\r
+    g_oggCtx.commentHeader[0x9] = (vendorLen >> 0x8) & 0xFF;\r
+    g_oggCtx.commentHeader[0xA] = (vendorLen >> 0x10) & 0xFF;\r
+    g_oggCtx.commentHeader[0xB] = (vendorLen >> 0x18) & 0xFF;\r
+    if (memcpy_s(g_oggCtx.commentHeader + OPUS_OPUSTAGS_LEN, commentHeaderResLen, vendor, strlen(vendor)) != 0) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "ogg vendor memcpy failed!");\r
+        goto FREE_COMMENT_HEADER;\r
+    }\r
+    return MEDIA_HAL_OK;\r
+FREE_COMMENT_HEADER:\r
+    MediaHalFree((void **)&g_oggCtx.commentHeader);\r
+    g_oggCtx.commentHeader = NULL;\r
+FREE_ID_HEADER:\r
+    MediaHalFree((void **)&g_oggCtx.idHeader);\r
+    g_oggCtx.idHeader = NULL;\r
+    return MEDIA_HAL_ERR;\r
+}\r
+\r
+static int32_t OggStreamFlush(int32_t fd)\r
+{\r
+    while (ogg_stream_flush(&g_oggCtx.oggStream, g_oggCtx.page)) {\r
+        int32_t ret = write(fd, g_oggCtx.page->header, g_oggCtx.page->header_len);\r
+        if (ret != g_oggCtx.page->header_len) {\r
+            MEDIA_HAL_LOGE(MODULE_NAME, "errno:%d, errmsg:%s", errno, strerror(errno));\r
+            return MEDIA_HAL_ERR;\r
+        }\r
+        ret = write(fd, g_oggCtx.page->body,  g_oggCtx.page->body_len);\r
+        if (ret != g_oggCtx.page->body_len) {\r
+            MEDIA_HAL_LOGE(MODULE_NAME, "errno:%d, errmsg:%s", errno, strerror(errno));\r
+            return MEDIA_HAL_ERR;\r
+        }\r
+    }\r
+    return MEDIA_HAL_OK;\r
+}\r
+\r
+static void OggParamInit(int32_t sampleRate, int32_t channels)\r
+{\r
+    g_oggCtx.sampleRate = sampleRate;\r
+    g_oggCtx.channels = channels;\r
+    g_oggCtx.granulepos = 0;\r
+    g_oggCtx.packetCount = 0;\r
+    g_oggCtx.serialno = 0x1;\r
+}\r
+\r
+static void OggPacketIn(unsigned char *packet, int32_t bytes)\r
+{\r
+    g_oggCtx.packet->packet = packet;\r
+    g_oggCtx.packet->bytes = bytes;\r
+    g_oggCtx.packet->b_o_s = g_oggCtx.packetCount != 0 ? 0 : 1; // 1 means first page\r
+    g_oggCtx.packet->e_o_s = 0;\r
+    g_oggCtx.packet->granulepos = g_oggCtx.packetCount != 0 ? g_oggCtx.granulepos : -1; // -1 means first page\r
+    g_oggCtx.packet->packetno = g_oggCtx.packetCount++;\r
+    ogg_stream_packetin(&g_oggCtx.oggStream, g_oggCtx.packet);\r
+}\r
+\r
+int32_t OggCtxInit(int32_t fd, int32_t sampleRate, int32_t channels)\r
+{\r
+    if (g_oggCtx.isInited) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "Ogg context has inited!");\r
+        goto EXIT;\r
+    }\r
+    g_oggCtx.packet = (ogg_packet *)MediaHalCalloc(sizeof(ogg_packet));\r
+    if (g_oggCtx.packet == NULL) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "ogg context packet malloc failed!");\r
+        goto EXIT;\r
+    }\r
+    g_oggCtx.page = (ogg_page *)MediaHalCalloc(sizeof(ogg_page));\r
+    if (g_oggCtx.page == NULL) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "ogg context page malloc failed!");\r
+        goto FREE_PACKET;\r
+    }\r
+    OggParamInit(sampleRate, channels);\r
+    if (ogg_stream_init(&g_oggCtx.oggStream, g_oggCtx.serialno) != MEDIA_HAL_OK) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "ogg stream init failed!");\r
+        goto FREE_PAGE;\r
+    }\r
+    if (OggHeaderInit(channels) != MEDIA_HAL_OK) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "Header init failed!");\r
+        goto STREAM_CLEAR;\r
+    }\r
+    OggPacketIn(g_oggCtx.idHeader, OPUS_ID_HEADER_LEN);\r
+    if (OggStreamFlush(fd) != MEDIA_HAL_OK) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "ogg packet flush failed!");\r
+        goto HEADER_FREE;\r
+    }\r
+    OggPacketIn(g_oggCtx.commentHeader, OPUS_COMMENT_HEADER_LEN);\r
+    if (OggStreamFlush(fd) != MEDIA_HAL_OK) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "ogg header flush failed!");\r
+        goto HEADER_FREE;\r
+    }\r
+    g_oggCtx.isInited = true;\r
+    return MEDIA_HAL_OK;\r
+HEADER_FREE:\r
+    MediaHalFree((void **)&g_oggCtx.idHeader);\r
+    MediaHalFree((void **)&g_oggCtx.commentHeader);\r
+STREAM_CLEAR:\r
+    ogg_stream_clear(&g_oggCtx.oggStream);\r
+FREE_PAGE:\r
+    MediaHalFree((void **)&g_oggCtx.page);\r
+FREE_PACKET:\r
+    MediaHalFree((void **)&g_oggCtx.packet);\r
+EXIT:\r
+    return MEDIA_HAL_ERR;\r
+}\r
+\r
+void OggCtxDeInit()\r
+{\r
+    g_oggCtx.sampleRate = 0;\r
+    g_oggCtx.channels = 0;\r
+    g_oggCtx.granulepos = 0;\r
+    g_oggCtx.packetCount = 0;\r
+    if (g_oggCtx.packet != NULL) {\r
+        MediaHalFree(g_oggCtx.packet);\r
+        g_oggCtx.packet = NULL;\r
+    }\r
+    if (g_oggCtx.page != NULL) {\r
+        MediaHalFree(g_oggCtx.page);\r
+        g_oggCtx.page = NULL;\r
+    }\r
+    if (g_oggCtx.idHeader != NULL) {\r
+        MediaHalFree(g_oggCtx.idHeader);\r
+        g_oggCtx.idHeader = NULL;\r
+    }\r
+    if (g_oggCtx.commentHeader != NULL) {\r
+        MediaHalFree(g_oggCtx.commentHeader);\r
+        g_oggCtx.commentHeader = NULL;\r
+    }\r
+    ogg_stream_clear(&g_oggCtx.oggStream);\r
+    g_oggCtx.isInited = false;\r
+}\r
+\r
+static int32_t OggWritePage(int32_t fd)\r
+{\r
+    while (ogg_stream_pageout(&g_oggCtx.oggStream, g_oggCtx.page)) {\r
+        int32_t ret = write(fd, g_oggCtx.page->header, g_oggCtx.page->header_len);\r
+        if (ret != g_oggCtx.page->header_len) {\r
+            MEDIA_HAL_LOGE(MODULE_NAME, "errno:%d, errmsg:%s", errno, strerror(errno));\r
+            return MEDIA_HAL_ERR;\r
+        }\r
+        ret = write(fd, g_oggCtx.page->body, g_oggCtx.page->body_len);\r
+        if (ret != g_oggCtx.page->body_len) {\r
+            MEDIA_HAL_LOGE(MODULE_NAME, "errno:%d, errmsg:%s", errno, strerror(errno));\r
+            return MEDIA_HAL_ERR;\r
+        }\r
+    }\r
+    return MEDIA_HAL_OK;\r
+}\r
+\r
+int32_t OggWritePacket(int32_t fd, uint8_t *buffer, int64_t bufferLen, int64_t samplePoint)\r
+{\r
+    if (bufferLen < 0) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "input buffer invalid");\r
+        return MEDIA_HAL_ERR;\r
+    }\r
+    OggPacketIn((unsigned char *)(buffer), bufferLen);\r
+    g_oggCtx.granulepos += samplePoint;\r
+    return OggWritePage(fd);\r
+}\r
+\r
+int32_t OggWriteEosPacket(int32_t fd)\r
+{\r
+    unsigned char emptyData = 0;\r
+    g_oggCtx.packet->packet = &emptyData;\r
+    g_oggCtx.packet->bytes = 1;\r
+    g_oggCtx.packet->b_o_s = 0;\r
+    g_oggCtx.packet->e_o_s = 1;\r
+    g_oggCtx.packet->granulepos = g_oggCtx.granulepos;\r
+    g_oggCtx.packet->packetno = g_oggCtx.packetCount;\r
+    ogg_stream_packetin(&g_oggCtx.oggStream, g_oggCtx.packet);\r
+    return OggStreamFlush(fd);\r
+}
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/ogg_muxer/ogg_manager.h b/code/sdk/middleware/services/media/hal/format/plugins/ogg_muxer/ogg_manager.h
new file mode 100644 (file)
index 0000000..905da84
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+ * Description: ogg manager file
+ * Author: Media Software Group
+ * Create: 2025-09-28
+ */
+#ifndef OGG_MANAGER_H
+#define OGG_MANAGER_H
+#include <stdint.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int32_t OggCtxInit(int32_t fd, int32_t sampleRate, int32_t channels);
+void OggCtxDeInit(void);
+int32_t OggWritePacket(int32_t fd, uint8_t *buffer, int64_t bufferLen, int64_t samplePoint);
+int32_t OggWriteEosPacket(int32_t fd);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/ogg_muxer/ogg_muxer.c b/code/sdk/middleware/services/media/hal/format/plugins/ogg_muxer/ogg_muxer.c
new file mode 100644 (file)
index 0000000..f155233
--- /dev/null
@@ -0,0 +1,649 @@
+/*
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: wav_muxer.c
+* Author: Media Software Group
+* Create: 2025-03-10
+*/
+
+#include "ogg_muxer.h"
+#include <malloc.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "muxer_interface.h"
+#include "dtcf_manager.h"
+#include "media_hal_common.h"
+#include "securec.h"
+#include "ogg_manager.h"
+
+#define MODULE_NAME "oggMuxer"
+
+#define BYTE_UNIT 1024
+#define OGG_MUXER_PRIORITY 100\r
+#ifdef SUPPORT_FEATURE_CONFIG\r
+#define INTERVAL_RECORD_FRAME (1000 / CONFIG_AUDIO_AI_FRAME_PER_SEC)\r
+#else\r
+#define INTERVAL_RECORD_FRAME 10\r
+#endif
+#define MSEC_PER_SEC (1000)
+#define REC_SPLIT_TIME_THRESHOLD (0.9)
+#define REC_SPLIT_SIZE_THRESHOLD (0.9)
+#define REC_US_TO_S (1000000.0)
+#define OPUS_SAMPLERATE 48000
+#define SIZE_PER_SAMPLE 2
+
+/* <max file size, determined by the file system */
+#ifndef ONLY_UT_TEST
+/* (4*1024*1024*1024-1*1024*1024*1024) */
+#define REC_MAX_FILE_SIZE (3221225472LL)
+#else
+/* 20*1024*1024 */
+#define REC_MAX_FILE_SIZE (20971520LL)
+#endif
+#define FILE_INFO_BUFFER_SIZE 350
+#define FILE_MODEL 0644
+
+typedef struct {
+    MuxerOutput muxerOutput;
+    MuxerTrackSource trackSource;
+    char fileName[REC_FILE_NAME_LEN];
+    int32_t fp;
+    bool muxerStarted;
+    int64_t maxFileSize;
+    int64_t maxDuration;
+    PluginCallback callBack;
+    DtcfCallBack dtcfCallBack;
+    uint64_t streamSize;
+    int64_t currentPos;
+    bool splitSizeBegin;
+    bool splitTimeBegin;
+    uint32_t realRecTimeLenMs;
+    uint64_t baseFramePts;
+    MediaHalMutexHandle mutex;
+    uint64_t maxMemorySize;
+    bool isSupportSplit;
+} OggMuxerContext;
+
+typedef struct {
+    int32_t dataLength;
+    int64_t frameTimeStamp;
+} OggFrameData;
+
+
+static void ReportInfo(PluginCallback callBack, PluginInfoType infoType, int32_t extra)
+{
+    CHK_NULL_RETURN_NONE(callBack.OnInfo, "OnInfo invalid pointer");
+    callBack.OnInfo(callBack.handle, infoType, extra);
+}
+
+static void ReportError(PluginCallback callBack, int32_t errorType, int32_t errorCode)
+{
+    CHK_NULL_RETURN_NONE(callBack.OnError, "OnError invalid pointer");
+    callBack.OnError(callBack.handle, errorType, errorCode);
+}
+
+static int32_t DtcfEventCallBack(void *callBack, DtcfCallBackType errorType, int32_t errorCode)
+{
+    CHK_NULL_RETURN(callBack, MEDIA_HAL_INVALID_PARAM, "callBack invalid pointer");
+    OggMuxerContext *context = (OggMuxerContext *)callBack;
+    CHK_NULL_RETURN(context->callBack.OnError, MEDIA_HAL_INVALID_PARAM, "OnError invalid pointer");
+    PluginErrorType pluginErrorType;
+    switch (errorType) {
+        case DELETE_THE_OLDEST_FAILED:
+            context->callBack.OnError(context->callBack.handle, ERROR_TYPE_INTERNAL_OPERATION_FAIL, errorCode);
+            break;
+        case MEMORY_REACH_THE_MAXIMUM_VALUE:
+            context->callBack.OnInfo(context->callBack.handle, MAX_MEMORYSIZE_REACHED, errorCode);
+            break;
+        default:
+            MEDIA_HAL_LOGE(MODULE_NAME, "not support type = %d", errorType);
+            break;
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t OggMuxerFind(const MuxerOutput *output, const ProtocolFun *protocol)
+{
+    CHK_NULL_RETURN(output, MEDIA_HAL_INVALID_PARAM, "output is NULL");
+    if (output->type == OUT_TYPE_INVALID) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "out type invlid");
+        return MEDIA_HAL_INVALID_PARAM;
+    }
+    if (protocol != NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "not support extra protocol");
+        return MEDIA_HAL_INVALID_PARAM;
+    }
+    if (output->format != FORMAT_TYPE_OGG) {
+        MEDIA_HAL_LOGI(MODULE_NAME, "oggMuxer not Found format = %d", output->format);
+        return MEDIA_HAL_ERR;
+    }
+    MEDIA_HAL_LOGI(MODULE_NAME, "oggMuxer Found");
+    return MEDIA_HAL_OK;
+}
+
+static int32_t OpenOutTypeUriProcess(const MuxerOutput *output, DtcfCallBack callBack)
+{
+    int32_t optInit = DtcfMgrFileOptInit(output->url, strlen(output->url) + 1, callBack);
+    if (optInit != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "DtcfMgrFileOptInit fail 0x%x", optInit);
+        (void)DtcfMgrFileOptDeInit();
+        return MEDIA_HAL_ERR;
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t InitOggMuxer(OggMuxerContext *ctx)
+{
+    if (ctx->muxerOutput.type == OUT_TYPE_URI) {
+        if (DtcfMgrIsFile(ctx->muxerOutput.url, REC_FILE_NAME_LEN)) {\r
+            ctx->isSupportSplit = false;\r
+            MEDIA_HAL_LOGI(MODULE_NAME, "DtcfMgrIsFile is enter, ctx->muxerOutput.url = %s", ctx->muxerOutput.url);\r
+            int32_t ret = DtcfMgrMakeDir(ctx->muxerOutput.url, REC_FILE_NAME_LEN);
+            if (ret != MEDIA_HAL_OK) {
+                MEDIA_HAL_LOGE(MODULE_NAME, "DtcfMgrMakeDir error");
+                return MEDIA_HAL_ERR;
+            }\r
+            ctx->fp = open(ctx->muxerOutput.url, O_RDWR | O_CREAT | O_TRUNC, FILE_MODEL);\r
+            if (ctx->fp < 0) {
+                MEDIA_HAL_LOGE(MODULE_NAME, "open file error, errno = %d", errno);
+                return MEDIA_HAL_ERR;
+            }\r
+            if (memcpy_s(ctx->fileName, REC_FILE_NAME_LEN, ctx->muxerOutput.url, REC_FILE_NAME_LEN) != EOK) {
+                MEDIA_HAL_LOGE(MODULE_NAME, "memcpy_s failed");
+                close(ctx->fp);
+                ctx->fp = -1;
+                return MEDIA_HAL_ERR;
+            }\r
+            return MEDIA_HAL_OK;\r
+        }\r
+        ctx->isSupportSplit = true;\r
+        int32_t ret = OpenOutTypeUriProcess(&ctx->muxerOutput, ctx->dtcfCallBack);
+        if (ret != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "OpenOutTypeUriProcess error, ret = %d", ret);
+            return MEDIA_HAL_ERR;
+        }\r
+        char fileNames[2][REC_FILE_NAME_LEN];
+        ret = DtcfMgrRequestFileNames(DTCF_FILE_TYPE_OGG, DTCF_DIR_RECORD_OGG_FILE, fileNames);
+        if (ret != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "DtcfMgrRequestFileNames error");
+            return MEDIA_HAL_ERR;
+        }
+        ctx->fp = open(fileNames[0], O_RDWR | O_CREAT | O_TRUNC, 0);
+        if (ctx->fp < 0) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "open file error, errno = %d", errno);
+            return MEDIA_HAL_ERR;
+        }
+        if (memcpy_s(ctx->fileName, REC_FILE_NAME_LEN, fileNames[0], REC_FILE_NAME_LEN) != EOK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "memcpy_s failed");
+            return MEDIA_HAL_ERR;
+        }
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t OggMuxerOpen(const MuxerOutput *output, const ProtocolFun *protocol, RecMuxerHandle *handle)
+{
+    MEDIA_HAL_UNUSED(protocol);
+    CHK_NULL_RETURN(output, MEDIA_HAL_INVALID_PARAM, "output is null");
+    CHK_NULL_RETURN(handle, MEDIA_HAL_INVALID_PARAM, "handle is null");
+    
+    OggMuxerContext *ctx = (OggMuxerContext*)malloc(sizeof(OggMuxerContext));
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_NO_MEM, "OggMuxerContext is null");
+    int32_t ret = MEDIA_HAL_OK;
+    if (memset_s(ctx, sizeof(OggMuxerContext), 0x0, sizeof(OggMuxerContext)) != EOK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "memset_s OggMuxerContext error");
+        goto CREATE_FAILED;
+    }
+    ctx->mutex = MediaHalMutexCreate(NULL);
+    if (ctx->mutex == NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "MediaHalMutexCreate failed!");
+        goto CREATE_FAILED;
+    }
+    ctx->muxerOutput = *output;
+    ctx->dtcfCallBack.handle = ctx;
+    ctx->dtcfCallBack.CallBack = DtcfEventCallBack;
+    ret = InitOggMuxer(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "InitOggMuxer failed:0x%x", ret);
+        goto MUXER_DESTORY;
+    }
+    *handle = ctx;
+    if (ctx->isSupportSplit) {\r
+        ret = DtcfMgrGetStorageMaxSize(&ctx->maxMemorySize);
+        if (ret != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "DtcfGetStorageMaxSize failed!");
+        }\r
+    }
+    MEDIA_HAL_LOGI(MODULE_NAME, "OggMuxerOpen :%d", ret);
+    return MEDIA_HAL_OK;
+MUXER_DESTORY:
+    MediaHalMutexDestroy(&ctx->mutex);
+CREATE_FAILED:
+    free(ctx);
+    return MEDIA_HAL_ERR;
+}
+
+static int32_t DeinitOggMuxer(OggMuxerContext *ctx)
+{
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "handle");
+    if (OggWriteEosPacket(ctx->fp) != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "ogg write eos failed!");
+    }
+    OggCtxDeInit();
+    close(ctx->fp);
+    ctx->fp = -1;
+    ctx->muxerStarted = false;
+    ctx->isSupportSplit = false;
+    MEDIA_HAL_LOGI(MODULE_NAME, "DeinitOggMuxer success");
+    return MEDIA_HAL_OK;
+}
+
+static int32_t OggMuxerDestroy(RecMuxerHandle handle)
+{
+    OggMuxerContext *ctx = (OggMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "handle");
+    int32_t ret = DeinitOggMuxer(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "call DeinitOggMuxer fail:0x%x", ret);
+    }
+    if (ctx->isSupportSplit) {
+        (void)DtcfMgrFileOptDeInit();
+    }
+    MediaHalMutexDestroy(&ctx->mutex);
+    free(ctx);
+    MEDIA_HAL_LOGI(MODULE_NAME, "OggMuxerDestroy success");
+    return MEDIA_HAL_OK;
+}
+
+static int32_t AddAudioTrack(OggMuxerContext *ctx)
+{
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "ctx is null");
+    int32_t ret = OggCtxInit(ctx->fp, ctx->trackSource.info.audioInfo.sampleRate,
+        ctx->trackSource.info.audioInfo.channelCount);
+    MEDIA_HAL_LOGE(MODULE_NAME, "ctx->trackSource.info.audioInfo.sampleRate = %d!", ctx->trackSource.info.audioInfo.sampleRate);
+    if (ret != MEDIA_HAL_OK) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "OggCtxInit failed!");\r
+        return MEDIA_HAL_ERR;\r
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t OggMuxerAddTrack(RecMuxerHandle handle, const MuxerTrackSource *trackSource)
+{
+    CHK_NULL_RETURN(trackSource, MEDIA_HAL_INVALID_PARAM, "trackSource is null");
+    OggMuxerContext *ctx = (OggMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "OggMuxerContext is null");
+    if (trackSource->type != STREAM_TYPE_AUDIO) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "only support STREAM_TYPE_AUDIO!");
+        return MEDIA_HAL_ERR;
+    }
+    ctx->trackSource = *trackSource;
+    int32_t ret = AddAudioTrack(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "MuxerAddTrack failed [0x%x]", ret);
+    }
+    return ret;
+}
+
+static int32_t OggMuxerStart(RecMuxerHandle handle)
+{
+    OggMuxerContext *ctx = (OggMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "ctx is null");
+    CHK_COND_RETURN(ctx->muxerStarted, MEDIA_HAL_OK, "ctx is Started");
+    ctx->muxerStarted = true;\r
+    ctx->splitSizeBegin = !ctx->isSupportSplit;
+    ctx->splitTimeBegin = !ctx->isSupportSplit;
+    MEDIA_HAL_LOGI(MODULE_NAME, "OggMuxerStart success ");
+    return MEDIA_HAL_OK;
+}
+
+static bool SplitIsAchiveSize(OggMuxerContext *ctx)
+{
+    bool result = false;
+    if (ctx->splitSizeBegin) {
+        if (ctx->maxFileSize > 0 && ctx->streamSize >= ctx->maxFileSize * REC_SPLIT_SIZE_THRESHOLD) {
+            ReportInfo(ctx->callBack, MAX_FILESIZE_APPROACHING,
+                ctx->muxerOutput.type == OUT_TYPE_FD ? ctx->muxerOutput.fd : -1);
+            MEDIA_HAL_LOGI(MODULE_NAME, "size %lld Approaching maxFileSize %lld", ctx->streamSize, ctx->maxFileSize);
+            ctx->splitSizeBegin = false;
+        }
+    }
+
+    if ((ctx->maxFileSize > 0 && ctx->streamSize >= (uint64_t)ctx->maxFileSize) ||
+        ctx->streamSize >= REC_MAX_FILE_SIZE) {
+        ReportInfo(ctx->callBack, MAX_FILESIZE_REACHED,
+            ctx->muxerOutput.type == OUT_TYPE_FD ? ctx->muxerOutput.fd : -1);
+        result = true;
+        MEDIA_HAL_LOGI(MODULE_NAME, "size %lld has Approached maxFileSize %lld", ctx->streamSize, ctx->maxFileSize);
+        ctx->streamSize = 0;
+        ctx->splitSizeBegin = true;
+        ctx->baseFramePts = 0;
+    }
+    return result;
+}
+
+static bool SplitIsAchiveTime(OggMuxerContext *ctx)
+{
+    bool result = false;
+    uint32_t realRecTimeLen = ctx->realRecTimeLenMs / MSEC_PER_SEC;
+    if (ctx->splitTimeBegin) {
+        if (ctx->maxDuration > 0 && realRecTimeLen >= ctx->maxDuration * REC_SPLIT_TIME_THRESHOLD) {
+            ReportInfo(ctx->callBack, MAX_DURATION_APPROACHING,
+                ctx->muxerOutput.type == OUT_TYPE_FD ? ctx->muxerOutput.fd : -1);
+            MEDIA_HAL_LOGI(MODULE_NAME, "realRecTimeLen %u Approaching maxDuration %lld",
+                realRecTimeLen, ctx->maxDuration);
+            ctx->splitTimeBegin = false;
+        }
+    }
+    if (ctx->maxDuration > 0 && realRecTimeLen >= ctx->maxDuration) {
+        // split and reset manual split info
+        ReportInfo(ctx->callBack, MAX_DURATION_REACHED,
+            ctx->muxerOutput.type == OUT_TYPE_FD ? ctx->muxerOutput.fd : -1);
+        result = true;
+        MEDIA_HAL_LOGI(MODULE_NAME, "time %u has Approached maxDuration %lld", ctx->realRecTimeLenMs, ctx->maxDuration);
+        ctx->splitTimeBegin = true;
+        ctx->baseFramePts = 0;
+        ctx->streamSize = 0;
+    }
+    return result;
+}
+
+static int32_t ReConfigMuxer(OggMuxerContext *ctx)
+{
+    int32_t ret = DeinitOggMuxer(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "call DeinitOggMuxer fail:0x%x", ret);
+        return MEDIA_HAL_ERR;
+    }
+    ret = InitOggMuxer(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "CreateOggMuxer failed:0x%x", ret);
+        return MEDIA_HAL_ERR;
+    }
+    ret = AddAudioTrack(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "AddAudioTrack failed:0x%x", ret);
+        DeinitOggMuxer(ctx);
+        return MEDIA_HAL_ERR;
+    }
+    ctx->muxerStarted = true;
+    MEDIA_HAL_LOGE(MODULE_NAME, "ReConfigMuxer success");
+    return MEDIA_HAL_OK;
+}
+
+static int32_t OggMuxerWriteFrameInner(OggMuxerContext *ctx, const FormatPacket *frameData,
+    const OggFrameData *wavFrameData)
+{
+    int64_t point = ((frameData->timestampUs - ctx->currentPos) / REC_US_TO_S) * OPUS_SAMPLERATE;
+    ctx->currentPos = frameData->timestampUs;
+    if (OggWritePacket(ctx->fp, frameData->data, frameData->len, point) != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "fwrite failed errno:%d", errno);
+        return MEDIA_HAL_ERR_AGAIN;
+    }
+    if (ctx->isSupportSplit) {
+        if (ctx->streamSize == 0) {
+            ctx->streamSize += wavFrameData->dataLength;
+        }
+        if (ctx->baseFramePts == 0) {
+            ctx->baseFramePts = wavFrameData->frameTimeStamp;
+        }
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t HandleOggFrame(OggMuxerContext *ctx, OggFrameData *wavFrameData, const FormatPacket *frameData)
+{
+    CHK_NULL_RETURN(frameData, MEDIA_HAL_INVALID_PARAM, "wavFrameData is NULL!");
+    wavFrameData->dataLength = frameData->len;
+    wavFrameData->frameTimeStamp = frameData->timestampUs;
+    if (ctx->isSupportSplit) {
+        uint32_t frameNum = frameData->timestampUs / (MSEC_PER_SEC* INTERVAL_RECORD_FRAME);
+        uint32_t frameSize = frameData->len;
+        if (frameNum != 0) {
+            frameSize = frameData->len / frameNum;
+        }
+        if (ctx->maxDuration < 1 || ctx->maxFileSize < frameSize) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "file duration or size is not right, write file failed!");
+            return MEDIA_HAL_ERR;
+        }
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t OggMuxerWriteFrame(RecMuxerHandle handle, const FormatPacket *frameData)
+{
+    CHK_NULL_RETURN(frameData, MEDIA_HAL_INVALID_PARAM, "frameData is NULL!");
+    OggMuxerContext *ctx = (OggMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "OggMuxerContext is null");
+    CHK_COND_RETURN(!ctx->muxerStarted, MEDIA_HAL_ERR, "OggMuxerContext is not Started");
+    if (ctx->isSupportSplit) {
+        if (DtcfMgrHandleRecordMaxSize(frameData->len, ctx->maxMemorySize) != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "handle reac max size failed!");
+            return MEDIA_HAL_ERR;
+        }
+    }
+    OggFrameData wavFrameData = {};
+    if (HandleOggFrame(ctx, &wavFrameData, frameData) != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "handle wav frame failed!");
+        return MEDIA_HAL_ERR;
+    }
+    MediaHalMutexLock(ctx->mutex);
+    if (ctx->isSupportSplit) {\r
+        ctx->streamSize += wavFrameData.dataLength;
+        ctx->realRecTimeLenMs = (uint32_t)((wavFrameData.frameTimeStamp - ctx->baseFramePts) / MSEC_PER_SEC);
+        if (SplitIsAchiveSize(ctx) || SplitIsAchiveTime(ctx)) {
+            int32_t ret = ReConfigMuxer(ctx);
+            if (ret != MEDIA_HAL_OK) {
+                ReportError(ctx->callBack, ERROR_TYPE_INTERNAL_OPERATION_FAIL, ERROR_TYPE_INTERNAL_OPERATION_FAIL);
+                MediaHalMutexUnLock(ctx->mutex);
+                return MEDIA_HAL_ERR;
+            }
+        }\r
+    }
+    int32_t ret = OggMuxerWriteFrameInner(ctx, frameData, &wavFrameData);
+    if (ret != MEDIA_HAL_OK) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "OggMuxerWriteFrameInner failed!");
+        MediaHalMutexUnLock(ctx->mutex);
+        return ret;\r
+    }
+    MediaHalMutexUnLock(ctx->mutex);
+    return MEDIA_HAL_OK;
+}
+
+static int32_t OggMuxerStop(RecMuxerHandle handle, bool block)
+{
+    CHK_NULL_RETURN(handle, MEDIA_HAL_INVALID_PARAM, "handle");
+    OggMuxerContext *ctx = (OggMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "OggMuxerContext");
+    CHK_COND_RETURN(!ctx->muxerStarted, MEDIA_HAL_ERR, "OggMuxerContext is not Started");
+    MEDIA_HAL_LOGI(MODULE_NAME, " block %d", block);
+    ctx->muxerStarted = false;
+    return MEDIA_HAL_OK;
+}
+
+static int32_t OggMuxerSetMaxFileSize(RecMuxerHandle handle, int64_t bytes)
+{
+    CHK_NULL_RETURN(handle, MEDIA_HAL_INVALID_PARAM, "handle");
+    OggMuxerContext *ctx = (OggMuxerContext *)handle;
+    MEDIA_HAL_LOGI(MODULE_NAME, "bytes:%lld ", bytes);
+    ctx->maxFileSize = bytes;
+    return MEDIA_HAL_OK;
+}
+
+static int32_t OggMuxerSetMaxFileDuration(RecMuxerHandle handle, int64_t durationUs)
+{
+    CHK_NULL_RETURN(handle, MEDIA_HAL_INVALID_PARAM, "handle");
+    OggMuxerContext *ctx = (OggMuxerContext *)handle;
+    MEDIA_HAL_LOGI(MODULE_NAME, "durationUs:%lld ", durationUs);
+    ctx->maxDuration = durationUs;
+    return MEDIA_HAL_OK;
+}
+
+static int32_t OggMuxerSetNextOutputFile(RecMuxerHandle handle, int32_t fd)
+{
+    OggMuxerContext *ctx = (OggMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "handle is null");
+    MEDIA_HAL_LOGI(MODULE_NAME, "fd:%d", fd);
+    if (ctx->muxerOutput.type == OUT_TYPE_URI) {
+        return MEDIA_HAL_ERR;
+    }
+    ctx->muxerOutput.fd = fd;
+    return MEDIA_HAL_OK;
+}
+
+static int32_t MuxerSetCallBack(OggMuxerContext *ctx, const PluginCallback *callBack)
+{
+    CHK_NULL_RETURN(callBack, MEDIA_HAL_INVALID_PARAM, "callBack");
+    ctx->callBack = *callBack;
+    return MEDIA_HAL_OK;
+}
+
+static void GetCurrentStorageTimeRemaindTime(OggMuxerContext *ctx, uint32_t packetLen, uint32_t *time)
+{
+    if (!ctx->isSupportSplit) {
+        MEDIA_HAL_LOGI(MODULE_NAME, "not support get recorder time!");
+        return;
+    }
+    MediaHalMutexLock(ctx->mutex);
+    *time = ((DtcfMgrGetCurrentMemorySize(ctx->maxMemorySize) - DtcfMgrGetCurrentRecordedSize()) / packetLen) *
+        INTERVAL_RECORD_FRAME;
+    MEDIA_HAL_LOGI(MODULE_NAME, "remaind storage packetLen = %u, time:%u\n", packetLen, *time);
+    MediaHalMutexUnLock(ctx->mutex);
+}
+
+static void GetCurrentFileRemaindTime(OggMuxerContext *ctx, uint32_t packetLen, uint32_t *time)
+{
+    if (!ctx->isSupportSplit) {
+        MEDIA_HAL_LOGI(MODULE_NAME, "not support get file time!");
+        return;
+    }
+    MediaHalMutexLock(ctx->mutex);
+    uint32_t currentSec = ((ctx->maxFileSize / packetLen) * INTERVAL_RECORD_FRAME) / MSEC_PER_SEC;
+    if (currentSec >= ctx->maxDuration) {
+        *time = (ctx->maxDuration * MSEC_PER_SEC) - ctx->realRecTimeLenMs;
+    } else {
+        *time = ((ctx->maxFileSize - ctx->streamSize) / packetLen) * INTERVAL_RECORD_FRAME;
+    }
+    MEDIA_HAL_LOGI(MODULE_NAME, "remaind file packetLen = %u, time:%u", packetLen, *time);
+    MediaHalMutexUnLock(ctx->mutex);
+}
+
+static int32_t GetCurrentOggFileInfo(OggMuxerContext *ctx, char **value)
+{
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "handle is null");
+    CHK_NULL_RETURN(value, MEDIA_HAL_INVALID_PARAM, "value is null");
+    CHK_NULL_RETURN(*value, MEDIA_HAL_INVALID_PARAM, "real value is null");
+    if (!ctx->isSupportSplit) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "not support get file info!");
+        return MEDIA_HAL_ERR;
+    }
+    MediaHalMutexLock(ctx->mutex);
+    FileDate fileDate = {};
+    int32_t ret = DtcfMgrGetCurrentFileDate(&fileDate);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "Get Current File Date failed:%d", ret);
+        MediaHalMutexUnLock(ctx->mutex);
+        return ret;
+    }
+    char *lastSlash = strrchr(ctx->fileName, '/');
+    if (lastSlash == NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "Get Current File name failed!");
+        MediaHalMutexUnLock(ctx->mutex);
+        return MEDIA_HAL_ERR;
+    }
+    ret = sprintf_s(*value, FILE_INFO_BUFFER_SIZE, "%llu,%u,%u,%u,%u,%u,%u,%u=%s", ctx->streamSize,
+        fileDate.fileDateYear, fileDate.fileDateMonth, fileDate.fileDateDay, fileDate.fileDateHour,
+        fileDate.fileDateMin, fileDate.fileDateSec, ctx->realRecTimeLenMs, lastSlash + 1);
+    if (ret == -1 || ret >= FILE_INFO_BUFFER_SIZE) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "sprintf_s failed!");
+        MediaHalMutexUnLock(ctx->mutex);
+        return MEDIA_HAL_ERR;
+    }
+    MediaHalMutexUnLock(ctx->mutex);
+    return MEDIA_HAL_OK;
+}
+
+static int32_t OggMuxerInvoke(RecMuxerHandle handle, uint32_t invokeId, void *arg)
+{
+    int32_t ret = MEDIA_HAL_OK;
+    OggMuxerContext *ctx = (OggMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "muxerContext is NULL!");
+    CHK_NULL_RETURN(arg, MEDIA_HAL_INVALID_PARAM, "arg is NULL!");
+    MEDIA_HAL_LOGI(MODULE_NAME, "invokeId:%d ", invokeId);
+    switch (invokeId) {
+        case INVOKE_SET_CALLBACK:
+            ret = MuxerSetCallBack(ctx, (const PluginCallback *)arg);
+            break;
+        case INVOKE_SET_DELETE_OLD_FILES_ENABLE: {
+            uint32_t value = *((uint32_t *)arg);
+            bool enable = false;
+            if (value != 0) {
+                enable = true;
+            }
+            if (!ctx->isSupportSplit) {
+                enable = false;
+            }
+            DtcfMgrSetDeleteFileEnable(enable);
+            break;
+        }
+        case INVOKE_SET_MAX_STORAGE_THRESHOLD: {
+            uint32_t value = *((uint32_t *)arg);
+            DtcfMgrSetMaxStorageThreshold(value);
+            break;
+        }
+        case INVOKE_CURRENT_STORAGE_REMAIND_TIME: {
+            uint32_t packetLen = *((uint32_t *)arg);
+            GetCurrentStorageTimeRemaindTime(ctx, packetLen, (uint32_t *)arg);
+            break;
+        }
+        case INVOKE_CURRENT_FILE_REMAIND_TIME: {
+            uint32_t packetLen = *((uint32_t *)arg);
+            GetCurrentFileRemaindTime(ctx, packetLen, (uint32_t *)arg);
+            break;
+        }
+        case INVOKE_CURRENT_FILE_INFO: {
+            ret = GetCurrentOggFileInfo(ctx, (char **)arg);
+            break;
+        }
+        default:
+            MEDIA_HAL_LOGI(MODULE_NAME, "not support invokeId:%d ", invokeId);
+            break;
+    }
+    return ret;
+}
+
+MuxerPluginEntry g_oggMuxerEntry = {
+    .desc = {
+        .libName = "libplugin_muxer_ogg.so",
+        .name = "ogg_muxer",
+        .version = "version 1.0.0",
+        .description = "ogg_muxer",
+        .supportCapability = "ogg",
+        .priority = OGG_MUXER_PRIORITY,
+    },
+    .fmt_find = OggMuxerFind,
+    .fmt_open = OggMuxerOpen,
+    .fmt_add_track = OggMuxerAddTrack,
+    .fmt_start = OggMuxerStart,
+    .fmt_write = OggMuxerWriteFrame,
+    .fmt_stop = OggMuxerStop,
+    .fmt_set_max_size = OggMuxerSetMaxFileSize,
+    .fmt_set_max_duration = OggMuxerSetMaxFileDuration,
+    .fmt_set_next_outputfile = OggMuxerSetNextOutputFile,
+    .fmt_invoke = OggMuxerInvoke,
+    .fmt_close = OggMuxerDestroy,
+};
+
+#ifdef ENABLE_DL_DEMUXER_PLUGIN
+const MuxerPluginEntry *GetMuxer(void)
+{
+    return &g_oggMuxerEntry;
+}
+#endif
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/ogg_muxer/ogg_muxer.h b/code/sdk/middleware/services/media/hal/format/plugins/ogg_muxer/ogg_muxer.h
new file mode 100644 (file)
index 0000000..9ca3fe8
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: raw_muxer define
+* Author: Media Software Group
+* Create: 2025-09-23
+*/
+
+#ifndef OGG_MUXER_H
+#define OGG_MUXER_H
+
+#include "muxer_interface.h"
+
+#ifdef ENABLE_DL_DEMUXER_PLUGIN
+const MuxerPluginEntry *GetMuxer(void);
+#else
+extern MuxerPluginEntry g_oggMuxerEntry;
+#endif
+
+#endif
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/raw_muxer/CMakeLists.txt b/code/sdk/middleware/services/media/hal/format/plugins/raw_muxer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b236a1f
--- /dev/null
@@ -0,0 +1,51 @@
+#===============================================================================
+# @brief    cmake file
+# Copyright (c) CompanyNameMagicTag 2022-2022. All rights reserved.
+#===============================================================================
+set(COMPONENT_NAME "plugin_muxer_raw")
+
+# use build env and option camke
+include(../../../../build/build_env.cmake)
+include(../../../../build/build_option.cmake)
+
+set(SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/raw_muxer.c
+)
+
+set(PUBLIC_HEADER
+)
+
+set(PRIVATE_HEADER
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../include
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../common/include
+    ${CMAKE_CURRENT_SOURCE_DIR}/../common/dtcf/include
+    ${CMAKE_CURRENT_SOURCE_DIR}/../common/dtcf_manager/include
+)
+
+set(PRIVATE_DEFINES
+)
+
+set(CDEFINES ${CDEFINES} "CMSIS_SUPPORT" "ENABLE_PLUGIN_MUXER_RAW")
+set(PUBLIC_DEFINES
+    ${CDEFINES}
+)
+
+# use this when you want to add ccflags like -include xxx
+set(COMPONENT_PUBLIC_CCFLAGS
+)
+
+set(COMPONENT_CCFLAGS
+)
+
+set(WHOLE_LINK
+    true
+)
+
+set(MAIN_COMPONENT
+    false
+)
+
+set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib/media/${BOARD}_${APPLICATION}/${OS}/${COMPONENT_NAME})
+
+build_component()
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/raw_muxer/raw_muxer.c b/code/sdk/middleware/services/media/hal/format/plugins/raw_muxer/raw_muxer.c
new file mode 100644 (file)
index 0000000..6be1cb9
--- /dev/null
@@ -0,0 +1,625 @@
+/*
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: wav_muxer.c
+* Author: Media Software Group
+* Create: 2025-03-10
+*/
+
+#include "raw_muxer.h"
+#include <malloc.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+#include <limits.h>
+#include <fcntl.h>
+#include "muxer_interface.h"
+#include "dtcf_manager.h"
+#include "media_hal_common.h"
+#include "securec.h"
+
+#define MODULE_NAME "RawMuxer"
+
+#define BYTE_UNIT 1024
+#define RAW_MUXER_PRIORITY 100\r
+#ifdef SUPPORT_FEATURE_CONFIG\r
+#define INTERVAL_RECORD_FRAME (1000 / CONFIG_AUDIO_AI_FRAME_PER_SEC)\r
+#else\r
+#define INTERVAL_RECORD_FRAME 10\r
+#endif
+#define MSEC_PER_SEC (1000)
+#define REC_SPLIT_TIME_THRESHOLD (0.9)
+#define REC_SPLIT_SIZE_THRESHOLD (0.9)
+#define REC_US_TO_S (1000000.0)
+
+#define SIZE_PER_SAMPLE 2
+#define FILE_MODEL 0644
+
+/* <max file size, determined by the file system */
+#ifndef ONLY_UT_TEST
+/* (4*1024*1024*1024-1*1024*1024*1024) */
+#define REC_MAX_FILE_SIZE (3221225472LL)
+#else
+/* 20*1024*1024 */
+#define REC_MAX_FILE_SIZE (20971520LL)
+#endif
+#define FILE_INFO_BUFFER_SIZE 350
+
+
+typedef struct {
+    MuxerOutput muxerOutput;
+    MuxerTrackSource trackSource;
+    char fileName[REC_FILE_NAME_LEN];
+    int32_t fp;
+    bool muxerStarted;
+    int64_t maxFileSize;
+    int64_t maxDuration;
+    PluginCallback callBack;
+    DtcfCallBack dtcfCallBack;
+    uint64_t streamSize;
+    bool splitSizeBegin;
+    bool splitTimeBegin;
+    uint32_t realRecTimeLenMs;
+    uint64_t baseFramePts;
+    MediaHalMutexHandle mutex;
+    uint64_t maxMemorySize;
+    bool isSupportSplit;
+} RawMuxerContext;
+
+typedef struct {
+    int32_t dataLength;
+    int64_t frameTimeStamp;
+} RawFrameData;
+
+static DTCF_FILE_TYPE_E g_fileType = DTCF_FILE_TYPE_BUTT;
+static DTCF_DIR_E g_dirType = DTCF_DIR_BUTT;
+
+static void ReportInfo(PluginCallback callBack, PluginInfoType infoType, int32_t extra)
+{
+    CHK_NULL_RETURN_NONE(callBack.OnInfo, "OnInfo invalid pointer");
+    callBack.OnInfo(callBack.handle, infoType, extra);
+}
+
+static void ReportError(PluginCallback callBack, int32_t errorType, int32_t errorCode)
+{
+    CHK_NULL_RETURN_NONE(callBack.OnError, "OnError invalid pointer");
+    callBack.OnError(callBack.handle, errorType, errorCode);
+}
+
+static int32_t DtcfEventCallBack(void *callBack, DtcfCallBackType errorType, int32_t errorCode)
+{
+    CHK_NULL_RETURN(callBack, MEDIA_HAL_INVALID_PARAM, "callBack invalid pointer");
+    RawMuxerContext *context = (RawMuxerContext *)callBack;
+    CHK_NULL_RETURN(context->callBack.OnError, MEDIA_HAL_INVALID_PARAM, "OnError invalid pointer");
+    PluginErrorType pluginErrorType;
+    switch (errorType) {
+        case DELETE_THE_OLDEST_FAILED:
+            context->callBack.OnError(context->callBack.handle, ERROR_TYPE_INTERNAL_OPERATION_FAIL, errorCode);
+            break;
+        case MEMORY_REACH_THE_MAXIMUM_VALUE:
+            context->callBack.OnInfo(context->callBack.handle, MAX_MEMORYSIZE_REACHED, errorCode);
+            break;
+        default:
+            MEDIA_HAL_LOGE(MODULE_NAME, "not support type = %d", errorType);
+            break;
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t RawMuxerFind(const MuxerOutput *output, const ProtocolFun *protocol)
+{
+    CHK_NULL_RETURN(output, MEDIA_HAL_INVALID_PARAM, "output is NULL");
+    if (output->type == OUT_TYPE_INVALID) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "out type invlid");
+        return MEDIA_HAL_INVALID_PARAM;
+    }
+    if (protocol != NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "not support extra protocol");
+        return MEDIA_HAL_INVALID_PARAM;
+    }
+    if (output->format == FORMAT_TYPE_MP3) {\r
+        g_fileType = DTCF_FILE_TYPE_MP3;\r
+        g_dirType = DTCF_DIR_RECORD_MP3_FILE;\r
+    } else if (output->format == FORMAT_TYPE_SILK) {\r
+        g_fileType = DTCF_FILE_TYPE_SILK;\r
+        g_dirType = DTCF_DIR_RECORD_SILK_FILE;\r
+    } else {\r
+        MEDIA_HAL_LOGI(MODULE_NAME, "rawMuxer not Found format = %d", output->format);
+        return MEDIA_HAL_ERR;\r
+    }
+    MEDIA_HAL_LOGI(MODULE_NAME, "rawMuxer Found");
+    return MEDIA_HAL_OK;
+}
+
+static int32_t OpenOutTypeUriProcess(const MuxerOutput *output, DtcfCallBack callBack)
+{
+    int32_t optInit = DtcfMgrFileOptInit(output->url, strlen(output->url) + 1, callBack);
+    if (optInit != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "DtcfMgrFileOptInit fail 0x%x", optInit);
+        (void)DtcfMgrFileOptDeInit();
+        return MEDIA_HAL_ERR;
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t InitRawMuxer(RawMuxerContext *ctx)
+{
+    if (ctx->muxerOutput.type == OUT_TYPE_URI) {
+        if (DtcfMgrIsFile(ctx->muxerOutput.url, REC_FILE_NAME_LEN)) {\r
+            ctx->isSupportSplit = false;\r
+            MEDIA_HAL_LOGI(MODULE_NAME, "DtcfMgrIsFile is enter, ctx->muxerOutput.url = %s", ctx->muxerOutput.url);\r
+            int32_t ret = DtcfMgrMakeDir(ctx->muxerOutput.url, REC_FILE_NAME_LEN);
+            if (ret != MEDIA_HAL_OK) {
+                MEDIA_HAL_LOGE(MODULE_NAME, "DtcfMgrMakeDir error");
+                return MEDIA_HAL_ERR;
+            }\r
+            ctx->fp = open(ctx->muxerOutput.url, O_RDWR | O_CREAT | O_TRUNC, FILE_MODEL);\r
+            if (ctx->fp < 0) {
+                MEDIA_HAL_LOGE(MODULE_NAME, "open file error, errno = %d", errno);
+                return MEDIA_HAL_ERR;
+            }\r
+            if (memcpy_s(ctx->fileName, REC_FILE_NAME_LEN, ctx->muxerOutput.url, REC_FILE_NAME_LEN) != EOK) {
+                MEDIA_HAL_LOGE(MODULE_NAME, "memcpy_s failed");
+                close(ctx->fp);
+                ctx->fp = -1;
+                return MEDIA_HAL_ERR;
+            }\r
+            return MEDIA_HAL_OK;\r
+        }\r
+        ctx->isSupportSplit = true;\r
+        int32_t ret = OpenOutTypeUriProcess(&ctx->muxerOutput, ctx->dtcfCallBack);
+        if (ret != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "OpenOutTypeUriProcess error, ret = %d", ret);
+            return MEDIA_HAL_ERR;
+        }\r
+        char fileNames[0x2][REC_FILE_NAME_LEN];
+        ret = DtcfMgrRequestFileNames(g_fileType, g_dirType, fileNames);
+        if (ret != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "DtcfMgrRequestFileNames error");
+            return MEDIA_HAL_ERR;
+        }
+        ctx->fp = open(fileNames[0], O_RDWR | O_CREAT | O_TRUNC, 0);
+        if (ctx->fp < 0) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "open file error, errno = %d", errno);
+            return MEDIA_HAL_ERR;
+        }
+        if (memcpy_s(ctx->fileName, REC_FILE_NAME_LEN, fileNames[0], REC_FILE_NAME_LEN) != EOK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "memcpy_s failed");
+            return MEDIA_HAL_ERR;
+        }
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t RawMuxerOpen(const MuxerOutput *output, const ProtocolFun *protocol, RecMuxerHandle *handle)
+{
+    MEDIA_HAL_UNUSED(protocol);
+    CHK_NULL_RETURN(output, MEDIA_HAL_INVALID_PARAM, "output is null");
+    CHK_NULL_RETURN(handle, MEDIA_HAL_INVALID_PARAM, "handle is null");
+    
+    RawMuxerContext *ctx = (RawMuxerContext*)malloc(sizeof(RawMuxerContext));
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_NO_MEM, "RawMuxerContext is null");
+    int32_t ret = MEDIA_HAL_OK;
+    if (memset_s(ctx, sizeof(RawMuxerContext), 0x0, sizeof(RawMuxerContext)) != EOK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "memset_s RawMuxerContext error");
+        goto CREATE_FAILED;
+    }
+    ctx->mutex = MediaHalMutexCreate(NULL);
+    if (ctx->mutex == NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "MediaHalMutexCreate failed!");
+        goto CREATE_FAILED;
+    }
+    ctx->muxerOutput = *output;
+    ctx->dtcfCallBack.handle = ctx;
+    ctx->dtcfCallBack.CallBack = DtcfEventCallBack;
+    ret = InitRawMuxer(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "CreateRawMuxer failed:0x%x", ret);
+        goto MUXER_DESTORY;
+    }
+    *handle = ctx;
+    if (ctx->isSupportSplit) {\r
+        ret = DtcfMgrGetStorageMaxSize(&ctx->maxMemorySize);
+        if (ret != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "DtcfGetStorageMaxSize failed!");
+        }\r
+    }
+    MEDIA_HAL_LOGI(MODULE_NAME, "RawMuxerOpen :%d", ret);
+    return MEDIA_HAL_OK;
+MUXER_DESTORY:
+    MediaHalMutexDestroy(&ctx->mutex);
+CREATE_FAILED:
+    free(ctx);
+    return MEDIA_HAL_ERR;
+}
+
+static int32_t DeinitRawMuxer(RawMuxerContext *ctx)
+{
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "handle");
+    close(ctx->fp);
+    ctx->fp = -1;
+    ctx->muxerStarted = false;
+    ctx->isSupportSplit = false;
+    MEDIA_HAL_LOGI(MODULE_NAME, "DeinitRawMuxer success");
+    return MEDIA_HAL_OK;
+}
+
+static int32_t RawMuxerDestroy(RecMuxerHandle handle)
+{
+    RawMuxerContext *ctx = (RawMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "handle");
+    int32_t ret = DeinitRawMuxer(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "call DeinitRawMuxer fail:0x%x", ret);
+    }
+    if (ctx->isSupportSplit) {
+        (void)DtcfMgrFileOptDeInit();
+    }
+    MediaHalMutexDestroy(&ctx->mutex);
+    free(ctx);
+    MEDIA_HAL_LOGI(MODULE_NAME, "RawMuxerDestroy success");
+    return MEDIA_HAL_OK;
+}
+
+static int32_t RawMuxerAddTrack(RecMuxerHandle handle, const MuxerTrackSource *trackSource)
+{
+    CHK_NULL_RETURN(trackSource, MEDIA_HAL_INVALID_PARAM, "trackSource is null");
+    RawMuxerContext *ctx = (RawMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "RawMuxerContext is null");
+    if (trackSource->type != STREAM_TYPE_AUDIO) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "only support STREAM_TYPE_AUDIO!");
+        return MEDIA_HAL_ERR;
+    }
+    ctx->trackSource = *trackSource;
+    return MEDIA_HAL_OK;
+}
+
+static int32_t RawMuxerStart(RecMuxerHandle handle)
+{
+    RawMuxerContext *ctx = (RawMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "ctx is null");
+    CHK_COND_RETURN(ctx->muxerStarted, MEDIA_HAL_OK, "ctx is Started");
+    ctx->muxerStarted = true;
+    ctx->splitSizeBegin = !ctx->isSupportSplit;
+    ctx->splitTimeBegin = !ctx->isSupportSplit;
+    MEDIA_HAL_LOGI(MODULE_NAME, "RawMuxerStart success ");
+    return MEDIA_HAL_OK;
+}
+
+static bool SplitIsAchiveSize(RawMuxerContext *ctx)
+{
+    bool result = false;
+    if (ctx->splitSizeBegin) {
+        if (ctx->maxFileSize > 0 && ctx->streamSize >= ctx->maxFileSize * REC_SPLIT_SIZE_THRESHOLD) {
+            ReportInfo(ctx->callBack, MAX_FILESIZE_APPROACHING,
+                ctx->muxerOutput.type == OUT_TYPE_FD ? ctx->muxerOutput.fd : -1);
+            MEDIA_HAL_LOGI(MODULE_NAME, "size %lld Approaching maxFileSize %lld", ctx->streamSize, ctx->maxFileSize);
+            ctx->splitSizeBegin = false;
+        }
+    }
+
+    if ((ctx->maxFileSize > 0 && ctx->streamSize >= (uint64_t)ctx->maxFileSize) ||
+        ctx->streamSize >= REC_MAX_FILE_SIZE) {
+        ReportInfo(ctx->callBack, MAX_FILESIZE_REACHED,
+            ctx->muxerOutput.type == OUT_TYPE_FD ? ctx->muxerOutput.fd : -1);
+        result = true;
+        MEDIA_HAL_LOGI(MODULE_NAME, "size %lld has Approached maxFileSize %lld", ctx->streamSize, ctx->maxFileSize);
+        ctx->streamSize = 0;
+        ctx->splitSizeBegin = true;
+        ctx->baseFramePts = 0;
+    }
+    return result;
+}
+
+static bool SplitIsAchiveTime(RawMuxerContext *ctx)
+{
+    bool result = false;
+    uint32_t realRecTimeLen = ctx->realRecTimeLenMs / MSEC_PER_SEC;
+    if (ctx->splitTimeBegin) {
+        if (ctx->maxDuration > 0 && realRecTimeLen >= ctx->maxDuration * REC_SPLIT_TIME_THRESHOLD) {
+            ReportInfo(ctx->callBack, MAX_DURATION_APPROACHING,
+                ctx->muxerOutput.type == OUT_TYPE_FD ? ctx->muxerOutput.fd : -1);
+            MEDIA_HAL_LOGI(MODULE_NAME, "realRecTimeLen %u Approaching maxDuration %lld",
+                realRecTimeLen, ctx->maxDuration);
+            ctx->splitTimeBegin = false;
+        }
+    }
+    if (ctx->maxDuration > 0 && realRecTimeLen >= ctx->maxDuration) {
+        // split and reset manual split info
+        ReportInfo(ctx->callBack, MAX_DURATION_REACHED,
+            ctx->muxerOutput.type == OUT_TYPE_FD ? ctx->muxerOutput.fd : -1);
+        result = true;
+        MEDIA_HAL_LOGI(MODULE_NAME, "time %u has Approached maxDuration %lld", ctx->realRecTimeLenMs, ctx->maxDuration);
+        ctx->splitTimeBegin = true;
+        ctx->baseFramePts = 0;
+        ctx->streamSize = 0;
+    }
+    return result;
+}
+
+static int32_t ReConfigMuxer(RawMuxerContext *ctx)
+{
+    int32_t ret = DeinitRawMuxer(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "call DeinitRawMuxer fail:0x%x", ret);
+        return MEDIA_HAL_ERR;
+    }
+    ret = InitRawMuxer(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "InitRawMuxer failed:0x%x", ret);
+        return MEDIA_HAL_ERR;
+    }
+    ctx->muxerStarted = true;
+    MEDIA_HAL_LOGE(MODULE_NAME, "ReConfigMuxer success");
+    return MEDIA_HAL_OK;
+}
+
+static int32_t RawMuxerWriteFrameInner(RawMuxerContext *ctx, const FormatPacket *frameData,
+    const RawFrameData *wavFrameData)
+{
+    if (write(ctx->fp, frameData->data, frameData->len) != frameData->len) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "fwrite failed errno:%d", errno);
+        return MEDIA_HAL_ERR_AGAIN;
+    }
+    if (ctx->isSupportSplit) {
+        if (ctx->streamSize == 0) {
+            ctx->streamSize += wavFrameData->dataLength;
+        }
+        if (ctx->baseFramePts == 0) {
+            ctx->baseFramePts = wavFrameData->frameTimeStamp;
+        }
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t HandleRawFrame(RawMuxerContext *ctx, RawFrameData *wavFrameData, const FormatPacket *frameData)
+{
+    CHK_NULL_RETURN(frameData, MEDIA_HAL_INVALID_PARAM, "wavFrameData is NULL!");
+    wavFrameData->dataLength = frameData->len;
+    if (ctx->isSupportSplit) {
+        wavFrameData->frameTimeStamp = frameData->timestampUs;
+        uint32_t frameNum = frameData->timestampUs / (MSEC_PER_SEC* INTERVAL_RECORD_FRAME);
+        uint32_t frameSize = frameData->len;
+        if (frameNum != 0) {
+            frameSize = frameData->len / frameNum;
+        }
+        if (ctx->maxDuration < 1 || ctx->maxFileSize < frameSize) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "file duration or size is not right, write file failed!");
+            return MEDIA_HAL_ERR;
+        }
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t RawMuxerWriteFrame(RecMuxerHandle handle, const FormatPacket *frameData)
+{
+    CHK_NULL_RETURN(frameData, MEDIA_HAL_INVALID_PARAM, "frameData is NULL!");
+    RawMuxerContext *ctx = (RawMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "RawMuxerContext is null");
+    CHK_COND_RETURN(!ctx->muxerStarted, MEDIA_HAL_ERR, "RawMuxerContext is not Started");
+    if (ctx->isSupportSplit) {
+        if (DtcfMgrHandleRecordMaxSize(frameData->len, ctx->maxMemorySize) != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "handle reac max size failed!");
+            return MEDIA_HAL_ERR;
+        }
+    }
+    RawFrameData wavFrameData = {};
+    if (HandleRawFrame(ctx, &wavFrameData, frameData) != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "handle wav frame failed!");
+        return MEDIA_HAL_ERR;
+    }
+    MediaHalMutexLock(ctx->mutex);
+    if (ctx->isSupportSplit) {\r
+        ctx->streamSize += wavFrameData.dataLength;
+        ctx->realRecTimeLenMs = (uint32_t)((wavFrameData.frameTimeStamp - ctx->baseFramePts) / MSEC_PER_SEC);
+        if (SplitIsAchiveSize(ctx) || SplitIsAchiveTime(ctx)) {
+            int32_t ret = ReConfigMuxer(ctx);
+            if (ret != MEDIA_HAL_OK) {
+                ReportError(ctx->callBack, ERROR_TYPE_INTERNAL_OPERATION_FAIL, ERROR_TYPE_INTERNAL_OPERATION_FAIL);
+                MediaHalMutexUnLock(ctx->mutex);
+                return MEDIA_HAL_ERR;
+            }
+        }\r
+    }
+    int32_t ret = RawMuxerWriteFrameInner(ctx, frameData, &wavFrameData);
+    if (ret != MEDIA_HAL_OK) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "RawMuxerWriteFrameInner failed!");
+        MediaHalMutexUnLock(ctx->mutex);
+        return ret;\r
+    }
+    MediaHalMutexUnLock(ctx->mutex);
+    return MEDIA_HAL_OK;
+}
+
+static int32_t RawMuxerStop(RecMuxerHandle handle, bool block)
+{
+    CHK_NULL_RETURN(handle, MEDIA_HAL_INVALID_PARAM, "handle");
+    RawMuxerContext *ctx = (RawMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "RawMuxerContext");
+    CHK_COND_RETURN(!ctx->muxerStarted, MEDIA_HAL_ERR, "RawMuxerContext is not Started");
+    MEDIA_HAL_LOGI(MODULE_NAME, " block %d", block);
+    ctx->muxerStarted = false;
+    return MEDIA_HAL_OK;
+}
+
+static int32_t RawMuxerSetMaxFileSize(RecMuxerHandle handle, int64_t bytes)
+{
+    CHK_NULL_RETURN(handle, MEDIA_HAL_INVALID_PARAM, "handle");
+    RawMuxerContext *ctx = (RawMuxerContext *)handle;
+    MEDIA_HAL_LOGI(MODULE_NAME, "bytes:%lld ", bytes);
+    ctx->maxFileSize = bytes;
+    return MEDIA_HAL_OK;
+}
+
+static int32_t RawMuxerSetMaxFileDuration(RecMuxerHandle handle, int64_t durationUs)
+{
+    CHK_NULL_RETURN(handle, MEDIA_HAL_INVALID_PARAM, "handle");
+    RawMuxerContext *ctx = (RawMuxerContext *)handle;
+    MEDIA_HAL_LOGI(MODULE_NAME, "durationUs:%lld ", durationUs);
+    ctx->maxDuration = durationUs;
+    return MEDIA_HAL_OK;
+}
+
+static int32_t RawMuxerSetNextOutputFile(RecMuxerHandle handle, int32_t fd)
+{
+    RawMuxerContext *ctx = (RawMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "handle is null");
+    if (ctx->muxerOutput.type == OUT_TYPE_URI) {
+        return MEDIA_HAL_ERR;
+    }
+    ctx->muxerOutput.fd = fd;
+    return MEDIA_HAL_OK;
+}
+
+static int32_t MuxerSetCallBack(RawMuxerContext *ctx, const PluginCallback *callBack)
+{
+    CHK_NULL_RETURN(callBack, MEDIA_HAL_INVALID_PARAM, "callBack");
+    ctx->callBack = *callBack;
+    return MEDIA_HAL_OK;
+}
+
+static void GetCurrentStorageTimeRemaindTime(RawMuxerContext *ctx, uint32_t packetLen, uint32_t *time)
+{
+    if (!ctx->isSupportSplit) {
+        MEDIA_HAL_LOGI(MODULE_NAME, "not support get recorder time!");
+        return;
+    }
+    MediaHalMutexLock(ctx->mutex);
+    *time = ((DtcfMgrGetCurrentMemorySize(ctx->maxMemorySize) - DtcfMgrGetCurrentRecordedSize()) / packetLen) *
+        INTERVAL_RECORD_FRAME;
+    MEDIA_HAL_LOGI(MODULE_NAME, "remaind storage packetLen = %u, time:%u\n", packetLen, *time);
+    MediaHalMutexUnLock(ctx->mutex);
+}
+
+static void GetCurrentFileRemaindTime(RawMuxerContext *ctx, uint32_t packetLen, uint32_t *time)
+{
+    if (!ctx->isSupportSplit) {
+        MEDIA_HAL_LOGI(MODULE_NAME, "not support get file time!");
+        return;
+    }
+    MediaHalMutexLock(ctx->mutex);
+    uint32_t currentSec = ((ctx->maxFileSize / packetLen) * INTERVAL_RECORD_FRAME) / MSEC_PER_SEC;
+    if (currentSec >= ctx->maxDuration) {
+        *time = (ctx->maxDuration * MSEC_PER_SEC) - ctx->realRecTimeLenMs;
+    } else {
+        *time = ((ctx->maxFileSize - ctx->streamSize) / packetLen) * INTERVAL_RECORD_FRAME;
+    }
+    MEDIA_HAL_LOGI(MODULE_NAME, "remaind file packetLen = %u, time:%u", packetLen, *time);
+    MediaHalMutexUnLock(ctx->mutex);
+}
+
+static int32_t GetCurrentRawFileInfo(RawMuxerContext *ctx, char **value)
+{
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "handle is null");
+    CHK_NULL_RETURN(value, MEDIA_HAL_INVALID_PARAM, "value is null");
+    CHK_NULL_RETURN(*value, MEDIA_HAL_INVALID_PARAM, "real value is null");
+    if (!ctx->isSupportSplit) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "not support get file info!");
+        return MEDIA_HAL_ERR;
+    }
+    MediaHalMutexLock(ctx->mutex);
+    FileDate fileDate = {};
+    int32_t ret = DtcfMgrGetCurrentFileDate(&fileDate);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "Get Current File Date failed:%d", ret);
+        MediaHalMutexUnLock(ctx->mutex);
+        return ret;
+    }
+    char *lastSlash = strrchr(ctx->fileName, '/');
+    if (lastSlash == NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "Get Current File name failed!");
+        MediaHalMutexUnLock(ctx->mutex);
+        return MEDIA_HAL_ERR;
+    }
+    ret = sprintf_s(*value, FILE_INFO_BUFFER_SIZE, "%llu,%u,%u,%u,%u,%u,%u,%u=%s", ctx->streamSize,
+        fileDate.fileDateYear, fileDate.fileDateMonth, fileDate.fileDateDay, fileDate.fileDateHour,
+        fileDate.fileDateMin, fileDate.fileDateSec, ctx->realRecTimeLenMs, lastSlash + 1);
+    if (ret == -1 || ret >= FILE_INFO_BUFFER_SIZE) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "sprintf_s failed!");
+        MediaHalMutexUnLock(ctx->mutex);
+        return MEDIA_HAL_ERR;
+    }
+    MediaHalMutexUnLock(ctx->mutex);
+    return MEDIA_HAL_OK;
+}
+
+static int32_t RawMuxerInvoke(RecMuxerHandle handle, uint32_t invokeId, void *arg)
+{
+    int32_t ret = MEDIA_HAL_OK;
+    RawMuxerContext *ctx = (RawMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "muxerContext is NULL!");
+    CHK_NULL_RETURN(arg, MEDIA_HAL_INVALID_PARAM, "arg is NULL!");
+    MEDIA_HAL_LOGI(MODULE_NAME, "invokeId:%d ", invokeId);
+    switch (invokeId) {
+        case INVOKE_SET_CALLBACK:
+            ret = MuxerSetCallBack(ctx, (const PluginCallback *)arg);
+            break;
+        case INVOKE_SET_DELETE_OLD_FILES_ENABLE: {
+            uint32_t value = *((uint32_t *)arg);
+            bool enable = false;
+            if (value != 0) {
+                enable = true;
+            }
+            if (!ctx->isSupportSplit) {
+                enable = false;
+            }
+            DtcfMgrSetDeleteFileEnable(enable);
+            break;
+        }
+        case INVOKE_SET_MAX_STORAGE_THRESHOLD: {
+            uint32_t value = *((uint32_t *)arg);
+            DtcfMgrSetMaxStorageThreshold(value);
+            break;
+        }
+        case INVOKE_CURRENT_STORAGE_REMAIND_TIME: {
+            uint32_t packetLen = *((uint32_t *)arg);
+            GetCurrentStorageTimeRemaindTime(ctx, packetLen, (uint32_t *)arg);
+            break;
+        }
+        case INVOKE_CURRENT_FILE_REMAIND_TIME: {
+            uint32_t packetLen = *((uint32_t *)arg);
+            GetCurrentFileRemaindTime(ctx, packetLen, (uint32_t *)arg);
+            break;
+        }
+        case INVOKE_CURRENT_FILE_INFO: {
+            ret = GetCurrentRawFileInfo(ctx, (char **)arg);
+            break;
+        }
+        default:
+            MEDIA_HAL_LOGI(MODULE_NAME, "not support invokeId:%d ", invokeId);
+            break;
+    }
+    return ret;
+}
+
+MuxerPluginEntry g_rawMuxerEntry = {
+    .desc = {
+        .libName = "libplugin_muxer_raw.so",
+        .name = "raw_muxer",
+        .version = "version 1.0.0",
+        .description = "raw_muxer",
+        .supportCapability = "raw",
+        .priority = RAW_MUXER_PRIORITY,
+    },
+    .fmt_find = RawMuxerFind,
+    .fmt_open = RawMuxerOpen,
+    .fmt_add_track = RawMuxerAddTrack,
+    .fmt_start = RawMuxerStart,
+    .fmt_write = RawMuxerWriteFrame,
+    .fmt_stop = RawMuxerStop,
+    .fmt_set_max_size = RawMuxerSetMaxFileSize,
+    .fmt_set_max_duration = RawMuxerSetMaxFileDuration,
+    .fmt_set_next_outputfile = RawMuxerSetNextOutputFile,
+    .fmt_invoke = RawMuxerInvoke,
+    .fmt_close = RawMuxerDestroy,
+};
+
+#ifdef ENABLE_DL_DEMUXER_PLUGIN
+const MuxerPluginEntry *GetMuxer(void)
+{
+    return &g_rawMuxerEntry;
+}
+#endif
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/raw_muxer/raw_muxer.h b/code/sdk/middleware/services/media/hal/format/plugins/raw_muxer/raw_muxer.h
new file mode 100644 (file)
index 0000000..825a08f
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: raw_muxer define
+* Author: Media Software Group
+* Create: 2025-09-23
+*/
+
+#ifndef RAW_MUXER_H
+#define RAW_MUXER_H
+
+#include "muxer_interface.h"
+
+#ifdef ENABLE_DL_DEMUXER_PLUGIN
+const MuxerPluginEntry *GetMuxer(void);
+#else
+extern MuxerPluginEntry g_rawMuxerEntry;
+#endif
+
+#endif
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/wav_muxer/CMakeLists.txt b/code/sdk/middleware/services/media/hal/format/plugins/wav_muxer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8edae31
--- /dev/null
@@ -0,0 +1,55 @@
+#===============================================================================
+# @brief    cmake file
+# Copyright (c) CompanyNameMagicTag 2022-2022. All rights reserved.
+#===============================================================================
+set(COMPONENT_NAME "plugin_muxer_wav")
+
+# use build env and option camke
+include(../../../../build/build_env.cmake)
+include(../../../../build/build_option.cmake)
+
+set(SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/wav_muxer.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/wav.c
+)
+
+set(PUBLIC_HEADER
+)
+
+set(PRIVATE_HEADER
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../include
+    ${CMAKE_CURRENT_SOURCE_DIR}/../../../common/include
+    ${CMAKE_CURRENT_SOURCE_DIR}/../common/dtcf/include
+    ${CMAKE_CURRENT_SOURCE_DIR}/../common/dtcf_manager/include
+)
+
+if ("${CHIP}" STREQUAL "brandy")
+    set(CDEFINES ${CDEFINES} "MINI_MEMORY_SUPPORT")
+endif()
+set(PRIVATE_DEFINES
+)
+
+set(CDEFINES ${CDEFINES} "CMSIS_SUPPORT" "ENABLE_PLUGIN_MUXER_WAV")
+set(PUBLIC_DEFINES
+    ${CDEFINES}
+)
+
+# use this when you want to add ccflags like -include xxx
+set(COMPONENT_PUBLIC_CCFLAGS
+)
+
+set(COMPONENT_CCFLAGS
+)
+
+set(WHOLE_LINK
+    true
+)
+
+set(MAIN_COMPONENT
+    false
+)
+
+set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib/media/${BOARD}_${APPLICATION}/${OS}/${COMPONENT_NAME})
+
+build_component()
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/wav_muxer/wav.c b/code/sdk/middleware/services/media/hal/format/plugins/wav_muxer/wav.c
new file mode 100644 (file)
index 0000000..9f57582
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+ * Description: wav file
+ * Author: Media Software Group
+ * Create: 2025-03-10
+ */
+#include "wav.h"
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "securec.h"
+#include "media_hal_common.h"
+#include "dfx_os_st.h"
+
+#define WAV_RIFF_CHUNK_ID       (((int32_t)'F' << 24) | ((int32_t)'F' << 16) | ((int32_t)'I' << 8) | 'R')
+#define WAV_FORMAT_CHUNK_ID     (((int32_t)' ' << 24) | ((int32_t)'t' << 16) | ((int32_t)'m' << 8) | 'f')
+#define WAV_FACT_CHUNK_ID       (((int32_t)'t' << 24) | ((int32_t)'c' << 16) | ((int32_t)'a' << 8) | 'f')
+#define WAV_DATA_CHUNK_ID       (((int32_t)'a' << 24) | ((int32_t)'t' << 16) | ((int32_t)'a' << 8) | 'd')
+#define WAV_WAVE_ID             (((int32_t)'E' << 24) | ((int32_t)'V' << 16) | ((int32_t)'A' << 8) | 'W')
+#define MODULE_NAME "WAV"
+#define WAV_SUB_FORMAT_LEN 16
+#define WAV_DEFAULTE_SAMPLERATE 48000
+#define FILE_MODEL 0644
+
+static void* WavDefaultMalloc(void *context, size_t size)
+{
+    (void)context;
+    void *p = malloc(size);
+    return p;
+}
+
+static void WavDefaultFree(void *context, void *p)
+{
+    (void)context;
+    free(p);
+}
+
+static WavAllocFuncs g_defaultAllocFuncs = {
+    &WavDefaultMalloc,
+    &WavDefaultFree
+};
+
+static void *g_allocContext = NULL;
+static const WavAllocFuncs* g_allocFuncs = &g_defaultAllocFuncs;
+
+void WavSetAllocator(void *context, const WavAllocFuncs *funcs)
+{
+    g_allocContext = context;
+    g_allocFuncs = funcs;
+}
+
+void* WavMalloc(size_t size)
+{
+    return g_allocFuncs->malloc(g_allocContext, size);
+}
+
+void WavFree(void *p)
+{
+    if (p != NULL) {
+        g_allocFuncs->free(g_allocContext, p);
+    }
+}
+
+char* WavStrdup(const char *str)
+{
+    size_t len = strlen(str) + 1;
+    void *new = WavMalloc(len);
+    if (new == NULL) {
+        return NULL;
+    }
+    if (memcpy_s(new, len, str, len) != EOK) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "memcpy_s failed");
+        WavFree(new);
+        return NULL;
+    }
+    return new;
+}
+
+#pragma pack(push, 1)
+
+typedef struct {
+    uint32_t id;
+    uint32_t size;
+} WavChunkHeader;
+
+typedef struct {
+    WavChunkHeader header;
+
+    uint64_t offset;
+
+    struct {
+        uint16_t formatTag;
+        uint16_t channelCounts;
+        uint32_t sampleRate;
+        uint32_t avgBytesPerSec;
+        uint16_t blockAlign;
+        uint16_t bitsPerSample;
+
+        uint16_t extSize;
+        uint16_t validBitsPerSample;
+        uint32_t channelMask;
+
+        uint8_t subFormat[WAV_SUB_FORMAT_LEN];
+    } body;
+} WavFormatChunk;
+
+typedef struct {
+    WavChunkHeader header;
+
+    uint64_t offset;
+
+    struct {
+        uint32_t sampleLength;
+    } body;
+} WavFactChunk;
+
+typedef struct {
+    WavChunkHeader header;
+    uint64_t offset;
+} WavDataChunk;
+
+typedef struct {
+    uint32_t id;
+    uint32_t position;
+    uint32_t chunkId;
+    uint32_t chunkStart;
+    uint32_t blockStart;
+    uint32_t sampleOffset;
+} CueMarker;
+
+#define WAV_CUE_SIZE 4
+#define WAV_DATA_HEAD_SIZE 8
+#define WAV_CUE_HEAD_SIZE 12
+
+#define WAV_MARKERS_ALL_SIZE (2 * 1024)
+#define WAV_MARKERS_BUFFER_SIZE ((WAV_MARKERS_ALL_SIZE - WAV_CUE_HEAD_SIZE) / sizeof(CueMarker))
+static char g_buffer[WAV_MARKERS_ALL_SIZE] = { 0 };
+
+typedef struct {
+    char cueFlag[WAV_CUE_SIZE];
+    uint32_t cueSize;
+    uint32_t numMarkers;
+    CueMarker markers[WAV_MARKERS_BUFFER_SIZE];
+} CueMarkList;
+
+typedef struct {
+    uint32_t id;
+    uint32_t size;
+    uint32_t waveId;
+    uint64_t offset;
+} WavMasterChunk;
+
+#pragma pack(pop)
+
+#define WAV_CHUNK_MASTER    ((uint32_t)1)
+#define WAV_CHUNK_FORMAT    ((uint32_t)2)
+#define WAV_CHUNK_FACT      ((uint32_t)4)
+#define WAV_CHUNK_DATA      ((uint32_t)8)
+
+struct WavFileInfo {
+    int32_t             fp;
+    char*               filename;
+    uint32_t            mode;
+    int32_t             isANewFile;
+
+    WavMasterChunk      riffChunk;
+    WavFormatChunk      formatChunk;
+    WavFactChunk        factChunk;
+    CueMarkList         cueChunk;
+    WavDataChunk        dataChunk;
+};
+
+static const uint8_t DEFAULT_SUB_FORMAT[WAV_SUB_FORMAT_LEN] = {
+    0x01, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
+};
+
+void WavMarkAndDataInfo(WavFile *self)
+{
+    uint32_t size = self->dataChunk.offset - sizeof(WavChunkHeader);
+    if (lseek(self->fp, size, SEEK_SET) < 0) {
+        goto EXIT1;
+    }
+    if (self->cueChunk.numMarkers > 0) {\r
+        self->cueChunk.cueSize = self->cueChunk.numMarkers * sizeof(CueMarker) +  WAV_CUE_SIZE;
+        uint32_t markerSize = sizeof(CueMarker) * self->cueChunk.numMarkers + WAV_CUE_HEAD_SIZE;
+        if (write(self->fp, &self->cueChunk, markerSize) <= 0) {
+            goto EXIT2;
+        }\r
+        \r
+        self->dataChunk.header.size += WAV_MARKERS_ALL_SIZE -\r
+            (sizeof(CueMarker) * self->cueChunk.numMarkers)- WAV_CUE_HEAD_SIZE;\r
+        if (self->dataChunk.header.id == WAV_DATA_CHUNK_ID) {
+            if (write(self->fp, &self->dataChunk.header, sizeof(WavChunkHeader)) <= 0) {
+                goto EXIT2;
+            }
+        }\r
+    } else {\r
+        memset_s(g_buffer, WAV_MARKERS_ALL_SIZE, 0xFF, WAV_MARKERS_ALL_SIZE);\r
+        if (write(self->fp, g_buffer, WAV_MARKERS_ALL_SIZE) <= 0) {
+            goto EXIT2;
+        }\r
+        if (self->dataChunk.header.size < WAV_MARKERS_ALL_SIZE) {\r
+            self->dataChunk.header.size += WAV_MARKERS_ALL_SIZE - WAV_DATA_HEAD_SIZE;\r
+        }\r
+        if (self->dataChunk.header.id == WAV_DATA_CHUNK_ID) {
+            if (lseek(self->fp, size, SEEK_SET) < 0) {
+                goto EXIT1;
+            }
+            if (write(self->fp, &self->dataChunk.header, sizeof(WavChunkHeader)) <= 0) {
+                goto EXIT2;
+            }
+        }\r
+        if (lseek(self->fp, size + WAV_MARKERS_ALL_SIZE, SEEK_SET) < 0) {
+            goto EXIT1;
+        }
+    }
+    return;
+EXIT1:
+    MEDIA_HAL_LOGE(MODULE_NAME, "lseek() failed [errno %d: %s]", errno, strerror(errno));
+    return;
+EXIT2:
+    MEDIA_HAL_LOGE(MODULE_NAME, "Error while writing to %s [errno %d: %s]",
+        self->filename, errno, strerror(errno));
+    return;
+}
+
+void WavWriteHeader(WavFile* self)
+{
+    self->riffChunk.size =
+        (uint32_t)sizeof(self->riffChunk.waveId) +
+        (self->formatChunk.header.id == WAV_FORMAT_CHUNK_ID ?
+            (sizeof(WavChunkHeader) + self->formatChunk.header.size) : 0) +
+        (self->factChunk.header.id == WAV_FACT_CHUNK_ID ? (sizeof(WavChunkHeader) + self->factChunk.header.size) : 0) +
+        (self->dataChunk.header.id == WAV_DATA_CHUNK_ID ? (sizeof(WavChunkHeader) + self->dataChunk.header.size) : 0);
+    self->riffChunk.size += sizeof(CueMarker) * WAV_MARKERS_BUFFER_SIZE + 0xC;
+    if (lseek(self->fp, 0, SEEK_SET) < 0) {
+        goto EXIT1;
+    }
+    if ((write(self->fp, &self->riffChunk, sizeof(WavChunkHeader) + 0x4)) <= 0) {
+        goto EXIT2;
+    }
+    if (self->formatChunk.header.id == WAV_FORMAT_CHUNK_ID) {
+        if (lseek(self->fp, (long)(self->formatChunk.offset - sizeof(WavChunkHeader)), SEEK_SET) < 0) {
+            goto EXIT1;
+        }
+        if (write(self->fp, &self->formatChunk.header, sizeof(WavChunkHeader)) <= 0) {
+            goto EXIT2;
+        }
+        if (write(self->fp, &self->formatChunk.body, self->formatChunk.header.size) <= 0) {
+            goto EXIT2;
+        }
+    }
+    if (self->factChunk.header.id == WAV_FACT_CHUNK_ID) {
+        if (lseek(self->fp, (long)(self->factChunk.offset - sizeof(WavChunkHeader)), SEEK_SET) < 0) {
+            goto EXIT1;
+        }
+        if (write(self->fp, &self->factChunk.header, sizeof(WavChunkHeader)) <= 0) {
+            goto EXIT2;
+        }
+        if (write(self->fp, &self->factChunk.body, self->factChunk.header.size) <= 0) {
+            goto EXIT2;
+        }
+    }
+    WavMarkAndDataInfo(self);
+    return;
+EXIT1:
+    MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "lseek() failed [errno %d: %s]", errno, strerror(errno));
+    return;
+EXIT2:
+    MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "Error while writing to %s [errno %d: %s]",
+        self->filename, errno, strerror(errno));
+    return;
+}
+
+void WavInitCueChunk(WavFile *self)
+{
+    self->cueChunk.cueFlag[0] = 'c';
+    self->cueChunk.cueFlag[0x1] = 'u';
+    self->cueChunk.cueFlag[0x2] = 'e';
+    self->cueChunk.cueFlag[0x3] = ' ';
+    self->cueChunk.cueSize = 0;
+    self->cueChunk.numMarkers = 0;
+}
+
+uint32_t GetFileOpenMode(uint32_t mode)
+{
+    uint32_t openMode = O_RDWR | O_CREAT | O_TRUNC;
+    if (mode & WAV_OPEN_READ) {
+        if (!(mode & WAV_OPEN_WRITE)) {
+            openMode = O_RDONLY;
+        }
+    } else {
+        if (!(mode & WAV_OPEN_WRITE)) {
+            MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "Invalid mode");
+            return 0;
+        }
+    }
+    return openMode;
+}
+
+int32_t WavInit(WavFile* self, const char* filename, uint32_t mode)
+{
+    if (memset_s(self, sizeof(WavFile), 0, sizeof(WavFile)) != EOK) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "memset_s failed");
+        return MEDIA_HAL_ERR;
+    }
+    uint32_t openMode = GetFileOpenMode(mode);
+    self->fp = open(filename, openMode, FILE_MODEL);
+    if (self->fp < 0) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "Error when opening %s [errno %d: %s]",
+            filename, errno, strerror(errno));
+        return MEDIA_HAL_ERR;
+    }
+    self->filename = WavStrdup(filename);
+    self->mode = mode;
+    self->riffChunk.id = WAV_RIFF_CHUNK_ID;
+    /* self->chunk.size = calculated by WavWriteHeader */
+    self->riffChunk.waveId = WAV_WAVE_ID;
+    self->riffChunk.offset = (uint64_t)sizeof(WavChunkHeader) + 0x4;
+
+    self->formatChunk.header.id                = WAV_FORMAT_CHUNK_ID;
+    self->formatChunk.header.size = (uint32_t)((unsigned long)&self->formatChunk.body.extSize -
+        (unsigned long)&self->formatChunk.body);
+    self->formatChunk.offset                   = self->riffChunk.offset + (uint64_t)sizeof(WavChunkHeader);
+    self->formatChunk.body.formatTag          = WAV_FORMAT_PCM;
+    self->formatChunk.body.channelCounts        = 1;
+    self->formatChunk.body.sampleRate         = WAV_DEFAULTE_SAMPLERATE;
+    self->formatChunk.body.avgBytesPerSec   = WAV_DEFAULTE_SAMPLERATE * 0x4;
+    self->formatChunk.body.blockAlign         = 0x4;
+    self->formatChunk.body.bitsPerSample     = 0x20;
+
+    if (memcpy_s(self->formatChunk.body.subFormat, WAV_SUB_FORMAT_LEN, DEFAULT_SUB_FORMAT, WAV_SUB_FORMAT_LEN) != EOK) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "memcpy_s subFormat failed");
+        return MEDIA_HAL_ERR;
+    }
+    self->dataChunk.header.id = WAV_DATA_CHUNK_ID;
+    self->dataChunk.offset = self->formatChunk.offset + self->formatChunk.header.size +
+        (uint64_t)sizeof(WavChunkHeader);
+    WavInitCueChunk(self);
+    return MEDIA_HAL_OK;
+}
+
+void WavFinalize(WavFile* self)
+{
+    WavFree(self->filename);
+    if (self->fp < 0) {
+        return;
+    }
+
+    int32_t ret = close(self->fp);
+    self->fp = -1; /* cannot open when File Descriptor equals -1 */
+    if (ret != 0) {
+        return;
+    }
+}
+
+WavFile* WavOpen(const char* filename, uint32_t mode)
+{
+    WavFile* self = WavMalloc(sizeof(WavFile));
+    if (self == NULL) {
+        return NULL;
+    }
+
+    int32_t ret = WavInit(self, filename, mode);
+    if (ret != MEDIA_HAL_OK) {\r
+        WavFree(self);\r
+        return NULL;\r
+    }
+    return self;
+}
+
+void WavClose(WavFile* self)
+{
+    WavFinalize(self);
+    WavFree(self);
+}
+
+static size_t WavGetSampleSize(const WavFile *self)
+{
+    return self->formatChunk.body.blockAlign / self->formatChunk.body.channelCounts;
+}
+ 
+size_t WavWrite(WavFile* self, const void *buffer, size_t count)
+{
+    size_t writeCount = 0;
+    uint32_t channels = WavGetNumChannels(self);
+    size_t sampleSize = WavGetSampleSize(self);
+    if (!(self->mode & WAV_OPEN_WRITE)) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "This WavFile is not writable");
+        return 0;
+    }
+    if (self->formatChunk.body.formatTag == WAV_FORMAT_EXTENSIBLE) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "Extensible format is not supported");
+        return 0;
+    }
+    if (count == 0) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "the wite count is 0!");
+        return 0;
+    }
+    writeCount = write(self->fp, buffer, channels * count);
+    if (writeCount <= 0) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "Error when writing to %s [errno %d: %s]",
+            self->filename, errno, strerror(errno));
+        return 0;
+    }
+    self->riffChunk.size += writeCount;
+    if (self->factChunk.header.id == WAV_FACT_CHUNK_ID) {
+        self->factChunk.body.sampleLength += writeCount / channels;
+    }
+    self->dataChunk.header.size += writeCount;
+    return writeCount;
+}
+
+void WavSetSampleSize(WavFile *self, size_t sampleSize)
+{
+    if (!(self->mode & WAV_OPEN_WRITE) && !((self->mode & WAV_OPEN_APPEND) &&
+        self->isANewFile && self->dataChunk.header.size == 0)) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "This WavFile is not writable");
+        return;
+    }
+
+    if (sampleSize < 1) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "Invalid sample size: %zu", sampleSize);
+        return;
+    }
+
+    self->formatChunk.body.blockAlign = (uint16_t)(sampleSize * self->formatChunk.body.channelCounts);
+    self->formatChunk.body.avgBytesPerSec = self->formatChunk.body.blockAlign * self->formatChunk.body.sampleRate;
+    self->formatChunk.body.bitsPerSample = (uint16_t)(sampleSize * 0x8);
+    if (self->formatChunk.body.formatTag == WAV_FORMAT_EXTENSIBLE) {
+        self->formatChunk.body.validBitsPerSample = (uint16_t)(sampleSize * 0x8);
+    }
+}
+
+void WavSetFormat(WavFile* self, uint16_t format)
+{
+    if (!(self->mode & WAV_OPEN_WRITE) && !((self->mode & WAV_OPEN_APPEND) &&
+        self->isANewFile && self->dataChunk.header.size == 0)) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "This WavFile is not writable");
+        return;
+    }
+
+    if (format == self->formatChunk.body.formatTag) {
+        return;
+    }
+
+    self->formatChunk.body.formatTag = format;
+    if (format != WAV_FORMAT_PCM && format != WAV_FORMAT_EXTENSIBLE) {
+        self->formatChunk.body.extSize = 0;
+        self->formatChunk.header.size =
+        (uint32_t)((unsigned long)&self->formatChunk.body.extSize - (unsigned long)&self->formatChunk.body);
+    } else if (format == WAV_FORMAT_EXTENSIBLE) {
+        self->formatChunk.body.extSize = 0x16;
+        self->formatChunk.header.size = (uint32_t)sizeof(WavFormatChunk) - (uint32_t)sizeof(WavChunkHeader);
+    }
+
+    if (format == WAV_FORMAT_ALAW || format == WAV_FORMAT_MULAW || format == WAV_FORMAT_726) {
+        uint16_t sampleSize = WavGetSampleSize(self);
+        if (sampleSize != 1) {
+            WavSetSampleSize(self, 1);
+        }
+    } else if (format == WAV_FORMAT_IEEE_FLOAT) {
+        uint16_t sampleSize = WavGetSampleSize(self);
+        if (sampleSize != 0x4 && sampleSize != 0x8) {
+            WavSetSampleSize(self, 0x4);
+        }
+    }
+}
+
+void WavSetNumChannels(WavFile* self, uint16_t channelCounts)
+{
+    if (!(self->mode & WAV_OPEN_WRITE) && !((self->mode & WAV_OPEN_APPEND) &&
+        self->isANewFile && self->dataChunk.header.size == 0)) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "This WavFile is not writable");
+        return;
+    }
+
+    if (channelCounts < 1) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "Invalid number of channels: %u", channelCounts);
+        return;
+    }
+
+    uint16_t oldChannelCounts = self->formatChunk.body.channelCounts;
+    if (channelCounts == oldChannelCounts) {
+        return;
+    }
+
+    self->formatChunk.body.channelCounts = channelCounts;
+    self->formatChunk.body.blockAlign = self->formatChunk.body.blockAlign / oldChannelCounts * channelCounts;
+    self->formatChunk.body.avgBytesPerSec = self->formatChunk.body.blockAlign * self->formatChunk.body.sampleRate;
+}
+
+void WavSetSampleRate(WavFile* self, uint32_t sampleRate)
+{
+    if (!(self->mode & WAV_OPEN_WRITE) && !((self->mode & WAV_OPEN_APPEND) &&
+        self->isANewFile && self->dataChunk.header.size == 0)) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "This WavFile is not writable");
+        return;
+    }
+
+    if (sampleRate == self->formatChunk.body.sampleRate) {
+        return;
+    }
+
+    self->formatChunk.body.sampleRate = sampleRate;
+    self->formatChunk.body.avgBytesPerSec = self->formatChunk.body.blockAlign * self->formatChunk.body.sampleRate;
+}
+
+uint32_t WavGetSampleRate(WavFile *self)
+{
+    return self->formatChunk.body.sampleRate;
+}
+
+uint32_t WavGetNumChannels(WavFile *self)
+{
+    return self->formatChunk.body.channelCounts;
+}
+
+void WavSetValidBitsPerSample(WavFile* self, uint16_t bits)
+{
+    if (!(self->mode & WAV_OPEN_WRITE) && !((self->mode & WAV_OPEN_APPEND) &&
+        self->isANewFile && self->dataChunk.header.size == 0)) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "This WavFile is not writable");
+        return;
+    }
+
+    if (bits < 1 || bits > 0x8 * self->formatChunk.body.blockAlign / self->formatChunk.body.channelCounts) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "Invalid ValidBitsPerSample: %u", bits);
+        return;
+    }
+
+    if ((self->formatChunk.body.formatTag == WAV_FORMAT_ALAW || self->formatChunk.body.formatTag == WAV_FORMAT_MULAW) &&
+        bits != 0x8) {
+        MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "Invalid ValidBitsPerSample: %u", bits);
+        return;
+    }
+
+    if (self->formatChunk.body.formatTag != WAV_FORMAT_EXTENSIBLE) {
+        self->formatChunk.body.bitsPerSample = bits;
+        self->formatChunk.body.blockAlign = bits / 0x8 * self->formatChunk.body.channelCounts;
+        self->formatChunk.body.avgBytesPerSec = self->formatChunk.body.blockAlign * self->formatChunk.body.sampleRate;
+    } else {
+        self->formatChunk.body.bitsPerSample =
+            0x8 * self->formatChunk.body.blockAlign / self->formatChunk.body.channelCounts;
+        self->formatChunk.body.validBitsPerSample = bits;
+    }
+}
+
+int32_t WavRecordMarks(WavFile *self, uint32_t marks)
+{
+    self->cueChunk.numMarkers++;
+    if (self->cueChunk.numMarkers <= WAV_MARKERS_BUFFER_SIZE) {\r
+        int16_t index = self->cueChunk.numMarkers - 1;\r
+        self->cueChunk.markers[index].id = self->cueChunk.numMarkers;\r
+        self->cueChunk.markers[index].position = marks;\r
+        self->cueChunk.markers[index].chunkId = 0x61746164;\r
+        self->cueChunk.markers[index].chunkStart = 0;\r
+        self->cueChunk.markers[index].blockStart = 0;\r
+        self->cueChunk.markers[index].sampleOffset = marks;
+        return MEDIA_HAL_OK;\r
+    }\r
+    self->cueChunk.numMarkers--;\r
+    MediaHalLogPrintf(MODULE_NAME, MEDIA_HAL_LOG_LEVEL_ERR, "The number of markers exceeds the limit[%d]",\r
+        WAV_MARKERS_BUFFER_SIZE);\r
+    return MEDIA_HAL_ERR;
+}
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/wav_muxer/wav.h b/code/sdk/middleware/services/media/hal/format/plugins/wav_muxer/wav.h
new file mode 100644 (file)
index 0000000..de9467c
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+ * Description: wav file
+ * Author: Media Software Group
+ * Create: 2025-03-10
+ */
+#ifndef WAV_H
+#define WAV_H
+#include <stddef.h>
+#include <stdint.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+enum {
+    WAV_FALSE,
+    WAV_TRUE
+};
+
+/* wave file format codes */
+#define WAV_FORMAT_PCM          ((uint16_t)0x0001)
+#define WAV_FORMAT_IEEE_FLOAT   ((uint16_t)0x0003)
+#define WAV_FORMAT_ALAW         ((uint16_t)0x0006)
+#define WAV_FORMAT_MULAW        ((uint16_t)0x0007)
+#define WAV_FORMAT_726          ((uint16_t)0x0008)
+#define WAV_FORMAT_EXTENSIBLE   ((uint16_t)0xfffe)
+
+typedef enum {
+    WAV_OK,         /** no error */
+    WAV_ERR_OS,     /** error when {wave} called a stdio function */
+    WAV_ERR_FORMAT, /** not a wave file or unsupported wave format */
+    WAV_ERR_MODE,   /** incorrect mode when opening the wave file or calling mode-specific API */
+    WAV_ERR_PARAM,  /** incorrect parameter passed to the API function */
+} WavErrCode;
+
+typedef struct {
+    WavErrCode  code;
+    char*       message;
+    int         isLiteral;
+} WavErrInfo;
+
+typedef struct {
+    void*   (*malloc)(void *context, size_t size);
+    void    (*free)(void *context, void *p);
+} WavAllocFuncs;
+
+void WavSetAllocator(void *context, const WavAllocFuncs *funcs);
+
+void* WavMalloc(size_t size);
+void WavFree(void *p);
+
+char* WavStrdup(const char *str);
+
+#define WAV_OPEN_READ       1
+#define WAV_OPEN_WRITE      2
+#define WAV_OPEN_APPEND     4
+
+typedef struct WavFileInfo WavFile;
+
+WavFile* WavOpen(const char* filename, uint32_t mode);
+void     WavClose(WavFile* self);
+void WavWriteHeader(WavFile *self);
+size_t WavWrite(WavFile* self, const void *buffer, size_t count);
+void WavSetSampleSize(WavFile *self, size_t sampleSize);
+void WavSetFormat(WavFile* self, uint16_t format);
+void WavSetSampleRate(WavFile *self, uint32_t sampleRate);
+uint32_t WavGetSampleRate(WavFile *self);
+void WavSetNumChannels(WavFile* self, uint16_t channelCounts);
+uint32_t WavGetNumChannels(WavFile *self);
+void WavSetValidBitsPerSample(WavFile* self, uint16_t bits);
+int32_t WavRecordMarks(WavFile *self, uint32_t marks);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/wav_muxer/wav_muxer.c b/code/sdk/middleware/services/media/hal/format/plugins/wav_muxer/wav_muxer.c
new file mode 100644 (file)
index 0000000..08841cf
--- /dev/null
@@ -0,0 +1,735 @@
+/*
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: wav_muxer.c
+* Author: Media Software Group
+* Create: 2025-03-10
+*/
+
+#include "wav_muxer.h"
+#include <malloc.h>
+#include <math.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+#include "muxer_interface.h"
+#include "dtcf_manager.h"
+#include "media_hal_common.h"
+#include "wav.h"
+#include "securec.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define MODULE_NAME "WavMuxer"
+
+#define BYTE_UNIT 1024
+#define WAV_MUXER_PRIORITY 100
+#ifdef SUPPORT_FEATURE_CONFIG\r
+#define INTERVAL_RECORD_FRAME (1000 / CONFIG_AUDIO_AI_FRAME_PER_SEC)\r
+#else\r
+#define INTERVAL_RECORD_FRAME 10\r
+#endif
+#define MSEC_PER_SEC (1000)
+#define REC_SPLIT_TIME_THRESHOLD (0.9)
+#define REC_SPLIT_SIZE_THRESHOLD (0.9)
+#ifdef TIME_CONSUMING_PRINTING
+#define MAX_TIMES 100
+#define MAX_TIME 100000
+#endif
+#define REC_US_TO_S (1000000.0)
+
+#define SIZE_PER_SAMPLE 2
+
+/* <max file size, determined by the file system */
+#ifndef ONLY_UT_TEST
+/* (4*1024*1024*1024-1*1024*1024*1024) */
+#define REC_MAX_FILE_SIZE (3221225472LL)
+#else
+/* 20*1024*1024 */
+#define REC_MAX_FILE_SIZE (20971520LL)
+#endif
+#define FILE_INFO_BUFFER_SIZE 350
+
+
+typedef struct {
+    MuxerOutput muxerOutput;
+    MuxerTrackSource trackSource;
+    char fileName[REC_FILE_NAME_LEN];
+    WavFile *fd;
+    bool muxerStarted;
+    int64_t maxFileSize;
+    int64_t maxDuration;
+    PluginCallback callBack;
+    DtcfCallBack dtcfCallBack;
+    uint64_t streamSize;
+    bool splitSizeBegin;
+    bool splitTimeBegin;
+    uint32_t realRecTimeLenMs;
+    uint64_t baseFramePts;
+    MediaHalMutexHandle mutex;
+    uint64_t maxMemorySize;
+    uint64_t startTime;
+    bool isFirstStart;
+       bool isSupportSplit;
+} WavMuxerContext;
+
+typedef struct {
+    int32_t dataLength;
+    int64_t frameTimeStamp;
+} WavFrameData;
+
+#ifdef TIME_CONSUMING_PRINTING
+static uint32_t g_times = 0;
+static uint32_t g_startTime = 0;
+static uint32_t g_endTime = 0;
+static uint32_t g_maxTime = 0;
+static uint32_t g_minTime = MAX_TIME;
+#endif
+
+static void GetCurrentTime(uint64_t *time)
+{
+    if (time == NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "time is NULL!");
+        return;
+    }
+    *time = uapi_tcxo_get_us();
+}
+
+static void ReportInfo(PluginCallback callBack, PluginInfoType infoType, int32_t extra)
+{
+    CHK_NULL_RETURN_NONE(callBack.OnInfo, "OnInfo invalid pointer");
+    callBack.OnInfo(callBack.handle, infoType, extra);
+}
+
+static void ReportError(PluginCallback callBack, int32_t errorType, int32_t errorCode)
+{
+    CHK_NULL_RETURN_NONE(callBack.OnError, "OnError invalid pointer");
+    callBack.OnError(callBack.handle, errorType, errorCode);
+}
+
+static int32_t DtcfEventCallBack(void *callBack, DtcfCallBackType errorType, int32_t errorCode)
+{
+    CHK_NULL_RETURN(callBack, MEDIA_HAL_INVALID_PARAM, "callBack invalid pointer");
+    WavMuxerContext *context = (WavMuxerContext *)callBack;
+    CHK_NULL_RETURN(context->callBack.OnError, MEDIA_HAL_INVALID_PARAM, "OnError invalid pointer");
+    PluginErrorType pluginErrorType;
+    switch (errorType) {
+        case DELETE_THE_OLDEST_FAILED:
+            context->callBack.OnError(context->callBack.handle, ERROR_TYPE_INTERNAL_OPERATION_FAIL, errorCode);
+            break;
+        case MEMORY_REACH_THE_MAXIMUM_VALUE:
+            context->callBack.OnInfo(context->callBack.handle, MAX_MEMORYSIZE_REACHED, errorCode);
+            break;
+        default:
+            MEDIA_HAL_LOGE(MODULE_NAME, "not support type = %d", errorType);
+            break;
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t WavMuxerFind(const MuxerOutput *output, const ProtocolFun *protocol)
+{
+    CHK_NULL_RETURN(output, MEDIA_HAL_INVALID_PARAM, "output is NULL");
+    if (output->type == OUT_TYPE_INVALID) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "out type invlid");
+        return MEDIA_HAL_INVALID_PARAM;
+    }
+    if (protocol != NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "not support extra protocol");
+        return MEDIA_HAL_INVALID_PARAM;
+    }
+    if (output->format != FORMAT_TYPE_WAV) {
+        return MEDIA_HAL_ERR;
+    }
+    MEDIA_HAL_LOGI(MODULE_NAME, "WavMuxer Found");
+    return MEDIA_HAL_OK;
+}
+
+static int32_t OpenOutTypeUriProcess(const MuxerOutput *output, DtcfCallBack callBack)
+{
+    int32_t optInit = DtcfMgrFileOptInit(output->url, strlen(output->url) + 1, callBack);
+    if (optInit != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "DtcfMgrFileOptInit fail 0x%x", optInit);
+        (void)DtcfMgrFileOptDeInit();
+        return MEDIA_HAL_ERR;
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t InitWavMuxer(WavMuxerContext *ctx)
+{
+    if (ctx->muxerOutput.type == OUT_TYPE_URI) {
+        if (DtcfMgrIsFile(ctx->muxerOutput.url, REC_FILE_NAME_LEN)) {
+            ctx->isSupportSplit = false;
+            MEDIA_HAL_LOGI(MODULE_NAME, "DtcfMgrIsFile is enter, ctx->muxerOutput.url = %s", ctx->muxerOutput.url);
+            int32_t ret = DtcfMgrMakeDir(ctx->muxerOutput.url, REC_FILE_NAME_LEN);
+            if (ret != MEDIA_HAL_OK) {
+                MEDIA_HAL_LOGE(MODULE_NAME, "DtcfMgrMakeDir error");
+                return MEDIA_HAL_ERR;
+            }
+            ctx ->fd = WavOpen(ctx->muxerOutput.url, WAV_OPEN_WRITE);
+               if (ctx->fd == NULL) {
+                MEDIA_HAL_LOGE(MODULE_NAME, "open file error, errno = %d", errno);
+                return MEDIA_HAL_ERR;
+            }
+            if (memcpy_s(ctx->fileName, REC_FILE_NAME_LEN, ctx->muxerOutput.url, REC_FILE_NAME_LEN) != EOK) {
+                MEDIA_HAL_LOGE(MODULE_NAME, "memcpy_s failed");
+                WavClose(ctx->fd);
+                ctx->fd = NULL;
+                return MEDIA_HAL_ERR;
+            }
+            return MEDIA_HAL_OK;
+        }
+        ctx->isSupportSplit = true;
+        int32_t ret = OpenOutTypeUriProcess(&ctx->muxerOutput, ctx->dtcfCallBack);
+        if (ret != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "OpenOutTypeUriProcess error, ret = %d", ret);
+            return MEDIA_HAL_ERR;
+        }
+        char fileNames[2][REC_FILE_NAME_LEN];
+        ret = DtcfMgrRequestFileNames(DTCF_FILE_TYPE_WAV, DTCF_DIR_RECORD_WAV_FILE, fileNames);
+        if (ret != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "DtcfMgrRequestFileNames error");
+            return MEDIA_HAL_ERR;
+        }
+        ctx ->fd = WavOpen(fileNames[0], WAV_OPEN_WRITE);
+        if (ctx->fd == NULL) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "wav open failed!");
+            return MEDIA_HAL_ERR;
+        }
+        if (memcpy_s(ctx->fileName, REC_FILE_NAME_LEN, fileNames[0], REC_FILE_NAME_LEN) != EOK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "memcpy_s failed");
+            return MEDIA_HAL_ERR;
+        }
+        WavWriteHeader(ctx->fd);
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t WavMuxerOpen(const MuxerOutput *output, const ProtocolFun *protocol, RecMuxerHandle *handle)
+{
+    MEDIA_HAL_UNUSED(protocol);
+    CHK_NULL_RETURN(output, MEDIA_HAL_INVALID_PARAM, "output is null");
+    CHK_NULL_RETURN(handle, MEDIA_HAL_INVALID_PARAM, "handle is null");
+    
+    WavMuxerContext *ctx = (WavMuxerContext*)malloc(sizeof(WavMuxerContext));
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_NO_MEM, "WavMuxerContext is null");
+    int32_t ret = MEDIA_HAL_OK;
+    if (memset_s(ctx, sizeof(WavMuxerContext), 0x0, sizeof(WavMuxerContext)) != EOK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "memset_s WavMuxerContext error");
+        goto CREATE_FAILED;
+    }
+    ctx->mutex = MediaHalMutexCreate(NULL);
+    if (ctx->mutex == NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "MediaHalMutexCreate failed!");
+        goto CREATE_FAILED;
+    }
+    ctx->muxerOutput = *output;
+    ctx->dtcfCallBack.handle = ctx;
+    ctx->dtcfCallBack.CallBack = DtcfEventCallBack;
+    ret = InitWavMuxer(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "CreateWavMuxer failed:0x%x", ret);
+        goto MUXER_DESTORY;
+    }
+    *handle = ctx;
+    if (ctx->isSupportSplit) {
+        ret = DtcfMgrGetStorageMaxSize(&ctx->maxMemorySize);
+        if (ret != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "DtcfGetStorageMaxSize failed!");
+        }
+    }
+    MEDIA_HAL_LOGI(MODULE_NAME, "WavMuxerOpen :%d", ret);
+    return MEDIA_HAL_OK;
+MUXER_DESTORY:
+    MediaHalMutexDestroy(&ctx->mutex);
+CREATE_FAILED:
+    free(ctx);
+    return MEDIA_HAL_ERR;
+}
+
+static int32_t DeinitWavMuxer(WavMuxerContext *ctx)
+{
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "handle");
+    WavWriteHeader(ctx->fd);
+    WavClose(ctx->fd);
+    ctx->fd = NULL;
+    ctx->muxerStarted = false;
+    ctx->isFirstStart = false;
+       ctx->isSupportSplit = false;
+    ctx->startTime = 0;
+    MEDIA_HAL_LOGI(MODULE_NAME, "DeinitWavMuxer success");
+    return MEDIA_HAL_OK;
+}
+
+static int32_t WavMuxerDestroy(RecMuxerHandle handle)
+{
+    WavMuxerContext *ctx = (WavMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "handle");
+    int32_t ret = DeinitWavMuxer(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "call DeinitWavMuxer fail:0x%x", ret);
+    }
+    if (ctx->isSupportSplit) {
+        (void)DtcfMgrFileOptDeInit();
+    }
+    MediaHalMutexDestroy(&ctx->mutex);
+    free(ctx);
+    MEDIA_HAL_LOGI(MODULE_NAME, "WavMuxerDestroy success");
+    return MEDIA_HAL_OK;
+}
+
+static int32_t AddAudioTrack(WavMuxerContext *ctx)
+{
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "ctx is null");
+    WavSetSampleRate(ctx->fd, ctx->trackSource.info.audioInfo.sampleRate);
+#ifdef MELODY_DEMO_BMIC_TX
+    WavSetNumChannels(ctx->fd, 1);
+#else
+    WavSetNumChannels(ctx->fd, ctx->trackSource.info.audioInfo.channelCount);
+#endif
+    int32_t sampleBitWidth = ctx->trackSource.info.audioInfo.sampleBitWidth;
+    if (sampleBitWidth == AUDIO_SAMPLE_FORMAT_FLOAT) {
+        WavSetFormat(ctx->fd, WAV_FORMAT_IEEE_FLOAT);
+        sampleBitWidth = AUDIO_SAMPLE_FORMAT_S32;
+    }
+    WavSetValidBitsPerSample(ctx->fd, sampleBitWidth);
+    return MEDIA_HAL_OK;
+}
+
+static int32_t WavMuxerAddTrack(RecMuxerHandle handle, const MuxerTrackSource *trackSource)
+{
+    CHK_NULL_RETURN(trackSource, MEDIA_HAL_INVALID_PARAM, "trackSource is null");
+    WavMuxerContext *ctx = (WavMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "WavMuxerContext is null");
+    if (trackSource->type != STREAM_TYPE_AUDIO) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "only support STREAM_TYPE_AUDIO!");
+        return MEDIA_HAL_ERR;
+    }
+    ctx->trackSource = *trackSource;
+    int32_t ret = AddAudioTrack(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "MuxerAddTrack failed [0x%x]", ret);
+    }
+    return ret;
+}
+
+static int32_t WavMuxerStart(RecMuxerHandle handle)
+{
+    WavMuxerContext *ctx = (WavMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "ctx is null");
+    CHK_COND_RETURN(ctx->muxerStarted, MEDIA_HAL_OK, "ctx is Started");
+    ctx->muxerStarted = true;
+    ctx->splitSizeBegin = !ctx->isSupportSplit;
+    ctx->splitTimeBegin = !ctx->isSupportSplit;
+    MEDIA_HAL_LOGI(MODULE_NAME, "RawMuxerStart success ");
+    return MEDIA_HAL_OK;
+}
+
+static bool SplitIsAchiveSize(WavMuxerContext *ctx)
+{
+    bool result = false;
+    if (ctx->splitSizeBegin) {
+        if (ctx->maxFileSize > 0 && ctx->streamSize >= ctx->maxFileSize * REC_SPLIT_SIZE_THRESHOLD) {
+            ReportInfo(ctx->callBack, MAX_FILESIZE_APPROACHING,
+                ctx->muxerOutput.type == OUT_TYPE_FD ? ctx->muxerOutput.fd : -1);
+            MEDIA_HAL_LOGI(MODULE_NAME, "size %lld Approaching maxFileSize %lld", ctx->streamSize, ctx->maxFileSize);
+            ctx->splitSizeBegin = false;
+        }
+    }
+
+    if ((ctx->maxFileSize > 0 && ctx->streamSize >= (uint64_t)ctx->maxFileSize) ||
+        ctx->streamSize >= REC_MAX_FILE_SIZE) {
+        ReportInfo(ctx->callBack, MAX_FILESIZE_REACHED,
+            ctx->muxerOutput.type == OUT_TYPE_FD ? ctx->muxerOutput.fd : -1);
+        result = true;
+        MEDIA_HAL_LOGI(MODULE_NAME, "size %lld has Approached maxFileSize %lld", ctx->streamSize, ctx->maxFileSize);
+        ctx->streamSize = 0;
+        ctx->splitSizeBegin = true;
+        ctx->baseFramePts = 0;
+    }
+    return result;
+}
+
+static bool SplitIsAchiveTime(WavMuxerContext *ctx)
+{
+    bool result = false;
+    uint32_t realRecTimeLen = ctx->realRecTimeLenMs / MSEC_PER_SEC;
+    if (ctx->splitTimeBegin) {
+        if (ctx->maxDuration > 0 && realRecTimeLen >= ctx->maxDuration * REC_SPLIT_TIME_THRESHOLD) {
+            ReportInfo(ctx->callBack, MAX_DURATION_APPROACHING,
+                ctx->muxerOutput.type == OUT_TYPE_FD ? ctx->muxerOutput.fd : -1);
+            MEDIA_HAL_LOGI(MODULE_NAME, "realRecTimeLen %u Approaching maxDuration %lld",
+                realRecTimeLen, ctx->maxDuration);
+            ctx->splitTimeBegin = false;
+        }
+    }
+    if (ctx->maxDuration > 0 && realRecTimeLen >= ctx->maxDuration) {
+        // split and reset manual split info
+        ReportInfo(ctx->callBack, MAX_DURATION_REACHED,
+            ctx->muxerOutput.type == OUT_TYPE_FD ? ctx->muxerOutput.fd : -1);
+        result = true;
+        MEDIA_HAL_LOGI(MODULE_NAME, "time %u has Approached maxDuration %lld", ctx->realRecTimeLenMs, ctx->maxDuration);
+        ctx->splitTimeBegin = true;
+        ctx->baseFramePts = 0;
+        ctx->streamSize = 0;
+    }
+    return result;
+}
+
+static int32_t ReConfigMuxer(WavMuxerContext *ctx)
+{
+    int32_t ret = DeinitWavMuxer(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "call DeinitWavMuxer fail:0x%x", ret);
+        return MEDIA_HAL_ERR;
+    }
+    ret = InitWavMuxer(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "CreateWavMuxer failed:0x%x", ret);
+        return MEDIA_HAL_ERR;
+    }
+    ret = AddAudioTrack(ctx);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "AddAudioTrack failed:0x%x", ret);
+        DeinitWavMuxer(ctx);
+        return MEDIA_HAL_ERR;
+    }
+    ctx->muxerStarted = true;
+    MEDIA_HAL_LOGE(MODULE_NAME, "ReConfigMuxer success");
+    return MEDIA_HAL_OK;
+}
+
+#ifdef TIME_CONSUMING_PRINTING
+static uint32_t WavMuxerWriteStartTime(void)
+{
+    if (g_times == 0) {
+        g_startTime = uapi_tcxo_get_ms();
+    }
+    return uapi_tcxo_get_ms();
+}
+
+static void WavMuxerWriteEndTime(uint32_t startTime)
+{
+    g_times++;
+    uint32_t endTime = uapi_tcxo_get_ms();
+    uint32_t writeTime = endTime - startTime;
+    g_maxTime = (writeTime > g_maxTime) ? writeTime : g_maxTime;
+    g_minTime = (writeTime < g_minTime) ? writeTime : g_minTime;
+    if (g_times == MAX_TIMES) {
+        g_endTime = uapi_tcxo_get_ms();
+        uint32_t totalTime = g_endTime - g_startTime;
+        MEDIA_HAL_LOGI(MODULE_NAME, " WavWrite totalTime = %ums", totalTime);
+        MEDIA_HAL_LOGI(MODULE_NAME, " WavWrite maxTime = %ums", g_maxTime);
+        MEDIA_HAL_LOGI(MODULE_NAME, " WavWrite minTime = %ums", g_minTime);
+        g_times = 0;
+        g_maxTime = 0;
+        g_minTime = MAX_TIME;
+    }
+}
+#endif
+
+static int32_t WavMuxerWriteFrameInner(WavMuxerContext *ctx, const FormatPacket *frameData,
+    const WavFrameData *wavFrameData)
+{
+#ifdef TIME_CONSUMING_PRINTING
+    uint32_t startTime = WavMuxerWriteStartTime();
+#endif
+    if (!ctx->isFirstStart) {\r
+        GetCurrentTime(&ctx->startTime);\r
+        ctx->isFirstStart = true;\r
+    }
+    if (WavWrite(ctx->fd, frameData->data, frameData->len) != frameData->len) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "fwrite failed errno:%d", errno);
+        return MEDIA_HAL_ERR_AGAIN;
+    }
+#ifdef TIME_CONSUMING_PRINTING
+        WavMuxerWriteEndTime(startTime);
+#endif
+       if (ctx->isSupportSplit) {
+        if (ctx->streamSize == 0) {
+            ctx->streamSize += wavFrameData->dataLength;
+        }
+        if (ctx->baseFramePts == 0) {
+            ctx->baseFramePts = wavFrameData->frameTimeStamp;
+        }
+       }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t HandleWavFrame(WavMuxerContext *ctx, WavFrameData *wavFrameData, const FormatPacket *frameData)
+{
+    CHK_NULL_RETURN(frameData, MEDIA_HAL_INVALID_PARAM, "wavFrameData is NULL!");
+    wavFrameData->dataLength = frameData->len;
+    if (ctx->isSupportSplit) {
+        wavFrameData->frameTimeStamp = frameData->timestampUs;
+        uint32_t frameNum = frameData->timestampUs / (MSEC_PER_SEC* INTERVAL_RECORD_FRAME);
+        uint32_t frameSize = frameData->len;
+        if (frameNum != 0) {
+            frameSize = frameData->len / frameNum;
+        }
+        MEDIA_HAL_LOGE(MODULE_NAME, "frameData->timestampUs = %lld, frameNum = %d, frameSize = %d!", frameData->timestampUs, frameNum, frameSize);
+        if (ctx->maxDuration < 1 || ctx->maxFileSize < frameSize) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "file duration or size is not right, write file failed!");
+            return MEDIA_HAL_ERR;
+        }
+    }
+    return MEDIA_HAL_OK;
+}
+
+static int32_t WavMuxerWriteFrame(RecMuxerHandle handle, const FormatPacket *frameData)
+{
+    CHK_NULL_RETURN(frameData, MEDIA_HAL_INVALID_PARAM, "frameData is NULL!");
+    WavMuxerContext *ctx = (WavMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "WavMuxerContext is null");
+    CHK_COND_RETURN(!ctx->muxerStarted, MEDIA_HAL_ERR, "WavMuxerContext is not Started");
+    if (ctx->isSupportSplit) {
+        if (DtcfMgrHandleRecordMaxSize(frameData->len, ctx->maxMemorySize) != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "handle reac max size failed!");
+            return MEDIA_HAL_ERR;
+        }
+    }
+    WavFrameData wavFrameData = {};
+    if (HandleWavFrame(ctx, &wavFrameData, frameData) != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "handle wav frame failed!");
+        return MEDIA_HAL_ERR;
+    }
+    MediaHalMutexLock(ctx->mutex);
+    int32_t ret = MEDIA_HAL_OK;
+    if (ctx->isSupportSplit) {
+        ctx->streamSize += wavFrameData.dataLength;
+        ctx->realRecTimeLenMs = (uint32_t)((wavFrameData.frameTimeStamp - ctx->baseFramePts) / MSEC_PER_SEC);
+        if (SplitIsAchiveSize(ctx) || SplitIsAchiveTime(ctx)) {
+            ret = ReConfigMuxer(ctx);
+            if (ret != MEDIA_HAL_OK) {
+                ReportError(ctx->callBack, ERROR_TYPE_INTERNAL_OPERATION_FAIL, ERROR_TYPE_INTERNAL_OPERATION_FAIL);
+                MediaHalMutexUnLock(ctx->mutex);
+                return MEDIA_HAL_ERR;
+            }
+        }
+    }
+    ret = WavMuxerWriteFrameInner(ctx, frameData, &wavFrameData);
+    if (ret != MEDIA_HAL_OK) {\r
+        MEDIA_HAL_LOGE(MODULE_NAME, "WavMuxerWriteFrameInner failed!");
+        MediaHalMutexUnLock(ctx->mutex);
+        return ret;\r
+    }
+    MediaHalMutexUnLock(ctx->mutex);
+    return MEDIA_HAL_OK;
+}
+
+static int32_t WavMuxerStop(RecMuxerHandle handle, bool block)
+{
+    CHK_NULL_RETURN(handle, MEDIA_HAL_INVALID_PARAM, "handle");
+    WavMuxerContext *ctx = (WavMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "WavMuxerContext");
+    CHK_COND_RETURN(!ctx->muxerStarted, MEDIA_HAL_ERR, "WavMuxerContext is not Started");
+    MEDIA_HAL_LOGI(MODULE_NAME, " block %d", block);
+    ctx->muxerStarted = false;
+    return MEDIA_HAL_OK;
+}
+
+static int32_t WavMuxerSetMaxFileSize(RecMuxerHandle handle, int64_t bytes)
+{
+    CHK_NULL_RETURN(handle, MEDIA_HAL_INVALID_PARAM, "handle");
+    WavMuxerContext *ctx = (WavMuxerContext *)handle;
+    MEDIA_HAL_LOGI(MODULE_NAME, "bytes:%lld ", bytes);
+    ctx->maxFileSize = bytes;
+    return MEDIA_HAL_OK;
+}
+
+static int32_t WavMuxerSetMaxFileDuration(RecMuxerHandle handle, int64_t durationUs)
+{
+    CHK_NULL_RETURN(handle, MEDIA_HAL_INVALID_PARAM, "handle");
+    WavMuxerContext *ctx = (WavMuxerContext *)handle;
+    MEDIA_HAL_LOGI(MODULE_NAME, "durationUs:%lld ", durationUs);
+    ctx->maxDuration = durationUs;
+    return MEDIA_HAL_OK;
+}
+
+static int32_t WavMuxerSetNextOutputFile(RecMuxerHandle handle, int32_t fd)
+{
+    WavMuxerContext *ctx = (WavMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "handle is null");
+    MEDIA_HAL_LOGI(MODULE_NAME, "fd:%d", fd);
+    if (ctx->muxerOutput.type == OUT_TYPE_URI) {
+        return MEDIA_HAL_ERR;
+    }
+    ctx->muxerOutput.fd = fd;
+    return MEDIA_HAL_OK;
+}
+
+static int32_t MuxerSetCallBack(WavMuxerContext *ctx, const PluginCallback *callBack)
+{
+    CHK_NULL_RETURN(callBack, MEDIA_HAL_INVALID_PARAM, "callBack");
+    ctx->callBack = *callBack;
+    return MEDIA_HAL_OK;
+}
+
+static void GetCurrentStorageTimeRemaindTime(WavMuxerContext *ctx, uint32_t packetLen, uint32_t *time)
+{
+    if (!ctx->isSupportSplit) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "not support get recorder time!");
+        return;
+    }
+    MediaHalMutexLock(ctx->mutex);
+    *time = ((DtcfMgrGetCurrentMemorySize(ctx->maxMemorySize) - DtcfMgrGetCurrentRecordedSize()) / packetLen) *
+        INTERVAL_RECORD_FRAME;
+    MEDIA_HAL_LOGI(MODULE_NAME, "remaind storage packetLen = %u, time:%u\n", packetLen, *time);
+    MediaHalMutexUnLock(ctx->mutex);
+}
+
+static void GetCurrentFileRemaindTime(WavMuxerContext *ctx, uint32_t packetLen, uint32_t *time)
+{
+    if (!ctx->isSupportSplit) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "not support get file time!");
+        return;
+    }
+    MediaHalMutexLock(ctx->mutex);
+    uint32_t currentSec = ((ctx->maxFileSize / packetLen) * INTERVAL_RECORD_FRAME) / MSEC_PER_SEC;
+    if (currentSec >= ctx->maxDuration) {
+        *time = (ctx->maxDuration * MSEC_PER_SEC) - ctx->realRecTimeLenMs;
+    } else {
+        *time = ((ctx->maxFileSize - ctx->streamSize) / packetLen) * INTERVAL_RECORD_FRAME;
+    }
+    MEDIA_HAL_LOGI(MODULE_NAME, "remaind file packetLen = %u, time:%u", packetLen, *time);
+    MediaHalMutexUnLock(ctx->mutex);
+}
+
+static int32_t GetCurrentFileInfo(WavMuxerContext *ctx, char **value)
+{
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "handle is null");
+    CHK_NULL_RETURN(value, MEDIA_HAL_INVALID_PARAM, "value is null");
+    CHK_NULL_RETURN(*value, MEDIA_HAL_INVALID_PARAM, "real value is null");
+    if (!ctx->isSupportSplit) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "not support get file info!");
+        return MEDIA_HAL_ERR;
+    }
+    MediaHalMutexLock(ctx->mutex);
+    FileDate fileDate = {};
+    int32_t ret = DtcfMgrGetCurrentFileDate(&fileDate);
+    if (ret != MEDIA_HAL_OK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "Get Current File Date failed:%d", ret);
+        MediaHalMutexUnLock(ctx->mutex);
+        return ret;
+    }
+    char *lastSlash = strrchr(ctx->fileName, '/');
+    if (lastSlash == NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "Get Current File name failed!");
+        MediaHalMutexUnLock(ctx->mutex);
+        return MEDIA_HAL_ERR;
+    }
+    ret = sprintf_s(*value, FILE_INFO_BUFFER_SIZE, "%llu,%u,%u,%u,%u,%u,%u,%u=%s", ctx->streamSize,
+        fileDate.fileDateYear, fileDate.fileDateMonth, fileDate.fileDateDay, fileDate.fileDateHour,
+        fileDate.fileDateMin, fileDate.fileDateSec, ctx->realRecTimeLenMs, lastSlash + 1);
+    if (ret == -1 || ret >= FILE_INFO_BUFFER_SIZE) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "sprintf_s failed!");
+        MediaHalMutexUnLock(ctx->mutex);
+        return MEDIA_HAL_ERR;
+    }
+    MediaHalMutexUnLock(ctx->mutex);
+    return MEDIA_HAL_OK;
+}
+
+static int32_t WavMuxerInvokeRecordMarks(WavMuxerContext *ctx)
+{
+    CHK_NULL_RETURN(ctx->fd, MEDIA_HAL_INVALID_PARAM, "ctx->fd is NULL!");
+    uint64_t markTime = 0;
+    GetCurrentTime(&markTime);
+    float marks = (markTime - ctx->startTime) / REC_US_TO_S;
+    uint32_t sampleRate = WavGetSampleRate(ctx->fd);
+    uint32_t channel = WavGetNumChannels(ctx->fd);
+    uint32_t sampleNum = marks * sampleRate * channel;
+    return WavRecordMarks(ctx->fd, sampleNum);
+}
+
+static int32_t WavMuxerInvoke(RecMuxerHandle handle, uint32_t invokeId, void *arg)
+{
+    int32_t ret = MEDIA_HAL_OK;
+    WavMuxerContext *ctx = (WavMuxerContext *)handle;
+    CHK_NULL_RETURN(ctx, MEDIA_HAL_INVALID_PARAM, "muxerContext is NULL!");
+    CHK_NULL_RETURN(arg, MEDIA_HAL_INVALID_PARAM, "arg is NULL!");
+    MEDIA_HAL_LOGI(MODULE_NAME, "invokeId:%d ", invokeId);
+    switch (invokeId) {
+        case INVOKE_SET_CALLBACK:
+            ret = MuxerSetCallBack(ctx, (const PluginCallback *)arg);
+            break;
+        case INVOKE_SET_DELETE_OLD_FILES_ENABLE: {
+            uint32_t value = *((uint32_t *)arg);
+            bool enable = false;
+            if (value != 0) {
+                enable = true;
+            }
+            if (!ctx->isSupportSplit) {
+                enable = false;
+            }
+            DtcfMgrSetDeleteFileEnable(enable);
+            break;
+        }
+        case INVOKE_SET_MAX_STORAGE_THRESHOLD: {
+            uint32_t value = *((uint32_t *)arg);
+            DtcfMgrSetMaxStorageThreshold(value);
+            break;
+        }
+        case INVOKE_RECORDE_WRITE_MARKS: {
+            ret = WavMuxerInvokeRecordMarks(ctx);
+            break;
+        }
+        case INVOKE_CURRENT_STORAGE_REMAIND_TIME: {
+            uint32_t packetLen = *((uint32_t *)arg);
+            GetCurrentStorageTimeRemaindTime(ctx, packetLen, (uint32_t *)arg);
+            break;
+        }
+        case INVOKE_CURRENT_FILE_REMAIND_TIME: {
+            uint32_t packetLen = *((uint32_t *)arg);
+            GetCurrentFileRemaindTime(ctx, packetLen, (uint32_t *)arg);
+            break;
+        }
+        case INVOKE_CURRENT_FILE_INFO: {
+            ret = GetCurrentFileInfo(ctx, (char **)arg);
+            break;
+        }
+        default:
+            MEDIA_HAL_LOGI(MODULE_NAME, "not support invokeId:%d ", invokeId);
+            break;
+    }
+    return ret;
+}
+
+MuxerPluginEntry g_wavMuxerEntry = {
+    .desc = {
+        .libName = "libplugin_muxer_wav.so",
+        .name = "wav_muxer",
+        .version = "version 1.0.0",
+        .description = "wav_muxer",
+        .supportCapability = "wav",
+        .priority = WAV_MUXER_PRIORITY,
+    },
+    .fmt_find = WavMuxerFind,
+    .fmt_open = WavMuxerOpen,
+    .fmt_add_track = WavMuxerAddTrack,
+    .fmt_start = WavMuxerStart,
+    .fmt_write = WavMuxerWriteFrame,
+    .fmt_stop = WavMuxerStop,
+    .fmt_set_max_size = WavMuxerSetMaxFileSize,
+    .fmt_set_max_duration = WavMuxerSetMaxFileDuration,
+    .fmt_set_next_outputfile = WavMuxerSetNextOutputFile,
+    .fmt_invoke = WavMuxerInvoke,
+    .fmt_close = WavMuxerDestroy,
+};
+
+#ifdef ENABLE_DL_DEMUXER_PLUGIN
+const MuxerPluginEntry *GetMuxer(void)
+{
+    return &g_wavMuxerEntry;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
\ No newline at end of file
diff --git a/code/sdk/middleware/services/media/hal/format/plugins/wav_muxer/wav_muxer.h b/code/sdk/middleware/services/media/hal/format/plugins/wav_muxer/wav_muxer.h
new file mode 100644 (file)
index 0000000..f478e15
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+* Copyright (c) CompanyNameMagicTag. 2025-2025. All rights reserved.
+* Description: wav_muxer define
+* Author: Media Software Group
+* Create: 2025-03-10
+*/
+
+#ifndef WAV_MUXER_H
+#define WAV_MUXER_H
+
+#include "muxer_interface.h"
+#ifdef MELODY_DEMO_BMIC_TX
+#include "feature_config.h"
+#endif
+#if (defined(CONFIG_SUPPORT_FILESYSTEM) && defined(PRE_ASIC)) || defined(PRE_FPGA)
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef ENABLE_DL_DEMUXER_PLUGIN
+const MuxerPluginEntry *GetMuxer(void);
+#else
+extern MuxerPluginEntry g_wavMuxerEntry;
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+#endif
diff --git a/code/sdk/middleware/services/media/hal/format/src/demuxer_manager/src/demuxer_buffer.c b/code/sdk/middleware/services/media/hal/format/src/demuxer_manager/src/demuxer_buffer.c
new file mode 100644 (file)
index 0000000..9c0df07
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag. 2025-2025. All rights reserved.
+ * Description: buffer cache for online play
+ * Author: Media Software Group
+ * Create: 2025-6-20
+ */
+
+#include "demuxer_buffer.h"
+
+#include <stdint.h>
+#include <inttypes.h>
+#include "securec.h"
+#include "demuxer_interface.h"
+#include "format_type.h"
+#include "format_common.h"
+#include "hal_list.h"
+#include "media_hal_thread_adapt.h"
+#include "media_hal_common.h"
+#include "demuxer_common.h"
+
+#define MODULE_NAME "DemuxerBuffer"
+#define DEFAULT_MAX_BUFFER_SIZE (2 * 1024 * 1024) // 2MB
+#define DEFAULT_MAX_BUFFER_DURATION (10 * 1000) // 10s
+#define BUFFER_HIGH_LEVEL (0.7) // 70%
+
+typedef enum {
+    STOPPED,            // thread stopped
+    NORMAL_READING,     // thread is working to read frame
+    BUFFER_FULL_SLEEP,  // thread is sleeping because buffer is full
+    GET_EOF_SLEEP,      // thread is sleeping because received eof flag
+} BufferThreadStatus;
+
+typedef enum {
+    BUFFER_FULL_NONE,
+    BUFFER_FULL_DURATION,
+    BUFFER_FULL_SIZE,
+} BufferFullType;
+
+typedef struct {
+    int32_t streamIndex;
+    int64_t timeStampUs;
+    FormatSeekMode mode;
+    bool shoudDoSeek;
+    int32_t doSeekResult;
+    MediaHalThreadCondHandle seekCond;
+} SeekContext;
+
+typedef struct {
+    bool running;
+    int32_t fmtReadResult;
+    BufferThreadStatus status;
+    FormatBufferSetting bufferSetting;
+    BufferFullType bufferFullType;
+    MediaHalMutexHandle mutex;
+    MediaHalThreadCondHandle cond;
+    MediaHalThreadIdHandle threadId;
+    const DemuxerPluginEntry *demuxer;
+    FormatHandle demuxerHdl;
+    List bufferQueue;
+    int64_t totalTime;
+    int64_t totalSize;
+    SeekContext seekCtx;
+} BufferManager;
+
+static void InitSeekContext(SeekContext *seekCtx)
+{
+    seekCtx->streamIndex = -1;
+    seekCtx->timeStampUs = -1;
+    seekCtx->mode = SEEK_MODE_BUT;
+    seekCtx->shoudDoSeek = false;
+    seekCtx->doSeekResult = -1;
+    seekCtx->seekCond = MediaHalThreadCondCreate();
+    return;
+}
+
+FormatHandle CreateDemuxerBuffer(void)
+{
+    BufferManager *ctx = (BufferManager*)malloc(sizeof(BufferManager));
+    CHK_NULL_RETURN(ctx, NULL, "malloc BufferManager failed");
+    ctx->running = false;
+    ctx->fmtReadResult = 0;
+    ctx->status = STOPPED;
+    ctx->bufferSetting.maxDurationMs = DEFAULT_MAX_BUFFER_DURATION;
+    ctx->bufferSetting.maxSize = DEFAULT_MAX_BUFFER_SIZE;
+    ctx->bufferFullType = BUFFER_FULL_NONE;
+    MediaHalMutexAttr attr = { false };
+    ctx->mutex = MediaHalMutexCreate(&attr);
+    ctx->cond = MediaHalThreadCondCreate();
+    ctx->threadId = NULL;
+    ctx->demuxer = NULL;
+    ctx->demuxerHdl = NULL;
+    HalListInit(&(ctx->bufferQueue), NULL);
+    ctx->totalTime = 0;
+    ctx->totalSize = 0;
+    InitSeekContext(&(ctx->seekCtx));
+    return (FormatHandle)ctx;
+}
+
+int32_t SetBufferConfig(FormatHandle handle, const FormatBufferSetting *setting)
+{
+    CHK_NULL_RETURN(handle, -1, "input param handle null");
+    CHK_NULL_RETURN(setting, -1, "input param setting null");
+    BufferManager *ctx = (BufferManager*)handle;
+    ctx->bufferSetting = *setting;
+    return 0;
+}
+
+int32_t GetBufferConfig(FormatHandle handle, FormatBufferSetting *setting)
+{
+    CHK_NULL_RETURN(handle, -1, "input param handle null");
+    CHK_NULL_RETURN(setting, -1, "input param setting null");
+    BufferManager *ctx = (BufferManager*)handle;
+    *setting = ctx->bufferSetting;
+    return 0;
+}
+
+static FormatFrame *PacketToFrame(const FormatPacket *packet)
+{
+    if (packet == NULL || packet->packetType > PACKET_TYPE_BUT) {
+        return NULL;
+    }
+
+    FormatFrame *frame = (FormatFrame*)malloc(sizeof(FormatFrame));
+    CHK_NULL_RETURN(frame, NULL, "malloc FormatFrame failed");
+    FormatPacketToFrame(packet, frame);
+
+    frame->data = (uint8_t*)malloc(packet->len);
+    if (frame->data == NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "malloc frame data failed");
+        goto FREE_FRAME;
+    }
+    if (memcpy_s(frame->data, packet->len, packet->data, packet->len) != EOK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "memcpy_s packet data failed");
+        goto FREE_DATA;
+    }
+
+    if (frame->itemCnt > 0) {
+        size_t itemLen = frame->itemCnt * sizeof(ParameterItem);
+        frame->item = (ParameterItem*)malloc(itemLen);
+        if (frame->item == NULL) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "malloc frame item failed");
+            goto FREE_DATA;
+        }
+        if (memcpy_s(frame->item, itemLen, packet->item, itemLen) != EOK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "memcpy_s frame item failed");
+            goto FREE_ITEM;
+        }
+    }
+
+    return frame;
+
+FREE_ITEM:
+    free(frame->item);
+    frame->item = NULL;
+FREE_DATA:
+    free(frame->data);
+    frame->data = NULL;
+FREE_FRAME:
+    free(frame);
+    frame = NULL;
+
+    return NULL;
+}
+
+static void ClearBuffer(BufferManager *ctx)
+{
+    FormatFrame *frame = NULL;
+    while (!HalListEmpty(&(ctx->bufferQueue))) {
+        frame = (FormatFrame*)HalListFront(&(ctx->bufferQueue));
+        HalListPopFront(&(ctx->bufferQueue));
+        if (frame != NULL) {
+            FreeBufferFrame(frame);
+            free(frame);
+            frame = NULL;
+        }
+    }
+    ctx->totalSize = 0;
+    ctx->totalTime = 0;
+    ctx->bufferFullType = BUFFER_FULL_NONE;
+    return;
+}
+
+static int32_t DoSeek(BufferManager *ctx)
+{
+    ClearBuffer(ctx);
+    int32_t ret = ctx->demuxer->fmt_seek_pts(ctx->demuxerHdl, ctx->seekCtx.streamIndex,
+        ctx->seekCtx.timeStampUs, ctx->seekCtx.mode);
+    ctx->seekCtx.shoudDoSeek = false;
+    ctx->seekCtx.doSeekResult = ret;
+    MediaHalThreadCondSignal(ctx->seekCtx.seekCond);
+    return ret;
+}
+
+static bool IsBufferFull(BufferManager *ctx)
+{
+    int64_t allowMaxSize = ctx->bufferSetting.maxSize;
+    if (allowMaxSize > 0 && ctx->totalSize >= allowMaxSize) {
+        ctx->bufferFullType = BUFFER_FULL_SIZE;
+        return true;
+    }
+
+    int64_t allowMaxDuration = ctx->bufferSetting.maxDurationMs;
+    if (allowMaxDuration > 0 && ctx->totalTime >= allowMaxDuration) {
+        ctx->bufferFullType = BUFFER_FULL_DURATION;
+        return true;
+    }
+
+    return false;
+}
+
+static bool IsBufferNotEnough(BufferManager *ctx)
+{
+    int64_t allowMaxSize = ctx->bufferSetting.maxSize;
+    if (allowMaxSize > 0 && ctx->bufferFullType == BUFFER_FULL_SIZE &&
+        ctx->totalSize <= (int64_t)(allowMaxSize * BUFFER_HIGH_LEVEL)) {
+        return true;
+    }
+
+    int64_t allowMaxTime = ctx->bufferSetting.maxDurationMs;
+    if (allowMaxTime > 0 && ctx->bufferFullType == BUFFER_FULL_DURATION &&
+        ctx->totalTime <= (int64_t)(allowMaxTime * BUFFER_HIGH_LEVEL)) {
+        return true;
+    }
+
+    return false;
+}
+
+static void DealThreadStatus(BufferManager *ctx)
+{
+    if (ctx->fmtReadResult == RET_FILE_EOF) {
+        ctx->status = GET_EOF_SLEEP;
+        MEDIA_HAL_LOGE(MODULE_NAME, "buffer thread get eof flag");
+    } else if (IsBufferFull(ctx)) {
+        ctx->status = BUFFER_FULL_SLEEP;
+    } else {
+        ctx->status = NORMAL_READING;
+    }
+    return;
+}
+
+static int32_t ReadDemuxerPacket(BufferManager *ctx, FormatPacket *packet)
+{
+    int32_t ret = ctx->demuxer->fmt_read(ctx->demuxerHdl, packet);
+    if ((ret == MEDIA_HAL_OK) && (packet->data != NULL) && (packet->len == 0)) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "fmt_read frame zero len");
+        ret = MEDIA_HAL_ERR;
+    }
+    return ret;
+}
+
+static int32_t FreeDemuxerPacket(BufferManager *ctx, FormatPacket *packet)
+{
+    int32_t ret = ctx->demuxer->fmt_free(ctx->demuxerHdl, packet);
+    packet->data = NULL;
+    packet->len = 0;
+    packet->item = NULL;
+    packet->itemCnt = 0;
+    return ret;
+}
+
+static void PushFrame(BufferManager *ctx, const FormatPacket *packet)
+{
+    FormatFrame *frame = PacketToFrame(packet);
+    if (frame == NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "PacketToFrame error");
+        return;
+    }
+    HalListPushBack(&(ctx->bufferQueue), (uintptr_t)frame);
+    ctx->totalSize += frame->len;
+    ctx->totalTime += frame->durationUs;
+    return;
+}
+
+static FormatFrame *PopFrame(BufferManager *ctx)
+{
+    FormatFrame *frontFrame = (FormatFrame*)HalListFront(&(ctx->bufferQueue));
+    HalListPopFront(&(ctx->bufferQueue));
+    if (frontFrame != NULL) {
+        ctx->totalSize -= frontFrame->len;
+        ctx->totalTime -= frontFrame->durationUs;
+    }
+    return frontFrame;
+}
+
+static void *BufferThread(void *args)
+{
+    BufferManager *ctx = (BufferManager*)args;
+    FormatPacket packet;
+    int32_t ret;
+    ctx->status = NORMAL_READING;
+    while (true) {
+        MediaHalMutexLock(ctx->mutex);
+        if (!ctx->running) {
+            MediaHalMutexUnLock(ctx->mutex);
+            break;
+        }
+        if (ctx->seekCtx.shoudDoSeek) {
+            DoSeek(ctx);
+            ctx->fmtReadResult = 0;
+        }
+        DealThreadStatus(ctx);
+        if (ctx->status != NORMAL_READING) {
+            MediaHalThreadCondWait(ctx->cond, ctx->mutex);
+            MediaHalMutexUnLock(ctx->mutex);
+            continue;
+        }
+        MediaHalMutexUnLock(ctx->mutex);
+
+        ret = ReadDemuxerPacket(ctx, &packet);
+
+        MediaHalMutexLock(ctx->mutex);
+        ctx->fmtReadResult = ret;
+        if (ctx->fmtReadResult != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "fmt_read error");
+            MediaHalMutexUnLock(ctx->mutex);
+            continue;
+        }
+        PushFrame(ctx, &packet);
+        MediaHalMutexUnLock(ctx->mutex);
+
+        FreeDemuxerPacket(ctx, &packet);
+    }
+
+    ClearBuffer(ctx);
+    ctx->status = STOPPED;
+    return NULL;
+}
+
+int32_t StartBufferThread(FormatHandle handle, FormatHandle demuxerHdl, const DemuxerPluginEntry *demuxer, const char *url)
+{
+    CHK_NULL_RETURN(handle, -1, "input param handle null");
+    CHK_NULL_RETURN(demuxerHdl, -1, "input param demuxerHdl null");
+    CHK_NULL_RETURN(demuxer, -1, "input param demuxer null");
+
+    BufferManager *ctx = (BufferManager*)handle;
+    ctx->demuxerHdl = demuxerHdl;
+    ctx->demuxer = demuxer;
+    MediaHalThreadattr attr = { "BufferThread", 0x1000, THREAD_SCHED_INVALID, 0, false };
+    if (HasM3U8(url)) {
+        attr.stackSize = 0xDF00;
+    }
+    ctx->running = true;
+    ctx->threadId = MediaHalThreadCreate(BufferThread, handle, &attr);
+    if (ctx->threadId == NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "crate BufferManager thread failed");
+        ctx->running = false;
+        return -1;
+    }
+    return 0;
+}
+
+int32_t ReadBufferFrame(FormatHandle handle, FormatFrame *frame)
+{
+    CHK_NULL_RETURN(handle, -1, "input param handle null");
+    CHK_NULL_RETURN(frame, -1, "input param frame null");
+
+    int32_t ret = 0;
+    BufferManager *ctx = (BufferManager*)handle;
+    MediaHalMutexLock(ctx->mutex);
+    if (HalListEmpty(&(ctx->bufferQueue))) {
+        if (ctx->status == GET_EOF_SLEEP) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "return eof when ReadBufferFrame");
+            MediaHalMutexUnLock(ctx->mutex);
+            return RET_FILE_EOF;
+        }
+        if (ctx->fmtReadResult == MEDIA_HAL_ERR) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "return error when ReadBufferFrame");
+            MediaHalMutexUnLock(ctx->mutex);
+            return MEDIA_HAL_ERR;
+        }
+        MEDIA_HAL_LOGE(MODULE_NAME, "return nodata when ReadBufferFrame");
+        MediaHalMutexUnLock(ctx->mutex);
+        return RET_NODATA;
+    }
+
+    FormatFrame *frontFrame = PopFrame(ctx);
+    if (frontFrame == NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "get frame from queue falied");
+        MediaHalMutexUnLock(ctx->mutex);
+        return -1;
+    }
+
+    if (ctx->status == BUFFER_FULL_SLEEP && IsBufferNotEnough(ctx)) {
+        MediaHalThreadCondSignal(ctx->cond);
+    }
+    if (memcpy_s(frame, sizeof(FormatFrame), frontFrame, sizeof(FormatFrame)) != EOK) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "memcpy_s frame failed");
+        ret = -1;
+    }
+    free(frontFrame);
+    frontFrame = NULL;
+    MediaHalMutexUnLock(ctx->mutex);
+    return ret;
+}
+
+int32_t FreeBufferFrame(FormatFrame *frame)
+{
+    CHK_NULL_RETURN(frame, -1, "input param frame null");
+    if (frame->data != NULL) {
+        free(frame->data);
+        frame->data = NULL;
+        frame->len = 0;
+    }
+    if (frame->item != NULL) {
+        free(frame->item);
+        frame->item = NULL;
+        frame->itemCnt = 0;
+    }
+    return 0;
+}
+
+int32_t SeekBuffer(FormatHandle handle, int32_t streamIndex, int64_t timeStampUs, FormatSeekMode mode)
+{
+    CHK_NULL_RETURN(handle, -1, "input param handle null");
+    BufferManager *ctx = (BufferManager*)handle;
+    MediaHalMutexLock(ctx->mutex);
+    ctx->seekCtx.streamIndex = streamIndex;
+    ctx->seekCtx.timeStampUs = timeStampUs;
+    ctx->seekCtx.mode = mode;
+    ctx->seekCtx.shoudDoSeek = true;
+    ctx->seekCtx.doSeekResult = -1;
+    MediaHalThreadCondSignal(ctx->cond);
+    while (ctx->seekCtx.shoudDoSeek && ctx->running) {
+        MediaHalThreadCondWait(ctx->seekCtx.seekCond, ctx->mutex);
+    }
+    MediaHalMutexUnLock(ctx->mutex);
+    return ctx->seekCtx.doSeekResult;
+}
+
+int32_t StopBufferThread(FormatHandle handle)
+{
+    CHK_NULL_RETURN(handle, -1, "input param handle null");
+    BufferManager *ctx = (BufferManager*)handle;
+    MediaHalMutexLock(ctx->mutex);
+    ctx->running = false;
+    MediaHalThreadCondSignal(ctx->cond);
+    MediaHalThreadCondSignal(ctx->seekCtx.seekCond);
+    MediaHalMutexUnLock(ctx->mutex);
+    MediaHalThreadJoin(&(ctx->threadId));
+    return 0;
+}
+
+int32_t DestoryDemuxerBuffer(FormatHandle *handle)
+{
+    CHK_NULL_RETURN(handle, -1, "input param handle null");
+    CHK_NULL_RETURN(*handle, -1, "input param *handle null");
+    BufferManager *ctx = (BufferManager*)(*handle);
+    if (ctx->running) {
+        StopBufferThread(*handle);
+    }
+    MediaHalMutexDestroy(&(ctx->mutex));
+    MediaHalThreadCondDestroy(&(ctx->cond));
+    MediaHalThreadCondDestroy(&(ctx->seekCtx.seekCond));
+    HalListDeinit(&(ctx->bufferQueue));
+    free(ctx);
+    *handle = NULL;
+    return 0;
+}
diff --git a/code/sdk/middleware/services/media/hal/format/src/demuxer_manager/src/demuxer_buffer.h b/code/sdk/middleware/services/media/hal/format/src/demuxer_manager/src/demuxer_buffer.h
new file mode 100644 (file)
index 0000000..0ec4fb4
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) @CompanyNameMagicTag. 2025-2025. All rights reserved.
+ * Description: buffer cache for online play
+ * Author: Media Software Group
+ * Create: 2025-6-20
+ */
+
+#ifndef DEMUXER_BUFFER_H
+#define DEMUXER_BUFFER_H
+
+#include <stdint.h>
+#include "format_type.h"
+#include "demuxer_interface.h"
+
+FormatHandle CreateDemuxerBuffer(void);
+int32_t SetBufferConfig(FormatHandle handle, const FormatBufferSetting *setting);
+int32_t GetBufferConfig(FormatHandle handle, FormatBufferSetting *setting);
+int32_t StartBufferThread(FormatHandle handle, FormatHandle demuxerHdl, const DemuxerPluginEntry *demuxer, const char *url);
+int32_t ReadBufferFrame(FormatHandle handle, FormatFrame *frame);
+int32_t FreeBufferFrame(FormatFrame *frame);
+int32_t SeekBuffer(FormatHandle handle, int32_t streamIndex, int64_t timeStampUs, FormatSeekMode mode);
+int32_t StopBufferThread(FormatHandle handle);
+int32_t DestoryDemuxerBuffer(FormatHandle *handle);
+
+#endif
index 53b0ab7..552dc1f 100644 (file)
 #include "protocol_plugins_manager.h"
 #include "media_hal_thread_adapt.h"
 
+#ifdef ENABLE_BUFFER_MANAGER
+#include "demuxer_buffer.h"
+#endif
+
 #ifdef __cplusplus
 #if __cplusplus
 extern "C" {
@@ -41,14 +45,6 @@ typedef struct {
     MediaHalMutexHandle mutex;
 } DemuxerManager;
 
-typedef struct {
-    bool enable;
-    bool isRunning;
-    FormatBufferSetting bufferSetting;
-    MediaHalMutexHandle mutex;
-    MediaHalThreadIdHandle threadId;
-} BufferCacheManager;
-
 typedef struct {
     int16_t programId;
     int16_t videoTrackId;
@@ -66,7 +62,10 @@ typedef struct {
     void *demuxerHdl;
     FileInfo info;
     FormatCallback callback;
-    BufferCacheManager cache;
+#ifdef ENABLE_BUFFER_MANAGER
+    FormatHandle bufferManager;
+    bool enableBuffer;
+#endif
     SelectTrack selectTrack;
     FormatAlbumArtInfo albumInfo;
 } DemuxerContext;
@@ -86,7 +85,7 @@ static int32_t TransToPluginSource(DemuxerSource *demuxerSrc, const FormatSource
         demuxerSrc->offset = formatSrc->offset;
     } else if (formatSrc->type == SOURCE_TYPE_URI) {
         demuxerSrc->type = DEMUXER_SOURCE_TYPE_URI;
-        if (memcpy_s(demuxerSrc->url, PLUGIN_URL_LEN, formatSrc->url, URL_LEN) != EOK) {
+        if (memcpy_s(demuxerSrc->url, URL_LEN, formatSrc->url, URL_LEN) != EOK) {
             MEDIA_HAL_LOGE(MODULE_NAME, "memcpy_s failed");
             return -1;
         }
@@ -130,6 +129,26 @@ void DemuxerManagerDeInit(void)
     MediaHalMutexUnLock(g_demuxerManager.mutex);
 }
 
+#ifdef ENABLE_BUFFER_MANAGER
+static void OpenDemuxerBuffer(DemuxerContext *ctx)
+{
+    if (ctx->source.type != DEMUXER_SOURCE_TYPE_URI) {
+        return;
+    }
+    bool isHttp = (strncasecmp(ctx->source.url, "https://", strlen("https://")) == 0) ||
+        (strncasecmp(ctx->source.url, "http://", strlen("http://")) == 0);
+    if (!isHttp) {
+        return;
+    }
+    ctx->bufferManager = CreateDemuxerBuffer();
+    if (ctx->bufferManager != NULL) {
+        MEDIA_HAL_LOGI(MODULE_NAME, "open demuxer buffer");
+        ctx->enableBuffer = true;
+    }
+    return;
+}
+#endif
+
 int32_t DemuxerCreate(const FormatSource *source, FormatHandle * const handle)
 {
     CHK_NULL_RETURN(handle, -1, "input param null");
@@ -161,8 +180,9 @@ int32_t DemuxerCreate(const FormatSource *source, FormatHandle * const handle)
     for (i = 0; i < SELECTED_IMG_TRACK_NUM_MAX; i++) {
         ctx->selectTrack.imgTrackId[i] = -1;
     }
-    ctx->cache.enable = false;
-    ctx->cache.mutex = MediaHalMutexCreate(&attr);
+#ifdef ENABLE_BUFFER_MANAGER
+    OpenDemuxerBuffer(ctx);
+#endif
     ctx->innerCtx = ctx;
     *handle = (FormatHandle)ctx;
 
@@ -320,7 +340,9 @@ int32_t DemuxerSetBufferConfig(const FormatHandle handle, const FormatBufferSett
         MediaHalMutexUnLock(ctx->mutex);
         return -1;
     }
-    ctx->cache.bufferSetting = *setting;
+#ifdef ENABLE_BUFFER_MANAGER
+    SetBufferConfig(ctx->bufferManager, setting);
+#endif
     MediaHalMutexUnLock(ctx->mutex);
     return 0;
 }
@@ -333,7 +355,9 @@ int32_t DemuxerGetBufferConfig(const FormatHandle handle, FormatBufferSetting *s
     DemuxerContext *ctx = (DemuxerContext *)cur->innerCtx;
 
     MediaHalMutexLock(ctx->mutex);
-    *setting = ctx->cache.bufferSetting;
+#ifdef ENABLE_BUFFER_MANAGER
+    GetBufferConfig(ctx->bufferManager, setting);
+#endif
     MediaHalMutexUnLock(ctx->mutex);
     return 0;
 }
@@ -360,6 +384,15 @@ int32_t DemuxerPrepare(const FormatHandle handle)
         MediaHalMutexUnLock(ctx->mutex);
         return -1;
     }
+#ifdef ENABLE_BUFFER_MANAGER
+    if (ctx->enableBuffer) {
+        int32_t ret = StartBufferThread(ctx->bufferManager, ctx->demuxerHdl, ctx->demuxer, ctx->source.url);
+        if (ret != 0) {
+            DestoryDemuxerBuffer(ctx->bufferManager);
+            ctx->enableBuffer = false;
+        }
+    }
+#endif
     ctx->state = STATE_INIT;
     MEDIA_HAL_LOGD(MODULE_NAME, "func out");
     MediaHalMutexUnLock(ctx->mutex);
@@ -739,8 +772,16 @@ int32_t DemuxerReadFrame(const FormatHandle handle, FormatFrame *frame, int32_t
         MediaHalMutexUnLock(ctx->mutex);
         return -1;
     }
+#ifdef ENABLE_BUFFER_MANAGER
+    if (ctx->enableBuffer) {
+        ret = ReadBufferFrame(ctx->bufferManager, frame);
+    } else {
+#endif
+        ret = ReadFrame(ctx, frame);
+#ifdef ENABLE_BUFFER_MANAGER
+    }
+#endif
 
-    ret = ReadFrame(ctx, frame);
     if ((ret == MEDIA_HAL_OK) && (frame->data != NULL) && (frame->len == 0)) {
         MEDIA_HAL_LOGE(MODULE_NAME, "fmt_read failed frame len:%d", frame->len);
         ret = MEDIA_HAL_ERR;
@@ -763,10 +804,17 @@ int32_t DemuxerFreeFrame(const FormatHandle handle, FormatFrame *frame)
         MediaHalMutexUnLock(ctx->mutex);
         return -1;
     }
-    FormatPacket packet;
-    FormatFrameToPacket(frame, &packet);
-
-    ret = ctx->demuxer->fmt_free(ctx->demuxerHdl, &packet);
+#ifdef ENABLE_BUFFER_MANAGER
+    if (ctx->enableBuffer) {
+        ret = FreeBufferFrame(frame);
+    } else {
+#endif
+        FormatPacket packet;
+        FormatFrameToPacket(frame, &packet);
+        ret = ctx->demuxer->fmt_free(ctx->demuxerHdl, &packet);
+#ifdef ENABLE_BUFFER_MANAGER
+    }
+#endif
     frame->data = NULL;
     frame->len = 0;
     frame->item = NULL;
@@ -791,7 +839,15 @@ int32_t DemuxerSeek(const FormatHandle handle, int32_t streamIndex, int64_t time
         MediaHalMutexUnLock(ctx->mutex);
         return -1;
     }
-    ret = ctx->demuxer->fmt_seek_pts(ctx->demuxerHdl, streamIndex, timeStampUs, mode);
+#ifdef ENABLE_BUFFER_MANAGER
+    if (ctx->enableBuffer) {
+        ret = SeekBuffer(ctx->bufferManager, streamIndex, timeStampUs, mode);
+    } else {
+#endif
+        ret = ctx->demuxer->fmt_seek_pts(ctx->demuxerHdl, streamIndex, timeStampUs, mode);
+#ifdef ENABLE_BUFFER_MANAGER
+    }
+#endif
     MediaHalMutexUnLock(ctx->mutex);
     return ret;
 }
@@ -809,6 +865,11 @@ int32_t DemuxerStop(const FormatHandle handle)
         MediaHalMutexUnLock(ctx->mutex);
         return -1;
     }
+#ifdef ENABLE_BUFFER_MANAGER
+    if (ctx->enableBuffer) {
+        StopBufferThread(ctx->bufferManager);
+    }
+#endif
 
     ctx->state = STATE_STOP;
     MediaHalMutexUnLock(ctx->mutex);
@@ -824,6 +885,12 @@ int32_t DemuxerDestroy(const FormatHandle handle)
     DemuxerContext *ctx = (DemuxerContext *)cur->innerCtx;
 
     MediaHalMutexLock(ctx->mutex);
+#ifdef ENABLE_BUFFER_MANAGER
+    if (ctx->enableBuffer) {
+        DestoryDemuxerBuffer(&(ctx->bufferManager));
+        ctx->enableBuffer = false;
+    }
+#endif
     if (ctx->state != STATE_IDLE) {
         int ret = ctx->demuxer->fmt_close(ctx->demuxerHdl);
         if (ret != MEDIA_HAL_OK) {
@@ -840,7 +907,6 @@ int32_t DemuxerDestroy(const FormatHandle handle)
     FreeFileInfo(ctx);
     MediaHalMutexUnLock(ctx->mutex);
     MediaHalMutexDestroy(&ctx->mutex);
-    MediaHalMutexDestroy(&ctx->cache.mutex);
     ctx->innerCtx = NULL;
     free(ctx);
     MEDIA_HAL_LOGD(MODULE_NAME, "func out");
index f4c8577..7dc11c4 100644 (file)
@@ -18,6 +18,7 @@ extern "C" {
 #endif
 #endif /* __cplusplus */
 
+bool HasM3U8(const char *url);
 void DemuxerPluginManagerInit(void);
 void DemuxerPluginManagerDeInit(void);
 const DemuxerPluginEntry *DemuxerPluginManagerFindPlugin(const DemuxerSource *source, const ProtocolFun *protocol,
index f29c126..fa6c534 100644 (file)
@@ -20,6 +20,9 @@
 #include "hmf_demuxer_plugin.h"
 #include "raw_format.h"
 #endif
+#ifdef ENABLE_FFMPEG_DEMUXER
+#include "ff_demuxer_plugin.h"
+#endif
 
 #ifdef __cplusplus
 #if __cplusplus
@@ -31,7 +34,7 @@ extern "C" {
 #define PLUGIN_PROBE_SCORE_FULL 100
 #define PLUGIN_PROBE_SCORE_HIGH 90
 #define PLUGIN_PROBE_SCORE_LOW 50
-
+#define M3U8_LENGTH 6
 typedef struct {
     const DemuxerPluginEntry *plugin;
     const ProtocolFun *protocol;
@@ -63,6 +66,9 @@ static DemuxerPluginsManager g_demuxerPluginsManager = {
 DemuxerPluginEntry*  g_allDemuxerEntry[] = {
     &g_hmfDemuxerEntry,
     &g_rawFormatDemuxerEntry,
+#ifdef ENABLE_FFMPEG_DEMUXER
+    &g_ffDemuxerEntry,
+#endif
     NULL
 };
 
@@ -159,6 +165,14 @@ void DemuxerPluginManagerDeInit(void)
     return;
 }
 
+bool HasM3U8(const char *url)
+{
+    if (!url) return false;
+    int len = strlen(url);
+    if (len < M3U8_LENGTH) return false;
+    return strstr(url, ".m3u8") != NULL;
+}
+
 static const DemuxerPluginEntry *FindNextDemuxerPlugin(const DemuxerPluginsManager *manager,
     const DemuxerSource *source, const DemuxerPluginEntry *cur, const ProtocolFun *protocol)
 {
@@ -176,6 +190,17 @@ static const DemuxerPluginEntry *FindNextDemuxerPlugin(const DemuxerPluginsManag
     }
     while (p != NULL) {
         const DemuxerPluginEntry *plugin = (const DemuxerPluginEntry *)p->plugin;
+        if (HasM3U8(source->url)) {
+            if (strcmp(plugin->desc.name, "ffmpeg_demuxer") != 0) {
+                p = (PluginEntry *)p->list.next;
+                continue;
+            }
+        } else {
+            if (strcmp(plugin->desc.name, "ffmpeg_demuxer") == 0) {
+                p = (PluginEntry *)p->list.next;
+                continue;
+            }
+        }
         if (plugin != NULL && plugin->fmt_find != NULL) {
             if (plugin->fmt_find(source, protocol) == 0) {
                 selectDemuxer = plugin;
index ce9bef9..96125e9 100644 (file)
@@ -313,6 +313,7 @@ int32_t FormatDemuxerDestroy(const FormatHandle handle)
 
 int32_t FormatMuxerCreate(FormatHandle * const handle, const FormatOutputConfig *outputConfig)
 {
+    FormatInit();
     CHK_NULL_RETURN(g_formatManager.muxerMgrFunc.MuxerCreate, -1, "not support muxer");
 
     return g_formatManager.muxerMgrFunc.MuxerCreate(handle, outputConfig);
index 283d457..8c63101 100644 (file)
@@ -114,7 +114,7 @@ int32_t MuxerCreate(FormatHandle * const handle, const FormatOutputConfig *outpu
     if (outputConfig->type == OUTPUT_TYPE_FD) {
         ctx->cfgParam.fd = outputConfig->fd;
     } else if (outputConfig->type == OUTPUT_TYPE_URI) {
-        if (memcpy_s(ctx->cfgParam.url, PLUGIN_URL_LEN, outputConfig->url, URL_LEN) != EOK) {
+        if (memcpy_s(ctx->cfgParam.url, URL_LEN, outputConfig->url, URL_LEN) != EOK) {
             MEDIA_HAL_LOGE(MODULE_NAME, "memcpy_s failed");
             FreeMuxer(&ctx);
             return MEDIA_HAL_ERR;
@@ -505,18 +505,11 @@ int32_t MuxerSetParameter(const FormatHandle handle, int32_t trackId, const Para
         return MEDIA_HAL_ERR;
     }
     for (int32_t index = 0; index < itemNum; index++) {
-        if (item[index].key == KEY_TYPE_PRE_CACHE) {
-            uint32_t value = item[index].value.s32Value;
-            ret = ctx->plugin->fmt_invoke(ctx->muxer, INVOKE_SET_REC_PRE_CACHE, &value);
-        } else if (item[index].key == KEY_TYPE_SET_SYNC_BUFFER_MSEC) {
-            uint32_t value = item[index].value.s32Value;
-            ret = ctx->plugin->fmt_invoke(ctx->muxer, INVOKE_SET_RINGBUFFER_SIZE, &value);
-        } else if (item[index].key == KEY_TYPE_WRITE_FRONT_COVER) {
-            FrontCover location = {0};
-            location.frameAddr = (uint8_t*)item[index].value.pValue;
-            index++;
-            location.len = item[index].value.s32Value;
-            ret = ctx->plugin->fmt_invoke(ctx->muxer, INVOKE_WRITE_FRONT_COVER, &location);
+        ret = ctx->plugin->fmt_invoke(ctx->muxer, item[index].key,
+            (void *)&item[index].value.u32Value);
+        if (ret != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "set param by key[%d] failed !", item[index].key);
+            break;
         }
     }
     MediaHalMutexUnLock(ctx->mutex);
@@ -526,15 +519,38 @@ int32_t MuxerSetParameter(const FormatHandle handle, int32_t trackId, const Para
 int32_t MuxerGetParameter(const FormatHandle handle, int32_t trackId, ParameterItem *item, int32_t itemNum)
 {
     MEDIA_HAL_UNUSED(trackId);
+    int32_t ret = 0;
     CHK_NULL_RETURN(item, FORMAT_ERR_INVALID_PARAM, "item null");
     const MuxerContext *cur = (const MuxerContext*)handle;
     CHK_HANDLE_VALID(cur);
     MuxerContext *ctx = (MuxerContext *)cur->innerCtx;
-
     MediaHalMutexLock(ctx->mutex);
-    MEDIA_HAL_LOGI(MODULE_NAME, "func in, itemNum:%d", itemNum);
+    if (ctx->state == STATE_IDLE) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "muxer not inited");
+        MediaHalMutexUnLock(ctx->mutex);
+        return MEDIA_HAL_ERR;
+    }
+    if (itemNum > PARAM_MAX_LEN) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "itemNum[%d] is too big, max value:%d", itemNum, PARAM_MAX_LEN);
+        MediaHalMutexUnLock(ctx->mutex);
+        return MEDIA_HAL_ERR;
+    }
+    if (ctx->plugin->fmt_invoke == NULL) {
+        MEDIA_HAL_LOGE(MODULE_NAME, "not support");
+        MediaHalMutexUnLock(ctx->mutex);
+        return MEDIA_HAL_ERR;
+    }
+    for (int32_t index = 0; index < itemNum; index++) {
+        ret = ctx->plugin->fmt_invoke(ctx->muxer, item[index].key,
+            item[index].key == INVOKE_CURRENT_FILE_INFO ? (void *)&item[index].value.pValue :
+            (void *)&item[index].value.u32Value);
+        if (ret != MEDIA_HAL_OK) {
+            MEDIA_HAL_LOGE(MODULE_NAME, "get param by key[%d] failed !", item[index].key);
+            break;
+        }
+    }
     MediaHalMutexUnLock(ctx->mutex);
-    return MEDIA_HAL_OK;
+    return ret;
 }
 
 #endif /* ENABLE_MUXER */
index 130cacc..7f46a62 100644 (file)
 #include "securec.h"
 #include "plugins_manager_common.h"
 #include "media_hal_common.h"
+#ifndef ENABLE_DL_DEMUXER_PLUGIN
+#ifdef ENABLE_PLUGIN_MUXER_WAV
+#include "wav_muxer.h"
+#endif
+#ifdef ENABLE_PLUGIN_MUXER_RAW
+#include "raw_muxer.h"
+#endif
+#ifdef ENABLE_PLUGIN_MUXER_OGG
+#include "ogg_muxer.h"
+#endif
+#endif
 
 #ifdef __cplusplus
 #if __cplusplus
@@ -45,6 +56,21 @@ static MuxerPluginsManager g_muxerPluginsManager = {
     .list = NULL,
 };
 
+MuxerPluginEntry *g_allMuxerEntry[] = {
+#if (defined(CONFIG_SUPPORT_FILESYSTEM) && defined(PRE_ASIC)) || defined(PRE_FPGA)
+#ifdef ENABLE_PLUGIN_MUXER_WAV
+    &g_wavMuxerEntry,
+#endif
+#ifdef ENABLE_PLUGIN_MUXER_RAW
+    &g_rawMuxerEntry,
+#endif
+#ifdef ENABLE_PLUGIN_MUXER_OGG
+    &g_oggMuxerEntry,
+#endif
+#endif
+    NULL
+};
+
 #ifdef ENABLE_DL_MUXER_PLUGIN
 static PluginEntry *GetMuxerPluginEntry(const char *name, int32_t index)
 {
@@ -71,9 +97,18 @@ static PluginEntry *GetMuxerPluginEntry(const char *name, int32_t index)
 static PluginEntry *GetMuxerPluginEntry(const char *name, int32_t index)
 {
     MEDIA_HAL_UNUSED(name);
-    MEDIA_HAL_UNUSED(index);
-    MEDIA_HAL_LOGW(MODULE_NAME, "not support get static muxer plugin entry !");
-    return NULL;
+    if ((uint32_t)index >= sizeof(g_allMuxerEntry) / sizeof(MuxerPluginEntry *)) {
+        return NULL;
+    }
+    const MuxerPluginEntry *entry = g_allMuxerEntry[index];
+    if (entry == NULL) {
+        return NULL;
+    }
+    if (entry->desc.libName) {
+        MEDIA_HAL_LOGI(MODULE_NAME, "add lib :%s!", entry->desc.libName);
+    }
+    PluginEntry *node = PluginFillNode((const PluginDesc *)entry, NULL);
+    return node;
 }
 #endif
 
index d86ed97..523f3b1 100644 (file)
Binary files a/code/sdk/middleware/services/media/hal_release/liteos/format/libs/js/libhmf_demuxer.a and b/code/sdk/middleware/services/media/hal_release/liteos/format/libs/js/libhmf_demuxer.a differ
index 04eaa67..b548ef9 100644 (file)
Binary files a/code/sdk/middleware/services/media/hal_release/liteos/format/libs/js/libplugin_demuxer_hmf.a and b/code/sdk/middleware/services/media/hal_release/liteos/format/libs/js/libplugin_demuxer_hmf.a differ
index d2056ed..5b24763 100644 (file)
Binary files a/code/sdk/middleware/services/media/hal_release/liteos/format/libs/js/libplugin_demuxer_mjpeg.a and b/code/sdk/middleware/services/media/hal_release/liteos/format/libs/js/libplugin_demuxer_mjpeg.a differ
index 6627224..34bfa34 100644 (file)
Binary files a/code/sdk/middleware/services/media/hal_release/liteos/format/libs/js/libplugin_protocol_https.a and b/code/sdk/middleware/services/media/hal_release/liteos/format/libs/js/libplugin_protocol_https.a differ
index b2ef79e..b15b336 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/vfs/brandy-auto-ota-cli/libx_vfs_private.a and b/code/sdk/middleware/utils/fs/vfs/brandy-auto-ota-cli/libx_vfs_private.a differ
index 6233af2..6f9f6bd 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/vfs/brandy-auto-ota-ser/libx_vfs_private.a and b/code/sdk/middleware/utils/fs/vfs/brandy-auto-ota-ser/libx_vfs_private.a differ
index ef8c37d..7689d31 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/vfs/brandy-native-js-r/libx_vfs_private.a and b/code/sdk/middleware/utils/fs/vfs/brandy-native-js-r/libx_vfs_private.a differ
index 1c08fcb..ff74eab 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/vfs/brandy-native-js/libx_vfs_private.a and b/code/sdk/middleware/utils/fs/vfs/brandy-native-js/libx_vfs_private.a differ
index 65e622b..270e16b 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/vfs/brandy-target1-r/libx_vfs_private.a and b/code/sdk/middleware/utils/fs/vfs/brandy-target1-r/libx_vfs_private.a differ
index c42993a..2f5f092 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/vfs/brandy-target1/libx_vfs_private.a and b/code/sdk/middleware/utils/fs/vfs/brandy-target1/libx_vfs_private.a differ
index 4f46e17..fc9c200 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/vfs/brandy-target3-r/libx_vfs_private.a and b/code/sdk/middleware/utils/fs/vfs/brandy-target3-r/libx_vfs_private.a differ
index 9983557..9546967 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/vfs/brandy-target3/libx_vfs_private.a and b/code/sdk/middleware/utils/fs/vfs/brandy-target3/libx_vfs_private.a differ
index 6517520..d3b56d4 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/vfs/brandy-target4-r/libx_vfs_private.a and b/code/sdk/middleware/utils/fs/vfs/brandy-target4-r/libx_vfs_private.a differ
index cd04a36..c3c4e9e 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/vfs/brandy-target4/libx_vfs_private.a and b/code/sdk/middleware/utils/fs/vfs/brandy-target4/libx_vfs_private.a differ
index 11e2d98..b8644cb 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/vfs/brandy-target5-r/libx_vfs_private.a and b/code/sdk/middleware/utils/fs/vfs/brandy-target5-r/libx_vfs_private.a differ
index 8bdeccc..9a93c4f 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/vfs/brandy-target5/libx_vfs_private.a and b/code/sdk/middleware/utils/fs/vfs/brandy-target5/libx_vfs_private.a differ
index a01bd75..65a14c8 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/vfs/brandy-xts-r/libx_vfs_private.a and b/code/sdk/middleware/utils/fs/vfs/brandy-xts-r/libx_vfs_private.a differ
index 08319d3..eb82fb3 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/vfs/brandy-xts/libx_vfs_private.a and b/code/sdk/middleware/utils/fs/vfs/brandy-xts/libx_vfs_private.a differ
index 2338692..32fdfa7 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/vfs/testsuite-brandy-sdk/libx_vfs_private.a and b/code/sdk/middleware/utils/fs/vfs/testsuite-brandy-sdk/libx_vfs_private.a differ
index f6822a1..04fbcc4 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/yaffs2/brandy-auto-ota-cli/libfs_yaffs2.a and b/code/sdk/middleware/utils/fs/yaffs2/brandy-auto-ota-cli/libfs_yaffs2.a differ
index 13bf834..f6f3f25 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/yaffs2/brandy-auto-ota-ser/libfs_yaffs2.a and b/code/sdk/middleware/utils/fs/yaffs2/brandy-auto-ota-ser/libfs_yaffs2.a differ
index 00beb36..6b9dd54 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/yaffs2/brandy-native-js-r/libfs_yaffs2.a and b/code/sdk/middleware/utils/fs/yaffs2/brandy-native-js-r/libfs_yaffs2.a differ
index 50e244a..2a44ced 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/yaffs2/brandy-native-js/libfs_yaffs2.a and b/code/sdk/middleware/utils/fs/yaffs2/brandy-native-js/libfs_yaffs2.a differ
index c900068..f92fb82 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/yaffs2/brandy-target1-r/libfs_yaffs2.a and b/code/sdk/middleware/utils/fs/yaffs2/brandy-target1-r/libfs_yaffs2.a differ
index 1cf1ddc..b7343a7 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/yaffs2/brandy-target1/libfs_yaffs2.a and b/code/sdk/middleware/utils/fs/yaffs2/brandy-target1/libfs_yaffs2.a differ
index 395874a..e2cd6fa 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/yaffs2/brandy-target3-r/libfs_yaffs2.a and b/code/sdk/middleware/utils/fs/yaffs2/brandy-target3-r/libfs_yaffs2.a differ
index 51c1921..a2cbb9e 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/yaffs2/brandy-target3/libfs_yaffs2.a and b/code/sdk/middleware/utils/fs/yaffs2/brandy-target3/libfs_yaffs2.a differ
index 70e8eb4..e4a9508 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/yaffs2/brandy-target4-r/libfs_yaffs2.a and b/code/sdk/middleware/utils/fs/yaffs2/brandy-target4-r/libfs_yaffs2.a differ
index 862959c..0cde8d8 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/yaffs2/brandy-target4/libfs_yaffs2.a and b/code/sdk/middleware/utils/fs/yaffs2/brandy-target4/libfs_yaffs2.a differ
index 1c53144..1a98924 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/yaffs2/brandy-target5-r/libfs_yaffs2.a and b/code/sdk/middleware/utils/fs/yaffs2/brandy-target5-r/libfs_yaffs2.a differ
index 58dec4a..b922dc7 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/yaffs2/brandy-target5/libfs_yaffs2.a and b/code/sdk/middleware/utils/fs/yaffs2/brandy-target5/libfs_yaffs2.a differ
index 89122da..5afdd2b 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/yaffs2/brandy-xts-r/libfs_yaffs2.a and b/code/sdk/middleware/utils/fs/yaffs2/brandy-xts-r/libfs_yaffs2.a differ
index faf814e..403e6b8 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/yaffs2/brandy-xts/libfs_yaffs2.a and b/code/sdk/middleware/utils/fs/yaffs2/brandy-xts/libfs_yaffs2.a differ
index a64241e..bcadde2 100644 (file)
Binary files a/code/sdk/middleware/utils/fs/yaffs2/testsuite-brandy-sdk/libfs_yaffs2.a and b/code/sdk/middleware/utils/fs/yaffs2/testsuite-brandy-sdk/libfs_yaffs2.a differ
index d771359..ae7dd74 100644 (file)
@@ -1482,9 +1482,6 @@ static int32_t RunAIVoice(AIVoiceContext *context)
                         LOS_Msleep(1000);
                         #endif
                     }
-                                        // struct timespec ts;
-                    // AudioStreamGetTimestamp(&ts);
-                    // printf("AudioStreamGetTimestamp %d\r\n",ts.tv_sec);
                     // 释放消息数据内存
                     free(msg.data);
                 }
index b2fe8f0..4ec027d 100644 (file)
@@ -62,7 +62,7 @@
 #include "alipay_feature.h"
 #endif
 
-#define SUPPORT_NV
+#define SUPPORT_NV 
 
 #ifdef SUPPORT_NV
 #include "nv.h"
@@ -142,12 +142,6 @@ extern time_t __tm_to_secs(const struct tm *tm);
 #include "lcd_common.h"
 #include "input_app.h"
 
-
-#ifdef BOARD_LEINIAO
-#include "PPPTestViewC.h"
-#include "audio_capture_wrapper.h"
-#endif
-
 static uint8_t factory_test_flag = 0;
 
 errcode_t uapi_create_osThread_custom(app_task_definition_t *task_cfg)
@@ -607,89 +601,13 @@ void a5133_demo_msg_change_callback(void)
         a5133_demo_msg_send_index = 0;
 }
 
-#ifdef BOARD_LEINIAO
-
-// static uint8_t k2_flag = 0;
-// static uint8_t k3_flag = 0;
-
-#define KEY2 S_AGPIO_L12
-#define KEY3 S_AGPIO_L28
-
-static void key2_enter_ppp_testView_callback(void)
-{
-    printf("111 key2_enter_ppp_testView_callback\n");
-
-    if(uapi_gpio_get_val(KEY3) == GPIO_LEVEL_LOW)
-        start_ppp_test_view();
-
-    // k2_flag = 1;
-    // if(k3_flag && k2_flag)
-    // {
-    //     printf("222 key2_enter_ppp_testView_callback\n");
-    //     start_ppp_test_view();
-    //     k2_flag = 0;
-    //     k3_flag = 0;
-    // }
-}
-
-static void key3_enter_ppp_testView_callback(void)
-{
-    printf("111 key3_enter_ppp_testView_callback\n");
-
-    if(uapi_gpio_get_val(KEY2) == GPIO_LEVEL_LOW)
-        start_ppp_test_view();
-    // k3_flag = 1;
-    // if(k3_flag && k2_flag)
-    // {
-    //     printf("222 key3_enter_ppp_testView_callback\n");
-    //     start_ppp_test_view();
-    //     k2_flag = 0;
-    //     k3_flag = 0;
-    // }
-}
-
-#endif
-
 void startup_post_init_task(void)
 {
     uint8_t day = 0;
     time_t rawtime;
     struct tm* timeinfo;
-
     PRINT("startup_post_init_task !\r\n");
-#ifdef BOARD_LEINIAO
-
-    uapi_get_file_data(FACTORY_TEST_MODE_PATH,&factory_test_flag,1);
-
-    char path[40] = {0};
-    uint16_t delay_time = 1500;
-    if(factory_test_flag == 1)
-    {
-        snprintf(path, 40, "/user/res/music/FactoryMode.mp3");
-        delay_time = 2000;
-    }
-    else
-    {
-        //snprintf(path, 40, "/user/res/music/PowerOn.mp3");
-        uapi_custom_set_uart_rx_enable_flag(false);
-    }
-    custom_play_audio(path,100);
-    LOS_Msleep(delay_time);
-    custom_stop_play_audio();
 
-    if(factory_test_flag)
-        factory_set_recoder_streamType();
-    else
-        uapi_ln_http_server_init();
-
-#ifdef SUPPORT_PPP_SERVICE
-    uint32_t baudrate = get_ppp_baudrate_from_config_model();   
-    if(baudrate != 0)
-        set_ppp_baudrate(baudrate);
-    ppp_env_init();
-#endif
-
-#endif
 #ifdef SUPPORT_CYWEE_SERVICE
     do_cywee_service_check_msg(CYWEE_SERVICE_CMD_TIME_SYNC,NULL);
 #endif
@@ -697,9 +615,8 @@ void startup_post_init_task(void)
     {
         stop_custom_ble_service();
     }
-#ifdef BOARD_LEINIAO
+
     cm_initScreenBrightness();
-#endif
     // cm_initializeScreenDuration();
     cm_initializeRaiseToWake();
     // cm_initializeVibrationModel();
@@ -734,10 +651,7 @@ void startup_post_init_task(void)
 #endif
 
 #endif
-#ifndef BOARD_LEINIAO
     ble_SOS_data_init();
-#endif
-
 #ifdef SUPPORT_CAT1_SERVICE
     // up_report_timer();
 #endif
@@ -763,8 +677,6 @@ void startup_post_init_task(void)
     
 #ifdef SUPPORT_CAT1_SERVICE
 
-#ifndef BOARD_LEINIAO
-
 if ( cm_poweron_cat1_on_bootup_flag() )
 {
     PRINT("PowerOn Cat1 !\r\n");
@@ -773,7 +685,6 @@ if ( cm_poweron_cat1_on_bootup_flag() )
     PRINT("PowerOff Cat1 !\r\n");
     uapi_set4GCapability(false);
 }
-#endif
 #else
 
 // #ifdef SUPPORT_PPP_SERVICE
@@ -799,31 +710,6 @@ if (custom_get_factory_test_flag() != 0 ) {
 #elif defined(A5133_DEMO_CLIENT)
     send_a5133_cmd_msg(A5133_SERVICE_CMD_TYPE_RUN_SLAVE);
 #endif
-
-#ifdef BOARD_LEINIAO
-
-    // uapi_button_unregister_event_cb(BUTTON2_LONGPRESS_5S_OVER);
-    // uapi_button_unregister_event_cb(BUTTON3_LONGPRESS_5S_OVER);
-
-    ret = uapi_button_register_event_cb(key2_enter_ppp_testView_callback, BUTTON2_LONGPRESS_5S_OVER);
-    if (ret != ERRCODE_SUCC)
-        printf("key2_enter_ppp_testView_callback error, ret = %d \n", ret);
-    else
-        printf("key2_enter_ppp_testView_callback succed\n");
-
-    ret = uapi_button_register_event_cb(key3_enter_ppp_testView_callback, BUTTON3_LONGPRESS_5S_OVER);
-    if (ret != ERRCODE_SUCC)
-        printf("key3_enter_ppp_testView_callback error, ret = %d\n", ret);
-    else
-        printf("key3_enter_ppp_testView_callback succed\n");
-
-
-    if(factory_test_flag == 2)
-    {
-        custom_aging_test_init();
-    }    
-
-#endif
 }
     
 void startup_post_init(void)
@@ -3047,11 +2933,7 @@ void uapi_cywee_time_sync(void)
 
 void uapi_cywee_get_id(uint8_t *id)
 {
-#ifdef BOARD_LEINIAO
-    custom_i2c_read_regs(0x62,0x01,1,id,1,I2C_BUS_2);
-#else
     custom_i2c_read_regs(0x19,0x0FU,1,id,1,I2C_BUS_2);
-#endif
 }
 
 
@@ -4813,32 +4695,7 @@ static void aging_task(void)
         int i = 0;
         uapi_set_screen_on_api();
         ScreenAlwaysOnCtr(1);
-        #ifdef BOARD_LEINIAO
-        start_lcd_test_view();
-        printf("fac:LCDTEST ATCMD Enter LCD test interface (LcdTestView)\n");
-        printf("fac:Use AT^LCDTEST=3-8 to change colors: 3=Green, 4=Blue, 5=Yellow, 6=Red, 7=White, 8=Black\n");
-        do
-        {
-            if(aging_t.flag != 1)
-            {
-                uapi_save_file_data("user/userdata/aging_test.bin",&aging_t,sizeof(custom_aging_t),"wb");
-                return;
-            }
-            uapi_get_timestampe_ss(&current_time);
-            // uapi_get_timestampe_ss(&enter_time);
-            set_lcd_test_color(i);
-            i++;
-            i = i%5;            
-            LOS_Msleep(2000);
-            // uapi_get_timestampe_ss(&age_time);
-            // PRINT("current_time - enter_time[%d]\n",current_time -  enter_time);
-        }while(current_time - enter_time <= 2 * 60);
-        // for(int i = 0; i < 5; i++)
-        // {
-        //     LOS_Msleep(2000);
-        //     set_lcd_test_color(i);
-        // }
-        #else
+        
         uint8_t lcd_cmd = 1;
         do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_TYPE_LCD_TEST, &lcd_cmd, sizeof(lcd_cmd));
         printf("fac:LCDTEST ATCMD Enter LCD test interface\n");
@@ -4848,19 +4705,12 @@ static void aging_task(void)
             LOS_Msleep(2000);
             do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_TYPE_LCD_COLOR_TEST, &i, 1);
         }
-        #endif
 
         ScreenAlwaysOnCtr(0);
-        // 退出LCD测试界面
-#ifdef BOARD_LEINIAO
-        stop_lcd_test_view();
-        printf("fac:LCDTEST ATCMD Exit LCD test interface (LcdTestView)\n");
-#else
         // 其他板:使用原有的消息机制
         lcd_cmd = 0;
         do_custom_cmd_service_check_msg(CUSTOM_CMD_MSG_TYPE_LCD_TEST, &lcd_cmd, sizeof(lcd_cmd));
         printf("fac:LCDTEST ATCMD Exit LCD test interface\n");
-#endif
 
 /*********************充电 老化测试*****************************/
         // if(!get_charge_stat())
index 5fbec6b..7f5c82e 100644 (file)
@@ -425,20 +425,6 @@ bool uapi_custom_uart_rx_enable_flag(void);
 */
 void uapi_custom_set_uart_rx_enable_flag(bool enable_uart);
 
-
-
-/**
- * param direction 0 = X , 1 = Y
-*/
-void enable_drag(uint8_t direction, uint8_t enable);
-
-/**
- * param direction 0 = X , 1 = Y
-*/
-void set_drag_limit(uint8_t direction, uint16_t limit);
-/**
- * param direction 0 = X , 1 = Y
-*/
 uint16_t get_drag_limit(uint8_t direction);
 
 errcode_t touch_resume_in_cmd_queue(void);
index cdc203b..bdfdcf0 100644 (file)
@@ -1531,13 +1531,6 @@ static uint32_t enabledrag(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
     }
     uint8_t direction = atol((char*)argv[0]);
     uint8_t enable = atol((char*)argv[1]);
-
-    #ifdef FD230_650
-    // enable_drag(direction,enable);
-    // uint8_t limit=get_drag_limit(direction);
-    // wstp_print("%s %s , current limit %d\r\n",enable==1?"enable":"disable",direction==0?"x":"y",limit);
-    #endif
-
     return ERRCODE_SUCC;
 }
 
@@ -1562,13 +1555,6 @@ static uint32_t setdraglimit(uint8_t *para, uint32_t paraLen, char *strCommonCmd
     }
     uint8_t direction = atol((char*)argv[0]);
     uint8_t value = atol((char*)argv[1]);
-
-    #ifdef FD230_650
-    // set_drag_limit(direction,value);
-    // uint8_t limit=get_drag_limit(direction);
-    // wstp_print("set drag  %s limit %d (current limit %d) \r\n",direction==0?"x":"y",value,limit);
-    #endif
-
     return ERRCODE_SUCC;
 }
 static uint32_t leantest(uint8_t *para, uint32_t paraLen, char *strCommonCmd)