1# Continuous Task 2 3 4## Overview 5 6 7### Introduction 8 9If 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. 10 11After an application requests a continuous task, the system verifies whether the application is actually executing the continuous task. It also attaches a notification to the continuous task. If the user deletes the notification, the system automatically stops the task. 12 13 14### Use Cases 15 16The 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. 17 18**Table 1** Continuous task types 19| Name| Description| Item| Example Scenario| 20| -------- | -------- | -------- | -------- | 21| DATA_TRANSFER | Data transfer| dataTransfer | The browser downloads a large file in the background.| 22| AUDIO_PLAYBACK | Audio and video playback| audioPlayback | A music application plays music in the background.| 23| AUDIO_RECORDING | Audio recording| audioRecording | A recorder records audio in the background.| 24| LOCATION | Positioning and navigation| location | A navigation application provides navigation in the background.| 25| BLUETOOTH_INTERACTION | Bluetooth-related task| bluetoothInteraction | Transfer a file through Bluetooth.| 26| MULTI_DEVICE_CONNECTION | Multi-device connection| multiDeviceConnection | Carry out distributed service connection.| 27| <!--DelRow-->WIFI_INTERACTION | WLAN-related task (for system applications only)| wifiInteraction | Transfer a file over WLAN.| 28| <!--DelRow-->VOIP | Voice and video calls (for system applications only)| voip | Use a system chat application to make an audio call in the background.| 29| TASK_KEEPING | <!--RP1-->Computing task (for specific devices only)<!--RP1End--> | taskKeeping | Run antivirus software.| 30 31- Only applications that use the [network management](../network/net-mgmt-overview.md) service can request a continuous task of the DATA_TRANSFER type to upload and download data in the background and avoid being suspended. If an application calls the [upload and download agent API](../reference/apis-basic-services-kit/js-apis-request.md) to delegate the upload and download task to the system, the application will be suspended regardless of whether it has requested such a continuous task. 32- Only audio and video applications that use [AVSession](../media/avsession/avsession-overview.md) can request a continuous task of the AUDIO_PLAYBACK type to implement background playback. 33 34 35### Constraints 36 37- **Ability restrictions**: In the stage model, only the UIAbility can request continuous tasks. In the FA model, only the ServiceAbility can request continuous tasks. 38 39- **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. 40 41- **Running restrictions**: The system verifies continuous tasks on mobile phones. 42 - Scenario 1: If an application requests a continuous task but does not execute or has finished the task of the requested type, the system performs certain control. 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. 43 - Scenario 2: If an application does not request a continuous task of a given type but executes such a continuous task, the system performs certain control. 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 performs control on the application. 44 - Scenario 3: 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. 45 46> **NOTE** 47> 48> 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. 49> 50> When an application that plays audio stops a continuous task in the background, it must suspend or stop the audio stream. Otherwise, the application will be forcibly terminated by the system. 51 52## Available APIs 53 54The 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). 55 56**Table 2** Main APIs for continuous tasks 57 58| API| Description| 59| -------- | -------- | 60| startBackgroundRunning(context: Context, bgMode: BackgroundMode, wantAgent: [WantAgent](../reference/apis-ability-kit/js-apis-app-ability-wantAgent.md)): Promise<void> | Requests a continuous task.| 61| stopBackgroundRunning(context: Context): Promise<void> | Cancels a continuous task.| 62 63## How to Develop 64 65The following walks you through how to request a continuous task for recording. In this example, the application provides two buttons: **Request Continuous Task** and **Cancel Continuous Task**. 66- 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. 67- When a user touches **Cancel Continuous Task**, the application cancels the continuous task, and the notification message is removed. 68 69### Stage Model 70 711. Declare the **ohos.permission.KEEP_BACKGROUND_RUNNING** permission. For details, see [Declaring Permissions](../security/AccessToken/declare-permissions.md). 72 732. Declare the continuous task type. 74 75 Declare the type of the continuous task for the target UIAbility in the **module.json5** file. (Set the corresponding configuration item in the configuration file.) 76 77 ```json 78 "module": { 79 "abilities": [ 80 { 81 "backgroundModes": [ 82 // Configuration item of the continuous task type 83 "audioRecording" 84 ], 85 } 86 ], 87 ... 88 } 89 ``` 90 913. Import the modules. 92 93 Import the modules related to continuous tasks: @ohos.resourceschedule.backgroundTaskManager and @ohos.app.ability.wantAgent. Import other modules based on the project requirements. 94 95 ```ts 96 import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager'; 97 import UIAbility from '@ohos.app.ability.UIAbility'; 98 import window from '@ohos.window'; 99 import AbilityConstant from '@ohos.app.ability.AbilityConstant'; 100 import Want from '@ohos.app.ability.Want'; 101 import rpc from '@ohos.rpc'; 102 import { BusinessError } from '@ohos.base'; 103 import wantAgent, { WantAgent } from '@ohos.app.ability.wantAgent'; 104 ``` 105 1064. Request and cancel a continuous task. 107 108 - In the stage model, an application can request a continuous task for itself or another application either on the local device or on a remote device.<!--RP2--><!--RP2End--> 109 <!--Del--> 110 - 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).<!--DelEnd--> 111 112 The code snippet below shows how an application requests a continuous task for itself. 113 114 ```ts 115 @Entry 116 @Component 117 struct Index { 118 @State message: string = 'ContinuousTask'; 119 // Use getContext to obtain the context of the UIAbility for the page. 120 private context: Context = getContext(this); 121 122 startContinuousTask() { 123 let wantAgentInfo: wantAgent.WantAgentInfo = { 124 // List of operations to be executed after the notification is clicked. 125 // Add the bundleName and abilityName of the application to start. 126 wants: [ 127 { 128 bundleName: "com.example.myapplication", 129 abilityName: "com.example.myapplication.MainAbility" 130 } 131 ], 132 // Specify the action to perform (starting the ability) after the notification message is clicked. 133 actionType: wantAgent.OperationType.START_ABILITY, 134 // Custom request code. 135 requestCode: 0, 136 // Execution attribute of the operation to perform after the notification is clicked. 137 wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] 138 }; 139 140 // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module. 141 wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => { 142 backgroundTaskManager.startBackgroundRunning(this.context, 143 backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => { 144 console.info(`Succeeded in operationing startBackgroundRunning.`); 145 }).catch((err: BusinessError) => { 146 console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 147 }); 148 }); 149 } 150 151 stopContinuousTask() { 152 backgroundTaskManager.stopBackgroundRunning(this.context).then(() => { 153 console.info(`Succeeded in operationing stopBackgroundRunning.`); 154 }).catch((err: BusinessError) => { 155 console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 156 }); 157 } 158 159 build() { 160 Row() { 161 Column() { 162 Text("Index") 163 .fontSize(50) 164 .fontWeight(FontWeight.Bold) 165 166 Button() { 167 Text('Request continuous task').fontSize(25).fontWeight(FontWeight.Bold) 168 } 169 .type(ButtonType.Capsule) 170 .margin({ top: 10 }) 171 .backgroundColor('#0D9FFB') 172 .width(250) 173 .height(40) 174 .onClick(() => { 175 // Request a continuous task by clicking a button. 176 this.startContinuousTask(); 177 178 // Execute the continuous task logic, for example, music playback. 179 }) 180 181 Button() { 182 Text ('Cancel 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 // Stop the continuous task. 191 192 // Cancel the continuous task by clicking a button. 193 this.stopContinuousTask(); 194 }) 195 } 196 .width('100%') 197 } 198 .height('100%') 199 } 200 } 201 ``` 202 <!--Del--> 203 The code snippet below shows how an application requests a continuous task across devices or applications. 204 205 ```ts 206 const MSG_SEND_METHOD: string = 'CallSendMsg' 207 208 let mContext: Context; 209 210 function startContinuousTask() { 211 let wantAgentInfo : wantAgent.WantAgentInfo = { 212 // List of operations to be executed after the notification is clicked. 213 wants: [ 214 { 215 bundleName: "com.example.myapplication", 216 abilityName: "com.example.myapplication.MainAbility", 217 } 218 ], 219 // Type of the operation to perform after the notification is clicked. 220 actionType: wantAgent.OperationType.START_ABILITY, 221 // Custom request code. 222 requestCode: 0, 223 // Execution attribute of the operation to perform after the notification is clicked. 224 wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] 225 }; 226 227 // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module. 228 wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj : WantAgent) => { 229 backgroundTaskManager.startBackgroundRunning(mContext, 230 backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => { 231 console.info(`Succeeded in operationing startBackgroundRunning.`); 232 }).catch((err: BusinessError) => { 233 console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 234 }); 235 }); 236 } 237 238 function stopContinuousTask() { 239 backgroundTaskManager.stopBackgroundRunning(mContext).then(() => { 240 console.info(`Succeeded in operationing stopBackgroundRunning.`); 241 }).catch((err: BusinessError) => { 242 console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 243 }); 244 } 245 246 class MyParcelable implements rpc.Parcelable { 247 num: number = 0; 248 str: string = ''; 249 250 constructor(num: number, string: string) { 251 this.num = num; 252 this.str = string; 253 } 254 255 marshalling(messageSequence: rpc.MessageSequence) { 256 messageSequence.writeInt(this.num); 257 messageSequence.writeString(this.str); 258 return true; 259 } 260 261 unmarshalling(messageSequence: rpc.MessageSequence) { 262 this.num = messageSequence.readInt(); 263 this.str = messageSequence.readString(); 264 return true; 265 } 266 } 267 268 function sendMsgCallback(data: rpc.MessageSequence) { 269 console.info('BgTaskAbility funcCallBack is called ' + data); 270 let receivedData: MyParcelable = new MyParcelable(0, ''); 271 data.readParcelable(receivedData); 272 console.info(`receiveData[${receivedData.num}, ${receivedData.str}]`); 273 // You can execute different methods based on the str value in the sequenceable data sent by the caller object. 274 if (receivedData.str === 'start_bgtask') { 275 // Request a continuous task. 276 startContinuousTask(); 277 } else if (receivedData.str === 'stop_bgtask') { 278 // Cancel the continuous task. 279 stopContinuousTask(); 280 } 281 return new MyParcelable(10, 'Callee test'); 282 } 283 284 export default class BgTaskAbility extends UIAbility { 285 // Create an ability. 286 onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { 287 console.info("[Demo] BgTaskAbility onCreate"); 288 try { 289 this.callee.on(MSG_SEND_METHOD, sendMsgCallback) 290 } catch (error) { 291 console.error(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`); 292 } 293 mContext = this.context; 294 } 295 296 // Destroy an ability. 297 onDestroy() { 298 console.info('[Demo] BgTaskAbility onDestroy'); 299 } 300 301 onWindowStageCreate(windowStage: window.WindowStage) { 302 console.info('[Demo] BgTaskAbility onWindowStageCreate'); 303 304 windowStage.loadContent('pages/Index', (error, data) => { 305 if (error.code) { 306 console.error(`load content failed with error ${JSON.stringify(error)}`); 307 return; 308 } 309 console.info(`load content succeed with data ${JSON.stringify(data)}`); 310 }); 311 } 312 313 onWindowStageDestroy() { 314 console.info('[Demo] BgTaskAbility onWindowStageDestroy'); 315 } 316 317 onForeground() { 318 console.info('[Demo] BgTaskAbility onForeground'); 319 } 320 321 onBackground() { 322 console.info('[Demo] BgTaskAbility onBackground'); 323 } 324 }; 325 ``` 326 <!--DelEnd--> 327 328### FA Model 329 3301. Start and connect to a ServiceAbility. 331 332 - 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. 333 334 - 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. 335 3362. Configure permissions and declare the continuous task type. 337 338 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. 339 340 ```json 341 "module": { 342 "package": "com.example.myapplication", 343 "abilities": [ 344 { 345 "backgroundModes": [ 346 "audioRecording", 347 ], // Background mode 348 "type": "service" // The ability type is Service. 349 } 350 ], 351 "reqPermissions": [ 352 { 353 "name": "ohos.permission.KEEP_BACKGROUND_RUNNING" // Continuous task permission 354 } 355 ] 356 } 357 ``` 358 3593. Import the modules. 360 361 ```js 362 import backgroundTaskManager from '@ohos.resourceschedule.backgroundTaskManager'; 363 import featureAbility from '@ohos.ability.featureAbility'; 364 import wantAgent, { WantAgent } from '@ohos.app.ability.wantAgent'; 365 import rpc from "@ohos.rpc"; 366 import { BusinessError } from '@ohos.base'; 367 import Want from '@ohos.app.ability.Want'; 368 ``` 369 3704. Request and cancel a continuous task. In the ServiceAbility, call **startBackgroundRunning()** and **stopBackgroundRunning()** to request and cancel a continuous task. Use JS code to implement this scenario. 371 372 ```js 373 function startContinuousTask() { 374 let wantAgentInfo: wantAgent.WantAgentInfo = { 375 // List of operations to be executed after the notification is clicked. 376 wants: [ 377 { 378 bundleName: "com.example.myapplication", 379 abilityName: "com.example.myapplication.MainAbility" 380 } 381 ], 382 // Type of the operation to perform after the notification is clicked. 383 actionType: wantAgent.OperationType.START_ABILITY, 384 // Custom request code. 385 requestCode: 0, 386 // Execution attribute of the operation to perform after the notification is clicked. 387 wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] 388 }; 389 390 // Obtain the WantAgent object by using the getWantAgent API of the wantAgent module. 391 wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => { 392 backgroundTaskManager.startBackgroundRunning(featureAbility.getContext(), 393 backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj).then(() => { 394 console.info(`Succeeded in operationing startBackgroundRunning.`); 395 }).catch((err: BusinessError) => { 396 console.error(`Failed to operation startBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 397 }); 398 }); 399 } 400 401 function stopContinuousTask() { 402 backgroundTaskManager.stopBackgroundRunning(featureAbility.getContext()).then(() => { 403 console.info(`Succeeded in operationing stopBackgroundRunning.`); 404 }).catch((err: BusinessError) => { 405 console.error(`Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`); 406 }); 407 } 408 409 async function processAsyncJobs() { 410 // Execute the continuous task. 411 412 // After the continuous task is complete, call the API to release resources. 413 stopContinuousTask(); 414 } 415 416 let mMyStub: MyStub; 417 418 // Start the service by calling connectAbility(). 419 class MyStub extends rpc.RemoteObject { 420 constructor(des: string) { 421 super(des); 422 } 423 424 onRemoteRequest(code: number, data: rpc.MessageParcel, reply: rpc.MessageParcel, option: rpc.MessageOption) { 425 console.log('ServiceAbility onRemoteRequest called'); 426 // Custom request code. 427 if (code === 1) { 428 // Receive the request code for requesting a continuous task. 429 startContinuousTask(); 430 // Execute the continuous task. 431 } else if (code === 2) { 432 // Receive the request code for canceling the continuous task. 433 stopContinuousTask(); 434 } else { 435 console.log('ServiceAbility unknown request code'); 436 } 437 return true; 438 } 439 } 440 441 // Start the service by calling startAbility(). 442 class ServiceAbility { 443 onStart(want: Want) { 444 console.info('ServiceAbility onStart'); 445 mMyStub = new MyStub("ServiceAbility-test"); 446 // Call the API to start the task. 447 startContinuousTask(); 448 processAsyncJobs(); 449 } 450 451 onStop() { 452 console.info('ServiceAbility onStop'); 453 } 454 455 onConnect(want: Want) { 456 console.info('ServiceAbility onConnect'); 457 return mMyStub; 458 } 459 460 onReconnect(want: Want) { 461 console.info('ServiceAbility onReconnect'); 462 } 463 464 onDisconnect() { 465 console.info('ServiceAbility onDisconnect'); 466 } 467 468 onCommand(want: Want, startId: number) { 469 console.info('ServiceAbility onCommand'); 470 } 471 } 472 473 export default new ServiceAbility(); 474 ``` 475 476