1# Continuous Task (ArkTS)
2
3## Overview
4
5### Introduction
6
7If an application has a perceivable task that needs to run in an extended period of time in the background, it can request a continuous task to prevent itself from being suspended. Examples of continuous tasks include music playback and navigation in the background. Within a continuous task, the application can concurrently request multiple types of tasks and update the task types. When the application operates in the background, the system performs consistency check to ensure that the application is executing the corresponding continuous task. Upon successful request for a continuous task, the notification panel displays the message associated with the task. If the user deletes the message, the system automatically terminates the task.
8
9### Use Cases
10
11The table below lists the types of continuous tasks, which are used in various scenarios. You can select a task type suitable for your case based on the description.
12
13**Table 1** Continuous task types
14| Name| Description| Item| Example Scenario|
15| -------- | -------- | -------- | -------- |
16| DATA_TRANSFER | Data transfer| dataTransfer | Non-hosting uploading and downloading operations, like those occurring in the background of a web browser for data transfer.|
17| AUDIO_PLAYBACK | Audio and video playback| audioPlayback | Audio and video playback in the background; audio and video casting.<br> **NOTE**<br>It can be used in atomic services.|
18| AUDIO_RECORDING | Audio recording| audioRecording | Recording and screen capture in the background.|
19| LOCATION | Positioning and navigation| location | Positioning and navigation.|
20| BLUETOOTH_INTERACTION | Bluetooth-related services| bluetoothInteraction | An application transitions into the background during the process of file transfer using Bluetooth.|
21| MULTI_DEVICE_CONNECTION | Multi-device connection| multiDeviceConnection | Distributed service connection and casting.<br> **NOTE**<br>It can be used in atomic services.|
22| <!--DelRow-->WIFI_INTERACTION | WLAN-related services (for system applications only)| wifiInteraction  | An application transitions into the background during the process of file transfer using WLAN.|
23| VOIP<sup>13+</sup> | Audio and video calls| voip  | Chat applications (with audio and video services) transition into the background during audio and video calls.|
24| TASK_KEEPING | Computing task (for 2-in-1 devices only).| taskKeeping  | Antivirus software is running.|
25
26Description of **DATA_TRANSFER**:
27
28- During data transfer, if an application uses the [upload and download agent API](../reference/apis-basic-services-kit/js-apis-request.md) to hand over tasks to the system, the application will be suspended in the background even if it has requested the continuous task of the DATA_TRANSFER type.
29
30- During data transfer, the application needs to update the progress. If the progress is not updated for more than 10 minutes, the continuous task of the DATA_TRANSFER type will be canceled. For details about how to update the progress, see the example in [startBackgroundRunning()](../reference/apis-backgroundtasks-kit/js-apis-resourceschedule-backgroundTaskManager.md#backgroundtaskmanagerstartbackgroundrunning12).
31
32Description of **AUDIO_PLAYBACK**:
33
34- To implement background playback through **AUDIO_PLAYBACK**, you must use the [AVSession](../media/avsession/avsession-overview.md) for audio and video development.
35
36- Casting audio and video involves transmitting content from one device to another for playback purposes. If the application transitions to the background while casting, the continuous task checks the audio and video playback and casting services. The task will persist as long as either the audio and video playback or casting service is running properly.
37
38### Constraints
39
40**Ability restrictions**: In the stage model, only the UIAbility can request continuous tasks. In the FA model, only the ServiceAbility can request continuous tasks. Continuous tasks can be requested by the current application on the current device or across devices or by other applications. However, the capability to make cross-device or cross-application requests is restricted to system applications.
41
42**Quantity restrictions**: A UIAbility (ServiceAbility in the FA model) can request only one continuous task at a time. If a UIAbility has a running continuous task, it can request another one only after the running task is finished. If an application needs to request multiple continuous tasks at the same time, it must create multiple UIAbilities. After a UIAbility requests a continuous task, all the processes of the application are not suspended.
43
44**Running restrictions**:
45
46- If an application requests a continuous task but does not carry out the relevant service, the system imposes restrictions on the application. For example, if the system detects that an application has requested a continuous task of the AUDIO_PLAYBACK type but does not play audio, the system cancels the continuous task.
47
48- If an application requests a continuous task but carries out a service that does not match the requested type, the system imposes restrictions on the application. For example, if the system detects that an application requests a continuous task of the AUDIO_PLAYBACK type, but the application is playing audio (corresponding to the AUDIO_PLAYBACK type) and recording (corresponding to the AUDIO_RECORDING type), the system enforces management measures.
49
50- When an application's operations are completed after a continuous task request, the system imposes restrictions on the application.
51
52- If the background load of the process that runs a continuous task is higher than the corresponding typical load for a long period of time, the system performs certain control.
53
54> **NOTE**
55>
56> The application shall proactively cancel a continuous task when it is finished. Otherwise, the system will forcibly cancel the task. For example, when a user taps the UI to pause music playback, the application must cancel the continuous task in a timely manner. When the user taps the UI again to continue music playback, the application needs to request a continuous task.
57>
58> If an application that plays an audio in the background is [interrupted](../media/audio/audio-playback-concurrency.md), the system automatically detects and stops the continuous task. The application must request a continuous task again to restart the playback.
59>
60> When an application that plays audio in the background stops a continuous task, it must suspend or stop the audio stream. Otherwise, the application will be forcibly terminated by the system.
61
62## Available APIs
63
64The table below uses promise as an example to describe the APIs used for developing continuous tasks. For details about more APIs and their usage, see [Background Task Management](../reference/apis-backgroundtasks-kit/js-apis-resourceschedule-backgroundTaskManager.md).
65
66**Table 2** Main APIs for continuous tasks
67
68| API| Description|
69| -------- | -------- |
70| startBackgroundRunning(context: Context, bgMode: BackgroundMode, wantAgent: [WantAgent](../reference/apis-ability-kit/js-apis-app-ability-wantAgent.md)): Promise&lt;void&gt; | Requests a continuous task.|
71| stopBackgroundRunning(context: Context): Promise&lt;void&gt; | Cancels a continuous task.|
72
73## How to Develop
74
75The following walks you through how to request a continuous task for recording to implement the following functions:
76
77- When a user touches **Request Continuous Task**, the application requests a continuous task for recording, and a message is displayed in the notification bar, indicating that a recording task is running.
78
79- When a user touches **Cancel Continuous Task**, the application cancels the continuous task, and the notification message is removed.
80
81### Stage Model
82
831. Declare the **ohos.permission.KEEP_BACKGROUND_RUNNING** permission. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md).
84
852. Declare the continuous task type.
86
87   Declare the type of the continuous task for the target UIAbility in the **module.json5** file. Set the corresponding [configuration item](continuous-task.md#use-cases) in the configuration file.
88
89   ```json
90    "module": {
91        "abilities": [
92            {
93                "backgroundModes": [
94                 // Configuration item of the continuous task type
95                "audioRecording"
96                ]
97            }
98        ],
99        // ...
100    }
101   ```
102
1033. Import the modules.
104
105   Import the modules related to continuous tasks: @ohos.resourceschedule.backgroundTaskManager and @ohos.app.ability.wantAgent. Import other modules based on the project requirements.
106
107   ```ts
108    import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
109    import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
110    import { window } from '@kit.ArkUI';
111    import { rpc } from '@kit.IPCKit'
112    import { BusinessError } from '@kit.BasicServicesKit';
113    import { wantAgent, WantAgent } from '@kit.AbilityKit';
114   ```
115
1164. Request and cancel a continuous task.
117
118   The code snippet below shows how an application requests a continuous task for itself.
119
120   ```ts
121    @Entry
122    @Component
123    struct Index {
124      @State message: string = 'ContinuousTask';
125     // Use getContext to obtain the context of the UIAbility for the page.
126      private context: Context = getContext(this);
127
128      startContinuousTask() {
129        let wantAgentInfo: wantAgent.WantAgentInfo = {
130          // List of operations to be executed after the notification is clicked.
131          // Add the bundleName and abilityName of the application to start.
132          wants: [
133            {
134              bundleName: "com.example.myapplication",
135              abilityName: "MainAbility"
136            }
137          ],
138          // Specify the action to perform (starting the ability) after the notification message is clicked.
139          actionType: wantAgent.OperationType.START_ABILITY,
140          // Custom request code.
141          requestCode: 0,
142          // Execution attribute of the operation to perform after the notification is clicked.
143          actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
144        };
145
146        try {
147          // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module.
148          wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {
149            try {
150              let list: Array<string> = ["audioRecording"];
151              backgroundTaskManager.startBackgroundRunning(this.context, list, wantAgentObj).then((res: backgroundTaskManager.ContinuousTaskNotification) => {
152                console.info("Operation startBackgroundRunning succeeded");
153                // Execute the continuous task logic, for example, recording.
154              }).catch((error: BusinessError) => {
155                console.error(`Failed to Operation startBackgroundRunning. code is ${error.code} message is ${error.message}`);
156              });
157            } catch (error) {
158              console.error(`Failed to Operation startBackgroundRunning. code is ${(error as BusinessError).code} message is ${(error as BusinessError).message}`);
159            }
160          });
161        } catch (error) {
162          console.error(`Failed to Operation getWantAgent. code is ${(error as BusinessError).code} message is ${(error as BusinessError).message}`);
163        }
164      }
165
166      stopContinuousTask() {
167         backgroundTaskManager.stopBackgroundRunning(this.context).then(() => {
168           console.info(`Succeeded in operationing stopBackgroundRunning.`);
169         }).catch((err: BusinessError) => {
170           console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
171         });
172      }
173
174      build() {
175        Row() {
176          Column() {
177            Text("Index")
178              .fontSize(50)
179              .fontWeight(FontWeight.Bold)
180
181           Button() {
182              Text('Request continuous task').fontSize(25).fontWeight(FontWeight.Bold)
183            }
184            .type(ButtonType.Capsule)
185            .margin({ top: 10 })
186            .backgroundColor('#0D9FFB')
187            .width(250)
188            .height(40)
189            .onClick(() => {
190              // Request a continuous task by clicking a button.
191              this.startContinuousTask();
192            })
193
194            Button() {
195              Text('Cancel continuous task').fontSize (25).fontWeight (FontWeight.Bold)
196            }
197            .type(ButtonType.Capsule)
198            .margin({ top: 10 })
199            .backgroundColor('#0D9FFB')
200            .width(250)
201            .height(40)
202            .onClick(() => {
203              // Stop the continuous task.
204
205              // Cancel the continuous task by clicking a button.
206              this.stopContinuousTask();
207            })
208          }
209          .width('100%')
210        }
211        .height('100%')
212      }
213    }
214   ```
215   <!--Del-->
216
217   The code snippet below shows how an application requests a continuous task across devices or applications. When a continuous task is executed across devices or applications in the background, the UIAbility can be created and run in the background in call mode. For details, see [Using Call to Implement UIAbility Interaction (for System Applications Only)](../application-models/uiability-intra-device-interaction.md#using-call-to-implement-uiability-interaction-for-system-applications-only) and [Using Cross-Device Call](../application-models/hop-multi-device-collaboration.md#using-cross-device-call).
218
219   ```ts
220    const MSG_SEND_METHOD: string = 'CallSendMsg'
221
222    let mContext: Context;
223
224    function startContinuousTask() {
225      let wantAgentInfo : wantAgent.WantAgentInfo = {
226        // List of operations to be executed after the notification is clicked.
227        wants: [
228          {
229            bundleName: "com.example.myapplication",
230            abilityName: "com.example.myapplication.MainAbility",
231          }
232        ],
233        // Type of the operation to perform after the notification is clicked.
234        actionType: wantAgent.OperationType.START_ABILITY,
235        // Custom request code.
236        requestCode: 0,
237        // Execution attribute of the operation to perform after the notification is clicked.
238        actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
239      };
240
241      // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module.
242      wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj : WantAgent) => {
243        backgroundTaskManager.startBackgroundRunning(mContext,
244          backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
245          console.info(`Succeeded in operationing startBackgroundRunning.`);
246        }).catch((err: BusinessError) => {
247          console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
248        });
249      });
250    }
251
252    function stopContinuousTask() {
253      backgroundTaskManager.stopBackgroundRunning(mContext).then(() => {
254        console.info(`Succeeded in operationing stopBackgroundRunning.`);
255      }).catch((err: BusinessError) => {
256        console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
257      });
258    }
259
260    class MyParcelable implements rpc.Parcelable {
261      num: number = 0;
262      str: string = '';
263
264      constructor(num: number, string: string) {
265        this.num = num;
266        this.str = string;
267      }
268
269      marshalling(messageSequence: rpc.MessageSequence) {
270        messageSequence.writeInt(this.num);
271        messageSequence.writeString(this.str);
272        return true;
273      }
274
275      unmarshalling(messageSequence: rpc.MessageSequence) {
276        this.num = messageSequence.readInt();
277        this.str = messageSequence.readString();
278        return true;
279      }
280    }
281
282    function sendMsgCallback(data: rpc.MessageSequence) {
283      console.info('BgTaskAbility funcCallBack is called ' + data);
284      let receivedData: MyParcelable = new MyParcelable(0, '');
285      data.readParcelable(receivedData);
286      console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`);
287      // You can execute different methods based on the str value in the sequenceable data sent by the caller object.
288      if (receivedData.str === 'start_bgtask') {
289        // Request a continuous task.
290        startContinuousTask();
291      } else if (receivedData.str === 'stop_bgtask') {
292        // Cancel the continuous task.
293        stopContinuousTask();
294      }
295      return new MyParcelable(10, 'Callee test');
296    }
297
298    export default class BgTaskAbility extends UIAbility {
299      // Create an ability.
300      onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
301        console.info("[Demo] BgTaskAbility onCreate");
302        try {
303          this.callee.on(MSG_SEND_METHOD, sendMsgCallback)
304        } catch (error) {
305          console.error(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`);
306        }
307        mContext = this.context;
308      }
309
310      // Destroy an ability.
311      onDestroy() {
312        console.info('[Demo] BgTaskAbility onDestroy');
313      }
314
315      onWindowStageCreate(windowStage: window.WindowStage) {
316        console.info('[Demo] BgTaskAbility onWindowStageCreate');
317
318        windowStage.loadContent('pages/Index', (error, data) => {
319          if (error.code) {
320            console.error(`load content failed with error ${JSON.stringify(error)}`);
321            return;
322          }
323          console.info(`load content succeed with data ${JSON.stringify(data)}`);
324        });
325      }
326
327      onWindowStageDestroy() {
328        console.info('[Demo] BgTaskAbility onWindowStageDestroy');
329      }
330
331      onForeground() {
332        console.info('[Demo] BgTaskAbility onForeground');
333      }
334
335      onBackground() {
336        console.info('[Demo] BgTaskAbility onBackground');
337      }
338    };
339   ```
340
341   <!--DelEnd-->
342
343<!--Del-->
344### FA Model
345
3461. Start and connect to a ServiceAbility.
347
348   - If no user interaction is required, use **startAbility()** to start the ServiceAbility. For details, see [ServiceAbility Component](../application-models/serviceability-overview.md). In the **onStart** callback of the ServiceAbility, call the APIs to request and cancel continuous tasks.
349
350   - If user interaction is required (for example, in music playback scenarios), use **connectAbility()** to start and connect to the ServiceAbility. For details, see [ServiceAbility Component](../application-models/serviceability-overview.md). After obtaining the agent of the ServiceAbility, the application can communicate with the ServiceAbility and control the request and cancellation of continuous tasks.
351
3522. Configure permissions and declare the continuous task type.
353
354   Declare the **ohos.permission.KEEP_BACKGROUND_RUNNING** permission in the **config.json** file. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md). In addition, declare the continuous task type for the ServiceAbility.
355
356   ```json
357   "module": {
358       "package": "com.example.myapplication",
359       "abilities": [
360           {
361               "backgroundModes": [
362               "audioRecording",
363               ], // Background mode
364               "type": "service"  // The ability type is Service.
365           }
366       ],
367       "reqPermissions": [
368           {
369               "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" // Continuous task permission
370           }
371       ]
372   }
373   ```
374
3753. Import the modules.
376
377   ```js
378    import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
379    import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
380    import { window } from '@kit.ArkUI';
381    import { rpc } from '@kit.IPCKit'
382    import { BusinessError } from '@kit.BasicServicesKit';
383    import { wantAgent, WantAgent } from '@kit.AbilityKit';
384   ```
385
3864. Request and cancel a continuous task. In the ServiceAbility, call [startBackgroundRunning](#available-apis) and [stopBackgroundRunning](#available-apis) to request and cancel a continuous task. Use JavaScript code to implement this scenario.
387
388   ```js
389    function startContinuousTask() {
390      let wantAgentInfo: wantAgent.WantAgentInfo = {
391        // List of operations to be executed after the notification is clicked.
392        wants: [
393          {
394            bundleName: "com.example.myapplication",
395            abilityName: "com.example.myapplication.MainAbility"
396          }
397        ],
398        // Type of the operation to perform after the notification is clicked.
399        actionType: wantAgent.OperationType.START_ABILITY,
400        // Custom request code.
401        requestCode: 0,
402        // Execution attribute of the operation to perform after the notification is clicked.
403        actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
404      };
405
406      // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module.
407      wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {
408        backgroundTaskManager.startBackgroundRunning(featureAbility.getContext(),
409          backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => {
410          console.info(`Succeeded in operationing startBackgroundRunning.`);
411        }).catch((err: BusinessError) => {
412          console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
413        });
414      });
415    }
416
417    function stopContinuousTask() {
418      backgroundTaskManager.stopBackgroundRunning(featureAbility.getContext()).then(() => {
419        console.info(`Succeeded in operationing stopBackgroundRunning.`);
420      }).catch((err: BusinessError) => {
421        console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);
422      });
423    }
424
425    async function processAsyncJobs() {
426      // Execute the continuous task.
427
428      // After the continuous task is complete, call the API to release resources.
429      stopContinuousTask();
430    }
431
432    let mMyStub: MyStub;
433
434    // Start the service by calling connectAbility().
435    class MyStub extends rpc.RemoteObject {
436      constructor(des: string) {
437        super(des);
438      }
439
440      onRemoteRequest(code: number, data: rpc.MessageParcel, reply: rpc.MessageParcel, option: rpc.MessageOption) {
441        console.log('ServiceAbility onRemoteRequest called');
442        // Custom request code.
443        if (code === 1) {
444          // Receive the request code for requesting a continuous task.
445          startContinuousTask();
446          // Execute the continuous task.
447        } else if (code === 2) {
448          // Receive the request code for canceling the continuous task.
449          stopContinuousTask();
450        } else {
451          console.log('ServiceAbility unknown request code');
452        }
453        return true;
454      }
455    }
456
457    // Start the service by calling startAbility().
458    class ServiceAbility {
459      onStart(want: Want) {
460        console.info('ServiceAbility onStart');
461        mMyStub = new MyStub("ServiceAbility-test");
462        // Call the API to start the task.
463        startContinuousTask();
464        processAsyncJobs();
465      }
466
467      onStop() {
468        console.info('ServiceAbility onStop');
469      }
470
471      onConnect(want: Want) {
472        console.info('ServiceAbility onConnect');
473        return mMyStub;
474      }
475
476      onReconnect(want: Want) {
477        console.info('ServiceAbility onReconnect');
478      }
479
480      onDisconnect() {
481        console.info('ServiceAbility onDisconnect');
482      }
483
484      onCommand(want: Want, startId: number) {
485        console.info('ServiceAbility onCommand');
486      }
487    }
488
489    export default new ServiceAbility();
490    ```
491<!--DelEnd-->
492
493