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
/* -------------------------------------------------------------------------- */
NotificationManager::GetInstance()->RegisterNotifyCleanupFunction(FreeDebugOutputMainView);
/* -------------------------------------------------------------------------- */
- enable_drag(0, 1);
- enable_drag(1, 1);
}
return DebugGroupView;
}
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;
}
}
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
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,
APPLISTMODEL_CPP,
APPLISTPRESENTER_CPP,
APPLISTVIEW_CPP,
- BLOODBANDOFFVIEW_CPP,
- BLOODOXYGENPRESENTER_CPP,
- BLOODOXYGENVIEW_CPP,
BLUETOOTHCASELISTADAPTER_CPP,
BLUETOOTHDEVICECASELISTADAPTER_CPP,
BLUETOOTHDEVICELISTVIEW_CPP,
TIPSCONNFAILMESSAGEVIEW_CPP,
TIPSFAILMESSAGEVIEW_CPP,
TIPSSUCCMESSAGEVIEW_CPP,
- CALLERLOGMODEL_CPP,
- CALLERLOGPRESENTER_CPP,
- CALLERLOGVIEW_CPP,
MAINCLOCKVIEW_CPP,
AMBIENTCLOCKVIEW_CPP,
AODVIEW_CPP,
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,
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,
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,
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;
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,
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,
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,
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
RAW_FORMAT_C,
SILK_DEMUXER_C,
DEMUXER_MANAGER_C,
+ DEMUXER_BUFFER_C,
DECRYPT_DATA_C,
DEMUXER_PLUGINS_MANAGER_C,
FORMAT_COMMON_C,
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,
"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]]
}
}
}
"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]]
}
}
}
#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
-/*
- * @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 */
#endif /* __KEY_ID_H__ */
-
\ No newline at end of file
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); }
#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
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 {
--- /dev/null
+#===============================================================================
+# @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()
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**
+ * 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
--- /dev/null
+/**
+ * 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
--- /dev/null
+/**
+ * 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
{\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
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
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
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
}\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
}\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
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
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
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
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
#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
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
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
}\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
/**
* @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
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);
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
${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
${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
${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
${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
)\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
--- /dev/null
+/*
+ * 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
#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"
*/
void Dump();
+ void EnterAod();
+ void ExitAod();
+ bool IsInAod() const
+ {
+ return isInAod_;
+ }
+
private:
struct ImageNode;
struct MultiImageInfo {
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
#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
*/\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
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
--- /dev/null
+/*
+ * 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
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
*/
void OnDraw(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea) override;
+ void ReMeasure() override;
+
private:
struct DrawCmd : public HeapBase {
PaintExt* paint;
--- /dev/null
+/*
+ * 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
+/**
+ * @}
+ */
*/\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
*/
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;
bool isNeedClip_ = false;
std::shared_ptr<bool> exists_;
bool waitProcessRes_ = false;
+ float scale_ = 1.0f;
void RemoveAllInner(UISwipeView& view);
void ProcessRes(bool loadAdjacent = true);
--- /dev/null
+/*\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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
float rotate_ = 0.0f;
};
+ void BlitKaleidoscopeImg(BufferInfo& gfxDstBuffer, const Rect& invalidatedArea);
+
#if ENABLE_ROTATE_INPUT
float factor_ = 1.0f;
#endif
KaleidoscopeUtils kaleidoscope_;
RotateCallback callback_;
Animator* animator_ = nullptr;
+ bool directFb_ = false;
};
}
#endif
~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;
std::string GetGuiInfo() const override;
+ friend void GetYuv2RgbTimeByUILiteSurfaceView(UILiteSurfaceView*);
+
private:
UILiteSurfaceView(const UILiteSurfaceView&) = delete;
UILiteSurfaceView &operator=(const UILiteSurfaceView&) = delete;
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_;
*/
uint32_t GetTime();
- /**
- * @brief Specifies whether to repeat particle animation.
- */
- void SetRepeat(bool repeat);
-
/**
* @brief Returns whether to repeat particle animation.
*/
--- /dev/null
+/*\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
--- /dev/null
+/*
+ * 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
~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;
--- /dev/null
+/*
+ * 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
~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
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
}\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
* @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
* @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
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
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
~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;
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
#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
#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
#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)
#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 {
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() {}
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();
}
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);
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_;
}
delete []rect;
rect = nullptr;
}
+ if (attr != nullptr) {
+ delete []attr;
+ attr = nullptr;
+ }
--frmCnt_;
}
uint64_t totalTime;
int pathCnt;
int drawCount;
Rect drawRect;
+ bool isSram;
FrameTrace *trace;
Rect *rect;
+ FrameTracePathAttr *attr;
};
struct TaskRecord {
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;
bool eventRecording_ = false;
bool taskRecording_ = false;
FrameTraceType pathType_ = FrameTraceType::HW_DRAW_PATH;
+ FrameTracePathAttr pathAttr_ = FrameTracePathAttr::NONE;
};
} // OHOS
#endif // GRAPHIC_LITE_DFX_FRAME_TRACE_H
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
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
LottEllipse();
virtual ~LottEllipse();
- void Update(LottShape* parent, float frameNo) override;
+ bool Update(float frameNo) override;
bool GetPathData(Path& path) override;
LottPositionProp position_;
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) {};
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)
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;
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;
uint32_t fillIndex = 0;
uint32_t strokeindex = 0;
uint32_t transIndex = 0;
+ uint32_t trimIndex = 0;
Graphic::Vector<uint32_t> shapes;
};
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);
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
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
void UpdateValue(float frameNo);\r
\r
float value_;\r
+ bool isUpdateValue_ = false;\r
\r
private:\r
Graphic::Vector<LottFloatFrame*>* frames_;\r
void UpdateValue(float frameNo);\r
\r
int value_;\r
+ bool isUpdateValue_ = false;\r
\r
private:\r
Graphic::Vector<LottIntegerFrame*>* frames_;\r
void UpdateValue(float frameNo);\r
\r
Color32 value_;\r
+ bool isUpdateValue_ = false;\r
\r
private:\r
Graphic::Vector<LottColorFrame*>* frames_;\r
void UpdateValue(float frameNo);\r
\r
Vector2<float> value_;\r
+ bool isUpdateValue_ = false;\r
\r
private:\r
Graphic::Vector<LottVectorFrame*>* frames_;\r
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
void PrepareLength();\r
\r
Vector2<float> value_;\r
+ bool isUpdateValue_ = false;\r
\r
private:\r
Graphic::Vector<LottPositionFrame*>* frames_;\r
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
LottRect();
virtual ~LottRect();
- void Update(LottShape* parent, float frameNo) override;
+ bool Update(float frameNo) override;
bool GetPathData(Path& path) override;
LottPositionProp position_;
\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
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
#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
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
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
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
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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
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.
*/
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 {
LottAnimCb() {}
virtual ~LottAnimCb() {}
void Callback(UIView* view) override;
-
+ void OnStop(UIView& view) override;
void SetEndValue(float value)
{
endValue_ = value;
friend class LottAnimCb;
+ bool repeat_ = false;
LottAnimCb lottAnimCb_;
Animator animator_;
LottComp* lottComp_ = nullptr;
\r
void ForceRefreshImmediately();\r
\r
+ void ForceRefreshMore();\r
+\r
static void NativeMainThread(void* args);\r
static void RtcEventThread(void* args);\r
\r
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
});\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
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)
--- /dev/null
+/*
+ * 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
* 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),
ClearBuffers();
}
+void LiteSurface::AsyncClearBuffers()
+{
+ std::weak_ptr<bool> wp = waitPrepareBuffer_;
+ GraphicService::GetInstance()->PostGraphicEvent([this, wp]() {
+ if (!wp.expired()) {
+ ClearBuffers();
+ }
+ });
+}
+
void LiteSurface::ClearBuffers()
{
lock_.Lock();
}
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_);
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:
--- /dev/null
+/*
+ * 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;
+}
+}
--- /dev/null
+/*
+ * 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
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
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);
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
#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
++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
#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
\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
GRAPHIC_LOGE("DrawHand failed. UpdateImageInfoIfNecessary failed.");
return;
}
+ } else {
+ return;
}
DrawHandImage(gfxDstBuffer, current, invalidatedArea, hand);
} else {
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
&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
~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)
return imgView_;
}
+ UIViewType GetViewType() const override
+ {
+ return UI_CARD_CONTAINER;
+ }
+
void PreLoad(void);
void UnLoad(void);
#if ENABLE_ROTATE_INPUT
bool OnRotateEvent(const RotateEvent& event) override;
#endif
+ void ClipImg(ImageInfo &img, float scale);
};
}
#endif
#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"
char* g_filePath = nullptr;
UIView* g_capView = nullptr;
Rect g_cropRect{0, 0, 0, 0};
+uint8_t *g_traceuiBuf = nullptr;
void DumpViewId(UIView* view)
{
}
}
+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();
}
}
-#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)
{
void DebugGetAllWatchFaceInfo(int argc, char *argv[])
{
- #ifdef FD230_650_0723
GraphicService::GetInstance()->PostGraphicEvent([]() {
watch_dial_info *info = nullptr;
uint8_t num = 0;
}
free(info);
});
- #endif
}
void DebugGetWatchFaceInfo(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;
return;
}
printf("Succuss to get file %s, uuid %u\n", path.c_str(), uuid);
- #endif
}
#endif // defined (SUPPORT_DIAL_DEBUG)
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 {
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},
{"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
};
{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"},
{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"},
};
#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;
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;
}
void DfxFrameTrace::FrameTraceEnd(FrameTraceType type, const Rect *rect)
{
+ TRACEUI_END();
if (!CanTrace()) {
return;
}
if (type == FrameTraceType::HW_DRAW_PATH) {
type = pathType_;
pathType_ = FrameTraceType::HW_DRAW_PATH;
+ pathAttr_ = FrameTracePathAttr::NONE;
}
RecordEnd(type, rect);
}
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_);
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)
return;
}
- if (events_ == nullptr || !eventRecording_ || !taskRecording_) {
+ if (events_ == nullptr || !eventRecording_ || !taskRecording_ || drawCount_ <= 0) {
return;
}
EventRecord &curEvt = *tailEvt_;
void DfxFrameTrace::ClearState()
{
- memset_s(trace_, sizeof(trace_), 0, sizeof(trace_));
drawRect_ = Rect();
drawCount_ = 0;
drawStack_ = 0;
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
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];
}
}
}
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());
}
}
void DfxFrameTrace::EventTraceStart()
{
+ TRACEUI_BEGIN("GraphicEvent");
if (traceCount_ <= 0) {
return;
}
void DfxFrameTrace::EventTraceEnd()
{
+ TRACEUI_END();
if (events_ == nullptr || !eventRecording_) {
return;
}
void DfxFrameTrace::TaskTraceStart()
{
+ TRACEUI_BEGIN("TaskExecute");
if (events_ == nullptr || !eventRecording_) {
return;
}
void DfxFrameTrace::TaskTraceEnd()
{
+ TRACEUI_END();
if (events_ == nullptr || !eventRecording_ || !taskRecording_) {
return;
}
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;
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_);
}
static FPSTask *GetInstance()
{
static FPSTask instance;
- instance.Init();
return &instance;
}
void PrintFPS(uint16_t duration = 0);
private:
+ FPSTask();
+ ~FPSTask() {}
UILabel *fpsLabel_ = nullptr;
bool isFirstShow_ = true;
bool isAdded_ = false;
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
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();
}
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;
+}
}
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
#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 {
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;
}
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;
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;
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) {
}
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)
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
#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 {
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() {}
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
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,
}
#endif
+
private:
LiteMGfxEngine() {}
virtual ~LiteMGfxEngine()
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,
#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;
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);
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++) {
*/
#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"
#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"
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;
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
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
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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
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;
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
#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"
GRAPHIC_LOGE("flush failed.");
}
exitUlps_ = false;
+ if (pendingSurface_ != nullptr) {
+ pendingSurface_->ClearBuffers();
+ pendingSurface_ = nullptr;
+ }
return;
}
uint8_t currentBufferIndex = currentBufferId_[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.");
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;
default:
GRAPHIC_LOGE("unsupported compress mode: %d, just return 0.", cmpMode);
return 0;
- break;
}
return size;
}
#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);
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;
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;
#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 {
*/
bool SwapBuffer(uint8_t layerId);
+ void SetPendingReleaseSurface(std::shared_ptr<LiteSurface> surface);
+
struct Layer {
uint32_t layerHdl;
LayerInfo layerInfo;
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
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)
${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}
)
*/
#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()
{
});
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;
+}
/*
- * 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
int SampleUi(void);
+/*
+ ¹¦ÄÜÃèÊö : Æô¶¯Ö¸¶¨ÓÃÀý
+ ²ÎÊýÄÚÈÝ : ²ÎÊýΪÓÃÀýÃû³Æ
+*/
+int StartCaseUi(const char* testCaseId);
+
#ifdef __cplusplus
}
#endif
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
/*
- * 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"
/*
- * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
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;
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
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_) {
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;
#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"
void UiKitChartPillarTestEnableReverse002();
void UiKitChartPillarTestSetAxisLineColor003();
void UiKitChartPillarTestSetAxisLineVisible004();
+ void UiKitChartPillarTestSwitchCap005();
+ void UiKitChartPillarTestSwitchPillarType006();
private:
void SetLastPos(UIView* view);
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;
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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
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
#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;
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},
{CardId::COMPASS, &UITestClockDial::InitCompassPage},
};
+static const char* g_transitionMapper[] = {
+ "1.推拉",
+ "2.翻页",
+ "3.立方体",
+ "4.卡片",
+};
+
void SwipeListener::OnSwipe(UISwipeView& view)
{
UNUSED(view);
g_pMainView = this;
}
-UITestClockDial *UITestClockDial::GetInstance(void)
+UITestClockDial* UITestClockDial::GetInstance(void)
{
return g_pMainView;
}
}
if (callback == nullptr) {
- callback = new ZoomEffect();
+ SwitchFlipTypeMode(g_modelIndex);
if (callback == nullptr) {
delete mainSwipeGroup;
mainSwipeGroup = nullptr;
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();
delete callback;
callback = nullptr;
}
+
+ if (controlButton != nullptr) {
+ delete controlButton;
+ controlButton = nullptr;
+ }
}
const UIView* UITestClockDial::GetTestView()
}
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;
}
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)
GRAPHIC_LOGD("UITestClockDial::PullViewLoad::Pull View Load complete\n");
}
-AppGroupView *UITestClockDial::InitWatchFacePage(void)
+AppGroupView* UITestClockDial::InitWatchFacePage(void)
{
mainClockView = new MainClockView();
if (mainClockView == nullptr) {
return mainClockView;
}
-AppGroupView *UITestClockDial::InitHeartRatePage(void)
+AppGroupView* UITestClockDial::InitHeartRatePage(void)
{
heartRateView = new HeartRateView();
if (heartRateView == nullptr) {
return heartRateView;
}
-AppGroupView *UITestClockDial::InitActivityPage(void)
+AppGroupView* UITestClockDial::InitActivityPage(void)
{
activityWeekView = new ActivityWeekView();
if (activityWeekView == nullptr) {
return activityWeekView;
}
-AppGroupView *UITestClockDial::InitCompassPage(void)
+AppGroupView* UITestClockDial::InitCompassPage(void)
{
compassControlView = new CompassControlView();
if (compassControlView == nullptr) {
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++) {
heartRateView->HeartbeatImageAnimatorStop();
}
}
-}
+} // namespace OHOS
#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"
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 {}
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);
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);
};
}
} 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();
}
}
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
}
if (pageIndex > 1) {
pageIndex = 0;
}
+#ifndef _WIN32
} else if (&view == video_) {
static uint16_t pageIndexFromCenter = 0;
container_->SetVerCurrentPage(pageIndexFromCenter);
} else {
pageIndexFromCenter = 0;
}
+#endif
}
return true;
}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
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");
scaleBtn_ = nullptr;
rotateBtn_ = nullptr;
matrixBtn_ = nullptr;
+ paddingBtn_ = nullptr;
matrixIndex_ = -1;
img_ = nullptr;
ImageCacheManager::GetInstance().UnloadSingleRes(RES_PATH"haha.bin");
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;
}
UILabelButton* scaleBtn_ = nullptr;
UILabelButton* rotateBtn_ = nullptr;
UILabelButton* matrixBtn_ = nullptr;
+ UILabelButton* paddingBtn_ = nullptr;
UIScrollView* container_ = nullptr;
SectorAnimatorCallback *sectorCallBack_ = nullptr;
Animator *sectorAnimator_ = nullptr;
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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());
+}
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
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()
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
}
/*
- * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
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);
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()
container_ = nullptr;
imgInfo_ = nullptr;
img_ = nullptr;
+ switchBtn_ = nullptr;
if (kaleidoscopeUtils_ != nullptr) {
delete kaleidoscopeUtils_;
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_;
#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 {
KaleidoscopeUtils* kaleidoscopeUtils_;
};
+ void InitKaleidoscopeView();
+ void InitKaleidoscopeImg();
+
UIViewGroup* container_ = nullptr;
ImageInfo* imgInfo_ = nullptr;
+ UILabelButton* switchBtn_ = nullptr;
UIKaleidoscopeView* kaleidoscope_ = nullptr;
#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
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);
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
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
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
#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
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
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
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
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
}\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
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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
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
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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
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;
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+
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
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
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
container_->Add(slipflow_);\r
container_->Add(label_);\r
container_->Add(slipUpNoticelabel_);\r
- InitButtonGroup();\r
}\r
}\r
\r
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
\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
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
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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
}\r
\r
if (videoPlay_ != nullptr) {\r
+ videoPlay_->StopVideoPlay();\r
delete videoPlay_;\r
videoPlay_ = nullptr;\r
}\r
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
+}
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
delete mainList_;
mainList_ = nullptr;
}
+
+ UITestGroup::GetInstance()->TearDownTestCase();
}
} // namespace OHOS
#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)
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()});
#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()});
#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()});
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()
void AnimatorManager::Init()
{
+ SetPeriod(0); // Animator的默认处理周期受RTC/TE刷新周期控制
Task::Init();
}
#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"
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)
#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 {
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;
}
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
}
#else
+
void RootView::OptimizeAddRect(Rect& rect)
{
Rect joinRect;
invalidRects[0].Join(invalidRects[0], commonRect);
}
#else
+ isDrawBeforeBlurViews_[view] = view->IsVisible();
OptimizeAddRect(commonRect);
#endif
if (!renderFlag_) {
{
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();
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_;
(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);
}
#else
if (curView == blurView_) {
- curView->HandleGaussianBlur(*dc_.bufferInfo);
+ curView->HandleGaussianBlur(*dc_.bufferInfo, isBlurCacheNeedRefresh_);
}
curView->OnDraw(*dc_.bufferInfo, curViewRect);
#endif
}
if (label != nullptr) {
+ label->SetDirect(direct_);
label->UIView::SetStyle(style_);
if (fontName_ == nullptr) {
label->SetFontId(fontId_);
newView->SetOnClickListener(clickListener_);
newView->SetTouchable(true);
}
- newView->SetDirect(direct_);
return newView;
}
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)
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;
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};
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_) {
{
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);
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_);
}
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
}
}
-#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);
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();
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)
startPos_ = pos;
}
+ void SetMarqueeBlankWidth(uint16_t size)
+ {
+ marqueeBlankWidth_ = size;
+ }
+
void UpdateWidth(uint16_t textWidth, uint16_t labelWidth)
{
textWidth_ = textWidth;
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();
}
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),
ellipsisIndex_(Text::TEXT_ELLIPSIS_END_INV),
truncateIndex_(Text::TEXT_TRUNCATE_END_INV),
offsetX_(0),
+ nextOffsetX_(0),
textColor_(Color::White()),
animator_{nullptr}
{
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 {
animator_.animator = animator;
hasAnimator_ = true;
}
+ static_cast<LabelAnimator*>(animator_.animator)->SetMarqueeBlankWidth(CalcBlankSpaceWidth(marqueeBlankNum_));
if (animator_.animator->GetState() == Animator::PAUSE) {
animator_.animator->Resume();
} else {
}
} else {
offsetX_ = 0;
+ nextOffsetX_ = rectWidth; // Set text outside the display area
labelText_->SetAlign(horAlign_, labelText_->GetVerAlign());
if (hasAnimator_) {
animator_.animator->Stop();
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);
#include "components/ui_abstract_scroll_bar.h"
#include "gfx_utils/graphic_log.h"
+#include "components/common_adapter.h"
namespace OHOS {
UIList::Recycle::~Recycle()
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;
}
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;
}
}
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()
}
}
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);
+ }
}
}
#include "gfx_utils/mem_api.h"
#include "securec.h"
#include "themes/theme_manager.h"
+#include "hals/gralloc_engines.h"
#include <cstdio>
namespace OHOS {
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),
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;
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;
}
}
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();
#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
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
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
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
} else if (RootView::GetInstance()->SetBlurView(this)) {
blurRadius_ = radius;
}
- RootView::GetInstance()->Invalidate();
+ if (fullScreenBlur_) {
+ RootView::GetInstance()->Invalidate();
+ } else {
+ Invalidate();
+ }
+
}
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();
+ }
}
}
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
}
}
+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) {
{
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
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;
void RenderManager::Init()
{
+ SetPeriod(0);
Task::Init();
}
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
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,
checkBoxOnInfo = {{0}};
checkBoxOffInfo = {{0}};
}
+#else
+void InitCheckBoxRes()
+{
+
+}
+
+void DeinitCheckBoxRes()
+{
+
+}
+#endif
ImageInfo* GetCheckBoxOnInfo()
{
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) {
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)) {
namespace OHOS {
BaseGfxEngine* BaseGfxEngine::baseEngine_ = nullptr;
+
+BaseGfxEngine::BaseGfxEngine()
+{
+}
+
void BaseGfxEngine::DrawArc(BufferInfo& dst,
ArcInfo& arcInfo,
const Rect& mask,
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) {
virtual uint16_t GetScreenHeight()
{
- // return height_;
+ // return height_;
return VERTICAL_RESOLUTION;
}
+ virtual uint16_t GetScreenRadius()
+ {
+ return radius_;
+ }
+
virtual void SetScreenShape(ScreenShape screenShape)
{
screenShape_ = screenShape;
{
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;
};
}
--- /dev/null
+/*
+ * 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
#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.
*/
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存储对象,获取的截图将被存到该引用中.
* @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 获取当前屏幕的形状.
*/
ScreenShape GetScreenShape();
+ bool GetBitMapFromBuffer(const BufferInfo &srcBuf, ImageInfo& info, const Rect *rect, float scale = 1.0, bool isClearMem = false);
+
private:
Screen() {}
virtual ~Screen() {}
#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
void OptimizeAddRect(Rect& rect);
void OptimizeInvalidateRects();
List<Rect> invalidateRects_;
+ std::map<UIView*, bool> isDrawBeforeBlurViews_;
+ bool isBlurCacheNeedRefresh_ = false;
#endif
bool renderFlag_ = false;
Rect invalidRect_;
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.
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.
enableBottomPoint_ = enable;
}
+ /**
+ * @brief enableBottomPoint_.
+ *
+ * @return Returns enableBottomPoint_.
+ */
+ bool GetEnableBottomPoint() const
+ {
+ return enableBottomPoint_;
+ }
+
void DrawPoint(BufferInfo& gfxDstBuffer, const Rect& mask);
void Refresh();
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;
*/
uint8_t GetAnimRealState();
+ void SetMarqueeBlankNum(uint16_t size)
+ {
+ marqueeBlankNum_ = size;
+ }
+
+ Text* GetLabelText()
+ {
+ return labelText_;
+ }
#if ENABLE_FONT_VECTOR_GLOBAL
virtual void ForceResetText() {};
#endif
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;
*/
void SetVideoPlayerListener(VideoPlayerListener* listener);
+ /**
+ * @brief Get current view type.
+ *
+ */
+ UIViewType GetViewType() const override
+ {
+ return UI_VIDEO;
+ }
+
private:
class SliderAnimatorCallback : public AnimatorCallback {
public:
#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. */
UI_CARD_PAGE,
UI_COVER_FLOW,
UI_SLIP_FLOW,
+ UI_FOLDABLE_VIEW,
UI_CROSS_VIEW,
UI_BARCODE,
UI_MAP_VIEW,
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
};
*/
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.
* @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
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_;
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
* 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
*/
#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;
#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 {
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)
{
}
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:
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;
* @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.
* @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
*/
#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" //印地语
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;
#endif
}
- ~GraphicCond()
+ virtual ~GraphicCond()
{
#ifdef _WIN32
CloseHandle(cond_);
#endif
}
-private:
+protected:
#if defined(_WIN32)
HANDLE cond_;
#elif defined(__FREERTOS__)
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 */
uint8_t lineOpa_;
uint8_t lineCap_;
int16_t lineWidth_;
+ /* extent style */
+private:
+ int16_t topBorderRadius_;
+ int16_t bottomBorderRadius_;
};
/**
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})
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")
#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
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
/** 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
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
\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
\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
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
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
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
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
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
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
}\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
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
\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
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
}\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
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
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
\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
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
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
--- /dev/null
+#===============================================================================
+# @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
--- /dev/null
+#===============================================================================
+# @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
--- /dev/null
+/*\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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+#===============================================================================
+# @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
--- /dev/null
+/*
+* 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
--- /dev/null
+/*\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
--- /dev/null
+/*
+* 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
--- /dev/null
+/*\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
*
* @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 将指定的流停止
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) {
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;
}
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
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;
}
uint32_t channelCount;\r
AudioLinkDirection linkDir;\r
uint16_t sampleFmt;\r
+ AudioBitWidth bitWidth;\r
} AudioRendererConfig;\r
\r
typedef struct {\r
uint32_t sessionID;\r
uint32_t channelCount;\r
AudioLinkDirection linkDir;\r
+ AudioBitWidth bitWidth;\r
} CapturerInputConfig;\r
\r
typedef enum {\r
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
)
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")
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,
};
PLAYERCONTROL_BUFFER_EMPTY, /* audio buffer empty */
PLAYERCONTROL_FIRST_VIDEO_FRAME,
PLAYERCONTROL_FIRST_AUDIO_FRAME,
+ PLAYERCONTROL_EVENT_PAUSED, /* play pause */
PLAYERCONTROL_EVENT_BUTT
};
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
// 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
lastReadPktStrmIdx_(-1),\r
lastReadPktPts_(0),\r
lastSendPktPts_(0),\r
+ speed_(TPLAY_SPEED_BASE),\r
isVideoStarted_(false),\r
isAudioStarted_(false),\r
strmReadEnd_(false),\r
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
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
DestroyDecoder();\r
MediaMutexDestroy(&schMutex_);\r
MediaThreadCondDestroy(&schCond_);\r
+ MediaThreadCondDestroy(&pauseCond_);\r
isInited_ = false;\r
return HI_SUCCESS;\r
}\r
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
\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
}\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
/* 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
\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
\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
\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
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
#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
\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
{\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
}\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
\r
bool isContinue = false;\r
DataSchPreProcess(play, &isContinue);\r
+ MediaMutexUnLock(play->schMutex_);\r
if (isContinue) {\r
goto CONTINUE;\r
}\r
\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
\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
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
} 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
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
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
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
\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
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
}\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, ¤tPosition_);\r
EventCallback(PLAYERCONTROL_EVENT_SEEK_END, static_cast<void *>(&seekTimeInMs));\r
return HI_SUCCESS;\r
\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
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;
{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},
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);
#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_;
int64_t lastReadPktPts_;
int64_t lastSendPktPts_;
+ // TPlay
+ float speed_;
+ TplayMode tplayMode_;
+ int32_t curSeekOffset_;
+ bool isTplayStartRead_;
+ bool isTplayLastFrame_;
+
bool isVideoStarted_;
bool isAudioStarted_;
bool strmReadEnd_;
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_;
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;
void AudioSink::ResetRendStartTime()
{
lastRendFrameCnt_ = 0;
-#ifdef MINI_MEMORY_SUPPORT
- lastRenderPosition_ = 0;
-#endif
lastRendPts_ = AV_INVALID_PTS;
rendStartTime_ = AV_INVALID_PTS;
}
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();
}
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;
void AudioSink::RecordLastPosition()
{
#ifdef MINI_MEMORY_SUPPORT
- lastRenderPosition_ = lastRendPts_;
+ lastRenderPosition_ += lastRendPts_;
#endif
}
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;
}
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;
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()
{
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;
}
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) {
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;
firstAudFrameTime_ = GetCurTimeUs();
}
if (GetCurTimeUs() - firstAudFrameTime_ <= FIRST_AUDIO_RENDER_WAIT_VID_TIME) {
- result = SYNC_RET_REPEAT;
+ result = SYNC_RET_DROP;
timeOut = false;
} else {
timeOut = true;
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;
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);
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_;
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 {
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_);
}
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;
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;
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;
}
}
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");
}
}
currentState_ = PLAYER_STOPPED;
+ OnInfoPlayCallBack(PlayerCallback::PlayerInfoType::PLAYER_INFO_STOPPED, 0);
MediaMutexUnLock(lock_);
MEDIA_INFO_LOG("process out");
return 0;
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);
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;
}
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_);
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;
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_);
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) {
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) {
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
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);
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);
int32_t SetMediaStream(void);
bool IsValidStreamType(int32_t type);
static int32_t GetStreamParam(const Format &format, StreamParam ¶m);
+ 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_;
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
};\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
* @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
set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/player_sample_wrapper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/audio_manager_c_wrapper.cpp
-
)
else()
set(SOURCE_COM ${SOURCES})
${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
)
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}
*/
#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
#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) { \
} 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;
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;
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},
{"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");
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) {
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;
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)
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()
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)
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)
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;
}
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);
}
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();
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");
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;
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;
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);
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;
#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
#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;
void OnInterrupt(int32_t type, int32_t hint) override
{
- printf("OnInterrupt xxxxxxxxxxxxxxxxxxxxxxxxxx\r\n");
ALOGI("type:%d hint:%d", type, hint);
}
};
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));
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)
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);
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);
int32_t AudioStreamOutFlush(void);
-int32_t AudioStreamGetTimestamp(struct timespec *timeStamp);
-
/**
* @brief Sets audio effect algorithm parameters.
*
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
--- /dev/null
+/*
+* 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
--- /dev/null
+/*
+* 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
#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
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
\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
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
}\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
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
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
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;
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");
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);
MediaThreadIdHandle mainId;
MediaThreadIdHandle subId;
bool detached;
+ MediaThreadCondHandle cond;
+ void *stackMem;
} MediaThreadMember;
#define THREAD_MANAGER_MAX_CNT 10
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)
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
#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);
}
uint32_t idx = MediaGetValidThreadManagerIdx();
if (idx >= THREAD_MANAGER_MAX_CNT) {
free(member);
- member = nullptr;
goto EXIT;
}
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;
#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);
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;
}
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");
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");
typedef enum {
AUDIO_MOD_AI = 0,
- AUDIO_MOD_AI_SEA,
AUDIO_MOD_ADP,
AUDIO_MOD_ADEC,
AUDIO_MOD_AENC,
void VolumePercentToDb(float volume, int32_t *db);
-bool IsRawFormat(struct PortPluginAttr inputAttr);
+bool IsRawFormat(enum AudioFormat audioFormat);
#ifdef AUDIO_SDK_SUPPORT
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,
#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 };
*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;
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 = {};
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;
}
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;
}
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);
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;
}
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;
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");
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");
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;
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;
}
#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[] = {
/* attr context */
bool isRaw;
struct PortPluginAttr inputAttr;
+ bool isSupportMultiFrame;
+ int32_t offset;
} SubPortTrackInContext;
typedef struct {
{ 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++) {
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;
}
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");
}
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;
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);
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);
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");
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;
{
#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");
{
#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");
{
#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");
}
}
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;
{
#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);
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);
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) {
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);
}
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;
}
*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;
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);
#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))
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);
if (len == 0) {
return NULL;
}
-
void *ptr = malloc(len);
if (ptr == NULL) {
MEDIA_HAL_LOGE(MODULE_NAME, "malloc failed");
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 };
MediaHalThreadIdHandle mainId;
MediaHalThreadIdHandle subId;
bool detached;
+ MediaHalThreadCondHandle cond;
+ void *stackMem;
} MediaHalThreadMember;
#define THREAD_MANAGER_MAX_CNT 10
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)
#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);
}
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);
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;
}
#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);
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);
#===============================================================================\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
${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
${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
} 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. */
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 */
};
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;
#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;
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, /* 设置日志级别 */
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;
*/
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;
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
}
--- /dev/null
+#===============================================================================\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
--- /dev/null
+/*
+* 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_ */
--- /dev/null
+/*
+* 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_ */
--- /dev/null
+/*
+* 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 */
--- /dev/null
+#===============================================================================\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
--- /dev/null
+/*
+* 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
--- /dev/null
+/*
+* 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);
+}
--- /dev/null
+#===============================================================================
+# @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
--- /dev/null
+/*
+* 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+#===============================================================================
+# @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
--- /dev/null
+/*\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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+* 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
--- /dev/null
+/*
+* 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
--- /dev/null
+#===============================================================================
+# @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
--- /dev/null
+/*
+* 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
--- /dev/null
+/*
+* 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
--- /dev/null
+#===============================================================================
+# @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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+* 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
--- /dev/null
+/*
+* 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
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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
#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" {
MediaHalMutexHandle mutex;
} DemuxerManager;
-typedef struct {
- bool enable;
- bool isRunning;
- FormatBufferSetting bufferSetting;
- MediaHalMutexHandle mutex;
- MediaHalThreadIdHandle threadId;
-} BufferCacheManager;
-
typedef struct {
int16_t programId;
int16_t videoTrackId;
void *demuxerHdl;
FileInfo info;
FormatCallback callback;
- BufferCacheManager cache;
+#ifdef ENABLE_BUFFER_MANAGER
+ FormatHandle bufferManager;
+ bool enableBuffer;
+#endif
SelectTrack selectTrack;
FormatAlbumArtInfo albumInfo;
} DemuxerContext;
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;
}
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");
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;
MediaHalMutexUnLock(ctx->mutex);
return -1;
}
- ctx->cache.bufferSetting = *setting;
+#ifdef ENABLE_BUFFER_MANAGER
+ SetBufferConfig(ctx->bufferManager, setting);
+#endif
MediaHalMutexUnLock(ctx->mutex);
return 0;
}
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;
}
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);
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;
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;
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;
}
MediaHalMutexUnLock(ctx->mutex);
return -1;
}
+#ifdef ENABLE_BUFFER_MANAGER
+ if (ctx->enableBuffer) {
+ StopBufferThread(ctx->bufferManager);
+ }
+#endif
ctx->state = STATE_STOP;
MediaHalMutexUnLock(ctx->mutex);
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) {
FreeFileInfo(ctx);
MediaHalMutexUnLock(ctx->mutex);
MediaHalMutexDestroy(&ctx->mutex);
- MediaHalMutexDestroy(&ctx->cache.mutex);
ctx->innerCtx = NULL;
free(ctx);
MEDIA_HAL_LOGD(MODULE_NAME, "func out");
#endif
#endif /* __cplusplus */
+bool HasM3U8(const char *url);
void DemuxerPluginManagerInit(void);
void DemuxerPluginManagerDeInit(void);
const DemuxerPluginEntry *DemuxerPluginManagerFindPlugin(const DemuxerSource *source, const ProtocolFun *protocol,
#include "hmf_demuxer_plugin.h"
#include "raw_format.h"
#endif
+#ifdef ENABLE_FFMPEG_DEMUXER
+#include "ff_demuxer_plugin.h"
+#endif
#ifdef __cplusplus
#if __cplusplus
#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;
DemuxerPluginEntry* g_allDemuxerEntry[] = {
&g_hmfDemuxerEntry,
&g_rawFormatDemuxerEntry,
+#ifdef ENABLE_FFMPEG_DEMUXER
+ &g_ffDemuxerEntry,
+#endif
NULL
};
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)
{
}
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;
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);
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;
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);
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 */
#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
.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)
{
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
LOS_Msleep(1000);
#endif
}
- // struct timespec ts;
- // AudioStreamGetTimestamp(&ts);
- // printf("AudioStreamGetTimestamp %d\r\n",ts.tv_sec);
// 释放消息数据内存
free(msg.data);
}
#include "alipay_feature.h"
#endif
-#define SUPPORT_NV
+#define SUPPORT_NV
#ifdef SUPPORT_NV
#include "nv.h"
#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)
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
{
stop_custom_ble_service();
}
-#ifdef BOARD_LEINIAO
+
cm_initScreenBrightness();
-#endif
// cm_initializeScreenDuration();
cm_initializeRaiseToWake();
// cm_initializeVibrationModel();
#endif
#endif
-#ifndef BOARD_LEINIAO
ble_SOS_data_init();
-#endif
-
#ifdef SUPPORT_CAT1_SERVICE
// up_report_timer();
#endif
#ifdef SUPPORT_CAT1_SERVICE
-#ifndef BOARD_LEINIAO
-
if ( cm_poweron_cat1_on_bootup_flag() )
{
PRINT("PowerOn Cat1 !\r\n");
PRINT("PowerOff Cat1 !\r\n");
uapi_set4GCapability(false);
}
-#endif
#else
// #ifdef SUPPORT_PPP_SERVICE
#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)
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
}
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(¤t_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");
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())
*/
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);
}
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;
}
}
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)