1# updater部件ux概述
2## 功能简介
3updater部件是在升级模式下的轻量小系统,ux组件是一套系统交互界面,提供OTA升级过程中的界面显示和信息提示,指导用户完成升级流程。组件不依赖ArkUI框架,无需引入JS,具有界面简洁、外部依赖少、跳转清晰的特点。
4## 基本概念
5- UX:User Experience,人机交互体验。<br>
6- 页面:界面交互时一个画面为一个页面。<br>
7- 控件:页面构成的基本单位,如按钮、文本、图片等单元。<br>
8- 引擎:控件显示必要条件,完成资源初始化、队列初始化、开启刷新线程等。<br>
9## 框架介绍
10框架主要由业务层、UX接口层、页面管理层、控件引擎层、设备驱动层组成,总体框架如下图所示:<br>
11
12图1 ux总体框架图<br>
13![输入图片说明](figures/framework.png)
14- 业务层<br>
15升级过程中的业务流程,包括读取misc分区信息获取升级包状态、对升级包进行校验、确保升级包合法有效、从升级包中解析出升级的可执行程序、创建子进程并启动升级程序等。
16
17- UX接口层<br>
18其他模块访问ux的统一通道,上层进行交互显示时,通过统一的类对象入口调用ux组件进行更新。接口调用包括进度条刷新、按钮刷新、文本刷新等。
19
20- 页面管理层<br>
21人机交互过程是一组页面的组合。主要负责页面组合管理,包括页面的配置、页面解析并初始化、页面间跳转等,是组件的核心组成部分。
22
23- 控件引擎层<br>
24控件是页面的基本组成单元。主要负责控件管理,包括两部分内容。一部分是完成图像引擎的初始化,包括字体初始化、图片解码初始化、申请显示缓存空间、开启屏幕刷新线程,依赖图形子系统的基础控件库。另外一部分是触控以及点击事件的初始化,可以感知用户点击屏幕和按键按下释放等操作,也是组件的核心组成部分。
25
26- 设备驱动层<br>
27主要完成各种设备类型屏幕设备节点的初始化,以及和引擎层刷新缓存的对接,保证上层的修改可以实时刷新显示。
28## 子模块介绍
291. 接口管理<br>
30在业务中通过唯一的对象实例UPDATER_UI_INSTANCE进行不同接口调用来实现不同界面的刷新。
31    ```c++
32    if (mode == HOTA_UPDATE) {
33        UPDATER_UI_INSTANCE.ShowFailedPage();
34    } else {
35        UPDATER_UI_INSTANCE.ShowMainpage();
36        UPDATER_UI_INSTANCE.Sleep(50); /* wait for page flush 50ms */
37        UPDATER_UI_INSTANCE.SaveScreen();
38    }
39    // Wait for user input
40    while (true) {
41        Utils::UsSleep(DISPLAY_TIME);
42    }
43    return 0;
44    ```
452. 页面管理<br>
46通过配置化进行页面管理,采用分层设计,config为统一入口,包含了不同类型产品的配置定义。product为特定产品的配置定义,包含了所有页面的配置定义。产品适配时可以从该入口开始梳理配置流程。有多个产品类型时,端侧在SelectConfig函数中会根据设备分辨率类型进行匹配,选择对应产品json。页面组成结构如下图所示:
47    ```c++
48    auto screenW = subCfg[WIDTH_KEY].As<int16_t>();
49    auto screenH = subCfg[HEIGHT_KEY].As<int16_t>();
50    if (!screenW.has_value() || !screenH.has_value()) {
51        LOG(ERROR) << "real config file should has screenW and screenH key";
52        return "";
53    }
54    if (screenW != Screen::GetInstance().GetWidth() || screenH != Screen::GetInstance().GetHeight()) {
55        LOG(INFO) << "screen size not matched" << subConfigPath;
56        continue;
57    }
58    LOG(INFO) << "select config: " << subConfigPath;
59    return subConfigPath;
60    ```
61    图2 页面组成结构图<br>
62    ![输入图片说明](figures/page_manage.png)
633. 控件管理<br>
64控件组织形式是一个树形结构,所有控件通过链表形式组成一颗渲染树,渲染时从最上面的覆盖脏区域的节点开始进行深度优先遍历绘图。RootView会挂载所有页面,类似于绘画时的白纸。UIViewGroup为配置文件中对应的各个page页面,类似于图像的图层。UIView为各个基本的显示控件。控件也是在配置中进行管理,挂载在每个页面下,因此在每个页面的定义中也需要增加控件的配置。控件结构如下图所示:<br>
65图3 控件结构示意图<br>
66![输入图片说明](figures/component_manage.png)
674. 事件管理<br>
68事件管理包含了触控事件响应,输入管理模块PointerInputDevice读取输入位置,根据上报的坐标信息所在的脏区域找到对应的控件,根据上报的状态信息,识别为点击事件,调用控件注册对应的触控回调函数,执行对应的响应。各控件的事件也是通过配置进行管理,如果某控件需要动态响应,需要在配置中添加对应回调函数。按钮响应的流程示例如下图所示:<br>
69图4 按钮响应流程示意图<br>
70![输入图片说明](figures/event_manage.png)
715. 资源管理<br>
72资源文件是ux功能正常运行的必备条件,主要包括字体、图片、文本、配置文件。当前字体的格式为ttf文件,图片资源格式为png,文本类型为string,所有配置文件为json。界面适配主要是定制化资源文件,可以在对应模块中修改适配。资源组成结构如下图所示:<br>
73图5 资源结构示意图<br>
74![输入图片说明](figures/res_manage.png)
75# 适配新产品RK3568
76## 约束与限制
77- 屏幕可以正常亮屏
78- 触控屏可以正常点击感应
79- 屏幕分辨率已知,以RK3568为例长宽的分辨率分别为720和1280
80## 适配流程
81适配过程主要是完成各种资源的初始化,流程如下图所示:<br>
82图6 适配流程图<br>
83![输入图片说明](figures/develop_process.png)
84### 新建rk3568.json
85进入到update_updater/resources/rk3568/pages目录。当前目录新建rk3568.json, 添加到config.json中。
86```json
87{
88    "config" : "/resources/pages/rk3568.json"
89}
90```
91### 初始化rk3568.json
92配置产品json文件中的各个字段值,配置列表如下所示:<br>
93
94表1 json各字段配置表
95| 字段 | 值 | 含义 | 备注 |
96|--|--|--|--|
97| screenWidth | 720 | 屏幕宽度分辨率 | 根据实际配置 |
98| screenHeight | 1280 | 屏幕长度分辨率 | 根据实际配置 |
99| dir | /resources/pages | 页面资源在单板的存放路径 | 使用默认 |
100| pages | ["menu.json","confirm.json","upd.json"] | 所有页面的列表 | 使用默认 |
101| enableFoucs | true | 使能焦点 | 使用默认 |
102| entry | menu:normal | 主菜单页面 | 使用默认 |
103| strategy | 见json配置:有default、sdcard、factoryRst、rebootFactoryRst | 默认有4种策略,分别为参数升级、SD卡升级、手动恢厂、参数恢厂 | 使用默认 |
104| locale | 见json配置:有res、localeFile | 单板上提示语资源存放路径、使用多语言的文件名 | 使用默认 |
105| callbacks | 见json配置:有pageId、comId、type、func | 为页面控件绑定回调函数类型,如点击事件和用户进行交互 | 使用默认 |
106
107因为pages字段中配置了3个页面,所以需要分别初始化这3个页面。
108
109### 初始化menu.json
110配置主菜单页面json文件中的各个字段值,配置列表如下所示:<br>
111
112表2 json各字段配置表
113| 字段 | 值 | 含义 | 备注 |
114|--|--|--|--|
115| id | menu | 主菜单页面,**值必须与上一小节中pages字段值保持一致** | 使用默认 |
116| bgColor | "r":0,"g":0,"b":0,"a":255 | 背景颜色为RGBA形式 | 根据实际配置 |
117| subpages | 见json配置:有id,coms,bgColor | 组成了包含的子页面,主菜单会跳转到这些子页面上 | 使用默认 |
118| default | 各控件属性 | 指定了默认控件的属性参数 | 使用默认 |
119| coms | type、id、x、y、w、h、fontSize、fontColor | 页面包含一组控件,定义了每个控件的基本属性,x、y、w、h确定了控件在页面上的唯一位置 | x、y、w、h、fontSize、fontColor需要根据分辨率的实际配置,其他使用默认 |
120
121- 下面举例看看更改这些字段后的效果。
122    ```json
123    "id": "menu",
124    "bgColor" : "#000000ff",
125    "subpages" : [
126         {
127             "id":"normal",
128             "bgColor" : "#f1f3f5ff"
129    ```
130
131    图7 修改前效果图<br>
132    ![输入图片说明](figures/menu_grey.png)
133- rk3568.json中entry字段配置为menu:normal,修改subpages中id为normal的背景色配置bgColor字段,改为绿色不透明:
134    ```json
135    "id": "menu",
136    "bgColor" : "#000000ff",
137    "subpages" : [
138        {
139            "id":"normal",
140            "bgColor" : "#00ff00ff"
141    ```
142
143    修改后效果:<br>
144    图8 修改后效果图<br>
145    ![输入图片说明](figures/menu_green.png)
146- 接下来再更改LOGO图片的位置,当前配置如上图所示:
147    ```json
148    "coms": [
149        {
150            "type": "UIImageView",
151            "id": "HarmonyOSIcon_Image",
152            "x": 120,
153            "y": 426,
154            "w": 480,
155            "h": 60,
156    ```
157
158    现在通过修改w、h、x、y属性移动到屏幕顶部左上角:
159    ```json
160    "coms": [
161        {
162            "type": "UIImageView",
163            "id": "HarmonyOSIcon_Image",
164            "x": 0,
165            "y": 0,
166            "w": 480,
167            "h": 60,
168    ```
169
170    修改后效果:<br>
171    图9 修改后效果图<br>
172    ![输入图片说明](figures/menu_top.png)<br>
173其他属性的配置操作都是一样,参照以上配置即可。
174### 初始化confirm.json
175配置确认页面json文件中的各个字段值,配置列表如下所示:<br>
176
177表3 json各字段配置表
178| 字段 | 值 | 含义 | 备注 |
179|--|--|--|--|
180| id | confirm | 确认页面,**值必须与上一小节中pages字段值保持一致** | 使用默认 |
181| bgColor | "r":0,"g":0,"b":0,"a":255 | 背景颜色为RGBA形式 | 根据实际配置 |
182| default | 各控件属性 | 指定了默认控件的属性参数 | 使用默认 |
183| coms | type、id、x、y、w、h、fontSize、fontColor | 页面包含一组控件,定义了每个控件的基本属性,x、y、w、h确定了控件在页面上的唯一位置 | x、y、w、h、fontSize、fontColor需要根据分辨率的实际配置,其他使用默认 |
184
185- 下面举例看看更改这些字段后的效果。<br>
186    ```json
187    "coms": [
188        {
189            "type": "UILabelButton",
190            "id": "Cancel_Button",
191            "text": "[LABEL_NOTE_CANCEL]",
192            "x": 48,
193            "y": 1130,
194            "w": 624,
195            "h": 80,
196            "fontSize": 32
197        },
198        {
199            "type": "UILabelButton",
200            "id": "Reset_Button",
201            "text": "[LABEL_USER_DATA_RESET]",
202            "x": 48,
203            "y": 1020,
204            "w": 624,
205            "h": 80,
206            "fontSize": 32
207        }
208    ```
209
210    图10 修改前效果图<br>
211    ![输入图片说明](figures/confirm_btn.png)
212- 页面中有两个按钮,和对应的按钮配置。现在把Cancel_Button取消居中移动到左对齐,字体变大。Reset_Button移动到屏幕底部,同时字体缩小一半,修改后的配置:
213    ```json
214    "coms": [
215        {
216            "type": "UILabelButton",
217            "id": "Cancel_Button",
218            "text": "[LABEL_NOTE_CANCEL]",
219            "x": 0,
220            "y": 1130,
221            "w": 624,
222            "h": 80,
223            "fontSize": 48
224        },
225        {
226            "type": "UILabelButton",
227            "id": "Reset_Button",
228            "text": "[LABEL_USER_DATA_RESET]",
229            "x": 48,
230            "y": 1200,
231            "w": 624,
232            "h": 80,
233            "fontSize": 16
234        }
235    ```
236
237    修改后效果如下:<br>
238    图11 修改后效果图<br>
239    ![输入图片说明](figures/confirm_bottom.png)
240### 初始化upd.json
241配置更新页面json文件中的各个字段值,配置列表如下所示:<br>
242
243表4 json各字段配置表
244| 字段 | 值 | 含义 | 备注 |
245|--|--|--|--|
246| id | upd | 进度条升级页面,**值必须与上一小节中pages字段值保持一致** | 使用默认 |
247| bgColor | "r":0,"g":0,"b":0,"a":255 | 背景颜色为RGBA形式 | 根据实际配置 |
248| subpages | 见json配置:有id,coms,bgColor | 组成了包含的子页面,主菜单会跳转到这些子页面上,有7个跳转页面 | 使用默认 |
249| default | 各控件属性 | 指定了默认控件的属性参数 | 使用默认 |
250| coms | type、id、x、y、w、h、fontSize、fontColor | 页面包含一组控件,定义了每个控件的基本属性,x、y、w、h确定了控件在页面上的唯一位置 | x、y、w、h、fontSize、fontColor需要根据分辨率的实际配置,其他使用默认 |
251
252- 同类型控件前几个小节已经介绍,下面举例看看更改进度条字段后的效果。**白色背景进度条在非安装包升级模式才有**,对应的控件id为UpdBox_Progress,修改配置时注意区分。<br>
253    ```json
254    "coms": [
255        {
256            "type": "UIBoxProgress",
257            "id": "UpdBox_Progress",
258            "x": 144,
259            "y": 584,
260            "w": 432,
261            "h": 4,
262            "endPoint" : "FlashPoint_Image",
263            "hasEp" : true
264        },
265    ```
266
267    图12 修改前效果图<br>
268    ![输入图片说明](figures/upd_progress.png)
269- 修改配置把进度条移动到LOGO上面,进度条宽度扩大10倍,配置如下:
270    ```json
271    "coms": [
272        {
273            "type": "UIBoxProgress",
274            "id": "UpdBox_Progress",
275            "x": 144,
276            "y": 200,
277            "w": 432,
278            "h": 40,
279            "endPoint" : "FlashPoint_Image",
280            "hasEp" : true
281        },
282    ```
283
284    修改后效果如下:<br>
285    图13 修改后效果图<br>
286    ![输入图片说明](figures/upd_wider.png)
287- **黑色背景进度条在安装包升级模式才有**,对应的控件id为ProgressUpdBoxDark_Progress,修改配置时注意区分。<br>
288    ```json
289    "coms": [
290        {
291            "type": "UIBoxProgress",
292            "id": "ProgressUpdBoxDark_Progress",
293            "x": 144,
294            "y": 548,
295            "w": 432,
296            "h": 4,
297            "bgColor" : "#262626ff",
298            "fgColor" : "#b4b4b4ff",
299            "endPoint" : "FlashPointDark_Image",
300            "hasEp" : true
301        },
302    ```
303
304    图14 修改前效果图<br>
305    ![输入图片说明](figures/upd_black.png)
306- 修改配置颜色变更为红色,配置如下:
307    ```json
308    "coms": [
309        {
310            "type": "UIBoxProgress",
311            "id": "ProgressUpdBoxDark_Progress",
312            "x": 144,
313            "y": 548,
314            "w": 432,
315            "h": 4,
316            "bgColor" : "#262626ff",
317            "fgColor" : "#ff0000ff",
318            "endPoint" : "FlashPointDark_Image",
319            "hasEp" : true
320        },
321    ```
322
323    修改后效果如下:<br>
324    图15 修改后效果图<br>
325    ![输入图片说明](figures/upd_red.png)
326### 初始化图片资源
327页面配置完成后,需要对资源images目录进行初始化。json文件中图片控件的resPath字段会配置为图片在设备上的路径,该路径下的资源来源于如下表格中的目录。如果需要更换这些图片资源,在此目录下替换即可。<br>
328
329表5 图片资源目录表
330| 目录 | 含义 | 备注 |
331|--|--|--|
332| resources/rk3568/images/icon | 主菜单LOGO图片资源 | 使用默认 |
333| resources/rk3568/images/progress | 进度条图片资源 | 使用默认 |
334| resources/rk3568/images/warn | 警告图片资源,升级过程中操作不当会触发警告 | 使用默认 |
335
336### 初始化提示语
337images目录适配完成后,需要适配同级目录的string文件夹。提示语通过配置文件string.json进行管理。支持中英文和西班牙语。文本控件以id形式组成一个列表。可以修改提示语值,也可以使用默认。<br>
338
339表6 提示语配置表
340| 字段 | 含义 | 备注 |
341|--|--|--|
342| type | 控件类型一般为文本 | 使用默认 |
343| zh | 中文提示语 | 根据实际配置 |
344| en | 英文提示语 | 根据实际配置 |
345| spa | 西班牙提示语 | 根据实际配置 |
346
347### 初始化字体
348接下来是字体的适配。可以使用默认ttf文件。若当前字体库不满足使用场景,用准备好的ttf字体库文件替换即可,文件在目录resources/font下。
349
350### 输入处理
351最后在HdfInit函数中进行触控屏的报点读取和分发处理。在ReportEventPkgCallback函数中更新坐标点和按压状态。
352```c++
353for (int i = 0; i < MAX_INPUT_DEVICES; i++) {
354    uint32_t idx = sta[i].devIndex;
355    if ((idx == 0) || (g_inputInterface->iInputManager->OpenInputDevice(idx) == INPUT_FAILURE)) {
356        continue;
357    }
358
359    LOG(INFO) << "hdf devType:" << sta[i].devType << ", devIndex:" << idx;
360}
361
362/* first param not necessary, pass default 1 */
363g_callback.EventPkgCallback = ReportEventPkgCallback;
364ret = g_inputInterface->iInputReporter->RegisterReportCallback(1, &g_callback);
365if (ret != INPUT_SUCCESS) {
366    LOG(ERROR) << "register callback failed for device 1";
367    return ret;
368}
369```
370
371如果输入使用了openharmony的HDF驱动框架,HdfInit函数不用修改即可完成坐标点正常获取。否则请适配该函数完成坐标点和按压状态更新。
372## 调测验证
373适配完成后即可编译版本刷写单板查看效果。
374- 主菜单页面menu.json<br>
375图16 主菜单页面效果图<br>
376![输入图片说明](figures/menu.png)
377- 确认页面confirm.json<br>
378图17 确认页面效果图<br>
379![输入图片说明](figures/confirm.png)
380- 更新页面upd.json<br>
381恢厂更新:<br>
382图18 恢厂更新页面效果图<br>
383![输入图片说明](figures/upd_sd.png)<br>
384安装包升级更新:<br>
385图19 安装包更新页面效果图<br>
386![输入图片说明](figures/upd_zip.png)
387