1# System Window Development (Stage Model Only)
2
3## Overview
4
5In the stage model, system applications are allowed to create and manage system windows, including the volume bar, wallpaper, notification panel, status bar, and navigation bar. For details about the supported system window types, see [WindowType](../reference/apis-arkui/js-apis-window.md#windowtype7).
6
7When a window is displayed, hidden, or switched, an animation is usually used to smooth the interaction process.
8
9The animation is the default behavior for application windows. You do not need to set or modify the code.
10
11However, you can customize an animation to be played during the display or hiding of a system window.
12
13> **NOTE**
14>
15> This document involves the use of system APIs. You must use the full SDK for development.<!--Del--> For details, see [Guide to Switching to Full SDK](../faqs/full-sdk-switch-guide.md).<!--DelEnd-->
16
17
18## Available APIs
19
20For details about more APIs, see [Window](../reference/apis-arkui/js-apis-window-sys.md).
21
22| Instance           | API                                                      | Description                                                        |
23| ----------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
24| Window static method   | createWindow(config: Configuration, callback: AsyncCallback\<Window>): void | Creates a subwindow or system window.<br>**config**: parameters used for creating the window.    |
25| Window            | resize(width: number, height: number, callback: AsyncCallback&lt;void&gt;): void | Changes the window size.                                          |
26| Window            | moveWindowTo(x: number, y: number, callback: AsyncCallback&lt;void&gt;): void | Moves this window.                                          |
27| Window            | setUIContent(path: string, callback: AsyncCallback&lt;void&gt;): void | Loads the content of a page, with its path in the current project specified, to this window.<br>**path**: path of the page from which the content will be loaded. The path is configured in the **main_pages.json** file of the project in the stage model.                                    |
28| Window            | showWindow(callback: AsyncCallback\<void>): void             | Shows this window.                                              |
29| Window            | on(type: 'touchOutside', callback: Callback&lt;void&gt;): void | Subscribes to touch events outside this window.                          |
30| Window            | hide (callback: AsyncCallback\<void>): void                  | Hides this window. This is a system API.                            |
31| Window            | destroyWindow(callback: AsyncCallback&lt;void&gt;): void     | Destroys this window.                                              |
32| Window            | getTransitionController(): TransitionController              | Obtains the transition animation controller. This is a system API.                  |
33| TransitionContext | completeTransition(isCompleted: boolean): void               | Completes the transition. This API can be called only after [animateTo()](../reference/apis-arkui/arkui-ts/ts-explicit-animation.md) is executed. This is a system API.|
34| Window            | showWithAnimation(callback: AsyncCallback\<void>): void      | Shows this window and plays an animation during the process. This is a system API.            |
35| Window            | hideWithAnimation(callback: AsyncCallback\<void>): void      | Hides this window and plays an animation during the process. This is a system API.            |
36
37## Developing a System Window
38
39This section uses the volume bar as an example to describe how to develop a system window.
40
41### How to Develop
42
43
441. Create a system window.
45
46   In [ServiceExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-serviceExtensionContext-sys.md), call **window.createWindow** to create a system window of the volume bar type.
47
482. Set the properties of the system window.
49
50   After the volume bar window is created, you can change its size and position, and set its properties such as the background color and brightness.
51
523. Load content to and show the system window.
53
54   You can call **setUIContent** to load content to the volume bar window and **showWindow** to show the window.
55
564. Hide or destroy the system window.
57
58   When the volume bar window is no longer needed, you can call **hide** or **destroyWindow** to hide or destroy it.
59
60```ts
61import { Want, ServiceExtensionAbility } from '@kit.AbilityKit';
62import { window } from '@kit.ArkUI';
63import { BusinessError } from '@kit.BasicServicesKit';
64
65export default class ServiceExtensionAbility1 extends ServiceExtensionAbility {
66  onCreate(want: Want) {
67    // 1. Create a volume bar window.
68    let windowClass: window.Window | null = null;
69    let config: window.Configuration = {
70      name: "volume", windowType: window.WindowType.TYPE_VOLUME_OVERLAY, ctx: this.context
71    };
72    window.createWindow(config, (err: BusinessError, data) => {
73      let errCode: number = err.code;
74      if (errCode) {
75        console.error('Failed to create the volume window. Cause:' + JSON.stringify(err));
76        return;
77      }
78      console.info('Succeeded in creating the volume window.')
79      windowClass = data;
80      // 2. Change the size and position of the volume bar window, or set its properties such as the background color and brightness.
81      windowClass.moveWindowTo(300, 300, (err: BusinessError) => {
82        let errCode: number = err.code;
83        if (errCode) {
84          console.error('Failed to move the window. Cause:' + JSON.stringify(err));
85          return;
86        }
87        console.info('Succeeded in moving the window.');
88      });
89      windowClass.resize(500, 500, (err: BusinessError) => {
90        let errCode: number = err.code;
91        if (errCode) {
92          console.error('Failed to change the window size. Cause:' + JSON.stringify(err));
93          return;
94        }
95        console.info('Succeeded in changing the window size.');
96      });
97      // 3.1 Load content to the volume bar window.
98      windowClass.setUIContent("pages/page_volume", (err: BusinessError) => {
99        let errCode: number = err.code;
100        if (errCode) {
101          console.error('Failed to load the content. Cause:' + JSON.stringify(err));
102          return;
103        }
104        console.info('Succeeded in loading the content.');
105        // 3.2 Show the volume bar window.
106        (windowClass as window.Window).showWindow((err: BusinessError) => {
107          let errCode: number = err.code;
108          if (errCode) {
109            console.error('Failed to show the window. Cause:' + JSON.stringify(err));
110            return;
111          }
112          console.info('Succeeded in showing the window.');
113        });
114      });
115      // 4. Hide or destroy the volume bar window.
116      // Hide the volume bar window when a touch event outside the window is detected.
117      windowClass.on('touchOutside', () => {
118        console.info('touch outside');
119        (windowClass as window.Window).hide((err: BusinessError) => {
120          let errCode: number = err.code;
121          if (errCode) {
122            console.error('Failed to hide the window. Cause: ' + JSON.stringify(err));
123            return;
124          }
125          console.info('Succeeded in hiding the window.');
126        });
127      });
128    });
129  }
130};
131```
132
133## Customizing an Animation to Be Played During the Display or Hiding of a System Window
134
135You can determine whether to play an animation when a system window is showing or hiding.
136
137### How to Develop
138
1391. Obtain the transition animation controller.
140
141   Call **getTransitionController** to obtain the controller, which completes subsequent animation operations.
142
1432. Configure the animation to be played.
144
145   Call [animateTo()](../reference/apis-arkui/arkui-ts/ts-explicit-animation.md) to configure the animation attributes.
146
1473. Complete the transition.
148
149   Use **completeTransition(true)** to set the completion status of the transition. If **false** is passed in, the transition is canceled.
150
1514. Show or hide the system window and play the animation during the process.
152
153   Call **showWithAnimation** to show the window and play the animation. Call **hideWithAnimation** to hide the window and play the animation.
154
155```ts
156// Import the showWithAnimation and hideWithAnimation methods to the .ts file.
157import { window } from '@kit.ArkUI';
158
159export class AnimationConfig {
160  private animationForShownCallFunc_: Function = undefined;
161  private animationForHiddenCallFunc_: Function = undefined;
162
163  ShowWindowWithCustomAnimation(windowClass: window.Window, callback) {
164    if (!windowClass) {
165      console.error('LOCAL-TEST windowClass is undefined');
166      return false;
167    }
168    this.animationForShownCallFunc_ = callback;
169    // Obtain the transition animation controller.
170    let controller: window.TransitionController = windowClass.getTransitionController();
171    controller.animationForShown = (context: window.TransitionContext)=> {
172      this.animationForShownCallFunc_(context);
173    };
174
175    windowClass.showWithAnimation(()=>{
176      console.info('LOCAL-TEST show with animation success');
177    })
178    return true;
179  }
180
181  HideWindowWithCustomAnimation(windowClass: window.Window, callback) {
182    if (!windowClass) {
183      console.error('LOCAL-TEST window is undefined');
184      return false;
185    }
186    this.animationForHiddenCallFunc_ = callback;
187    // Obtain the transition animation controller.
188    let controller: window.TransitionController = windowClass.getTransitionController();
189    controller.animationForHidden = (context : window.TransitionContext) => {
190      this.animationForHiddenCallFunc_(context);
191    };
192
193    windowClass.hideWithAnimation(()=>{
194      console.info('Hide with animation success');
195    })
196    return true;
197  }
198}
199```
200
201```ts
202// In the .ets file, implement the operation of creating the main window.
203import { window } from '@kit.ArkUI';
204import { UIAbility, Want, AbilityConstant, common } from '@kit.AbilityKit';
205import { hilog } from '@kit.PerformanceAnalysisKit'
206
207export default class EntryAbility extends UIAbility {
208  onCreate(want: Want,launchParam:AbilityConstant.LaunchParam) {
209    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
210  }
211
212  onDestroy(): void {
213    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability Destroy');
214  }
215
216  onWindowStageCreate(windowStage:window.WindowStage): void{
217    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
218
219    windowStage.loadContent('pages/transferControllerPage',(err, data)=>{
220      if(err.code){
221        hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause:%{public}s', JSON.stringify(err)??'');
222        return ;
223      }
224      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data:%{public}s', JSON.stringify(data)??'');
225
226    });
227
228    AppStorage.setOrCreate<common.UIAbilityContext>("currentContext",this.context);
229  }
230
231  onWindowStageDestroy(): void{
232    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
233  }
234
235  onForeground(): void{
236    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
237  }
238
239  onBackground(): void{
240    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
241  }
242};
243```
244
245```ts
246// In the xxx.ets file, implement the attribute setting of the subwindow.
247import { window, router } from '@kit.ArkUI';
248import { common } from '@kit.AbilityKit';
249
250@Entry
251@Component
252struct transferCtrlSubWindow {
253  @State message: string = 'transferCtrlSubWindow'
254
255  build() {
256    Column() {
257      Text("close")
258        .fontSize(24)
259        .fontWeight(FontWeight.Normal)
260        .margin({ left: 10, top: 10 })
261      Button() {
262        Text("close")
263          .fontSize(24)
264          .fontSize(FontWeight.Normal)
265      }.width(220).height(68)
266      .margin({ left: 10, top: 10 })
267      .onClick(() => {
268        let subWin = AppStorage.get<window.Window>("TransferSubWindow");
269        subWin?.destroyWindow();
270        AppStorage.setOrCreate<window.Window>("TransferSubWindow", undefined);
271      })
272    }.height('100%').width('100%').backgroundColor('#ff556243').shadow({radius: 30,color: '#ff555555',offsetX: 15,offsetY: 15})
273  }
274}
275```
276
277```ts
278// In the .ets file, implement the operations of creating a subwindow and displaying or hiding a window.
279import { window, router } from '@kit.ArkUI';
280import { common, Want } from '@kit.AbilityKit';
281import { BusinessError } from '@kit.BasicServicesKit';
282import { AnimationConfig } from '../entryability/AnimationConfig';
283
284@Entry
285@Component
286struct Index {
287  @State message: string = 'transferControllerWindow';
288
289  private animationConfig_?:AnimationConfig = undefined;
290  private subWindow_?:window.Window = undefined;
291
292  aboutToAppear(){
293    if(!this.animationConfig_){
294      this.animationConfig_ = new AnimationConfig();
295    }
296  }
297
298  private CreateTransferSubWindow(){
299    if(this.subWindow_){
300      this.subWindow_ = AppStorage.get<window.Window>("TransferSubWindow");
301      if(!this.subWindow_){
302        this.subWindow_ = undefined;
303      }
304    }
305    let context = AppStorage.get<common.UIAbilityContext>("currentContext");
306    console.log('LOCAL-TEST try to CreateTransferSubWindow');
307    let windowConfig:window.Configuration = {
308      name : "systemTypeWindow",
309      windowType : window.WindowType.TYPE_FLOAT,
310      ctx : context,
311    };
312    let promise = window?.createWindow(windowConfig);
313    promise?.then(async(subWin) => {
314      this.subWindow_ = subWin;
315      AppStorage.setOrCreate<window.Window>("systemTypeWindow", subWin);
316      await subWin.setUIContent("pages/transferCtrlSubWindow",()=>{});
317      await subWin.moveWindowTo(100,100);
318      await subWin.resize(200,200);
319    }).catch((err:Error)=>{
320      console.log('LOCAL-TEST createSubWindow err:' + JSON.stringify(err));
321    })
322  }
323  private ShowSUBWindow(){
324    if(!this.subWindow_){
325      console.log('LOCAL-TEST this.subWindow_is null');
326      return ;
327    }
328    let animationConfig = new AnimationConfig();
329    let systemTypeWindow = window.findWindow("systemTypeWindow");
330    console.log("LOCAL-TEST try to ShowWindowWithCustomAnimation");
331    animationConfig.ShowWindowWithCustomAnimation(systemTypeWindow,(context:window.TransitionContext)=>{
332      console.info('LOCAL-TEST start show window animation');
333      let toWindow = context.toWindow;
334      animateTo({
335        duration: 200, // Animation duration
336        tempo: 0.5, // Playback speed.
337        curve: Curve.EaseInOut, // Animation curve.
338        delay: 0, // Animation delay.
339        iterations: 1, // Number of playback times.
340        playMode: PlayMode.Normal // Animation playback mode.
341        onFinish: () => {
342          console.info('LOCAL-TEST onFinish in show animation');
343          context.completeTransition(true);
344        }
345      },() => {
346        let obj: window.TranslateOptions = {
347          x: 100.0,
348          y: 0.0,
349          z: 0.0
350        };
351        try {
352          toWindow.translate(obj); // Set the transition animation.
353        }catch(exception){
354          console.error('Failed to translate. Cause: ' + JSON.stringify(exception));
355        }
356      });
357      console.info('LOCAL-TEST complete transition end');
358    });
359  }
360
361  private HideSUBWindow(){
362    if(!this.subWindow_){
363      console.log('LOCAL-TEST this.subWindow_is null');
364      return ;
365    }
366    let animationConfig = new AnimationConfig();
367    let systemTypeWindow = window.findWindow("systemTypeWindow");
368    console.log("LOCAL-TEST try to HideWindowWithCustomAnimation");
369    animationConfig.HideWindowWithCustomAnimation(systemTypeWindow,(context:window.TransitionContext)=>{
370      console.info('LOCAL-TEST start hide window animation');
371      let toWindow = context.toWindow;
372      animateTo({
373        duration: 200, // Animation duration
374        tempo: 0.5, // Playback speed.
375        curve: Curve.EaseInOut, // Animation curve.
376        delay: 0, // Animation delay.
377        iterations: 1, // Number of playback times.
378        playMode: PlayMode.Normal // Animation playback mode.
379        onFinish: () => {
380          console.info('LOCAL-TEST onFinish in hide animation');
381          context.completeTransition(true);
382        }
383      },() => {
384        let obj: window.TranslateOptions = {
385          x: 500.0,
386          y: 0.0,
387          z: 0.0
388        };
389        try {
390          toWindow.translate(obj); // Set the transition animation.
391        }catch(exception){
392          console.error('Failed to translate. Cause: ' + JSON.stringify(exception));
393        }
394      });
395      console.info('LOCAL-TEST complete transition end');
396    });
397  }
398
399  build() {
400    Column() {
401      Text(this.message)
402        .fontSize(24)
403        .fontWeight(FontWeight.Normal)
404        .margin({left: 10, top: 10})
405
406      Button(){
407        Text("CreateSub")
408          .fontSize(24)
409          .fontWeight(FontWeight.Normal)
410      }.width(220).height(68)
411      .margin({left: 10, top: 10})
412      .onClick(() => {
413        this.CreateTransferSubWindow();
414      })
415
416      Button(){
417        Text("Show")
418          .fontSize(24)
419          .fontWeight(FontWeight.Normal)
420      }.width(220).height(68)
421      .margin({left: 10, top: 10})
422      .onClick(() => {
423        this.ShowSUBWindow();
424      })
425
426      Button(){
427        Text("Hide")
428          .fontSize(24)
429          .fontWeight(FontWeight.Normal)
430      }.width(220).height(68)
431      .margin({left: 10, top: 10})
432      .onClick(() => {
433        this.HideSUBWindow();
434      })
435    }.width('100%').height('100%')
436  }
437}
438```
439