1e41f4b71Sopenharmony_ci# Widget Host Development (for System Applications Only)
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## Widget Overview
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ciA widget is a set of UI components that display important information or operations specific to an application. It provides users with direct access to a desired application service, without the need to open the application first.
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciA widget usually appears as a part of the UI of another application (which currently can only be a system application) and provides basic interactive features such as opening a UI page or sending a message. The widget host is responsible for displaying the service widget.
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ci- Before you get started, it would be helpful if you have a basic understanding of the following concepts:
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci  - Widget provider: an atomic service that controls the widget content to display, how widget components are laid out, and how they interact with users.
12e41f4b71Sopenharmony_ci  
13e41f4b71Sopenharmony_ci  - Widget host: an application that displays the widget content and controls the widget location.
14e41f4b71Sopenharmony_ci  
15e41f4b71Sopenharmony_ci  - Widget Manager: a resident agent that provides widget management features such as periodic widget updates.
16e41f4b71Sopenharmony_ci  
17e41f4b71Sopenharmony_ci   ![formHostMoudle](./figures/widget-host-development-guide-1.png)
18e41f4b71Sopenharmony_ci
19e41f4b71Sopenharmony_ci## When to Use
20e41f4b71Sopenharmony_ci
21e41f4b71Sopenharmony_ciCarry out the following operations to develop the widget host based on the stage model:
22e41f4b71Sopenharmony_ci
23e41f4b71Sopenharmony_ci- Use **FormComponent**.
24e41f4b71Sopenharmony_ci- Use the APIs provided by the **formHost** module to delete or update widgets.
25e41f4b71Sopenharmony_ci
26e41f4b71Sopenharmony_ci## Using FormComponent
27e41f4b71Sopenharmony_ci
28e41f4b71Sopenharmony_ci**FormComponent** is a component used to display widgets. For details, see [FormComponent](../reference/apis-arkui/arkui-ts/ts-basic-components-formcomponent-sys.md).
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ci> **NOTE**
31e41f4b71Sopenharmony_ci>
32e41f4b71Sopenharmony_ci> - This component is supported since API version 7. Updates will be marked with a superscript to indicate their earliest API version.
33e41f4b71Sopenharmony_ci>
34e41f4b71Sopenharmony_ci> - This component functions as the widget host.
35e41f4b71Sopenharmony_ci>
36e41f4b71Sopenharmony_ci> - To use this component, you must have the system signature.
37e41f4b71Sopenharmony_ci>
38e41f4b71Sopenharmony_ci> - The APIs provided by this component are system APIs.
39e41f4b71Sopenharmony_ci
40e41f4b71Sopenharmony_ciWhen a widget is added through **FormComponent**, the [onAddForm](../reference/apis-form-kit/js-apis-app-form-formExtensionAbility.md#onaddform) API in **FormExtensionAbility** of the widget provider is called.
41e41f4b71Sopenharmony_ci
42e41f4b71Sopenharmony_ci### Temporary and Normal Widgets
43e41f4b71Sopenharmony_ci
44e41f4b71Sopenharmony_ciThe **temporary** field in **FormComponent** specifies whether a widget is a temporary or normal widget. The value **true** indicates a temporary widget, and **false** indicates a normal widget.
45e41f4b71Sopenharmony_ci
46e41f4b71Sopenharmony_ci- Normal widget: a widget persistently used by the widget host, for example, a widget added to the home screen.
47e41f4b71Sopenharmony_ci
48e41f4b71Sopenharmony_ci- Temporary widget: a widget temporarily used by the widget host, for example, the widget displayed when you swipe up on a widget application.
49e41f4b71Sopenharmony_ci  
50e41f4b71Sopenharmony_ciData of a temporary widget will be deleted on the Widget Manager if the widget framework is killed and restarted. The widget provider, however, is not notified of the deletion and still keeps the data. Therefore, the widget provider needs to clear the data of temporary widgets proactively if the data has been kept for a long period of time. If the widget host has converted a temporary widget into a normal one, the widget provider should change the widget data from temporary storage to persistent storage. Otherwise, the widget data may be deleted by mistake. 
51e41f4b71Sopenharmony_ci
52e41f4b71Sopenharmony_ci## Using formHost APIs
53e41f4b71Sopenharmony_ci
54e41f4b71Sopenharmony_ciThe **formHost** module provides a series of APIs for the widget host to update and delete widgets. For details, see the [API reference](../reference/apis-form-kit/js-apis-app-form-formHost-sys.md).
55e41f4b71Sopenharmony_ci
56e41f4b71Sopenharmony_ci## Example
57e41f4b71Sopenharmony_ci
58e41f4b71Sopenharmony_ci```ts
59e41f4b71Sopenharmony_ci//Index.ets
60e41f4b71Sopenharmony_ciimport { HashMap, HashSet } from '@kit.ArkTS';
61e41f4b71Sopenharmony_ciimport { formHost, formInfo, formObserver } from '@kit.FormKit';
62e41f4b71Sopenharmony_ciimport { bundleMonitor } from '@kit.AbilityKit';
63e41f4b71Sopenharmony_ciimport { BusinessError } from '@kit.BasicServicesKit';
64e41f4b71Sopenharmony_ci
65e41f4b71Sopenharmony_ci@Entry
66e41f4b71Sopenharmony_ci@Component
67e41f4b71Sopenharmony_cistruct formHostSample {
68e41f4b71Sopenharmony_ci  // Enumerated values of the widget size.
69e41f4b71Sopenharmony_ci  static FORM_DIMENSIONS_MAP = [
70e41f4b71Sopenharmony_ci    '1*2',
71e41f4b71Sopenharmony_ci    '2*2',
72e41f4b71Sopenharmony_ci    '2*4',
73e41f4b71Sopenharmony_ci    '4*4',
74e41f4b71Sopenharmony_ci    '2*1',
75e41f4b71Sopenharmony_ci    '1*1',
76e41f4b71Sopenharmony_ci    '6*4',
77e41f4b71Sopenharmony_ci  ]
78e41f4b71Sopenharmony_ci
79e41f4b71Sopenharmony_ci  // Simulate the widget sizes.
80e41f4b71Sopenharmony_ci  static FORM_SIZE = [
81e41f4b71Sopenharmony_ci    [120, 60],    // 1*2
82e41f4b71Sopenharmony_ci    [120, 120],   // 2*2
83e41f4b71Sopenharmony_ci    [240, 120],   // 2*4
84e41f4b71Sopenharmony_ci    [240, 240],   // 4*4
85e41f4b71Sopenharmony_ci    [60, 120],    // 2*1
86e41f4b71Sopenharmony_ci    [60, 60],     // 1*1
87e41f4b71Sopenharmony_ci    [240, 360],   // 6*4
88e41f4b71Sopenharmony_ci  ]
89e41f4b71Sopenharmony_ci
90e41f4b71Sopenharmony_ci  @State message: Resource | string = $r('app.string.Host');
91e41f4b71Sopenharmony_ci  formCardHashMap: HashMap<string, formInfo.FormInfo> = new HashMap();
92e41f4b71Sopenharmony_ci  @State showFormPicker: boolean = false;
93e41f4b71Sopenharmony_ci  @State operation: Resource | string = $r('app.string.formOperation');
94e41f4b71Sopenharmony_ci  @State index: number = 2;
95e41f4b71Sopenharmony_ci  @State space: number = 8;
96e41f4b71Sopenharmony_ci  @State arrowPosition: ArrowPosition = ArrowPosition.END;
97e41f4b71Sopenharmony_ci  formIds: HashSet<string> = new HashSet();
98e41f4b71Sopenharmony_ci  currentFormKey: string = '';
99e41f4b71Sopenharmony_ci  focusFormInfo: formInfo.FormInfo = {
100e41f4b71Sopenharmony_ci    bundleName: '',
101e41f4b71Sopenharmony_ci    moduleName: '',
102e41f4b71Sopenharmony_ci    abilityName: '',
103e41f4b71Sopenharmony_ci    name: '',
104e41f4b71Sopenharmony_ci    displayName: '',
105e41f4b71Sopenharmony_ci    displayNameId: 0,
106e41f4b71Sopenharmony_ci    description: '',
107e41f4b71Sopenharmony_ci    descriptionId: 0,
108e41f4b71Sopenharmony_ci    type: formInfo.FormType.eTS,
109e41f4b71Sopenharmony_ci    jsComponentName: '',
110e41f4b71Sopenharmony_ci    colorMode: formInfo.ColorMode.MODE_AUTO,
111e41f4b71Sopenharmony_ci    isDefault: false,
112e41f4b71Sopenharmony_ci    updateEnabled: false,
113e41f4b71Sopenharmony_ci    formVisibleNotify: true,
114e41f4b71Sopenharmony_ci    scheduledUpdateTime: '',
115e41f4b71Sopenharmony_ci    formConfigAbility: '',
116e41f4b71Sopenharmony_ci    updateDuration: 0,
117e41f4b71Sopenharmony_ci    defaultDimension: 6,
118e41f4b71Sopenharmony_ci    supportDimensions: [],
119e41f4b71Sopenharmony_ci    supportedShapes: [],
120e41f4b71Sopenharmony_ci    customizeData: {},
121e41f4b71Sopenharmony_ci    isDynamic: false,
122e41f4b71Sopenharmony_ci    transparencyEnabled: false
123e41f4b71Sopenharmony_ci  }
124e41f4b71Sopenharmony_ci  formInfoRecord: TextCascadePickerRangeContent[] = [];
125e41f4b71Sopenharmony_ci  pickerBtnMsg: Resource | string = $r('app.string.formType');
126e41f4b71Sopenharmony_ci  @State showForm: boolean = true;
127e41f4b71Sopenharmony_ci  @State selectFormId: string = '0';
128e41f4b71Sopenharmony_ci  @State pickDialogIndex: number = 0;
129e41f4b71Sopenharmony_ci
130e41f4b71Sopenharmony_ci  aboutToAppear(): void {
131e41f4b71Sopenharmony_ci    try {
132e41f4b71Sopenharmony_ci      // Check whether the system is ready.
133e41f4b71Sopenharmony_ci      formHost.isSystemReady().then(() => {
134e41f4b71Sopenharmony_ci        console.log('formHost isSystemReady success');
135e41f4b71Sopenharmony_ci
136e41f4b71Sopenharmony_ci        // Subscribe to events indicating that a widget becomes invisible and events indicating that a widget becomes visible.
137e41f4b71Sopenharmony_ci        let notifyInvisibleCallback = (data: formInfo.RunningFormInfo[]) => {
138e41f4b71Sopenharmony_ci          console.log(`form change invisibility, data: ${JSON.stringify(data)}`);
139e41f4b71Sopenharmony_ci        }
140e41f4b71Sopenharmony_ci        let notifyVisibleCallback = (data: formInfo.RunningFormInfo[]) => {
141e41f4b71Sopenharmony_ci          console.log(`form change visibility, data: ${JSON.stringify(data)}`);
142e41f4b71Sopenharmony_ci        }
143e41f4b71Sopenharmony_ci        formObserver.on('notifyInvisible', notifyInvisibleCallback);
144e41f4b71Sopenharmony_ci        formObserver.on('notifyVisible', notifyVisibleCallback);
145e41f4b71Sopenharmony_ci
146e41f4b71Sopenharmony_ci        // Subscribe to bundle installation events.
147e41f4b71Sopenharmony_ci        try {
148e41f4b71Sopenharmony_ci          bundleMonitor.on('add', (bundleChangeInfo) => {
149e41f4b71Sopenharmony_ci            console.info(`bundleName : ${bundleChangeInfo.bundleName} userId : ${bundleChangeInfo.userId}`);
150e41f4b71Sopenharmony_ci            this.getAllBundleFormsInfo();
151e41f4b71Sopenharmony_ci          })
152e41f4b71Sopenharmony_ci        } catch (errData) {
153e41f4b71Sopenharmony_ci          let message = (errData as BusinessError).message;
154e41f4b71Sopenharmony_ci          let errCode = (errData as BusinessError).code;
155e41f4b71Sopenharmony_ci          console.log(`errData is errCode:${errCode}  message:${message}`);
156e41f4b71Sopenharmony_ci        }
157e41f4b71Sopenharmony_ci        // Subscribe to bundle update events.
158e41f4b71Sopenharmony_ci        try {
159e41f4b71Sopenharmony_ci          bundleMonitor.on('update', (bundleChangeInfo) => {
160e41f4b71Sopenharmony_ci            console.info(`bundleName : ${bundleChangeInfo.bundleName} userId : ${bundleChangeInfo.userId}`);
161e41f4b71Sopenharmony_ci            this.getAllBundleFormsInfo();
162e41f4b71Sopenharmony_ci          })
163e41f4b71Sopenharmony_ci        } catch (errData) {
164e41f4b71Sopenharmony_ci          let message = (errData as BusinessError).message;
165e41f4b71Sopenharmony_ci          let errCode = (errData as BusinessError).code;
166e41f4b71Sopenharmony_ci          console.log(`errData is errCode:${errCode}  message:${message}`);
167e41f4b71Sopenharmony_ci        }
168e41f4b71Sopenharmony_ci        // Subscribe to bundle uninstall events.
169e41f4b71Sopenharmony_ci        try {
170e41f4b71Sopenharmony_ci          bundleMonitor.on('remove', (bundleChangeInfo) => {
171e41f4b71Sopenharmony_ci            console.info(`bundleName : ${bundleChangeInfo.bundleName} userId : ${bundleChangeInfo.userId}`);
172e41f4b71Sopenharmony_ci            this.getAllBundleFormsInfo();
173e41f4b71Sopenharmony_ci          })
174e41f4b71Sopenharmony_ci        } catch (errData) {
175e41f4b71Sopenharmony_ci          let message = (errData as BusinessError).message;
176e41f4b71Sopenharmony_ci          let errCode = (errData as BusinessError).code;
177e41f4b71Sopenharmony_ci          console.log(`errData is errCode:${errCode}  message:${message}`);
178e41f4b71Sopenharmony_ci        }
179e41f4b71Sopenharmony_ci      }).catch((error: BusinessError) => {
180e41f4b71Sopenharmony_ci        console.error(`error, code: ${error.code}, message: ${error.message}`);
181e41f4b71Sopenharmony_ci      });
182e41f4b71Sopenharmony_ci    }
183e41f4b71Sopenharmony_ci    catch (error) {
184e41f4b71Sopenharmony_ci      console.error(`catch error, code: ${(error as BusinessError).code}, message: ${(error as BusinessError).message}`);
185e41f4b71Sopenharmony_ci    }
186e41f4b71Sopenharmony_ci  }
187e41f4b71Sopenharmony_ci
188e41f4b71Sopenharmony_ci  aboutToDisappear(): void {
189e41f4b71Sopenharmony_ci    // Delete all widgets.
190e41f4b71Sopenharmony_ci    this.formIds.forEach((id) => {
191e41f4b71Sopenharmony_ci      console.log('delete all form')
192e41f4b71Sopenharmony_ci      formHost.deleteForm(id);
193e41f4b71Sopenharmony_ci    });
194e41f4b71Sopenharmony_ci    // Unsubscribe from bundle installation events.
195e41f4b71Sopenharmony_ci    try {
196e41f4b71Sopenharmony_ci      bundleMonitor.off('add');
197e41f4b71Sopenharmony_ci    } catch (errData) {
198e41f4b71Sopenharmony_ci      let message = (errData as BusinessError).message;
199e41f4b71Sopenharmony_ci      let errCode = (errData as BusinessError).code;
200e41f4b71Sopenharmony_ci      console.log(`errData is errCode:${errCode}  message:${message}`);
201e41f4b71Sopenharmony_ci    }
202e41f4b71Sopenharmony_ci    // Unsubscribe from bundle update events.
203e41f4b71Sopenharmony_ci    try {
204e41f4b71Sopenharmony_ci      bundleMonitor.off('update');
205e41f4b71Sopenharmony_ci    } catch (errData) {
206e41f4b71Sopenharmony_ci      let message = (errData as BusinessError).message;
207e41f4b71Sopenharmony_ci      let errCode = (errData as BusinessError).code;
208e41f4b71Sopenharmony_ci      console.log(`errData is errCode:${errCode}  message:${message}`);
209e41f4b71Sopenharmony_ci    }
210e41f4b71Sopenharmony_ci    // Unsubscribe from bundle uninstall events.
211e41f4b71Sopenharmony_ci    try {
212e41f4b71Sopenharmony_ci      bundleMonitor.off('remove');
213e41f4b71Sopenharmony_ci    } catch (errData) {
214e41f4b71Sopenharmony_ci      let message = (errData as BusinessError).message;
215e41f4b71Sopenharmony_ci      let errCode = (errData as BusinessError).code;
216e41f4b71Sopenharmony_ci      console.log(`errData is errCode:${errCode}  message:${message}`);
217e41f4b71Sopenharmony_ci    }
218e41f4b71Sopenharmony_ci    // Unsubscribe from events indicating that a widget becomes invisible and events indicating that a widget becomes visible.
219e41f4b71Sopenharmony_ci    formObserver.off('notifyInvisible');
220e41f4b71Sopenharmony_ci    formObserver.off('notifyVisible');
221e41f4b71Sopenharmony_ci  }
222e41f4b71Sopenharmony_ci
223e41f4b71Sopenharmony_ci  // Save the information of all widgets to formHapRecordMap.
224e41f4b71Sopenharmony_ci  getAllBundleFormsInfo() {
225e41f4b71Sopenharmony_ci    this.formCardHashMap.clear();
226e41f4b71Sopenharmony_ci    this.showFormPicker = false;
227e41f4b71Sopenharmony_ci    let formHapRecordMap: HashMap<string, formInfo.FormInfo[]> = new HashMap();
228e41f4b71Sopenharmony_ci    this.formInfoRecord = [];
229e41f4b71Sopenharmony_ci    formHost.getAllFormsInfo().then((formList: Array<formInfo.FormInfo>) => {
230e41f4b71Sopenharmony_ci      console.log('getALlFormsInfo size:' + formList.length)
231e41f4b71Sopenharmony_ci      for (let formItemInfo of formList) {
232e41f4b71Sopenharmony_ci        let formBundleName = formItemInfo.bundleName;
233e41f4b71Sopenharmony_ci        if (formHapRecordMap.hasKey(formBundleName)) {
234e41f4b71Sopenharmony_ci          formHapRecordMap.get(formBundleName).push(formItemInfo)
235e41f4b71Sopenharmony_ci        } else {
236e41f4b71Sopenharmony_ci          let formInfoList: formInfo.FormInfo[] = [formItemInfo];
237e41f4b71Sopenharmony_ci          formHapRecordMap.set(formBundleName, formInfoList);
238e41f4b71Sopenharmony_ci        }
239e41f4b71Sopenharmony_ci      }
240e41f4b71Sopenharmony_ci      for (let formBundle of formHapRecordMap.keys()) {
241e41f4b71Sopenharmony_ci        let bundleFormInfo: TextCascadePickerRangeContent = {
242e41f4b71Sopenharmony_ci          text: formBundle,
243e41f4b71Sopenharmony_ci          children: []
244e41f4b71Sopenharmony_ci        }
245e41f4b71Sopenharmony_ci        let bundleFormList: formInfo.FormInfo[] = formHapRecordMap.get(formBundle);
246e41f4b71Sopenharmony_ci        bundleFormList.forEach((formItemInfo) => {
247e41f4b71Sopenharmony_ci          let dimensionName = formHostSample.FORM_DIMENSIONS_MAP[formItemInfo.defaultDimension - 1];
248e41f4b71Sopenharmony_ci          bundleFormInfo.children?.push({ text: formItemInfo.name + '#' + dimensionName });
249e41f4b71Sopenharmony_ci          this.formCardHashMap.set(formBundle + "#" + formItemInfo.name + '#' + dimensionName, formItemInfo);
250e41f4b71Sopenharmony_ci        })
251e41f4b71Sopenharmony_ci        this.formInfoRecord.push(bundleFormInfo);
252e41f4b71Sopenharmony_ci      }
253e41f4b71Sopenharmony_ci      this.formCardHashMap.forEach((formItem: formInfo.FormInfo) => {
254e41f4b71Sopenharmony_ci        console.info(`formCardHashmap: ${JSON.stringify(formItem)}`);
255e41f4b71Sopenharmony_ci      })
256e41f4b71Sopenharmony_ci      this.showFormPicker = true;
257e41f4b71Sopenharmony_ci    })
258e41f4b71Sopenharmony_ci  }
259e41f4b71Sopenharmony_ci
260e41f4b71Sopenharmony_ci  build() {
261e41f4b71Sopenharmony_ci    Column() {
262e41f4b71Sopenharmony_ci      Text(this.message)
263e41f4b71Sopenharmony_ci        .fontSize(30)
264e41f4b71Sopenharmony_ci        .fontWeight(FontWeight.Bold)
265e41f4b71Sopenharmony_ci
266e41f4b71Sopenharmony_ci      Divider().vertical(false).color(Color.Black).lineCap(LineCapStyle.Butt).margin({ top: 10, bottom: 10 })
267e41f4b71Sopenharmony_ci
268e41f4b71Sopenharmony_ci      Row() {
269e41f4b71Sopenharmony_ci        // Click to query information about all widgets.
270e41f4b71Sopenharmony_ci        Button($r('app.string.inquiryForm'))
271e41f4b71Sopenharmony_ci          .onClick(() => {
272e41f4b71Sopenharmony_ci            this.getAllBundleFormsInfo();
273e41f4b71Sopenharmony_ci          })
274e41f4b71Sopenharmony_ci
275e41f4b71Sopenharmony_ci        // After the user clicks a button, a selection page is displayed. After the user clicks OK, the selected widget of the default size is added.
276e41f4b71Sopenharmony_ci        Button($r('app.string.selectAddForm'))
277e41f4b71Sopenharmony_ci          .enabled(this.showFormPicker)
278e41f4b71Sopenharmony_ci          .onClick(() => {
279e41f4b71Sopenharmony_ci            console.info("TextPickerDialog: show()")
280e41f4b71Sopenharmony_ci            TextPickerDialog.show({
281e41f4b71Sopenharmony_ci              range: this.formInfoRecord,
282e41f4b71Sopenharmony_ci              selected: this.pickDialogIndex,
283e41f4b71Sopenharmony_ci              canLoop: false,
284e41f4b71Sopenharmony_ci              disappearTextStyle: { color: Color.Red, font: { size: 10, weight: FontWeight.Lighter } },
285e41f4b71Sopenharmony_ci              textStyle: { color: Color.Black, font: { size: 12, weight: FontWeight.Normal } },
286e41f4b71Sopenharmony_ci              selectedTextStyle: { color: Color.Blue, font: { size: 12, weight: FontWeight.Bolder } },
287e41f4b71Sopenharmony_ci              onAccept: (result: TextPickerResult) => {
288e41f4b71Sopenharmony_ci                this.currentFormKey = result.value[0] + "#" + result.value[1];
289e41f4b71Sopenharmony_ci                this.pickDialogIndex = result.index[0]
290e41f4b71Sopenharmony_ci                console.info(`TextPickerDialog onAccept: ${this.currentFormKey}, ${this.pickDialogIndex}`);
291e41f4b71Sopenharmony_ci                if (!this.formCardHashMap.hasKey(this.currentFormKey)) {
292e41f4b71Sopenharmony_ci                  console.error(`invalid formItemInfo by form key`)
293e41f4b71Sopenharmony_ci                  return;
294e41f4b71Sopenharmony_ci                }
295e41f4b71Sopenharmony_ci                this.showForm = true;
296e41f4b71Sopenharmony_ci                this.focusFormInfo = this.formCardHashMap.get(this.currentFormKey);
297e41f4b71Sopenharmony_ci              },
298e41f4b71Sopenharmony_ci              onCancel: () => {
299e41f4b71Sopenharmony_ci                console.info("TextPickerDialog : onCancel()")
300e41f4b71Sopenharmony_ci              },
301e41f4b71Sopenharmony_ci              onChange: (result: TextPickerResult) => {
302e41f4b71Sopenharmony_ci                this.pickerBtnMsg = result.value[0] + '#' + result.value[1];
303e41f4b71Sopenharmony_ci                console.info("TextPickerDialog:onChange:" + this.pickerBtnMsg)
304e41f4b71Sopenharmony_ci              }
305e41f4b71Sopenharmony_ci            })
306e41f4b71Sopenharmony_ci          })
307e41f4b71Sopenharmony_ci          .margin({ left: 10 })
308e41f4b71Sopenharmony_ci      }
309e41f4b71Sopenharmony_ci      .margin({ left: 10 })
310e41f4b71Sopenharmony_ci
311e41f4b71Sopenharmony_ci      Divider().vertical(false).color(Color.Black).lineCap(LineCapStyle.Butt).margin({ top: 10, bottom: 10 })
312e41f4b71Sopenharmony_ci
313e41f4b71Sopenharmony_ci      if(this.showForm){
314e41f4b71Sopenharmony_ci        Text(this.pickerBtnMsg)
315e41f4b71Sopenharmony_ci          .margin({ top: 10, bottom: 10 })
316e41f4b71Sopenharmony_ci      }
317e41f4b71Sopenharmony_ci
318e41f4b71Sopenharmony_ci      if (this.showForm) {
319e41f4b71Sopenharmony_ci        Text('formId: ' + this.selectFormId)
320e41f4b71Sopenharmony_ci          .margin({ top: 10, bottom: 10 })
321e41f4b71Sopenharmony_ci
322e41f4b71Sopenharmony_ci        // FormComponent
323e41f4b71Sopenharmony_ci        FormComponent({
324e41f4b71Sopenharmony_ci          id: Number.parseInt(this.selectFormId),
325e41f4b71Sopenharmony_ci          name: this.focusFormInfo.name,
326e41f4b71Sopenharmony_ci          bundle: this.focusFormInfo.bundleName,
327e41f4b71Sopenharmony_ci          ability: this.focusFormInfo.abilityName,
328e41f4b71Sopenharmony_ci          module: this.focusFormInfo.moduleName,
329e41f4b71Sopenharmony_ci          dimension: this.focusFormInfo.defaultDimension,
330e41f4b71Sopenharmony_ci          temporary: false,
331e41f4b71Sopenharmony_ci        })
332e41f4b71Sopenharmony_ci          .size({
333e41f4b71Sopenharmony_ci            width: formHostSample.FORM_SIZE[this.focusFormInfo.defaultDimension - 1][0],
334e41f4b71Sopenharmony_ci            height: formHostSample.FORM_SIZE[this.focusFormInfo.defaultDimension - 1][1],
335e41f4b71Sopenharmony_ci          })
336e41f4b71Sopenharmony_ci          .borderColor(Color.Black)
337e41f4b71Sopenharmony_ci          .borderRadius(10)
338e41f4b71Sopenharmony_ci          .borderWidth(1)
339e41f4b71Sopenharmony_ci          .onAcquired((form: FormCallbackInfo) => {
340e41f4b71Sopenharmony_ci            console.log(`onAcquired: ${JSON.stringify(form)}`)
341e41f4b71Sopenharmony_ci            this.selectFormId = form.id.toString();
342e41f4b71Sopenharmony_ci            this.formIds.add(this.selectFormId);
343e41f4b71Sopenharmony_ci          })
344e41f4b71Sopenharmony_ci          .onRouter(() => {
345e41f4b71Sopenharmony_ci            console.log(`onRouter`)
346e41f4b71Sopenharmony_ci          })
347e41f4b71Sopenharmony_ci          .onError((error) => {
348e41f4b71Sopenharmony_ci            console.error(`onError: ${JSON.stringify(error)}`)
349e41f4b71Sopenharmony_ci            this.showForm = false;
350e41f4b71Sopenharmony_ci          })
351e41f4b71Sopenharmony_ci          .onUninstall((info: FormCallbackInfo) => {
352e41f4b71Sopenharmony_ci            this.showForm = false;
353e41f4b71Sopenharmony_ci            console.error(`onUninstall: ${JSON.stringify(info)}`)
354e41f4b71Sopenharmony_ci            this.formIds.remove(this.selectFormId);
355e41f4b71Sopenharmony_ci          })
356e41f4b71Sopenharmony_ci
357e41f4b71Sopenharmony_ci        // A select list that displays some formHost APIs
358e41f4b71Sopenharmony_ci        Row() {
359e41f4b71Sopenharmony_ci          Select([{ value: $r('app.string.deleteForm') },
360e41f4b71Sopenharmony_ci            { value: $r('app.string.updateForm') },
361e41f4b71Sopenharmony_ci            { value: $r('app.string.visibleForms') },
362e41f4b71Sopenharmony_ci            { value: $r('app.string.invisibleForms') },
363e41f4b71Sopenharmony_ci            { value: $r('app.string.enableFormsUpdate') },
364e41f4b71Sopenharmony_ci            { value: $r('app.string.disableFormsUpdate') },
365e41f4b71Sopenharmony_ci          ])
366e41f4b71Sopenharmony_ci            .selected(this.index)
367e41f4b71Sopenharmony_ci            .value(this.operation)
368e41f4b71Sopenharmony_ci            .font({ size: 16, weight: 500 })
369e41f4b71Sopenharmony_ci            .fontColor('#182431')
370e41f4b71Sopenharmony_ci            .selectedOptionFont({ size: 16, weight: 400 })
371e41f4b71Sopenharmony_ci            .optionFont({ size: 16, weight: 400 })
372e41f4b71Sopenharmony_ci            .space(this.space)
373e41f4b71Sopenharmony_ci            .arrowPosition(this.arrowPosition)
374e41f4b71Sopenharmony_ci            .menuAlign(MenuAlignType.START, { dx: 0, dy: 0 })
375e41f4b71Sopenharmony_ci            .optionWidth(200)
376e41f4b71Sopenharmony_ci            .optionHeight(300)
377e41f4b71Sopenharmony_ci            .onSelect((index: number, text?: string | Resource) => {
378e41f4b71Sopenharmony_ci              console.info('Select:' + index)
379e41f4b71Sopenharmony_ci              this.index = index;
380e41f4b71Sopenharmony_ci              if (text) {
381e41f4b71Sopenharmony_ci                this.operation = text;
382e41f4b71Sopenharmony_ci              }
383e41f4b71Sopenharmony_ci            })
384e41f4b71Sopenharmony_ci
385e41f4b71Sopenharmony_ci          // Operate the widget based on what selected in the select list.
386e41f4b71Sopenharmony_ci          Button($r('app.string.execute'), {
387e41f4b71Sopenharmony_ci            type: ButtonType.Capsule
388e41f4b71Sopenharmony_ci          })
389e41f4b71Sopenharmony_ci            .fontSize(16)
390e41f4b71Sopenharmony_ci            .onClick(() => {
391e41f4b71Sopenharmony_ci              switch (this.index) {
392e41f4b71Sopenharmony_ci                case 0:
393e41f4b71Sopenharmony_ci                  try {
394e41f4b71Sopenharmony_ci                    formHost.deleteForm(this.selectFormId, (error: BusinessError) => {
395e41f4b71Sopenharmony_ci                      if (error) {
396e41f4b71Sopenharmony_ci                        console.error(`deleteForm error, code: ${error.code}, message: ${error.message}`);
397e41f4b71Sopenharmony_ci                      } else {
398e41f4b71Sopenharmony_ci                        console.log('formHost deleteForm success');
399e41f4b71Sopenharmony_ci                      }
400e41f4b71Sopenharmony_ci                    });
401e41f4b71Sopenharmony_ci                  } catch (error) {
402e41f4b71Sopenharmony_ci                    console.error(`deleteForm catch error, code: ${(error as BusinessError).code}, message: ${(error as BusinessError).message}`);
403e41f4b71Sopenharmony_ci                  }
404e41f4b71Sopenharmony_ci                  this.showForm = false;
405e41f4b71Sopenharmony_ci                  this.selectFormId = '';
406e41f4b71Sopenharmony_ci                  break;
407e41f4b71Sopenharmony_ci                case 1:
408e41f4b71Sopenharmony_ci                  try {
409e41f4b71Sopenharmony_ci                    formHost.requestForm(this.selectFormId, (error: BusinessError) => {
410e41f4b71Sopenharmony_ci                      if (error) {
411e41f4b71Sopenharmony_ci                        console.error(`requestForm error, code: ${error.code}, message: ${error.message}`);
412e41f4b71Sopenharmony_ci                      }
413e41f4b71Sopenharmony_ci                    });
414e41f4b71Sopenharmony_ci                  } catch (error) {
415e41f4b71Sopenharmony_ci                    console.error(`requestForm catch error, code: ${(error as BusinessError).code}, message: ${(error as BusinessError).message}`);
416e41f4b71Sopenharmony_ci                  }
417e41f4b71Sopenharmony_ci                  break;
418e41f4b71Sopenharmony_ci                case 2:
419e41f4b71Sopenharmony_ci                  try {
420e41f4b71Sopenharmony_ci                    formHost.notifyVisibleForms([this.selectFormId], (error: BusinessError) => {
421e41f4b71Sopenharmony_ci                      if (error) {
422e41f4b71Sopenharmony_ci                        console.error(`notifyVisibleForms error, code: ${error.code}, message: ${error.message}`);
423e41f4b71Sopenharmony_ci                      } else {
424e41f4b71Sopenharmony_ci                        console.info('notifyVisibleForms success');
425e41f4b71Sopenharmony_ci                      }
426e41f4b71Sopenharmony_ci                    });
427e41f4b71Sopenharmony_ci                  } catch (error) {
428e41f4b71Sopenharmony_ci                    console.error(`notifyVisibleForms catch error, code: ${(error as BusinessError).code}, message: ${(error as BusinessError).message}`);
429e41f4b71Sopenharmony_ci                  }
430e41f4b71Sopenharmony_ci                  break;
431e41f4b71Sopenharmony_ci                case 3:
432e41f4b71Sopenharmony_ci                  try {
433e41f4b71Sopenharmony_ci                    formHost.notifyInvisibleForms([this.selectFormId], (error: BusinessError) => {
434e41f4b71Sopenharmony_ci                      if (error) {
435e41f4b71Sopenharmony_ci                        console.error(`notifyInvisibleForms error, code: ${error.code}, message: ${error.message}`);
436e41f4b71Sopenharmony_ci                      } else {
437e41f4b71Sopenharmony_ci                        console.info('notifyInvisibleForms success');
438e41f4b71Sopenharmony_ci                      }
439e41f4b71Sopenharmony_ci                    });
440e41f4b71Sopenharmony_ci                  } catch (error) {
441e41f4b71Sopenharmony_ci                    console.error(`notifyInvisibleForms catch error, code: ${(error as BusinessError).code}, message: ${(error as BusinessError).message}`);
442e41f4b71Sopenharmony_ci                  }
443e41f4b71Sopenharmony_ci                  break;
444e41f4b71Sopenharmony_ci                case 4:
445e41f4b71Sopenharmony_ci                  try {
446e41f4b71Sopenharmony_ci                    formHost.enableFormsUpdate([this.selectFormId], (error: BusinessError) => {
447e41f4b71Sopenharmony_ci                      if (error) {
448e41f4b71Sopenharmony_ci                        console.error(`enableFormsUpdate error, code: ${error.code}, message: ${error.message}`);
449e41f4b71Sopenharmony_ci                      }
450e41f4b71Sopenharmony_ci                    });
451e41f4b71Sopenharmony_ci                  } catch (error) {
452e41f4b71Sopenharmony_ci                    console.error(`enableFormsUpdate catch error, code: ${(error as BusinessError).code}, message: ${(error as BusinessError).message}`);
453e41f4b71Sopenharmony_ci                  }
454e41f4b71Sopenharmony_ci                  break;
455e41f4b71Sopenharmony_ci                case 5:
456e41f4b71Sopenharmony_ci                  try {
457e41f4b71Sopenharmony_ci                    formHost.disableFormsUpdate([this.selectFormId], (error: BusinessError) => {
458e41f4b71Sopenharmony_ci                      if (error) {
459e41f4b71Sopenharmony_ci                        console.error(`disableFormsUpdate error, code: ${error.code}, message: ${error.message}`);
460e41f4b71Sopenharmony_ci                      } else {
461e41f4b71Sopenharmony_ci                        console.info('disableFormsUpdate success');
462e41f4b71Sopenharmony_ci                      }
463e41f4b71Sopenharmony_ci                    });
464e41f4b71Sopenharmony_ci                  } catch (error) {
465e41f4b71Sopenharmony_ci                    console.error(`disableFormsUpdate catch error, code: ${(error as BusinessError).code}, message: ${(error as BusinessError).message}`);
466e41f4b71Sopenharmony_ci                  }
467e41f4b71Sopenharmony_ci                  break;
468e41f4b71Sopenharmony_ci              }
469e41f4b71Sopenharmony_ci            })
470e41f4b71Sopenharmony_ci        }
471e41f4b71Sopenharmony_ci        .margin({
472e41f4b71Sopenharmony_ci          top: 20,
473e41f4b71Sopenharmony_ci          bottom: 10
474e41f4b71Sopenharmony_ci        })
475e41f4b71Sopenharmony_ci      }
476e41f4b71Sopenharmony_ci    }
477e41f4b71Sopenharmony_ci  }
478e41f4b71Sopenharmony_ci}
479e41f4b71Sopenharmony_ci```
480e41f4b71Sopenharmony_ci
481e41f4b71Sopenharmony_ci![screenshot](./figures/widget-host-development-guide-2.jpeg)
482